Beware the rounding error (or “Avoiding Out of Range errors”)

When iterating through an array that was generated by some built-in function (such as getVector()), check to make sure you’re rounding the input first. If you get an “out of range” error but your code is fucking perfect, then it’s probably because the rectangle used as input by getVector is skipping a row of pixels because the x,y of said rectangle is being rounded UP. For example, 12.51 becomes 13 but since the rectangle is limited by certain dimensions it simply (stupidly, moronically, fucking ridiculously) truncates the dimensions by one row or column. So when it turns the pixel data into a 1D array it’s missing a whole chunk of data which causes your pre-computed (with the correct dimensions) array length to be too high… hence the iterator will hit a number outside the array’s range.

Judging by the number of results Google returns, this is a pretty fringe case (that or I’m exceptionally stupid… hush). Regardless, it’s a problem that has been plaguing me for the past few months. If it weren’t for my genius programmery brother I would have never found it either. But thanks to him I’m now savvy to what’s termed as “rounding errors”. They even sound evil.

Here’s an example with code…

Below we define our dimensions grabbed from pixels (raw bitmapData from some loaded file elsewhere). We just want to analyze a quarter of the image, hence we’re dividing both dimensions by 2. We also instantiate the array (a fixed-length Vector) we’ll be iterating through:

?View Code ACTIONSCRIPT3
1
2
3
4
5
var w:int = pixels.width / 2;
var h:int = pixels.height / 2;
var _l:int = w * h;
var _rc:Rectangle = new Rectangle(0, 0, w, h);
array = new Vector.<uint>(_l, true);

Awesome. Now somewhere else in the code (say, an update method) we want to assign a chunk of pixel data to the array so we can pick through them one by one:

?View Code ACTIONSCRIPT3
6
7
8
9
10
11
12
_rc.x = pixels.x;
_rc.y = pixels.y;
array = pixels.getVector(_rc);
for (i; i < _l; ++i) {
	_pixel = array[i];
	var alpha:uint = _pixel >> 24;
}

Alright, looks mighty fine. We’re just checkin’ out the alpha value in those pixels, you know whatever. BUT WAIT. While we’re running this code, the values for pixels.x and pixels.y are changing because our source image is moving around the stage. And guess what? Without pixel snapping on, we’re getting floating point values for those coordinates even though they’re typed as ints. This wouldn’t normally be a problem but since we’re extracting other pixel data using those values, they need to be floored or else we’ll get the rounding error I discussed above.

So to fix this bitch we simply change lines 6 and 7 to:

?View Code ACTIONSCRIPT3
6
7
_rc.x = int(pixels.x);
_rc.y = int(pixels.y);

…and viola, no more error. (I used int() instead of Math.floor() because it’s hella faster). So I hope that helped someone out there because I sure as hell needed it :( Good luck and have fun.

Tags:

  • Twitter
  • del.icio.us
  • StumbleUpon
  • Facebook
  • Google Bookmarks
  • FriendFeed

Leave a Reply