// split the face in the center // return the new Vertex public Vertex Split() { Vertex v = hmesh.CreateVertex(); List <Halfedge> newHalfedges = new List <Halfedge>(); List <Vertex> vertices = new List <Vertex>(); // create double halfedges foreach (var he in Circulate()) { v.position += he.vert.position; v.uv1 += he.vert.uv1; v.uv2 += he.vert.uv2; Halfedge toNewVertex = hmesh.CreateHalfedge(); Halfedge fromNewVertex = hmesh.CreateHalfedge(); toNewVertex.Glue(fromNewVertex); newHalfedges.Add(toNewVertex); vertices.Add(he.vert); } int count = 0; // second iteration - link everything together foreach (var he in Circulate()) { Vertex prevVertex = vertices[(count - 1 + newHalfedges.Count) % newHalfedges.Count]; Vertex nextVertex = vertices[count]; Halfedge prevNewOppEdge = newHalfedges[(count - 1 + newHalfedges.Count) % newHalfedges.Count].opp; Halfedge newEdge = newHalfedges[count]; // link halfedges newEdge.Link(prevNewOppEdge); prevNewOppEdge.Link(he); he.Link(newEdge); // link vertices newEdge.vert = v; v.halfedge = prevNewOppEdge; prevNewOppEdge.vert = prevVertex; bool first = count == 0; Face f = he.face; if (!first) { f = hmesh.CreateFace(); } f.halfedge = he; f.ReassignFaceToEdgeLoop(); count++; } v.position = v.position * (1.0f / count); // set average position v.uv1 = v.uv1 * (1.0f / count); v.uv2 = v.uv2 * (1.0f / count); return(v); }
// Creates a new vertex inside the face and connect it to the cutFrom vertex using two halfedges. // Note that this function leaves the face in an invalid state, since the new halfedges will have face == opp.face. public Vertex CutInto(Vertex cutFrom, Vector3 pos) { Debug.Assert(cutFrom.hmesh == hmesh); Halfedge cutFromEdge = null; foreach (var e in Circulate()) { if (e.vert == cutFrom) { cutFromEdge = e; } } if (cutFromEdge == null) { Debug.LogError("Cannot find vertex in face"); return(null); } Vertex newVertex = hmesh.CreateVertex(); newVertex.position = pos; Halfedge he1 = hmesh.CreateHalfedge(); Halfedge he2 = hmesh.CreateHalfedge(); he1.Glue(he2); Halfedge cutFromEdgeNext = cutFromEdge.next; cutFromEdge.Link(he1); he1.Link(he2); he2.Link(cutFromEdgeNext); he1.Link(this); he2.Link(this); he1.vert = newVertex; newVertex.halfedge = he1.next; Debug.Assert(newVertex.halfedge != null); he2.vert = cutFrom; cutFrom.halfedge = he2.next; return(newVertex); }
// Cut the face in two parts. Assumes that the face is convex public Face Cut(Vertex v1, Vertex v2) { Debug.Assert(v1.hmesh == hmesh); Debug.Assert(v2.hmesh == hmesh); Debug.Assert(v1.halfedge != null); Debug.Assert(v2.halfedge != null); Debug.Assert(v1 != v2); Halfedge v1He = null; Halfedge v2He = null; foreach (var he in Circulate()) { if (he.vert == v1) { v1He = he; } else if (he.vert == v2) { v2He = he; } } if (v1He == null || v2He == null) { Debug.LogError("Cannot find vertices for split"); return(null); } Debug.Assert(v1He != v2He); Halfedge v1HeNext = v1He.next; Halfedge v2HeNext = v2He.next; Face f = hmesh.CreateFace(); Halfedge he1 = hmesh.CreateHalfedge(); Halfedge he2 = hmesh.CreateHalfedge(); he1.Glue(he2); v1He.Link(he1); he1.Link(v2HeNext); v2He.Link(he2); he2.Link(v1HeNext); he1.vert = v2; he2.vert = v1; halfedge = he1; ReassignFaceToEdgeLoop(); f.halfedge = he2; f.ReassignFaceToEdgeLoop(); v1.halfedge = v1HeNext; v2.halfedge = v2HeNext; return(f); }
// If boundary vertex Dissolve face. // Otherwise return false public bool Dissolve() { List <Halfedge> hes = Circulate(); if (!IsBoundary()) { return(false); } if (hes.Count == 1) { var faceEdges = halfedge.face.Circulate(); if (faceEdges.Count > 2) { Halfedge oldHe = halfedge; Halfedge prev = halfedge.prev; Halfedge next = halfedge.next; prev.Link(next); prev.vert = oldHe.vert; oldHe.face.halfedge = prev; hmesh.Destroy(oldHe); hmesh.Destroy(this); } else { halfedge.face.Dissolve2Edges(); } } else if (hes.Count == 2) { foreach (var he in hes) { if (he.opp != null) { var newPos = he.vert.positionD; var vertex = he.Collapse(); vertex.positionD = newPos; return(true); } } } else { // iterate each neighbour face foreach (var faceHe in hes) { faceHe.face.Dissolve(); } } return(true); }
// Cut the face in two parts. Assumes that the face is convex // The new face is always created as the one that contains vertices between v1 and v2 public Face Cut(Vertex v1, Vertex v2) { Debug.Assert(v1.hmesh == hmesh); Debug.Assert(v2.hmesh == hmesh); Debug.Assert(v1.halfedge != null); Debug.Assert(v2.halfedge != null); Debug.Assert(v1 != v2); Halfedge v1He = null; Halfedge v2He = null; var edges = Circulate(); Debug.Assert(edges.Count > 3); foreach (var he in edges) { if (he.vert == v1) { v1He = he; } else if (he.vert == v2) { v2He = he; } } if (v1He == null || v2He == null) { if (v1He == null) { Debug.Log("Could not find first parameter"); } if (v2He == null) { Debug.Log("Could not find second parameter"); } return(null); } Debug.Assert(v1He != v2He); if (v1He.prev.vert == v2) { Debug.LogWarning("face " + id + " cut adjacent vertices " + v1 + " to " + v2); return(this); } if (v2He.prev.vert == v1) { Debug.LogWarning("face " + id + " cut adjacent vertices " + v1 + " to " + v2); return(this); } Halfedge v1HeNext = v1He.next; Halfedge v2HeNext = v2He.next; Face f = hmesh.CreateFace(); Halfedge he1 = hmesh.CreateHalfedge(); Halfedge he2 = hmesh.CreateHalfedge(); he1.Glue(he2); v1He.Link(he1); he1.Link(v2HeNext); v2He.Link(he2); he2.Link(v1HeNext); he1.vert = v2; he2.vert = v1; halfedge = he1; ReassignFaceToEdgeLoop(); f.halfedge = he2; f.ReassignFaceToEdgeLoop(); return(f); }
public void Build(Mesh mesh, Matrix4x4 transform, int submesh = 0) { if (mesh.GetTopology(0) != MeshTopology.Triangles) { Debug.LogError("Only triangles supported."); } Dictionary <ulong, Halfedge> halfedgeByVertexID = new Dictionary <ulong, Halfedge>(); // Create a list of (HMesh) Vertices var meshVertices = mesh.vertices; var meshUv = mesh.uv; var meshUv2 = mesh.uv2; List <Vertex> vertexList = new List <Vertex>(meshVertices.Length); bool hasUv1 = meshUv != null && meshUv.Length == meshVertices.Length; bool hasUv2 = meshUv2 != null && meshUv2.Length == meshVertices.Length; for (int i = 0; i < meshVertices.Length; i++) { var newV = CreateVertex(); newV.position = transform.MultiplyPoint(meshVertices[i]); if (hasUv1) { newV.uv1 = meshUv[i]; } if (hasUv2) { newV.uv2 = meshUv2[i]; } vertexList.Add(newV); } // create faces and half edges var meshTriangles = mesh.GetTriangles(submesh); for (int i = 0; i < meshTriangles.Length; i += 3) { int[] idx = new int[] { meshTriangles[i], meshTriangles[i + 1], meshTriangles[i + 2] }; Halfedge[] edges = new Halfedge[3]; Face face = CreateFace(); for (int j = 0; j < 3; j++) { Halfedge edge = CreateHalfedge(); edge.Link(face); edges[j] = edge; } for (int j = 0; j < 3; j++) { int from = idx[j]; int to = idx[(j + 1) % 3]; edges[j].Link(edges[(j + 1) % 3]); edges[j].vert = vertexList[to]; edges[j].vert.label++; ulong edgeId = EdgeKey(from, to); if (halfedgeByVertexID.ContainsKey(edgeId)) { var oldEdge = halfedgeByVertexID[edgeId]; Debug.LogError("Edge old edge from " + oldEdge.vert.position + " to " + oldEdge.prev.vert.position); Debug.LogError("Edge already exists from " + vertexList[to].position + " to " + vertexList[from].position); } halfedgeByVertexID.Add(edgeId, edges[j]); } } for (int i = vertexList.Count - 1; i >= 0; i--) { if (vertexList[i].label == 0) { Destroy(vertexList[i]); } } int glued = 0; // glue all opposite half edges for (int i = 0; i < meshTriangles.Length; i += 3) { int[] idx = { meshTriangles[i], meshTriangles[i + 1], meshTriangles[i + 2] }; for (int j = 0; j < 3; j++) { int from = idx[j]; int to = idx[(j + 1) % 3]; ulong key = EdgeKey(from, to); ulong oppKey = EdgeKey(to, from); Halfedge edge = halfedgeByVertexID[key]; bool isOppUnassigned = edge.opp == null; if (isOppUnassigned && key < oppKey && halfedgeByVertexID.ContainsKey(oppKey)) { Halfedge oppEdge = halfedgeByVertexID[oppKey]; edge.Glue(oppEdge); glued++; } } } SplitNonManifoldVertices(); }
public void Build(Mesh mesh, Matrix4x4 transform) { if (mesh.subMeshCount != 1) { Debug.LogError("Invalid mesh.subMeshCount. Must be 1."); } if (mesh.GetTopology(0) != MeshTopology.Triangles) { Debug.LogError("Only triangles supported."); } List <Vertex> vertexList = new List <Vertex>(); Dictionary <uint, Halfedge> halfedgeByVertexID = new Dictionary <uint, Halfedge>(); // Create a list of (HMesh) Vertices bool hasUv1 = mesh.uv != null && mesh.uv.Length == mesh.vertices.Length; bool hasUv2 = mesh.uv2 != null && mesh.uv2.Length == mesh.vertices.Length; for (int i = 0; i < mesh.vertices.Length; i++) { var newV = CreateVertex(); newV.position = transform.MultiplyPoint(mesh.vertices[i]); if (hasUv1) { newV.uv1 = mesh.uv[i]; } if (hasUv2) { newV.uv2 = mesh.uv2[i]; } vertexList.Add(newV); } // create faces and half edges for (int i = 0; i < mesh.triangles.Length; i += 3) { int[] idx = new int[] { mesh.triangles[i], mesh.triangles[i + 1], mesh.triangles[i + 2] }; Halfedge[] edges = new Halfedge[3]; Face face = CreateFace(); for (int j = 0; j < 3; j++) { Halfedge edge = CreateHalfedge(); edge.Link(face); edges[j] = edge; } for (int j = 0; j < 3; j++) { int from = idx[j]; int to = idx[(j + 1) % 3]; edges[j].Link(edges[(j + 1) % 3]); edges[j].vert = vertexList[to]; vertexList[to].halfedge = edges[j].next; uint edgeId = EdgeKey(from, to); halfedgeByVertexID.Add(edgeId, edges[j]); } } int glued = 0; // glue all opposite half edges for (int i = 0; i < mesh.triangles.Length; i += 3) { int[] idx = new int[] { mesh.triangles[i], mesh.triangles[i + 1], mesh.triangles[i + 2] }; for (int j = 0; j < 3; j++) { int from = idx[j]; int to = idx[(j + 1) % 3]; uint key = EdgeKey(from, to); uint oppKey = EdgeKey(to, from); Halfedge edge = halfedgeByVertexID[key]; bool isOppUnassigned = edge.opp == null; if (isOppUnassigned && halfedgeByVertexID.ContainsKey(oppKey)) { Halfedge oppEdge = halfedgeByVertexID[oppKey]; edge.Glue(oppEdge); glued++; } } } }