/** * splits the facet incident to h and g into two facets with a new diagonal between the two * vertices denoted by h and g respectively. The second (new) facet is a copy of the first facet. * Returns h->next() after the operation, i.e., the new diagonal. The new face is to the right of * the new diagonal, the old face is to the left. The time is proportional to the distance from h * to g around the facet. */ public Halfedge splitFacet(Halfedge h, Halfedge g) { if (h == null || g == null) throw new Error("splitFacet: null pointer"); if (h.face != g.face) throw new Error("splitFacet: different incident facets"); if (h == g || h.next == g || g.next == h) { throw new Error("loops and multiple edges are not allowed"); } Halfedge<X> newDiagonal = new Halfedge<X>(); Halfedge<X> oppositeNewDiagonal = new Halfedge<X>(); Face<X> newFace = new Face<X>(); newFace.halfedge = g; newDiagonal.opposite = oppositeNewDiagonal; oppositeNewDiagonal.opposite = newDiagonal; newDiagonal.face = h.face; oppositeNewDiagonal.face = newFace; // a completer Halfedge p = h.next; while (p != g) { p.face = newFace; p = p.next; } h.next = newDiagonal; g.next = oppositeNewDiagonal; return newDiagonal; }
public int vertexDegree(Vertex v) { int result = 0; Halfedge e = v.getHalfedge(); Halfedge pEdge = e.getNext().getOpposite(); while (pEdge != e) { pEdge = pEdge.getNext().getOpposite(); result++; } return result + 1; }
public Halfedge<X> makeHole(Halfedge h) { if (h == null || h.face == null) throw new Error("error making hole: h or h.face null"); this.facets.remove(h.getFace()); Halfedge p = h.next; h.face = null; int cont = 1; while (p != h) { p.face = null; p = p.next; } return h; }
public void createCenterVertex(Face<X> f) { int degree = f.degree(); Point_[] neighbors = new Point_[degree]; Halfedge<X> e = f.getEdge(); neighbors[0] = e.getVertex().getPoint(); for (int i = 1; i < degree; i++) { e = e.getNext(); neighbors[i] = e.getVertex().getPoint(); } Point_ centerVertex; if (neighbors[0].dimension() == 2) centerVertex = new Point_2(); else if (neighbors[0].dimension() == 3) centerVertex = new Point_3(); else throw new Error("error point dimension"); }
public Halfedge<X> fillHole(Halfedge h) { if (h.face != null) throw new Error("error filling hole: h not boundary edge"); Face<X> newFace = new Face<X>(); this.facets.add(newFace); newFace.setEdge(h); Halfedge p = h.next; h.face = newFace; int cont = 1; while (p != h) { p.face = newFace; p = p.next; } return h; }
public String facesToString() { String result = "List of faces\n"; Iterator it = this.facets.iterator(); int cont = 0; while (it.hasNext()) { Face<X> f = (Face<X>) it.next(); result = result + "f" + cont + " "; Halfedge<X> e = f.getEdge(); while (e.getNext() != f.getEdge()) { result = result + vertices.indexOf(e.getVertex()) + " "; e = e.getNext(); } result = result + vertices.indexOf(e.getVertex()) + "\n"; cont++; } return result; }
/** * a triangle with border edges is added to the polyhedral surface. Returns a non-border halfedge * of the triangle. */ public Halfedge<X> makeTriangle(X p1, X p2, X p3) { Face<X> newFace = new Face<X>(); Vertex<X> newVertex1 = new Vertex<X>(p1); Vertex<X> newVertex2 = new Vertex<X>(p2); Vertex<X> newVertex3 = new Vertex<X>(p3); Halfedge<X> e1 = new Halfedge<X>(); Halfedge<X> e2 = new Halfedge<X>(); Halfedge<X> e3 = new Halfedge<X>(); Halfedge<X> e1Opp = new Halfedge<X>(); Halfedge<X> e2Opp = new Halfedge<X>(); Halfedge<X> e3Opp = new Halfedge<X>(); // setting the new face newFace.setEdge(e1); // setting the new vertices (LCA: a' controler) newVertex1.setEdge(e2); newVertex2.setEdge(e3); newVertex3.setEdge(e1); // setting e1 e1.setFace(newFace); e1.setVertex(newVertex1); e1.setPrev(e3); e1.setNext(e2); e1.setOpposite(e1Opp); // setting e2 e2.setFace(newFace); e2.setVertex(newVertex2); e2.setPrev(e1); e2.setNext(e3); e2.setOpposite(e2Opp); // setting e3 e3.setFace(newFace); e3.setVertex(newVertex3); e3.setPrev(e2); e3.setNext(e1); e3.setOpposite(e3Opp); // setting e1Opp (boundary halfedge opposite to e1) e1Opp.setFace(null); e1Opp.setVertex(newVertex3); e1Opp.setPrev(e2Opp); e1Opp.setNext(e3Opp); e1Opp.setOpposite(e1); // setting e2Opp (boundary halfedge opposite to e2) e2Opp.setFace(null); e2Opp.setVertex(newVertex1); e2Opp.setPrev(e3Opp); e2Opp.setNext(e1Opp); e2Opp.setOpposite(e2); // setting e3Opp (boundary halfedge opposite to e3) e3Opp.setFace(null); e3Opp.setVertex(newVertex2); e3Opp.setPrev(e1Opp); e3Opp.setNext(e2Opp); e3Opp.setOpposite(e3); this.facets.add(newFace); this.vertices.add(newVertex1); this.vertices.add(newVertex2); this.vertices.add(newVertex3); this.halfedges.add(e1); this.halfedges.add(e1Opp); this.halfedges.add(e2); this.halfedges.add(e2Opp); this.halfedges.add(e3); this.halfedges.add(e3Opp); return e1; }
/** * creates a new triangle facet within the hole incident to h by connecting the tip of h with two * new halfedges and a new vertex. Returns the halfedge of the new edge that is incident to the * new facet and the new vertex. */ public Halfedge<X> addTriangleToBorder(Halfedge h, X point) { if (h.face != null) throw new Error("no border edge"); System.out.println("adding triangle to " + h); Face<X> newFace = new Face<X>(); Vertex<X> newVertex = new Vertex<X>(point); Halfedge<X> hPrev = new Halfedge<X>(); Halfedge<X> hNext = new Halfedge<X>(); Halfedge<X> hPrevOpp = new Halfedge<X>(); Halfedge<X> hNextOpp = new Halfedge<X>(); // setting the new face newFace.setEdge(h); // setting hPrev (halfedge preceding h in the new face) hPrev.setFace(newFace); hPrev.setVertex(h.getOpposite().getVertex()); hPrev.setPrev(hNext); hPrev.setNext(h); hPrev.setOpposite(hPrevOpp); // setting hNext (halfedge following h in the new face) hNext.setFace(newFace); hNext.setVertex(newVertex); hNext.setPrev(h); hNext.setNext(hPrev); hNext.setOpposite(hNextOpp); // setting hPrevOpp (new boundary halfedge) hPrevOpp.setFace(null); hPrevOpp.setVertex(newVertex); hPrevOpp.setPrev(h.getPrev()); hPrevOpp.setNext(hNextOpp); hPrevOpp.setOpposite(hPrev); // setting hNextOpp (the other new boundary halfedge) hNextOpp.setFace(null); hNextOpp.setVertex(h.getVertex()); hNextOpp.setPrev(hPrevOpp); hNextOpp.setNext(h.getNext()); hNextOpp.setOpposite(hNext); // updating old boundary halfedge informations h.setFace(newFace); h.setPrev(hPrev); h.setNext(hNext); // setting newVertex newVertex.setEdge(hPrev); // LCA: a controler si c'est hPrev ou hNext // adding new facet, vertex and the four halfedges this.vertices.add(newVertex); this.facets.add(newFace); this.halfedges.add(hPrev); this.halfedges.add(hNext); this.halfedges.add(hPrevOpp); this.halfedges.add(hNextOpp); return hNext; }
/** * returns true if the polyhedral surface is combinatorially consistent. If borders==true * normalization of the border edges is checked too. This method checks that each facet is at * least a triangle and that the two incident facets of a non-border edge are distinct. */ public boolean isValid(boolean borders) { boolean valid = true; System.out.print("Checking Polyhedron..."); int n = this.vertices.size(); int e = this.halfedges.size(); int f = this.facets.size(); for (int i = 0; i < this.halfedges.size(); i++) { Halfedge<X> pedge = this.halfedges.get(i); if (pedge.getOpposite() == null) { System.out.print("error opposite: " + i); valid = false; // Face face=pedge.getFace(); // int[] ind=face.getVertexIndices(this); // System.out.println(" "+ind[0]+" "+ind[1]+" "+ind[2]); } if (pedge.getNext() == null) { System.out.println("error next_edge: " + i); valid = false; } if (pedge.getPrev() == null) { System.out.println("error prev_edge: " + i); valid = false; } if (pedge.getVertex() == null) { System.out.println("error vertex: " + i); valid = false; } if (pedge.opposite != null && pedge.face == pedge.getOpposite().face) { System.out.println("error edge: " + i); valid = false; } } for (int i = 0; i < this.facets.size(); i++) { Face<X> pface = this.facets.get(i); if (pface == null) { System.out.println("error face pointer"); valid = false; } if (pface.halfedge == null) { System.out.println("error face.halfedge"); valid = false; } if (pface.degree() < 3) { System.out.println("error face degree"); return valid = false; } } for (int i = 0; i < this.vertices.size(); i++) { Vertex<X> pvertex = this.vertices.get(i); // System.out.println(""+pvertex.toString()); if (pvertex == null) { System.out.println("error vertex pointer:" + i); valid = false; } if (pvertex.halfedge == null) { System.out.println("error vertex.halfedge: " + i); valid = false; } if (pvertex.getPoint() == null) { System.out.println("error vertex.point: " + i); valid = false; } } if (valid == true) System.out.println("ok"); else System.out.println("not valid"); System.out.print("n: " + n + " e: " + e / 2 + " f: " + f + " - "); int g = -(n - e / 2 + f - 2) / 2; System.out.println("genus: " + g); return valid; }
private void fortunesAlgorithm() { Site newSite, bottomSite, topSite, tempSite; Vertex v, vertex; Point newintstar = null; LR leftRight; Halfedge lbnd, rbnd, llbnd, rrbnd, bisector; Edge edge; Rectangle dataBounds = _sites.getSitesBounds(); int sqrt_nsites = (int) Math.sqrt(_sites.get_length() + 4); HalfedgePriorityQueue heap = new HalfedgePriorityQueue(dataBounds.y, dataBounds.height, sqrt_nsites); EdgeList edgeList = new EdgeList(dataBounds.x, dataBounds.width, sqrt_nsites); ArrayList<Halfedge> halfEdges = new ArrayList(); ArrayList<Vertex> vertices = new ArrayList(); Site bottomMostSite = _sites.next(); newSite = _sites.next(); for (; ; ) { if (heap.empty() == false) { newintstar = heap.min(); } if (newSite != null && (heap.empty() || compareByYThenX(newSite, newintstar) < 0)) { /* new site is smallest */ // trace("smallest: new site " + newSite); // Step 8: lbnd = edgeList.edgeListLeftNeighbor( newSite.get_coord()); // the Halfedge just to the left of newSite // trace("lbnd: " + lbnd); rbnd = lbnd.edgeListRightNeighbor; // the Halfedge just to the right // trace("rbnd: " + rbnd); bottomSite = rightRegion(lbnd, bottomMostSite); // this is the same as leftRegion(rbnd) // this Site determines the region containing the new site // trace("new Site is in region of existing site: " + bottomSite); // Step 9: edge = Edge.createBisectingEdge(bottomSite, newSite); // trace("new edge: " + edge); _edges.add(edge); bisector = Halfedge.create(edge, LR.LEFT); halfEdges.add(bisector); // inserting two Halfedges into edgeList constitutes Step 10: // insert bisector to the right of lbnd: edgeList.insert(lbnd, bisector); // first half of Step 11: if ((vertex = Vertex.intersect(lbnd, bisector)) != null) { vertices.add(vertex); heap.remove(lbnd); lbnd.vertex = vertex; lbnd.ystar = vertex.get_y() + newSite.dist(vertex); heap.insert(lbnd); } lbnd = bisector; bisector = Halfedge.create(edge, LR.RIGHT); halfEdges.add(bisector); // second Halfedge for Step 10: // insert bisector to the right of lbnd: edgeList.insert(lbnd, bisector); // second half of Step 11: if ((vertex = Vertex.intersect(bisector, rbnd)) != null) { vertices.add(vertex); bisector.vertex = vertex; bisector.ystar = vertex.get_y() + newSite.dist(vertex); heap.insert(bisector); } newSite = _sites.next(); } else if (heap.empty() == false) { /* intersection is smallest */ lbnd = heap.extractMin(); llbnd = lbnd.edgeListLeftNeighbor; rbnd = lbnd.edgeListRightNeighbor; rrbnd = rbnd.edgeListRightNeighbor; bottomSite = leftRegion(lbnd, bottomMostSite); topSite = rightRegion(rbnd, bottomMostSite); // these three sites define a Delaunay triangle // (not actually using these for anything...) // _triangles.push(new Triangle(bottomSite, topSite, rightRegion(lbnd))); v = lbnd.vertex; v.setIndex(); lbnd.edge.setVertex(lbnd.leftRight, v); rbnd.edge.setVertex(rbnd.leftRight, v); edgeList.remove(lbnd); heap.remove(rbnd); edgeList.remove(rbnd); leftRight = LR.LEFT; if (bottomSite.get_y() > topSite.get_y()) { tempSite = bottomSite; bottomSite = topSite; topSite = tempSite; leftRight = LR.RIGHT; } edge = Edge.createBisectingEdge(bottomSite, topSite); _edges.add(edge); bisector = Halfedge.create(edge, leftRight); halfEdges.add(bisector); edgeList.insert(llbnd, bisector); edge.setVertex(LR.other(leftRight), v); if ((vertex = Vertex.intersect(llbnd, bisector)) != null) { vertices.add(vertex); heap.remove(llbnd); llbnd.vertex = vertex; llbnd.ystar = vertex.get_y() + bottomSite.dist(vertex); heap.insert(llbnd); } if ((vertex = Vertex.intersect(bisector, rrbnd)) != null) { vertices.add(vertex); bisector.vertex = vertex; bisector.ystar = vertex.get_y() + bottomSite.dist(vertex); heap.insert(bisector); } } else { break; } } // heap should be empty now heap.dispose(); edgeList.dispose(); for (Halfedge halfEdge : halfEdges) { halfEdge.reallyDispose(); } halfEdges.clear(); // we need the vertices to clip the edges for (Edge e : _edges) { e.clipVertices(_plotBounds); } // but we don't actually ever use them again! for (Vertex v0 : vertices) { v0.dispose(); } vertices.clear(); }