/// /// Represents a region composed of one or more rectangles, providing methods for union, intersection, exclusion, and /// complement operations. /// public class Region : IDisposable { private List _rectangles; /// /// Initializes a new instance of the class. /// public Region () { _rectangles = new (); } /// /// Initializes a new instance of the class with the specified rectangle. /// /// The initial rectangle for the region. public Region (Rectangle rectangle) { _rectangles = new() { rectangle }; } /// /// Adds the specified rectangle to the region. /// /// The rectangle to add to the region. public void Union (Rectangle rectangle) { _rectangles.Add (rectangle); _rectangles = MergeRectangles (_rectangles); } /// /// Adds the specified region to this region. /// /// The region to add to this region. public void Union (Region region) { _rectangles.AddRange (region._rectangles); _rectangles = MergeRectangles (_rectangles); } /// /// Updates the region to be the intersection of itself with the specified rectangle. /// /// The rectangle to intersect with the region. public void Intersect (Rectangle rectangle) { _rectangles = _rectangles.Select (r => Rectangle.Intersect (r, rectangle)).Where (r => !r.IsEmpty).ToList (); } /// /// Updates the region to be the intersection of itself with the specified region. /// /// The region to intersect with this region. public void Intersect (Region region) { List intersections = new List (); foreach (Rectangle rect1 in _rectangles) { foreach (Rectangle rect2 in region._rectangles) { Rectangle intersected = Rectangle.Intersect (rect1, rect2); if (!intersected.IsEmpty) { intersections.Add (intersected); } } } _rectangles = intersections; } /// /// Removes the portion of the specified rectangle from the region. /// /// The rectangle to exclude from the region. public void Exclude (Rectangle rectangle) { _rectangles = _rectangles.SelectMany (r => SubtractRectangle (r, rectangle)).ToList (); } /// /// Removes the portion of the specified region from this region. /// /// The region to exclude from this region. public void Exclude (Region region) { foreach (Rectangle rect in region._rectangles) { _rectangles = _rectangles.SelectMany (r => SubtractRectangle (r, rect)).ToList (); } } /// /// Updates the region to be the complement of itself within the specified bounds. /// /// The bounding rectangle to use for complementing the region. public void Complement (Rectangle bounds) { if (bounds.IsEmpty || _rectangles.Count == 0) { _rectangles.Clear (); return; } List complementRectangles = new List { bounds }; foreach (Rectangle rect in _rectangles) { complementRectangles = complementRectangles.SelectMany (r => SubtractRectangle (r, rect)).ToList (); } _rectangles = complementRectangles; } /// /// Creates an exact copy of the region. /// /// A new that is a copy of this instance. public Region Clone () { var clone = new Region (); clone._rectangles = new (_rectangles); return clone; } /// /// Gets a bounding rectangle for the entire region. /// /// A that bounds the region. public Rectangle GetBounds () { if (_rectangles.Count == 0) { return Rectangle.Empty; } int left = _rectangles.Min (r => r.Left); int top = _rectangles.Min (r => r.Top); int right = _rectangles.Max (r => r.Right); int bottom = _rectangles.Max (r => r.Bottom); return new (left, top, right - left, bottom - top); } /// /// Determines whether the region is empty. /// /// true if the region is empty; otherwise, false. public bool IsEmpty () { return !_rectangles.Any (); } /// /// Determines whether the specified point is contained within the region. /// /// The x-coordinate of the point. /// The y-coordinate of the point. /// true if the point is contained within the region; otherwise, false. public bool Contains (int x, int y) { return _rectangles.Any (r => r.Contains (x, y)); } /// /// Determines whether the specified rectangle is contained within the region. /// /// The rectangle to check for containment. /// true if the rectangle is contained within the region; otherwise, false. public bool Contains (Rectangle rectangle) { return _rectangles.Any (r => r.Contains (rectangle)); } /// /// Returns an array of rectangles that represent the region. /// /// An array of objects that make up the region. public Rectangle [] GetRegionScans () { return _rectangles.ToArray (); } /// /// Merges overlapping rectangles into a minimal set of non-overlapping rectangles. /// /// The list of rectangles to merge. /// A list of merged rectangles. private List MergeRectangles (List rectangles) { // Simplified merging logic: this does not handle all edge cases for merging overlapping rectangles. // For a full implementation, a plane sweep algorithm or similar would be needed. List merged = new List (rectangles); bool mergedAny; do { mergedAny = false; for (var i = 0; i < merged.Count; i++) { for (int j = i + 1; j < merged.Count; j++) { if (merged [i].IntersectsWith (merged [j])) { merged [i] = Rectangle.Union (merged [i], merged [j]); merged.RemoveAt (j); mergedAny = true; break; } } if (mergedAny) { break; } } } while (mergedAny); return merged; } /// /// Subtracts the specified rectangle from the original rectangle, returning the resulting rectangles. /// /// The original rectangle. /// The rectangle to subtract from the original. /// An enumerable collection of resulting rectangles after subtraction. private IEnumerable SubtractRectangle (Rectangle original, Rectangle subtract) { if (!original.IntersectsWith (subtract)) { yield return original; yield break; } // Top segment if (original.Top < subtract.Top) { yield return new (original.Left, original.Top, original.Width, subtract.Top - original.Top); } // Bottom segment if (original.Bottom > subtract.Bottom) { yield return new (original.Left, subtract.Bottom, original.Width, original.Bottom - subtract.Bottom); } // Left segment if (original.Left < subtract.Left) { int top = Math.Max (original.Top, subtract.Top); int bottom = Math.Min (original.Bottom, subtract.Bottom); if (bottom > top) { yield return new (original.Left, top, subtract.Left - original.Left, bottom - top); } } // Right segment if (original.Right > subtract.Right) { int top = Math.Max (original.Top, subtract.Top); int bottom = Math.Min (original.Bottom, subtract.Bottom); if (bottom > top) { yield return new (subtract.Right, top, original.Right - subtract.Right, bottom - top); } } } /// /// Releases all resources used by the . /// public void Dispose () { _rectangles.Clear (); } }