|
@@ -0,0 +1,269 @@
|
|
|
|
+/*-------------------------------------------------------------------------
|
|
|
|
+ * 功能描述:PolygonUtil
|
|
|
|
+ * 作者:xulisong
|
|
|
|
+ * 创建时间: 2019/4/29 17:36:49
|
|
|
|
+ * 版本号:v1.0
|
|
|
|
+ * -------------------------------------------------------------------------*/
|
|
|
|
+
|
|
|
|
+using System;
|
|
|
|
+using System.Collections.Generic;
|
|
|
|
+using System.Linq;
|
|
|
|
+using System.Text;
|
|
|
|
+using System.Threading.Tasks;
|
|
|
|
+using System.Windows;
|
|
|
|
+using Autodesk.Revit.DB;
|
|
|
|
+using SAGA.DotNetUtils.Extend;
|
|
|
|
+using SAGA.RevitUtils.Extends;
|
|
|
|
+
|
|
|
|
+namespace SAGA.RevitUtils.Utils
|
|
|
|
+{
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// 多边形相关算法
|
|
|
|
+ /// </summary>
|
|
|
|
+ public class PolygonUtil
|
|
|
|
+ {
|
|
|
|
+ public static List<Polygon> SplitToConvexPolygons(Polygon polygon)
|
|
|
|
+ {
|
|
|
|
+ List<Polygon> polygons = new List<Polygon>();
|
|
|
|
+ List<Polygon> tempPolygons = new List<Polygon>() { polygon };
|
|
|
|
+ for (int i = 0; i < tempPolygons.Count; i++)
|
|
|
|
+ {
|
|
|
|
+ var childPolygons = SplitPolygons(tempPolygons[i]);
|
|
|
|
+ if (childPolygons.Count == 1)
|
|
|
|
+ {
|
|
|
|
+ polygons.AddRange(childPolygons);
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ tempPolygons.AddRange(childPolygons);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return polygons;
|
|
|
|
+ }
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// 分割多边形
|
|
|
|
+ /// </summary>
|
|
|
|
+ /// <param name="polygon"></param>
|
|
|
|
+ /// <returns>如果是凹多边形,则返回多个。如果是凸多边形则返回一个本身</returns>
|
|
|
|
+ private static List<Polygon> SplitPolygons(Polygon polygon)
|
|
|
|
+ {
|
|
|
|
+ /*
|
|
|
|
+ * 循环末尾最后一条边需不需要判定。应该可以忽略
|
|
|
|
+ */
|
|
|
|
+ if (polygon.Points.Count == 3)
|
|
|
|
+ {
|
|
|
|
+ return new List<Polygon>() { polygon };
|
|
|
|
+ }
|
|
|
|
+ var basePoints = polygon.Points;
|
|
|
|
+ #region 找到多边形中,y值最小的点
|
|
|
|
+ var bottomPoint = basePoints[0];
|
|
|
|
+ var bottomPointIndex = 0;
|
|
|
|
+ for (int i = 1; i < basePoints.Count; i++)
|
|
|
|
+ {
|
|
|
|
+ var usePoint = basePoints[i];
|
|
|
|
+ if (usePoint.Y.IsLess(bottomPoint.Y))
|
|
|
|
+ {
|
|
|
|
+ bottomPoint = usePoint;
|
|
|
|
+ bottomPointIndex = i;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ #endregion
|
|
|
|
+ var totalPoint = basePoints.Count;
|
|
|
|
+ #region 整理新的集合,以y值最小点为起点遍历
|
|
|
|
+ List<XYZ> newPoints = new List<XYZ>();
|
|
|
|
+ for (int i = 0; i < totalPoint; i++)
|
|
|
|
+ {
|
|
|
|
+ var useIndex = (bottomPointIndex + i) % totalPoint;
|
|
|
|
+ newPoints.Add(basePoints[useIndex]);
|
|
|
|
+ }
|
|
|
|
+ #endregion
|
|
|
|
+
|
|
|
|
+ for (int i = 0; i < totalPoint - 1; i++)
|
|
|
|
+ {
|
|
|
|
+ var start = newPoints[i];
|
|
|
|
+ var end = newPoints[i + 1];
|
|
|
|
+ var baseVector = end - start;
|
|
|
|
+ bool needSplit = false;
|
|
|
|
+ int splitStart = -1, splitEnd = -1;
|
|
|
|
+ for (int num = 0; num < totalPoint - 2; num++)
|
|
|
|
+ {
|
|
|
|
+ var useIndex = (i + 2 + num) % totalPoint;
|
|
|
|
+ var judgePoint = newPoints[useIndex];
|
|
|
|
+ var refVector = judgePoint - end;
|
|
|
|
+ //三维立面,判断叉乘的正负,比较叉乘结果的Z值
|
|
|
|
+ if (!needSplit && baseVector.CrossProduct( refVector).Z.IsLess(0))
|
|
|
|
+ {
|
|
|
|
+ //出现拐点,分割多边形.使用拐点加上拐点前后构成一个三角形
|
|
|
|
+ needSplit = true;
|
|
|
|
+ splitStart = (useIndex - 1);
|
|
|
|
+ if (splitStart < 0)
|
|
|
|
+ {
|
|
|
|
+ splitStart = totalPoint - 1;
|
|
|
|
+ }
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ if (needSplit && baseVector.CrossProduct(refVector).Z.IsThanEq(0))
|
|
|
|
+ {
|
|
|
|
+ splitEnd = useIndex;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (needSplit)
|
|
|
|
+ {
|
|
|
|
+ List<XYZ> aPoints = new List<XYZ>();
|
|
|
|
+ List<XYZ> bPoints = new List<XYZ>();
|
|
|
|
+ if (splitEnd == -1)
|
|
|
|
+ {
|
|
|
|
+ splitEnd = (splitStart + 2) % totalPoint;
|
|
|
|
+ }
|
|
|
|
+ if (splitEnd < splitStart)
|
|
|
|
+ {
|
|
|
|
+ splitEnd += totalPoint;
|
|
|
|
+ }
|
|
|
|
+ int num = Math.Abs(splitEnd - splitStart) + 1;
|
|
|
|
+ for (int index = 0; index < num; index++)
|
|
|
|
+ {
|
|
|
|
+ aPoints.Add(newPoints[(splitStart + index) % totalPoint]);
|
|
|
|
+ }
|
|
|
|
+ for (int index = 0; index < (totalPoint - num + 2); index++)
|
|
|
|
+ {
|
|
|
|
+ bPoints.Add(newPoints[(splitEnd + index) % totalPoint]);
|
|
|
|
+ }
|
|
|
|
+ List<Polygon> polygons = new List<Polygon>();
|
|
|
|
+ polygons.Add(new Polygon(aPoints));
|
|
|
|
+ polygons.Add(new Polygon(bPoints));
|
|
|
|
+ return polygons;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return new List<Polygon>() { polygon };
|
|
|
|
+ }
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// 判断两个凸多边形是否相交
|
|
|
|
+ /// </summary>
|
|
|
|
+ /// <param name="polygon1"></param>
|
|
|
|
+ /// <param name="polygon2"></param>
|
|
|
|
+ /// <returns></returns>
|
|
|
|
+ public static bool IsConvexIntersection(Polygon polygon1, Polygon polygon2)
|
|
|
|
+ {
|
|
|
|
+ /*
|
|
|
|
+ * 分离轴方法;
|
|
|
|
+ * 以两个多边形的边的法线为轴做投影。
|
|
|
|
+ * 如果存在一条轴中投影没有重叠,则两个凸多边形不相交
|
|
|
|
+ */
|
|
|
|
+ List<XYZ> useVectors = new List<XYZ>();
|
|
|
|
+ List<List<XYZ>> pointsCollection = new List<List<XYZ>>()
|
|
|
|
+ {polygon1.Points.ToList(), polygon2.Points.ToList()};
|
|
|
|
+ foreach (var points in pointsCollection)
|
|
|
|
+ {
|
|
|
|
+ for (int i = 0; i < points.Count; i++)
|
|
|
|
+ {
|
|
|
|
+ var start = points[i];
|
|
|
|
+ var end = points[(i + 1) % points.Count];
|
|
|
|
+ var baseDirection = end - start;
|
|
|
|
+ if (baseDirection.GetLength().IsZero())
|
|
|
|
+ {
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ baseDirection.Normalize();
|
|
|
|
+ var crossDirection = new XYZ(baseDirection.Y, -baseDirection.X,0);
|
|
|
|
+ if (useVectors.Any(v => VectorUtil.IsParallel(v, crossDirection)))
|
|
|
|
+ {
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ //到指定轴的投影区域
|
|
|
|
+ var range1 = VectorUtil.CalcProjectRange(crossDirection, pointsCollection[0]);
|
|
|
|
+ var range2 = VectorUtil.CalcProjectRange(crossDirection, pointsCollection[1]);
|
|
|
|
+ //大于0,才算有重叠
|
|
|
|
+ useVectors.Add(crossDirection);
|
|
|
|
+ if (range1.IntersectionTest(range2) < 1)
|
|
|
|
+ {
|
|
|
|
+ //如果存在分离轴,则图形不相交
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// 判断两个多边形是否相交
|
|
|
|
+ /// </summary>
|
|
|
|
+ /// <param name="polygon1"></param>
|
|
|
|
+ /// <param name="polygon2"></param>
|
|
|
|
+ /// <returns></returns>
|
|
|
|
+ public static bool IsIntersection(Polygon polygon1, Polygon polygon2)
|
|
|
|
+ {
|
|
|
|
+ if (!polygon1.Box.Intersects(polygon2.Box, 0))
|
|
|
|
+ {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ /*
|
|
|
|
+ * 分离轴方法
|
|
|
|
+ */
|
|
|
|
+ var polygonCollection1 = polygon1.ChildrenConvexPolygons;// SplitToConvexPolygons(polygon1);
|
|
|
|
+ var polygonCollection2 = polygon2.ChildrenConvexPolygons;//SplitToConvexPolygons(polygon2);
|
|
|
|
+ foreach (var outPolygon in polygonCollection1)
|
|
|
|
+ {
|
|
|
|
+ foreach (var inPolygon in polygonCollection2)
|
|
|
|
+ {
|
|
|
|
+ if (IsConvexIntersection(outPolygon, inPolygon))
|
|
|
|
+ {
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// 判断annular1,是否在annular2的内轮廓中
|
|
|
|
+ /// </summary>
|
|
|
|
+ /// <param name="annular1"></param>
|
|
|
|
+ /// <param name="annular2"></param>
|
|
|
|
+ /// <returns></returns>
|
|
|
|
+ public static bool IsInInnerPolygon(Annular annular1, Annular annular2)
|
|
|
|
+ {
|
|
|
|
+ var out1 = annular1.OutPolygon;
|
|
|
|
+ var inPolygon2 = annular2.InPolygons;
|
|
|
|
+ foreach (var polygon in inPolygon2)
|
|
|
|
+ {
|
|
|
|
+ if (IsIntersection(polygon, out1))
|
|
|
|
+ {
|
|
|
|
+ var pointList = polygon.ToList();
|
|
|
|
+ if (out1.All(p => p.PointInPolygonByRay(pointList) > -1))
|
|
|
|
+ {
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// 判断两个多边形是否相交
|
|
|
|
+ /// </summary>
|
|
|
|
+ /// <param name="annular1"></param>
|
|
|
|
+ /// <param name="annular2"></param>
|
|
|
|
+ /// <returns></returns>
|
|
|
|
+ public static bool IsIntersection(Annular annular1, Annular annular2)
|
|
|
|
+ {
|
|
|
|
+ /*
|
|
|
|
+ * 分离轴方法
|
|
|
|
+ */
|
|
|
|
+ var out1 = annular1.OutPolygon;
|
|
|
|
+ var out2 = annular2.OutPolygon;
|
|
|
|
+ if (IsIntersection(out1, out2))
|
|
|
|
+ {
|
|
|
|
+ //如果相交,检测内轮廓关系,判断是否真实相交
|
|
|
|
+ if (IsInInnerPolygon(annular1, annular2) || IsInInnerPolygon(annular2, annular1))
|
|
|
|
+ {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|