Flash is introducing insane rounding errors because of some arbitrary decision to round x and y coordinates to 0.05 increments
The data type for x and y properties is a double precision floating-point Number, so why is it rounding off values? Rounding is an unnecessary operation, and furthermore it's not saving any memory, because it just requires me to store a more precise value elsewhere, in addition to the lower-bit rounded value.
This rounding causing unnecessary additional work when coding against these values, because I have to round other values as well to make sure there aren't discrepancies when transforming coordinates.
So I was really surprised to discover that if I assign a value to a DisplayObject's x or y coordinates such as 10.3333333, and trace the value, it becomes 10.3.
If I assign 10.666666, it becomes 10.65. Apparently it's rounding everything to the nearest 20th of a unit. So now, I have to override the x and y properties to store the Number-type value, once again as a Number-type, which is not rounded.
Flash's arbitrary rounding of coordinates is causing erratic rounding errors when performing coordinate system transformations using localToGlobal and globalToLocal to find the composite scale of an object on the stage.
For example, suppose an object was laid out to occupy one third of the display, and it's width ends up being 200.3333333. One calculation of my docking framework involves obtaining the orthagonal bounding box of the child by transforming its corner points into stage coordinates using localToGlobal, which accounts for things like scaling and rotation. So despite everything having a scale of 1, and having zero rotation, you'd still end up with a rectangle with a width of 200.3 instead of the expected 200.3333333 in stage coordinates. So it would appear as though the composite scale is slightly smaller than 1, since 200.3 / 200.333333 is 0.99983361081528. But the composite scale is in fact 1, we just don't know that because Flash unexpectedly rounded some coordinates to an arbitrary 1/20 unit.
No game engine in existence does that with its transformation matrices, because it's retarded to round so early, and then allow those rounding errors to accumulate through a display hierarchy via functions like localToGlobal.
This rounding is causing jittering by a pixel or so when animating a drop down panel in my my docking framework, because it's constantly correcting for unexpected anomalies in the scaling factor on each frame. Despite the parent container having a constant fixed width, the child object, once its corner coordinates are passed through localToGlobal, end up reporting rounded widths, which ultimately leads to a series such as the following:
dockedChild.width: 538.3842482614723, parent.width: 558.3412118444024
dockedChild.width: 538.3754595467979, parent.width: 558.3412118444024
dockedChild.width: 538.3666709755926, parent.width: 558.3412118444024
dockedChild.width: 538.3578825478539, parent.width: 558.3412118444024
dockedChild.width: 538.3490942635798, parent.width: 558.3412118444024
dockedChild.width: 538.3903098666023, parent.width: 558.3412118444024
dockedChild.width: 538.3815210529766, parent.width: 558.3412118444024
dockedChild.width: 538.3727323828218, parent.width: 558.3412118444024
dockedChild.width: 538.3639438561353, parent.width: 558.3412118444024
dockedChild.width: 538.3551554729148, parent.width: 558.3412118444024
dockedChild.width: 538.346367233158, parent.width: 558.3412118444024
dockedChild.width: 538.3875826274011, parent.width: 558.3412118444024
dockedChild.width: 538.3787938582956, parent.width: 558.3412118444024
dockedChild.width: 538.37000523266, parent.width: 558.3412118444024
dockedChild.width: 538.3612167504922, parent.width: 558.3412118444024
dockedChild.width: 538.3524284117897, parent.width: 558.3412118444024
dockedChild.width: 538.3436402165502, parent.width: 558.3412118444024
dockedChild.width: 538.384855402015, parent.width: 558.3412118444024
dockedChild.width: 538.3760666774294, parent.width: 558.3412118444024
dockedChild.width: 538.3672780963132, parent.width: 558.3412118444024
dockedChild.width: 538.3584896586638, parent.width: 558.3412118444024
dockedChild.width: 538.349701364479, parent.width: 558.3412118444024
dockedChild.width: 538.3909170139807, parent.width: 558.3412118444024
Is there any way to turn off this rounding to 0.05 units?
To override the x and y values to have greater precision, I must do the following:
public class Control extends MovieClip
{
public function Control()
{
super(); //Flash performs timeline/graphics initialization here, which means after this call, the object may have non-zero x and y values
_x = super.x; //acquire them immediately, so if we try to set x or y to zero, the 'if (_x != value)' check does not think it's already positioned at zero and ignore the call
_y = super.y;
}
private var _x:Number;
private var _y:Number;
override public function get x():Number { return _x; } //return precise value, rather than rounded super.x value
override public function set x( value:Number ):void
{
if (_x != value) //ensure value is actually changing before performing work
{
_x = value; //store precise value in private variable
super.x = value; //DisplayObject will round value to nearest 0.05
if (stage != null)
stage.invalidate(); //ensure RENDER event is dispatched to re-render anything that may need to account for a repositioned object
}
}
override public function get y():Number { return _y; } //return precise value, rather than rounded super.y value
override public function set y( value:Number ):void
{
if (_y != value) //ensure value is actually changing before performing work
{
_y = value; //store precise value in private variable
super.y = value; //DisplayObject will round value to nearest 0.05
if (stage != null)
stage.invalidate(); //ensure RENDER event is dispatched to re-render anything that may need to account for a repositioned object }
}
}
Most importantly, you must initialize the _x and _y values to super.x and super.y in the constructor immediately after a call to super(), in order to acquire any non-zero values that the object instance may have been initialized with on the timeline.
I just cannot fathom why they didn't leave the x and y coordinates as-is, instead of rounding them, when it causes so many problems and complications, and requires overriding not only x and y, but functions like localToGlobal/globalToLocal/getRect.
This has been an issue for a while:
flash - AS3 x and y property precision - Stack Overflow specifically: flash - AS3 x and y property precision - Stack Overflow
http://www.actionscript.org/forums/showthread.php3?t=96510
Problems with Sub-pixel Coordinate Movement
In fact, that last link says: "
Running the code:
- The motion is still jerky; and
- The distance between the two squares diverges
However, the one benefit is that the distance does not diverge by more than 1 pixel."
That's precisely what I saw happening in my own code, as you can see from the series of widths I posted above, which seem to fluctuate randomly between 358.34 and 358.39.
