/// <summary> /// 边是否相交 /// </summary> /// <param name="_edgeA">边A</param> /// <param name="_edgeB">边B</param> /// <returns>是否相交</returns> public static bool EdgeIntersection(PolygonEdge2D _edgeA, PolygonEdge2D _edgeB) { Vector3 p1 = _edgeA.vertexA.position; Vector3 p2 = _edgeA.vertexB.position; Vector3 q1 = _edgeB.vertexA.position; Vector3 q2 = _edgeB.vertexB.position; Vector3 v1 = Vector3.Cross(p2 - p1, q1 - p1).normalized; Vector3 v2 = Vector3.Cross(p2 - p1, q2 - p1).normalized; Vector3 v3 = Vector3.Cross(q2 - q1, p1 - q1).normalized; Vector3 v4 = Vector3.Cross(q2 - q1, p2 - q1).normalized; return(Vector3.Dot(v1, v2) < 0 && Vector3.Dot(v3, v4) < 0); }
/// <summary> /// 边是否相交 /// </summary> /// <param name="_edgeA">边A</param> /// <param name="_edgeB">边B</param> /// <param name="_point">交点</param> /// <returns>是否相交</returns> public static bool EdgeIntersection(PolygonEdge2D _edgeA, PolygonEdge2D _edgeB, ref Vector3 _point) { bool isCross = EdgeIntersection(_edgeA, _edgeB); if (isCross) { float a1 = _edgeA.vertexA.position.x; float b1 = _edgeA.vertexA.position.y; float a2 = _edgeA.vertexB.position.x; float b2 = _edgeA.vertexB.position.y; float c1 = _edgeB.vertexA.position.x; float d1 = _edgeB.vertexA.position.y; float c2 = _edgeB.vertexB.position.x; float d2 = _edgeB.vertexB.position.y; _point = Vector3.zero; _point.x = ((a2 - a1) * (c2 - c1) * (d2 - b2) + (b2 - b1) * (c2 - c1) * a2 - (d2 - d1) * (a2 - a1) * c2) / ((b2 - b1) * (c2 - c1) - (d2 - d1) * (a2 - a1)); _point.y = (b2 - b1) / (a2 - a1) * (_point.x - a2) + b2; } return(isCross); }
/// <summary> /// 多边形三角形 /// </summary> /// <param name="_vertexA">顶点A</param> /// <param name="_vertexB">顶点B</param> /// <param name="_vertexC">顶点C</param> public PolygonTriangle2D(PolygonPoint2D _vertexA, PolygonPoint2D _vertexB, PolygonPoint2D _vertexC) { //Vector3 ab = (_vertexB.position - _vertexA.position).normalized; //Vector3 ac = (_vertexC.position - _vertexA.position).normalized; //Vector3 vc = Vector3.Cross(ab, ac); //if (vc.z > 0) //{ // //逆时针三角形,B,C点交换 // PolygonPoint2D p = _vertexC; // _vertexC = _vertexB; // _vertexB = p; //} vertexs = new PolygonPoint2D[3] { _vertexA, _vertexB, _vertexC }; edges = new PolygonEdge2D[3] { new PolygonEdge2D(_vertexA, _vertexB), new PolygonEdge2D(_vertexB, _vertexC), new PolygonEdge2D(_vertexC, _vertexA) }; circumCircleCenter = Geometry2DUtility.TriangleCircumCircle(_vertexA.position, _vertexB.position, _vertexC.position); circumCircleRadius = Vector3.Distance(circumCircleCenter, _vertexA.position); key = (_vertexA.index.ToString() + _vertexB.index.ToString() + _vertexC.ToString()).UniqueHashCode(); }
/// <summary> /// 边切割三角形 /// </summary> /// <param name="_triangle">三角形</param> /// <param name="_edge">边</param> /// <returns></returns> static List <PolygonTriangle2D> EdgeCutTriangle(PolygonTriangle2D _triangle, PolygonEdge2D _edge) { List <PolygonTriangle2D> triangles = new List <PolygonTriangle2D>(); return(triangles); }
/// <summary> /// 生成三角剖分结果 /// </summary> /// <param name="_vertexs">离散顶点集</param> /// <param name="_polygonBoundsPointIndexs">多边形边界点索引</param> /// <returns>三角剖分结果</returns> public static PolygonDelaunayResult2D BuilderDelaunay2D(List <Vector3> _vertexs, List <int> _polygonBoundsPointIndexs) { List <PolygonPoint2D> polygonVertexs = new List <PolygonPoint2D>(); Bounds polygonBounds = new Bounds(); PolygonTriangle2D polygonSupperTriangle = new PolygonTriangle2D(new PolygonPoint2D(0, Vector3.zero), new PolygonPoint2D(1, Vector3.zero), new PolygonPoint2D(2, Vector3.zero)); //已完成的剖分三角形 List <PolygonTriangle2D> polygonDelaunayTriangles = new List <PolygonTriangle2D>(); //多边形边界边 Dictionary <int, PolygonEdge2D> polygonBoundsEdgeMaping = new Dictionary <int, PolygonEdge2D>(); if (_vertexs.Count >= 3) { #region 分析点 Vector3 max = Vector3.one * float.MinValue; Vector3 min = Vector3.one * float.MaxValue; //构建顶点 for (int i = 0; i < _vertexs.Count; i++) { polygonVertexs.Add(new PolygonPoint2D(i, _vertexs[i])); min.x = Mathf.Min(min.x, _vertexs[i].x); min.y = Mathf.Min(min.y, _vertexs[i].y); min.z = Mathf.Min(min.z, _vertexs[i].z); max.x = Mathf.Max(max.x, _vertexs[i].x); max.y = Mathf.Max(max.y, _vertexs[i].y); max.z = Mathf.Max(max.z, _vertexs[i].z); } PolygonEdge2D tempPolygonEdge2D = null; if (_polygonBoundsPointIndexs != null && _polygonBoundsPointIndexs.Count > 0) { for (int i = 0; i < _polygonBoundsPointIndexs.Count; i++) { if (i < _polygonBoundsPointIndexs.Count - 1) { tempPolygonEdge2D = new PolygonEdge2D(polygonVertexs[i], polygonVertexs[i + 1]); } else { tempPolygonEdge2D = new PolygonEdge2D(polygonVertexs[i], polygonVertexs[0]); } polygonBoundsEdgeMaping.Add(tempPolygonEdge2D.key, tempPolygonEdge2D); } } //x轴从左往右排序 polygonVertexs.Sort((x, y) => { return(x.position.x >= y.position.x ? 1 : -1); }); //y轴从下往上排序 polygonVertexs.Sort((x, y) => { return((x.position.x == y.position.x && x.position.y >= y.position.y) ? 1 : -1); }); //构建一个包含所有点集的三角形 polygonBounds = new Bounds(Vector3.Lerp(min, max, 0.5f), Vector3.zero); polygonBounds.SetMinMax(min, max); float raudis = Vector3.Distance(polygonBounds.min, polygonBounds.max) * 0.6f; Vector3 tvc = polygonBounds.center + Vector3.back * raudis; Vector3 tvl = polygonBounds.min + Vector3.back * (raudis - Mathf.Abs(polygonBounds.extents.z)); Vector3 axis = tvc - polygonBounds.center; Vector3 vc = (tvl - tvc).normalized * raudis * 2; Vector3 tp0 = vc + tvc; vc = Quaternion.AngleAxis(120, axis) * vc; Vector3 tp1 = vc + tvc; vc = Quaternion.AngleAxis(120, axis) * vc; Vector3 tp2 = vc + tvc; tp0.z = tp1.z = tp2.z = 0; polygonSupperTriangle = new PolygonTriangle2D(new PolygonPoint2D(_vertexs.Count, tp0, true), new PolygonPoint2D(_vertexs.Count + 1, tp1, true), new PolygonPoint2D(_vertexs.Count + 2, tp2, true)); #endregion #region 角剖分 //缓存的剖分三角形 List <PolygonTriangle2D> tempDelaunayTriangles = new List <PolygonTriangle2D>(); //等待检测的三角形 List <PolygonTriangle2D> validateTriangles = new List <PolygonTriangle2D>() { polygonSupperTriangle }; //从第一个顶点开始,进行三角剖分检测 int count = polygonVertexs.Count; for (int i = 0; i < count; i++) { List <PolygonTriangle2D> delTris = FindDelaunayTriangle(polygonVertexs[i], ref validateTriangles); if (delTris.Count > 0) { tempDelaunayTriangles.AddRange(delTris); } } tempDelaunayTriangles.AddRange(validateTriangles); #endregion #region 除超级三角形 //需要补边的三角形 List <PolygonTriangle2D> pushEdgeTriangles = new List <PolygonTriangle2D>(); int supperPointCount = 0; foreach (PolygonTriangle2D tri in tempDelaunayTriangles) { //缓存三角形有任意点是超三角形的点 supperPointCount = 0; foreach (PolygonPoint2D v in tri.vertexs) { if (v.isSupperPoint) { supperPointCount++; } } if (supperPointCount > 0) { pushEdgeTriangles.Add(tri); } else { polygonDelaunayTriangles.Add(tri); foreach (PolygonEdge2D edge in tri.edges) { polygonBoundsEdgeMaping.Remove(edge.key); } } } #endregion #region 对删除的超级三角形与边界比对,补充未绘制的边界三角形 //点索引 int pointIndex = _vertexs.Count; //交点 Vector3 point = Vector3.zero; //边是否相交 bool isIntersection = false; //边交点 Dictionary <int, Dictionary <int, PolygonPoint2D> > edgePoint = new Dictionary <int, Dictionary <int, PolygonPoint2D> >(); //三角形被边界线切割后的多边形点 Dictionary <int, PolygonPoint2D> polygonPoints = new Dictionary <int, PolygonPoint2D>(); //检测三角形 foreach (PolygonTriangle2D tri in pushEdgeTriangles) { polygonPoints.Clear(); foreach (PolygonEdge2D triEdge in tri.edges) { foreach (PolygonEdge2D edge in polygonBoundsEdgeMaping.Values) { #region 求交点 isIntersection = false; point = Vector3.zero; if (edgePoint.ContainsKey(triEdge.key) && edgePoint[triEdge.key].ContainsKey(edge.key)) { isIntersection = true; } else if (Geometry2DUtility.EdgeIntersection(triEdge, edge, ref point)) { isIntersection = true; if (!edgePoint.ContainsKey(triEdge.key)) { edgePoint.Add(triEdge.key, new Dictionary <int, PolygonPoint2D>()); } if (!edgePoint[triEdge.key].ContainsKey(edge.key)) { edgePoint[triEdge.key].Add(edge.key, new PolygonPoint2D(pointIndex, point)); } polygonVertexs.Add(edgePoint[triEdge.key][edge.key]); pointIndex++; } if (isIntersection) { //加入交点 if (!polygonPoints.ContainsKey(edgePoint[triEdge.key][edge.key].index)) { polygonPoints.Add(edgePoint[triEdge.key][edge.key].index, edgePoint[triEdge.key][edge.key]); } } #endregion } } if (polygonPoints.Count > 0) { //如果有任意交点,保留三角形非超级点 foreach (PolygonPoint2D p in tri.vertexs) { if (!p.isSupperPoint) { if (!polygonPoints.ContainsKey(p.index)) { polygonPoints.Add(p.index, p); } } } if (polygonPoints.Count >= 3) { List <PolygonPoint2D> pps = new List <PolygonPoint2D>(polygonPoints.Values); if (pps.Count == 3) { polygonDelaunayTriangles.Add( new PolygonTriangle2D(pps[0], pps[1], pps[2])); } else if (pps.Count == 4) { //如果有两个交点,则pps中前两个是交点,后两个是原三角形的两个顶点 //交点与顶点各取一点组成两条边,然后看两条边是否相交,相交则是对角线,不相交则不是 //找到对角线后,与非对角线点的另外一个交点和顶点组成新的两个三角形 PolygonEdge2D edge1 = new PolygonEdge2D(pps[0], pps[2]); PolygonEdge2D edge2 = new PolygonEdge2D(pps[1], pps[3]); if (Geometry2DUtility.EdgeIntersection(edge1, edge2)) { //0,2,1 和0,2,3 组成两个新的三角形 polygonDelaunayTriangles.Add( new PolygonTriangle2D(pps[0], pps[2], pps[1])); polygonDelaunayTriangles.Add( new PolygonTriangle2D(pps[0], pps[2], pps[3])); } else { //0,3,1 和 0,3,2 组成两个新的三角形 polygonDelaunayTriangles.Add( new PolygonTriangle2D(pps[0], pps[3], pps[1])); polygonDelaunayTriangles.Add( new PolygonTriangle2D(pps[0], pps[3], pps[2])); } } } } } #endregion } else { throw new UnityException("There are not enough vertexs to constitute polygon,the vertexs are least of three."); } return(new PolygonDelaunayResult2D(polygonVertexs, polygonBounds, polygonSupperTriangle, polygonDelaunayTriangles)); }