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; }
public void Init(Vector3 normal, float dist, bool bevel) { Plane = new HalfSpace(); Plane.Normal = normal; Plane.Dist = dist; Bevel = bevel; }
// 计算生成的凸包是否合法 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); }
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); }
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); }
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); }
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恢复到缺省的阈值 }
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); }
// 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); }
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(); //恢复到缺省的阈值 }
public void SetHS(HalfSpace hs) { Normal = hs.Normal; Dist = hs.Dist; }
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); }
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(); //恢复到缺省的阈值 }
public HalfSpace(HalfSpace hs) { mNormal = hs.Normal; mD = hs.Dist; }
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); }
///////////////////////////////////////////////////////// // 该函数用来处理对于边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); }
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; }
public CDSide(HalfSpace hs, bool bevel) { Init(hs, bevel); }
public void Init(HalfSpace hs, bool bevel) { Plane = hs; Bevel = bevel; }