Exemple #1
0
        /// <summary>
        ///     Describes whether validate polygon
        /// </summary>
        /// <param name="polygon">The polygon</param>
        /// <returns>The bool</returns>
        private static bool ValidatePolygon(Vertices polygon)
        {
            PolygonError errorCode = polygon.CheckPolygon();

            if (errorCode == PolygonError.InvalidAmountOfVertices || errorCode == PolygonError.AreaTooSmall ||
                errorCode == PolygonError.SideTooSmall || errorCode == PolygonError.NotSimple)
            {
                return(false);
            }

            if (
                errorCode ==
                PolygonError
                .NotCounterClockWise)     //NotCounterCloseWise is the last check in CheckPolygon(), thus we don't need to call ValidatePolygon again.
            {
                polygon.Reverse();
            }

            if (errorCode == PolygonError.NotConvex)
            {
                polygon = GiftWrap.GetConvexHull(polygon);
                return(ValidatePolygon(polygon));
            }

            return(true);
        }
        private ConvexHull2Test()
        {
            _pointCloud1 = new Vertices(PointCount);

            for (int i = 0; i < PointCount; i++)
            {
                float x = Rand.RandomFloat(-10, 10);
                float y = Rand.RandomFloat(-10, 10);

                _pointCloud1.Add(new Vector2(x, y));
            }

            _pointCloud2 = new Vertices(_pointCloud1);
            _pointCloud3 = new Vertices(_pointCloud1);

            //Melkman DOES NOT work on point clouds. It only works on simple polygons.
            _pointCloud1.Translate(new Vector2(-20, 30));
            _melkman = Melkman.GetConvexHull(_pointCloud1);

            //Giftwrap works on point clouds
            _pointCloud2.Translate(new Vector2(20, 30));
            _giftWrap = GiftWrap.GetConvexHull(_pointCloud2);

            //Chain hull also works on point clouds
            _pointCloud3.Translate(new Vector2(20, 10));
            _chainHull = ChainHull.GetConvexHull(_pointCloud3);
        }
        /// <summary>
        /// Updates data for the convex hull of the polygon.
        /// </summary>
        private void UpdateConvexHull()
        {
            // compute convex hull
            Vertices hull = GiftWrap.GetConvexHull(Polygon.Vertices);

            // update polygon lines
            convexHullLines = new PointF[hull.Count];
            for (int i = 0; i < hull.Count; ++i)
            {
                convexHullLines[i] = new PointF(hull[i].X, hull[i].Y);
            }

            // update valid/invalid vertices
            for (int i = 0; i < vertices.Count; ++i)
            {
                int index = hull.IndexOf(Polygon.Vertices[i]);
                if (index == -1)
                {
                    vertices[i] = new KeyValuePair <PointF, bool>(vertices[i].Key, false);
                }
                else
                {
                    vertices[i] = new KeyValuePair <PointF, bool>(vertices[i].Key, true);
                }
            }
        }
Exemple #4
0
        /// <summary>
        /// sets the vertices without copying over the data from verts to the local List.
        /// </summary>
        /// <param name="verts">Verts.</param>
        public void setVerticesNoCopy(Vertices verts)
        {
            Debug.Assert(verts.Count >= 3 && verts.Count <= Settings.maxPolygonVertices);
            _vertices = verts;

            if (Settings.useConvexHullPolygons)
            {
                // FPE note: This check is required as the GiftWrap algorithm early exits on triangles
                // So instead of giftwrapping a triangle, we just force it to be clock wise.
                if (_vertices.Count <= 3)
                {
                    _vertices.forceCounterClockWise();
                }
                else
                {
                    _vertices = GiftWrap.getConvexHull(_vertices);
                }
            }

            if (_normals == null)
            {
                _normals = new Vertices(_vertices.Count);
            }
            else
            {
                _normals.Clear();
            }

            // Compute normals. Ensure the edges have non-zero length.
            for (var i = 0; i < _vertices.Count; ++i)
            {
                var next = i + 1 < _vertices.Count ? i + 1 : 0;
                var edge = _vertices[next] - _vertices[i];
                Debug.Assert(edge.LengthSquared() > Settings.epsilon * Settings.epsilon);

                // FPE optimization: Normals.Add(MathHelper.Cross(edge, 1.0f));
                var temp = new Vector2(edge.Y, -edge.X);
                Nez.Vector2Ext.normalize(ref temp);
                _normals.Add(temp);
            }

            // Compute the polygon mass data
            computeProperties();
        }
        /// <summary>
        /// Makes convex hull from the polygon.
        /// </summary>
        public void MakeConvexHull()
        {
            // compute convex hull
            Vertices hull = GiftWrap.GetConvexHull(Polygon.Vertices);

            // remove all unused vertices from convex hull
            for (int i = 0; i < Polygon.Vertices.Count; ++i)
            {
                int index = hull.IndexOf(Polygon.Vertices[i]);
                if (index == -1)
                {
                    Polygon.Vertices.RemoveAt(i);
                    --i;
                }
            }

            // update data
            UpdateVertices();
        }
Exemple #6
0
    public static bool MakeHull(Mesh mesh, Transform tr, string path, ref ConvexData data)
    {
        GiftWrap gw = new GiftWrap();

        gw.Reset();

        List <Vector3> vecVertex = new List <Vector3>();
        Vector3        vmin      = Vector3.zero;
        Vector3        vmax      = Vector3.zero;

        Bounds bound = mesh.bounds;

        vmin = bound.min;
        vmax = bound.max;

        Vector3[] verts = mesh.vertices;
        for (int j = 0; j < mesh.vertexCount; ++j)
        {
            Vector3 wp = verts[j];
            if (null != tr)
            {
                wp = tr.TransformPoint(wp);
            }
            bool bnear = false;
            for (int k = 0; k < (int)vecVertex.Count; k++)
            {
                if ((wp - vecVertex[k]).magnitude < CLOSE_VERTEX_DISTANCE_THRESH)
                {
                    bnear = true;
                    break;
                }
            }
            if (!bnear)
            {
                vecVertex.Add(wp);
            }
        }

        int numallvert = vecVertex.Count;

        gw.SetVertexes(vecVertex);
        gw.ComputeConvexHull();

        path += "/" + System.DateTime.Now.ToString("dd-MM-yy-HH-mm-ss") + "_vts.txt";
        if (gw.ExceptionOccur())
        {
            gw.SaveVerticesToFile(path);
            gw.Reset();
            return(false);
        }

        ConvexPolytope cp = new ConvexPolytope();

        cp.Init(gw, (vmax - vmin).magnitude);

        if (cp.ExceptionOccur && cp.MinPatchNum > 20)
        {
            gw.SaveVerticesToFile(path);
            return(false);
        }

        int patchnum = Mathf.Min(cp.OriginPatchNum, Mathf.Max(10, cp.MinPatchNum));

        if (patchnum > MAX_FACE_IN_HULL)
        {
            gw.Reset();
            return(false);
        }
        else
        {
            cp.Goto(Mathf.Min(patchnum, MAX_FACE_IN_HULL));
        }

        gw.Reset();

        data.Reset();
        cp.ExportCHData(data);

        return(true);
    }
        public static List <Vertices> ConvexPartition(Vertices vertices, TriangulationAlgorithm algorithm, bool discardAndFixInvalid = true, float tolerance = 0.001f)
        {
            if (vertices.Count <= 3)
            {
                return new List <Vertices> {
                           vertices
                }
            }
            ;

            List <Vertices> results;

            switch (algorithm)
            {
            case TriangulationAlgorithm.Earclip:
                if (Settings.SkipSanityChecks)
                {
                    Debug.Assert(!vertices.IsCounterClockWise(), "The Earclip algorithm expects the polygon to be clockwise.");
                }
                else
                {
                    if (vertices.IsCounterClockWise())
                    {
                        Vertices temp = new Vertices(vertices);
                        temp.Reverse();
                        results = EarclipDecomposer.ConvexPartition(temp, tolerance);
                    }
                    else
                    {
                        results = EarclipDecomposer.ConvexPartition(vertices, tolerance);
                    }
                }
                break;

            case TriangulationAlgorithm.Bayazit:
                if (Settings.SkipSanityChecks)
                {
                    Debug.Assert(vertices.IsCounterClockWise(), "The polygon is not counter clockwise. This is needed for Bayazit to work correctly.");
                }
                else
                {
                    if (!vertices.IsCounterClockWise())
                    {
                        Vertices temp = new Vertices(vertices);
                        temp.Reverse();
                        results = BayazitDecomposer.ConvexPartition(temp);
                    }
                    else
                    {
                        results = BayazitDecomposer.ConvexPartition(vertices);
                    }
                }
                break;

            case TriangulationAlgorithm.Flipcode:
                if (Settings.SkipSanityChecks)
                {
                    Debug.Assert(vertices.IsCounterClockWise(), "The polygon is not counter clockwise. This is needed for Bayazit to work correctly.");
                }
                else
                {
                    if (!vertices.IsCounterClockWise())
                    {
                        Vertices temp = new Vertices(vertices);
                        temp.Reverse();
                        results = FlipcodeDecomposer.ConvexPartition(temp);
                    }
                    else
                    {
                        results = FlipcodeDecomposer.ConvexPartition(vertices);
                    }
                }
                break;

            case TriangulationAlgorithm.Seidel:
                results = SeidelDecomposer.ConvexPartition(vertices, tolerance);
                break;

            case TriangulationAlgorithm.SeidelTrapezoids:
                results = SeidelDecomposer.ConvexPartitionTrapezoid(vertices, tolerance);
                break;

            case TriangulationAlgorithm.Delauny:
                results = CDTDecomposer.ConvexPartition(vertices);
                break;

            default:
                throw new ArgumentOutOfRangeException("algorithm");
            }

            if (discardAndFixInvalid)
            {
                for (int i = results.Count - 1; i >= 0; i--)
                {
                    Vertices polygon = results[i];

                    PolygonError errorCode = polygon.CheckPolygon();

                    if (errorCode == PolygonError.InvalidAmountOfVertices || errorCode == PolygonError.AreaTooSmall || errorCode == PolygonError.SideTooSmall || errorCode == PolygonError.NotSimple)
                    {
                        results.RemoveAt(i);
                    }
                    else if (errorCode == PolygonError.NotCounterClockWise)
                    {
                        polygon.Reverse();
                    }
                    else if (errorCode == PolygonError.NotConvex)
                    {
                        results[i] = GiftWrap.GetConvexHull(polygon);
                    }
                }
            }

            return(results);
        }
    }
Exemple #8
0
 public bool Init(GiftWrap gw, float error)
 {
     //重载一个Init的方法,避免顺序耦合
     ErrorBase = error;
     return(Init(gw));
 }
Exemple #9
0
    public bool Init(GiftWrap gw)
    {
        if (gw.ExceptionOccur())
        {
            return(false);
        }

        Reset();                                                //重置为初始状态

        Centroid = gw.Centroid;                                 //质心置为初始化gw的质心

        //分情况考虑构造CConvexPolytope
        if (gw.HullType == GiftWrap.HULL_TYPE.HULL_3D)          //3D Hull的情况
        {
            int[] map   = new int[gw.LstVertex.Count];          //构造一个映射表
            int   count = 0;

            //添加有效顶点&构造映射表
            int i;
            for (i = 0; i < gw.LstVertex.Count; i++)
            {
                map[i] = -1;
                if (gw.LstExtremeVertex[i])
                {
                    //当前点有效,用其初始化v,并将其插入到顶点列表
                    Vector3 v = gw.LstVertex[i];
                    LstVertecies.Add(v);
                    LstVertexInfo.Add(new VertexInfo());
                    map[i] = count++;
                }
            }

            //构造面片
            //添加三角形面片
            for (i = 0; i < gw.LstFaces.Count; i++)
            {
                Face f = gw.LstFaces[i];
                if (!f.InPolygon)               //不属于任何多边形,添加
                {
                    Vector3 v1  = gw.LstVertex[f.v1];
                    Vector3 v2  = gw.LstVertex[f.v2];
                    Vector3 v3  = gw.LstVertex[f.v3];
                    Patch   pat = new Patch(this);
                    pat.Set(v1, v2, v3);                        //几何信息

                    //依次向Neighbors中添加元素
                    VPNeighbor        vpn         = new VPNeighbor();
                    List <VPNeighbor> lstNeighbor = pat.LstNeighbors;

                    vpn.Vid = map[f.v1];                                //这里必须作一个映射
                    lstNeighbor.Add(vpn);

                    vpn     = new VPNeighbor();
                    vpn.Vid = map[f.v2];
                    lstNeighbor.Add(vpn);

                    vpn     = new VPNeighbor();
                    vpn.Vid = map[f.v3];
                    lstNeighbor.Add(vpn);

                    //各顶点度数增1
                    LstVertexInfo[map[f.v1]].Degree++;
                    LstVertexInfo[map[f.v2]].Degree++;
                    LstVertexInfo[map[f.v3]].Degree++;

                    //添加到链表
                    LstPatches.Add(pat);
                }
            }

            //添加多边形面片
            for (i = 0; i < gw.LstPlanes.Count; i++)
            {
                List <int> planes = gw.LstPlanes[i];

                //取前三个点构造平面几何信息
                Vector3 v1  = gw.LstVertex[planes[0]];
                Vector3 v2  = gw.LstVertex[planes[1]];
                Vector3 v3  = gw.LstVertex[planes[2]];
                Patch   pat = new Patch(this);
                pat.Set(v1, v2, v3);                            //几何信息

                //依次向Neighbors中添加元素
                VPNeighbor        vpn          = new VPNeighbor();
                List <VPNeighbor> lstNeighbors = pat.LstNeighbors;

                for (int j = 0; j < planes.Count; j++)
                {
                    vpn     = new VPNeighbor();
                    vpn.Vid = map[planes[j]];                           //这里必须作一个映射
                    lstNeighbors.Add(vpn);

                    LstVertexInfo[vpn.Vid].Degree++;                    //顶点度数增1
                }

                //添加到链表
                LstPatches.Add(pat);
            }
        }
        else
        {
            //说明是2D Hull的情况
            List <int> lstCHVs = gw.GetCHVertecies();
            if (lstCHVs == null)
            {
                return(false);
            }
            if (lstCHVs.Count < 3)              //至少是一个三角形
            {
                return(false);
            }

            //顶点信息
            VertexInfo vInfo = new VertexInfo();
            vInfo.Degree = 3;                           //直棱拄所有顶点的面度数均为3

            HalfSpace planeOut = new HalfSpace();
            HalfSpace planeIn  = new HalfSpace();

            //取前三个点构造平面几何信息
            Vector3 v1 = gw.LstVertex[lstCHVs[0]];
            Vector3 v2 = gw.LstVertex[lstCHVs[1]];
            Vector3 v3 = gw.LstVertex[lstCHVs[2]];

            //构造两个平面PlaneOut和PlaneIn,分别表示顶面和底面
            planeOut.Set(v1, v2, v3);

            planeIn.Normal = -planeOut.Normal;
            planeIn.Dist   = -planeOut.Dist;

            planeIn.Translate(HULL2D_HALF_THICKNESS);
            planeOut.Translate(HULL2D_HALF_THICKNESS);

            Vector3 vOutNormal = planeOut.Normal;
            Vector3 vInNormal  = planeIn.Normal;

            //分别求出PlaneOut,PlaneIn上的两点
            Vector3 vOut = v1 + HULL2D_HALF_THICKNESS * vOutNormal;
            Vector3 vIn  = v1 + HULL2D_HALF_THICKNESS * vInNormal;

            //构造顶点及顶点信息
            int i;
            for (i = 0; i < lstCHVs.Count; i++)
            {
                //同时添加底面和顶面的一个顶点
                Vector3 vec1 = gw.LstVertex[lstCHVs[i]];
                Vector3 vec2 = vec1;
                if (i < 3)
                {
                    vec1 += HULL2D_HALF_THICKNESS * vOutNormal;
                    vec2 += HULL2D_HALF_THICKNESS * vInNormal;
                }
                else
                {
                    Vector3 vDiff = vec1 - vOut;
                    vec1 -= Vector3.Dot(vDiff, vOutNormal) * vOutNormal;

                    vDiff = vec2 - vIn;
                    vec2 -= Vector3.Dot(vDiff, vInNormal) * vInNormal;
                }

                LstVertecies.Add(vec1);
                LstVertecies.Add(vec2);

                //相应的,添加两个顶点信息
                LstVertexInfo.Add(vInfo);
                LstVertexInfo.Add(vInfo);
            }

            //开始构造平面面片

            //向外的面
            Patch pat = new Patch(this);
            pat.Normal = vOutNormal;                            //几何信息
            pat.Dist   = planeOut.Dist;

            //依次向Neighbors中添加元素
            VPNeighbor        vpn           = new VPNeighbor();
            List <VPNeighbor> lstNeighbors1 = pat.LstNeighbors;
            for (i = 0; i < lstCHVs.Count; i++)
            {
                vpn     = new VPNeighbor();
                vpn.Vid = 2 * i;
                lstNeighbors1.Add(vpn);
            }
            //添加到链表
            LstPatches.Add(pat);

            //向内的面

            pat        = new Patch(this);
            pat.Normal = vInNormal;                     //几何信息
            pat.Dist   = planeIn.Dist;

            //依次向Neighbors中添加元素
            List <VPNeighbor> lstNeighbors2 = pat.LstNeighbors;
            //顶面按照逆序添加
            for (i = lstCHVs.Count - 1; i >= 0; i--)
            {
                vpn     = new VPNeighbor();
                vpn.Vid = 2 * i + 1;
                lstNeighbors2.Add(vpn);
            }
            //添加到链表
            LstPatches.Add(pat);

            //开始添加各个侧面
            for (i = 0; i < lstCHVs.Count; i++)
            {
                pat = new Patch(this);
                List <VPNeighbor> lstNeighbors = pat.LstNeighbors;

                //每个侧面都是一个矩形
                if (i < lstCHVs.Count - 1)
                {
                    v1 = LstVertecies[2 * i + 2];
                    v2 = LstVertecies[2 * i];
                    v3 = LstVertecies[2 * i + 1];
                    pat.Set(v1, v2, v3);

                    vpn     = new VPNeighbor();
                    vpn.Vid = 2 * i;
                    lstNeighbors.Add(vpn);

                    vpn     = new VPNeighbor();
                    vpn.Vid = 2 * i + 1;
                    lstNeighbors.Add(vpn);

                    vpn     = new VPNeighbor();
                    vpn.Vid = 2 * i + 3;
                    lstNeighbors.Add(vpn);

                    vpn     = new VPNeighbor();
                    vpn.Vid = 2 * i + 2;
                    lstNeighbors.Add(vpn);
                }
                else
                {
                    //最后一个矩形的情况比较特殊
                    v1 = LstVertecies[0];
                    v2 = LstVertecies[2 * i];
                    v3 = LstVertecies[2 * i + 1];
                    pat.Set(v1, v2, v3);

                    vpn     = new VPNeighbor();
                    vpn.Vid = 2 * i;
                    lstNeighbors.Add(vpn);

                    vpn     = new VPNeighbor();
                    vpn.Vid = 2 * i + 1;
                    lstNeighbors.Add(vpn);

                    vpn     = new VPNeighbor();
                    vpn.Vid = 1;
                    lstNeighbors.Add(vpn);

                    vpn     = new VPNeighbor();
                    vpn.Vid = 0;
                    lstNeighbors.Add(vpn);
                }
                LstPatches.Add(pat);
            }
        }


        OriginPatchNum = LstPatches.Count;
        CurVNum        = LstVertecies.Count;

        //初始化删除误差
        if (mLstRemovedError == null)
        {
            mLstRemovedError = new List <float>(OriginPatchNum + 1);
        }
        mLstRemovedError.Clear();
        for (int i = 0; i < OriginPatchNum + 1; i++)
        {
            mLstRemovedError.Add(-1.0f);                        //0,1,2,3都置为无效值
        }
        ExceptionOccur = false;

        //计算每个patch的邻域patch
        ComputePatchNeighbors();

        //HalfSpace::SetDistThresh(1e-3);  //恢复到缺省的阈值

        //寻找最小删除误差对应的面片
        SearchLeastErrorPatch();

        //开始简化,简化到头
        ReduceAll();

        return(true);
    }