Commit 550befe2 authored by Benedikt Zoennchen's avatar Benedikt Zoennchen
Browse files

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<P extends IPoint> implements Iterable<HalfEdge<P>> {
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<P extends IPoint> implements Iterable<HalfEdge<P>> {
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<P> edge) {
public void setEdge(final HalfEdge<P> edge) {
this.edge = edge;
}
......@@ -108,6 +115,10 @@ public class Face<P extends IPoint> implements Iterable<HalfEdge<P>> {
return edge;
}
public boolean isDestroyed() {
return destroyed;
}
/**
* Computes the area of this face.
*
......
......@@ -76,106 +76,14 @@ public class HalfEdge<P extends IPoint> implements Iterable<HalfEdge<P>> {
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<HalfEdge<P>> 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<P> halfEdge : this.face) {
halfEdge.setFace(getTwin().getFace());
}
// 2. Delete the edge and its twin be rearranging pointers
HalfEdge<P> xy = this;
HalfEdge<P> yx = getTwin();
HalfEdge<P> yz = xy.getNext();
HalfEdge<P> wy = yx.getPrevious();
wy.setNext(yz);
HalfEdge<P> ux = xy.getPrevious();
HalfEdge<P> 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<P> borderFace = getFace().isBorder() ? getFace() : getTwin().getFace();
Face<P> nonBorderFace = getFace().isBorder() ? getTwin().getFace() : getFace();
HalfEdge<P> borderHe = getFace().isBorder() ? this : getTwin();
HalfEdge<P> nonBorderHe = getFace().isBorder() ? getTwin() : this;
// nonBorder-Face is not a triangle
if(!nonBorderHe.getNext().getTwin().getFace().isBorder() && !nonBorderHe.getPrevious().getTwin().getFace().isBorder()) {
for(HalfEdge<P> 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<P> y = getNext();
HalfEdge<P> 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<P extends IPoint> implements Iterable<HalfEdge<P>> {
}
}
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<P extends IPoint> {
public interface Triangulation<P extends IPoint> extends Iterable<Face<P>> {
void compute();
Face<P> locate(final double x, final double y);
Face<P> locate(final IPoint point);
Stream<Face<P>> streamFaces();
Set<Face<P>> getFaces();
HalfEdge<P> insert(final P point);
void insert(final P point);
void remove(final P point);
}
......@@ -32,8 +32,8 @@ public class UniformTriangulation<P extends IPoint> extends DelaunayTriangulatio
this.minTriangleSideLength = minTriangleSideLength;
this.pointConstructor = pointConstructor;
List<P> pointList = new ArrayList<P>(generatePointSet());
Collections.shuffle(pointList);
List<P> 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<VPoint> 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<VPoint> pointSet = new HashSet<>();
Face face3 = new Face();
VPoint u = new VPoint(9,9);
HalfEdge<VPoint> uz = new HalfEdge<>(z, face3);
HalfEdge<VPoint> zu = new HalfEdge<>(u, border);
zu.setTwin(uz);
HalfEdge<VPoint> yu = new HalfEdge<>(u, face3);
HalfEdge<VPoint> uy = new HalfEdge<>(y, border);
uy.setTwin(yu);
HalfEdge<VPoint> 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()));
}
}
......@@ -14,6 +14,7 @@ import java.util.Collection;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import java.util.stream.Collectors;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
......@@ -39,11 +40,45 @@ public class TestBoyerWatson {
points.add(p3);
points.add(p4);
points.add(p6);
points.add(p5);
DelaunayTriangulation<VPoint> boyerWatsonImproved = new DelaunayTriangulation<>(points, (x, y) -> new VPoint(x, y));
boyerWatsonImproved.compute();
Collection<VTriangle> triangulation = boyerWatsonImproved.getTriangles();
triangulation.forEach(System.out::print);
boyerWatsonImproved.finalize();
Set<VTriangle> triangulation = new HashSet<>(boyerWatsonImproved.getTriangles());
Set<VPoint> triangle1 = new HashSet<>();
triangle1.add(p1);
triangle1.add(p5);
triangle1.add(p4);
Set<VPoint> triangle2 = new HashSet<>();
triangle2.add(p1);
triangle2.add(p2);
triangle2.add(p5);
Set<VPoint> triangle3 = new HashSet<>();
triangle3.add(p2);
triangle3.add(p3);
triangle3.add(p5);
Set<VPoint> triangle4 = new HashSet<>();
triangle4.add(p4);
triangle4.add(p5);
triangle4.add(p3);
Set<Set<VPoint>> pointSets = triangulation.stream().map(t -> new HashSet<>(t.getPoints())).collect(Collectors.toSet());
Set<Set<VPoint>> expextedPointSets = new HashSet<>();
expextedPointSets.add(triangle1);
expextedPointSets.add(triangle2);
expextedPointSets.add(triangle3);
expextedPointSets.add(triangle4);
assertTrue(expextedPointSets.equals(pointSets));
triangulation.forEach(System.out::println);
}
@Test
......@@ -61,12 +96,13 @@ public class TestBoyerWatson {
Face<VPoint> face = Face.of(p1,p2,p3);
DAG<DAGElement<VPoint>> dag = new DAG<>(new DAGElement<>(face, Triple.of(p1,p2,p3)));
DelaunayTriangulation<VPoint> boyerWatsonImproved = new DelaunayTriangulation<>(points, (x, y) -> new VPoint(x, y));
HalfEdge<VPoint> result = boyerWatsonImproved.split(centerPoint, dag);
DelaunayTriangulation<VPoint> triangulation = new DelaunayTriangulation<>(points, (x, y) -> new VPoint(x, y));
triangulation.splitTriangleDB(centerPoint, dag);
triangulation.finalize();
Set<VTriangle> triangulation = new HashSet<>(result.collectLeafs().stream().map(dagElement -> dagElement.getTriangle()).collect(Collectors.toList()));
Set<VTriangle> triangles = new HashSet<>(triangulation.getTriangles());
Set<VTriangle> expectedResult = new HashSet<>(Arrays.asList(new VTriangle(p1, p2, centerPoint), new VTriangle(p2, p3, centerPoint), new VTriangle(p1, p3, centerPoint)));
assertTrue(testTriangulationEquality(triangulation, expectedResult));
assertTrue(testTriangulationEquality(triangles, expectedResult));
}
@Test
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment