Commit e8f8fbbf authored by Benedikt Zoennchen's avatar Benedikt Zoennchen

improve the refinement triangulation, some updates for the mesh classes

parent 839bf075
package org.vadere.util.geometry.mesh.triangulations;
package org.vadere.util.geometry.mesh.gen;
import org.jetbrains.annotations.NotNull;
......
package org.vadere.util.geometry.mesh.triangulations;
package org.vadere.util.geometry.mesh.gen;
import org.apache.commons.lang3.tuple.Triple;
import org.vadere.util.geometry.mesh.inter.IFace;
......
......@@ -40,13 +40,11 @@ public class DelaunayHierarchy<P extends IPoint, V extends IVertex<P>, E extends
private Supplier<ITriangulation<P, V, E, F>> triangulationSupplier;
// see delaunay-hierarchy paper!
/*private double alpha = 30;
private double alpha = 30;
private int maxLevel = 5;
private int minSize = 20;*/
private double alpha = 30;
private int maxLevel = 5;
private int minSize = 20;
private int minSize = 20;
private LinkedList<F> prevLocationResult;
......@@ -127,8 +125,6 @@ public class DelaunayHierarchy<P extends IPoint, V extends IVertex<P>, E extends
prev = v;
}
}
//System.out.println(this);
}
private ITriangulation<P, V, E, F> getLevel(final int level) {
......@@ -144,8 +140,7 @@ public class DelaunayHierarchy<P extends IPoint, V extends IVertex<P>, E extends
}
private V getDown(V src, int srcLevel) {
// srcLevel-1 since the resulting vertex is contained in the mesh one level below the src vertex!
return getLevel(srcLevel-1).getMesh().getDown(src);
return getLevel(srcLevel).getMesh().getDown(src);
}
private int randomLevel() {
......@@ -235,16 +230,7 @@ public class DelaunayHierarchy<P extends IPoint, V extends IVertex<P>, E extends
}
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder("");
for(int i = 0; i < hierarchySets.size(); i++) {
builder.append("["+i+"]:" + hierarchySets.get(i).getMesh().getNumberOfVertices()+"\n");
}
return builder.toString();
}
/**
/**
* Returns vertex of the triangulation of the face with the smallest distance to point.
* Assumption: The face has to be part of the mesh of the triangulation.
*
......
......@@ -114,7 +114,6 @@ public class IncrementalTriangulation<P extends IPoint, V extends IVertex<P>, E
p1 = mesh.insertVertex(bound.getX() + 2 * max + gap, bound.getY() - gap);
p2 = mesh.insertVertex(bound.getX() + (max+2*gap)/2, bound.getY() + 2 * max + gap);
// counter clockwise!
superTriangle = mesh.createFace(p0, p1, p2);
borderFace = mesh.getTwinFace(mesh.getEdge(superTriangle));
......@@ -230,24 +229,17 @@ 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));
if(!mesh.isDestroyed(p0)) {
List<F> faces1 = mesh.getFaces(p0);
faces1.removeIf(f -> mesh.isBoundary(f));
faces1.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));
}
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));
}
List<F> faces3 = mesh.getFaces(p2);
faces3.removeIf(f -> mesh.isDestroyed(f) || mesh.isBoundary(f));
faces3.forEach(f -> removeFace(f, true));
finalized = true;
}
......@@ -384,7 +376,7 @@ public class IncrementalTriangulation<P extends IPoint, V extends IVertex<P>, E
*/
@Override
public boolean isIllegal(E edge, V p) {
if(!mesh.isAtBoundary(edge)) {
if(!mesh.isBoundary(mesh.getTwinFace(edge))) {
//assert mesh.getVertex(mesh.getNext(edge)).equals(p);
//V p = mesh.getVertex(mesh.getNext(edge));
E t0 = mesh.getTwin(edge);
......@@ -547,7 +539,7 @@ public class IncrementalTriangulation<P extends IPoint, V extends IVertex<P>, E
points.add(new VPoint(80,70));*/
Random r = new Random();
for(int i=0; i< 10000; i++) {
for(int i=0; i< 1000000; i++) {
VPoint point = new VPoint(width*r.nextDouble(), height*r.nextDouble());
points.add(point);
}
......@@ -560,9 +552,11 @@ public class IncrementalTriangulation<P extends IPoint, V extends IVertex<P>, E
IPointLocator.Type.DELAUNAY_HIERARCHY,
points,
pointConstructor);
new IncrementalTriangulation<>(points);
bw.finalize();
Set<VLine> edges = bw.getEdges();
System.out.println(System.currentTimeMillis() - ms);
Set<VLine> edges = bw.getEdges();
JFrame window = new JFrame();
window.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
......@@ -570,22 +564,6 @@ public class IncrementalTriangulation<P extends IPoint, V extends IVertex<P>, E
window.getContentPane().add(new Lines(edges, points, max));
window.setVisible(true);
ms = System.currentTimeMillis();
ITriangulation<VPoint, AVertex<VPoint>, AHalfEdge<VPoint>, AFace<VPoint>> bw2 = ITriangulation.createATriangulation(
IPointLocator.Type.DELAUNAY_HIERARCHY,
points,
pointConstructor);
bw2.finalize();
System.out.println(System.currentTimeMillis() - ms);
Set<VLine> edges2 = bw2.getEdges();
JFrame window2 = new JFrame();
window2.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
window2.setBounds(0, 0, max, max);
window2.getContentPane().add(new Lines(edges2, points, max));
window2.setVisible(true);
/*ms = System.currentTimeMillis();
BowyerWatsonSlow<VPoint> bw2 = new BowyerWatsonSlow<VPoint>(points, (x, y) -> new VPoint(x, y));
bw2.execute();
......@@ -614,7 +592,7 @@ public class IncrementalTriangulation<P extends IPoint, V extends IVertex<P>, E
window3.getContentPane().add(new Lines(edges3, edges3.stream().flatMap(edge -> edge.streamPoints()).collect(Collectors.toSet()), max));
window3.setVisible(true);*/
/*VRectangle bound = new VRectangle(0, 0, width, height);
VRectangle bound = new VRectangle(0, 0, width, height);
ITriangulation triangulation = ITriangulation.createVPTriangulation(bound);
VPUniformRefinement uniformRefinement = new VPUniformRefinement(
triangulation,
......@@ -629,7 +607,7 @@ public class IncrementalTriangulation<P extends IPoint, V extends IVertex<P>, E
window4.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
window4.setBounds(0, 0, max, max);
window4.getContentPane().add(new Lines(edges4, edges4.stream().flatMap(edge -> edge.streamPoints()).collect(Collectors.toSet()), max));
window4.setVisible(true);*/
window4.setVisible(true);
}
private static class Lines extends JComponent{
......
......@@ -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;
}*/
}
}
......@@ -10,7 +10,6 @@ import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
......@@ -20,7 +19,6 @@ import java.util.stream.Stream;
public class PMesh<P extends IPoint> implements IMesh<P, PVertex<P>, PHalfEdge<P>, PFace<P>> {
private List<PFace<P>> faces;
//private List<PFace<P>> borderFaces;
private PFace<P> boundary;
private List<PHalfEdge<P>> edges;
private IPointConstructor<P> pointConstructor;
......@@ -28,7 +26,6 @@ public class PMesh<P extends IPoint> implements IMesh<P, PVertex<P>, PHalfEdge<P
public PMesh(final IPointConstructor<P> pointConstructor) {
this.faces = new ArrayList<>();
//this.borderFaces = new ArrayList<>();
this.edges = new ArrayList<>();
this.vertices = new HashSet<>();
this.boundary = new PFace<>(true);
......@@ -138,23 +135,11 @@ 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);
}
......@@ -180,16 +165,6 @@ public class PMesh<P extends IPoint> implements IMesh<P, PVertex<P>, PHalfEdge<P
return faces.size();
}
@Override
public boolean tryLock(@NotNull PVertex<P> vertex) {
return vertex.getLock().tryLock();
}
@Override
public void unlock(@NotNull PVertex<P> vertex) {
vertex.getLock().unlock();
}
@Override
public PHalfEdge<P> createEdge(@NotNull PVertex<P> vertex) {
PHalfEdge<P> edge = new PHalfEdge<>(vertex);
......@@ -282,21 +257,13 @@ public class PMesh<P extends IPoint> implements IMesh<P, PVertex<P>, PHalfEdge<P
}
@Override
public Stream<PHalfEdge<P>> streamEdges() {
return edges.stream().filter(e -> !isDestroyed(e));
}
@Override
public Stream<PHalfEdge<P>> streamEdgesParallel() {
return edges.parallelStream().filter(e -> !isDestroyed(e));
public Stream<PFace<P>> streamFaces() {
return faces.stream();
}
@Override
public Stream<PVertex<P>> streamVertices() { return vertices.stream().filter(v -> !isDestroyed(v)); }
@Override
public Stream<PVertex<P>> streamVerticesParallel() {
return vertices.parallelStream().filter(v -> !isDestroyed(v));
public Stream<PHalfEdge<P>> streamEdges() {
return edges.stream();
}
@Override
......@@ -306,25 +273,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.isBorder()).filter(face -> !face.isDestroyed()).collect(Collectors.toList());
}
@Override
public List<PHalfEdge<P>> getBoundaryEdges() {
return streamEdges().filter(edge -> edge.isBoundary()).filter(edge -> !edge.isDestroyed()).collect(Collectors.toList());
return streamFaces().filter(face -> !face.isDestroyed()).collect(Collectors.toList());
}
@Override
public List<PVertex<P>> getBoundaryVertices() {
return streamEdges().filter(edge -> edge.isBoundary()).filter(edge -> !edge.isDestroyed()).map(edge -> getVertex(edge)).collect(Collectors.toList());
}
@Override
public Stream<PFace<P>> streamFaces(@NotNull Predicate<PFace<P>> predicate) {
return faces.stream().filter(predicate);
}
@Override
public int getNumberOfEdges() {
return edges.size();
}
}
......@@ -3,16 +3,12 @@ package org.vadere.util.geometry.mesh.gen;
import org.vadere.util.geometry.mesh.inter.IVertex;
import org.vadere.util.geometry.shapes.IPoint;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author Benedikt Zoennchen
* @param <P>
*/
public class PVertex<P extends IPoint> implements IVertex<P> {
private final Lock lock;
private final P point;
private PVertex<P> down;
private PHalfEdge<P> halfEdge;
......@@ -22,7 +18,6 @@ public class PVertex<P extends IPoint> implements IVertex<P> {
this.point = point;
this.destroyed = false;
this.down = null;
this.lock = new ReentrantLock();
}
@Override
......@@ -67,10 +62,6 @@ public class PVertex<P extends IPoint> implements IVertex<P> {
destroyed = true;
}
public Lock getLock() {
return lock;
}
@Override
public int hashCode() {
return point.hashCode();
......
......@@ -13,16 +13,13 @@ 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.Random;
import java.util.Set;
/**
......@@ -40,16 +37,12 @@ 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;
private final static Random random = new Random();
public UniformRefinementTriangulation(
final ITriangulation<P, V, E, F> triangulation,
final VRectangle bound,
final Collection<VShape> boundary,
final IEdgeLengthFunction lenFunc,
final IDistanceFunction distFunc) {
this.distFunc = distFunc;
final IEdgeLengthFunction lenFunc) {
this.triangulation = triangulation;
this.mesh = triangulation.getMesh();
this.boundary = boundary;
......@@ -66,7 +59,7 @@ public class UniformRefinementTriangulation<P extends IPoint, V extends IVertex<
for(E edge : mesh.getEdgeIt(mesh.getBoundary())) {
if(!isCompleted(edge) && !points.contains(mesh.getVertex(edge))) {
toRefineEdges.add(mesh.getTwin(edge));
toRefineEdges.add(edge);
}
}
......@@ -86,31 +79,10 @@ public class UniformRefinementTriangulation<P extends IPoint, V extends IVertex<
}
private void removeTrianglesOutsideBBox() {
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;
}
}
}
//TODO:
}
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
......@@ -138,26 +110,23 @@ 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());
}
private boolean isCompleted(E edge) {
if(mesh.isBoundary(edge)){
edge = mesh.getTwin(edge);
}
private boolean isCompleted(final E edge) {
F face = mesh.getFace(edge);
F twin = mesh.getTwinFace(edge);
VTriangle triangle = mesh.toTriangle(face);
VTriangle twinTriangle = mesh.toTriangle(twin);
VLine line = mesh.toLine(edge);
return (line.length() <= lenFunc.apply(line.midPoint()) && random.nextDouble() < 0.96)
|| (!triangle.intersect(bbox) && (mesh.isBoundary(twin) || !mesh.toTriangle(twin).intersect(bbox)))
|| boundary.stream().anyMatch(shape -> shape.contains(triangle.getBounds2D()) || (!mesh.isBoundary(twin) && shape.contains(mesh.toTriangle(twin).getBounds2D())));
return line.length() <= lenFunc.apply(line.midPoint())
|| (!triangle.intersect(bbox) && !twinTriangle.intersect(bbox))
|| boundary.stream().anyMatch(shape -> shape.contains(triangle.getBounds2D()) || shape.contains(twinTriangle.getBounds2D()));
}
private Collection<E> refine(final E edge) {
......
package org.vadere.util.geometry.mesh.impl;
import org.jetbrains.annotations.NotNull;
import org.vadere.util.geometry.GeometryUtils;
import org.vadere.util.geometry.mesh.inter.IFace;
import org.vadere.util.geometry.mesh.iterators.EdgeIterator;
import org.vadere.util.geometry.shapes.IPoint;
import org.vadere.util.geometry.shapes.MLine;
import org.vadere.util.geometry.shapes.VPoint;
import org.vadere.util.geometry.shapes.VPolygon;
import org.vadere.util.geometry.shapes.VTriangle;
import java.awt.geom.Path2D;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
/**
* A Face is a region of a planar separation of the 2-D space, e.g. the region of a Polygon/Triangle and so on.
*
* @author Benedikt Zoennchen
* @param <P> the type of the coordinates the face uses.
*/
public class PFace<P extends IPoint> implements IFace<P> {
/**
* One of the half-edges bordering this face.
*/
private PHalfEdge<P> edge;
private boolean border;
private boolean destroyed = false;
/**
* Default constructor. To construct a face where you have already some half-edges
* bordering this face.
*
* @param edge one of the half-edges bordering this face.
*/
PFace(@NotNull final PHalfEdge<P> edge) {
this(edge, false);
}
PFace(@NotNull final PHalfEdge<P> edge, boolean border) {
this.border = border;
this.edge = edge;
}
/**
* This constructor can be used for constructing a new face without having
* constructed the bordering half-edges jet.
*/
PFace(boolean border) {
this.border = border;
}
PFace() {
this.border = false;
}
boolean isBorder() {
return border;
}
void destroy() {
setEdge(null);
destroyed = true;
}
/**
* Sets one of the half-edges bordering this face.
*
* @param edge half-edge bordering this face
*/
void setEdge(final PHalfEdge<P> edge) {
this.edge = edge;
}
PHalfEdge<P> getEdge() {
return edge;
}
boolean isDestroyed() {
return destroyed;
}
@Override
public String toString() {
PHalfEdge<P> current = edge;
PHalfEdge<P> next = edge.getNext();
StringBuilder builder = new StringBuilder();
while (!edge.equals(next)) {
builder.append(current + " ");
current = next;
next = current.getNext();
}
builder.append(current);
return builder.toString();
}
}
package org.vadere.util.geometry.mesh.impl;
import org.jetbrains.annotations.NotNull;
import org.vadere.util.geometry.mesh.inter.IHalfEdge;
import org.vadere.util.geometry.shapes.IPoint;
import org.vadere.util.geometry.shapes.VLine;
import org.vadere.util.geometry.shapes.VPoint;
public class PHalfEdge<P extends IPoint> implements IHalfEdge<P> {
/**
* point at the end of the half edge.
*/
private PVertex<P> end;
/**
* next half-edge around the face.
*/
private PHalfEdge<P> next;
/**
* previous half-edge around the face.
*/
private PHalfEdge<P> previous;
/**
* oppositely oriented adjacnet half-edge. If the face is a the boundary
* there is no twin.
*/
private PHalfEdge<P> twin;
/**
* the face the half-edge borders.
*/
private PFace<P> face;
PHalfEdge(@NotNull final PVertex<P> end, @NotNull final PFace<P> face) {
this.end = end;
this.face = face;
}