基于C#的多边形冲突检测

之前在项目上碰到了一个多边形冲突检测的问题,经百度、bing、google,发现目前已有的方案,要么是场景覆盖不全,要么是通过第三方类库实现(而这些第三方类库几乎是无法逆向反编译的),而项目中禁止使用第三方类库,遂自己实现了此算法。

场景是这样的,有两个多边形,多边形A和多变型B,需要判断多边形B是否在多变型A内,即多边形B是否是多边形A的子多边形。

 

  1. B的点全部在A内
  2. A的点全部在B外
  3. A的线段与B的线段没有相交

接下来进行实现

第一步:创建多边形类

 多边形

第二步:创建点类

 

第三步:创建线段类

 线段

第四步:创建线段的类型枚举

 View Code

第五步:在多边形类中增加冲突检测方法

复制代码
  1 /// <summary>
  2 /// 多边形冲突检测
  3 /// </summary>
  4 public bool CheckIfInArea(Area_Dto area)
  5 {
  6     if (area.LineSagements == null)
  7     {
  8         return true;
  9     }
 10     //若子点有在父外的则结束
 11     foreach (Point_Dto point in this.Points)
 12     {
 13         if (!point.CheckIfInArea(area))
 14             return false;
 15     }
 16     //若父点有在子内的则结束
 17     foreach (Point_Dto point in area.Points)
 18     {
 19         if (point.CheckIfInChildArea(this))
 20             return false;
 21     }
 22     //所有子线段与父线段没有相交则不冲突
 23     if (WhetherPolygonIntersection(area))
 24     {
 25         foreach (LineSagement_Dto edg in this.LineSagements)
 26         {
 27             if (edg.Intersection.Any())
 28             {
 29                 if (edg.FunType == LineType_Enum.XX)
 30                 {
 31                     List<Point_Dto> jiaodainList = edg.Intersection.OrderBy(m => m.Y).ToList();
 32                     for (int i = 0; i < jiaodainList.Count - 1; i++)
 33                     {
 34                         Point_Dto start = jiaodainList[i];
 35                         Point_Dto end = jiaodainList[i + 1];
 36                         Point_Dto z = new Point_Dto(start.X, start.Y + ((end.Y - start.Y) / 2));
 37                         if (z.CheckIfInArea(area))
 38                         {
 39                             continue;
 40                         }
 41                         else
 42                         {
 43                             return false;
 44                         }
 45                     }
 46                 }
 47                 else if (edg.FunType == LineType_Enum.YY)
 48                 {
 49                     List<Point_Dto> jiaodainList = edg.Intersection.OrderBy(m => m.X).ToList();
 50                     for (int i = 0; i < jiaodainList.Count - 1; i++)
 51                     {
 52                         Point_Dto start = jiaodainList[i];
 53                         Point_Dto end = jiaodainList[i + 1];
 54                         Point_Dto z = new Point_Dto(start.X + ((end.X - start.X) / 2), start.Y);
 55                         if (z.CheckIfInArea(area))
 56                         {
 57                             continue;
 58                         }
 59                         else
 60                         {
 61                             return false;
 62                         }
 63                     }
 64                 }
 65                 else if (edg.FunType == LineType_Enum.XnXYnY)
 66                 {
 67                     if (edg.Start.Y <= edg.End.Y)
 68                     {
 69                         List<Point_Dto> jiaodainList = edg.Intersection.OrderBy(m => m.X).ThenBy(m => m.Y).ToList();
 70                         for (int i = 0; i < jiaodainList.Count - 1; i++)
 71                         {
 72                             Point_Dto start = jiaodainList[i];
 73                             Point_Dto end = jiaodainList[i + 1];
 74                             Point_Dto z = new Point_Dto(start.X + ((end.X - start.X) / 2), start.Y + ((end.Y - start.Y) / 2));
 75                             if (z.CheckIfInArea(area))
 76                             {
 77                                 continue;
 78                             }
 79                             else
 80                             {
 81                                 return false;
 82                             }
 83                         }
 84                     }
 85                     else
 86                     {
 87                         List<Point_Dto> jiaodainList = edg.Intersection.OrderBy(m => m.X).ThenByDescending(m => m.Y).ToList();
 88                         for (int i = 0; i < jiaodainList.Count - 1; i++)
 89                         {
 90                             Point_Dto start = jiaodainList[i];
 91                             Point_Dto end = jiaodainList[i + 1];
 92                             Point_Dto z = new Point_Dto(start.X + ((end.X - start.X) / 2), start.Y - ((start.Y - end.Y) / 2));
 93                             if (z.CheckIfInArea(area))
 94                             {
 95                                 continue;
 96                             }
 97                             else
 98                             {
 99                                 return false;
100                             }
101                         }
102                     }
103                 }
104             }
105         }
106     }
107     else
108     {
109         return true;
110     }
111     return true;
112 }
复制代码

第六步:在点的类中增加点与线段关系的判断方法

复制代码
 1 /// <summary>
 2 /// 此点向右引出的射线是否穿过sagement
 3 /// 穿过的定义:
 4 ///     此点在sagement的顶点上
 5 ///     此点在sagement上
 6 ///     此点不符合以上两种情况且此点引出的射线穿过sagement
 7 /// </summary>
 8 /// <param name="sagement"></param>
 9 /// <returns>True:穿过线段 False:没有穿过线段</returns>
10 public PointWithLineSagementState_Enum CheckPointInLineSagement(LineSagement_Dto sagement)
11 {
12     double px = this.X;
13     double py = this.Y;
14     //bool flag = false;
15 
16 
17     Point_Dto pi = sagement.Start;
18     Point_Dto pj = sagement.End;
19     double sx = pi.X; double sy = pi.Y;
20     double tx = pj.X; double ty = pj.Y;
21 
22     //点与线段顶点重合
23     bool psTf = (px == sx && py == sy);
24     bool ptTf = (px == tx && py == ty);
25     if (psTf || ptTf)
26     {
27         return PointWithLineSagementState_Enum.VertexOverlap;
28     }
29     switch (sagement.FunType)
30     {
31         case LineType_Enum.XX:
32             if (px == pi.X && ((py <= sy && py >= ty) || (py >= sy && py <= ty)))
33                 return PointWithLineSagementState_Enum.OnLineSagement;
34             break;
35         case LineType_Enum.YY:
36             if (py == pi.Y && ((px >= sx && px <= tx) || (px <= sx && px >= tx)))
37                 return PointWithLineSagementState_Enum.OnLineSagement;
38             break;
39         case LineType_Enum.XnXYnY:
40         default:
41             break;
42     }
43     //判断线段端点是否在射线两侧
44     if ((sy < py && ty >= py) || (sy >= py && ty < py))
45     {
46         //线段上与射线Y坐标相同的点的X坐标
47         double x = sx + (py - sy) * (tx - sx) / (ty - sy);
48         //点在线段上
49         if (x == px)
50         {
51             return PointWithLineSagementState_Enum.OnLineSagement;
52         }
53         //射线穿过线段
54         if (x > px)
55         {
56             return PointWithLineSagementState_Enum.Cross;
57         }
58     }
59     return PointWithLineSagementState_Enum.UnCross;
60 }
61 
62 /// <summary>
63 /// 点线的关系
64 /// </summary>
65 public enum PointWithLineSagementState_Enum
66 {
67     /// <summary>
68     /// 顶点重合
69     /// </summary>
70     VertexOverlap,
71     /// <summary>
72     /// 相交
73     /// </summary>
74     Cross,
75     /// <summary>
76     /// 不相交
77     /// </summary>
78     UnCross,
79     /// <summary>
80     /// 在线段上
81     /// </summary>
82     OnLineSagement
83 }
复制代码

第七步:在点的类中实现子多边形的点是否在父多边形内的判断方法

 子多边形的点是否在父多边形内

第八步:在点的类中实现父多边形的点是否在子多边形内的判断方法

 父多边形的点是否在子多边形内

第九步:在多边形的类中实现多边形自身的线段是否与另外一个多边形的所有线段相交的方法

 线段是否与多边形的所有线段有相交

 

“老天爷给你的任何机会,你也不会珍惜,更不会深入下去,你认为自己就是穷命,最喜欢通过脉脉阅读免费的职场技巧。如果你还是杠精思维,任何事情,跑上来先论证困难,给自己一个不干不参与的充分理由,那你完了。人生不过是短短十五年的机会,到了四十岁,你还在屌丝堆里,啥也不干,那你没希望了。”
posted @ 2021-07-02 15:18  dreamw  阅读(127)  评论(0编辑  收藏  举报