Commit 18c5286b authored by Benedikt Zoennchen's avatar Benedikt Zoennchen

refactoring of the triangulation code

parent b9421a8d
package org.vadere.util.delaunay;
public class GuibasDAC {
}
package org.vadere.util.geometry;
import org.vadere.util.geometry.shapes.IPoint;
import org.vadere.util.geometry.shapes.VLine;
import org.vadere.util.geometry.shapes.VPoint;
import java.awt.geom.Line2D;
import java.util.Iterator;
public class LineIterator implements Iterator<IPoint> {
private final Line2D.Double line;
private final double delta;
private VPoint startPoint;
private VPoint currentPoint;
private VPoint endPoint;
private VPoint deltaPoint;
private double slope;
private double lineLength;
private double dx;
private double dy;
private int counter;
private int numberOfSegments;
public LineIterator(final Line2D.Double line, final double delta) {
this.line = line;
if(line.getX1() < line.getX2()) {
startPoint = new VPoint(line.getX1(), line.getY1());
endPoint = new VPoint(line.getX2(), line.getY2());
}
else if(line.getX1() == line.getX2()) {
if(line.getY1() < line.getY2()) {
startPoint = new VPoint(line.getX1(), line.getY1());
endPoint = new VPoint(line.getX2(), line.getY2());
}
else if(line.getY1() > line.getY2()) {
startPoint = new VPoint(line.getX2(), line.getY2());
endPoint = new VPoint(line.getX1(), line.getY1());
}
else {
throw new IllegalArgumentException(line + " is not a feasible line.");
}
}
else {
startPoint = new VPoint(line.getX2(), line.getY2());
endPoint = new VPoint(line.getX1(), line.getY1());
}
lineLength = startPoint.distance(endPoint);
numberOfSegments = (int)Math.floor(lineLength / delta) - 3;
this.delta = lineLength / numberOfSegments;
if(line.getX1() == line.getX2()) {
dx = 0;
dy = this.delta;
slope = 0;
}
if(line.getY1() == line.getY2()) {
dx = this.delta;
dy = 0;
slope = 0;
}
if(line.getX1() != line.getX2() && line.getY1() != line.getY2()) {
double len = startPoint.distance(endPoint);
slope = new VLine(startPoint, endPoint).slope();
dx = Math.sqrt((this.delta * this.delta) / (1 + slope*slope));
dy = dx * slope;
}
deltaPoint = new VPoint(dx, dy);
currentPoint = null;
}
@Override
public boolean hasNext() {
return currentPoint == null || !currentPoint.equals(endPoint);
}
@Override
public IPoint next() {
// first point
if(currentPoint == null) {
counter++;
currentPoint = startPoint;
}
else if(counter < numberOfSegments) {
counter++;
currentPoint = currentPoint.add(deltaPoint);
} // last point
else {
currentPoint = endPoint;
}
if(slope != 0) {
// this is more accurate for slope != 0.
return new VPoint(currentPoint.getX(), startPoint.getY() + slope * (currentPoint.getX() - startPoint.getX()));
}
else {
return currentPoint;
}
}
}
......@@ -3,11 +3,16 @@ package org.vadere.util.geometry.data;
import org.jetbrains.annotations.NotNull;
import org.vadere.util.geometry.GeometryUtils;
import org.vadere.util.geometry.shapes.IPoint;
import org.vadere.util.geometry.shapes.MLine;
import org.vadere.util.geometry.shapes.VLine;
import org.vadere.util.geometry.shapes.VPoint;
import org.vadere.util.geometry.shapes.VPolygon;
import org.vadere.util.geometry.shapes.VTriangle;
import java.awt.geom.Path2D;
import java.util.Iterator;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
......@@ -19,6 +24,23 @@ import java.util.stream.StreamSupport;
*/
public class Face<P extends IPoint> implements Iterable<HalfEdge<P>> {
public static <P extends IPoint> Face<P> of(P p1, P p2, P p3) {
Face superTriangle = new Face();
HalfEdge edge1 = new HalfEdge(p1, superTriangle);
HalfEdge edge2 = new HalfEdge(p2, superTriangle);
HalfEdge edge3 = new HalfEdge(p3, superTriangle);
edge1.setNext(edge2);
edge2.setNext(edge3);
edge3.setNext(edge1);
superTriangle.setEdge(edge1);
return superTriangle;
}
public static <P extends IPoint> Face<P> getBorder(Class<P> p) {
return new Face<>();
}
/**
* One of the half-edges bordering this face.
*/
......@@ -40,18 +62,6 @@ public class Face<P extends IPoint> implements Iterable<HalfEdge<P>> {
*/
public Face() {}
public static <P extends IPoint> Face<P> of(P p1, P p2, P p3) {
Face superTriangle = new Face();
HalfEdge edge1 = new HalfEdge(p1, superTriangle);
HalfEdge edge2 = new HalfEdge(p2, superTriangle);
HalfEdge edge3 = new HalfEdge(p3, superTriangle);
edge1.setNext(edge2);
edge2.setNext(edge3);
edge3.setNext(edge1);
superTriangle.setEdge(edge1);
return superTriangle;
}
/**
* Sets one of the half-edges bordering this face.
* @param edge half-edge bordering this face
......@@ -60,6 +70,10 @@ public class Face<P extends IPoint> implements Iterable<HalfEdge<P>> {
this.edge = edge;
}
public HalfEdge<P> getEdge() {
return edge;
}
/**
* Computes the area of this face.
* @return the area of this face
......@@ -89,6 +103,19 @@ public class Face<P extends IPoint> implements Iterable<HalfEdge<P>> {
return new VPolygon(path2D);
}
public VTriangle toTriangle() {
List<HalfEdge<P>> edges = getEdges();
if(edges.size() != 3) {
throw new IllegalArgumentException("this face is not a feasible triangle.");
}
else {
VPoint p1 = new VPoint(edges.get(0).getEnd().getX(), edges.get(0).getEnd().getY());
VPoint p2 = new VPoint(edges.get(1).getEnd().getX(), edges.get(1).getEnd().getY());
VPoint p3 = new VPoint(edges.get(2).getEnd().getX(), edges.get(2).getEnd().getY());
return new VTriangle(p1, p2, p3);
}
}
@Override
public Iterator<HalfEdge<P>> iterator() {
return new HalfEdgeIterator();
......@@ -103,6 +130,10 @@ public class Face<P extends IPoint> implements Iterable<HalfEdge<P>> {
return stream().collect(Collectors.toList());
}
public Stream<MLine<P>> streamLines() {
return stream().map(halfEdge -> new MLine(halfEdge.getPrevious().getEnd(), halfEdge.getEnd()));
}
public Stream<P> streamPoints() {
return stream().map(edge -> edge.getEnd());
}
......
package org.vadere.util.geometry.data;
import org.vadere.util.geometry.shapes.IPoint;
import java.util.Set;
import java.util.stream.Stream;
public interface Triangulation<P extends IPoint> {
Face<P> locate(P point);
Stream<Face<P>> streamFaces();
Set<Face<P>> getFaces();
void insert(P point);
void remove(P point);
}
package org.vadere.util.triangulation.adaptive;
import org.vadere.util.geometry.shapes.VLine;
import org.vadere.util.geometry.shapes.VPoint;
public class MLine {
public final MPoint p1;
public final MPoint p2;
private VPoint velocity;
public MLine(MPoint p1, MPoint p2) {
this.p1 = p1;
this.p2 = p2;
this.velocity = new VPoint(0,0);
}
public double length() {
return toVLine().length();
}
public VLine toVLine() {
return new VLine(p1.getX(), p1.getY(), p2.getX(), p2.getY());
}
public double getX1() {
return p1.getX();
}
public double getY1() {
return p1.getY();
}
public double getX2() {
return p2.getX();
}
public double getY2() {
return p2.getY();
}
public MPoint getP1() {
return p1;
}
public MPoint getP2() {
return p2;
}
public void setVelocity(final VPoint velocity) {
this.velocity = velocity;
}
public VPoint getVelocity() {
return velocity;
}
public VPoint midPoint() {
return new VPoint((p1.getX() + p2.getX()) / 2, (p1.getY() + p2.getY()) / 2);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MLine that = (MLine) o;
return (p1.equals(that.p1) && p2.equals(that.p2)) || (p2.equals(that.p1) && p1.equals(that.p2));
}
@Override
public int hashCode() {
int result = p1.hashCode();
result = 31 * result * p2.hashCode();
return result;
}
}
package org.vadere.util.triangulation.adaptive;
import org.vadere.util.geometry.shapes.IPoint;
import org.vadere.util.geometry.shapes.VPoint;
public class MPoint implements IPoint {
private boolean fixPoint;
private VPoint point;
private IPoint velocity;
public MPoint(final double x, final double y, boolean fixPoint){
this.point = new VPoint(x, y);
this.fixPoint = fixPoint;
this.velocity = new VPoint(0,0);
}
public MPoint(final double x, final double y, final int id){
this(x, y, false);
}
public VPoint toVPoint() {
return new VPoint(getX(), getY());
}
@Override
public double getX() {
return point.getX();
}
@Override
public double getY() {
return point.getY();
}
@Override
public MPoint add(final IPoint point) {
this.point = this.point.add(point);
return this;
}
@Override
public MPoint addPrecise(final IPoint point) {
this.point = this.point.addPrecise(point);
return this;
}
@Override
public MPoint subtract(IPoint point) {
this.point = this.point.subtract(point);
return this;
}
@Override
public MPoint multiply(IPoint point) {
this.point = this.point.multiply(point);
return this;
}
@Override
public MPoint scalarMultiply(double factor) {
this.point = this.point.scalarMultiply(factor);
return this;
}
@Override
public MPoint rotate(double radAngle) {
this.point = this.point.rotate(radAngle);
return this;
}
@Override
public double scalarProduct(IPoint point) {
return this.point.scalarProduct(point);
}
@Override
public MPoint norm() {
this.point = this.point.norm();
return this;
}
@Override
public MPoint normZeroSafe() {
this.point = this.point.normZeroSafe();
return this;
}
@Override
public int hashCode() {
// hashCode of java.awt.geom.Point2D
long bits = java.lang.Double.doubleToLongBits(getX());
bits ^= java.lang.Double.doubleToLongBits(getY()) * 31;
return (((int) bits) ^ ((int) (bits >> 32)));
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof MPoint))
return false;
MPoint other = (MPoint) obj;
if (this.getX() != other.getX())
return false;
if (this.getY() != other.getY())
return false;
return true;
}
@Override
public String toString() {
return point.toString();
}
@Override
public double distance(IPoint other) {
return point.distance(other);
}
@Override
public double distanceToOrigin() {
return this.point.distanceToOrigin();
}
public void increaseVelocity(final VPoint increase) {
this.velocity = this.velocity.add(increase);
}
public void decreaseVelocity(final VPoint decrease) {
this.velocity = this.velocity.subtract(decrease);
}
public void setVelocity(final VPoint velocity) {
this.velocity = velocity;
}
public IPoint getVelocity() {
return velocity;
}
public boolean isFixPoint() {
return fixPoint;
}
}
......@@ -32,11 +32,17 @@ public class TestBoyerWatson {
VPoint p3 = new VPoint(50, 50);
VPoint p4 = new VPoint(0, 50);
VPoint p6 = new VPoint(50, 50);
VPoint p5 = new VPoint(25, 25);
Arrays.asList(p1, p2, p3, p4, p5);
Set<VPoint> points = new HashSet<>();
points.add(p1);
points.add(p2);
points.add(p3);
points.add(p4);
points.add(p6);
BowyerWatson<VPoint> boyerWatsonImproved = new BowyerWatson<>(Arrays.asList(p1, p2, p3, p4, p5), (x, y) -> new VPoint(x, y), (a, b, c) -> new VTriangle(a, b, c));
BowyerWatson<VPoint> boyerWatsonImproved = new BowyerWatson<>(points, (x, y) -> new VPoint(x, y), (a, b, c) -> new VTriangle(a, b, c));
boyerWatsonImproved.init();
boyerWatsonImproved.execude();
Collection<VTriangle> triangulation = boyerWatsonImproved.getTriangles();
......@@ -50,10 +56,15 @@ public class TestBoyerWatson {
VPoint p3 = new VPoint(25, 25);
VPoint centerPoint = new VPoint(25, 10);
Set<VPoint> points = new HashSet<>();
points.add(p1);
points.add(p2);
points.add(p3);
Face<VPoint> face = Face.of(p1,p2,p3);
DAG<DAGElement<VPoint>> dag = new DAG<>(new DAGElement<>(face, Triple.of(p1,p2,p3), (a, b, c) -> new VTriangle(a, b, c)));
BowyerWatson<VPoint> boyerWatsonImproved = new BowyerWatson<>(Arrays.asList(p1, p2, p3), (x, y) -> new VPoint(x, y), (a, b, c) -> new VTriangle(a, b, c));
BowyerWatson<VPoint> boyerWatsonImproved = new BowyerWatson<>(points, (x, y) -> new VPoint(x, y), (a, b, c) -> new VTriangle(a, b, c));
DAG<DAGElement<VPoint>> result = boyerWatsonImproved.split(centerPoint, dag);
Set<VTriangle> triangulation = new HashSet<>(result.collectLeafs().stream().map(dagElement -> dagElement.getTriangle()).collect(Collectors.toList()));
Set<VTriangle> expectedResult = new HashSet<>(Arrays.asList(new VTriangle(p1, p2, centerPoint), new VTriangle(p2, p3, centerPoint), new VTriangle(p1, p3, centerPoint)));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment