private bool ShouldRemoveEdge(HEEdge edge, bool pairInOtherSide) { HEEdge pair = heEdges[edge.pair]; return !pairInOtherSide || (pairInOtherSide && (pair.startVertex != edge.endVertex || pair.endVertex != edge.startVertex)); }
/** * Analyzes the input mesh and populates the half-edge structure. Can be called as many times you want (for examples if the original mesh is modified). */ public IEnumerator Generate() { if (input != null){ heFaces.Clear(); heVertices.Clear(); heEdges.Clear(); _area = 0; _modified = false; Dictionary<Vector3, HEVertex> vertexBuffer = new Dictionary<Vector3, HEVertex>(); Dictionary<KeyValuePair<int,int>,HEEdge> edgeBuffer = new Dictionary<KeyValuePair<int,int>,HEEdge>(); // Get copies of vertex and triangle buffers: Vector3[] vertices = input.vertices; int[] triangles = input.triangles; // first, create vertices: for(int i = 0; i < vertices.Length; i++){ //if the vertex already exists, add physical vertex index to it. HEVertex vertex; if (vertexBuffer.TryGetValue(vertices[i], out vertex)){ vertex.physicalIDs.Add(i); }else{ vertex = new HEVertex(i); } vertexBuffer[vertices[i]] = vertex; if (i % 200 == 0) yield return new CoroutineJob.ProgressInfo("Half-edge: analyzing vertices...",i/(float)vertices.Length); } // assign unique indices to vertices: int index = 0; foreach(KeyValuePair<Vector3,HEVertex> pair in vertexBuffer){ ((HEVertex)pair.Value).index = index; heVertices.Add(pair.Value); if (index % 200 == 0) yield return new CoroutineJob.ProgressInfo("Half-edge: assigning indices...",index/(float)vertices.Length); index++; } // build half edge structure: for(int i = 0; i<triangles.Length;i+=3){ Vector3 pos1 = vertices[triangles[i]]; Vector3 pos2 = vertices[triangles[i+1]]; Vector3 pos3 = vertices[triangles[i+2]]; HEVertex v1 = vertexBuffer[pos1]; HEVertex v2 = vertexBuffer[pos2]; HEVertex v3 = vertexBuffer[pos3]; // create half edges: HEEdge e1 = new HEEdge(); e1.index = heEdges.Count; e1.indexOnFace = 0; e1.faceIndex = heFaces.Count; e1.endVertex = v1.index; e1.startVertex = v2.index; HEEdge e2 = new HEEdge(); e2.index = heEdges.Count+1; e2.indexOnFace = 1; e2.faceIndex = heFaces.Count; e2.endVertex = v2.index; e2.startVertex = v3.index; HEEdge e3 = new HEEdge(); e3.index = heEdges.Count+2; e3.indexOnFace = 2; e3.faceIndex = heFaces.Count; e3.endVertex = v3.index; e3.startVertex = v1.index; // link half edges together: e1.nextEdgeIndex = e3.index; e2.nextEdgeIndex = e1.index; e3.nextEdgeIndex = e2.index; // vertex outgoing half edge indices: v1.halfEdgeIndex = e3.index; v2.halfEdgeIndex = e1.index; v3.halfEdgeIndex = e2.index; // add edges: heEdges.Add(e1); heEdges.Add(e2); heEdges.Add(e3); // populate and add face: HEFace face = new HEFace(); face.edges[0] = e1.index; face.edges[1] = e2.index; face.edges[2] = e3.index; face.area = ObiUtils.TriangleArea(pos1,pos2,pos3); _area += face.area; _volume += Vector3.Dot(Vector3.Cross(pos1,pos2),pos3)/6f; face.index = heFaces.Count; heFaces.Add(face); try{ edgeBuffer.Add(new KeyValuePair<int,int>(v1.index,v2.index),e1); edgeBuffer.Add(new KeyValuePair<int,int>(v2.index,v3.index),e2); edgeBuffer.Add(new KeyValuePair<int,int>(v3.index,v1.index),e3); }catch{ Debug.LogError("Your mesh is non manifold, and thus cannot be processed by Obi: more than 1 edge joining the same pair of vertices."); heFaces.Clear(); heVertices.Clear(); heEdges.Clear(); _area = 0; yield break; } if (i % 500 == 0) yield return new CoroutineJob.ProgressInfo("Half-edge: generating edges and faces...",i/(float)triangles.Length); } List<HEEdge> borderEdges = new List<HEEdge>(); //edges belonging to a mesh border. // stitch half edge pairs together: index = 0; foreach(KeyValuePair<KeyValuePair<int,int>,HEEdge> pair in edgeBuffer){ KeyValuePair<int,int> edgeKey = new KeyValuePair<int,int>(pair.Key.Value,pair.Key.Key); HEEdge edge = null; if (edgeBuffer.TryGetValue(edgeKey, out edge)){ ((HEEdge)pair.Value).pair = edge.index; }else{ //create border edge: HEEdge e = new HEEdge(); e.index = heEdges.Count; e.endVertex = ((HEEdge)pair.Value).startVertex; e.startVertex = ((HEEdge)pair.Value).endVertex; heVertices[e.startVertex].halfEdgeIndex = e.index; e.pair = ((HEEdge)pair.Value).index; ((HEEdge)pair.Value).pair = e.index; heEdges.Add(e); borderEdges.Add(e); } if (index % 1000 == 0) yield return new CoroutineJob.ProgressInfo("Half-edge: stitching half-edges...",index/(float)edgeBuffer.Count); index++; } _closed = borderEdges.Count == 0; // link together border edges: foreach(HEEdge edge in borderEdges){ edge.nextEdgeIndex = heVertices[edge.endVertex].halfEdgeIndex; } }else{ Debug.LogWarning("Tried to generate adjacency info for an empty mesh."); } }