Difference (XOR) between two rectangles, as rectangles?
I'm looking for a simple way to calculate the difference between two rectangles. I mean all points which belong to one of the rectangles, but not to both (so it's like XOR).
The rectangles are axis-aligned in this case, so there will be only right angles. I believe the difference region can be expressed in 0-4 rectangles (0 if both rectangles are the开发者_运维技巧 same, 1 if just one edge is different, 4 in the general case), and I'd like to get the difference region as a list of rectangles.
You can also think of it as the areas of the screen that have to be updated when a solid rectangle is moved/resized.
Examples: Doubling the width of rectangle "a" - I want the added region (R).
+----+----+
| a | R |
| | |
+----+----+
Intersecting rectangles (a and b) - I want the area given by T, L, R and B in rectangles (other partitioning possible), but excluding X:
+------------+ a
| T |
|·····+------+-----+ b
| L | X | R |
| | | |
+-----+------+·····|
| B |
+------------+
I'd prefer a python solution/library, but any robust algorithm would be helpful.
Split the problem down onto a per-axis basis. Your rectangles can be defined in terms of their spans on each axis - find the interesting points on each axis where a rectangle starts or ends and then define your results in those terms. This'll give you 6 rectangles of difference areas, you can easily combine them down to the four you've illustrated or eliminate degenerate zero-area rectangles if you need to.
Here's a Java implementation:
public class Rect
{
private float minX, maxX, minY, maxY;
public Rect( float minX, float maxX, float minY, float maxY )
{
this.minX = minX;
this.maxX = maxX;
this.minY = minY;
this.maxY = maxY;
}
/**
* Finds the difference between two intersecting rectangles
*
* @param r
* @param s
* @return An array of rectangle areas that are covered by either r or s, but
* not both
*/
public static Rect[] diff( Rect r, Rect s )
{
float a = Math.min( r.minX, s.minX );
float b = Math.max( r.minX, s.minX );
float c = Math.min( r.maxX, s.maxX );
float d = Math.max( r.maxX, s.maxX );
float e = Math.min( r.minY, s.minY );
float f = Math.max( r.minY, s.minY );
float g = Math.min( r.maxY, s.maxY );
float h = Math.max( r.maxY, s.maxY );
// X = intersection, 0-7 = possible difference areas
// h ┌─┬─┬─┐
// . │5│6│7│
// g ├─┼─┼─┤
// . │3│X│4│
// f ├─┼─┼─┤
// . │0│1│2│
// e └─┴─┴─┘
// . a b c d
Rect[] result = new Rect[ 6 ];
// we'll always have rectangles 1, 3, 4 and 6
result[ 0 ] = new Rect( b, c, e, f );
result[ 1 ] = new Rect( a, b, f, g );
result[ 2 ] = new Rect( c, d, f, g );
result[ 3 ] = new Rect( b, c, g, h );
// decide which corners
if( r.minX == a && r.minY == e || s.minX == a && s.minY == e )
{ // corners 0 and 7
result[ 4 ] = new Rect( a, b, e, f );
result[ 5 ] = new Rect( c, d, g, h );
}
else
{ // corners 2 and 5
result[ 4 ] = new Rect( c, d, e, f );
result[ 5 ] = new Rect( a, b, g, h );
}
return result;
}
}
There is an algorithm in this link: https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Rectangle_difference
It is called "4-zone Rectangle Difference".
It basically computes the four possible rectangles that may remain after subtracting one rectangle from other.
In this case, the algorithm have to be run twice.
I would imagine finding the area of the intersecting rectangle (that is X) and deducting that from the combined area of rectangle a + rectangle b will give your solution.
I found this on my hunt for a quick answer:
http://tekpool.wordpress.com/2006/10/12/rectangle-intersection-find-the-intersecting-rectangle/
精彩评论