Exemplo n.º 1
0
    /// <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="_vh">顶点Helper</param>
    /// <param name="_masks">绘制组</param>
    protected virtual void OnFillExceptMask(VertexHelper _vh, List <AbsUIGuideGraphic> _masks)
    {
        #region 屏幕矩形
        GraphicRect2D sceneRect = new GraphicRect2D(-1, this);
        #endregion

        #region 遮罩矩形
        List <GraphicRect2D> maskRect = new List <GraphicRect2D>();
        GraphicRect2D        rect;
        for (int i = 0; i < _masks.Count; i++)
        {
            rect = new GraphicRect2D(i, _masks[i].graphic);
            maskRect.Add(rect);
        }

        //求两矩形填充点和矩形在屏幕上的填充点
        List <Vector3> useVertexs      = new List <Vector3>();
        List <Vector3> tempVertexs     = new List <Vector3>();
        List <Vector3> validateVertexs = new List <Vector3>();
        if (maskRect.Count <= 1)
        {
            tempVertexs = maskRect[0].IntersectionFill(sceneRect);
            if (tempVertexs.Count > 0)
            {
                validateVertexs.AddRange(tempVertexs);
            }
        }
        else
        {
            foreach (GraphicRect2D a in maskRect)
            {
                foreach (GraphicRect2D b in maskRect)
                {
                    tempVertexs = a.IntersectionFill(b);
                    if (tempVertexs.Count > 0)
                    {
                        validateVertexs.AddRange(tempVertexs);
                    }
                }
            }
        }
        #endregion

        validateVertexs.InsertRange(0, sceneRect.corners);

        #region 清理重复的点
        List <int> hasPoint = new List <int>();
        int        pk       = 0;
        Vector3    tp       = Vector3.zero;
        foreach (Vector3 cv in validateVertexs)
        {
            //顶点不超过屏幕
            tp.x = cv.x;
            tp.x = Mathf.Max(tp.x, sceneRect.rect.xMin);
            tp.x = Mathf.Min(tp.x, sceneRect.rect.xMax);
            tp.y = cv.y;
            tp.y = Mathf.Max(tp.y, sceneRect.rect.yMin);
            tp.y = Mathf.Min(tp.y, sceneRect.rect.yMax);
            //过滤重复点
            pk = (tp.x.ToString() + tp.y.ToString()).UniqueHashCode();
            if (!hasPoint.Contains(pk))
            {
                hasPoint.Add(pk);
                useVertexs.Add(tp);
            }
        }
        #endregion

        mDelaunayResult = Polygon2DUtility.BuilderDelaunay2D(useVertexs, new List <int>()
        {
            0, 1, 2, 3
        });

        #region 绘制三角面
        _vh.Clear();
        Vector4    uv           = (sprite != null) ? UnityEngine.Sprites.DataUtility.GetOuterUV(sprite) : Vector4.zero;
        UIVertex[] vertexs      = new UIVertex[mDelaunayResult.vertexs.Count];
        List <int> vertexIndexs = new List <int>();
        foreach (PolygonPoint2D p in mDelaunayResult.vertexs)
        {
            vertexs[p.index] = new UIVertex()
            {
                position = p.position, color = color, uv0 = Rect.PointToNormalized(sceneRect.rect, p.position)
            };
        }

        bool isInAnyRect = false;
        foreach (PolygonTriangle2D tri in mDelaunayResult.delaunayTriangle)
        {
            foreach (GraphicRect2D r in maskRect)
            {
                isInAnyRect =
                    Geometry2DUtility.IsPointInRect(tri.vertexs[0].position, r.rect) &&
                    Geometry2DUtility.IsPointInRect(tri.vertexs[1].position, r.rect) &&
                    Geometry2DUtility.IsPointInRect(tri.vertexs[2].position, r.rect);
                if (isInAnyRect)
                {
                    break;
                }
            }
            if (!isInAnyRect)
            {
                vertexIndexs.Add(tri.vertexs[0].index);
                vertexIndexs.Add(tri.vertexs[1].index);
                vertexIndexs.Add(tri.vertexs[2].index);
            }
        }
        _vh.AddUIVertexStream(new List <UIVertex>(vertexs), vertexIndexs);
        #endregion
    }
Exemplo n.º 3
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));
    }
    /// <summary>
    /// 除遮罩之外都填充
    /// </summary>
    /// <param name="_sceneRect">屏幕矩形</param>
    /// <param name="_masks">绘制组</param>
    protected virtual void OnFillExceptMask(Rect _sceneRect, List <AbsUIGuideGraphic> _masks)
    {
        Sprite  sprite                     = null;
        Image   image                      = null;
        Vector4 spriteUVRatio              = Vector4.zero;
        Vector4 spriteUV                   = Vector4.zero;
        Vector4 spriteUVClip               = Vector4.zero;
        Vector4 spriteBorder               = Vector4.zero;
        Vector4 rectUV                     = Vector4.zero;
        Vector4 sceneGraphicWh             = Vector4.zero;
        Vector4 graphicRectSlicedBorder    = Vector4.zero;
        Vector4 graphicUvSlicedBorderRatio = Vector4.zero;
        Vector2 rectMin                    = Vector2.zero;
        Vector2 rectMax                    = Vector2.zero;
        bool    isGraphicSliced            = false;

        sceneGraphicWh.x = _sceneRect.size.x;
        sceneGraphicWh.y = _sceneRect.size.y;
        Rect maskRect = new Rect();

        for (int i = 0; i < _masks.Count; i++)
        {
            spriteUV         = uvDefault;
            spriteUVClip     = uvDefault;
            spriteBorder     = Vector4.zero;
            isGraphicSliced  = false;
            maskRect         = _masks[i].graphic.GraphicLocalRectForVertexHelper();
            sceneGraphicWh.z = maskRect.size.x;
            sceneGraphicWh.w = maskRect.size.y;
            rectMin          = Rect.PointToNormalized(_sceneRect, maskRect.min);
            rectMax          = Rect.PointToNormalized(_sceneRect, maskRect.max);
            rectUV.Set(rectMin.x, rectMin.y, rectMax.x, rectMax.y);

            if (!Geometry2DUtility.IsPointInRect(maskRect.min, _sceneRect))
            {
                if (rectMin.x == 0)
                {
                    spriteUVClip.x = Mathf.InverseLerp(maskRect.min.x, maskRect.max.x, _sceneRect.min.x);
                }
                if (rectMin.y == 0)
                {
                    spriteUVClip.y = Mathf.InverseLerp(maskRect.min.y, maskRect.max.y, _sceneRect.min.y);
                }
            }

            if (_masks[i].graphic is Image)
            {
                image  = (Image)_masks[i].graphic;
                sprite = image.overrideSprite;
                if (sprite != null)
                {
                    spriteUV = UnityEngine.Sprites.DataUtility.GetOuterUV(sprite);
                    Texture2D texSrc = sprite.texture;
                    spriteUVRatio.x = sprite.rect.x / texSrc.width;
                    spriteUVRatio.y = sprite.rect.y / texSrc.height;
                    spriteUVRatio.z = sprite.rect.width / texSrc.width;
                    spriteUVRatio.w = sprite.rect.height / texSrc.height;

                    graphicRectSlicedBorder.x = sprite.border.x / _masks[i].graphic.GetPixelAdjustedRect().width * 0.5f;
                    graphicRectSlicedBorder.y = sprite.border.y / _masks[i].graphic.GetPixelAdjustedRect().height * 0.5f;
                    graphicRectSlicedBorder.z = sprite.border.z / _masks[i].graphic.GetPixelAdjustedRect().width * 0.5f;
                    graphicRectSlicedBorder.w = sprite.border.w / _masks[i].graphic.GetPixelAdjustedRect().height * 0.5f;
                    graphicRectSlicedBorder.z = 1 - graphicRectSlicedBorder.z;
                    graphicRectSlicedBorder.w = 1 - graphicRectSlicedBorder.w;

                    graphicUvSlicedBorderRatio.x = sprite.border.x / sprite.textureRect.width;
                    graphicUvSlicedBorderRatio.y = sprite.border.y / sprite.textureRect.height;
                    graphicUvSlicedBorderRatio.z = sprite.border.z / sprite.textureRect.width;
                    graphicUvSlicedBorderRatio.w = sprite.border.w / sprite.textureRect.height;
                }
                switch (image.type)
                {
                case Image.Type.Sliced:
                case Image.Type.Tiled:
                    isGraphicSliced = true;
                    break;
                }
            }
            material.SetTexture("_GraphicTex" + i, _masks[i].graphic.mainTexture);
            material.SetVector("_GraphicUvSlicedBorderRatio" + i, graphicUvSlicedBorderRatio);
            material.SetVector("_SceneGraphicWh" + i, sceneGraphicWh);
            material.SetVector("_GraphicUvRatio" + i, spriteUVRatio);
            material.SetVector("_GraphicUvMinMax" + i, spriteUV);
            material.SetVector("_GraphicUvMinMaxClip" + i, spriteUVClip);
            material.SetVector("_GraphicUvMaskForScene" + i, rectUV);
            material.SetInt("_isGraphicSliced" + i, isGraphicSliced ? 1 : 0);
            material.SetVector("_GraphicRectSlicedBorder" + i, graphicRectSlicedBorder);
        }
    }