How to copy a Rectangle in Dart - dart

I have two rectangles, one that is occasionally reset to some other rectangle. In C++ I'd just do:
_rect = _resetRect;
But in Dart that actually means that _rect now refers to the same object as _resetRect which is not what I want.
My current solution is this:
_rect.left = _resetRect.left;
_rect.width = _resetRect.width;
_rect.top = _resetRect.top;
_rect.height = _resetRect.height;
This is idiotic. Other questions suggest that there is no built-in way to copy objects (like there is in C++), and you have to rely on the object providing a clone() method. But Rectangle doesn't have one so what do I do?
Also even if it did have a clone() method, wouldn't that allocate an entirely new Rectangle rather than just setting the fields of the existing one (like C++'s operator=), and therefore be less efficient?

C++ also does not have a way to deep-copy an object which contains pointers/references to other objects. In Dart, all values are references, so that restriction applies to all objects.
I assume this is a MutableRectangle since the Rectange in dart:math is unmodifiable.
That class indeed does not have a way to clone the values of another rectangle, so you have to copy each of them. I would use a cascade for that:
_rect
..left = _resetRect.left
..top = _resetRect.top
..width = _resetRect.width
..height = _resetRect.height;
Alternatively, if it happens often enough, you can create a helper function:
void copyRectangle(MutableRectangle target, Rectangle source) {
target
..left = source.left
..top = source.top
..width = source.width
..height = source.height;
}

Related

Why this lua function is modifying tables it shouldn't?

I have this function in my code to load and setup sizes for sprites.
function aux.Sprite:setTexture(renderer,imgPath)
... -- Not important for this question
img = loadImage(renderer,imgPath)
self.texture = img.texture
self.rect.w = img.w
self.rect.h = img.h
end
(loadImage here is the function implemented in C, and is returning the correct values)
Using it should be easy enough
bg = aux.Sprite:new()
bg:setTexture(R, "testfiles/bg.png")
ship = aux.Sprite:new()
ship:setTexture(R, "testfiles/testship.png")
The problem is that after the second call for setTexture the values for the FIRST sprite is changed!
for example
bg = aux.Sprite:new()
bg:setTexture(R, "testfiles/bg.png")
print(bg.rect.w)
ship = aux.Sprite:new()
ship:setTexture(R, "testfiles/testship.png")
print(bg.rect.w)
should return
1920 1920
because I'm printing the width for bg twice
but I'm getting
1920
300
That is, the second setTexture changes the value for "bg" and not only for "ship".
My guess is that self.rect.w = img.w is setting a "pointer", or whatever is called in lua, to img.w and when I use the function later this pointer is updated in all references?
What I'm doing wrong here? Is this the correct lua behavior?
PS: The definition of the Sprite:new function as asked
function aux.Sprite:new(o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end
There is nothing in the provided code that actually creates the rect (or aux.Sprite for that matter). I guess this means that is done via something like
aux.Sprite = { rect = {} }
This is a problem because it means all your sprites share the same rect.
aux.Sprite:new() returns a new empty table that has the metatable and its __index set to Sprite. Thus when in setTexture self.rect is searched in this empty table the one from Sprite is returned via __index.
You need to make sure every sprite has its own unique rect.
I don't really know what is the typical Lua object pattern here, but you can eg. have self.rect = { w = img.w, h = img.h } in setTexture or maybe o.rect = {} in new - something that actually sets rect to a new table for this particular sprite.

Cannot cast from 'TFmxChildrenList' to 'TRectangle *'

I'm new to using C++ Builder so apologies if I'm making any rudimentary mistakes.
I have drawn out a TLayout named 'Collection' with a 5x5 grid of TRectangles within it. The cells are named like so "CellXY".
I presumed it might be easier to draw these out on the Form rather than instantiating them with code, now I'm thinking otherwise, but I would still like to solve the problem this way to better my understanding.
I'm trying to write a method which will return a pointer to a TRectangle whose name contains the coordinates passed to the method.
Currently, I'm trying to do this by iterating through the children of the TLayout Collection:
TRectangle* __fastcall TForm2::getCellRectangleFromCoordinate(int X, int Y){
TRectangle* targetCell = NULL;
char targetCellName[6];
sprintf(targetCellName, "Cell%i%i", X, Y);
for (int cIndex = 0; cIndex < Collection->ChildrenCount; ++cIndex)
{
TRectangle* cellRect = (TRectangle*) Collection->Children[cIndex]; // Error Here
string cellName = cellRect->Name;
if (targetCellName == cellName) {
targetCell = cellRect;
break;
}
}
return targetCell;
}
But I am given an error reading:
E2031 Cannot cast from 'TFmxChildrenList' to 'TRectangle *'
If anyone could help, I'd be very grateful!
The Children property is a pointer to a class type (TFmxChildrenList) that internally holds an array of objects. Children is not the actual array itself, like you are trying to treat it as.
Children[cIndex] is using pointer arithmetic, which is not what you want in this situation. You need to use the Children->Items[] sub-property instead, by changing this statement:
Collection->Children[cIndex]
To either this:
Collection->Children->Items[cIndex]
Or this:
(*(Collection->Children))[cIndex]

Accessing data inside a table inside a table gives nil value

As of now, I'm trying to draw a layered world map from a spritesheet, through Tiled (pretty useful since you can export the map you've created visually, directly in a .lua file).
Concerning this, I've encountered a problem: Tiled provides a lua file of this type, let's call it data.lua
return {
---data
tilesets = {
image = "path/to/image",
imagewidth = 2560,
imageheight = 1664,
--other data
},
layers = {
layer1 = {}, --there's data in here
layer2 = {} --there's data in here
}
}
In another file, world_map.lua, i have this
local world_map = {}
local world_data = {}
world_data = require "data"
local last_tile = (world_data.tilesets.imagewidth * world_data.tilesets.imageheight)/(world_data.tilewidth * world_data.tileheight)
--various functions which also use world_data
return world_map
now, when I run this code, I get that it's impossible to operate arithmethic operations on imagewidth because it's a nil value, so, i guess, it looks like it's not initialised. I can't understand what I'm doing wrong: the require instruction should assegnate that table (the one returned by data.lua) to the local variable and then I simply access this variable and operate on its fields. Then again, all the fields inside the nested table are initialised with their own value, but they are nil according to the interpreter. What am I doing wrong?

How to add Tuples and apply a ceiling/clamp function in F#

So I am working on a project using F# for some SVG line manipulations.
I thought it would be good to represent color an RGB value as a tuple (R,G,B). It just made sense to me. Well since my project involves generating SVG lines in a loop. I decided to have a color offset, conveniently also represented in a tuple (Roffset, Goffset, Boffset)
An offset in this case represents how much each line differs from the previous.
I got to a point where I needed to add the tuples. I thought since they were of the same dimensions and types, it would be fine. But apparently not. I also checked the MSDN on tuples, but I did not find anything about how to add them or combine them.
Here is what I tried. Bear in mind I tried to omit as much irrelevant code as possible since this is a long class definition with LOTS of members.
type lineSet ( 10+ params omitted ,count, colorOff :byte*byte*byte, color :byte*byte*byte ,strokeWid , strokeWidthOff ) =
member val Color = color with get, set
member val ColorOffset = colorOff with get, set
member val lineCount = count with get, set
interface DrawingInterfaces.IRepresentable_SVG with
member __.getSVGRepresenation() =
let mutable currentColor = __.Color
for i in 1..__.lineCount do
currentColor <- currentColor + __.ColorOffset
That last line of code is what I wanted to do. However, it appears you cannot add tuples directly.
I also need a way to clamp the result so it cannot go over 255, but I suspect a simple try with block will do the trick. OR I could let the params take a type int*int*int and just use an if to reset it back to 255 each time.
As I mentioned in the comments, the clamping function in your code does not actually work - you need to convert the numbers to integers before doing the addition (and then you can check if the integer is greater than 255). You can do something like this:
let addClamp (a:byte) (b:byte) =
let r = int a + int b
if r > 255 then 255uy else byte r
Also, if you work with colors, then it might make sense to define a custom color type rather than passing colors around as tuples. That way, you can also define + on colors (with clamping) and it will make your code simpler (but still, 10 constructor arguments is a bit scary, so I'd try to think if there is a way to simplify that a bit). A color type might look like this:
type Color(r:byte, g:byte, b:byte) =
static let addClamp (a:byte) (b:byte) =
let r = int a + int b
if r > 255 then 255uy else byte r
member x.R = r
member x.B = b
member x.G = g
static member (+) (c1:Color, c2:Color) =
Color(addClamp c1.R c2.R, addClamp c1.G c2.G,addClamp c1.B c2.B)
Using the type, you can then add colors pretty easily and do not have to add clamping each time you need to do that. For example:
Color(255uy, 0uy, 0uy) + Color(1uy, 0uy, 0uy)
But I still think you could make the code more readable and more composable by refactoring some of the visual properties (like stroke & color) to a separate type and then just pass that to LineSet. This way you won't have 10+ parameters to a constructor and your code will probably be more flexible too.
Here is a modified version of your code which I think is a bit nicer
let add3DbyteTuples (tuple1:byte*byte*byte , tuple2:byte*byte*byte) =
let inline intify (a,b,c) = int a,int b,int c
let inline tripleadd (a,b,c) (d,e,f) = a+d,b+e,c+f
let clamp a = if a > 255 then 255 else a
let R,G,B = tripleadd (intify tuple1) (intify tuple2)
clamp R,clamp G,clamp B

add mouseevents to webgl objects

im using xtk to visualize medical data in a webgl canvas. currently im playing around with this lesson:
lesson 10
this library is pretty good but not very well documented. i want to get rid of that gui and add some mouseevents. if i load the mesh from the gui how can i add a mouse event to the mesh? i actually don't know where to start. it's a little bit confusing to get started with this library....
i tried
mesh.click(function(){
alert("yes");
})
or
mesh.mousedown(function(){
alert("yes");
}
Objects rendered in WebGL are not part of the DOM, and as such don't generate events like DOM elements do. This means that for events like these you have to implement the mouse interaction code yourself.
Traditionally in WebGL/OpenGL this process is known as "Picking", and there's several decent resources for it online. (For example: http://webgldemos.thoughtsincomputation.com/engine_tests/picking) The core process is something like this, though:
For each pickable object in your scene, assign it a color. Put this in a lookup table somewhere
Re-render the entire scene to a texture, rendering each pickable object with it's assigned color
Once the scene is rendered, determine your mouse coordinates and read back the color of the texture at that X/Y.
Fetch the object associated with that color from your lookup table. This is the object your mouse cursor is pointing at!
As you can see, while not a difficult method conceptually this also involves several mid-level WebGL topics, such as rendering to a texture, and as such is not usually recommended for beginners. I'm not sure if there are any features in xtk to assist with this (honestly I had never heard of the library before your post), but I would guess that this is something that you'll have to implement on your own.
DOM events are not supported but you can do it with xtk. Check out this JSFiddle
http://jsfiddle.net/haehn/r7Ugf/
// create and initialize a 3D renderer
var r = new X.renderer3D();
r.init();
// create a cube and a sphere
cube = new X.cube();
sphere = new X.sphere();
sphere.center = [-20, 0, 0];
r.interactor.onMouseMove = function() {
// grab the current mouse position
var _pos = r.interactor.mousePosition;
// pick the current object
var _id = r.pick(_pos[0], _pos[1]);
if (_id != 0) {
// grab the object and turn it red
r.get(_id).color = [1, 0, 0];
} else {
// no object under the mouse
cube.color = [1, 1, 1];
sphere.color = [1, 1, 1];
}
r.render();
}
r.interactor.onMouseDown = function(left, middle, right) {
// only observe right mouse clicks
if (!right) return;
// grab the current mouse position
var _pos = r.interactor.mousePosition;
// pick the current object
var _id = r.pick(_pos[0], _pos[1]);
if (_id == sphere.id) {
// turn the sphere green
sphere.color = [0, 1, 0];
r.render();
}
}
r.add(cube); // add the cube to the renderer
r.add(sphere); // and the sphere as well
r.render(); // ..and render it
Easy, no?
XTK implements picking the way Toji explained (i.e. with a frameBuffer where every object is rendered in a different RGBA "color"). It will work while you have less than 255^4 objects, so almost always. There are other methods like unprojecting but they would be longer I think.
So with X.renderer.pick and X.renderer.get you can find the object under the mouse and change its properties. However for the moment you can only change vizualisation properties (see the setGetter and setSetter in every class) but you cannot move an X.object (since X.object._transform attribute is private and there is no getter/setter for it yet).
That's something interesting to deal with : adding a pair of getter/setter for X.object's transform would allow, for example, an user to put medical stuff (modelized by a mesh or something else) in the scene and place to mesure distances or see if it will fit for an operation or something like that. Shouldn't be a good idea Haehn ? And it's a minor change in the framework.

Resources