private bool m_IsQuadEdge; //if not, then this edge is not shown in quad mode #endregion "data" #region "public method" // public method public VEdge(VVert v0, VVert v1) { // init the two verts m_VVerts = new VVert[2]; int cmp = v0.CompareTo(v1); if (cmp < 0) { m_VVerts[0] = v0; m_VVerts[1] = v1; } else if (cmp > 0) { m_VVerts[0] = v1; m_VVerts[1] = v0; } else { Dbg.LogErr("VEdge.ctor: v0 == v1: {0}, {1}", v0, v1); } // init the tri cont m_TriCont = new RTriCont(); m_IsQuadEdge = true; }
/// <summary> /// given an edge, and select the edge loop based on that /// </summary> public void Execute(VEdge vedge, Op op) { VVert v0 = vedge.GetVVert(0); VVert v1 = vedge.GetVVert(1); Execute(v0, v1, op); }
/// <summary> /// given two real tri indices, /// put the VVerts into the allocated 4-elem array, /// 0 for triIdx0, 1-2 for vedge, 3 for triIdx1 /// </summary> private void _GetAsQuadVerts(int triIdx0, int triIdx1, VEdge vedge, VVert[] tmpVertArr) { VVert ev0 = vedge.GetVVert(0); VVert ev1 = vedge.GetVVert(1); GetVVertsFromRTri(triIdx0, out tmpVertArr[0], out tmpVertArr[1], out tmpVertArr[2]); // put the non-edge vert at idx-0 for (int specialVertIdx = 0; specialVertIdx < 3; ++specialVertIdx) { if (tmpVertArr[specialVertIdx] != ev0 && tmpVertArr[specialVertIdx] != ev1) { var tmp = tmpVertArr[0]; tmpVertArr[0] = tmpVertArr[specialVertIdx]; tmpVertArr[specialVertIdx] = tmp; break; } } GetVVertsFromRTri(triIdx1, out tmpVertArr[1], out tmpVertArr[2], out tmpVertArr[3]); // put the non-edge vert at idx-3 for (int specialVertIdx = 1; specialVertIdx < 4; ++specialVertIdx) { if (tmpVertArr[specialVertIdx] != ev0 && tmpVertArr[specialVertIdx] != ev1) { var tmp = tmpVertArr[3]; tmpVertArr[3] = tmpVertArr[specialVertIdx]; tmpVertArr[specialVertIdx] = tmp; break; } } }
/// <summary> /// given a real vert, return the virtual vert /// </summary> public VVert GetVV(int rvIdx) { Dbg.Assert(m_VVertCont.ContainsKey(rvIdx), "VMesh.GetVV: real vert idx: {0}", rvIdx); VVert vvert = m_VVertCont[rvIdx]; return(vvert); }
// private method private void _PrepareEdgeIndices() { VMesh vmesh = VMesh.Instance; VVert[] allVVerts = vmesh.GetAllVVerts(); VEdge[] allVEdges = vmesh.GetAllVActiveEdges(); Dictionary <VVert, int> vert2idx = new Dictionary <VVert, int>(); for (int i = 0; i < allVVerts.Length; ++i) { VVert v = allVVerts[i]; vert2idx[v] = i; } m_EdgeIndices = new int[allVEdges.Length * 2]; for (int i = 0; i < allVEdges.Length; i++) { VEdge e = allVEdges[i]; VVert v0 = e.GetVVert(0); VVert v1 = e.GetVVert(1); int vidx0 = vert2idx[v0]; int vidx1 = vert2idx[v1]; m_EdgeIndices[i * 2] = vidx0; m_EdgeIndices[i * 2 + 1] = vidx1; } }
private void _AddToVVert(int rvidx, VVert vvert) { Dbg.Assert(!m_VVertCont.ContainsKey(rvidx), "VMesh._AddToVVert: rvIdx already in m_VVertCont: {0}", rvidx); Dbg.Assert(!vvert.Contains(rvidx), "VMesh._AddToVVert: rvIdx already in vvert: {0}", rvidx); m_VVertCont.Add(rvidx, vvert); vvert.AddRVert(rvidx); }
/// <summary> /// DEBUG only /// </summary> public static float CalcScore(int v0, int v1, int v2, int v3) { var inst = sm_Instance; VVert vv0 = inst.GetVV(v0); VVert vv1 = inst.GetVV(v1); VVert vv2 = inst.GetVV(v2); VVert vv3 = inst.GetVV(v3); return(inst._CalcQuadScore(new VVert[] { vv0, vv1, vv2, vv3 })); }
private VVert _ForceGetVVert(_VertUnit v) { int idx = v.idx; VVert vvert = null; if (!m_VVertCont.TryGetValue(idx, out vvert)) { vvert = new VVert(idx); m_VVertCont.Add(idx, vvert); } return(vvert); }
/// <summary> /// given a real-tri idx, /// return the 3 virtual verts belonging to this tri /// [BE WARNED: there're chances that the vverts are not three distinct verts, if the rtri is degraded into edge or point] /// </summary> public void GetVVertsFromRTri(int rtriIdx, out VVert vv0, out VVert vv1, out VVert vv2) { MeshCache cache = MeshCache.Instance; int[] tris = cache.triangles; int rvIdx0 = tris[rtriIdx * 3]; int rvIdx1 = tris[rtriIdx * 3 + 1]; int rvIdx2 = tris[rtriIdx * 3 + 2]; vv0 = GetVV(rvIdx0); vv1 = GetVV(rvIdx1); vv2 = GetVV(rvIdx2); }
/// <summary> /// update the markers, if not dirty, do nothing; /// /// will retrieve info from Mesh & Selection & other related external data-structures /// </summary> public void UpdateMarkers() { if (!Dirty) { return; } //Mesh m = m_EditMesh.mesh; //Transform meshTr = m_EditMesh.transform; //Vector3[] verts = MeshCache.Instance.vertices; VMesh vmesh = VMesh.Instance; // vert positions VVert[] allVVerts = vmesh.GetAllVVerts(); int vcnt = allVVerts.Length; Vector3[] allVVertPos = new Vector3[vcnt]; for (int i = 0; i < vcnt; ++i) { allVVertPos[i] = allVVerts[i].GetWorldPos(); } // colors Color32[] colors = new Color32[vcnt]; for (int i = 0; i < vcnt; ++i) { VVert oneVVert = allVVerts[i]; if (m_Selection.IsSelectedVert(oneVVert.RepVert)) { colors[i] = SelectedVertColor; } else { colors[i] = NonSelectedVertColor; } } // set to mesh(vert) m_VertMarker.SetVerts(allVVertPos); //indices are set altogether with vertices m_VertMarker.SetColors(colors); // set to mesh(edge) m_EdgeMarker.SetVerts(allVVertPos); m_EdgeMarker.SetColors(colors); m_EdgeMarker.SetIndices(m_EdgeIndices); Dirty = false; }
/// <summary> /// NOTE: when with 2 tris, the order is: /// tri0: 012, tri1: 123 /// /// </summary> public void AddRTri(int rTriIdx) { //Dbg.Log("VFace{0}, AddRTri: {1}", m_Idx, rTriIdx); Dbg.Assert(m_rTriCnt < 2, "VFace.AddRTri: already have 2 rtris"); m_rTriIdxs[m_rTriCnt] = rTriIdx; ++m_rTriCnt; VVert vv0, vv1, vv2; VMesh vmesh = VMesh.Instance; vmesh.GetVVertsFromRTri(rTriIdx, out vv0, out vv1, out vv2); if (m_rTriCnt == 1) { m_VVertLst.Add(vv0); m_VVertLst.Add(vv1); m_VVertLst.Add(vv2); } else { //merge with another tri, must ensure order of verts // set lst[0] for (int i = 0; i < 3; ++i) { if (m_VVertLst[i] != vv0 && m_VVertLst[i] != vv1 && m_VVertLst[i] != vv2) { if (i != 0) { VVert tmp = m_VVertLst[0]; m_VVertLst[0] = m_VVertLst[i]; m_VVertLst[i] = tmp; } break; } } //set lst[3] VVert[] verts = new VVert[] { vv0, vv1, vv2 }; for (int i = 0; i < 3; ++i) { if (verts[i] != m_VVertLst[1] && verts[i] != m_VVertLst[2]) { m_VVertLst.Add(verts[i]); break; } } Dbg.Assert(m_VVertLst.Count == 4, "VFace.AddTri: adding new tri, but no new vert added?!"); } }
private VEdge _CreateNewVEdge(VVert vv0, VVert vv1) { // new VEdge e = new VEdge(vv0, vv1); // add to vv0 vv0.AddVEdge(e); // add to vv1 vv1.AddVEdge(e); // add to vedgeCont m_VEdgeCont.Add(e); return(e); }
public void GetVVertsFromRTri(int rtriIdx, List <VVert> vvs) { MeshCache cache = MeshCache.Instance; int[] tris = cache.triangles; for (int i = 0; i < 3; ++i) { int rvIdx = tris[rtriIdx * 3 + i]; VVert vv = GetVV(rvIdx); if (!vvs.Contains(vv)) { vvs.Add(vv); } } }
// private method #region "VVert table init" // "VVert table init" private void _InitVVertTable() { Vector3[] verts = m_RealMesh.vertices; List <_VertUnit> vunits = verts.Select((v, idx) => { return(new _VertUnit(v, idx)); }).ToList(); vunits.Sort(_VertUnit.Compare); m_VVertCont.Clear(); if (vunits.Count == 0) { return; } // init vVertCont List <VVert> vvertLst = new List <VVert>(); float sqrDistThres = DEF_SAME_VERT_DIST_THRES * DEF_SAME_VERT_DIST_THRES; _VertUnit guard = vunits[0]; VVert guardVV = _ForceGetVVert(guard); vvertLst.Add(guardVV); for (int i = 1; i < vunits.Count; ++i) { _VertUnit one = vunits[i]; Vector3 diff = guard.pos - one.pos; if (Vector3.SqrMagnitude(diff) < sqrDistThres) { _AddToVVert(one.idx, guardVV); } else { guard = one; //advance guard to 'one' guardVV = _ForceGetVVert(guard); vvertLst.Add(guardVV); } } // init m_VVertArr m_VVertArr = vvertLst.ToArray(); }
public void Execute(VVert v0, VVert v1, Op op) { if (op == Op.Restart) { m_Selection.Clear(); op = Op.Add; } if (op == Op.Add) { m_Selection.AddVVert(v0); m_Selection.AddVVert(v1); } else { m_Selection.DelVVert(v0); m_Selection.DelVVert(v1); } m_EdgeSet.Add(v0.GetVEdge(v1)); _WalkSelect(v0, v1, op); _WalkSelect(v1, v0, op); m_EdgeSet.Clear(); }
/// <summary> /// rTriIdx might be degraded rtri, but we can get the VFace to which it belongs anyway /// </summary> public VFace GetVFaceFromRTri(int rTriIdx, RaycastHit hit) { VFace vf = null; if (m_VFaceCont.TryGetValue(rTriIdx, out vf)) { return(vf); } else { Dbg.Assert(m_DegRTriCont.Contains(rTriIdx), "VMesh.GetVFaceFromRTri: not in m_VFaceCont or degradedTriCont!?"); m_tmpVVLst.Clear(); GetVVertsFromRTri(rTriIdx, m_tmpVVLst); float minDist = float.MaxValue; VVert retVV = null; for (int i = 0; i < m_tmpVVLst.Count; ++i) { VVert vv = m_tmpVVLst[i]; float dist = Vector3.Distance(hit.point, vv.GetWorldPos()); if (dist < minDist) { minDist = dist; retVV = vv; } } Dbg.Assert(retVV != null, "VMesh.GetVFaceFromRTri: no VVert for given rtri!? {0}", rTriIdx); VFLst vfLst = retVV.GetAllVFaces(); Dbg.Assert(vfLst.Count > 0, "VMesh.GetVFaceFromRTri: the vvert has no VFace, {0}", retVV); return(vfLst[0]); } }
public bool IsSelectedVVert(VVert vvert) { return(IsSelectedVert(vvert.RepVert)); }
// "VQuad table init" /// <summary> /// this method will try to make VMesh from tri-mesh into hybrid tri-quad-mesh, /// it will mark some vedges as "ActiveEdge" which will be used, /// /// the result will be used in: /// * edge marker, /// * edge loop /// * etc /// /// [BE WARNED]: /// </summary> private void _InitVFaceTable() { ////////////////////////////////////////////////// // 1. foreach vedge of the vmesh // if vedge has and only has 2 tris // calc a score and store in sorted_vEdges // 2. foreach vedge in sorted_vEdges // if the 2 tris not be 'marked' yet, then // take it as the 'non-quad' edge; // mark the 2 tris; // 3. get all active-edge into m_VActiveEdgeArr // 3.1 call all vvert, to make activeVEdge // 4. prepare the VFaceCont: // create the rTriIdx <=> VFace first; // merge VFace with those markedTris; // 5. process the degraded r-tris, assign them to some good VFace (so we can handle click-selection) ////////////////////////////////////////////////// int totalTriCnt = MeshCache.Instance.triangles.Length / 3; VVert[] tmpVertArr = new VVert[4]; // step 1 SortedDictionary <_ScoredEdge, bool> sortedVEdges = new SortedDictionary <_ScoredEdge, bool>(); foreach (var vedge in m_VEdgeCont) { if (vedge.GetRTriCount() != 2) { continue; } RTriCont rtris = vedge.GetRTris(); _GetAsQuadVerts(rtris[0], rtris[1], vedge, tmpVertArr); float score = _CalcQuadScore(tmpVertArr); // calc score for the quad-to-be sortedVEdges.Add(new _ScoredEdge(score, vedge), false); } // step 2 //int cnt = 0; Dictionary <int, int> markedTris = new Dictionary <int, int>(); for (var ie = sortedVEdges.GetEnumerator(); ie.MoveNext();) { var vedge = ie.Current.Key.vEdge; //if (cnt < 100) //Dbg.Log("sortedVEdges: {0}: {1}, score:{2}", cnt++, vedge, ie.Current.Key.score); RTriCont triCont = vedge.GetRTris(); Dbg.Assert(triCont.Count == 2, "VMesh._InitVFaceTable: the tri-cont count of vEdge != 2"); if (!markedTris.ContainsKey(triCont[0]) && !markedTris.ContainsKey(triCont[1])) { //Dbg.Log("Add markedTris: {0}<=>{1}", triCont[0], triCont[1]); markedTris.Add(triCont[0], triCont[1]); markedTris.Add(triCont[1], triCont[0]); vedge.IsActiveEdge = false; if (markedTris.Count >= totalTriCnt) { break; // all tris covered, no need to loop on } } } // step 3 List <VEdge> quadEdges = new List <VEdge>(); for (int i = 0; i < m_VEdgeArr.Length; ++i) { if (m_VEdgeArr[i].IsActiveEdge) { quadEdges.Add(m_VEdgeArr[i]); } } m_VActiveEdgeArr = quadEdges.ToArray(); //step 3.1 for (int i = 0; i < m_VVertArr.Length; ++i) { m_VVertArr[i].CreateActiveVEdgesList(); } // step 4 int[] rTriIdxs = MeshCache.Instance.triangles; int rTriCnt = rTriIdxs.Length / 3; for (int i = 0; i < rTriCnt; ++i) { VFace vFace = new VFace(); vFace.AddRTri(i); m_VFaceCont.Add(i, vFace); } for (var ie = markedTris.GetEnumerator(); ie.MoveNext();) { int rTriIdx0 = ie.Current.Key; int rTriIdx1 = ie.Current.Value; if (rTriIdx0 > rTriIdx1) { continue; } VFace vf0 = m_VFaceCont[rTriIdx0]; VFace vf1 = m_VFaceCont[rTriIdx1]; _MergeVFace(vf0, vf1); } markedTris.Clear(); // step 5 _MapVVertToVFaces(); }
// "VEdge cont init" /// <summary> /// [BE WARNED: the degraded triangle case, the triangle might degrade into an edge or a point] /// /// /// </summary> private void _InitVEdgeTable() { int[] rvIdxs = m_RealMesh.triangles; int triCnt = rvIdxs.Length / 3; //Dbg.Log("triCnt = {0}", triCnt); //ETimeProf prof = new ETimeProf(); // loop over all real-tris, and generate VEdges for (int triIdx = 0; triIdx < triCnt; triIdx++) { //prof.SecStart(0); int rv0 = rvIdxs[triIdx * 3]; int rv1 = rvIdxs[triIdx * 3 + 1]; int rv2 = rvIdxs[triIdx * 3 + 2]; VVert vv0 = GetVV(rv0); VVert vv1 = GetVV(rv1); VVert vv2 = GetVV(rv2); bool bDegradedTri = (vv0 == vv1) || (vv1 == vv2) || (vv0 == vv2); if (bDegradedTri) { m_DegRTriCont.Add(triIdx); //record the degraded real-tri } //prof.SecEnd(0); if (vv0 != vv1) { VEdge vedge = null; //prof.SecStart(1); if ((vedge = vv0.GetVEdge(vv1)) == null) { vedge = _CreateNewVEdge(vv0, vv1); } Dbg.Assert(vedge != null, "VMesh._InitVEdgeTable: vedge is null"); if (!bDegradedTri) { vedge.AddRTri(triIdx); } //prof.SecEnd(1); } if (vv1 != vv2) { VEdge vedge = null; //prof.SecStart(2); if ((vedge = vv1.GetVEdge(vv2)) == null) { vedge = _CreateNewVEdge(vv1, vv2); } if (!bDegradedTri) { vedge.AddRTri(triIdx); } //prof.SecEnd(2); } if (vv0 != vv2) { VEdge vedge = null; //prof.SecStart(3); if ((vedge = vv2.GetVEdge(vv0)) == null) { vedge = _CreateNewVEdge(vv2, vv0); } if (!bDegradedTri) { vedge.AddRTri(triIdx); } //prof.SecEnd(3); } } // end of for m_VEdgeArr = m_VEdgeCont.ToArray(); //prof.SecShowAll(); }
public bool Contains(VVert vvert) { return(vvert.Equals(m_VVerts[0]) || vvert.Equals(m_VVerts[1])); }
public void DelVVert(VVert vvert) { RVLst vLst = vvert.GetRVerts(); DelVert(vLst.ToArray()); }
/// <summary> /// given a real vert idx, /// return all virtual edges connected to this vert /// </summary> public VELst GetVEdgesFromRVert(int rvIdx) { VVert vvert = GetVV(rvIdx); return(vvert.GetVEdges()); }
/// <summary> /// given a real vert idx, /// return all real verts under same virtual vert /// </summary> public RVLst GetRVertsFromRVert(int rvIdx) { VVert vvert = GetVV(rvIdx); return(vvert.GetRVerts()); }
// private method /// <summary> /// try to process v2 if possible (under given op) /// [v0 ==> v1 == v2] in this order /// </summary> private void _WalkSelect(VVert v0, VVert v1, Op op) { ////////////////////////////////////////////////// // 1. if v1 doesn't have exactly 4 vedges, return; // 2. take the vedge E that doesn't share VFace with vedge(v0,v1) // 3. select the other vvert v2 of E; // 4. iterate as _WalkSelect(v1, v2, op) ////////////////////////////////////////////////// VEdge thisEdge = v0.GetVEdge(v1); thisEdge.GetVFaces(m_tmpVFaces1); while (true) { // step 1 VELst veLst = v1.GetActiveVEdges(); if (veLst.Count != GOOD_EDGE_CNT) { //Dbg.Log("_WalkSelect: {0}=>{1}, veLst.Count not 4, is {2}", v0, v1, veLst.Count); break; //END } // step 2 VEdge thatEdge = null; for (int i = 0; i < GOOD_EDGE_CNT; ++i) { VEdge rhs = veLst[i]; if (rhs == thisEdge) { continue; } rhs.GetVFaces(m_tmpVFaces2); if (!_HasIntersect(m_tmpVFaces1, m_tmpVFaces2)) { thatEdge = rhs; break; //just out of edge loop } } // step 3 VVert v2 = null; if (thatEdge != null) { v2 = thatEdge.GetVVert(0); if (v2 == v1) { v2 = thatEdge.GetVVert(1); } // check for inf loop VEdge newEdge = v1.GetVEdge(v2); if (m_EdgeSet.Contains(newEdge)) { break; //END } m_EdgeSet.Add(newEdge); // modify selection if (op == Op.Add) { m_Selection.AddVVert(v2); } else { m_Selection.DelVVert(v2); } // step 4 v0 = v1; v1 = v2; thisEdge = thatEdge; Misc.Swap(ref m_tmpVFaces1, ref m_tmpVFaces2); } else { //Dbg.Log("_WalkSelect: {0}=>{1}, not found thatEdge", v0, v1); break; //END } } // end of while(true) }
public void AddVVert(VVert vvert) { RVLst vLst = vvert.GetRVerts(); AddVert(vLst.ToArray()); }
public void SetVVert(int idx, VVert vvert) { m_VVerts[idx] = vvert; }