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 { ...@@ -46,7 +46,7 @@ public interface IGaussianFilter {
void setInputValue(final int x, final int y, final double value); 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 filterImage();
void clear(); void clear();
......
...@@ -30,7 +30,7 @@ ...@@ -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). // * version).
// */ // */
//public class TestVoronoiDensityProcessors { //public class TestVoronoiDensityProcessors {
......
...@@ -16,7 +16,7 @@ package org.vadere.state.attributes; ...@@ -16,7 +16,7 @@ package org.vadere.state.attributes;
* VPoint,...). * VPoint,...).
* *
* The standard clone method makes a flat copy. This is enough if the subclass * 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()} * objects, it must implement a copy constructor and override {@link #clone()}
* to make a deep copy. * to make a deep copy.
* *
......
...@@ -243,9 +243,9 @@ public class Table implements Iterable<Row> { ...@@ -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() { public boolean isEmpty() {
return columns() == 0 || size() == 0 || getEntry(getColumnNames()[0], 0) == null; return columns() == 0 || size() == 0 || getEntry(getColumnNames()[0], 0) == null;
......
...@@ -7,6 +7,8 @@ import java.util.Collection; ...@@ -7,6 +7,8 @@ import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; 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.IPoint;
import org.vadere.util.geometry.shapes.VCircle; import org.vadere.util.geometry.shapes.VCircle;
import org.vadere.util.geometry.shapes.VLine; import org.vadere.util.geometry.shapes.VLine;
...@@ -23,6 +25,8 @@ public class GeometryUtils { ...@@ -23,6 +25,8 @@ public class GeometryUtils {
*/ */
public static final double DOUBLE_EPS = 1e-8; 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. * Interpolates between start and end with the given factor.
*/ */
...@@ -42,6 +46,23 @@ public class GeometryUtils { ...@@ -42,6 +46,23 @@ public class GeometryUtils {
return false; 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 * Computes the point on the line segment that is closest to the given point
* point. from: * point. from:
...@@ -93,11 +114,6 @@ public class GeometryUtils { ...@@ -93,11 +114,6 @@ public class GeometryUtils {
/** /**
* Computes area (it maybe a negative area) of the parallelogram defined by p, q, r. * 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 pX x-coordinate of p
* @param pY y-coordinate of p * @param pY y-coordinate of p
...@@ -108,7 +124,37 @@ public class GeometryUtils { ...@@ -108,7 +124,37 @@ public class GeometryUtils {
* @return * @return
*/ */
public static double ccw(final double qX, final double qY, final double pX, final double pY, final double rX, final double rY) { 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 { ...@@ -134,7 +180,7 @@ public class GeometryUtils {
} }
public static boolean isCCW(final IPoint p1, final IPoint p2, final IPoint p3) { 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) { 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 { ...@@ -201,9 +247,9 @@ public class GeometryUtils {
* @param p2 point of the triangle * @param p2 point of the triangle
* @param p3 point of the triangle * @param p3 point of the triangle
* @param r point which the triangle might contain. * @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; boolean b1, b2, b3;
double d1 = GeometryUtils.ccw(r, p1, p2); double d1 = GeometryUtils.ccw(r, p1, p2);
double d2 = GeometryUtils.ccw(r, p2, p3); double d2 = GeometryUtils.ccw(r, p2, p3);
...@@ -214,6 +260,54 @@ public class GeometryUtils { ...@@ -214,6 +260,54 @@ public class GeometryUtils {
return ((b1 == b2) && (b2 == b3)); 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 * Computes the cross product of two vectors and store it in the cross
* vector. * vector.
...@@ -282,6 +376,38 @@ public class GeometryUtils { ...@@ -282,6 +376,38 @@ public class GeometryUtils {
return Math.abs(result) / 2.0; 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 * 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. * length and is defined by the two points of the VLine.
......
...@@ -85,7 +85,7 @@ public class LinkedCellsGrid<T> implements Iterable<T> { ...@@ -85,7 +85,7 @@ public class LinkedCellsGrid<T> implements Iterable<T> {
private double[] cellSize = new double[2]; 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. * objects. This means that one can store multiple objects in one cell.
* *
* *
...@@ -362,7 +362,7 @@ public class LinkedCellsGrid<T> implements Iterable<T> { ...@@ -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 * given object). The complexity of this operation is O(N), N = number of
* objects in the grid. * objects in the grid.
* *
......
...@@ -11,7 +11,7 @@ public class PHalfEdge<P extends IPoint> implements IHalfEdge<P> { ...@@ -11,7 +11,7 @@ public class PHalfEdge<P extends IPoint> implements IHalfEdge<P> {
/** /**
* point at the end of the half edge. * point at the end of the half edge.
*/ */
private P end; private PVertex<P> end;
/** /**
* next half-edge around the face. * next half-edge around the face.
...@@ -35,12 +35,12 @@ public class PHalfEdge<P extends IPoint> implements IHalfEdge<P> { ...@@ -35,12 +35,12 @@ public class PHalfEdge<P extends IPoint> implements IHalfEdge<P> {
private PFace<P> face; 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.end = end;
this.face = face; this.face = face;
} }
PHalfEdge(@NotNull final P end) { PHalfEdge(@NotNull final PVertex<P> end) {
this.end = end; this.end = end;
this.face = null; this.face = null;
} }
...@@ -53,7 +53,7 @@ public class PHalfEdge<P extends IPoint> implements IHalfEdge<P> { ...@@ -53,7 +53,7 @@ public class PHalfEdge<P extends IPoint> implements IHalfEdge<P> {
this.face = face; this.face = face;
} }
P getEnd() { PVertex<P> getEnd() {
return end; return end;
} }
...@@ -116,7 +116,7 @@ public class PHalfEdge<P extends IPoint> implements IHalfEdge<P> { ...@@ -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; this.end = end;
} }
......
...@@ -11,17 +11,18 @@ import java.util.HashSet; ...@@ -11,17 +11,18 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
/** /**
* @author Benedikt Zoennchen * @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 List<PFace<P>> faces;
private PFace<P> boundary; private PFace<P> boundary;
private List<PHalfEdge<P>> edges; private List<PHalfEdge<P>> edges;
private IPointConstructor<P> pointConstructor; private IPointConstructor<P> pointConstructor;
private Set<P> vertices; private Set<PVertex<P>> vertices;
public PMesh(final IPointConstructor<P> pointConstructor) { public PMesh(final IPointConstructor<P> pointConstructor) {
this.faces = new ArrayList<>(); this.faces = new ArrayList<>();
...@@ -48,13 +49,13 @@ public class PMesh<P extends IPoint> implements IMesh<P, PHalfEdge<P>, PFace<P>> ...@@ -48,13 +49,13 @@ public class PMesh<P extends IPoint> implements IMesh<P, PHalfEdge<P>, PFace<P>>
} }
@Override @Override
public PFace<P> getFace(final PHalfEdge<P> halfEdge) { public PFace<P> getFace(@NotNull final PHalfEdge<P> halfEdge) {
return halfEdge.getFace(); return halfEdge.getFace();
} }
@Override @Override
public PHalfEdge<P> getEdge(@NotNull P vertex) { public PHalfEdge<P> getEdge(@NotNull PVertex<P> vertex) {
return null; return vertex.getEdge();
} }
@Override @Override
...@@ -63,10 +64,20 @@ public class PMesh<P extends IPoint> implements IMesh<P, PHalfEdge<P>, PFace<P>> ...@@ -63,10 +64,20 @@ public class PMesh<P extends IPoint> implements IMesh<P, PHalfEdge<P>, PFace<P>>
} }
@Override @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(); return halfEdge.getEnd();
} }
@Override
public P getPoint(@NotNull PVertex<P> vertex) {
return vertex.getPoint();
}
@Override @Override
public PFace<P> getFace() { public PFace<P> getFace() {
return faces.stream().filter(face -> !face.isDestroyed()).findAny().get(); 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>> ...@@ -118,22 +129,22 @@ public class PMesh<P extends IPoint> implements IMesh<P, PHalfEdge<P>, PFace<P>>
} }
@Override @Override
public void setEdge(@NotNull P vertex, @NotNull PHalfEdge<P> edge) { public void setEdge(@NotNull PVertex<P> vertex, @NotNull PHalfEdge<P> edge) {
throw new UnsupportedOperationException("not jet implemented."); vertex.setEdge(edge);
} }
@Override @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); halfEdge.setEnd(vertex);
} }
@Override @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()); return edges.stream().filter(edge -> !edge.isValid()).filter(edge -> getVertex(edge).equals(vertex)).collect(Collectors.toList());
} }
@Override @Override
public Collection<P> getVertices() { public Collection<PVertex<P>> getVertices() {
return vertices; return vertices;
} }
...@@ -148,14 +159,14 @@ public class PMesh<P extends IPoint> implements IMesh<P, PHalfEdge<P>, PFace<P>> ...@@ -148,14 +159,14 @@ public class PMesh<P extends IPoint> implements IMesh<P, PHalfEdge<P>, PFace<P>>
} }
@Override @Override
public PHalfEdge<P> createEdge(@NotNull P vertex) { public PHalfEdge<P> createEdge(@NotNull PVertex<P> vertex) {
PHalfEdge<P> edge = new PHalfEdge<>(vertex); PHalfEdge<P> edge = new PHalfEdge<>(vertex);
edges.add(edge); edges.add(edge);
return edge; return edge;
} }
@Override @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); PHalfEdge<P> edge = new PHalfEdge<>(vertex, face);
edges.add(edge); edges.add(edge);
return edge; return edge;
...@@ -179,10 +190,20 @@ public class PMesh<P extends IPoint> implements IMesh<P, PHalfEdge<P>, PFace<P>> ...@@ -179,10 +190,20 @@ public class PMesh<P extends IPoint> implements IMesh<P, PHalfEdge<P>, PFace<P>>
} }
@Override @Override
public P createVertex(double x, double y) { public P createPoint(double x, double y) {
P vertex = pointConstructor.create(x, y); return pointConstructor.create(x, y);
//vertices.add(vertex); }
return vertex;
// 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);
}