Commit 9b5c6caa authored by Benedikt Zoennchen's avatar Benedikt Zoennchen
Browse files

improve the refinement triangulation, some updates for the mesh classes

parent e2544d76
package org.vadere.util.geometry.mesh.triangulations;
package org.vadere.util.geometry.mesh.gen;
import org.vadere.util.geometry.mesh.inter.IFace;
import org.vadere.util.geometry.mesh.inter.IHalfEdge;
......
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;
......
package org.vadere.util.geometry.mesh.triangulations;
package org.vadere.util.geometry.mesh.gen;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
......
package org.vadere.util.geometry.mesh.triangulations;
package org.vadere.util.geometry.mesh.gen;
import org.apache.commons.lang3.tuple.Triple;
......@@ -10,14 +10,12 @@ import org.vadere.util.geometry.mesh.inter.ITriangulation;
import org.vadere.util.geometry.mesh.inter.IVertex;
import org.vadere.util.geometry.shapes.IPoint;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
public class DelaunayTree<P extends IPoint, V extends IVertex<P>, E extends IHalfEdge<P>, F extends IFace<P>> implements IPointLocator<P, V, E, F> {
private DAG<DAGElement<P, F>> dag;
......
package org.vadere.util.geometry.mesh.triangulations;
package org.vadere.util.geometry.mesh.gen;
import org.apache.commons.collections.IteratorUtils;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import org.vadere.util.geometry.GeometryUtils;
import org.vadere.util.geometry.mesh.impl.PFace;
import org.vadere.util.geometry.mesh.impl.PVertex;
import org.vadere.util.geometry.mesh.impl.VPUniformRefinement;
import org.vadere.util.geometry.mesh.inter.IVertex;
import org.vadere.util.geometry.mesh.iterators.FaceIterator;
import org.vadere.util.geometry.mesh.inter.IFace;
import org.vadere.util.geometry.mesh.inter.IHalfEdge;
import org.vadere.util.geometry.mesh.inter.IMesh;
import org.vadere.util.geometry.mesh.iterators.AdjacentFaceIterator;
import org.vadere.util.geometry.mesh.impl.PHalfEdge;
import org.vadere.util.geometry.mesh.impl.PMesh;
import org.vadere.util.geometry.shapes.IPoint;
import org.vadere.util.geometry.shapes.VCircle;
import org.vadere.util.geometry.shapes.VLine;
......@@ -67,12 +64,14 @@ public class IncrementalTriangulation<P extends IPoint, V extends IVertex<P>, E
protected F superTriangle;
private F borderFace;
private final Predicate<E> illegalPredicate;
private final Predicate<? extends E> illegalPredicate;
private static Logger log = LogManager.getLogger(IncrementalTriangulation.class);
// constructors
public IncrementalTriangulation(
final Collection<P> points,
final Predicate<E> illegalPredicate) {
final Predicate<? extends E> illegalPredicate) {
this.points = points;
this.illegalPredicate = illegalPredicate;
this.bound = GeometryUtils.bound(points);
......@@ -85,7 +84,7 @@ public class IncrementalTriangulation<P extends IPoint, V extends IVertex<P>, E
public IncrementalTriangulation(
final VRectangle bound,
final Predicate<E> illegalPredicate) {
final Predicate<? extends E> illegalPredicate) {
this.points = new HashSet<>();
this.illegalPredicate = illegalPredicate;
this.bound = bound;
......@@ -96,6 +95,8 @@ public class IncrementalTriangulation<P extends IPoint, V extends IVertex<P>, E
this(bound, halfEdge -> true);
}
// end constructors
public void setPointLocator(final IPointLocator<P, V, E, F> pointLocator) {
this.pointLocator = pointLocator;
}
......@@ -106,22 +107,27 @@ public class IncrementalTriangulation<P extends IPoint, V extends IVertex<P>, E
@Override
public void init() {
double gap = 1.0;
double max = Math.max(bound.getWidth(), bound.getHeight())*2;
p0 = mesh.insertVertex(bound.getX() - max - gap, bound.getY() - gap);
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);
superTriangle = mesh.createFace(p0, p1, p2);
borderFace = mesh.getTwinFace(mesh.getEdge(superTriangle));
List<E> borderEdges = mesh.getEdges(borderFace);
he0 = borderEdges.get(0);
he1 = borderEdges.get(1);
he2 = borderEdges.get(2);
this.superEdges = Arrays.asList(p0, p1, p2);
this.initialized = true;
if(!initialized) {
double gap = 1.0;
double max = Math.max(bound.getWidth(), bound.getHeight())*2;
p0 = mesh.insertVertex(bound.getX() - max - gap, bound.getY() - gap);
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);
superTriangle = mesh.createFace(p0, p1, p2);
borderFace = mesh.getTwinFace(mesh.getEdge(superTriangle));
List<E> borderEdges = mesh.getEdges(borderFace);
he0 = borderEdges.get(0);
he1 = borderEdges.get(1);
he2 = borderEdges.get(2);
this.superEdges = Arrays.asList(p0, p1, p2);
this.initialized = true;
}
else {
log.warn("the second initialization of the " + this.getClass().getSimpleName() + " has no effect.");
}
}
@Override
......@@ -198,7 +204,7 @@ public class IncrementalTriangulation<P extends IPoint, V extends IVertex<P>, E
/**
* Removes the super triangle from the mesh data structure.
*/
public void finalize() {
/*public void finalize() {
if(!finalized) {
// we have to use other halfedges than he1 and he2 since they might be deleted
// if we deleteBoundaryFace he0!
......@@ -215,6 +221,26 @@ public class IncrementalTriangulation<P extends IPoint, V extends IVertex<P>, E
faces3.removeIf(f -> mesh.isDestroyed(f) || mesh.isBoundary(f));
faces3.forEach(f -> deleteBoundaryFace(f));
finalized = true;
}
}*/
public void finalize() {
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));
List<F> faces3 = mesh.getFaces(p2);
faces3.removeIf(f -> mesh.isDestroyed(f) || mesh.isBoundary(f));
faces3.forEach(f -> removeFace(f, true));
finalized = true;
}
}
......@@ -331,10 +357,6 @@ public class IncrementalTriangulation<P extends IPoint, V extends IVertex<P>, E
return stream().map(face -> faceToTriangle(face)).collect(Collectors.toSet());
}
public Set<VLine> getEdges() {
return getTriangles().stream().flatMap(triangle -> triangle.getLineStream()).collect(Collectors.toSet());
}
private VTriangle faceToTriangle(final F face) {
List<V> points = mesh.getEdges(face).stream().map(edge -> mesh.getVertex(edge)).collect(Collectors.toList());
V p1 = points.get(0);
......@@ -555,7 +577,7 @@ public class IncrementalTriangulation<P extends IPoint, V extends IVertex<P>, E
window2.getContentPane().add(new Lines(edges2, points, max));
window2.setVisible(true);
UniformTriangulation<VPoint, PVertex<VPoint>, PHalfEdge<VPoint>, PFace<VPoint>> uniformTriangulation = ITriangulation.createUnifirmTriangulation(
UniformTriangulation<VPoint, PVertex<VPoint>, PHalfEdge<VPoint>, PFace<VPoint>> uniformTriangulation = ITriangulation.createUniformTriangulation(
IPointLocator.Type.DELAUNAY_TREE,
new VRectangle(0, 0, width, height),
10.0,
......@@ -568,22 +590,24 @@ public class IncrementalTriangulation<P extends IPoint, V extends IVertex<P>, E
window3.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
window3.setBounds(0, 0, max, max);
window3.getContentPane().add(new Lines(edges3, edges3.stream().flatMap(edge -> edge.streamPoints()).collect(Collectors.toSet()), max));
window3.setVisible(true);
window3.setVisible(true);*/
UniformRefinementTriangulation<VPoint> uniformRefinement = new UniformRefinementTriangulation<>(
new VRectangle(0, 0, width, height),
VRectangle bound = new VRectangle(0, 0, width, height);
ITriangulation triangulation = ITriangulation.createVPTriangulation(bound);
VPUniformRefinement uniformRefinement = new VPUniformRefinement(
triangulation,
bound,
Arrays.asList(new VRectangle(200, 200, 100, 200)),
p -> 10.0,
(x, y) -> new VPoint(x, y));
p -> 10.0);
uniformRefinement.compute();
Set<VLine> edges4 = uniformRefinement.getEdges();
Set<VLine> edges4 = triangulation.getEdges();
JFrame window4 = new JFrame();
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{
......
package org.vadere.util.geometry.mesh.impl;
package org.vadere.util.geometry.mesh.gen;
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.
......@@ -40,11 +27,11 @@ public class PFace<P extends IPoint> implements IFace<P> {
*
* @param edge one of the half-edges bordering this face.
*/
PFace(@NotNull final PHalfEdge<P> edge) {
protected PFace(@NotNull final PHalfEdge<P> edge) {
this(edge, false);
}
PFace(@NotNull final PHalfEdge<P> edge, boolean border) {
protected PFace(@NotNull final PHalfEdge<P> edge, boolean border) {
this.border = border;
this.edge = edge;
}
......
package org.vadere.util.geometry.mesh.impl;
package org.vadere.util.geometry.mesh.gen;
import org.jetbrains.annotations.NotNull;
import org.vadere.util.geometry.mesh.inter.IHalfEdge;
......@@ -34,15 +34,19 @@ public class PHalfEdge<P extends IPoint> implements IHalfEdge<P> {
*/
private PFace<P> face;
private boolean destroyed;
PHalfEdge(@NotNull final PVertex<P> end, @NotNull final PFace<P> face) {
protected PHalfEdge(@NotNull final PVertex<P> end, @NotNull final PFace<P> face) {
this.end = end;
this.face = face;
this.destroyed = false;
}
PHalfEdge(@NotNull final PVertex<P> end) {
protected PHalfEdge(@NotNull final PVertex<P> end) {
this.end = end;
this.face = null;
this.destroyed = false;
}
PFace<P> getFace() {
......@@ -89,6 +93,7 @@ public class PHalfEdge<P extends IPoint> implements IHalfEdge<P> {
setPrevious(null);
setTwin(null);
setFace(null);
destroyed = true;
}
boolean isValid() {
......@@ -124,12 +129,15 @@ public class PHalfEdge<P extends IPoint> implements IHalfEdge<P> {
return new VLine(new VPoint(this.getPrevious().getEnd()), new VPoint(this.getEnd()));
}
public boolean isDestroyed() {
return destroyed;
}
@Override
public String toString() {
return getEnd().toString();
}
/*
* A half-edge is defined by its end vertex and its face. In a geometry there can not be more than
* one half-edge part of face and ending at end.
......
package org.vadere.util.geometry.mesh.impl;
package org.vadere.util.geometry.mesh.gen;
import org.jetbrains.annotations.NotNull;
import org.vadere.util.geometry.mesh.inter.IMesh;
......@@ -103,6 +103,11 @@ public class PMesh<P extends IPoint> implements IMesh<P, PVertex<P>, PHalfEdge<P
return !edge.isValid();
}
@Override
public boolean isDestroyed(@NotNull PVertex<P> vertex) {
return vertex.isDestroyed();
}
@Override
public void setTwin(final PHalfEdge<P> halfEdge, final PHalfEdge<P> twin) {
halfEdge.setTwin(twin);
......@@ -138,10 +143,12 @@ public class PMesh<P extends IPoint> implements IMesh<P, PVertex<P>, PHalfEdge<P
halfEdge.setEnd(vertex);
}
@Override
/*@Override
public List<PHalfEdge<P>> getEdges(@NotNull final PVertex<P> vertex) {
return edges.stream().filter(edge -> !edge.isValid()).filter(edge -> getVertex(edge).equals(vertex)).collect(Collectors.toList());
}
return
//return streamEdges().filter(edge -> !edge.isValid()).filter(edge -> getVertex(edge).equals(vertex)).collect(Collectors.toList());
}*/
@Override
public Collection<PVertex<P>> getVertices() {
......@@ -246,6 +253,7 @@ public class PMesh<P extends IPoint> implements IMesh<P, PVertex<P>, PHalfEdge<P
@Override
public void destroyVertex(@NotNull PVertex<P> vertex) {
vertices.remove(vertex);
vertex.destroy();
}
@Override
......@@ -255,7 +263,12 @@ public class PMesh<P extends IPoint> implements IMesh<P, PVertex<P>, PHalfEdge<P
@Override
public Stream<PHalfEdge<P>> streamEdges() {
return streamFaces().flatMap(face -> streamEdges(face));
return edges.stream();
}
@Override
public Iterable<PHalfEdge<P>> getEdgeIt() {
return () -> edges.iterator();
}
@Override
......
package org.vadere.util.geometry.mesh.impl;
package org.vadere.util.geometry.mesh.gen;
import org.vadere.util.geometry.mesh.inter.IVertex;
import org.vadere.util.geometry.shapes.IPoint;
......@@ -12,9 +12,11 @@ public class PVertex<P extends IPoint> implements IVertex<P> {
private final P point;
private PVertex<P> down;
private PHalfEdge<P> halfEdge;
private boolean destroyed;
public PVertex(final P point) {
this.point = point;
this.destroyed = false;
this.down = null;
}
......@@ -52,6 +54,14 @@ public class PVertex<P extends IPoint> implements IVertex<P> {
return point.equals(((PVertex<P>)obj).getPoint());
}
public boolean isDestroyed() {
return destroyed;
}
public void destroy() {
destroyed = true;
}
@Override
public int hashCode() {
return point.hashCode();
......
package org.vadere.util.geometry.mesh.triangulations;
package org.vadere.util.geometry.mesh.gen;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.vadere.util.geometry.mesh.impl.PFace;
import org.vadere.util.geometry.mesh.impl.PHalfEdge;
import org.vadere.util.geometry.mesh.impl.PVertex;
import org.vadere.util.geometry.mesh.inter.IFace;
import org.vadere.util.geometry.mesh.inter.IHalfEdge;
import org.vadere.util.geometry.mesh.inter.IMesh;
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.VLine;
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.IPointConstructor;
import org.vadere.util.triangulation.adaptive.IEdgeLengthFunction;
import java.util.Collection;
......@@ -25,83 +23,86 @@ import java.util.Optional;
import java.util.Set;
/**
* Triangulation creator!
*
* @author Benedikt Zoennchen
*
* @param <P>
*/
public class UniformRefinementTriangulation<P extends IPoint> {
public class UniformRefinementTriangulation<P extends IPoint, V extends IVertex<P>, E extends IHalfEdge<P>, F extends IFace<P>> {
private final Collection<VShape> boundary;
private final VRectangle bbox;
private final IEdgeLengthFunction lenFunc;
private ITriangulation<P, PVertex<P>, PHalfEdge<P>, PFace<P>> pTriangulation;
private ITriangulation<P, V, E, F> triangulation;
private Set<P> points;
private IMesh<P, PVertex<P>, PHalfEdge<P>, PFace<P>> mesh;
private IMesh<P, V, E, F> mesh;
private static final Logger logger = LogManager.getLogger(UniformRefinementTriangulation.class);
public UniformRefinementTriangulation(
final ITriangulation<P, V, E, F> triangulation,
final VRectangle bound,
final Collection<VShape> boundary,
final IEdgeLengthFunction lenFunc,
final IPointConstructor<P> pointConstructor) {
this.pTriangulation = ITriangulation.createPTriangulation(IPointLocator.Type.DELAUNAY_TREE, bound, pointConstructor);
this.mesh = pTriangulation.getMesh();
final IEdgeLengthFunction lenFunc) {
this.triangulation = triangulation;
this.mesh = triangulation.getMesh();
this.boundary = boundary;
this.lenFunc = lenFunc;
this.bbox = bound;
this.points = new HashSet<>();
}
public boolean isCompleted(final PHalfEdge<P> edge) {
PFace<P> face = mesh.isBoundary(edge) ? mesh.getTwinFace(edge) : mesh.getFace(edge);
VTriangle triangle = mesh.toTriangle(face);
P end = mesh.getPoint(edge);
P begin = mesh.getPoint(mesh.getPrev(edge));
return !bbox.intersect(triangle) || boundary.stream().anyMatch(shape -> shape.contains(triangle.getBounds2D())) || begin.distance(end) <= lenFunc.apply(midPoint(edge));
}
public void compute() {
pTriangulation.init();
triangulation.init();
logger.info("start computation");
LinkedList<PHalfEdge<P>> toRefineEdges = new LinkedList<>();
LinkedList<E> toRefineEdges = new LinkedList<>();
for(PHalfEdge<P> edge : mesh.getEdgeIt(mesh.getBoundary())) {
for(E edge : mesh.getEdgeIt(mesh.getBoundary())) {
if(!isCompleted(edge) && !points.contains(mesh.getVertex(edge))) {
toRefineEdges.add(edge);
}
}
while (!toRefineEdges.isEmpty()) {
PHalfEdge<P> edge = toRefineEdges.removeFirst();
for(PHalfEdge<P> refinedHalfEdges : refine(edge)) {
E edge = toRefineEdges.removeFirst();
for(E refinedHalfEdges : refine(edge)) {
if(!isCompleted(refinedHalfEdges)) {
toRefineEdges.addLast(refinedHalfEdges);
}
}
}
removeTrianglesOutsideBBox();
removeTrianglesInsideObstacles();
triangulation.finalize();
logger.info("end computation");
}
private void removeTrianglesOutsideBBox() {
//TODO:
}
private void removeTrianglesInsideObstacles() {
for(VShape shape : boundary) {
// 1. find a triangle inside the boundary
VPoint centroid = shape.getCentroid();
Optional<PFace<P>> optFace = pTriangulation.locateFace(centroid.getX(), centroid.getY());
Optional<F> optFace = triangulation.locateFace(centroid.getX(), centroid.getY());
if(optFace.isPresent()) {
LinkedList<PFace<P>> candidates = new LinkedList<>();
LinkedList<F> candidates = new LinkedList<>();
candidates.add(optFace.get());
// 2. as long as there is a face which has a vertex inside the shape remove it
while (!candidates.isEmpty()) {
PFace<P> face = candidates.removeFirst();
if(mesh.streamEdges(face).map(mesh::getVertex).anyMatch(shape::contains)) {
mesh.streamFaces(face).forEach(f -> candidates.add(f));
pTriangulation.removeFace(face, false);
F face = candidates.removeFirst();
if(!mesh.isDestroyed(face) && mesh.streamEdges(face).map(mesh::toLine).anyMatch(line -> intersectShape(line, shape))) {
mesh.streamFaces(face)
//.filter(f -> !face.equals(f)).distinct()
.forEach(candidate -> candidates.addFirst(candidate));
triangulation.removeFace(face, true);
}
}
}
......@@ -111,12 +112,25 @@ public class UniformRefinementTriangulation<P extends IPoint> {
}
}
public Set<VLine> getEdges() {
return pTriangulation.getEdges();
private boolean intersectShape(final VLine line, final VShape shape) {
return shape.intersects(line) || shape.contains(line.getP1()) || shape.contains(line.getP2());
}
public Collection<PHalfEdge<P>> refine(final PHalfEdge<P> edge) {
VPoint midPoint = midPoint(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);