public static HMesh CreateTestMeshQuad() { HMesh mesh = new HMesh(); var face = mesh.CreateFace(); var edges = new Halfedge[]{ mesh.CreateHalfedge(), mesh.CreateHalfedge(), mesh.CreateHalfedge(), mesh.CreateHalfedge(), }; var verts = new Vertex[]{ mesh.CreateVertex(new Vector3(0,0,0)), mesh.CreateVertex(new Vector3(1,0,0)), mesh.CreateVertex(new Vector3(1,0,1)), mesh.CreateVertex(new Vector3(0,0,1)), }; for (int i=0;i<4;i++){ edges[i].Link(face); edges[i].next = edges[(i+1)%4]; edges[(i+1)%4].prev = edges[i]; edges[i].vert = verts[i]; verts[i].halfedge = edges[i].next; } return mesh; }
public EdgeList(float xmin,float deltax,int sqrt_nsites) { _xmin=xmin; _deltax=deltax; _hashsize=2*sqrt_nsites; int i; _hash=new List<Halfedge>(); _leftEnd = Halfedge.createDummy(); _rightEnd = Halfedge.createDummy(); _leftEnd.edgeListLeftNeighbor = null; _leftEnd.edgeListRightNeighbor = _rightEnd; _rightEnd.edgeListLeftNeighbor = _leftEnd; _rightEnd.edgeListRightNeighbor = null; _hash[0] = _leftEnd; _hash[_hashsize - 1] = _rightEnd; }
public void remove(Halfedge halfEdge) { Halfedge previous; int removalBucket=bucket(halfEdge); if(halfEdge.vertex!=null){ previous = _hash[removalBucket]; while (previous.nextInPriorityQueue != halfEdge) { previous = previous.nextInPriorityQueue; } previous.nextInPriorityQueue = halfEdge.nextInPriorityQueue; _count--; halfEdge.vertex = null; halfEdge.nextInPriorityQueue = null; halfEdge.dispose(); } }
public void insert(Halfedge halfEdge) { Halfedge previous,next; int insertionBucket=bucket(halfEdge); if (insertionBucket < _minBucket) { _minBucket = insertionBucket; } previous = _hash[insertionBucket]; while ((next = previous.nextInPriorityQueue) != null && (halfEdge.ystar > next.ystar || (halfEdge.ystar == next.ystar && halfEdge.vertex.x > next.vertex.x))) { previous = next; } halfEdge.nextInPriorityQueue = previous.nextInPriorityQueue; previous.nextInPriorityQueue = halfEdge; ++_count; }
public void dispose() { Halfedge halfEdge=_leftEnd; Halfedge prevHe; while (halfEdge != _rightEnd) { prevHe = halfEdge; halfEdge = halfEdge.edgeListRightNeighbor; prevHe.dispose(); } _leftEnd = null; _rightEnd.dispose(); _rightEnd = null; int i; for (i = 0; i < _hashsize; ++i) { _hash[i] = null; } _hash = null; }
public static Vertex intersect( Halfedge halfedge0,Halfedge halfedge1) { Edge edge0,edge1,edge; Halfedge helfedge; float determinant,intersectionX,intersectionY; bool rightOfSite; edge0=halfedge0.edge; edge1=halfedge1.edge; if(edge0==null || edge1==null){ return null; } if(edge0.rightSite==edge1.rightSite){ return null; } determinant=edge0.a*dege1.b-dege0.b*edge1.a; if(-1.0e-10 <determinant && determinant<1.0e-10){ return null; } intersectionX = (edge0.c * edge1.b - edge1.c * edge0.b)/determinant; intersectionY = (edge1.c * edge0.a - edge0.c * edge1.a)/determinant; if (Voronoi.compareByYThenX(edge0.rightSite, edge1.rightSite) < 0) { halfedge = halfedge0; edge = edge0; } else { halfedge = halfedge1; edge = edge1; } rightOfSite = intersectionX >= edge.rightSite.x; if ((rightOfSite && halfedge.leftRight == LR.LEFT) || (!rightOfSite && halfedge.leftRight == LR.RIGHT)) { return null; } return Vertex.create(intersectionX, intersectionY); }
// push the HalfEdge into the ordered linked list of vertices private void PQinsert( Halfedge he, Site v, double offset ) { Halfedge last, next; he.vertex = v; he.ystar = (double)(v.coord.y + offset); last = PQhash [ PQbucket (he) ]; while ( (next = last.PQnext) != null && (he.ystar > next.ystar || (he.ystar == next.ystar && v.coord.x > next.vertex.coord.x)) ) { last = next; } he.PQnext = last.PQnext; last.PQnext = he; PQcount++; }
/* returns true if p is to right of halfedge e */ private bool right_of(Halfedge el, Point p) { Edge e; Site topsite; bool right_of_site; bool above, fast; double dxp, dyp, dxs, t1, t2, t3, yl; e = el.ELedge; topsite = e.reg[1]; if ( p.x > topsite.coord.x ) right_of_site = true; else right_of_site = false; if ( right_of_site && el.ELpm == LE ) return true; if (!right_of_site && el.ELpm == RE ) return false; if ( e.a == 1.0 ) { dxp = p.x - topsite.coord.x; dyp = p.y - topsite.coord.y; fast = false; if ( (!right_of_site & (e.b < 0.0)) | (right_of_site & (e.b >= 0.0)) ) { above = dyp >= e.b * dxp; fast = above; } else { above = p.x + p.y * e.b > e.c; if ( e.b < 0.0 ) above = !above; if ( !above ) fast = true; } if ( !fast ) { dxs = topsite.coord.x - ( e.reg[0] ).coord.x; above = e.b * (dxp * dxp - dyp * dyp) < dxs * dyp * (1.0 + 2.0 * dxp / dxs + e.b * e.b); if ( e.b < 0 ) above = !above; } } else // e.b == 1.0 { yl = e.c - e.a * p.x; t1 = p.y - yl; t2 = p.x - topsite.coord.x; t3 = yl - topsite.coord.y; above = t1 * t1 > t2 * t2 + t3 * t3; } return ( el.ELpm == LE ? above : !above ); }
private Site leftreg( Halfedge he ) { if (he.ELedge == null) { return bottomsite; } return (he.ELpm == LE ? he.ELedge.reg[LE] : he.ELedge.reg[RE]); }
// remove the HalfEdge from the list of vertices private void PQdelete( Halfedge he ) { Halfedge last; if (he.vertex != null) { last = PQhash [ PQbucket (he) ]; while ( last.PQnext != he ) { last = last.PQnext; } last.PQnext = he.PQnext; PQcount--; he.vertex = null; } }
private bool ELinitialize() { ELhashsize = 2 * sqrt_nsites; ELhash = new Halfedge[ELhashsize]; for (int i = 0; i < ELhashsize; i++) { ELhash[i] = null; } ELleftend = HEcreate ( null, 0 ); ELrightend = HEcreate ( null, 0 ); ELleftend.ELleft = null; ELleftend.ELright = ELrightend; ELrightend.ELleft = ELleftend; ELrightend.ELright = null; ELhash[0] = ELleftend; ELhash[ELhashsize - 1] = ELrightend; return true; }
double min_angle(Halfedge h) { compute_angles(h); return(System.Math.Min(System.Math.Min(System.Math.Min(System.Math.Min(aa_12, aa_b1), aa_c1), aa_2a), aa_2d)); }
public void remove(Halfedge halfEdge) { halfEdge.edgeListLeftNeighbor.edgeListRightNeighbor = halfEdge.edgeListRightNeighbor; halfEdge.edgeListRightNeighbor.edgeListLeftNeighbor = halfEdge.edgeListLeftNeighbor; halfEdge.edge = Edge.DELETED; halfEdge.edgeListLeftNeighbor = halfEdge.edgeListRightNeighbor = null; }
private Halfedge init(Edge edge,LR lr) { this.edge=edge; leftRight=lr; nextInPriorityQueue=null; vertex=null; return this; }
bool PrecondFlipEdge(Halfedge h) { Face hf = h.face; if (h.opp == null) { return(false); } Face hof = h.opp.face; if (FaceLabelContrain) { if (hf.label != hof.label) { return(false); } } if (FaceNormalContrain) { var fn = hf.GetNormal(); var fon = hof.GetNormal(); if (Vector3D.Angle(fn, fon) > epsilonAngle) { return(false); } } // boundary case if (hf == null || hof == null) { return(false); } // We can only flip an edge if both incident polygons are triangles. if (hf.Circulate().Count != 3 || hof.Circulate().Count != 3) { return(false); } // non boundary vertices with a valency of less than 4(less than 3 after operation) degenerates mesh. Vertex hv = h.vert; var hov = h.opp.vert; if ((hv.Valency < 4 && !hv.IsBoundary()) || (hov.Valency < 4 && !hov.IsBoundary())) { return(false); } // Disallow flip if vertices being connected already are. Vertex hnv = h.next.vert; Vertex honv = h.opp.next.vert; if (hnv.GetSharedEdge(honv) != null) { return(false); } return(true); }
public void insert(Halfedge lb,Halfedge newHalfedge) { newHalfedge.edgeListLeftNeighbor=lb; newHalfedge.edgeListRightNeighbor=lb.edgeListRightNeighbor; lb.edgeListRightNeighbor.edgeListLeftNeighbor=newHalfedge; lb.edgeListRightNeighbor=newHalfedge; }
private void AddToQueue(Dictionary <int, HalfEdgeCounter> counter, SimplePriorityQueue <PQElement> Q, Halfedge h, EnergyFun efun, Dictionary <int, int> flipCounter, int time) { if (h.IsBoundary()) { return; } // only consider one of the halfedges if (h.id < h.opp.id) { h = h.opp; } // if half edge already tested for queue in the current frame then skip HalfEdgeCounter c = null; if (!counter.TryGetValue(h.id, out c)) { c = new HalfEdgeCounter(); counter[h.id] = c; } if (c.touched == time) { return; } c.isRemovedFromQueue = false; if (!PrecondFlipEdge(h)) { return; } double energy = efun.DeltaEnergy(h); c.touched = time; const int avgValence = 6; int count = 0; if (!flipCounter.TryGetValue(h.vert.id, out count)) { flipCounter[h.vert.id] = 0; } if ((energy < 0) && (count < avgValence)) { Q.Enqueue(new PQElement(energy, h, time), (float)energy); } }
//PQElement() {} public PQElement(double _pri, Halfedge _h, int _time) { pri = _pri; h = _h; time = _time; }
public virtual double Energy(Halfedge h) { return(0); }
/// <summary> /// Split edges (and vertices) if /// angle between faces is less than sharpEdgeAngle /// or if face ids are different (when splitByFaceId is true) /// Note that this will not preserve the edge labels nor face labels /// </summary> /// <param name="sharpEdgeAngle"></param> /// <param name="splitByFaceId"></param> // Creates a new HMesh where sharp edges and materials (defined by face labels) results in edge splits public HMesh Split(bool splitByFaceLabel = true, double sharpEdgeAngle = 360) { MarkSharpEdges(sharpEdgeAngle); if (splitByFaceLabel) { MarkSharpEdgesByLabel(); } Halfedge[] oldIdToNewEdge = new Halfedge[halfedgeMaxId + 1]; // main concept: // halfedges with label != 0 should not be glued together // A vertex should be split into multiple vertices and assigned to regions of halfedges. // a pair of the max outgoing he id for a single side and the vertex id Vertex[] splitVertex = new Vertex[halfedgeMaxId + 1]; HMesh newHMesh = new HMesh(); var findOrCreateVertex = new Func <Halfedge, Vertex>(delegate(Halfedge he){ // find maximum ingoing he var h = he; // rewind while (h.opp != null && h.label == 0 && h.opp.prev != he) { h = h.opp.prev; } int maxId = h.id; var first = h; while (h.next.opp != null && h.next.label == 0 && h.next.opp != first) { h = h.next.opp; maxId = Mathf.Max(h.id, maxId); } Vertex res = splitVertex[maxId]; if (res == null) { res = newHMesh.CreateVertex(he.vert.positionD); res.label = he.vert.label; res.uv1 = he.vert.uv1; res.uv2 = he.vert.uv2; splitVertex[maxId] = res; } return(res); }); foreach (var face in GetFacesRaw()) { // copy the face and half edges Face newFace = newHMesh.CreateFace(); newFace.label = face.label; var edges = face.Circulate(); var edgeList = new Halfedge[edges.Count]; var vertexList = new Vertex[edges.Count]; for (int i = 0; i < edges.Count; i++) { var newEdge = newHMesh.CreateHalfedge(); oldIdToNewEdge[edges[i].id] = newEdge; var newVertex = findOrCreateVertex(edges[i]); edgeList[i] = newEdge; vertexList[i] = newVertex; if (i > 0) { edgeList[i - 1].Link(edgeList[i]); } if (i == edges.Count - 1) { edgeList[i].Link(edgeList[0]); } newEdge.Link(newFace); } for (int i = 0; i < edgeList.Length; i++) { edgeList[i].vert = vertexList[i]; } } foreach (var oldHE in GetHalfedgesRaw()) { if (oldHE.opp == null || oldHE.label != 0) { continue; } if (oldHE.opp.id < oldHE.id) { continue; // only glue one way } var newHe = oldIdToNewEdge[oldHE.id]; var newHeOpp = oldIdToNewEdge[oldHE.opp.id]; newHe.Glue(newHeOpp); } return(newHMesh); }
public HMesh Copy() { List <Vertex> fromVert = new List <Vertex>(); List <Face> fromFaces = new List <Face>(); List <Halfedge> fromHalfedge = new List <Halfedge>(); List <Vertex> toVert = new List <Vertex>(); List <Face> toFace = new List <Face>(); List <Halfedge> toHalfedge = new List <Halfedge>(); HMesh newMesh = new HMesh(); int index = 0; foreach (var v in vertices) { v.label = index; fromVert.Add(v); var nv = newMesh.CreateVertex(v.positionD); nv.uv1 = v.uv1; nv.uv2 = v.uv2; toVert.Add(nv); index++; } index = 0; foreach (var f in faces) { f.label = index; fromFaces.Add(f); var nf = newMesh.CreateFace(); nf.label = f.label; toFace.Add(nf); index++; } index = 0; foreach (var e in halfedges) { e.label = index; fromHalfedge.Add(e); toHalfedge.Add(newMesh.CreateHalfedge()); index++; } foreach (var from in faces) { Face to = toFace[from.label]; if (from.halfedge != null) { to.halfedge = toHalfedge[from.halfedge.label]; } } foreach (var from in halfedges) { Halfedge to = toHalfedge[from.label]; if (from.face != null) { to.face = toFace[from.face.label]; } if (from.opp != null) { to.opp = toHalfedge[from.opp.label]; } if (from.next != null) { to.next = toHalfedge[from.next.label]; } if (from.prev != null) { to.prev = toHalfedge[from.prev.label]; } if (from.vert != null) { to.vert = toVert[from.vert.label]; } } return(newMesh); }
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(); }
private Halfedge ELleft( Halfedge he ) { return he.ELleft; }
/* * This delete routine can't reclaim node, since pointers from hash table * may be present. */ private void ELdelete( Halfedge he ) { (he.ELleft).ELright = he.ELright; (he.ELright).ELleft = he.ELleft; he.deleted = true; }
private Halfedge HEcreate(Edge e, int pm) { Halfedge answer = new Halfedge(); answer.ELedge = e; answer.ELpm = pm; answer.PQnext = null; answer.vertex = null; return answer; }
private void ELinsert( Halfedge lb, Halfedge newHe ) { newHe.ELleft = lb; newHe.ELright = lb.ELright; (lb.ELright).ELleft = newHe; lb.ELright = newHe; }
public abstract double DeltaEnergy(Halfedge h);
private Halfedge ELright( Halfedge he ) { return he.ELright; }
static bool PrecondFlipEdge(HMesh mesh, Halfedge he) { return true; }
// create a new site where the HalfEdges el1 and el2 intersect - note that // the Point in the argument list is not used, don't know why it's there private Site intersect( Halfedge el1, Halfedge el2 ) { Edge e1, e2, e; Halfedge el; double d, xint, yint; bool right_of_site; Site v; // vertex e1 = el1.ELedge; e2 = el2.ELedge; if ( e1 == null || e2 == null ) return null; // if the two edges bisect the same parent, return null if ( e1.reg[1] == e2.reg[1] ) return null; d = e1.a * e2.b - e1.b * e2.a; if ( -1.0e-10 < d && d < 1.0e-10 ) return null; xint = ( e1.c * e2.b - e2.c * e1.b ) / d; yint = ( e2.c * e1.a - e1.c * e2.a ) / d; if ( (e1.reg[1].coord.y < e2.reg[1].coord.y) || (e1.reg[1].coord.y == e2.reg[1].coord.y && e1.reg[1].coord.x < e2.reg[1].coord.x) ) { el = el1; e = e1; } else { el = el2; e = e2; } right_of_site = xint >= e.reg[1].coord.x; if ((right_of_site && el.ELpm == LE) || (!right_of_site && el.ELpm == RE)) return null; // create a new site at the point of intersection - this is a new vector // event waiting to happen v = new Site(); v.coord.x = xint; v.coord.y = yint; return v; }
static void FlipEdge(Halfedge e, Stack<Halfedge> flipStack) { e.Flip(); }
private int PQbucket( Halfedge he ) { int bucket; bucket = (int) ((he.ystar - ymin) / deltay * PQhashsize); if ( bucket < 0 ) bucket = 0; if ( bucket >= PQhashsize ) bucket = PQhashsize - 1; if ( bucket < PQmin ) PQmin = bucket; return bucket; }
static bool IsLocalDelaunay(Halfedge e) { if (e.IsBoundary()){ return true; } Vector3 p1 = e.vert.position; Vector3 p2 = e.next.vert.position; Vector3 p3 = e.next.next.vert.position; Vector3 p4 = e.opp.next.vert.position; return HMeshMath.InCircle(p1,p2,p3,p4) || HMeshMath.InCircle(p2,p1,p4,p2); }
private bool PQinitialize() { PQcount = 0; PQmin = 0; PQhashsize = 4 * sqrt_nsites; PQhash = new Halfedge[ PQhashsize ]; for ( int i = 0; i < PQhashsize; i++ ) { PQhash [i] = new Halfedge(); } return true; }
/// <summary> /// /// </summary> /// <typeparam name="V"></typeparam> /// <typeparam name="E"></typeparam> /// <param name="hedge"></param> /// <param name="getPosition"></param> /// <returns></returns> public static Line ToLine <V, E>(this Halfedge <V, E> hedge) where V : HeVertex <V, E>, IPosition3d where E : Halfedge <V, E> { return(ToLine(hedge, IPosition3d <V> .Get)); }
private Site rightreg(Halfedge he) { if (he.ELedge == (Edge) null) // if this halfedge has no edge, return the bottom site (whatever // that is) { return (bottomsite); } // if the ELpm field is zero, return the site 0 that this edge bisects, // otherwise return site number 1 return (he.ELpm == LE ? he.ELedge.reg[RE] : he.ELedge.reg[LE]); }
Site rightRegion(Halfedge he,Site bottomMostSite) { Edge edge = he.edge; if (edge == null) { return bottomMostSite; } return edge.site(LR.other(he.leftRight)); }
private int bucket(Halfedge halfEdge) { int theBucket= (halfEdge.ystar - _ymin)/_deltay * _hashsize; if (theBucket < 0) theBucket = 0; if (theBucket >= _hashsize) theBucket = _hashsize - 1; return theBucket; }
public void reallyDispose() { edgeListLeftNeighbor = null; edgeListRightNeighbor = null; nextInPriorityQueue = null; edge = null; leftRight = null; vertex = null; _pool.RemoveAt(_pool.Count-1); }
/// <summary> /// Construct the geometry from a mesh. /// </summary> public void FromMesh(Mesh mesh) { linkedMesh = mesh; Clear(); // Build vertices Vector3[] meshVerts = mesh.vertices; for (int i = 0; i < meshVerts.Length; i++) { vertices.Add(new Vertex(meshVerts[i])); vertices[i].index = i; vertices[i].edges = new List<Halfedge>(); } // Build faces and halfedges, linked to vertices int[] meshFaces = mesh.triangles; for (int i = 0; i < meshFaces.Length / 3; i++) { Face trig = new Face(); Halfedge e1 = new Halfedge(), e2 = new Halfedge(), e3 = new Halfedge(); e1.face = trig; e1.next = e2; e1.prev = e3; e1.vertex = vertices[meshFaces[3*i]]; e2.face = trig; e2.next = e3; e2.prev = e1; e2.vertex = vertices[meshFaces[3*i+1]]; e3.face = trig; e3.next = e1; e3.prev = e2; e3.vertex = vertices[meshFaces[3*i+2]]; trig.edge = e1; trig.index = i; faces.Add(trig); halfedges.Add(e1); halfedges.Add(e2); halfedges.Add(e3); e1.vertex.edge = e1; e1.vertex.edges.Add(e1); e2.vertex.edge = e2; e2.vertex.edges.Add(e2); e3.vertex.edge = e3; e3.vertex.edges.Add(e3); } // Set the corresponding opposite to each halfedge for (int i = 0; i < vertices.Count; i++) { vertices[i].onBorder = false; for (int j = 0; j < vertices[i].edges.Count; j++) { Halfedge et = vertices[i].edges[j]; if (et.opposite == null) { Vertex vt = et.prev.vertex; bool foundOpposite = false; for (int k = 0; k < vt.edges.Count; k++) { if (vt.edges[k].prev.vertex == vertices[i]) { if (foundOpposite) { //GameObject.Instantiate(GameObject.Find("Pin")).transform.position = vertices[i].p; throw new Exception("Edge shared by 3 faces, not manifold!"); } et.opposite = vt.edges[k]; //vt.edges[k].opposite = et; //break; foundOpposite = true; } } // If no opposite, we are on a boundary if (et.opposite == null) { vertices[i].onBorder = true; et.opposite = new Halfedge(); et.opposite.opposite = et; et.opposite.vertex = et.prev.vertex; halfedges.Add(et.opposite); } } } } //throw new UnityException("WOW"); // Reconnect all newly created halfedges on a boundary for (int i = 0; i < halfedges.Count; i++) { if (halfedges[i].next == null) { // This halfedge is on a boundary, adding a new boundary face. Face boundary = new Face(); boundaries.Add(boundary); boundary.edge = halfedges[i]; boundary.index = -1; // Connect all halfedges of this boundary Halfedge first = halfedges[i], temp = halfedges[i]; do { Halfedge next = temp.opposite; while (next.prev != null) { next = next.prev.opposite; } temp.next = next; next.prev = temp; temp.face = boundary; temp.vertex.edges.Add(temp); temp = next; } while (temp != first); } } //throw new UnityException("WOW"); for (int i = 0; i < vertices.Count; i++) { vertices[i].ClearEdgeArray(); } // Calculate the max edge length h = 0; foreach (Halfedge e in halfedges) { if (e.Length() > h) { h = e.Length(); } //h += e.Length(); } //h /= halfedges.Count; Debug.Log("Geometry created, Eular number = " + (vertices.Count - halfedges.Count / 2 + faces.Count)); }
public void BuildFromObj(string objFileContent, bool splitNonManifoldVertices = true) { StringReader stringReader = new StringReader(objFileContent); string line; List <Vertex> vertices = new List <Vertex>(); Dictionary <IntPair, Halfedge> heLookup = new Dictionary <IntPair, Halfedge> (); int label = -1; while ((line = stringReader.ReadLine()) != null) { var tokens = line.Trim().Split(' '); if (tokens.Length == 0) { continue; } if (tokens[0] == "o") { label++; } if (tokens[0] == "v") { var v = CreateVertex(new Vector3D(double.Parse(tokens[1]), double.Parse(tokens[2]), double.Parse(tokens[3]))); vertices.Add(v); } if (tokens[0] == "f") { List <int> vertexIndices = new List <int>(); for (var i = 1; i < tokens.Length; i++) { var vertexIdx = int.Parse(tokens[i].Split('/')[0]) - 1; vertexIndices.Add(vertexIdx); } var face = CreateFace(); face.label = Mathf.Max(0, label); for (var i = 0; i < vertexIndices.Count; i++) { var halfEdge = CreateHalfedge(); halfEdge.Link(face); heLookup[new IntPair(vertexIndices[i], vertexIndices[(i + 1) % vertexIndices.Count])] = halfEdge; Halfedge opp = null; if (heLookup.TryGetValue( new IntPair(vertexIndices[(i + 1) % vertexIndices.Count], vertexIndices[i]), out opp)) { // if (invalid) 2-gon face, then don't glue // this would connect opp to itself if (vertexIndices.Count > 2) { halfEdge.Glue(opp); } } halfEdge.vert = vertices[vertexIndices[(i + 1) % vertexIndices.Count]]; } for (var i = 0; i < vertexIndices.Count; i++) { var thisHe = heLookup[new IntPair(vertexIndices[i], vertexIndices[(i + 1) % vertexIndices.Count])]; var nextHe = heLookup[ new IntPair(vertexIndices[(i + 1) % vertexIndices.Count], vertexIndices[(i + 2) % vertexIndices.Count])]; thisHe.Link(nextHe); } } } if (splitNonManifoldVertices) { SplitNonManifoldVertices(); } }