Commit 70a64a34 authored by Benedikt Zoennchen's avatar Benedikt Zoennchen
Browse files

add basic point location algorithm - not jet finished

parent b8c109fb
......@@ -6,7 +6,10 @@ import org.vadere.util.geometry.shapes.IPoint;
import org.vadere.util.triangulation.IPointConstructor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
......@@ -18,11 +21,14 @@ public class PMesh<P extends IPoint> implements IMesh<P, PHalfEdge<P>, PFace<P>>
private PFace<P> boundary;
private List<PHalfEdge<P>> edges;
private IPointConstructor<P> pointConstructor;
private Set<P> vertices;
public PMesh(final IPointConstructor<P> pointConstructor) {
this.faces = new ArrayList<>();
this.edges = new ArrayList<>();
this.vertices = new HashSet<>();
this.boundary = new PFace<>(true);
//this.faces.add(boundary);
this.pointConstructor = pointConstructor;
}
......@@ -76,6 +82,16 @@ public class PMesh<P extends IPoint> implements IMesh<P, PHalfEdge<P>, PFace<P>>
return halfEdge.isBoundary();
}
@Override
public boolean isHole(@NotNull PFace<P> face) {
return false;
}
@Override
public boolean isHole(@NotNull PHalfEdge<P> halfEdge) {
return false;
}
@Override
public boolean isDestroyed(@NotNull PFace<P> face) {
return face.isDestroyed();
......@@ -126,6 +142,16 @@ public class PMesh<P extends IPoint> implements IMesh<P, PHalfEdge<P>, PFace<P>>
return edges.stream().filter(edge -> !edge.isValid()).filter(edge -> getVertex(edge).equals(vertex)).collect(Collectors.toList());
}
@Override
public Collection<P> getVertices() {
return vertices;
}
@Override
public int getNumberOfVertices() {
return vertices.size();
}
@Override
public PHalfEdge<P> createEdge(@NotNull P vertex) {
PHalfEdge<P> edge = new PHalfEdge<>(vertex);
......@@ -159,19 +185,38 @@ public class PMesh<P extends IPoint> implements IMesh<P, PHalfEdge<P>, PFace<P>>
@Override
public P createVertex(double x, double y) {
return pointConstructor.create(x, y);
P vertex = pointConstructor.create(x, y);
//vertices.add(vertex);
return vertex;
}
@Override
public void insert(P vertex) {
vertices.add(vertex);
}
@Override
public void insertVertex(P vertex) {
vertices.add(vertex);
}
@Override
public void destroyFace(@NotNull PFace<P> face) {
faces.remove(face);
face.destroy();
}
@Override
public void destroyEdge(@NotNull PHalfEdge<P> edge) {
edges.remove(edge);
edge.destroy();
}
@Override
public void destroyVertex(@NotNull P vertex) {
vertices.remove(vertex);
}
@Override
public List<PFace<P>> getFaces() {
return faces.stream().filter(face -> !face.isDestroyed()).collect(Collectors.toList());
......
......@@ -4,6 +4,6 @@ import org.vadere.util.geometry.shapes.IPoint;
/**
* @author Benedikt Zoennchen
* @param <P>
* @param <P> the type of the vertices
*/
public interface IFace<P extends IPoint> {}
......@@ -2,4 +2,8 @@ package org.vadere.util.geometry.mesh.inter;
import org.vadere.util.geometry.shapes.IPoint;
/**
* @author Benedikt Zoennchen
* @param <P> the type of the vertices
*/
public interface IHalfEdge<P extends IPoint> {}
package org.vadere.util.geometry.mesh.inter;
import org.vadere.util.geometry.shapes.IPoint;
/**
* @author Benedikt Zoennchen
*/
public interface IHierarchyPoint extends IPoint {
void setDown(IHierarchyPoint down);
void setUp(IHierarchyPoint up);
}
package org.vadere.util.geometry.mesh.inter;
import org.apache.commons.collections.IteratorUtils;
import org.apache.commons.lang3.tuple.Triple;
import org.jetbrains.annotations.NotNull;
import org.vadere.util.geometry.mesh.impl.PFace;
import org.vadere.util.geometry.mesh.impl.PHalfEdge;
import org.vadere.util.geometry.mesh.impl.PMesh;
import org.vadere.util.geometry.mesh.iterators.EdgeIterator;
import org.vadere.util.geometry.mesh.iterators.AdjacentFaceIterator;
import org.vadere.util.geometry.mesh.iterators.IncidentEdgeIterator;
......@@ -10,9 +14,11 @@ import org.vadere.util.geometry.shapes.IPoint;
import org.vadere.util.geometry.shapes.VPoint;
import org.vadere.util.geometry.shapes.VPolygon;
import org.vadere.util.geometry.shapes.VTriangle;
import org.vadere.util.triangulation.IPointConstructor;
import java.awt.geom.Path2D;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
......@@ -48,8 +54,18 @@ public interface IMesh<P extends IPoint, E extends IHalfEdge<P>, F extends IFace
}
F getFace();
/**
* Returns true if the face is the boundar
*
* @param face
* @return
*/
boolean isBoundary(@NotNull F face);
boolean isBoundary(@NotNull E halfEdge);
boolean isHole(@NotNull F face);
boolean isHole(@NotNull E halfEdge);
boolean isDestroyed(@NotNull F face);
boolean isDestroyed(@NotNull E edge);
......@@ -67,6 +83,15 @@ public interface IMesh<P extends IPoint, E extends IHalfEdge<P>, F extends IFace
F createFace();
F createFace(boolean boundary);
P createVertex(double x, double y);
void insert(P vertex);
void insertVertex(P vertex);
default P insertVertex(double x, double y) {
P vertex = createVertex(x, y);
insertVertex(vertex);
return vertex;
}
// TODO: name?
default F createFace(P... points) {
......@@ -114,6 +139,7 @@ public interface IMesh<P extends IPoint, E extends IHalfEdge<P>, F extends IFace
void destroyFace(@NotNull F face);
void destroyEdge(@NotNull E edge);
void destroyVertex(@NotNull P vertex);
List<F> getFaces();
......@@ -140,6 +166,12 @@ public interface IMesh<P extends IPoint, E extends IHalfEdge<P>, F extends IFace
return new VTriangle(new VPoint(vertices.get(0)), new VPoint(vertices.get(1)), new VPoint(vertices.get(2)));
}
default Triple<P, P, P> toTriple(F face) {
List<P> vertices = getVertices(face);
assert vertices.size() == 3;
return Triple.of(vertices.get(0), vertices.get(1), vertices.get(2));
}
default Optional<F> locate(final double x, final double y) {
for(F face : getFaces()) {
VPolygon polygon = toPolygon(face);
......@@ -245,7 +277,7 @@ public interface IMesh<P extends IPoint, E extends IHalfEdge<P>, F extends IFace
* @return a List of all faces which are adjacent to the vertex of the edge
*/
default List<F> getAdjacentFaces(@NotNull E edge) {
return IteratorUtils.toList(new IncidentEdgeIterator(this, edge));
return IteratorUtils.toList(new AdjacentFaceIterator(this, edge));
}
/**
......@@ -301,4 +333,28 @@ public interface IMesh<P extends IPoint, E extends IHalfEdge<P>, F extends IFace
return vertices;
}
/**
* Tests whether the point (x,y) is a vertex of the face.
*
* @param face
* @param x
* @param y
* @return
*/
default boolean isMember(F face, double x, double y) {
return getMemberEdge(face, x, y).isPresent();
}
default Optional<E> getMemberEdge(F face, double x, double y) {
return streamEdges(face).filter(e -> getVertex(e).getX() == x && getVertex(e).getY() == y).findAny();
}
Collection<P> getVertices();
int getNumberOfVertices();
static <P extends IPoint> IMesh<P, PHalfEdge<P>, PFace<P>> createPMesh(final IPointConstructor<P> pointConstructor) {
return new PMesh<>(pointConstructor);
}
}
package org.vadere.util.geometry.mesh.inter;
import org.vadere.util.geometry.mesh.triangulations.BasePointLocator;
import org.vadere.util.geometry.mesh.triangulations.DelaunayHierarchy;
import org.vadere.util.geometry.mesh.triangulations.DelaunayTree;
import org.vadere.util.geometry.shapes.IPoint;
import java.util.Collection;
import java.util.Optional;
/**
* @author Benedikt Zoennchen
*
* @param <P>
* @param <E>
* @param <F>
*/
public interface IPointLocator<P extends IPoint, E extends IHalfEdge<P>, F extends IFace<P>> extends ITriEventListener<P, E, F> {
Collection<F> locatePoint(final IPoint point, final boolean insertion);
Optional<F> locate(final IPoint point);
static <P extends IPoint, E extends IHalfEdge<P>, F extends IFace<P>> BasePointLocator<P, E, F> createBaseLocator(final ITriangulation<P, E, F> triangulation) {
return new BasePointLocator<>(triangulation);
}
static <P extends IPoint, E extends IHalfEdge<P>, F extends IFace<P>> DelaunayHierarchy<P, E, F> createDelaunayHierarchy(final ITriangulation<P, E, F> triangulation) {
return new DelaunayHierarchy<>(triangulation);
}
static <P extends IPoint, E extends IHalfEdge<P>, F extends IFace<P>> DelaunayTree<P, E, F> createDelaunayTree(final ITriangulation<P, E, F> triangulation, final F superTriangle) {
return new DelaunayTree<>(triangulation, superTriangle);
}
}
package org.vadere.util.geometry.mesh;
package org.vadere.util.geometry.mesh.inter;
import org.jetbrains.annotations.NotNull;
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.shapes.IPoint;
import org.vadere.util.geometry.shapes.VPoint;
import org.vadere.util.geometry.shapes.VPolygon;
......@@ -21,7 +18,7 @@ public interface IPolyConnectivity<P extends IPoint, E extends IHalfEdge<P>, F e
IMesh<P, E, F> getMesh();
default boolean isBoundary(E halfEdge) {
default boolean isAtBoundary(E halfEdge) {
IMesh<P, E, F> mesh = getMesh();
return mesh.isBoundary(halfEdge) || mesh.isBoundary(mesh.getTwin(halfEdge));
}
......@@ -40,13 +37,13 @@ public interface IPolyConnectivity<P extends IPoint, E extends IHalfEdge<P>, F e
return locate(point.getX(), point.getY());
}
default boolean isBoundary(F face) {
return getMesh().getEdges(face).stream().anyMatch(edge -> isBoundary(edge));
default boolean isAtBoundary(F face) {
return getMesh().getEdges(face).stream().anyMatch(edge -> isAtBoundary(edge));
}
default void adjustVertex(P vertex){
List<E> edges = getMesh().getEdges(vertex);
edges.stream().filter(edge -> isBoundary(edge)).findAny().ifPresent(edge -> getMesh().setEdge(vertex, edge));
edges.stream().filter(edge -> isAtBoundary(edge)).findAny().ifPresent(edge -> getMesh().setEdge(vertex, edge));
}
default Optional<E> findEdge(P begin, P end) {
......
package org.vadere.util.geometry.mesh;
package org.vadere.util.geometry.mesh.inter;
import org.jetbrains.annotations.NotNull;
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.GeometryUtils;
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.VTriangle;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
/**
* @author Benedikt Zoennchen
......@@ -22,6 +26,8 @@ public interface ITriConnectivity<P extends IPoint, E extends IHalfEdge<P>, F ex
default void flipEdgeEvent(F f1, F f2) {}
default void insertEvent(P vertex) {};
boolean isIllegal(E edge);
/**
......@@ -32,6 +38,7 @@ public interface ITriConnectivity<P extends IPoint, E extends IHalfEdge<P>, F ex
*/
default List<E> splitEdge(@NotNull P p, @NotNull E halfEdge, boolean legalize) {
IMesh<P, E, F> mesh = getMesh();
mesh.insertVertex(p);
List<E> newEdges = new ArrayList<>(4);
/*
* Situation: h0 = halfEdge
......@@ -224,6 +231,10 @@ public interface ITriConnectivity<P extends IPoint, E extends IHalfEdge<P>, F ex
return edges.size() == 3;
}
default boolean insert(@NotNull F face, @NotNull P p) {
throw new UnsupportedOperationException("not jet implemented.");
}
/**
* Splits the triangle xyz into three new triangles xyp, yzp and zxp.
*
......@@ -234,6 +245,7 @@ public interface ITriConnectivity<P extends IPoint, E extends IHalfEdge<P>, F ex
*/
default List<F> splitTriangle(@NotNull F face, P p, boolean legalize) {
assert isTriangle(face);
getMesh().insertVertex(p);
List<F> faceList = new ArrayList<>(3);
IMesh<P, E, F> mesh = getMesh();
List<E> edges = mesh.getEdges(face);
......@@ -323,13 +335,19 @@ public interface ITriConnectivity<P extends IPoint, E extends IHalfEdge<P>, F ex
P vertex = getMesh().getVertex(edge);
if(vertex.equals(p)) {
legalize(getMesh().getPrev(edge));
legalize(getMesh().getNext(getMesh().getTwin(edge)));
E e1 = getMesh().getPrev(edge);
E e2 = getMesh().getPrev(getMesh().getTwin(edge));
legalize(e1);
legalize(getMesh().getPrev(e2));
}
else {
legalize(getMesh().getNext(edge));
legalize(getMesh().getPrev(getMesh().getTwin(edge)));
E e1 = getMesh().getNext(edge);
E e2 = getMesh().getNext(getMesh().getTwin(edge));
legalize(e1);
legalize(getMesh().getNext(e2));
}
}
}
......@@ -361,4 +379,186 @@ public interface ITriConnectivity<P extends IPoint, E extends IHalfEdge<P>, F ex
}
return true;
}
@Override
default Optional<F> locate(final IPoint point) {
return this.locate(point.getX(), point.getY());
}
@Override
default Optional<F> locate(final double x, final double y) {
return locate(x, y, getMesh().getFace());
}
/*default Optional<P> locateVertex(double x, double y, F startFace) {
Optional<F> optFace = locate(x, y, startFace);
if(optFace.isPresent()) {
F face = optFace.get();
assert !getMesh().isBoundary(face);
}
return Optional.empty();
}*/
default Optional<F> locate(double x, double y, F startFace) {
// there is no face.
if(getDimension() <= 0 ){
return Optional.empty();
}
if(getDimension() == 1) {
return marchLocate1D(x, y, startFace);
}
else {
VTriangle triangle = getMesh().toTriangle(startFace);
VPoint incenter = triangle.getIncenter();
return Optional.of(marchLocate2D(incenter.getX(), incenter.getY(), x, y, startFace));
}
}
default Optional<F> marchLocate1D(double x, double y, F startFace) {
if(contains(startFace, x, y)) {
return Optional.of(startFace);
}
else {
return Optional.empty();
}
}
/**
* Marching to the face which contains the point defined by (x2, y2). The march
* starts at (x1, y2) at inside the startFace.
*
* @param x1 the x-coordinate of the starting point
* @param y1 the y-coordinate of the starting point
* @param x2 the x-coordinate of the ending point
* @param y2 the y-coordinate of the ending point
* @param startFace the face where the march start containing (x1,y1).
* @return
*/
default F marchLocate2D(double x1, double y1, double x2, double y2, F startFace) {
assert !getMesh().isBoundary(startFace);
assert contains(startFace, x1, y1);
E entryEdge = null;
F face = startFace;
boolean found = true;
while(found && !contains(face, x2, y2)) {
found = false;
for(E halfEdge : getMesh().getEdgeIt(face)) {
if(!halfEdge.equals(entryEdge)) {
P sVertex = getMesh().getVertex(getMesh().getPrev(halfEdge));
P eVertex = getMesh().getVertex(halfEdge);
if(VLine.linesIntersect(sVertex.getX(), sVertex.getY(), eVertex.getX(), eVertex.getY(), x1, y1, x2, y2)) {
entryEdge = getMesh().getTwin(halfEdge);
face = getMesh().getTwinFace(halfEdge);
found = true;
break;
}
}
}
}
assert found || getMesh().isBoundary(face);
return face;
}
default boolean contains(F face, double x, double y) {
if(getMesh().isMember(face, x, y)) {
return true;
}
// in this case the face might be a polygon
if(getMesh().isBoundary(face)) {
return getMesh().toPolygon(face).contains(x, y);
}
else {
return getMesh().toTriangle(face).contains(x, y);
}
}
//Optional<F> marchLocate2DLFC(double x, double y, F startFace);
default P getMaxDistanceVertex(F face, double x, double y) {
List<P> vertices = getMesh().getVertices(face);
assert vertices.size() == 3;
P result = vertices.get(0);
result = result.distance(x, y) < vertices.get(1).distance(x, y) ? vertices.get(1) : result;
result = result.distance(x, y) < vertices.get(2).distance(x, y) ? vertices.get(2) : result;
return result;
}
default P getMinDistanceVertex(F face, double x, double y) {
List<P> vertices = getMesh().getVertices(face);
assert vertices.size() == 3;
P result = vertices.get(0);
result = result.distance(x, y) > vertices.get(1).distance(x, y) ? vertices.get(1) : result;
result = result.distance(x, y) > vertices.get(2).distance(x, y) ? vertices.get(2) : result;
return result;
}
default int getDimension() {
return getMesh().getNumberOfVertices() - 2;
}
/**
* Returns a Collection of faces which contain the point (x,y). In case of the point lying on the
* boundary of the face, the face contains the point. If the point lies on a vertex of the face,
* the face contains the point as well.
*
* @param x the x-coordinate of the point
* @param y the y-coordinate of the point
* @return a Collection of faces which contain the point.
*/
default Collection<F> getAdjacentFaces(final double x, final double y) {
Optional<F> optFace = locate(x, y);
if(optFace.isPresent()) {
F face = optFace.get();
/*
* the point (x,y) may
* 1. lies on a vertex of the face,
* 2. lies on a edge of the face,
* 3. lies on the interior of the face
*/
Optional<E> optMemberEdge = getMesh().getMemberEdge(face, x, y);
if(optMemberEdge.isPresent()) {
return getMesh().getAdjacentFaces(optMemberEdge.get());
}
else {
List<F> faces = new ArrayList<>(2);
faces.add(face);
for(E halfEdge : getMesh().getEdgeIt(face)) {
P v1 = getMesh().getVertex(halfEdge);
P v2 = getMesh().getVertex(getMesh().getPrev(halfEdge));
// TODO: think about the epsilon, absolute value seems to be a really bad idea!
if(!getMesh().isBoundary(getMesh().getTwinFace(halfEdge)) && Math.abs(GeometryUtils.sign(x, y, v1.getX(), v1.getY(), v2.getX(), v2.getY())) == 0.0) {
faces.add(getMesh().getTwinFace(halfEdge));
break;
}
}
return faces;
}
}
else {
return Collections.emptyList();
}
}
}