In January 2021 we will introduce a 10 GB quota for project repositories. Higher limits for individual projects will be available on request. Please see https://doku.lrz.de/display/PUBLIC/GitLab for more information.

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();
}
}
......@@ -14,16 +14,30 @@ import java.util.Set;
/**
* @author Benedikt Zoennchen
*/
public interface IPolyConnectivity<P extends IPoint, E extends IHalfEdge<P>, F extends IFace<P>> extends Iterable<F>{
public interface IPolyConnectivity<P extends IPoint, V extends IVertex<P>, E extends IHalfEdge<P>, F extends IFace<P>> extends Iterable<F>{
IMesh<P, E, F> getMesh();
/**
* Returns the mesh of this IPolyConnectivity.
* Non mesh changing method.
*
* @return the mesh of this IPolyConnectivity
*/
IMesh<P, V, E, F> getMesh();
default boolean isAtBoundary(E halfEdge) {
IMesh<P, E, F> mesh = getMesh();
default boolean isAtBoundary(@NotNull final E halfEdge) {
IMesh<P, V, E, F> mesh = getMesh();
return mesh.isBoundary(halfEdge) || mesh.isBoundary(mesh.getTwin(halfEdge));
}
default Optional<F> locate(final double x, final double y) {
/**
* Searches and returns the face containing the point (x,y).
* Non mesh changing method.
*
* @param x x-coordinate of the location point
* @param y y-coordinate of the location point
* @return the face containing the point or empty() if there is none
*/
default Optional<F> locateFace(final double x, final double y) {
for(F face : getMesh().getFaces()) {
VPolygon polygon = getMesh().toPolygon(face);
if(polygon.contains(new VPoint(x, y))) {
......@@ -33,25 +47,65 @@ public interface IPolyConnectivity<P extends IPoint, E extends IHalfEdge<P>, F e
return Optional.empty();
}
default Optional<F> locate(final P point) {
return locate(point.getX(), point.getY());
/**
* Searches and returns the face containing the point (x,y).
* Non mesh changing method.
*
* @param point the location point
* @return the face containing the point or empty() if there is none
*/
default Optional<F> locateFace(@NotNull final P point) {
return locateFace(point.getX(), point.getY());
}
default boolean isAtBoundary(F face) {
/**
* Tests if the face share any boundary edge.
* Non mesh changing method.
*
* @param face the face
* @return true if the face share any boundary edge, otherwise false
*/
default boolean isAtBoundary(@NotNull final F face) {
return getMesh().getEdges(face).stream().anyMatch(edge -> isAtBoundary(edge));
}
default void adjustVertex(P vertex){
/**
* If there is an half-edge e which is at the boundary and has the vertex v
* as its end point, this method will set the half-edge of v to e.
* Non mesh changing method.
*
* @param vertex v
*/
default void adjustVertex(@NotNull final V vertex) {
List<E> edges = getMesh().getEdges(vertex);
edges.stream().filter(edge -> isAtBoundary(edge)).findAny().ifPresent(edge -> getMesh().setEdge(vertex, edge));
}
default Optional<E> findEdge(P begin, P end) {
IMesh<P, E, F> mesh = getMesh();
return mesh.getIncidentEdges(mesh.getEdge(begin)).stream().filter(edge -> mesh.getPrev(edge).equals(end)).map(edge -> mesh.getTwin(edge)).findAny();
/**
* Returns a half-edge (begin, end) where end is its end point
* and begin is the end point of its predecessor.
* Non mesh changing method.
*
* @param begin the end point of the predecessor of the searched half-edge
* @param end the end point of the searched half-edge
* @return a half-edge (begin, end) if there is any, otherwise empty()
*/
default Optional<E> findEdge(@NotNull final V begin, @NotNull final V end) {
IMesh<P, V, E, F> mesh = getMesh();
return mesh.getIncidentEdges(mesh.getEdge(begin)).stream()
.filter(edge -> mesh.getPrev(edge).equals(end))
.map(edge -> mesh.getTwin(edge)).findAny();
}
default boolean isSimpleLink(E halfEdge) {
/**
* Tests if the half-edge is the only link (of the face of the half-edge)
* between the face of the half-edge and the face of its twin.
* Non mesh changing method.
*
* @param halfEdge a half-edge to test
* @return true if the half-edge is a simple link, false otherwise
*/
default boolean isSimpleLink(@NotNull final E halfEdge) {
E edge = halfEdge;
E twin = getMesh().getTwin(halfEdge);
F twinFace = getMesh().getFace(twin);
......@@ -67,7 +121,15 @@ public interface IPolyConnectivity<P extends IPoint, E extends IHalfEdge<P>, F e
return true;
}
default boolean isSimpleConnected(F face) {
/**
* Tests if there is any face which shares more than one edge with the face
* we are checking.
* Non mesh changing method.
*
* @param face the face we are checking
* @return true if there is no face which shares more than one edge with this face, false otherwise
*/
default boolean isSimpleConnected(@NotNull final F face) {
Set<F> faceSet = new HashSet<>();
E edge = getMesh().getEdge(face);
E next = getMesh().getNext(edge);
......@@ -85,7 +147,33 @@ public interface IPolyConnectivity<P extends IPoint, E extends IHalfEdge<P>, F e
return true;
}
default void split(F face, P vertex) {
/**
* Splitting the face i.e. a polygon into as many faces as the face has edges.
* Assumption: the vertex is valid i.e. it is contained any face.
* Mesh changing method.
*
* @param vertex the vertex which spilts the face which triangleContains the vertex. It has to be contained any face.
*/
default void split(@NotNull final V vertex) {
Optional<F> optFace = locateFace(getMesh().getPoint(vertex));
if(!optFace.isPresent()) {
throw new IllegalArgumentException(vertex + " is not contained in any face. Therefore, no face found to split into faces.");
} else {
split(optFace.get(), vertex);
}
}
/**
* Splitting the face i.e. a polygon into as many faces as the face has edges.
* Assumption: the vertex is valid i.e. it is contained in the face.
* Mesh changing method.
*
* @param face the face to be split into n faces, where n is the number of edges of the face
* @param vertex the vertex which spilts the face. It has to be contained in the face
*/
default void split(@NotNull final F face, @NotNull final V vertex) {
assert locateFace(getMesh().getPoint(vertex)).get().equals(face);
E hend = getMesh().getEdge(face);
E hh = getMesh().getNext(hend);
E hold = getMesh().createEdge(vertex);
......@@ -100,7 +188,10 @@ public interface IPolyConnectivity<P extends IPoint, E extends IHalfEdge<P>, F e
E hnext = getMesh().getNext(hh);
F newFace = getMesh().createFace();
getMesh().setEdge(newFace, hh);
// update the edge of the vertex such that the last new created edge will be its edge
E hnew = getMesh().createEdge(vertex);
getMesh().setEdge(vertex, hnew);
getMesh().setNext(hnew, hold);
getMesh().setNext(hold, hh);
......@@ -123,13 +214,16 @@ public interface IPolyConnectivity<P extends IPoint, E extends IHalfEdge<P>, F e
}
/**
* Removes a simple link.
* Removes a simple link. This will be done by merging two faces into one remaining face.
* Assumption: the edge is a simple link
* Mesh changing method.
*
* @param edge
* @return
* @param edge the simple link
* @return the remaining face
*/
default F removeEdge(E edge) {
default F removeEdge(@NotNull final E edge) {
assert isSimpleLink(edge) && !getMesh().isDestroyed(edge);
E twin = getMesh().getTwin(edge);
F delFace = getMesh().getFace(edge);
F remFace = getMesh().getFace(twin);
......@@ -151,10 +245,12 @@ public interface IPolyConnectivity<P extends IPoint, E extends IHalfEdge<P>, F e
getMesh().setNext(prevEdge, nextTwin);
getMesh().setNext(prevTwin, nextEdge);
/* adjust vertices, mb later
P eVertex = getMesh().getVertex(edge);
P tVertex = getMesh().getVertex(twin);
*/
// adjust vertices, mb later
V eVertex = getMesh().getVertex(edge);
V tVertex = getMesh().getVertex(twin);
getMesh().setEdge(eVertex, prevTwin);
getMesh().setEdge(tVertex, prevEdge);
if(getMesh().getEdge(remFace).equals(edge)) {
getMesh().setEdge(remFace, prevTwin);
......@@ -174,13 +270,21 @@ public interface IPolyConnectivity<P extends IPoint, E extends IHalfEdge<P>, F e
return remFace;
}
default void removeFace(@NotNull F face, boolean deleteIsolatedVertices) {
/**
* Removes a face from the mesh by removing all boundary edges of the face.
* If there are no boundary edges the face will be converted to be a part of the boundary
* itself i.e. a hole.
* Mesh changing method.
*
* @param face the face that will be removed from the mesh
* @param deleteIsolatedVertices true means that all vertices with degree <= 1 will be removed as well
*/
default void removeFace(@NotNull final F face, final boolean deleteIsolatedVertices) {
assert !getMesh().isDestroyed(face);
getMesh().destroyFace(face);
List<E> delEdges = new ArrayList<>();
List<P> vertices = new ArrayList<>();
List<V> vertices = new ArrayList<>();
F boundary = getMesh().createFace(true);
......@@ -195,7 +299,7 @@ public interface IPolyConnectivity<P extends IPoint, E extends IHalfEdge<P>, F e
if(!delEdges.isEmpty()) {
E h0, h1, next0, next1, prev0, prev1;
P v0, v1;
V v0, v1;
for(E delEdge : delEdges) {
h0 = delEdge;
......@@ -208,18 +312,37 @@ public interface IPolyConnectivity<P extends IPoint, E extends IHalfEdge<P>, F e
next1 = getMesh().getNext(h1);
prev1 = getMesh().getPrev(h1);
// adjust next and prev handles
// adjust next and prev half-edges
getMesh().setNext(prev0, next1);
getMesh().setNext(prev1, next0);
// TODO: test the isolated part!
boolean isolated0 = getMesh().getNext(prev1).equals(getMesh().getTwin(prev1));
boolean isolated1 = getMesh().getNext(prev0).equals(getMesh().getTwin(prev0));
// adjust vertices
if(getMesh().getEdge(v0).equals(h0) && !isolated0) {
getMesh().setEdge(v0, prev1);
}
if(deleteIsolatedVertices && isolated0) {
getMesh().destroyVertex(v0);
}
if(getMesh().getEdge(v1).equals(h1) && !isolated1) {
getMesh().setEdge(v1, prev0);
}
if(deleteIsolatedVertices && isolated1) {
getMesh().destroyVertex(v1);
}
// mark edge deleted if the mesh has a edge status
getMesh().destroyEdge(h0);
getMesh().destroyEdge(h1);
// TODO: delete isolated vertices?
for(P vertex : vertices) {
// TODO: do we need this?
for(V vertex : vertices) {
adjustVertex(vertex);
}
}
......
package org.vadere.util.geometry.mesh.inter;
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.shapes.IPoint;
......@@ -7,11 +9,9 @@ import org.vadere.util.geometry.shapes.VLine;
import org.vadere.util.geometry.shapes.VPoint;
import org.vadere.util.geometry.shapes.VTriangle;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Random;
/**
* @author Benedikt Zoennchen
......@@ -20,26 +20,60 @@ import java.util.Optional;
* @param <E>
* @param <F>
*/
public interface ITriConnectivity<P extends IPoint, E extends IHalfEdge<P>, F extends IFace<P>> extends IPolyConnectivity<P, E, F> {
public interface ITriConnectivity<P extends IPoint, V extends IVertex<P>, E extends IHalfEdge<P>, F extends IFace<P>> extends IPolyConnectivity<P, V, E, F> {
default void splitFaceEvent(F original, F... faces) {}
Logger log = LogManager.getLogger(ITriConnectivity.class);
Random random = new Random();
/**
* Non mesh changing method.
*
* @param original
* @param f1
* @param f2