Commit 550befe2 by Benedikt Zoennchen

### simplify the splitEdge and splitTriangle operation and add a face iterator to...

`simplify the splitEdge and splitTriangle operation and add a face iterator to the delaunay-triangulation`
parent 385c9537
 ... ... @@ -89,7 +89,7 @@ public class Geometry { * * @param polygon * @param createMidpoints * if true, every line is split into two by inserting a midpoint. * if true, every line is splitEdge into two by inserting a midpoint. * @return */ public boolean intersects(VPolygon polygon, boolean createMidpoints, ... ...
 ... ... @@ -64,6 +64,8 @@ public class Face

implements Iterable> { private boolean border; private boolean destroyed = false; /** * Default constructor. To construct a face where you have already some half-edges * bordering this face. ... ... @@ -95,12 +97,17 @@ public class Face

implements Iterable> { return border; } public void destroy() { setEdge(null); destroyed = true; } /** * Sets one of the half-edges bordering this face. * * @param edge half-edge bordering this face */ public void setEdge(@NotNull HalfEdge

edge) { public void setEdge(final HalfEdge

edge) { this.edge = edge; } ... ... @@ -108,6 +115,10 @@ public class Face

implements Iterable> { return edge; } public boolean isDestroyed() { return destroyed; } /** * Computes the area of this face. * ... ...

 ... ... @@ -76,106 +76,14 @@ public class HalfEdge

implements Iterable> { return twin; } /** * Deletes the vertex i.e. end point of this halfedge from the geometry by deleting all halfedges * connected to this vertex. */ public void deleteVertex() { // 1. gather all edges List> edges = IteratorUtils.toList(this.iterator()); // 2. delete all edges of connected to the end point edges.stream().filter(HalfEdge::isValid).forEach(edge -> edge.deleteEdge()); } /** * Deletes this edge (and its twin) from the geometry. This operation requires O(n) where * n is the number of edges inside a face. It may delete an vertex if it has degree = 2. * Furthermore, faces may be merged. If a face will become invalid it will be the face of this * edge. * * @return true if the operation deletes a vertex i.e. an end point is no longer part of the geometry, false otherwise. */ public boolean deleteEdge() { boolean deleteVertex = false; // the edge is inside another face. if(!getFace().isBorder() && !getTwin().getFace().isBorder()) { // 1. remove one of the 2 faces. We deleteEdge the face of this edge, the twin face survives. for(HalfEdge

halfEdge : this.face) { halfEdge.setFace(getTwin().getFace()); } // 2. Delete the edge and its twin be rearranging pointers HalfEdge

xy = this; HalfEdge

yx = getTwin(); HalfEdge

yz = xy.getNext(); HalfEdge

wy = yx.getPrevious(); wy.setNext(yz); HalfEdge

ux = xy.getPrevious(); HalfEdge

xt = yx.getNext(); ux.setNext(xt); // 3. update the edge of the survived face since it might be the twin. getTwin().getFace().setEdge(ux); } // the edge is on the border, therefore we remove the whole non-border face if this face does only consist of <= 3 edges before the deletion. else { Face

borderFace = getFace().isBorder() ? getFace() : getTwin().getFace(); Face

nonBorderFace = getFace().isBorder() ? getTwin().getFace() : getFace(); HalfEdge

borderHe = getFace().isBorder() ? this : getTwin(); HalfEdge

nonBorderHe = getFace().isBorder() ? getTwin() : this; // nonBorder-Face is not a triangle if(!nonBorderHe.getNext().getTwin().getFace().isBorder() && !nonBorderHe.getPrevious().getTwin().getFace().isBorder()) { for(HalfEdge

halfEdge : nonBorderFace) { halfEdge.setFace(borderFace); } // since the face may has this edge as pointer which will be invalid borderFace.setEdge(borderHe.getNext()); //nonBorderFace.setEdge(nonBorderHe.getNext()); nonBorderHe.getPrevious().setNext(borderHe.getNext()); nonBorderHe.getNext().setPrevious(borderHe.getPrevious()); } // special case1: there is no possibility to delete this edge without deleting the vertex, since the vertex has degree 2. else if(!borderHe.equals(borderHe.getNext().getNext().getNext())) { borderFace.setEdge(borderHe.getNext()); nonBorderFace.setEdge(nonBorderHe.getNext()); borderHe.getPrevious().setNext(borderHe.getNext()); nonBorderHe.getPrevious().setNext(nonBorderHe.getNext()); deleteVertex = true; } // special case2: inner face and outer face is a triangle => there is only 1 inner face. // if we delete the edge there is no face in the geometry. Therefore we delete the whole triangle. else { HalfEdge

y = getNext(); HalfEdge

z = y.getNext(); // delete pointers for the GC y.getTwin().destroy(); y.destroy(); z.getTwin().destroy(); z.destroy(); deleteVertex = true; } } // delete pointers for the GC getTwin().destroy(); destroy(); return deleteVertex; public boolean isBoundary() { return face.isBorder(); } /** * removes the cyclic pointer structure such that the GC can delete these objects. * removes the cyclic pointer structure such that the GC can deleteBoundaryFace these objects. */ private void destroy() { public void destroy() { setNext(null); setPrevious(null); setTwin(null); ... ... @@ -207,6 +115,10 @@ public class HalfEdge

implements Iterable> { } } public void setEnd(P end) { this.end = end; } public VLine toLine() { return new VLine((VPoint) this.getPrevious().getEnd(), (VPoint) this.getEnd()); } ... ...

 ... ... @@ -5,12 +5,12 @@ import org.vadere.util.geometry.shapes.IPoint; import java.util.Set; import java.util.stream.Stream; public interface Triangulation

{ public interface Triangulation

extends Iterable> { void compute(); Face

locate(final double x, final double y); Face

locate(final IPoint point); Stream> streamFaces(); Set> getFaces(); HalfEdge

insert(final P point); void insert(final P point); void remove(final P point); }

This diff is collapsed.
 ... ... @@ -32,8 +32,8 @@ public class UniformTriangulation

extends DelaunayTriangulatio this.minTriangleSideLength = minTriangleSideLength; this.pointConstructor = pointConstructor; List

pointList = new ArrayList

(generatePointSet()); Collections.shuffle(pointList); List

pointList = new ArrayList<>(generatePointSet()); //Collections.shuffle(pointList); for(P point : pointList) { insert(point); } ... ...

 ... ... @@ -114,78 +114,4 @@ public class TestFace { assertEquals(expectedNeighbours, neighbours); } @Test public void testDeleteEdge() { // remove the edge between the two triangles (face1 and face2) which should result in a single rectangle. HashSet pointSet = new HashSet<>(); pointSet.add(x); pointSet.add(y); pointSet.add(z); pointSet.add(w); Face twinFace = xy.getTwin().getFace(); boolean vertexDeletion = xy.deleteEdge(); // we get a rectangle assertEquals(vertexDeletion, false); assertEquals(pointSet, new HashSet<>(twinFace.getPoints())); pointSet.remove(twinFace.getEdge().getEnd()); vertexDeletion = twinFace.getEdge().deleteEdge(); assertEquals(vertexDeletion, true); assertEquals(pointSet, new HashSet<>(twinFace.getPoints())); vertexDeletion = twinFace.getEdge().deleteEdge(); assertEquals(vertexDeletion, true); } @Test public void testDeleteVertex() { // remove the edge between the two triangles (face1 and face2) which should result in a single rectangle. HashSet pointSet = new HashSet<>(); Face face3 = new Face(); VPoint u = new VPoint(9,9); HalfEdge uz = new HalfEdge<>(z, face3); HalfEdge zu = new HalfEdge<>(u, border); zu.setTwin(uz); HalfEdge yu = new HalfEdge<>(u, face3); HalfEdge uy = new HalfEdge<>(y, border); uy.setTwin(yu); HalfEdge zy = new HalfEdge<>(y, face3); yz.setTwin(zy); zy.setNext(yu); yu.setNext(uz); uz.setNext(zy); face3.setEdge(zy); zu.setNext(uy); uy.setNext(yw); xz.setNext(zu); pointSet.add(y); pointSet.add(z); pointSet.add(w); assertEquals(pointSet, wx.getIncidentPoints().stream().map(he -> he.getEnd()).collect(Collectors.toSet())); pointSet.add(u); pointSet.add(x); pointSet.remove(y); assertEquals(pointSet, zy.getIncidentPoints().stream().map(he -> he.getEnd()).collect(Collectors.toSet())); yu.deleteVertex(); pointSet.remove(u); assertEquals(pointSet, zy.getIncidentPoints().stream().map(he -> he.getEnd()).collect(Collectors.toSet())); } }