Commit e2544d76 authored by Benedikt Zoennchen's avatar Benedikt Zoennchen
Browse files

update triangulation algorithm, implementation of the delaunay-hierarchy

parent a3b8d98c
......@@ -46,7 +46,7 @@ public interface IGaussianFilter {
void setInputValue(final int x, final int y, final double value);
/** refresh or update the values of the image that contains all values. */
/** refresh or update the values of the image that triangleContains all values. */
void filterImage();
void clear();
......
......@@ -30,7 +30,7 @@
//
//
///**
// * This class contains tests that test both Voronoi-Implementation (the JTS-Version and our own
// * This class triangleContains tests that test both Voronoi-Implementation (the JTS-Version and our own
// * version).
// */
//public class TestVoronoiDensityProcessors {
......
......@@ -16,7 +16,7 @@ package org.vadere.state.attributes;
* VPoint,...).
*
* The standard clone method makes a flat copy. This is enough if the subclass
* only contains immutable fields. If the subclass contains other Attributes
* only triangleContains immutable fields. If the subclass triangleContains other Attributes
* objects, it must implement a copy constructor and override {@link #clone()}
* to make a deep copy.
*
......
......@@ -243,9 +243,9 @@ public class Table implements Iterable<Row> {
}
/**
* Returns true if this table contains no elements.
* Returns true if this table triangleContains no elements.
*
* @return true if this table contains no elements
* @return true if this table triangleContains no elements
*/
public boolean isEmpty() {
return columns() == 0 || size() == 0 || getEntry(getColumnNames()[0], 0) == null;
......
......@@ -7,6 +7,8 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.vadere.util.geometry.shapes.IPoint;
import org.vadere.util.geometry.shapes.VCircle;
import org.vadere.util.geometry.shapes.VLine;
......@@ -23,6 +25,8 @@ public class GeometryUtils {
*/
public static final double DOUBLE_EPS = 1e-8;
public static final Logger log = LogManager.getLogger(GeometryUtils.class);
/**
* Interpolates between start and end with the given factor.
*/
......@@ -42,6 +46,23 @@ public class GeometryUtils {
return false;
}
public static VPoint getCircumcenter(final IPoint p1, final IPoint p2, final IPoint p3) {
double d = 2 * (p1.getX() * (p2.getY() - p3.getY()) + p2.getX() * (p3.getY() - p1.getY()) + p3.getX() * (p1.getY() - p2.getY()));
double x = ((p1.getX() * p1.getX() + p1.getY() * p1.getY()) * (p2.getY() - p3.getY())
+ (p2.getX() * p2.getX() + p2.getY() * p2.getY()) * (p3.getY() - p1.getY())
+ (p3.getX() * p3.getX() + p3.getY() * p3.getY()) * (p1.getY() - p2.getY())) / d;
double y = ((p1.getX() * p1.getX() + p1.getY() * p1.getY()) * (p3.getX() - p2.getX())
+ (p2.getX() * p2.getX() + p2.getY() * p2.getY()) * (p1.getX() - p3.getX())
+ (p3.getX() * p3.getX() + p3.getY() * p3.getY()) * (p2.getX() - p1.getX())) / d;
return new VPoint(x,y);
}
public static boolean isInCircumscribedCycle(final IPoint p1, final IPoint p2, final IPoint p3, final IPoint point) {
VPoint circumcenter = getCircumcenter(p1, p2, p3);
return circumcenter.distance(point) < circumcenter.distance(p1);
}
/**
* Computes the point on the line segment that is closest to the given point
* point. from:
......@@ -93,11 +114,6 @@ public class GeometryUtils {
/**
* Computes area (it maybe a negative area) of the parallelogram defined by p, q, r.
* Note: + This area is zero if p, q, r lie on one line.
* + The area is < 0 if the points p, q, r are aligned clockwise (order matters).
* This is equivalent to: r lies on the right side of the line defined by p, q.
* + The area is > 0 if the points p, q, r are aligned counter-clockwise (order matters).
* This is equivalent to: r lies on the left side of the line defined by p, q.
*
* @param pX x-coordinate of p
* @param pY y-coordinate of p
......@@ -108,7 +124,37 @@ public class GeometryUtils {
* @return
*/
public static double ccw(final double qX, final double qY, final double pX, final double pY, final double rX, final double rY) {
return (qX - pX) * (rY - pY) - (rX - pX) * (qY - pY);
return -((qX - pX) * (rY - pY) - (rX - pX) * (qY - pY));
}
/**
* Returns true if q is right of the oriented-line defined by (p1, p2).
* @param p1
* @param p2
* @param q
* @return true if q is right of the oriented-line defined by (p1, p2), false otherwise
*/
public static boolean isRightOf(final IPoint p1, final IPoint p2, final IPoint q) {
return isRightOf(p1, p2, q.getX(), q.getY());
}
/**
* Returns true if q is left of the oriented-line defined by (p1, p2).
* @param p1
* @param p2
* @param q
* @return true if q is right of the oriented-line defined by (p1, p2), false otherwise
*/
public static boolean isLeftOf(final IPoint p1, final IPoint p2, final IPoint q) {
return isLeftOf(p1, p2, q.getX(), q.getY());
}
public static boolean isRightOf(final IPoint p1, final IPoint p2, final double x, final double y) {
return isCW(p1.getX(), p1.getY(), p2.getX(), p2.getY(), x, y);
}
public static boolean isLeftOf(final IPoint p1, final IPoint p2, final double x, final double y) {
return isCCW(p1.getX(), p1.getY(), p2.getX(), p2.getY(), x, y);
}
/**
......@@ -134,7 +180,7 @@ public class GeometryUtils {
}
public static boolean isCCW(final IPoint p1, final IPoint p2, final IPoint p3) {
return ccw(p1, p2, p3) > 0;
return isCCW(p1.getX(), p1.getY(), p2.getX(), p2.getY(), p3.getX(), p3.getY());
}
public static boolean isCW(final double qX, final double qY, final double pX, final double pY, final double rX, final double rY) {
......@@ -201,9 +247,9 @@ public class GeometryUtils {
* @param p2 point of the triangle
* @param p3 point of the triangle
* @param r point which the triangle might contain.
* @return if the triangle (p1,p2,p3) contains the point r, otherwise false.
* @return true if the triangle (p1,p2,p3) contains the point r, otherwise false.
*/
public static boolean contains(final IPoint p1, final IPoint p2, final IPoint p3, final IPoint r) {
public static boolean triangleContains(final IPoint p1, final IPoint p2, final IPoint p3, final IPoint r) {
boolean b1, b2, b3;
double d1 = GeometryUtils.ccw(r, p1, p2);
double d2 = GeometryUtils.ccw(r, p2, p3);
......@@ -214,6 +260,54 @@ public class GeometryUtils {
return ((b1 == b2) && (b2 == b3));
}
/**
* Tests if the circle defined by three non-lin points (p1,p2,p3) contains the point r.
* The center of the circle is the circumcenter of the triangle and the radius is equalt to the
* distance between the circumcenter and any point of {p1, p2, p3}.
*
* @param a point of the triangle
* @param b point of the triangle
* @param c point of the triangle
* @param p point which the circle might contain.
* @return true, if the circle defined by three non-lin points (p1,p2,p3) contains the point r, otherwise false
*/
public static boolean isInsideCircle(final IPoint a, final IPoint b, final IPoint c, final IPoint p) {
return isInsideCircle(a, b, c, p.getX(), p.getY());
}
public static boolean isInsideCircle(final IPoint a, final IPoint b, final IPoint c, double x , double y) {
/*IPoint qp = q.subtract(p);
IPoint rp = r.subtract(p);
IPoint tp = t.subtract(p);
double a = qp.getX() * tp.getY() - qp.getY() * tp.getX();
double b = tp.getX() * (t.getX() - q.getX()) + tp.getY() * (t.getY() - q.getY());
double c = qp.getX() * rp.getY() - qp.getY() * rp.getX();
double d = rp.getX() * (r.getX() - q.getX()) + rp.getY() * (r.getY() - q.getY());
return a * d > c * b;*/
double adx = a.getX() - x;
double ady = a.getY() - y;
double bdx = b.getX() - x;
double bdy = b.getY() - y;
double cdx = c.getX() - x;
double cdy = c.getY() - y;
double abdet = adx * bdy - bdx * ady;
double bcdet = bdx * cdy - cdx * bdy;
double cadet = cdx * ady - adx * cdy;
double alift = adx * adx + ady * ady;
double blift = bdx * bdx + bdy * bdy;
double clift = cdx * cdx + cdy * cdy;
double disc = alift * bcdet + blift * cadet + clift * abdet;
//log.info("inCicle = " + disc);
return disc > 0;
}
/**
* Computes the cross product of two vectors and store it in the cross
* vector.
......@@ -282,6 +376,38 @@ public class GeometryUtils {
return Math.abs(result) / 2.0;
}
/**
* Computes the distance from the line-segment defined by (p1,p2) to the point p.
* @param p1 first point of the line-segment
* @param p2 second point of the line-segment
* @param p the point
* @return he distance from the line-segment defined by (p1,p2) to the point p.
*/
public static double distanceToLineSegment(final IPoint p1, final IPoint p2, final IPoint p) {
return distanceToLineSegment(p1, p2, p.getX(), p.getY());
}
public static double distanceToLineSegment(final IPoint p1, final IPoint p2, final double x, final double y) {
if (p1.getX() == p2.getX() && p1.getY() == p2.getY())
return p1.distance(x,y);
double len2 = (p2.getX() - p1.getX()) * (p2.getX() - p1.getX()) + (p2.getY() - p1.getY()) * (p2.getY() - p1.getY());
double r = ((x - p1.getX()) * (p2.getX() - p1.getX()) + (y - p1.getY()) * (p2.getY() - p1.getY())) / len2;
if (r <= 0.0)
return p1.distance(x,y);
if (r >= 1.0)
return p2.distance(x,y);
double s = ((p1.getY() - y) * (p2.getX() - p1.getX()) - (p1.getX() - x) * (p2.getY() - p1.getY())) / len2;
return Math.abs(s) * Math.sqrt(len2);
}
public static boolean isOnEdge(final IPoint p1, final IPoint p2, final IPoint p, double tolerance) {
return distanceToLineSegment(p1, p2, p) < tolerance;
}
/**
* Computes the intersection points of a line and a circle. The line is supposed to have infinity
* length and is defined by the two points of the VLine.
......
......@@ -85,7 +85,7 @@ public class LinkedCellsGrid<T> implements Iterable<T> {
private double[] cellSize = new double[2];
/**
* One cell in the grid. It contains a mapping from points to lists of
* One cell in the grid. It triangleContains a mapping from points to lists of
* objects. This means that one can store multiple objects in one cell.
*
*
......@@ -362,7 +362,7 @@ public class LinkedCellsGrid<T> implements Iterable<T> {
}
/**
* Tests whether the linked cells grid contains an object that equals(the
* Tests whether the linked cells grid triangleContains an object that equals(the
* given object). The complexity of this operation is O(N), N = number of
* objects in the grid.
*
......
......@@ -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();
}
}
......@@ -7,10 +7,12 @@ import org.vadere.util.geometry.GeometryUtils;
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.impl.PVertex;
import org.vadere.util.geometry.mesh.iterators.EdgeIterator;
import org.vadere.util.geometry.mesh.iterators.AdjacentFaceIterator;
import org.vadere.util.geometry.mesh.iterators.IncidentEdgeIterator;
import org.vadere.util.geometry.mesh.iterators.SurroundingFaceIterator;
import org.vadere.util.geometry.mesh.iterators.VertexIterator;
import org.vadere.util.geometry.shapes.IPoint;
import org.vadere.util.geometry.shapes.VPoint;
import org.vadere.util.geometry.shapes.VPolygon;
......@@ -39,22 +41,37 @@ import java.util.stream.StreamSupport;
* @param <E> the type of the half-edges
* @param <F> the type of the faces
*/
public interface IMesh<P extends IPoint, E extends IHalfEdge<P>, F extends IFace<P>> extends Iterable<F> {
public interface IMesh<P extends IPoint, V extends IVertex<P>, E extends IHalfEdge<P>, F extends IFace<P>> extends Iterable<F> {
E getNext(@NotNull E halfEdge);
E getPrev(@NotNull E halfEdge);
E getTwin(@NotNull E halfEdge);
F getFace(@NotNull E halfEdge);
E getEdge(@NotNull P vertex);
E getEdge(@NotNull V vertex);
E getEdge(@NotNull F face);
P getVertex(@NotNull E halfEdge);
P getPoint(@NotNull E halfEdge);