diff --git a/VadereUtils/src/org/vadere/util/geometry/mesh/impl/PHalfEdge.java b/VadereUtils/src/org/vadere/util/geometry/mesh/impl/PHalfEdge.java
index 5fbb0128d1db3a47cc792852c7783be5cd3df54f..e7c44cad1d7d4041f475e45405002ddd686e3aff 100644
--- a/VadereUtils/src/org/vadere/util/geometry/mesh/impl/PHalfEdge.java
+++ b/VadereUtils/src/org/vadere/util/geometry/mesh/impl/PHalfEdge.java
@@ -11,7 +11,7 @@ public class PHalfEdge
implements IHalfEdge
{
/**
* point at the end of the half edge.
*/
- private P end;
+ private PVertex
end;
/**
* next half-edge around the face.
@@ -35,12 +35,12 @@ public class PHalfEdge
implements IHalfEdge
{
private PFace
face;
- PHalfEdge(@NotNull final P end, @NotNull final PFace
face) {
+ PHalfEdge(@NotNull final PVertex
end, @NotNull final PFace
face) {
this.end = end;
this.face = face;
}
- PHalfEdge(@NotNull final P end) {
+ PHalfEdge(@NotNull final PVertex
end) {
this.end = end;
this.face = null;
}
@@ -53,7 +53,7 @@ public class PHalfEdge
implements IHalfEdge
{
this.face = face;
}
- P getEnd() {
+ PVertex
getEnd() {
return end;
}
@@ -116,7 +116,7 @@ public class PHalfEdge
implements IHalfEdge
{
}
}
- void setEnd(P end) {
+ void setEnd(PVertex
end) {
this.end = end;
}
diff --git a/VadereUtils/src/org/vadere/util/geometry/mesh/impl/PMesh.java b/VadereUtils/src/org/vadere/util/geometry/mesh/impl/PMesh.java
index 386e47c88ee7f618c13b9b2ec21161efb52a3986..8c7d654034502808baea2bc346238d1cbe17610f 100644
--- a/VadereUtils/src/org/vadere/util/geometry/mesh/impl/PMesh.java
+++ b/VadereUtils/src/org/vadere/util/geometry/mesh/impl/PMesh.java
@@ -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
implements IMesh
, PFace
> {
+public class PMesh
implements IMesh
, PHalfEdge
, PFace
> {
private List> faces;
private PFace boundary;
private List> edges;
private IPointConstructor pointConstructor;
- private Set
vertices;
+ private Set> vertices;
public PMesh(final IPointConstructor pointConstructor) {
this.faces = new ArrayList<>();
@@ -48,13 +49,13 @@ public class PMesh
implements IMesh
, PFace
>
}
@Override
- public PFace
getFace(final PHalfEdge
halfEdge) {
+ public PFace
getFace(@NotNull final PHalfEdge
halfEdge) {
return halfEdge.getFace();
}
@Override
- public PHalfEdge
getEdge(@NotNull P vertex) {
- return null;
+ public PHalfEdge
getEdge(@NotNull PVertex
vertex) {
+ return vertex.getEdge();
}
@Override
@@ -63,10 +64,20 @@ public class PMesh
implements IMesh
, PFace
>
}
@Override
- public P getVertex(@NotNull PHalfEdge
halfEdge) {
+ public P getPoint(@NotNull PHalfEdge
halfEdge) {
+ return getVertex(halfEdge).getPoint();
+ }
+
+ @Override
+ public PVertex
getVertex(@NotNull PHalfEdge
halfEdge) {
return halfEdge.getEnd();
}
+ @Override
+ public P getPoint(@NotNull PVertex
vertex) {
+ return vertex.getPoint();
+ }
+
@Override
public PFace
getFace() {
return faces.stream().filter(face -> !face.isDestroyed()).findAny().get();
@@ -118,22 +129,22 @@ public class PMesh
implements IMesh
, PFace
>
}
@Override
- public void setEdge(@NotNull P vertex, @NotNull PHalfEdge
edge) {
- throw new UnsupportedOperationException("not jet implemented.");
+ public void setEdge(@NotNull PVertex
vertex, @NotNull PHalfEdge
edge) {
+ vertex.setEdge(edge);
}
@Override
- public void setVertex(@NotNull PHalfEdge
halfEdge, @NotNull P vertex) {
+ public void setVertex(@NotNull PHalfEdge
halfEdge, @NotNull PVertex
vertex) {
halfEdge.setEnd(vertex);
}
@Override
- public List> getEdges(@NotNull P vertex) {
+ public List> getEdges(@NotNull final PVertex vertex) {
return edges.stream().filter(edge -> !edge.isValid()).filter(edge -> getVertex(edge).equals(vertex)).collect(Collectors.toList());
}
@Override
- public Collection
getVertices() {
+ public Collection> getVertices() {
return vertices;
}
@@ -148,14 +159,14 @@ public class PMesh implements IMesh
, PFace
>
}
@Override
- public PHalfEdge
createEdge(@NotNull P vertex) {
+ public PHalfEdge
createEdge(@NotNull PVertex
vertex) {
PHalfEdge
edge = new PHalfEdge<>(vertex);
edges.add(edge);
return edge;
}
@Override
- public PHalfEdge
createEdge(@NotNull P vertex, @NotNull PFace
face) {
+ public PHalfEdge
createEdge(@NotNull PVertex
vertex, @NotNull PFace
face) {
PHalfEdge
edge = new PHalfEdge<>(vertex, face);
edges.add(edge);
return edge;
@@ -179,10 +190,20 @@ public class PMesh
implements IMesh
, PFace
>
}
@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
createVertex(double x, double y) {
+ return createVertex(pointConstructor.create(x, y));
+ }
+
+ @Override
+ public PVertex
createVertex(P point) {
+ return new PVertex<>(point);
}
@Override
@@ -191,12 +212,12 @@ public class PMesh
implements IMesh
, PFace
>
}
@Override
- public void insert(P vertex) {
+ public void insert(final PVertex
vertex) {
vertices.add(vertex);
}
@Override
- public void insertVertex(P vertex) {
+ public void insertVertex(final PVertex
vertex) {
vertices.add(vertex);
}
@@ -213,12 +234,32 @@ public class PMesh
implements IMesh
, PFace
>
}
@Override
- public void destroyVertex(@NotNull P vertex) {
+ public void setDown(@NotNull PVertex
up, @NotNull PVertex
down) {
+ up.setDown(down);
+ }
+
+ @Override
+ public PVertex
getDown(@NotNull PVertex
vertex) {
+ return vertex.getDown();
+ }
+
+ @Override
+ public void destroyVertex(@NotNull PVertex
vertex) {
vertices.remove(vertex);
}
+ @Override
+ public Stream> streamFaces() {
+ return faces.stream();
+ }
+
+ @Override
+ public Stream> streamEdges() {
+ return streamFaces().flatMap(face -> streamEdges(face));
+ }
+
@Override
public List> getFaces() {
- return faces.stream().filter(face -> !face.isDestroyed()).collect(Collectors.toList());
+ return streamFaces().filter(face -> !face.isDestroyed()).collect(Collectors.toList());
}
}
diff --git a/VadereUtils/src/org/vadere/util/geometry/mesh/impl/PVertex.java b/VadereUtils/src/org/vadere/util/geometry/mesh/impl/PVertex.java
new file mode 100644
index 0000000000000000000000000000000000000000..ccc2cdd2bf1545faf2fd67358b9b1ac93d29a9c3
--- /dev/null
+++ b/VadereUtils/src/org/vadere/util/geometry/mesh/impl/PVertex.java
@@ -0,0 +1,64 @@
+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
+ */
+public class PVertex
implements IVertex
{
+
+ private final P point;
+ private PVertex
down;
+ private PHalfEdge
halfEdge;
+
+ public PVertex(final P point) {
+ this.point = point;
+ this.down = null;
+ }
+
+ @Override
+ public P getPoint() {
+ return point;
+ }
+
+ public PHalfEdge
getEdge() {
+ return halfEdge;
+ }
+
+ public void setEdge(final PHalfEdge
halfEdge) {
+ this.halfEdge = halfEdge;
+ }
+
+ public PVertex
getDown() {
+ return down;
+ }
+
+ public void setDown(final PVertex
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
)obj).getPoint());
+ }
+
+ @Override
+ public int hashCode() {
+ return point.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return point.toString();
+ }
+}
diff --git a/VadereUtils/src/org/vadere/util/geometry/mesh/inter/IPolyConnectivity.java b/VadereUtils/src/org/vadere/util/geometry/mesh/inter/IPolyConnectivity.java
index acb10e2a0853306b9476618e4effbc89b490f50d..371c496e0c29e58d55f418a3b3de2387d127da28 100644
--- a/VadereUtils/src/org/vadere/util/geometry/mesh/inter/IPolyConnectivity.java
+++ b/VadereUtils/src/org/vadere/util/geometry/mesh/inter/IPolyConnectivity.java
@@ -14,16 +14,30 @@ import java.util.Set;
/**
* @author Benedikt Zoennchen
*/
-public interface IPolyConnectivity
, F extends IFace
> extends Iterable{
+public interface IPolyConnectivity, E extends IHalfEdge
, F extends IFace
> extends Iterable{
- IMesh getMesh();
+ /**
+ * Returns the mesh of this IPolyConnectivity.
+ * Non mesh changing method.
+ *
+ * @return the mesh of this IPolyConnectivity
+ */
+ IMesh
getMesh();
- default boolean isAtBoundary(E halfEdge) {
- IMesh
mesh = getMesh();
+ default boolean isAtBoundary(@NotNull final E halfEdge) {
+ IMesh
mesh = getMesh();
return mesh.isBoundary(halfEdge) || mesh.isBoundary(mesh.getTwin(halfEdge));
}
- default Optional 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 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, F e
return Optional.empty();
}
- default Optional 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 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 edges = getMesh().getEdges(vertex);
edges.stream().filter(edge -> isAtBoundary(edge)).findAny().ifPresent(edge -> getMesh().setEdge(vertex, edge));
}
- default Optional findEdge(P begin, P end) {
- IMesh 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 findEdge(@NotNull final V begin, @NotNull final V end) {
+ IMesh 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
, 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 faceSet = new HashSet<>();
E edge = getMesh().getEdge(face);
E next = getMesh().getNext(edge);
@@ -85,7 +147,33 @@ public interface IPolyConnectivity, 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 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, 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
, 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
, 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
, 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 delEdges = new ArrayList<>();
-
- List vertices = new ArrayList<>();
+ List vertices = new ArrayList<>();
F boundary = getMesh().createFace(true);
@@ -195,7 +299,7 @@ public interface IPolyConnectivity, 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
, 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);
}
}
diff --git a/VadereUtils/src/org/vadere/util/geometry/mesh/inter/ITriConnectivity.java b/VadereUtils/src/org/vadere/util/geometry/mesh/inter/ITriConnectivity.java
index be9bf58db1528d0293bc4ee6da00d268a67b1ad9..32792ca8d1176f02d9761eaee19db1c4ee17894b 100644
--- a/VadereUtils/src/org/vadere/util/geometry/mesh/inter/ITriConnectivity.java
+++ b/VadereUtils/src/org/vadere/util/geometry/mesh/inter/ITriConnectivity.java
@@ -1,5 +1,7 @@
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
* @param
*/
-public interface ITriConnectivity, F extends IFace
> extends IPolyConnectivity
{
+public interface ITriConnectivity
, E extends IHalfEdge
, F extends IFace
> extends IPolyConnectivity
{
- 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
+ * @param f3
+ */
+ default void splitTriangleEvent(F original, F f1, F f2, F f3) {}
+
+ default void splitEdgeEvent(F original, F f1, F f2) {}
+
+ /**
+ * Non mesh changing method.
+ *
+ * @param f1
+ * @param f2
+ */
default void flipEdgeEvent(F f1, F f2) {}
+ /**
+ * Non mesh changing method.
+ *
+ * @param vertex
+ */
default void insertEvent(E vertex) {};
- boolean isIllegal(E edge);
+ /**
+ * Non mesh changing method.
+ *
+ * @param edge
+ * @return
+ */
+ boolean isIllegal(E edge, V p);
/**
* Splits the half-edge at point p, preserving a valid triangulation.
+ * Assumption: p is located on the edge!
+ * Mesh changing method.
*
* @param p the split point
* @param halfEdge the half-edge which will be split
+ * @return an newly created half-edge which has p as its end-point
*/
- default List splitEdge(@NotNull P p, @NotNull E halfEdge, boolean legalize) {
- IMesh mesh = getMesh();
- mesh.insertVertex(p);
- List newEdges = new ArrayList<>(4);
+ default E splitEdge(@NotNull P p, @NotNull E halfEdge, boolean legalize) {
+ IMesh mesh = getMesh();
+ V v = mesh.createVertex(p);
+ mesh.insertVertex(v);
+
/*
* Situation: h0 = halfEdge
* h1 -> h2 -> h0
@@ -65,18 +99,19 @@ public interface ITriConnectivity
, F ex
E h0 = halfEdge;
E o0 = mesh.getTwin(h0);
- P v2 = mesh.getVertex(o0);
+ V v2 = mesh.getVertex(o0);
F f0 = mesh.getFace(h0);
F f3 = mesh.getFace(o0);
// faces correct?
mesh.createEdge(v2, mesh.getFace(o0));
E e1 = mesh.createEdge(v2, mesh.getFace(o0));
- E t1 = mesh.createEdge(p, mesh.getFace(h0));
+
+ E t1 = mesh.createEdge(v, mesh.getFace(h0));
+ mesh.setEdge(v, t1);
+
mesh.setTwin(e1, t1);
- mesh.setVertex(o0, p);
- newEdges.add(t1);
- newEdges.add(h0);
+ mesh.setVertex(o0, v);
if(!mesh.isBoundary(h0)) {
F f1 = mesh.createFace();
@@ -84,12 +119,11 @@ public interface ITriConnectivity
, F ex
E h1 = mesh.getNext(h0);
E h2 = mesh.getNext(h1);
- P v1 = mesh.getVertex(h1);
+ V v1 = mesh.getVertex(h1);
E e0 = mesh.createEdge(v1, f1);
- E t0 = mesh.createEdge(p, f0);
+ E t0 = mesh.createEdge(v, f0);
mesh.setTwin(e0, t0);
- newEdges.add(t0);
mesh.setEdge(f0, h0);
mesh.setEdge(f1, h2);
@@ -110,7 +144,7 @@ public interface ITriConnectivity
, F ex
mesh.setNext(h2, t1);
mesh.setNext(t1, e0);
- splitFaceEvent(f0, f0, f1);
+ splitEdgeEvent(f0, f0, f1);
}
else {
mesh.setNext(mesh.getPrev(h0), t1);
@@ -121,14 +155,13 @@ public interface ITriConnectivity
, F ex
E o1 = mesh.getNext(o0);
E o2 = mesh.getNext(o1);
- P v3 = mesh.getVertex(o1);
+ V v3 = mesh.getVertex(o1);
F f2 = mesh.createFace();
// face
E e2 = mesh.createEdge(v3, mesh.getFace(o0));
- E t2 = mesh.createEdge(p, f2);
+ E t2 = mesh.createEdge(v, f2);
mesh.setTwin(e2, t2);
- newEdges.add(t2);
mesh.setEdge(f2, o1);
mesh.setEdge(f3, o0);
@@ -149,7 +182,7 @@ public interface ITriConnectivity
, F ex
mesh.setNext(e2, o2);
mesh.setNext(o2, o0);
- splitFaceEvent(f3, f3, f2);
+ splitEdgeEvent(f3, f3, f2);
}
else {
mesh.setNext(e1, mesh.getNext(o0));
@@ -160,33 +193,34 @@ public interface ITriConnectivity
, F ex
if(!mesh.isBoundary(h0)) {
E h1 = mesh.getNext(h0);
E h2 = mesh.getPrev(t1);
- legalize(h1);
- legalize(h2);
+ legalize(h1, v);
+ legalize(h2, v);
}
if(!mesh.isBoundary(o0)) {
E o1 = mesh.getNext(e1);
E o2 = mesh.getPrev(o0);
- legalize(o1);
- legalize(o2);
+ legalize(o1, v);
+ legalize(o2, v);
}
}
- return newEdges;
+ return t1;
}
- default List splitEdge(@NotNull P p, @NotNull E halfEdge) {
+ default E splitEdge(@NotNull P p, @NotNull E halfEdge) {
return splitEdge(p, halfEdge, true);
}
/**
* Flips an edge in the triangulation assuming the egdge which will be
* created is not jet there.
+ * mesh changing method.
*
* @param edge the edge which will be flipped.
*/
default void flip(@NotNull final E edge) {
- IMesh mesh = getMesh();
+ IMesh
mesh = getMesh();
// 1. gather all the references required
E a0 = edge;
@@ -200,6 +234,12 @@ public interface ITriConnectivity
, F ex
F fa = mesh.getFace(a0);
F fb = mesh.getFace(b0);
+ V va1 = mesh.getVertex(a1);
+ V vb1 = mesh.getVertex(b1);
+
+ V va0 = mesh.getVertex(a0);
+ V vb0 = mesh.getVertex(b0);
+
if(mesh.getEdge(fb).equals(b1)) {
mesh.setEdge(fb, a1);
}
@@ -208,8 +248,17 @@ public interface ITriConnectivity
, F ex
mesh.setEdge(fa, b1);
}
- mesh.setVertex(a0, mesh.getVertex(a1));
- mesh.setVertex(b0, mesh.getVertex(b1));
+ // TODO: maybe without if, just do it? its faster?
+ if(mesh.getEdge(va0).equals(a0)) {
+ mesh.setEdge(va0, b2);
+ }
+
+ if(mesh.getEdge(vb0).equals(b0)) {
+ mesh.setEdge(vb0, a2);
+ }
+
+ mesh.setVertex(a0, va1);
+ mesh.setVertex(b0, vb1);
mesh.setNext(a0, a2);
mesh.setNext(a2, b1);
@@ -226,43 +275,48 @@ public interface ITriConnectivity
, F ex
}
default boolean isTriangle(F face) {
- IMesh
mesh = getMesh();
+ IMesh
mesh = getMesh();
List edges = mesh.getEdges(face);
return edges.size() == 3;
}
- default boolean insert(@NotNull F face, @NotNull P p) {
- throw new UnsupportedOperationException("not jet implemented.");
- }
+ E insert(@NotNull P p, @NotNull F face);
/**
* Splits the triangle xyz into three new triangles xyp, yzp and zxp.
+ * Assumption: p is inside the face.
+ * Mesh changing method.
*
- * @param p the point which splits the triangle
- * @param face the triangle face we split
+ * @param point the point which splits the triangle
+ * @param face the triangle face we split
+ * @param legalize true means that recursive filps will be done afterwards to legalize illegal edges (e.g. delaunay requirement).
*
- * returns a list of all newly created face.
+ * @return an half-edge which has point as its end-point
*/
- default List splitTriangle(@NotNull F face, P p, boolean legalize) {
- assert isTriangle(face);
+ default E splitTriangle(@NotNull F face, @NotNull final P point, boolean legalize) {
+ //assert isTriangle(face) && locateFace(point).get().equals(face);
+
+ V p = getMesh().createVertex(point);
getMesh().insertVertex(p);
- List faceList = new ArrayList<>(3);
- IMesh mesh = getMesh();
- List edges = mesh.getEdges(face);
+ IMesh mesh = getMesh();
F xyp = mesh.createFace();
F yzp = mesh.createFace();
- F zxp = mesh.createFace();
- E zx = edges.get(0);
- E xy = edges.get(1);
- E yz = edges.get(2);
+ //F zxp = mesh.createFace();
+ F zxp = face;
- P x = mesh.getVertex(zx);
- P y = mesh.getVertex(xy);
- P z = mesh.getVertex(yz);
+ E zx = mesh.getEdge(face);
+ E xy = mesh.getNext(zx);
+ E yz = mesh.getNext(xy);
+
+ V x = mesh.getVertex(zx);
+ V y = mesh.getVertex(xy);
+ V z = mesh.getVertex(yz);
E yp = mesh.createEdge(p, xyp);
+ mesh.setEdge(p, yp);
+
E py = mesh.createEdge(y, yzp);
mesh.setTwin(yp, py);
@@ -294,70 +348,86 @@ public interface ITriConnectivity
, F ex
mesh.setFace(zx, zxp);
mesh.setFace(yz, yzp);
- // TODO: maybe we do not destroy the face, instead use it.
- mesh.destroyFace(face);
- faceList.add(xyp);
- faceList.add(yzp);
- faceList.add(zxp);
+ // we reuse the face for efficiency
+ //mesh.destroyFace(face);
- splitFaceEvent(face, xyp, yzp, zxp);
+ splitTriangleEvent(face, xyp, yzp, zxp);
if(legalize) {
- legalize(zx);
- legalize(xy);
- legalize(yz);
+ legalize(zx, p);
+ legalize(xy, p);
+ legalize(yz, p);
}
- return faceList;
+ return xp;
}
- default List splitTriangle(@NotNull F face, P p) {
+ /**
+ * Splits the triangle xyz into three new triangles xyp, yzp and zxp and legalizes all possibly illegal edges.
+ * Assumption: p is inside the face.
+ * Mesh changing method.
+ *
+ * @param p the point which splits the triangle
+ * @param face the triangle face we split
+ *
+ * returns a list of all newly created face.
+ */
+ default E splitTriangle(@NotNull final F face, @NotNull final P p) {
return splitTriangle(face, p, true);
}
/**
* Legalizes an edge xy of a triangle xyz if it is illegal by flipping it.
+ * Mesh changing method.
*
* @param edge an edge zx of a triangle xyz
*/
- default void legalize(E edge) {
- if(isIllegal(edge)) {
+ /*default void legalize(@NotNull final E edge, final V p, int depth) {
+ if(isIllegal(edge, p)) {
assert isFlipOk(edge);
-
- P p = getMesh().getVertex(getMesh().getNext(edge));
+ assert getMesh().getVertex(getMesh().getNext(edge)).equals(p);
F f1 = getMesh().getFace(edge);
F f2 = getMesh().getTwinFace(edge);
flip(edge);
- P vertex = getMesh().getVertex(edge);
+ V vertex = getMesh().getVertex(edge);
if(vertex.equals(p)) {
E e1 = getMesh().getPrev(edge);
- E e2 = getMesh().getPrev(getMesh().getTwin(edge));
- legalize(e1);
- legalize(getMesh().getPrev(e2));
+ E e2 = getMesh().getNext(getMesh().getTwin(edge));
+
+
+ legalize(e1, p, depth+1);
+ legalize(e2, p, depth+1);
}
else {
E e1 = getMesh().getNext(edge);
- E e2 = getMesh().getNext(getMesh().getTwin(edge));
- legalize(e1);
- legalize(getMesh().getNext(e2));
+ E e2 = getMesh().getPrev(getMesh().getTwin(edge));
+ legalize(e1, p, depth+1);
+ legalize(e2, p, depth+1);
}
}
+ }*/
+
+ void legalizeNonRecursive(final E edge, final V p);
+
+ default void legalize(final E edge, V p) {
+ legalizeNonRecursive(edge, p);
}
/**
* Tests if a flip for this half-edge is valid, i.e. the edge does not already exist.
+ * Non mesh changing method.
*
* @param halfEdge the half-edge that might be flipped
* @return true if and only if the flip is valid
*/
- default boolean isFlipOk(final E halfEdge) {
+ default boolean isFlipOk(@NotNull final E halfEdge) {
if(getMesh().isBoundary(halfEdge)) {
return false;
}
@@ -369,7 +439,7 @@ public interface ITriConnectivity, F ex
return false;
}
- P vertex = getMesh().getVertex(getMesh().getNext(yx));
+ V vertex = getMesh().getVertex(getMesh().getNext(yx));
for(E neigbhour : getMesh().getIncidentEdgesIt(getMesh().getNext(xy))) {
if(getMesh().getVertex(neigbhour).equals(vertex)) {
@@ -381,14 +451,17 @@ public interface ITriConnectivity
, F ex
}
@Override
- default Optional locate(final P point) {
- return this.locate(point.getX(), point.getY());
+ default Optional locateFace(final P point) {
+ return this.locateFace(point.getX(), point.getY());
}
@Override
- default Optional locate(final double x, final double y) {
- if(getMesh().getNumberOfFaces() > 0) {
- return locate(x, y, getMesh().getFace());
+ default Optional locateFace(final double x, final double y) {
+ if(getMesh().getNumberOfFaces() > 1) {
+ return locateFace(x, y, getMesh().getFace());
+ }
+ else if(getMesh().getNumberOfFaces() == 1) {
+ return Optional.of(getMesh().getFace());
}
else {
return Optional.empty();
@@ -396,7 +469,7 @@ public interface ITriConnectivity, F ex
}
/*default Optional
locateVertex(double x, double y, F startFace) {
- Optional optFace = locate(x, y, startFace);
+ Optional optFace = locateFace(x, y, startFace);
if(optFace.isPresent()) {
F face = optFace.get();
@@ -409,7 +482,15 @@ public interface ITriConnectivity, F ex
return Optional.empty();
}*/
- default Optional locate(double x, double y, F startFace) {
+ /**
+ * None mesh changing method.
+ *
+ * @param x
+ * @param y
+ * @param startFace
+ * @return
+ */
+ default Optional locateFace(double x, double y, F startFace) {
// there is no face.
if(getDimension() <= 0 ){
return Optional.empty();
@@ -419,12 +500,22 @@ public interface ITriConnectivity, F ex
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));
+ return Optional.of(marchRandom2D(x, y, startFace));
}
}
+ default Optional locateFace(P point, F startFace) {
+ return locateFace(point.getX(), point.getY(), startFace);
+ }
+
+ /**
+ * None mesh changing method.
+ *
+ * @param x
+ * @param y
+ * @param startFace
+ * @return
+ */
default Optional marchLocate1D(double x, double y, F startFace) {
if(contains(startFace, x, y)) {
return Optional.of(startFace);
@@ -435,31 +526,38 @@ public interface ITriConnectivity, F ex
}
/**
- * Marching to the face which contains the point defined by (x2, y2). The march
- * starts at (x1, y2) at inside the startFace.
+ * Marching to the face which triangleContains the point defined by (x2, y2). Inside the startFace.
+ * None mesh changing method.
*
- * @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 x1 the x-coordinate of the ending point
+ * @param y1 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);
+ default F marchLocate2D(double x1, double y1, F startFace) {
+ //assert !getMesh().isBoundary(startFace);
+ //assert contains(startFace, x1, y1);
+
+ VTriangle triangle = getMesh().toTriangle(startFace);
+ VPoint incenter = triangle.getIncenter();
+
+ double x2 = incenter.getX();
+ double y2 = incenter.getY();
E entryEdge = null;
F face = startFace;
boolean found = true;
- while(found && !contains(face, x2, y2)) {
+ //TODO: this seems to be very slow!
+
+ while(found && !contains(face, x1, y1)) {
found = false;
for(E halfEdge : getMesh().getEdgeIt(face)) {
if(!halfEdge.equals(entryEdge)) {
- P sVertex = getMesh().getVertex(getMesh().getPrev(halfEdge));
- P eVertex = getMesh().getVertex(halfEdge);
+ V sVertex = getMesh().getVertex(getMesh().getPrev(halfEdge));
+ V eVertex = getMesh().getVertex(halfEdge);
+ //TODO: use faster/own implementation?
if(VLine.linesIntersect(sVertex.getX(), sVertex.getY(), eVertex.getX(), eVertex.getY(), x1, y1, x2, y2)) {
entryEdge = getMesh().getTwin(halfEdge);
face = getMesh().getTwinFace(halfEdge);
@@ -470,15 +568,242 @@ public interface ITriConnectivity
, F ex
}
}
- assert found || getMesh().isBoundary(face);
+ //assert found || getMesh().isBoundary(face);
return face;
}
- default boolean contains(F face, double x, double y) {
+ default F marchRandom2D(double x1, double y1, F startFace) {
+ boolean first = true;
+ F face = startFace;
+ F prevFace = null;
+ int count = 0;
+
+ while (true) {
+ count++;
+ //boolean goLeft = random.nextBoolean();
+ boolean goLeft = true;
+
+ E e1 = getMesh().getEdge(face);
+ E e2 = getMesh().getNext(e1);
+ E e3 = getMesh().getNext(e2);
+
+ V v1 = getMesh().getVertex(e1);
+ V v2 = getMesh().getVertex(e2);
+ V v3 = getMesh().getVertex(e3);
+
+ // loop unrolling for efficiency!
+ if(first) {
+ first = false;
+ prevFace = face;
+
+ if (GeometryUtils.isRightOf(v3, v1, x1, y1)) {
+ face = getMesh().getTwinFace(e1);
+ continue;
+ }
+
+ if (GeometryUtils.isRightOf(v1, v2, x1, y1)) {
+ face = getMesh().getTwinFace(e2);
+ continue;
+ }
+
+ if (GeometryUtils.isRightOf(v2, v3, x1, y1)) {
+ face = getMesh().getTwinFace(e3);
+ continue;
+ }
+ } else if(goLeft) {
+ if(prevFace == getMesh().getTwinFace(e1)) {
+ prevFace = face;
+
+ if (GeometryUtils.isRightOf(v2, v3, x1, y1)) {
+ face = getMesh().getTwinFace(e3);
+ continue;
+ }
+
+ if(GeometryUtils.isRightOf(v1, v2, x1, y1)) {
+ face = getMesh().getTwinFace(e2);
+ continue;
+ }
+
+ }
+ else if(prevFace == getMesh().getTwinFace(e2)) {
+ prevFace = face;
+
+ if (GeometryUtils.isRightOf(v3, v1, x1, y1)) {
+ face = getMesh().getTwinFace(e1);
+ continue;
+ }
+
+ if (GeometryUtils.isRightOf(v2, v3, x1, y1)) {
+ face = getMesh().getTwinFace(e3);
+ continue;
+ }
+
+ }
+ else {
+ prevFace = face;
+
+ if(GeometryUtils.isRightOf(v1, v2, x1, y1)) {
+ face = getMesh().getTwinFace(e2);
+ continue;
+ }
+
+ if (GeometryUtils.isRightOf(v3, v1, x1, y1)) {
+ face = getMesh().getTwinFace(e1);
+ continue;
+ }
+
+ }
+ }
+ else {
+ if(prevFace == getMesh().getTwinFace(e1)) {
+ prevFace = face;
+
+ if(GeometryUtils.isRightOf(v1, v2, x1, y1)) {
+ face = getMesh().getTwinFace(e2);
+ continue;
+ }
+
+ if (GeometryUtils.isRightOf(v2, v3, x1, y1)) {
+ face = getMesh().getTwinFace(e3);
+ continue;
+ }
+
+ }
+ else if(prevFace == getMesh().getTwinFace(e2)) {
+ prevFace = face;
+
+ if (GeometryUtils.isRightOf(v2, v3, x1, y1)) {
+ face = getMesh().getTwinFace(e3);
+ continue;
+ }
+
+ if (GeometryUtils.isRightOf(v3, v1, x1, y1)) {
+ face = getMesh().getTwinFace(e1);
+ continue;
+ }
+
+ }
+ else {
+ prevFace = face;
+
+ if (GeometryUtils.isRightOf(v3, v1, x1, y1)) {
+ face = getMesh().getTwinFace(e1);
+ continue;
+ }
+
+ if(GeometryUtils.isRightOf(v1, v2, x1, y1)) {
+ face = getMesh().getTwinFace(e2);
+ continue;
+ }
+
+ }
+ }
+ //log.info("#traversed triangles = " + count);
+ return face;
+ }
+ }
+
+ /**
+ * Returns the point which is closest to the p = (x1, y1) assuming it is in the
+ * circumcircle defined by the face.
+ *
+ * @param x1 the x-coordinate of the starting point
+ * @param y1 the y-coordinate of the starting point
+ * @param face the face where the march start containing (x1,y1).
+ * @return
+ */
+ default V locateNearestNeighbour(double x1, double y1, F face) {
+ assert isInsideCircumscribedCycle(face, x1, y1);
+
+ V nn = getNearestPoint(face, x1, y1);
+ E edge = getMesh().getEdge(face);
+
+
+ nn = lookUpNearestNeighbour(x1, y1, nn, getMesh().getTwin(edge));
+ nn = lookUpNearestNeighbour(x1, y1, nn, getMesh().getTwin(getMesh().getNext(edge)));
+ nn = lookUpNearestNeighbour(x1, y1, nn, getMesh().getTwin(getMesh().getNext(edge)));
+
+ return nn;
+ }
+
+ default V locateNearestNeighbour(P point, F startFace) {
+ return locateNearestNeighbour(point.getX(), point.getY(), startFace);
+ }
+
+ default V locateNearestNeighbour(P point) {
+ return locateNearestNeighbour(point.getX(), point.getY(), getMesh().getFace());
+ }
+
+ default V locateNearestNeighbour(double x1, double y1) {
+ return locateNearestNeighbour(x1, y1, getMesh().getFace());
+ }
+
+ //TODO: rename
+ default V lookUpNearestNeighbour(double x1, double y1, V nn, E edge) {
+ F face = getMesh().getFace(edge);
+
+ if(isInsideCircumscribedCycle(face, x1, y1)) {
+ V v = getMesh().getVertex(edge);
+
+ if(v.distance(x1, y1) < nn.distance(x1, y1)) {
+ nn = v;
+ }
+
+ nn = lookUpNearestNeighbour(x1, y1, nn, getMesh().getTwin(getMesh().getNext(edge)));
+ nn = lookUpNearestNeighbour(x1, y1, nn, getMesh().getTwin(getMesh().getPrev(edge)));
+ }
+
+ return nn;
+ }
+
+ /**
+ * Tests if the point p = (x1, y1) is inside the circumscribedcycle defined by the triangle of the face.
+ * @param face the face
+ * @param x1 x-coordinate of the point
+ * @param y1 y-coordinate of the point
+ * @return true if the point p = (x1, y1) is inside the circumscribedcycle defined by the triangle of the face, false otherwise.
+ */
+ default boolean isInsideCircumscribedCycle(final F face, double x1, double y1) {
+ E e1 = getMesh().getEdge(face);
+ E e2 = getMesh().getNext(e1);
+ E e3 = getMesh().getNext(e2);
+
+ V v1 = getMesh().getVertex(e1);
+ V v2 = getMesh().getVertex(e2);
+ V v3 = getMesh().getVertex(e3);
+
+ return GeometryUtils.isInsideCircle(v1, v2, v3, x1, y1);
+ }
+
+ /**
+ * 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.
+ *
+ * @param face the face of the trianuglation
+ * @param point the point
+ * @return vertex of the triangulation of the face with the smallest distance to point
+ */
+ default V getNearestPoint(final F face, final P point) {
+ return getNearestPoint(face, point.getX(), point.getY());
+ }
+
+ default V getNearestPoint(final F face, final double x, final double y) {
+ IMesh
mesh = getMesh();
+ return mesh.streamEdges(face).map(edge -> mesh.getVertex(edge)).reduce((p1, p2) -> p1.distance(x,y) > p2.distance(x,y) ? p2 : p1).get();
+ }
- if(getMesh().isMember(face, x, y)) {
+ /**
+ * None mesh changing method.
+ *
+ * @param face
+ * @param x
+ * @param y
+ * @return
+ */
+ default boolean contains(F face, double x, double y) {
+ if(isMember(face, x, y)) {
return true;
}
@@ -487,29 +812,47 @@ public interface ITriConnectivity
, F ex
return getMesh().toPolygon(face).contains(x, y);
}
else {
- return getMesh().toTriangle(face).contains(x, y);
+ E h1 = getMesh().getEdge(face);
+ E h2 = getMesh().getNext(h1);
+ E h3 = getMesh().getNext(h2);
+ return GeometryUtils.triangleContains(getMesh().getPoint(h1), getMesh().getPoint(h2), getMesh().getPoint(h3), new VPoint(x, y));
}
}
//Optional marchLocate2DLFC(double x, double y, F startFace);
- default P getMaxDistanceVertex(F face, double x, double y) {
- List vertices = getMesh().getVertices(face);
+ /**
+ * None mesh changing method.
+ *
+ * @param face
+ * @param x
+ * @param y
+ * @return
+ */
+ default V getMaxDistanceVertex(F face, double x, double y) {
+ List vertices = getMesh().getVertices(face);
- assert vertices.size() == 3;
+ //assert vertices.size() == 3;
- P result = vertices.get(0);
+ V 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 vertices = getMesh().getVertices(face);
+ /**
+ * None mesh changing method.
+ * @param face
+ * @param x
+ * @param y
+ * @return
+ */
+ default V getMinDistanceVertex(F face, double x, double y) {
+ List vertices = getMesh().getVertices(face);
- assert vertices.size() == 3;
+ //assert vertices.size() == 3;
- P result = vertices.get(0);
+ V 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;
@@ -520,50 +863,142 @@ public interface ITriConnectivity, F ex
}
/**
- * 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.
+ * Returns the closest half-edge of a face containing p = (x,y) if there is any face that contains p, otherwise empty().
+ * Three cases are possible:
+ * 1) p is in the interior of the face
+ * 2) p lies on the edge which will be returned.
+ * 3) p is a vertex of the mesh
*
- * @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.
+ * @param x x-coordinate of the point p
+ * @param y y-coordinate of the point p
+ * @return the closest half-edge of a face containing p = (x,y) if there is any face that contains p, otherwise empty().
*/
- default Collection getAdjacentFaces(final double x, final double y) {
- Optional optFace = locate(x, y);
+ default Optional getClosestEdge(final double x, final double y) {
+ Optional optFace = locateFace(x, y);
+
if(optFace.isPresent()) {
- F face = optFace.get();
+ return Optional.of(getMesh().closestEdge(optFace.get(), x, y));
+ }
+ else {
+ return Optional.empty();
+ }
+ }
- /*
- * 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 optMemberEdge = getMesh().getMemberEdge(face, x, y);
- if(optMemberEdge.isPresent()) {
- return getMesh().getAdjacentFaces(optMemberEdge.get());
- }
- else {
- List faces = new ArrayList<>(2);
- faces.add(face);
+ /**
+ * Returns the closest half-edge of a face containing p = (x,y) if there is any face that contains p, otherwise empty().
+ * Two cases are possible:
+ * 1) p is in the interior of the face
+ * 2) p lies on the edge which will be returned.
+ * 3) p is a vertex of the mesh
+ *
+ * @param x x-coordinate of the point p
+ * @param y y-coordinate of the point p
+ * @param startFace the face the search will start from
+ * @return the closest half-edge of a face containing p = (x,y) if there is any face that contains p, otherwise empty().
+ */
+ default Optional getClosestEdge(final double x, final double y, final F startFace) {
+ Optional optFace = locateFace(x, y, startFace);
- for(E halfEdge : getMesh().getEdgeIt(face)) {
- P v1 = getMesh().getVertex(halfEdge);
- P v2 = getMesh().getVertex(getMesh().getPrev(halfEdge));
+ if(optFace.isPresent()) {
+ return Optional.of(getMesh().closestEdge(optFace.get(), x, y));
+ }
+ else {
+ return Optional.empty();
+ }
+ }
- // TODO: think about the epsilon, absolute value seems to be a really bad idea!
- if(!getMesh().isBoundary(getMesh().getTwinFace(halfEdge)) && Math.abs(GeometryUtils.ccw(x, y, v1.getX(), v1.getY(), v2.getX(), v2.getY())) == 0.0) {
- faces.add(getMesh().getTwinFace(halfEdge));
- break;
- }
- }
+ /**
+ * Returns the closest vertex of a face containing p = (x,y) if there is any face that contains p, otherwise empty().
+ * Note that this might not be the closest point with respect to p in general. There might be a point closer which
+ * is however not part of the triangle which contains p.
+ *
+ * @param x x-coordinate of the point p
+ * @param y y-coordinate of the point p
+ * @return the closest vertex of a face containing p = (x,y) if there is any face that contains p, otherwise empty().
+ */
+ default Optional getClosestVertex(final double x, final double y) {
+ Optional optFace = locateFace(x, y);
- return faces;
- }
+ if(optFace.isPresent()) {
+ return Optional.of(getMesh().closestVertex(optFace.get(), x, y));
+ }
+ else {
+ return Optional.empty();
+ }
+ }
+ /**
+ * Returns the closest vertex of a face containing p = (x,y) if there is any face that contains p, otherwise empty().
+ * Note that this might not be the closest point with respect to p in general. There might be a point closer which
+ * is however not part of the triangle which contains p. The search for the face containing p starts at the startFace.
+ *
+ * @param x x-coordinate of the point p
+ * @param y y-coordinate of the point p
+ * @param startFace the face the search will start from
+ * @return the closest vertex of a face containing p = (x,y) if there is any face that contains p, otherwise empty().
+ */
+ default Optional getClosestVertex(final double x, final double y, final F startFace) {
+ Optional optFace = locateFace(x, y, startFace);
+
+ if(optFace.isPresent()) {
+ return Optional.of(getMesh().closestVertex(optFace.get(), x, y));
}
else {
- return Collections.emptyList();
+ return Optional.empty();
+ }
+ }
+
+ default boolean isMember(F face, double x, double y, double epsilon) {
+ return getMemberEdge(face, x, y, epsilon).isPresent();
+ }
+
+ default Optional getMemberEdge(F face, double x, double y, double epsilon) {
+ E e1 = getMesh().getEdge(face);
+ E e2 = getMesh().getNext(e1);
+ E e3 = getMesh().getNext(e2);
+
+ if(getMesh().getPoint(e1).distance(x, y) < epsilon) {
+ return Optional.of(e1);
+ }
+
+ if(getMesh().getPoint(e2).distance(x, y) < epsilon) {
+ return Optional.of(e2);
+ }
+
+ if(getMesh().getPoint(e3).distance(x, y) < epsilon) {
+ return Optional.of(e3);
+ }
+
+ return Optional.empty();
+ }
+
+ default boolean isMember(F face, double x, double y) {
+ return getMemberEdge(face, x, y).isPresent();
+ }
+
+ default Optional getMemberEdge(F face, double x, double y) {
+ E e1 = getMesh().getEdge(face);
+ P p1 = getMesh().getPoint(e1);
+
+ if(p1.getX() == x && p1.getY() == y) {
+ return Optional.of(e1);
+ }
+
+ E e2 = getMesh().getNext(e1);
+ P p2 = getMesh().getPoint(e2);
+
+ if(p2.getX() == x && p2.getY() == y) {
+ return Optional.of(e2);
+ }
+
+ E e3 = getMesh().getNext(e2);
+ P p3 = getMesh().getPoint(e3);
+
+ if(p3.getX() == x && p3.getY() == y) {
+ return Optional.of(e3);
}
+
+ return Optional.empty();
}
+
}
diff --git a/VadereUtils/src/org/vadere/util/geometry/mesh/inter/ITriangulationHierarchy.java b/VadereUtils/src/org/vadere/util/geometry/mesh/inter/ITriangulationHierarchy.java
deleted file mode 100644
index eace286face55de9180556c366065d3ccc0f211a..0000000000000000000000000000000000000000
--- a/VadereUtils/src/org/vadere/util/geometry/mesh/inter/ITriangulationHierarchy.java
+++ /dev/null
@@ -1,73 +0,0 @@
-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,
- F extends IFace
,
- 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 faces = locateInAll(x ,y);
-
- ITriangulation 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
getLevel(int level);
-
- default List locateInAll(double x, double y) {
- int level = getMaxLevel();
- F face;
- List 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;
- }
-}
diff --git a/VadereUtils/src/org/vadere/util/geometry/mesh/iterators/EdgeIterator.java b/VadereUtils/src/org/vadere/util/geometry/mesh/iterators/EdgeIterator.java
index 9ade16d065fdb44bfd9acd14327b289ef98a4b64..3251ea36650d9fb8849c8f4a2be78aa3387fe3da 100644
--- a/VadereUtils/src/org/vadere/util/geometry/mesh/iterators/EdgeIterator.java
+++ b/VadereUtils/src/org/vadere/util/geometry/mesh/iterators/EdgeIterator.java
@@ -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 the type of the half-edge
* @param the type of the face
*/
-public class EdgeIterator, F extends IFace
> implements Iterator {
+public class EdgeIterator, E extends IHalfEdge
, F extends IFace
> implements Iterator {
private E currentHalfEdge;
private E edge;
private boolean started = false;
- private IMesh mesh;
+ private IMesh
mesh;
- public EdgeIterator(final IMesh
mesh, final F face){
+ public EdgeIterator(final IMesh
mesh, final F face){
this.edge = mesh.getEdge(face);
this.currentHalfEdge = edge;
this.mesh = mesh;
diff --git a/VadereUtils/src/org/vadere/util/geometry/mesh/triangulations/BasePointLocator.java b/VadereUtils/src/org/vadere/util/geometry/mesh/triangulations/BasePointLocator.java
index 7b3ac74d866ab8d4e11c9f013e0fdf277c96b91a..9e5194267bc62609d89eae7e42a64a0b49a05efa 100644
--- a/VadereUtils/src/org/vadere/util/geometry/mesh/triangulations/BasePointLocator.java
+++ b/VadereUtils/src/org/vadere/util/geometry/mesh/triangulations/BasePointLocator.java
@@ -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
+ * @param
* @param
* @param
*/
-public class BasePointLocator, F extends IFace
> implements IPointLocator
{
+public class BasePointLocator
, E extends IHalfEdge
, F extends IFace
> implements IPointLocator
{
- private ITriConnectivity
triConnectivity;
+ private ITriConnectivity
triConnectivity;
- public BasePointLocator(final ITriConnectivity
triConnectivity) {
+ public BasePointLocator(final ITriConnectivity
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 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 optFace = triConnectivity.locate(point.getX(), point.getY());
+ Optional optFace = triConnectivity.locateFace(point.getX(), point.getY());
return optFace.isPresent() ? Collections.singleton(optFace.get()) : Collections.emptyList();
- }
+ }*/
}
@Override
public Optional locate(final IPoint point) {
- return triConnectivity.locate(point.getX(), point.getY());
+ return triConnectivity.locateFace(point.getX(), point.getY());
}
}
diff --git a/VadereUtils/src/org/vadere/util/geometry/mesh/triangulations/DelaunayHierarchy.java b/VadereUtils/src/org/vadere/util/geometry/mesh/triangulations/DelaunayHierarchy.java
index a858fac896deda8f6e4293012168fe690c78f9d9..9e02257c0e13346ddfdadc2ac512dceed4f7337b 100644
--- a/VadereUtils/src/org/vadere/util/geometry/mesh/triangulations/DelaunayHierarchy.java
+++ b/VadereUtils/src/org/vadere/util/geometry/mesh/triangulations/DelaunayHierarchy.java
@@ -1,19 +1,20 @@
package org.vadere.util.geometry.mesh.triangulations;
+import org.apache.log4j.LogManager;
+import org.apache.log4j.Logger;
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.mesh.inter.IPointLocator;
-import org.vadere.util.geometry.mesh.inter.ITriConnectivity;
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.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -27,137 +28,219 @@ import java.util.function.Supplier;
* @param
* @param
*/
-public class DelaunayHierarchy, F extends IFace
> implements IPointLocator
{
+public class DelaunayHierarchy
, E extends IHalfEdge
, F extends IFace
> implements IPointLocator
{
+ private static Logger log = LogManager.getLogger(DelaunayHierarchy.class);
- private List> hierarchySets;
+ private List> hierarchySets;
- private List