コード例 #1
0
    public void Export(CDBrush cdBrush)
    {
        if (cdBrush == null)
        {
            return;
        }
        cdBrush.Release();
        for (int i = 0; i < GetFaceNum(); i++)
        {
            CDSide    side = new CDSide();
            HalfSpace HS   = new HalfSpace();
            HS.Normal = GetFace(i).Normal;
            HS.Dist   = GetFace(i).Dist;

            side.Init(HS, false);
            cdBrush.LstSides.Add(side);
            cdBrush.cd = this;
        }

        Bounds tmpAABB;

        GetAABB(out tmpAABB);
        if (tmpAABB != null)
        {
            cdBrush.BoundAABB = tmpAABB;
        }
        cdBrush.Flags = Flags;
    }
コード例 #2
0
ファイル: ConvexBrush.cs プロジェクト: liuxq/GJKLearn
 public void Init(Vector3 normal, float dist, bool bevel)
 {
     Plane        = new HalfSpace();
     Plane.Normal = normal;
     Plane.Dist   = dist;
     Bevel        = bevel;
 }
コード例 #3
0
ファイル: GiftWrap.cs プロジェクト: liuxq/GJKLearn
    // 计算生成的凸包是否合法
    public bool ValidConvexHull()
    {
        // 检查共面的顶点是否会出现顶点到平面的距离超出阈值的情况
        HalfSpace hs = new HalfSpace();

        for (int i = 0; i < mLstPlanes.Count; i++)
        {
            if (mLstPlanes[i].Count < 3)
            {
                continue;
            }

            hs.Set(mLstVertex[mLstPlanes[i][0]], mLstVertex[mLstPlanes[i][1]], mLstVertex[mLstPlanes[i][2]]);

            for (int j = 3; j < mLstPlanes[i].Count; j++)
            {
                if (Mathf.Abs(hs.Dist2Plane(mLstVertex[mLstPlanes[i][j]])) > CH_VALID_TOLERANCE)
                {
                    return(false);
                }
            }
        }

        return(true);
    }
コード例 #4
0
ファイル: GiftWrap.cs プロジェクト: liuxq/GJKLearn
 protected bool ValidateCHPlane(HalfSpace hs)
 {
     for (int i = 0; i < mLstVertex.Count; i++)
     {
         if (!hs.Inside(mLstVertex[i]) && !hs.OnPlane(mLstVertex[i]))
         {
             return(false);
         }
     }
     return(true);
 }
コード例 #5
0
    public bool EditLoad(LEditTextFile file)
    {
        Normal = file.LoadVector3Line(_Key_FaceNormal);
        Dist   = file.LoadValueLine <float>(_Key_FaceDist);
        int elenum = file.LoadValueLine <int>(_Key_FaceEleNum);

        for (int i = 0; i < elenum; i++)
        {
            HalfSpace hs  = new HalfSpace();
            int       vid = file.LoadValueLine <int>(_Key_FaceEleVid);
            hs.Normal = file.LoadVector3Line(_Key_FaceEleNormal);
            hs.Dist   = file.LoadValueLine <float>(_Key_FaceEleDist);
            AddElement(vid);
        }
        return(true);
    }
コード例 #6
0
    public bool IsVertexOutside(Vector3 v, float fInflateRadius = 0.0f)
    {
        HalfSpace hs  = new HalfSpace();
        Patch     cur = null;

        for (int i = 0; i < LstPatches.Count; i++)
        {
            cur       = LstPatches[i];
            hs.Normal = cur.Normal;
            hs.Dist   = cur.Dist + fInflateRadius;
            if (hs.Outside(v))
            {
                return(true);
            }
        }
        return(false);
    }
コード例 #7
0
    private int mCurOperator;                                                                          //当前操作所在位置

    public ConvexPolytope()
    {
        mLstIndices     = new List <ushort>();                              //初始化为一个大值
        mLstLEPIndices  = new List <ushort>();                              //最小误差面片的三角形个数*3
        mLstLEPNIndices = new List <ushort>();                              //最小误差面片的邻域面片三角形个数*3

        mLstVerticesForRender = new List <Vector3>();                       //初始化渲染用到的顶点
        OriginPatchNum        = 0;
        mCurOperator          = -1;

        mLstRemovedError = null;
        ErrorBase        = 1.0f;                                //给一个缺省值1.0f,即绝对误差
        MinPatchNum      = 4;
        ExceptionOccur   = false;
        Centroid         = Vector3.zero;
        HalfSpace.SetDistThresh();      //将Halfspace恢复到缺省的阈值
    }
コード例 #8
0
    public Patch IsVertexOnPatch(Vector3 v, float fInflateRadius)
    {
        HalfSpace hs  = new HalfSpace();
        Patch     cur = null;

        for (int i = 0; i < LstPatches.Count; i++)
        {
            cur       = LstPatches[i];
            hs.Normal = cur.Normal;
            hs.Dist   = cur.Dist + fInflateRadius;
            if (hs.OnPlane(v))
            {
                return(cur);
            }
        }
        return(null);
    }
コード例 #9
0
ファイル: HalfSpace.cs プロジェクト: liuxq/GJKLearn
    // compute the best-fit plane via an array of vertices, return true if all vertices's
    // distances to plane is less than MaxDistError.
    public static bool BestFitPlane(Vector3[] verts, ref HalfSpace plane, float maxDistErr)
    {
        Vector4 p = Vector4.zero;

        BestFit.ComputeBestFitPlane(verts, null, ref p);
        Vector3 normal = new Vector3(p[0], p[1], p[2]);

        plane.Normal = normal;
        plane.Dist   = -p[3];

        // now check the distance error...
        for (int i = 0; i < verts.Length; i++)
        {
            if (plane.Dist2Plane(verts[i]) > maxDistErr)
            {
                return(false);
            }
        }

        return(true);
    }
コード例 #10
0
ファイル: GiftWrap2D.cs プロジェクト: liuxq/GJKLearn
    public override void ComputeConvexHull()
    {
        //设置HalfSpace的共面距离阈值
        float hsDistThresh = 1e-1f;

        //保证没有异常的求出凸包!
        do
        {
            hsDistThresh *= 0.1f;                       //放大阈值10倍
            HalfSpace.SetDistThresh(hsDistThresh);      //调整阈值

            //先调用父类函数从而完成清空操作
            base.ComputeConvexHull();
            ResetSameVertices();

            //寻找第一条边
            Edge edge = SearchFirstEdge(Vector3.up);
            mFirstEdge = edge;

            //由于都是共面因此,不需要作压栈等处理了!

            //处理该边
            DealEdge(edge);
        } while (mExceptionOccur && hsDistThresh > 5e-7);

        if (hsDistThresh < 5e-7f)
        {
            //说明已经超出了阈值范围,如果还有异常发生
            //则说明确实该模型的凸壳计算存在异常!
            mExceptionOccur = true;
        }

        //计算完后,m_Planes中保存了2D凸包的顶点连接信息

        //清空边栈
        mEdgeStack.Clear();

        HalfSpace.SetDistThresh();      //恢复到缺省的阈值
    }
コード例 #11
0
 public void SetHS(HalfSpace hs)
 {
     Normal = hs.Normal;
     Dist   = hs.Dist;
 }
コード例 #12
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);
    }
コード例 #13
0
ファイル: GiftWrap.cs プロジェクト: liuxq/GJKLearn
    protected void InternalComputeConvexHull()
    {
        HalfSpace hsFitPlane = new HalfSpace();
        Vector3   vFitNormal = Vector3.zero;
        bool      bFit       = HalfSpace.BestFitPlane(LstVertex.ToArray(), ref hsFitPlane, mIdenticalPosErr);

        if (bFit)
        {
            // tune the vertices's position to make the convex-hull generation more accurately...
            //for (int i = 0; i < LstVertex.Count; i++)
            //{
            //    LstVertex[i] = hsFitPlane.GetPorjectPos(LstVertex[i]);
            //}
        }

        vFitNormal = hsFitPlane.Normal;
        if (vFitNormal == Vector3.zero)
        {
            vFitNormal.Set(0.0f, 1.0f, 0.0f);
        }

        //////////////////////////////////////////////////////////////////////////
        // 由于求解凸包的过程在一定程度上依赖于HalfSpace类的距离阈值,因此
        // 这里将设法找到一个可以得到正确结果的距离阈值。
        // 一个重要的问题是能否求解出凸包与该阈值并非是单调的关系,即并非是阈值越大或越小
        // 就一定可以得到结果。实际上,阈值的一个微小的扰动,将可能导致异常出现或求出凸包
        // 但目前还没有找出两者之间的必然关系和规律。
        // 因此,目前的阈值设定,采用了宽度优先的尝试法。简单说明如下:
        // 首先尝试一个基本值hsDistThreshBase,然后将阈值设为hsDistThreshBase×0.1,
        // 直到阈值<CH_FLT_EPSILON。
        // 如果上述所有的阈值仍不能满足要求,则对hsDistThreshBase-0.1*hsDistThreshBase,
        // 然后继续上面的循环!
        // 可考虑另外的方法,如随机数的方法
        //////////////////////////////////////////////////////////////////////////

        float hsDistThreshBase     = HSDistThresh * 10.0f; //每次递减循环的基数,先放大10倍
        float hsDistThreshBaseStep = HSDistThresh;         //递减步长
        float hsDistThresh;                                //当前的阈值

        //保证没有异常的求出凸包!
        //双重循环
        do
        {
            hsDistThresh = hsDistThreshBase;

            do
            {
                HullType = HULL_TYPE.HULL_3D;                   //重新计算时,初始化为3D凸包

                hsDistThresh *= 0.1f;                           //缩小阈值10倍

                HalfSpace.SetDistThresh(hsDistThresh);          //调整阈值

                //先调用父类函数从而完成清空操作
                base.ComputeConvexHull();
                ResetSameVertices();

                Edge e = SearchFirstEdge(vFitNormal);

                if (!ValidateCHPlane(new HalfSpace(LstVertex[e.start], LstVertex[e.end], LstVertex[e.start] + vFitNormal)))
                {
                    Vector3[] vAxis = new Vector3[3] {
                        Vector3.right, Vector3.up, Vector3.forward
                    };
                    for (int i = 0; i < 3; i++)
                    {
                        if (Mathf.Abs(Vector3.Dot(vFitNormal, vAxis[i])) > 0.9f)
                        {
                            continue;
                        }

                        Vector3 vN = Vector3.Cross(vFitNormal, vAxis[i]);
                        Edge    e1 = SearchFirstEdge(vN);
                        if (ValidateCHPlane(new HalfSpace(LstVertex[e1.start], LstVertex[e1.end], LstVertex[e1.start] + vN)))
                        {
                            e = e1;
                            break;
                        }
                    }
                }

                mFirstEdge = e;
                mEdgeStack.Push(e);
                //e = new Edge(e.start,e.end);
                mEdgeStack.Push(new Edge(e.start, e.end));                      //注意,这里应该push两次!从而保证在while条件中的弹出后,仍有一个边被保存在栈中!

                while (!mEdgeStack.IsEmpty() && !mExceptionOccur && HullType == HULL_TYPE.HULL_3D)
                {
                    Edge se = mEdgeStack.Pop();
                    DealEdge(se);
                }
            } while (ExceptionOccur() && hsDistThresh > CH_FLT_EPSILON);

            hsDistThreshBase -= hsDistThreshBaseStep;                   //外层循环再进行一个扰动
        } while (ExceptionOccur() && hsDistThreshBase > 0.0f);

        if (hsDistThreshBase <= 0.0f)
        {
            //说明已经超出了阈值范围,如果还有异常发生
            //则说明确实该模型的凸壳计算存在异常!
            Debug.LogError("gift wrap ExceptionOccur: hsDistThreshBase <= 0.0f");
            mExceptionOccur = true;
        }

        //hsDistThresh*=0.01f;
        //CHalfSpace::SetDistThresh(hsDistThresh);  //恢复到缺省的阈值

        HalfSpace.SetDistThresh();      //恢复到缺省的阈值
    }
コード例 #14
0
ファイル: HalfSpace.cs プロジェクト: liuxq/GJKLearn
 public HalfSpace(HalfSpace hs)
 {
     mNormal = hs.Normal;
     mD      = hs.Dist;
 }
コード例 #15
0
ファイル: GiftWrap.cs プロジェクト: liuxq/GJKLearn
    protected bool DealEdge(Edge edge)
    {
        int i;

        for (i = 0; i == edge.start || i == edge.end || IsFaceInCH(new Face(edge.start, edge.end, i)) || mLstVInvalid[i]; i++)
        {
            ;
        }

        //构造e和该点组成的半空间,此时的hs必定有效,因为,保证了不共线条件
        HalfSpace  hs = new HalfSpace(mLstVertex[edge.start], mLstVertex[edge.end], mLstVertex[i]);
        List <int> lstCoPlanarVertexes = new List <int>();      //构造一个所有共面点的列表

        lstCoPlanarVertexes.Add(i);                             //添加当前第一个元素
        //开始主循环!注意循环开始条件!从下一个元素开始!
        for (i++; i < mLstVertex.Count; i++)
        {
            //不是e端点,没有考察过,且不在半空间内部!
            if (i != edge.start && i != edge.end && !mLstVInvalid[i] && !IsFaceInCH(new Face(edge.start, edge.end, i)) && !hs.Inside(mLstVertex[i]))
            {
                if (hs.OnPlane(mLstVertex[i]))
                {
                    //在半空间的边界上,则添加到共面点列表
                    lstCoPlanarVertexes.Add(i);                                         //添加当前点
                }
                else
                {
                    //说明该点不在内部,则该点为新的目标点,并重构半空间
                    hs.Set(mLstVertex[edge.start], mLstVertex[edge.end], mLstVertex[i]);

                    //同时清空共面列表,并将该点添加至共面列表
                    lstCoPlanarVertexes.Clear();
                    lstCoPlanarVertexes.Add(i);                                         //添加当前点

                    //注意,根据凸壳的性质,这里不需从头开始遍历
                }
            }
        }

        //经过上面的循环后,CoPlanarVertexes中就存储了由当前边e找到的一个凸面上的所有点

        //在这里判断是否是2D的凸包
        HullType = HULL_TYPE.HULL_2D;
        for (i = 0; i < mLstVertex.Count; i++)                          //遍历所有顶点
        {
            if (i != edge.start && i != edge.end && !mLstVInvalid[i])   //非e的端点,而且有效
            {
                if (!IsVInVSets(i, lstCoPlanarVertexes))                // 如果当前顶点不再公面集中!
                {
                    // 增加一个判断,从而使得结果更严密
                    HalfSpace hstmp = new HalfSpace(mLstVertex[edge.start], mLstVertex[edge.end], mLstVertex[lstCoPlanarVertexes[0]]);
                    if (hstmp.OnPlane(mLstVertex[i]))
                    {
                        lstCoPlanarVertexes.Add(i);
                    }
                    else
                    {
                        HullType = HULL_TYPE.HULL_3D;
                        break;
                    }
                }
            }
        }

        //下面开始进行处理,这里将原本在ComputeConvexHull的主循环中的处理放在这里!
        if (lstCoPlanarVertexes.Count == 1)
        {
            //最简单的情况:没有共面点
            int v3 = lstCoPlanarVertexes[0];
            //将另两条边压栈
            Edge e1 = new Edge(edge.start, v3);
            Edge e2 = new Edge(v3, edge.end);
            SelectivePushStack(e1);
            SelectivePushStack(e2);

            //构造三角面片,并插入队列中
            mLstFaces.Add(new Face(edge.start, edge.end, v3));
            //同时,该三角面片的三个顶点为凸壳的ExtremeVertex!
            mLstExtremeVertex[edge.start] = true;
            mLstExtremeVertex[edge.end]   = true;
            mLstExtremeVertex[v3]         = true;

            if (HullType == HULL_TYPE.HULL_2D)                          // 凸包为一个三角形的情况
            {
                lstCoPlanarVertexes.Add(edge.start);
                lstCoPlanarVertexes.Add(edge.end);
                mLstPlanes.Add(lstCoPlanarVertexes);
            }
            else
            {
                lstCoPlanarVertexes.Clear();                                    //没有多点共面
            }
        }
        else                    //多点共面的情况!
        {
            //在由e.start,e.end和CoPlanarVertexes[0]组成的平面上找凸壳
            DealCoPlanarV(edge, lstCoPlanarVertexes);
        }

        return(true);
    }
コード例 #16
0
ファイル: GiftWrap.cs プロジェクト: liuxq/GJKLearn
    /////////////////////////////////////////////////////////
    // 该函数用来处理对于边edge,找到的目标点是多点共面的情况
    // 注意,参数中的CoPlanarVertexes所含的点数应>1
    /////////////////////////////////////////////////////////
    protected void DealCoPlanarV(Edge edge, List <int> lstCoPlanarVertexes)
    {
        //如果出现该边的两点无效的情况,直接返回
        if (mLstVInvalid[edge.start] || mLstVInvalid[edge.end])
        {
            //异常退出时,一定要释放内存
            lstCoPlanarVertexes.Clear();
            return;
        }

        //构造初始的halfspace
        //注意构造的方法:该halfspace的分割面过e.end和CoPlanarVertexes[0],同时平行于法向
        HalfSpace  hs = new HalfSpace();
        List <int> lstExtremeVertexes  = new List <int>();                      //平面上所有点的凸壳点集,用来存储结果
        List <int> lstCoLinearVertexes = new List <int>();                      //共线的情况,用一个点集表示

        //将edge.start和edge.end也存入CoPlanarVertexes中
        lstCoPlanarVertexes.Add(edge.start);
        lstCoPlanarVertexes.Add(edge.end);

        //每条边edge已经是延伸到最大的情况,因此,不用考虑还能将其延伸的情况
        int vidNotCL = lstCoPlanarVertexes[0];
        //由于上面的条件,CoPlanarVertexes[0]一定不会和edge共线的
        //利用vidNotCL,首先求出平面的法向
        Vector3 normal = Vector3.Cross(mLstVertex[edge.end] - mLstVertex[edge.start], mLstVertex[vidNotCL] - mLstVertex[edge.start]);

        normal.Normalize();

        Edge curE = new Edge(edge.end, vidNotCL);                                                       //当前的边

        int vSize = lstCoPlanarVertexes.Count;

        //main loop
        while (curE.start != edge.start)                                        //当最后找到edge.start这一点时,表明找到了所有点处在凸壳上的点
        {
            //初始化hs
            hs.Set(mLstVertex[curE.start], mLstVertex[curE.end], mLstVertex[curE.start] + normal);

            lstCoLinearVertexes.Clear();
            lstCoLinearVertexes.Add(curE.end);                          //当前点添加至共线点集

            //寻找满足当前curE的目标点
            for (int idx = 0; idx < lstCoPlanarVertexes.Count; idx++)
            {
                int id = lstCoPlanarVertexes[idx];
                if (id != curE.start && id != curE.end && !mLstVInvalid[id] && !hs.Inside(mLstVertex[id]))
                {
                    //判断是否共面,实际上为是否共线
                    if (hs.OnPlane(mLstVertex[lstCoPlanarVertexes[idx]]))
                    {
                        lstCoLinearVertexes.Add(lstCoPlanarVertexes[idx]);
                    }
                    else
                    {
                        //更改当前边
                        curE.end = lstCoPlanarVertexes[idx];
                        //重新计算halfspace
                        hs.Set(mLstVertex[curE.start], mLstVertex[curE.end], mLstVertex[curE.start] + normal);

                        //清空,并重新计算共线点集
                        lstCoLinearVertexes.Clear();
                        lstCoLinearVertexes.Add(lstCoPlanarVertexes[idx]);
                    }
                }
            }

            //循环完成,此时应该已经找到一个点或一组点集
            if (lstCoLinearVertexes.Count == 1)
            {
                //一个点的情况
                //添加至凸壳边界点集
                lstExtremeVertexes.Add(lstCoLinearVertexes[0]);
                //找到的点成为当前边的起点
                curE.start = lstCoLinearVertexes[0];

                //找一个点作为curE.end
                int j;
                for (j = 0; j < lstCoPlanarVertexes.Count && lstCoPlanarVertexes[j] == curE.start; j++)
                {
                    ;                                                                                                           //不能等于start!
                }
                curE.end = lstCoPlanarVertexes[j];

                vSize--;
                if (vSize < 0)
                {
                    mExceptionOccur = true;                             //出现异常了,退出!
                    //异常退出时,一定要释放内存
                    lstCoPlanarVertexes.Clear();
                    return;
                }
            }
            else
            {
                //多个点集的情况
                //按点到curE.start欧氏距离的远近排序,从近到远
                SortByDist(curE.start, ref lstCoLinearVertexes);
                //重置起点为最远点
                curE.start = lstCoLinearVertexes[lstCoLinearVertexes.Count - 1];
                //插入最远点!
                lstExtremeVertexes.Add(curE.start);

                //找一个点作为curE.end
                int j;
                for (j = 0; j < lstCoPlanarVertexes.Count && (lstCoPlanarVertexes[j] == curE.start || mLstVInvalid[lstCoPlanarVertexes[j]]); j++)
                {
                    ;                                                                                                                                                   //不能等于start!
                }
                curE.end = lstCoPlanarVertexes[j];

                vSize--;
                if (vSize < 0)
                {
                    mExceptionOccur = true;                             //出现异常了,退出!
                    //异常退出时,一定要释放内存
                    lstCoPlanarVertexes.Clear();
                    return;
                }
            }
        }           // end of main loop

        //注意,经过前面的循环ExtremeVertexes的最后一个元素应该就是e.start
        if (lstExtremeVertexes.Count <= 1)
        {
            mExceptionOccur = true;                             //出现异常了,退出!
            //异常退出时,一定要释放内存
            lstCoPlanarVertexes.Clear();
            return;
        }

        //此时,已经得到了一组按顺序的顶点,可以向边堆栈和面列表中添加了
        Edge ep = new Edge(lstExtremeVertexes[0], edge.end);

        SelectivePushStack(ep);
        mLstFaces.Add(new Face(edge.start, edge.end, lstExtremeVertexes[0], true));         //该面将被剖分

        int i;

        for (i = 0; i < lstExtremeVertexes.Count - 2; i++)
        {
            ep = new Edge(lstExtremeVertexes[i + 1], lstExtremeVertexes[i]);
            //添加边到堆栈,一定要注意顺序!
            //ep.Set(lstExtremeVertexes[i+1],lstExtremeVertexes[i]);		//应该反向添加
            SelectivePushStack(ep);
            mLstFaces.Add(new Face(edge.start, lstExtremeVertexes[i], lstExtremeVertexes[i + 1], true));
        }

        //最后一条边
        //注意:对该边的处理应该直接使用m_EdgeStack.CheckPush
        //因为,此前已经添加了包含该边的三角面,所以
        //如果使用SelectivePushStack,则会认为该边已经被
        //添加到三角形列表中,从而漏掉了这条边!
        //这样会导致最终凸壳缺少了一个面!
        ep = new Edge(lstExtremeVertexes[i + 1], lstExtremeVertexes[i]);
        //ep.Set(lstExtremeVertexes[i+1],lstExtremeVertexes[i]);
        mEdgeStack.CheckPush(ep);

        //将所有共面点都置为无效
        for (i = 0; i < lstCoPlanarVertexes.Count; i++)
        {
            mLstVInvalid[lstCoPlanarVertexes[i]] = true;
        }

        //重新整理CoPlanarVertexes,使其仅包括边界点
        lstCoPlanarVertexes.Clear();
        //将e.end插入到ExtremeVertexes中
        lstExtremeVertexes.Add(edge.end);
        //然后将所有边界点置为有效
        for (i = 0; i < lstExtremeVertexes.Count; i++)
        {
            mLstVInvalid[lstExtremeVertexes[i]]      = false;
            mLstExtremeVertex[lstExtremeVertexes[i]] = true;
            lstCoPlanarVertexes.Add(lstExtremeVertexes[i]);
        }

        //此时再将CoPlanarVertexes插入到m_Planes中
        //将共面的所有点构成的平面添加至m_Planes
        mLstPlanes.Add(lstCoPlanarVertexes);
    }
コード例 #17
0
ファイル: GiftWrap.cs プロジェクト: liuxq/GJKLearn
    protected Edge SearchFirstEdge(Vector3 refNormal)
    {
        Edge edge = new Edge();
        // find lowest vertexes
        List <int> lstLowestVertexes = new List <int>();
        float      yMin = mLstVertex[0].y;

        lstLowestVertexes.Add(0);
        int i = 0;

        for (i = 1; i < mLstVertex.Count; i++)
        {
            if (yMin - mLstVertex[i].y > mIdenticalPosErr)              // smaller than yMin
            {
                yMin = mLstVertex[i].y;
                lstLowestVertexes.Clear();
                lstLowestVertexes.Add(i);
            }
            else if (Mathf.Abs(yMin - mLstVertex[i].y) < mIdenticalPosErr)
            {
                // vertex in the same plane
                lstLowestVertexes.Add(i);
            }
        }

        if (lstLowestVertexes.Count == 1)           // only one vertex on bottom
        {
            edge.start = lstLowestVertexes[0];
            // search second vertex on XOY plane
            for (i = 0; i == edge.start; i++)
            {
                ;
            }

            // 利用vRefNormal构造半平面...
            HalfSpace  hs = new HalfSpace(mLstVertex[edge.start], mLstVertex[i], mLstVertex[edge.start] + refNormal);
            List <int> lstCoPlanarVertexes = new List <int>();
            lstCoPlanarVertexes.Add(i);                                     //add first vertex
            for (i++; i < mLstVertex.Count; i++)
            {
                if (i != edge.start && !hs.Inside(mLstVertex[i]))
                {
                    if (hs.OnPlane(mLstVertex[i]))
                    {
                        lstCoPlanarVertexes.Add(i);                                     //add current vetex
                    }
                    else
                    {
                        // this vetex is not inside, use this vetex as a new one to reconstruct the helf space
                        hs.Set(mLstVertex[edge.start], mLstVertex[i], mLstVertex[edge.start] + refNormal);
                        lstCoPlanarVertexes.Clear();
                        lstCoPlanarVertexes.Add(i);
                    }
                }
            }

            if (lstCoPlanarVertexes.Count == 1)
            {
                // only one vetex, let it be edge's end
                edge.end = lstCoPlanarVertexes[0];
                return(edge);
            }
            else
            {
                // more than one conplane vetex
                Vector3 vd3 = hs.Normal;

                // contruct initial half space
                hs.Set(mLstVertex[edge.start], mLstVertex[lstCoPlanarVertexes[0]], mLstVertex[edge.start] + vd3);
                List <int> lstCoLinearVertexes = new List <int>();
                lstCoLinearVertexes.Add(lstCoPlanarVertexes[0]);
                for (i = 1; i < lstCoPlanarVertexes.Count; i++)
                {
                    if (!hs.Inside(mLstVertex[lstCoPlanarVertexes[i]]))
                    {
                        if (hs.OnPlane(mLstVertex[lstCoPlanarVertexes[i]]))
                        {
                            lstCoLinearVertexes.Add(lstCoPlanarVertexes[i]);
                        }
                        else
                        {
                            // rerconstruct halfspace
                            hs.Set(mLstVertex[edge.start], mLstVertex[lstCoPlanarVertexes[i]], mLstVertex[edge.start] + vd3);
                            lstCoLinearVertexes.Clear();
                            lstCoLinearVertexes.Add(lstCoPlanarVertexes[i]);
                        }
                    }
                }

                if (lstCoLinearVertexes.Count == 1)
                {
                    // only one vetex, let it be edge's end
                    edge.end = lstCoLinearVertexes[0];
                    return(edge);
                }
                else
                {
                    // sort all colinear vertex
                    SortByDist(edge.start, ref lstCoLinearVertexes);

                    // the farest veterx is the end, set other vertexes to invalid
                    edge.end = lstCoLinearVertexes[lstCoLinearVertexes.Count - 1];
                    for (i = 0; i < lstCoLinearVertexes.Count - 1; i++)
                    {
                        mLstVInvalid[lstCoLinearVertexes[i]] = true;
                    }
                    return(edge);
                }
            }
        }
        else                    // more than one vetexes on bottom
        {
            // just consider to find the edge on XOZ plane
            if (lstLowestVertexes.Count == 2)
            {
                // only two vertex, just return the result edge
                edge.start = lstLowestVertexes[0];
                edge.end   = lstLowestVertexes[1];
                return(edge);
            }

            //find the minimum vetex acording to z value
            List <int> lstZMinVertexes = new List <int>();
            float      zmin            = mLstVertex[lstLowestVertexes[0]].z;
            lstZMinVertexes.Add(lstLowestVertexes[0]);
            for (i = 1; i < lstLowestVertexes.Count; i++)
            {
                if (zmin - mLstVertex[lstLowestVertexes[i]].z > mIdenticalPosErr)
                {
                    zmin = mLstVertex[lstLowestVertexes[i]].z;
                    lstZMinVertexes.Clear();
                    lstZMinVertexes.Add(lstLowestVertexes[i]);
                }
                else if (Mathf.Abs(zmin - mLstVertex[lstLowestVertexes[i]].z) < mIdenticalPosErr)
                {
                    // coplane
                    lstZMinVertexes.Add(lstLowestVertexes[i]);
                }
            }

            if (lstZMinVertexes.Count == 1)             //only one veterx found
            {
                //set the vertex to be start
                edge.start = lstZMinVertexes[0];
                List <int> lstCoLinearVertexes = new List <int>();

                //find the other vertex in LowestVertexes
                for (i = 0; lstLowestVertexes[i] == edge.start; i++)
                {
                    ;
                }

                lstCoLinearVertexes.Add(lstLowestVertexes[i]);
                Vector3   vd3 = new Vector3(0.0f, -1.0f, 0.0f);
                HalfSpace hs  = new HalfSpace(mLstVertex[edge.start], mLstVertex[lstLowestVertexes[i]], mLstVertex[edge.start] + vd3);
                for (i++; i < lstLowestVertexes.Count; i++)
                {
                    if (lstLowestVertexes[i] != edge.start && !hs.Inside(mLstVertex[lstLowestVertexes[i]]))
                    {
                        if (hs.OnPlane(mLstVertex[lstLowestVertexes[i]]))
                        {
                            lstCoLinearVertexes.Add(lstLowestVertexes[i]);
                        }
                        else
                        {
                            //reonstruct halfspace
                            hs.Set(mLstVertex[edge.start], mLstVertex[lstLowestVertexes[i]], mLstVertex[edge.start] + vd3);
                            //清空,并重新计算共线点集
                            lstCoLinearVertexes.Clear();
                            lstCoLinearVertexes.Add(lstLowestVertexes[i]);
                        }
                    }
                }

                if (lstCoLinearVertexes.Count == 1)
                {
                    //only one colinear vertex
                    edge.end = lstCoLinearVertexes[0];
                    return(edge);
                }
                else
                {
                    // sort all colinear vertex
                    SortByDist(edge.start, ref lstCoLinearVertexes);

                    // the farest veterx is the end, set other vertexes to invalid
                    edge.end = lstCoLinearVertexes[lstCoLinearVertexes.Count - 1];
                    for (i = 0; i < lstCoLinearVertexes.Count - 1; i++)
                    {
                        mLstVInvalid[lstCoLinearVertexes[i]] = true;
                    }
                    return(edge);
                }
            }
            else        //more than one veterx found
            {
                //find the veterxs with min and max X value
                int   xminID = lstZMinVertexes[0];
                int   xmaxID = lstZMinVertexes[0];
                float XMin   = mLstVertex[lstZMinVertexes[0]].x;
                float XMax   = mLstVertex[lstZMinVertexes[0]].x;
                for (i = 1; i < lstZMinVertexes.Count; i++)
                {
                    if (XMin - mLstVertex[lstZMinVertexes[i]].x > mIdenticalPosErr)
                    {
                        XMin   = mLstVertex[lstZMinVertexes[i]].x;
                        xminID = lstZMinVertexes[i];
                    }
                    if (mLstVertex[lstZMinVertexes[i]].x - XMax > mIdenticalPosErr)
                    {
                        XMax   = mLstVertex[lstZMinVertexes[i]].x;
                        xmaxID = lstZMinVertexes[i];
                    }
                }

                // set all vertex to invalid
                for (i = 0; i < lstZMinVertexes.Count; i++)
                {
                    mLstVInvalid[lstZMinVertexes[i]] = true;
                }

                // set edge end vertex to valid
                mLstVInvalid[xmaxID] = false;
                mLstVInvalid[xminID] = false;

                mLstExtremeVertex[xmaxID] = true;
                mLstExtremeVertex[xminID] = true;

                edge.start = xminID;
                edge.end   = xmaxID;
                return(edge);
            }
        }

        //return null;
    }
コード例 #18
0
ファイル: ConvexBrush.cs プロジェクト: liuxq/GJKLearn
 public CDSide(HalfSpace hs, bool bevel)
 {
     Init(hs, bevel);
 }
コード例 #19
0
ファイル: ConvexBrush.cs プロジェクト: liuxq/GJKLearn
 public void Init(HalfSpace hs, bool bevel)
 {
     Plane = hs;
     Bevel = bevel;
 }