public override bool Equals(object obj) { if (obj is EdgePair) { EdgePair other = (EdgePair)obj; return((x == other.x) && (y == other.y)); } else { return(false); } }
public void InitFromMesh(Mesh m) { Dictionary <EdgePair, HalfEdge> edgesToHEs = new Dictionary <EdgePair, HalfEdge>(); Vector3[] meshVertices = m.vertices; int[] meshTriangles = m.triangles; List <EdgePair>[] vertsToEdges = new List <EdgePair> [meshVertices.Length]; int numTriangles = meshTriangles.Length / 3; // Map directed edges to the triangles that contain them. for (int i = 0; i < numTriangles; i++) { int i1 = meshTriangles[3 * i]; int i2 = meshTriangles[3 * i + 1]; int i3 = meshTriangles[3 * i + 2]; EdgePair e1 = new EdgePair(i1, i2); EdgePair e2 = new EdgePair(i2, i3); EdgePair e3 = new EdgePair(i3, i1); // Also map each vertex to the set of edges originating from it. // We need this to traverse boundary loops later. if (vertsToEdges[i1] == null) { vertsToEdges[i1] = new List <EdgePair>(); } vertsToEdges[i1].Add(e1); if (vertsToEdges[i2] == null) { vertsToEdges[i2] = new List <EdgePair>(); } vertsToEdges[i2].Add(e2); if (vertsToEdges[i3] == null) { vertsToEdges[i3] = new List <EdgePair>(); } vertsToEdges[i3].Add(e3); } Vertex[] heVertices = new Vertex[m.vertices.Length]; List <Face> heFaces = new List <Face>(); List <Edge> heEdges = new List <Edge>(); List <HalfEdge> hes = new List <HalfEdge>(); // Make all the vertices we're going to need, mapped by same indices for (int i = 0; i < heVertices.Length; i++) { Vertex v = new Vertex(); v.position = meshVertices[i]; heVertices[i] = v; } // Make all the faces, mapped by same indices for (int i = 0; i < numTriangles; i++) { Face f = new Face(); heFaces.Add(f); } // Make all half-edges, face by face. for (int triBase = 0; triBase < numTriangles; triBase++) { int triIndex = 3 * triBase; // For each edge in the current triangle, we make both half-edges. for (int vert = 0; vert < 3; vert++) { int currOffset = vert; int nextOffset = (vert + 1) % 3; int v1 = meshTriangles[triIndex + currOffset]; int v2 = meshTriangles[triIndex + nextOffset]; // Make the forward-pointing half-edge. EdgePair currentEdge = new EdgePair(v1, v2); HalfEdge forwardHE = new HalfEdge(); hes.Add(forwardHE); edgesToHEs.Add(currentEdge, forwardHE); // Mark the new half-edge as belonging to the current face. forwardHE.face = heFaces[triBase]; heFaces[triBase].anyHalfEdge = forwardHE; } // Now we set the "next" pointers for each half-edge in this face, // and also the "flip" pointers if the flip edges have already been // created. for (int vert = 0; vert < 3; vert++) { int currOffset = vert; int nextOffset = (vert + 1) % 3; int lastOffset = (vert + 2) % 3; int v1 = meshTriangles[triIndex + currOffset]; int v2 = meshTriangles[triIndex + nextOffset]; int v3 = meshTriangles[triIndex + lastOffset]; HalfEdge current = edgesToHEs[new EdgePair(v1, v2)]; HalfEdge nextHE = edgesToHEs[new EdgePair(v2, v3)]; current.next = nextHE; HalfEdge flipHE; if (edgesToHEs.TryGetValue(new EdgePair(v2, v1), out flipHE)) { current.flip = flipHE; flipHE.flip = current; } } } List <EdgePair> boundaryPairs = new List <EdgePair>(); List <HalfEdge> boundaryHEs = new List <HalfEdge>(); int numBoundaryFaces = 0; int numBoundaryEdges = 0; // Make boundary loops foreach (var kv in edgesToHEs) { EdgePair edgeIndices = kv.Key; HalfEdge he = kv.Value; // If this half-edge already has a flip if (he.flip != null) { continue; } // Otherwise make the flip half-edge, which will be the first // of a boundary loop. EdgePair reversedEdge = new EdgePair(edgeIndices[1], edgeIndices[0]); HalfEdge boundaryHE = new HalfEdge(); boundaryHE.onBoundary = true; boundaryPairs.Add(reversedEdge); boundaryHEs.Add(boundaryHE); // Make a new face for this boundary loop. Face boundaryFace = new Face(); numBoundaryFaces++; heFaces.Add(boundaryFace); boundaryFace.anyHalfEdge = boundaryHE; boundaryHE.face = boundaryFace; // Assign the flip half-edge to the same edge as the original. boundaryHE.edge = he.edge; // The tail of this vertex is opposite the tail of the original. boundaryHE.tailVertex = heVertices[edgeIndices[1]]; // Assign flips. he.flip = boundaryHE; boundaryHE.flip = he; numBoundaryEdges++; // Now we need to walk this boundary loop until the end. int startIndex = edgeIndices[1]; HalfEdge prevHE = boundaryHE; // Search for the next edge along this boundary loop, // by looking for the next half-edge with no flip vertex. do { EdgePair nextPair = new EdgePair(); foreach (EdgePair e in vertsToEdges[startIndex]) { nextPair = e; // If the next half-edge has no flip, then it's also on the boundary, // so its flip is the one we want to make. if (edgesToHEs[e].flip == null) { break; } } if (edgesToHEs[nextPair].flip != null) { throw new System.Exception("Boundary loop hits a dead end."); } HalfEdge insideHE = edgesToHEs[nextPair]; // Make the flip of this one. HalfEdge nextBoundary = new HalfEdge(); nextBoundary.onBoundary = true; // Set flips. insideHE.flip = nextBoundary; nextBoundary.flip = insideHE; // Since the boundary loops are pointing the opposite direction from // how we're traversing, "next" from the new half-edge is actually // the previous half-edge we added. nextBoundary.next = prevHE; // The face is the same boundary loop. nextBoundary.face = boundaryFace; // The edge is the same as its twin. nextBoundary.edge = insideHE.edge; // The vertex is the head vertex of the twin. nextBoundary.tailVertex = heVertices[nextPair[1]]; numBoundaryEdges++; // Add to lists boundaryPairs.Add(new EdgePair(nextPair[1], nextPair[0])); boundaryHEs.Add(nextBoundary); prevHE = nextBoundary; startIndex = nextPair[1]; }while (startIndex != edgeIndices[0]); // Now prevHE comes directly after the initial half-edge, so // this is the initial half-edge's "next". boundaryHE.next = prevHE; } for (int i = 0; i < boundaryPairs.Count; i++) { edgesToHEs.Add(boundaryPairs[i], boundaryHEs[i]); } hes.AddRange(boundaryHEs); // Set vertices and edges foreach (var kv in edgesToHEs) { EdgePair edgeIndices = kv.Key; HalfEdge he = kv.Value; int baseVertex = edgeIndices[0]; he.tailVertex = heVertices[baseVertex]; heVertices[baseVertex].anyHalfEdge = he; // If the edge object has not been created yet, create it if (he.edge == null) { Edge edgeObj = new Edge(); heEdges.Add(edgeObj); edgeObj.anyHalfEdge = he; he.edge = edgeObj; he.flip.edge = edgeObj; } } /* * Debug.Log("Original mesh: " + * meshVertices.Length + " vertices, " + * (numInteriorEdges + numBoundaryEdges / 2) + " edges, " + * numTriangles + " faces"); * Debug.Log("Half-edge mesh: " + * heVertices.Length + " vertices, " + * hes.Count + " half-edges, " + * heEdges.Count + " edges, " + * heFaces.Count + " faces (" + numBoundaryFaces + " boundary)"); */ vertices = heVertices; edges = heEdges.ToArray(); faces = heFaces.ToArray(); halfEdges = hes.ToArray(); TagIndices(); //Validate(); //ComputeAverageValence(); }