Exemplo n.º 1
0
    /// <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));
    }