Commit 839bf075 authored by Benedikt Zoennchen's avatar Benedikt Zoennchen

update triangulation algorithm, implementation of the delaunay-hierarchy

parent 0ce6b028
......@@ -11,7 +11,7 @@ public class PHalfEdge<P extends IPoint> implements IHalfEdge<P> {
/**
* point at the end of the half edge.
*/
private P end;
private PVertex<P> end;
/**
* next half-edge around the face.
......@@ -35,12 +35,12 @@ public class PHalfEdge<P extends IPoint> implements IHalfEdge<P> {
private PFace<P> face;
PHalfEdge(@NotNull final P end, @NotNull final PFace<P> face) {
PHalfEdge(@NotNull final PVertex<P> end, @NotNull final PFace<P> face) {
this.end = end;
this.face = face;
}
PHalfEdge(@NotNull final P end) {
PHalfEdge(@NotNull final PVertex<P> end) {
this.end = end;
this.face = null;
}
......@@ -53,7 +53,7 @@ public class PHalfEdge<P extends IPoint> implements IHalfEdge<P> {
this.face = face;
}
P getEnd() {
PVertex<P> getEnd() {
return end;
}
......@@ -116,7 +116,7 @@ public class PHalfEdge<P extends IPoint> implements IHalfEdge<P> {
}
}
void setEnd(P end) {
void setEnd(PVertex<P> end) {
this.end = end;
}
......
......@@ -11,17 +11,18 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @author Benedikt Zoennchen
*/
public class PMesh<P extends IPoint> implements IMesh<P, PHalfEdge<P>, PFace<P>> {
public class PMesh<P extends IPoint> implements IMesh<P, PVertex<P>, PHalfEdge<P>, PFace<P>> {
private List<PFace<P>> faces;
private PFace<P> boundary;
private List<PHalfEdge<P>> edges;
private IPointConstructor<P> pointConstructor;
private Set<P> vertices;
private Set<PVertex<P>> vertices;
public PMesh(final IPointConstructor<P> pointConstructor) {
this.faces = new ArrayList<>();
......@@ -48,13 +49,13 @@ public class PMesh<P extends IPoint> implements IMesh<P, PHalfEdge<P>, PFace<P>>
}
@Override
public PFace<P> getFace(final PHalfEdge<P> halfEdge) {
public PFace<P> getFace(@NotNull final PHalfEdge<P> halfEdge) {
return halfEdge.getFace();
}
@Override
public PHalfEdge<P> getEdge(@NotNull P vertex) {
return null;
public PHalfEdge<P> getEdge(@NotNull PVertex<P> vertex) {
return vertex.getEdge();
}
@Override
......@@ -63,10 +64,20 @@ public class PMesh<P extends IPoint> implements IMesh<P, PHalfEdge<P>, PFace<P>>
}
@Override
public P getVertex(@NotNull PHalfEdge<P> halfEdge) {
public P getPoint(@NotNull PHalfEdge<P> halfEdge) {
return getVertex(halfEdge).getPoint();
}
@Override
public PVertex<P> getVertex(@NotNull PHalfEdge<P> halfEdge) {
return halfEdge.getEnd();
}
@Override
public P getPoint(@NotNull PVertex<P> vertex) {
return vertex.getPoint();
}
@Override
public PFace<P> getFace() {
return faces.stream().filter(face -> !face.isDestroyed()).findAny().get();
......@@ -118,22 +129,22 @@ public class PMesh<P extends IPoint> implements IMesh<P, PHalfEdge<P>, PFace<P>>
}
@Override
public void setEdge(@NotNull P vertex, @NotNull PHalfEdge<P> edge) {
throw new UnsupportedOperationException("not jet implemented.");
public void setEdge(@NotNull PVertex<P> vertex, @NotNull PHalfEdge<P> edge) {
vertex.setEdge(edge);
}
@Override
public void setVertex(@NotNull PHalfEdge<P> halfEdge, @NotNull P vertex) {
public void setVertex(@NotNull PHalfEdge<P> halfEdge, @NotNull PVertex<P> vertex) {
halfEdge.setEnd(vertex);
}
@Override
public List<PHalfEdge<P>> getEdges(@NotNull P vertex) {
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());
}
@Override
public Collection<P> getVertices() {
public Collection<PVertex<P>> getVertices() {
return vertices;
}
......@@ -148,14 +159,14 @@ public class PMesh<P extends IPoint> implements IMesh<P, PHalfEdge<P>, PFace<P>>
}
@Override
public PHalfEdge<P> createEdge(@NotNull P vertex) {
public PHalfEdge<P> createEdge(@NotNull PVertex<P> vertex) {
PHalfEdge<P> edge = new PHalfEdge<>(vertex);
edges.add(edge);
return edge;
}
@Override
public PHalfEdge<P> createEdge(@NotNull P vertex, @NotNull PFace<P> face) {
public PHalfEdge<P> createEdge(@NotNull PVertex<P> vertex, @NotNull PFace<P> face) {
PHalfEdge<P> edge = new PHalfEdge<>(vertex, face);
edges.add(edge);
return edge;
......@@ -179,10 +190,20 @@ public class PMesh<P extends IPoint> implements IMesh<P, PHalfEdge<P>, PFace<P>>
}
@Override
public P createVertex(double x, double y) {
P vertex = pointConstructor.create(x, y);
//vertices.add(vertex);
return vertex;
public P createPoint(double x, double y) {
return pointConstructor.create(x, y);
}
// TODO: maybe remove insertVertex!
@Override
public PVertex<P> createVertex(double x, double y) {
return createVertex(pointConstructor.create(x, y));
}
@Override
public PVertex<P> createVertex(P point) {
return new PVertex<>(point);
}
@Override
......@@ -191,12 +212,12 @@ public class PMesh<P extends IPoint> implements IMesh<P, PHalfEdge<P>, PFace<P>>
}
@Override
public void insert(P vertex) {
public void insert(final PVertex<P> vertex) {
vertices.add(vertex);
}
@Override
public void insertVertex(P vertex) {
public void insertVertex(final PVertex<P> vertex) {
vertices.add(vertex);
}
......@@ -213,12 +234,32 @@ public class PMesh<P extends IPoint> implements IMesh<P, PHalfEdge<P>, PFace<P>>
}
@Override
public void destroyVertex(@NotNull P vertex) {
public void setDown(@NotNull PVertex<P> up, @NotNull PVertex<P> down) {
up.setDown(down);
}
@Override
public PVertex<P> getDown(@NotNull PVertex<P> vertex) {
return vertex.getDown();
}
@Override
public void destroyVertex(@NotNull PVertex<P> vertex) {
vertices.remove(vertex);
}
@Override
public Stream<PFace<P>> streamFaces() {
return faces.stream();
}
@Override
public Stream<PHalfEdge<P>> streamEdges() {
return streamFaces().flatMap(face -> streamEdges(face));
}
@Override
public List<PFace<P>> getFaces() {
return faces.stream().filter(face -> !face.isDestroyed()).collect(Collectors.toList());
return streamFaces().filter(face -> !face.isDestroyed()).collect(Collectors.toList());
}
}
package org.vadere.util.geometry.mesh.impl;
import org.vadere.util.geometry.mesh.inter.IVertex;
import org.vadere.util.geometry.shapes.IPoint;
/**
* @author Benedikt Zoennchen
* @param <P>
*/
public class PVertex<P extends IPoint> implements IVertex<P> {
private final P point;
private PVertex<P> down;
private PHalfEdge<P> halfEdge;
public PVertex(final P point) {
this.point = point;
this.down = null;
}
@Override
public P getPoint() {
return point;
}
public PHalfEdge<P> getEdge() {
return halfEdge;
}
public void setEdge(final PHalfEdge<P> halfEdge) {
this.halfEdge = halfEdge;
}
public PVertex<P> getDown() {
return down;
}
public void setDown(final PVertex<P> down) {
this.down = down;
}
@Override
public boolean equals(Object obj) {
if(obj == null) {
return false;
}
if(obj.getClass() != this.getClass()) {
return false;
}
return point.equals(((PVertex<P>)obj).getPoint());
}
@Override
public int hashCode() {
return point.hashCode();
}
@Override
public String toString() {
return point.toString();
}
}
package org.vadere.util.geometry.mesh.inter;
import java.util.ArrayList;
import java.util.List;
/**
* Created by bzoennchen on 04.04.17.
*/
public interface ITriangulationHierarchy<
P extends IHierarchyPoint,
E extends IHalfEdge<P>,
F extends IFace<P>,
T extends ITriangulation> {
enum LOCATE_TYPE {}
default P insert(final double x, final double y, LOCATE_TYPE locateType, F face, int li) {
int vertexLevel = randomLevel();
List<F> faces = locateInAll(x ,y);
ITriangulation<P, E, F> triangulation = getLevel(0);
P vertex = triangulation.getMesh().insertVertex(x, y);
triangulation.insert(faces.get(0), vertex);
P prev = vertex;
P first = vertex;
int level = 1;
while(level <= vertexLevel) {
triangulation = getLevel(level);
vertex = triangulation.getMesh().insertVertex(x, y);
vertex.setDown(prev);// link with level above
prev.setUp(vertex);
prev = vertex;
level++;
}
return first;
}
int randomLevel();
int getMaxLevel();
int getMinSize();
IHierarchyPoint create(P vertex);
ITriangulation<P, E, F> getLevel(int level);
default List<F> locateInAll(double x, double y) {
int level = getMaxLevel();
F face;
List<F> faces = new ArrayList<>(getMaxLevel());
while(level > 0 && (getLevel(level).getMesh().getNumberOfVertices() < getMinSize() || getLevel(level).getDimension() < 2)) {
level--;
}
for(int i = level+1; i < getMaxLevel(); i++) {
//pos[i] = 0???
}
while(level > 0) {
//getLevel(level).lo
//faces.add(face);
}
return null;
}
}
......@@ -3,6 +3,7 @@ package org.vadere.util.geometry.mesh.iterators;
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.IVertex;
import org.vadere.util.geometry.shapes.IPoint;
import java.util.Iterator;
......@@ -15,13 +16,13 @@ import java.util.Iterator;
* @param <E> the type of the half-edge
* @param <F> the type of the face
*/
public class EdgeIterator<P extends IPoint, E extends IHalfEdge<P>, F extends IFace<P>> implements Iterator<E> {
public class EdgeIterator<P extends IPoint, V extends IVertex<P>, E extends IHalfEdge<P>, F extends IFace<P>> implements Iterator<E> {
private E currentHalfEdge;
private E edge;
private boolean started = false;
private IMesh<P, E, F> mesh;
private IMesh<P, V, E, F> mesh;
public EdgeIterator(final IMesh<P, E, F> mesh, final F face){
public EdgeIterator(final IMesh<P, V, E, F> mesh, final F face){
this.edge = mesh.getEdge(face);
this.currentHalfEdge = edge;
this.mesh = mesh;
......
......@@ -2,13 +2,11 @@ package org.vadere.util.geometry.mesh.triangulations;
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.ITriConnectivity;
import org.vadere.util.geometry.mesh.inter.IVertex;
import org.vadere.util.geometry.shapes.IPoint;
import java.util.Collection;
import java.util.Collections;
import java.util.Optional;
/**
......@@ -16,47 +14,53 @@ import java.util.Optional;
*
* The BasePointLocatetor only uses the mesh itself and does not use any additional data structure
* to find the face for a given point. It runs a march starting from some (not known) face of the
* mesh and end up at the face that contains the point. In worst case this is not faster than
* mesh and end up at the face that triangleContains the point. In worst case this is not faster than
* checking each each face of the mesh but it is more clever and faste in the most cases.
*
*
* @param <P>
* @param <V>
* @param <E>
* @param <F>
*/
public class BasePointLocator<P extends IPoint, E extends IHalfEdge<P>, F extends IFace<P>> implements IPointLocator<P, E, F> {
public class BasePointLocator<P extends IPoint, V extends IVertex<P>, E extends IHalfEdge<P>, F extends IFace<P>> implements IPointLocator<P, V, E, F> {
private ITriConnectivity<P, E, F> triConnectivity;
private ITriConnectivity<P, V, E, F> triConnectivity;
public BasePointLocator(final ITriConnectivity<P, E, F> triConnectivity) {
public BasePointLocator(final ITriConnectivity<P, V, E, F> triConnectivity) {
this.triConnectivity = triConnectivity;
}
@Override
public void splitFaceEvent(final F original, final F[] faces) {}
public void splitTriangleEvent(F original, F f1, F f2, F f3) {}
@Override
public void splitEdgeEvent(F original, F f1, F f2) {}
@Override
public void flipEdgeEvent(final F f1, final F f2) {}
@Override
public void insertEvent(E vertex) {}
public void insertEvent(V vertex) {}
@Override
public void deleteBoundaryFace(final F face) {}
@Override
public Collection<F> locatePoint(final IPoint point, boolean insertion) {
if(insertion) {
return triConnectivity.getAdjacentFaces(point.getX(), point.getY());
public F locatePoint(final P point, boolean insertion) {
//return triConnectivity.getMesh().getFace(triConnectivity.locateNearestNeighbour(point));
return triConnectivity.locateFace(point.getX(), point.getY()).get();
/*if(insertion) {
return triConnectivity.getClosestEdge(point.getX(), point.getY());
}
else {
Optional<F> optFace = triConnectivity.locate(point.getX(), point.getY());
Optional<F> optFace = triConnectivity.locateFace(point.getX(), point.getY());
return optFace.isPresent() ? Collections.singleton(optFace.get()) : Collections.emptyList();
}
}*/
}
@Override
public Optional<F> locate(final IPoint point) {
return triConnectivity.locate(point.getX(), point.getY());
return triConnectivity.locateFace(point.getX(), point.getY());
}
}
......@@ -7,6 +7,7 @@ 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 java.util.Collection;
......@@ -18,13 +19,13 @@ import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
public class DelaunayTree<P extends IPoint, E extends IHalfEdge<P>, F extends IFace<P>> implements IPointLocator<P, E, F> {
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;
private final HashMap<F, DAG<DAGElement<P, F>>> map;
private final IMesh<P, E, F> mesh;
private final IMesh<P, V, E, F> mesh;
private double eps = 0.0000001;
public DelaunayTree(final ITriangulation<P, E, F> triangulation) {
public DelaunayTree(final ITriangulation<P, V, E, F> triangulation) {
this.mesh = triangulation.getMesh();
this.map = new HashMap<>();
}
......@@ -42,9 +43,9 @@ public class DelaunayTree<P extends IPoint, E extends IHalfEdge<P>, F extends IF
}
@Override
public Collection<F> locatePoint(final P point, final boolean insertion) {
public F locatePoint(final P point, final boolean insertion) {
checkRoot();
Set<DAG<DAGElement<P, F>>> leafs = new HashSet<>();
LinkedList<DAG<DAGElement<P, F>>> nodesToVisit = new LinkedList<>();
nodesToVisit.add(dag);
......@@ -56,9 +57,7 @@ public class DelaunayTree<P extends IPoint, E extends IHalfEdge<P>, F extends IF
leafs.add(currentNode);
// if we are not interested in insertion we just want to find one triangle.
if(!insertion) {
return leafs.stream().map(dag -> dag.getElement().getFace()).collect(Collectors.toList());
}
return currentNode.getElement().getFace();
}
else {
nodesToVisit.addAll(currentNode.getChildren());
......@@ -66,31 +65,55 @@ public class DelaunayTree<P extends IPoint, E extends IHalfEdge<P>, F extends IF
}
}
return leafs.stream().map(dag -> dag.getElement().getFace()).collect(Collectors.toList());
throw new IllegalArgumentException(point + " is invalid, it can not be located by " + this);
}
@Override
public Optional<F> locate(final P point) {
checkRoot();
Optional<F> optFace = locatePoint(point, false).stream().findAny();
if(optFace.isPresent()) {
return Optional.of(optFace.get());
}
else {
return Optional.empty();
}
return Optional.of(locatePoint(point, false));
}
@Override
public void splitFaceEvent(F original, F[] faces) {
public void splitTriangleEvent(F original, F f1, F f2, F f3) {
checkRoot();
DAG<DAGElement<P, F>> faceDag = map.remove(original);
for(F face : faces) {
List<P> points = mesh.getVertices(face);
DAG<DAGElement<P, F>> newFaceDag = new DAG<>(new DAGElement(face, Triple.of(points.get(0), points.get(1), points.get(2))));
faceDag.addChild(newFaceDag);
map.put(face, newFaceDag);
}
F face = f1;
List<V> points1 = mesh.getVertices(face);
DAG<DAGElement<P, F>> newFaceDag1 = new DAG<>(new DAGElement(face, Triple.of(points1.get(0), points1.get(1), points1.get(2))));
faceDag.addChild(newFaceDag1);
map.put(face, newFaceDag1);
face = f2;
List<V> points2 = mesh.getVertices(face);
DAG<DAGElement<P, F>> newFaceDag2 = new DAG<>(new DAGElement(face, Triple.of(points2.get(0), points2.get(1), points2.get(2))));
faceDag.addChild(newFaceDag2);
map.put(face, newFaceDag2);
face = f3;
List<V> points3 = mesh.getVertices(face);
DAG<DAGElement<P, F>> newFaceDag3 = new DAG<>(new DAGElement(face, Triple.of(points3.get(0), points3.get(1), points3.get(2))));
faceDag.addChild(newFaceDag3);
map.put(face, newFaceDag3);
}
@Override
public void splitEdgeEvent(F original, F f1, F f2) {
checkRoot();
DAG<DAGElement<P, F>> faceDag = map.remove(original);
F face = f1;
List<V> points1 = mesh.getVertices(face);
DAG<DAGElement<P, F>> newFaceDag1 = new DAG<>(new DAGElement(face, Triple.of(points1.get(0), points1.get(1), points1.get(2))));
faceDag.addChild(newFaceDag1);
map.put(face, newFaceDag1);
face = f2;
List<V> points2 = mesh.getVertices(face);
DAG<DAGElement<P, F>> newFaceDag2 = new DAG<>(new DAGElement(face, Triple.of(points2.get(0), points2.get(1), points2.get(2))));
faceDag.addChild(newFaceDag2);
map.put(face, newFaceDag2);
}
@Override
......@@ -98,8 +121,8 @@ public class DelaunayTree<P extends IPoint, E extends IHalfEdge<P>, F extends IF
checkRoot();
DAG<DAGElement<P, F>> f1Dag = map.remove(f1);
DAG<DAGElement<P, F>> f2Dag = map.remove(f2);
List<P> points1 = mesh.getVertices(f1);
List<P> points2 = mesh.getVertices(f2);
List<V> points1 = mesh.getVertices(f1);
List<V> points2 = mesh.getVertices(f2);