C#矩形对矩形拆分

发布时间 2023-12-05 15:06:26作者: HotSky
  1 public enum TanglecySide
  2 {
  3     None = 1,
  4     LeftToRight = 1 >> 1,
  5     RightToLeft = 1 >> 2,
  6     TopBottom = 1 >> 3,
  7     BottomToTop = 1 >> 4,
  8     LeftToLeft = 1 >> 5,
  9     RightToRight = 1 >> 6,
 10     TopToTop = 1 >> 7,
 11     BottomToBottom = 1 >> 8,
 12 }
 13 
 14 public class Rect2DCompare : IComparer<Rect2D>
 15 {
 16     public int Compare(Rect2D? x, Rect2D? y)
 17     {
 18         if(x is null  && y is null) return 0;
 19         if(x is null && y is not null) return -1;
 20         if (x is not null && y is null) return 1;
 21         return x.CompareTo(y);
 22     }
 23 }
 24 
 25 public class Rect2D : IComparable<Rect2D>
 26 {
 27     public int X { get; set; }
 28     public int Y { get; set; }
 29     public int Width { get; set; }
 30     public int Height { get; set; }
 31     public bool CanSplit { get; set; }
 32     public int Right { get => Right; }
 33     public int Bottom { get => Bottom; }
 34 
 35     public override string ToString()
 36     {
 37         return $"{X},{Y},{Width},{Height}";
 38     }
 39     public Rect2D() { }
 40     public Rect2D(int x, int y, int width, int height, bool canSplit = true)
 41     {
 42         X = x;
 43         Y = y;
 44         Width = width; Height = height;
 45         CanSplit = canSplit;
 46     }
 47 
 48     public int CompareTo(Rect2D? y)
 49     {
 50         if(y == null) return 1;
 51         return (X * Y).CompareTo(y.X * y.Y);
 52     }
 53 
 54     /// <summary>
 55     /// 不相切但相交
 56     /// </summary>
 57     /// <param name="rect"></param>
 58     /// <returns></returns>
 59     public bool IsIntersect(Rect2D rect)
 60     {
 61         return !(Right <= rect.X || Bottom <= rect.Y || X >= rect.Right || Y >= rect.Bottom);
 62     }
 63 
 64     /// <summary>
 65     /// 获取本矩形于目标矩形相切的边
 66     /// </summary>
 67     /// <param name="rect">目标矩形</param>
 68     /// <param name="intersect">是否包括同侧相切的情况,例如本矩形左侧与目标矩形左侧相切</param>
 69     /// <returns>返回本矩形相交的边</returns>
 70     public TanglecySide TangencySides(Rect2D rect, bool includeSameSide = false)
 71     {
 72         TanglecySide sideToSide = TanglecySide.None;
 73         if (!IsIntersect(rect)) return sideToSide;
 74         if (this.X == rect.Right) sideToSide |= TanglecySide.LeftToRight;
 75         if (this.Y == rect.Bottom) sideToSide |= TanglecySide.TopBottom;
 76         if (this.Right == rect.X) sideToSide |= TanglecySide.RightToLeft;
 77         if (this.Bottom == rect.Y) sideToSide |= TanglecySide.BottomToTop;
 78         if (includeSameSide)
 79         {
 80             if (X == rect.X) sideToSide |= TanglecySide.LeftToLeft;
 81             if (Y == rect.Y) sideToSide |= TanglecySide.TopToTop;
 82             if (Right == rect.Right) sideToSide |= TanglecySide.RightToRight;
 83             if (X + Height == rect.Bottom) sideToSide |= TanglecySide.BottomToBottom;
 84         }
 85         return sideToSide;
 86     }
 87 
 88     /// <summary>
 89     /// 判断点是否在矩形上,包括在边上
 90     /// </summary>
 91     /// <param name="x"></param>
 92     /// <param name="y"></param>
 93     /// <returns></returns>
 94     public bool Contains(int x, int y) => x >= X && y >= Y && x <= Right && y <= Bottom;
 95     /// <summary>
 96     /// 判断rect整个区域是否在矩形上,包括相切
 97     /// </summary>
 98     /// <param name="rect"></param>
 99     /// <returns></returns>
100     public bool Contains(Rect2D rect) => X <= rect.X && rect.Right <= Right && Y <= rect.Y && rect.Bottom <= Bottom;
101 
102     /// <summary>
103     /// 传入矩形按四个顶点进行拆分
104     /// </summary>
105     /// <param name="rect">不可拆分的矩形</param>
106     /// <returns>返回拆分后的矩形列表</returns>
107     public List<Rect2D> GetUnIntersectAreas(Rect2D rect)
108     {
109         if (this.CanSplit == rect.CanSplit) return null;
110         if (!this.CanSplit) return rect.GetUnIntersectAreas(this);
111         if (!IsIntersect(rect)) return null;
112         if (rect.Contains(this)) return null;
113         List<Rect2D> result = new List<Rect2D>();
114 
115         //当被拆分的矩形在左上侧时才有左上角矩形
116         Rect2D leftTop = new Rect2D
117         {
118             X = Math.Min(X, rect.X),
119             Y = Math.Min(Y, rect.Y),
120             Width = Math.Max(rect.X - X, 0),
121             Height = Math.Max(rect.Y - Y, 0),
122             CanSplit = true,
123         };
124         if (leftTop.Width > 0 && leftTop.Height > 0)
125             result.Add(leftTop);
126 
127         //当被拆分的矩形在右上侧时才有右上角矩形
128         Rect2D rightTop = new Rect2D
129         {
130             X = Math.Min(Right, rect.Right),
131             Y = Math.Min(Y, rect.Y),
132             Width = Math.Max(0, Right - rect.Right),
133             Height = Math.Max(0, rect.Y - Y),
134             CanSplit = true,
135         };
136         if (rightTop.Width > 0 && rightTop.Height > 0)
137             result.Add(rightTop);
138 
139         //当被拆分的矩形在上侧时才有上侧矩形
140         Rect2D top = new Rect2D
141         {
142             X = Math.Max(X, rect.X),
143             Y = Math.Min(Y, rect.Y),
144             Width = Math.Max(0, Width - leftTop.Width - rightTop.Width),
145             Height = Math.Max(0, leftTop.Height),
146             CanSplit = true,
147         };
148         if(top.Width > 0 && top.Height > 0) result.Add(top);
149 
150         //当被拆分的矩形在左下侧时才有左下角矩形
151         Rect2D leftBottom = new Rect2D
152         {
153             X = Math.Min(X, rect.X),
154             Y = Math.Min(rect.Bottom, Bottom),
155             Width = Math.Max(rect.X - X, 0),
156             Height = Math.Max(0, Bottom - rect.Bottom),
157             CanSplit = true,
158         };
159         if (leftBottom.Width > 0 && leftBottom.Height > 0) result.Add(leftBottom);
160 
161         //当被拆分的矩形在右下侧时才有右下角矩形
162         Rect2D rightBottom = new Rect2D
163         {
164             X = Math.Min(Right, rect.Right),
165             Y = Math.Min(rect.Bottom, Bottom),
166             Width = Math.Max(0, Right - rect.Right),
167             Height = Math.Max(0, Bottom - rect.Bottom),
168             CanSplit = true,
169         };
170         if (rightBottom.Width > 0 && rightBottom.Height > 0) result.Add(rightBottom);
171 
172         //当被拆分的矩形在下侧时才有下侧矩形
173         Rect2D bottom = new Rect2D
174         {
175             X = Math.Max(X, rect.X),
176             Y = Math.Min(rect.Bottom, Bottom),
177             Width = Math.Max(0, Width - leftTop.Width - rightTop.Width),
178             Height = Math.Max(0, Bottom - rect.Bottom),
179             CanSplit = true,
180         };
181         if (bottom.Width > 0 && bottom.Height > 0) result.Add(bottom);
182 
183         //当被拆分的矩形在左侧时才有左侧矩形
184         Rect2D left = new Rect2D
185         {
186             X = Math.Min(X, rect.X),
187             Y = Math.Max(Y, rect.Y),
188             Width = Math.Max(rect.X - X, 0),
189             Height = Height - leftTop.Height - leftBottom.Height,
190             CanSplit = true,
191         };
192         if (left.Width > 0 && left.Height > 0) result.Add(left);
193 
194 
195         //当被拆分的矩形在右侧时才有右侧矩形
196         Rect2D right = new Rect2D
197         {
198             X = Math.Min(Right, rect.Right),
199             Y = Math.Max(Y, rect.Y),
200             Width = Math.Max(0, Right - rect.Right),
201             Height = Height - rightTop.Height - rightBottom.Height,
202             CanSplit = true,
203         };
204         if (right.Width > 0 && right.Height > 0) result.Add(right);
205         return result;
206     }
207 
208     /// <summary>
209     /// 传入被拆分的矩形和填充的不可拆分的矩形列表
210     /// </summary>
211     /// <param name="container">被拆分的矩形</param>
212     /// <param name="noSplitRects">填充的矩形列表</param>
213     /// <returns></returns>
214     public static List<Rect2D> GetUnIntersectAreas(Rect2D container, List<Rect2D> noSplitRects)
215     {
216         var rects = new List<Rect2D> { container };
217         foreach (var item in noSplitRects)
218         {
219             List<Rect2D> items = new List<Rect2D>();
220             int i = 0;
221             while (i < rects.Count)
222             {
223                 var list = rects[i].GetUnIntersectAreas(item);
224                 if (list != null && list.Count > 0)
225                 {
226                     items.AddRange(list);
227                     rects.RemoveAt(i);
228                 }
229                 else if (item.Contains(rects[i]))
230                     rects.RemoveAt(i);
231                 else
232                 {
233                     i++;
234                 }
235             }
236             if (items.Count > 0)
237             {
238                 rects.AddRange(items);
239             }
240         }
241         return rects;
242     }
243 }
View Code