Skip to main content
Inspiring
May 1, 2014
Question

Bug in Rectangle.union?

  • May 1, 2014
  • 1 reply
  • 1109 views

Is is just me, or is this wrong.  I'm guessing there's some sort of zero-area-based optimization that's causing rectangles to be improperly unioned.

import flash.geom.Rectangle;
 
var r1:Rectangle = new Rectangle( 0, 0, 40, 23 ); //non-zero area plus
var r2:Rectangle = new Rectangle( 0, 0, 100, 0 ); //zero-area but non-zero height
trace( r1.union( r2 ) ); //(x=0, y=0, w=40, h=23) WRONG!!! no-effect
 
 
var r3:Rectangle = new Rectangle( 0, 0, 40, 23 ); //non-zero area plus
var r4:Rectangle = new Rectangle( 0, 0, 0, 100 ); //zero-area but non-zero height
trace( r3.union( r4 ) ); //(x=0, y=0, w=40, h=23)  WRONG!!! no-effect
 
 
var r5:Rectangle = new Rectangle( 0, 0, 40, 0 ); //zero-area but non-zero height plus
var r6:Rectangle = new Rectangle( 0, 0, 0, 100 ); //zero-area but non-zero height
trace( r5.union( r6 ) ); //(x=0, y=0, w=0, h=100)  WHAT??? height is added?? and width is removed??

It sure doesn't fit, for example, this Java reference implementation:

/**
      * Computes the union of this <code>Rectangle</code> with the
      * specified <code>Rectangle</code>. Returns a new
      * <code>Rectangle</code> that
      * represents the union of the two rectangles
      * @9397041 r the specified <code>Rectangle</code>
      * @Return the smallest <code>Rectangle</code> containing both
      * the specified <code>Rectangle</code> and this
      * <code>Rectangle</code>.
      */

     public Rectangle union(Rectangle r) {

         int x1 = Math.min(x, r.x);

         int x2 = Math.max(x + width, r.x + r.width);

         int y1 = Math.min(y, r.y);

         int y2 = Math.max(y + height, r.y + r.height);

         return new Rectangle (x1, y1, x2 - x1, y2 - y1);

     }

That's how I would expect a union operation to work.   Add this to the previous chunk of AS3 to see the difference:

trace( union( r1, r2 ) ); //(x=0, y=0, w=100, h=23) //CORRECT
trace( union( r2, r3 ) ); //(x=0, y=0, w=100, h=23) //CORRECT
trace( union( r4, r5 ) ); //(x=0, y=0, w=40, h=100) //CORRECT
  
function union(r0:Rectangle, r:Rectangle ):Rectangle
{
   var x1 = Math.min(r0.x, r.x);
   var x2 = Math.max(r0.x + r0.width, r.x + r.width);
   var y1 = Math.min(r0.y, r.y);
   var y2 = Math.max(r0.y + r0.height, r.y + r.height);
   return new Rectangle (x1, y1, x2 - x1, y2 - y1);
}

This bug was completely messing up my Flex-like framework and took forever to track down.  I would have never expected such a core and basic math operation like Rectangle.union to be failing.  This was causing my autoHeight calculations for custom GUIControls to fail.

The union is supposed to be the smallest rectangle containing both rectangles.  If either of the rectangles has zero width and/or zero height, it is a point or a line, but the final rectangle must still contain it.  As you can see, Rectangle.union is not working correctly.

This topic has been closed for replies.

1 reply

Ned Murphy
Legend
May 1, 2014

Per the AS3 documentation:

Note: The union() method ignores rectangles with 0 as the height or width value, such as: var rect2:Rectangle = new Rectangle(300,300,50,0);

So it is probably a case where you will get unexpected results

Inspiring
May 1, 2014

It's not a rectangle union operation, plain and simple.  Adding a note to the documentation doesn't make it correctly functioning.

Note: The union() method ignores rectangles with 0 as the height or width value, such as: var rect2:Rectangle = new Rectangle(300,300,50,0);

Why the special case for zero?  Rectangles can have any x and y point, and any width or height, positive or negative.  They are ulimately defined by four points, regardless of whether those four points create a non-zero area, and a rectangle union operation is supposed to be the smallest rectangle containing all points on both unioned rectangles.

You also must not have noticed the inconconsistancy between the three examples I posted.  The last two show that it uses the first rectangle in one case, but the second rectangle in the other case.

var r3:Rectangle = new Rectangle( 0, 0, 40, 23 );
var r4:Rectangle = new Rectangle( 0, 0, 0, 100 ); //ADDING ZERO WIDTH RECTANGLE
trace( r3.union( r4 ) ); //(x=0, y=0, w=40, h=23)  //USES FIRST RECTANGLE


var r5:Rectangle = new Rectangle( 0, 0, 40, 0 );
var r6:Rectangle = new Rectangle( 0, 0, 0, 100 ); //ADDING ZERO WIDTH RECTANGLE (same as before)
trace( r5.union( r6 ) ); //(x=0, y=0, w=0, h=100)  //USES SECOND RECTANGLE (when first one has zero area?)


In the second case, it clearly is not ignoring one of the rectangles, despite both having zero area, because the instance upon which it's operating is having its value replaced by the parameter passed to it.  If it was simply ignoring the passed parameter, it would return the original rectangle (0,0,40,0), and if it was ignoring both, it would return an empty rectangle, but it's not.  So something is very wrong with this implementation.

The note appearing in the documentation is interesting, because there is no such note for other operations like Rectangle.intersection.

var r7:Rectangle = new Rectangle( 0, 0, 40, 40 ); //40x40

var r8:Rectangle = new Rectangle( 10, 10, 0, 1 ); //zero-area but non-zero height

trace("intersects: " + r7.intersects( r8 ) ); //intersects: false

trace("contains: " + r7.containsRect( r8 ) ); //contains: true


That is logically inconsistant for one rectangle to completely contain another rectangle but not intersect it, and this operation is not talking about edge intersection, but whether they overlap: "Similarly, you can use the intersects() method to find out whether the bounding rectangles of two display objects overlap."

Ned Murphy
Legend
May 1, 2014

I saw all of your cases which is why I said "So it is probably a case where you will get unexpected results"

The bottom line ius, the developers have indicated how the processing behaves.  If you have an issue with how they process a union then offer it as a suggestion to improve the program.

Adobe - Wishlist & Bug Report

-----------------------------

https://www.adobe.com/cfusion/mmform/index.cfm?name=wishform

(I do not know if that is still a valid submittal resource, though it does link to the expected page)