Esempio n. 1
0
    //////////////////////////////////////////////////////////////////////
    // 本类最核心的方法: 将本面片从凸多面体中删除!
    // 涉及到了很多相关的操作,包括:
    // 计算新的顶点、新顶点的添加、本面片的删除、及邻域面片的更新等操作
    //////////////////////////////////////////////////////////////////////
    public bool Removed()
    {
        int npCount = mLstNeighbors.Count;

        if (npCount < 3)
        {
            return(false);
        }

        //一些重要的数据结构
        List <Vector3> lstVerteciesAdded = new List <Vector3>();                        //删除后将产生的新的顶点集
        List <byte>    lstVDegree        = new List <byte>();                           //新产生顶点的度数,即邻接平面数。与上动态数组一一对应

        //哪些邻域平面相交于相同的顶点
        //对应于上面的要添加的顶点
        //如对于添加的顶点v,其在VerteciesAdded中的id为2
        //则PatchesIntersectV[2]对应了一个动态数组,其元素
        //即为相交于点v的所有patch领域面片的id
        //=======注意:======
        //AArray<AArray<int,int>,AArray<int,int>>在编译时会报错!
        //说明模板类的使用暂时不支持嵌套定义。因此,这里采用了指针!
        List <List <int> > PatchesIntersectV = new List <List <int> >();

        //邻域面片包含了哪些新加入的顶点
        List <List <int> > VerticesInPatch = new List <List <int> >(npCount);
        int i;

        for (i = 0; i < npCount; i++)
        {
            //初始化VerticesInPatch的每一个元素
            VerticesInPatch.Add(new List <int>());
        }

        /////////////////////////////////////////////////////////////////////
        // 求解新交点部分!
        /////////////////////////////////////////////////////////////////////

        List <int>    lstN = new List <int>();              //存储选出的三个相邻面片的id
        CombGenerator cg   = new CombGenerator(3, npCount);
        Vector3       v    = Vector3.zero;
        bool          valid;

        //主循环
        while (!cg.Over)
        {
            //产生一个组合
            cg.GetNextComb(lstN);
            if (Processed(lstN, PatchesIntersectV))                     //已经处理过,直接跳过,进入下一轮循环!
            {
                continue;
            }

            if (Solve3NPIntersection(lstN, ref v))                              //有唯一解
            {
                valid = true;

                //如果有解,先代入到当前平面的方程
                //注意:考察当前面片时,则应该是不在当前面片的内部!
                //在该平面上或其外部都可以
                if (this.Inside(v))
                {
                    continue;                                  //直接进入下一轮while循环
                }
                List <int> lstPatchesPassV = new List <int>(); //定义一个过v的所有面片的动态数组

                //依次代入其他的邻域面片方程检验
                for (i = 0; i < npCount; i++)
                {
                    if (i != lstN[0] && i != lstN[1] && i != lstN[2])
                    {
                        //不能在这些面片的外部
                        if (mLstNeighbors[i].NeighborPatch.Outside(v))
                        {
                            valid = false;
                            break;              //在某个平面外部,跳出for循环
                        }
                        //在平面上的情况
                        if (mLstNeighbors[i].NeighborPatch.OnPlane(v))
                        {
                            lstPatchesPassV.Add(i);                     //出现共面的情况!
                        }
                    }
                }

                if (valid)                    //有效的交点
                {
                    lstVerteciesAdded.Add(v); //添加到新有效顶点列表

                    //添加lstN[0,1,2]到相交于该顶点的邻域平面列表
                    lstPatchesPassV.Add(lstN[0]);
                    lstPatchesPassV.Add(lstN[1]);
                    lstPatchesPassV.Add(lstN[2]);

                    //modified by wf, 04-10-09
                    //为保证前后计算的一致性而作的代码修改:
                    int ExistPIV;
                    if ((ExistPIV = HasPIntersectVExist(lstPatchesPassV, PatchesIntersectV)) == -1)
                    {
                        //不存在不一致的情况

                        //添加上述列表到PatchesIntersectV中
                        PatchesIntersectV.Add(lstPatchesPassV);

                        //将顶点度数记录下来
                        lstVDegree.Add((byte)lstPatchesPassV.Count);

                        //将该顶点在VerteciesAdded中的id添加到
                        //相交于该顶点的各个面片对应的VerticesInPatch中
                        int vid = lstVerteciesAdded.Count - 1;
                        int npid;
                        for (i = 0; i < lstPatchesPassV.Count; i++)
                        {
                            npid = lstPatchesPassV[i];
                            VerticesInPatch[npid].Add(vid);
                        }
                    }
                    else
                    {
                        //出现了不一致的情况,此时按照最后最多面片相交的情况处理!
                        lstVerteciesAdded.RemoveAt(lstVerteciesAdded.Count - 1);                //删除该点

                        List <int> lstExistPIV = PatchesIntersectV[ExistPIV];
                        PatchesIntersectV[ExistPIV] = lstPatchesPassV;
                        lstVDegree[ExistPIV]        = (byte)lstPatchesPassV.Count;
                        //将该顶点在VerteciesAdded中的id添加到
                        //相交于该顶点的各个面片对应的VerticesInPatch中
                        //int vid=VerteciesAdded.GetSize()-1;
                        int npid;
                        for (i = 0; i < lstPatchesPassV.Count; i++)
                        {
                            npid = lstPatchesPassV[i];
                            if (!InArray(npid, lstExistPIV))                            //如果该npid没有出现过,则添加vid
                            {
                                VerticesInPatch[npid].Add(ExistPIV);
                            }
                        }

                        lstExistPIV.Clear();                    //释放内存
                    }
                }
                else
                {
                    lstPatchesPassV.Clear(); //当前顶点无效,回收前面分配的内存
                };
            }                                //无解的情况暂不考虑
        }

        //如果没有合法的新交点,则这里应该返回false了
        //正常而言,应该不太回出现这种情况,因为在计算最小误差时
        //就应该排除掉了无解的情况,因此还有一个最小误差求解和本方法结果一致性的问题
        if (lstVerteciesAdded.Count == 0)
        {
            // error occured!
            mRemovedError = -1.0f;
            mConvexPolytope.ExceptionOccur = true;
            return(false);
        }

        /////////////////////////////////////////////////////////////////////
        // 向Polytope中插入新交点部分!
        /////////////////////////////////////////////////////////////////////
        //记录插入前Polytope已有的顶点数目,新交点插入后的全局id则依次为:g_vid,g_vid+1,g_vid+2...
        //因此可供以后更新面片的邻域顶点列表使用
        int g_vid = mConvexPolytope.LstVertecies.Count;

        for (i = 0; i < lstVerteciesAdded.Count; i++)
        {
            VertexInfo vInfo = new VertexInfo();
            vInfo.Degree = lstVDegree[i];
            mConvexPolytope.AddV(lstVerteciesAdded[i], vInfo);
        }


        //更新之前应先将以前的邻域面片备份,这一步可以考虑放在Polytope调用Removed()函数
        //前进行!

        /////////////////////////////////////////////////////////////////////
        // 更新邻域面片的邻域列表(包括顶点和相邻面片)
        /////////////////////////////////////////////////////////////////////
        Patch curNP;                    //当前的邻域面片
        int   g_vid1, g_vid2;           //当前的邻域面片对应的顶点,及邻边上的另一个顶点(都是全局id)
        /////////////////////////////////////////////////////////////////////
        // =======注意在两相邻面片中,边的方向正好相反=====
        //
        //				 当前面片P
        //             \  ---.   /
        //	对应(Pnk) v1\________/ v2 对应邻域面片(Pn2)
        //              /        \
        //             / <-----   \
        //				  邻域面片(Pn1)
        //
        /////////////////////////////////////////////////////////////////////
        int        next, pre;
        List <int> lstVSorted = new List <int>();                               //按照顶点连接顺序连接好的数组
        List <int> lstVertices = null;
        int        ivid, lastvid;

        for (i = 0; i < npCount; i++)                           //外层循环,对每一个邻域面片分别考虑!循环体内是一个邻域面片的处理
        {
            lstVSorted.Clear();                                 //清空上次循环中的顶点排序列表

            next = (i + 1 < npCount) ? i + 1 : 0;               //下一个neighbor的索引,由于是用数组表示环状结构,因此要作一个运算
            pre  = (i - 1 < 0) ? npCount - 1 : i - 1;           //上一个neighbor的索引

            curNP       = mLstNeighbors[i].NeighborPatch;
            g_vid1      = mLstNeighbors[i].Vid;
            g_vid2      = mLstNeighbors[next].Vid;
            lstVertices = VerticesInPatch[i];

            /////////////////////////////////////////////////////////////////////
            // 开始顶点连接
            // 注意下面的顶点连接算法似乎没有必然得出正确结果的保障
            // 因此,这一段也应作为测试和调试的重点!
            /////////////////////////////////////////////////////////////////////

            //先查找与vid2邻接的顶点
            int j;
            for (j = 0; j < lstVertices.Count; j++)
            {
                ivid = lstVertices[j];
                if (InArray(i, PatchesIntersectV[ivid]) &&      //vid1对应的邻域面片(Pn1)过vid
                    InArray(next, PatchesIntersectV[ivid]))     //vid2对应的邻域面片(Pn2)过vid
                {
                    //说明vid与v2相邻接
                    lstVSorted.Add(ivid);               //插入数组中
                    break;                              //找到了,跳出
                }
            }
            //确保找到!
            if (lstVSorted.Count != 1)
            {
                // error occured!
                mRemovedError = -1.0f;
                mConvexPolytope.ExceptionOccur = true;
                return(false);
            }

            //然后,依次寻找并连接相邻的两个顶点!
            //lastvid标志最后一个已被连接的顶点
            //定义llvid则标志倒数第二个被连接的顶点,引入改变量是为了避免重复连接!
            int llvid;
            int counter = 1;                            //引入counter防止死循环
            while (counter < lstVertices.Count)
            {
                counter++;

                lastvid = lstVSorted[lstVSorted.Count - 1];
                if (lstVSorted.Count < 2)
                {
                    llvid = -1;                 //一个无效值,因为此时还没有倒数第二个
                }
                else
                {
                    llvid = lstVSorted[lstVSorted.Count - 2];
                }

                for (j = 0; j < lstVertices.Count; j++)
                {
                    ivid = lstVertices[j];
                    //这个地方应该增加判断:即不能重复连接!
                    if ((ivid != lastvid) && (ivid != llvid) && IsVAdjacent(PatchesIntersectV[lastvid], PatchesIntersectV[ivid]))       //相邻
                    {
                        lstVSorted.Add(ivid);
                        break;
                    }
                }
            }

            if (counter != lstVSorted.Count)
            {
                // error occured!
                mRemovedError = -1.0f;
                mConvexPolytope.ExceptionOccur = true;
                return(false);
            }

            if (lstVSorted.Count != 1)
            {
                // error occured!
            }

            lastvid = lstVSorted[lstVSorted.Count - 1];

            //确保最后一个顶点lastvid应该是和v1邻接的

            if (!InArray(pre, PatchesIntersectV[lastvid]) || !InArray(i, PatchesIntersectV[lastvid]))
            {
                // error occured!
                mRemovedError = -1.0f;
                mConvexPolytope.ExceptionOccur = true;
                return(false);
            }

            /////////////////////////////////////////////////////////////////////
            // 确定顶点连接关系后,则可以开始邻域面片的顶点插入操作了
            /////////////////////////////////////////////////////////////////////
            //判断v1和v2是否应该从当前邻域面片的Neighbor中删除!
            //判断方法:以v2为例,如果过v2的面片仅有P,Pn1,Pn2,则v2可以删除了,这可以简化为看其度数是否为3或>3
            List <VPNeighbor> lstNeighbors = curNP.LstNeighbors;
            //寻找v2在当前邻域面片中的位置
            for (j = 0; j < lstNeighbors.Count; j++)
            {
                int tmp = lstNeighbors[j].Vid;
                if (g_vid2 == tmp)
                {
                    break;
                }
            }
            //循环结束,j保存了当前的v2位置
            int v2pos = j;

            if (v2pos >= lstNeighbors.Count)           //确保一定找到
            {
                // error occured!
                mRemovedError = -1.0f;
                mConvexPolytope.ExceptionOccur = true;
                return(false);
            }

            if (g_vid1 != curNP.GetNextV(v2pos))           //确保一定找到
            {
                // error occured!
                mRemovedError = -1.0f;
                mConvexPolytope.ExceptionOccur = true;
                return(false);
            }

            bool bv2Last = (v2pos == lstNeighbors.Count - 1);           //v2是否是Neighbor中最后一个元素?

            //先处理v1,因为对其的操作比较简单!直接删除或保留即可!
            //判断v1是否应该从当前邻域面片的Neighbor中删除
            VertexInfo v1Info = mConvexPolytope.LstVertexInfo[g_vid1];
            if (v1Info.Degree == 3)
            {
                //删除该邻域,v1在当前patch中的索引为pCurNP.GetNext(j)
                lstNeighbors.RemoveAt(curNP.GetNext(v2pos));
                if (bv2Last)                    //说明v1是第一个元素,因此,删除v1后,应将v2pos自减
                {
                    v2pos--;
                }
            }
            int InsertPos;                              //新邻域添加的位置

            //处理v2是否删除或保留!
            VertexInfo v2Info = mConvexPolytope.LstVertexInfo[g_vid2];
            if (v2Info.Degree == 3)
            {
                //则应删除v2
                lstNeighbors.RemoveAt(v2pos);
                InsertPos = v2pos;                                              //v2已被删除,直接从v2pos插入
            }
            else
            {
                //不删除v2,但必须修改其pNeighborPatch
                lstNeighbors[v2pos].NeighborPatch = mLstNeighbors[next].NeighborPatch; //修改其对应NeighborPatch为Pn2!
                InsertPos = curNP.GetNext(v2pos);                                      //插入点在v2pos后面第一个元素起
            }

            //构造新要添加的邻域
            List <VPNeighbor> lstNeighborsToAdd = new List <VPNeighbor>();              //新要添加的邻域
            VPNeighbor        vpn = new VPNeighbor();
            for (j = 0; j < lstVSorted.Count; j++)
            {
                vpn.Vid = lstVSorted[j] + g_vid;                                                //注意,这里要用全局id,因此应加上g_vid
                if (j == lstVSorted.Count - 1)
                {
                    //最后一个邻域节点要特殊处理
                    //其邻域面片应等于本面片的上一个邻域面片
                    vpn.NeighborPatch = mLstNeighbors[pre].NeighborPatch;
                }
                else
                {
                    //要用一个查找算法!找出对应于该点的邻域面片!
                    for (int k = 0; k < npCount; k++)
                    {
                        if (k != i)             //不是当前正在考察的面片
                        {
                            List <int> lstVertecies = VerticesInPatch[k];
                            if (InArray(lstVSorted[j], lstVertecies) && InArray(lstVSorted[j + 1], lstVertecies))
                            {
                                //由VSorted[j,j+1]构成的边出现在pVertecies中
                                //说明第k个邻域面片对应了顶点VSorted[j]
                                vpn.NeighborPatch = mLstNeighbors[k].NeighborPatch;
                            }
                        }
                    }
                }

                if (vpn.NeighborPatch == null)           //确保一定找到
                {
                    // error occured!
                    mRemovedError = -1.0f;
                    mConvexPolytope.ExceptionOccur = true;
                    return(false);
                }

                lstNeighborsToAdd.Add(vpn);
            }

            //插入新的邻域
            lstNeighbors.InsertRange(InsertPos, lstNeighborsToAdd);

            //当前邻域面片pCurNP的新的邻域构造OK后,需要对其进行更新删除误差操作!
            curNP.UpdateRemovedError();
        }     // end of for-loop

        //循环遍历当前面片的每一个顶点,并将其度数自减1
        int curvid;

        for (i = 0; i < npCount; i++)
        {
            curvid = mLstNeighbors[i].Vid;
            VertexInfo curVInfo = mConvexPolytope.LstVertexInfo[curvid];
            curVInfo.Degree--;
        }

        return(true);                   //删除成功
    }
Esempio n. 2
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);
    }