/// <summary> Returns the parts of a not overlapping with b. </summary> public static Rect[] Subtract(Rect a, ref Rect b) { var legs = a.GetCorners().Count(b.Contains); if (legs == 0) { return a.Substract0Legged(ref b); } else if (legs == 1) { return a.Substract1Legged(b); } else if (legs == 2) { return a.Substract2Legged(b); } else { Contract.Assert(legs == 4); return EmptyCollection<Rect>.Array; //rect is already contained in r } }
/// <summary> Returns parts of a that are not contained in b, assuming that no corner of a is in b. </summary> public static Rect[] Substract0Legged(this Rect a, ref Rect b) { bool rightQ = b.Left <= a.Right && a.Right < b.Right; //a.right is in b bool leftQ = b.Left <= a.Left && a.Left < b.Right; //a.left is in b bool topQ = b.Top <= a.Top && a.Top < b.Bottom; //a.top is in b bool bottomQ = b.Top <= a.Bottom && a.Bottom < b.Bottom; //a.bottom is in b //no corner of a may be in b Contract.Assert(!(leftQ && topQ)); Contract.Assert(!(rightQ && topQ)); Contract.Assert(!(rightQ && bottomQ)); Contract.Assert(!(leftQ && bottomQ)); int invCornerCount = b.GetCorners().Count(a.Contains); if (invCornerCount == 2) { Rect[] result = Substract2Legged(b, a); b = a; //must be set after calling Substract2Legged return result; } else if (invCornerCount == 4) { b = default(Rect); return new[] { a }; } if (leftQ && rightQ) { //b is horizontal if (b.Bottom <= a.Top || b.Top >= a.Bottom) { //no intersection } else { //top part of a: Rect result1 = FromExplicitCoordinates(a.Left, a.Right, a.Top, b.Top); //bottom part of a: Rect result2 = FromExplicitCoordinates(a.Left, a.Right, b.Bottom, a.Bottom); return new[] { result1, result2 }; } } else if (topQ && bottomQ) { //b is vertical if (b.Left >= a.Right || b.Right <= a.Left) { //no intersection } else { //left part of a: Rect result1 = FromExplicitCoordinates(a.Left, b.Left, a.Top, a.Bottom); //right part of b: Rect result2 = FromExplicitCoordinates(b.Right, a.Right, a.Top, a.Bottom); return new[] { result1, result2 }; } } //no intersection return new[] { a }; }