Commit b7e4a4a2 authored by Benedikt Zoennchen's avatar Benedikt Zoennchen

starting to try to improve the distmesh algorithm

parent e8f8fbbf
......@@ -229,17 +229,24 @@ public class IncrementalTriangulation<P extends IPoint, V extends IVertex<P>, E
if(!finalized) {
// we have to use other halfedges than he1 and he2 since they might be deleted
// if we deleteBoundaryFace he0!
List<F> faces1 = mesh.getFaces(p0);
faces1.removeIf(f -> mesh.isBoundary(f));
faces1.forEach(f -> removeFace(f, true));
List<F> faces2 = mesh.getFaces(p1);
faces2.removeIf(f -> mesh.isDestroyed(f) || mesh.isBoundary(f));
faces2.forEach(f -> removeFace(f, true));
if(!mesh.isDestroyed(p0)) {
List<F> faces1 = mesh.getFaces(p0);
faces1.removeIf(f -> mesh.isBoundary(f));
faces1.forEach(f -> removeFace(f, true));
}
List<F> faces3 = mesh.getFaces(p2);
faces3.removeIf(f -> mesh.isDestroyed(f) || mesh.isBoundary(f));
faces3.forEach(f -> removeFace(f, true));
if(!mesh.isDestroyed(p1)) {
List<F> faces2 = mesh.getFaces(p1);
faces2.removeIf(f -> mesh.isDestroyed(f) || mesh.isBoundary(f));
faces2.forEach(f -> removeFace(f, true));
}
if(!mesh.isDestroyed(p2)) {
List<F> faces3 = mesh.getFaces(p2);
faces3.removeIf(f -> mesh.isDestroyed(f) || mesh.isBoundary(f));
faces3.forEach(f -> removeFace(f, true));
}
finalized = true;
}
......
......@@ -143,7 +143,7 @@ public class PHalfEdge<P extends IPoint> implements IHalfEdge<P> {
* one half-edge part of face and ending at end.
*/
@Override
/*@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
......@@ -159,5 +159,5 @@ public class PHalfEdge<P extends IPoint> implements IHalfEdge<P> {
int result = end.hashCode();
result = 31 * result + (face != null ? face.hashCode() : 0);
return result;
}
}*/
}
......@@ -135,11 +135,23 @@ public class PMesh<P extends IPoint> implements IMesh<P, PVertex<P>, PHalfEdge<P
@Override
public void setEdge(@NotNull PVertex<P> vertex, @NotNull PHalfEdge<P> edge) {
assert edge.getEnd().equals(vertex);
if(!edge.getEnd().equals(vertex)) {
System.out.println("end of the edge is not equals to the vertex.");
}
vertex.setEdge(edge);
}
@Override
public void setVertex(@NotNull PHalfEdge<P> halfEdge, @NotNull PVertex<P> vertex) {
/*if(halfEdge.getEnd().getEdge() == halfEdge) {
System.out.println("error44");
}
if(!vertex.getEdge().getEnd().equals(vertex)) {
System.out.println("error2");
}*/
halfEdge.setEnd(vertex);
}
......@@ -266,6 +278,9 @@ public class PMesh<P extends IPoint> implements IMesh<P, PVertex<P>, PHalfEdge<P
return edges.stream();
}
@Override
public Stream<PVertex<P>> streamVertices() { return vertices.stream(); };
@Override
public Iterable<PHalfEdge<P>> getEdgeIt() {
return () -> edges.iterator();
......@@ -273,6 +288,6 @@ public class PMesh<P extends IPoint> implements IMesh<P, PVertex<P>, PHalfEdge<P
@Override
public List<PFace<P>> getFaces() {
return streamFaces().filter(face -> !face.isDestroyed()).collect(Collectors.toList());
return streamFaces().filter(face -> !face.isBorder()).filter(face -> !face.isDestroyed()).collect(Collectors.toList());
}
}
......@@ -13,12 +13,14 @@ import org.vadere.util.geometry.shapes.VPoint;
import org.vadere.util.geometry.shapes.VRectangle;
import org.vadere.util.geometry.shapes.VShape;
import org.vadere.util.geometry.shapes.VTriangle;
import org.vadere.util.triangulation.adaptive.IDistanceFunction;
import org.vadere.util.triangulation.adaptive.IEdgeLengthFunction;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
......@@ -37,12 +39,15 @@ public class UniformRefinementTriangulation<P extends IPoint, V extends IVertex<
private Set<P> points;
private IMesh<P, V, E, F> mesh;
private static final Logger logger = LogManager.getLogger(UniformRefinementTriangulation.class);
private final IDistanceFunction distFunc;
public UniformRefinementTriangulation(
final ITriangulation<P, V, E, F> triangulation,
final VRectangle bound,
final Collection<VShape> boundary,
final IEdgeLengthFunction lenFunc) {
final IEdgeLengthFunction lenFunc,
final IDistanceFunction distFunc) {
this.distFunc = distFunc;
this.triangulation = triangulation;
this.mesh = triangulation.getMesh();
this.boundary = boundary;
......@@ -79,10 +84,31 @@ public class UniformRefinementTriangulation<P extends IPoint, V extends IVertex<
}
private void removeTrianglesOutsideBBox() {
//TODO:
boolean removedSome = true;
while (removedSome) {
removedSome = false;
List<F> candidates = mesh.getFaces(mesh.getBoundary());
for(F face : candidates) {
if(!mesh.isDestroyed(face) && mesh.streamVertices(face).anyMatch(v -> !bbox.contains(v))) {
triangulation.removeFace(face, true);
removedSome = true;
}
}
}
}
private void removeTrianglesInsideObstacles() {
List<F> faces = triangulation.getMesh().getFaces();
for(F face : faces) {
if(!triangulation.getMesh().isDestroyed(face) && distFunc.apply(triangulation.getMesh().toTriangle(face).midPoint()) > 0) {
triangulation.removeFace(face, true);
}
}
}
/*private void removeTrianglesInsideObstacles() {
for(VShape shape : boundary) {
// 1. find a triangle inside the boundary
......@@ -110,7 +136,7 @@ public class UniformRefinementTriangulation<P extends IPoint, V extends IVertex<
logger.warn("no face found");
}
}
}
}*/
private boolean intersectShape(final VLine line, final VShape shape) {
return shape.intersects(line) || shape.contains(line.getP1()) || shape.contains(line.getP2());
......
......@@ -291,6 +291,10 @@ public interface IPolyConnectivity<P extends IPoint, V extends IVertex<P>, E ext
if(getMesh().isBoundary(getMesh().getTwin(edge))) {
delEdges.add(edge);
}
else {
// update the edge of the boundary since it might be deleted!
getMesh().setEdge(boundary, edge);
}
vertices.add(getMesh().getVertex(edge));
}
......@@ -310,6 +314,9 @@ public interface IPolyConnectivity<P extends IPoint, V extends IVertex<P>, E ext
next1 = getMesh().getNext(h1);
prev1 = getMesh().getPrev(h1);
boolean isolated0 = isSimpleConnected(v0);
boolean isolated1 = isSimpleConnected(v1);
// adjust next and prev half-edges
getMesh().setNext(prev0, next1);
getMesh().setNext(prev1, next0);
......@@ -317,11 +324,11 @@ public interface IPolyConnectivity<P extends IPoint, V extends IVertex<P>, E ext
//boolean isolated0 = getMesh().getNext(prev1).equals(getMesh().getTwin(prev1));
//boolean isolated1 = getMesh().getNext(prev0).equals(getMesh().getTwin(prev0));
boolean isolated0 = getMesh().getTwin(h0).equals(getMesh().getNext(h0)) || getMesh().getTwin(h0).equals(getMesh().getPrev(h0));
boolean isolated1 = getMesh().getTwin(h1).equals(getMesh().getNext(h1)) || getMesh().getTwin(h1).equals(getMesh().getPrev(h1));
//boolean isolated0 = getMesh().getTwin(h0) == getMesh().getNext(h0) || getMesh().getTwin(h0) == getMesh().getPrev(h0);
//boolean isolated1 = getMesh().getTwin(h1) == getMesh().getNext(h1) || getMesh().getTwin(h1) == getMesh().getPrev(h1);
// adjust vertices
if(getMesh().getEdge(v0).equals(h0) && !isolated0) {
if(getMesh().getEdge(v0) == h0 && !isolated0) {
getMesh().setEdge(v0, prev1);
}
......@@ -329,7 +336,7 @@ public interface IPolyConnectivity<P extends IPoint, V extends IVertex<P>, E ext
getMesh().destroyVertex(v0);
}
if(getMesh().getEdge(v1).equals(h1) && !isolated1) {
if(getMesh().getEdge(v1) == h1 && !isolated1) {
getMesh().setEdge(v1, prev0);
}
......@@ -342,12 +349,31 @@ public interface IPolyConnectivity<P extends IPoint, V extends IVertex<P>, E ext
getMesh().destroyEdge(h1);
// TODO: do we need this?
vertices.stream().filter(getMesh()::isAlive).forEach(this::adjustVertex);
//vertices.stream().filter(getMesh()::isAlive).forEach(this::adjustVertex);
}
}
getMesh().destroyFace(face);
}
/**
* Tests whether the vertex has degree smaller or equals 2.
* If an edge gets deleted and the vertex is simple connected
* the vertex becomes isolated.
*
* @param vertex the vertex
* @return true if the vertex has degree smaller or equals 2, false otherwise.
*/
default boolean isSimpleConnected(@NotNull final V vertex) {
if(getMesh().isDestroyed(vertex)) {
return true;
}
// test if degree of the vertex is <= 2
E edge0 = getMesh().getEdge(vertex);
E edge1 = getMesh().getTwin(getMesh().getNext(edge0));
E edge2 = getMesh().getTwin(getMesh().getNext(edge1));
return edge0 == edge1 || edge0 == edge2;
}
/**
* Returns a half-edge such that it is part of face1 and the twin of this half-edge
* is part of face2.
......
......@@ -60,6 +60,10 @@ public interface ITriConnectivity<P extends IPoint, V extends IVertex<P>, E exte
*/
boolean isIllegal(E edge, V p);
default boolean isIllegal(E edge) {
return isIllegal(edge, getMesh().getVertex(getMesh().getNext(edge)));
}
/**
* Splits the half-edge at point p, preserving a valid triangulation.
* Assumption: p is located on the edge!
......@@ -111,7 +115,17 @@ public interface ITriConnectivity<P extends IPoint, V extends IVertex<P>, E exte
mesh.setEdge(v, t1);
mesh.setTwin(e1, t1);
/*
* These two operations are strongly connected.
* Before these operations the vertex of o0 is v2.
* If the edge of v2 is equal to o0, the edge becomes
* invalid after calling mesh.setVertex(o0, v);
*/
mesh.setVertex(o0, v);
if(mesh.getEdge(v2).equals(o0)) {
mesh.setEdge(v2, e1);
}
if(!mesh.isBoundary(h0)) {
F f1 = mesh.createFace();
......@@ -249,6 +263,11 @@ public interface ITriConnectivity<P extends IPoint, V extends IVertex<P>, E exte
}
// TODO: maybe without if, just do it? its faster?
assert mesh.getVertex(b2) == va0;
assert mesh.getVertex(a2) == vb0;
if(mesh.getEdge(va0).equals(a0)) {
mesh.setEdge(va0, b2);
}
......
......@@ -11,8 +11,13 @@ import org.junit.Test;
import org.vadere.util.geometry.mesh.gen.PFace;
import org.vadere.util.geometry.mesh.gen.PVertex;
import org.vadere.util.geometry.mesh.gen.PHalfEdge;
import org.vadere.util.geometry.mesh.impl.VPTriangulation;
import org.vadere.util.geometry.mesh.inter.IFace;
import org.vadere.util.geometry.mesh.inter.IHalfEdge;
import org.vadere.util.geometry.mesh.inter.IPointLocator;
import org.vadere.util.geometry.mesh.inter.ITriangulation;
import org.vadere.util.geometry.mesh.inter.IVertex;
import org.vadere.util.geometry.shapes.IPoint;
import org.vadere.util.geometry.shapes.VPoint;
import org.vadere.util.geometry.shapes.VRectangle;
import org.vadere.util.geometry.shapes.VTriangle;
......@@ -60,7 +65,7 @@ public class TestBoyerWatson {
triangulationList.add(ITriangulation.createPTriangulation(IPointLocator.Type.BASE, points, (x, y) -> new VPoint(x, y)));
triangulationList.add(ITriangulation.createPTriangulation(IPointLocator.Type.DELAUNAY_TREE, points, (x, y) -> new VPoint(x, y)));
//triangulationList.add(ITriangulation.createPTriangulation(IPointLocator.Type.DELAUNAY_HIERARCHY, points, (x, y) -> new VPoint(x, y)));
triangulationList.add(ITriangulation.createPTriangulation(IPointLocator.Type.DELAUNAY_HIERARCHY, points, (x, y) -> new VPoint(x, y)));
for(ITriangulation<VPoint, PVertex<VPoint>, PHalfEdge<VPoint>, PFace<VPoint>> delaunayTriangulation : triangulationList) {
delaunayTriangulation.finalize();
......@@ -125,6 +130,7 @@ public class TestBoyerWatson {
assertTrue(testTriangulationEquality(triangles, expectedResult));
}
@Test
public void testPerformanceForDifferentPointLocators() {
List<VPoint> points = new ArrayList<>();
......@@ -132,7 +138,7 @@ public class TestBoyerWatson {
int height = 300;
Random r = new Random();
assert false;
int numberOfPoints = 500000;
int numberOfPoints = 100000;
for(int i=0; i< numberOfPoints; i++) {
VPoint point = new VPoint(width*r.nextDouble(), height*r.nextDouble());
......@@ -212,6 +218,27 @@ public class TestBoyerWatson {
log.info("runtime of the ? for " + numberOfPoints + " vertices =" + (System.currentTimeMillis() - ms) + " using the JTS-Delaunay-Triangulation");
}
@Test
public void testEdgeVertexRelation() {
List<VPoint> points = new ArrayList<>();
int width = 300;
int height = 300;
Random r = new Random();
assert false;
int numberOfPoints = 5000;
for (int i = 0; i < numberOfPoints; i++) {
VPoint point = new VPoint(width * r.nextDouble(), height * r.nextDouble());
points.add(point);
}
VPTriangulation vpTriangulation = ITriangulation.createVPTriangulation(new VRectangle(0, 0, width, height));
vpTriangulation.insert(points);
vpTriangulation.finalize();
assertTrue(hasCorrectEdgeVertexRealtion(vpTriangulation));
}
private static boolean testTriangulationEquality(final Set<VTriangle> triangulation1, final Set<VTriangle> triangulation2) {
if(triangulation1.size() != triangulation2.size())
......@@ -231,6 +258,13 @@ public class TestBoyerWatson {
return true;
}
private static <P extends IPoint, V extends IVertex<P>, E extends IHalfEdge<P>, F extends IFace<P>> boolean hasCorrectEdgeVertexRealtion(final ITriangulation<P, V, E, F> triangulation) {
return triangulation.getMesh()
.streamVertices()
.filter(v -> triangulation.getMesh().isAlive(v))
.noneMatch(v -> triangulation.getMesh().getVertex(triangulation.getMesh().getEdge(v)) != v);
}
private static boolean testTriangleEquality(final VTriangle triangle1, final VTriangle triangle2) {
return (triangle2.p1.equals(triangle1.p1) && triangle2.p2.equals(triangle1.p2) && triangle2.p3.equals(triangle1.p3)) ||
(triangle2.p1.equals(triangle1.p1) && triangle2.p2.equals(triangle1.p3) && triangle2.p3.equals(triangle1.p2)) ||
......
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