Commit 89c47fd2 authored by Benedikt Zoennchen's avatar Benedikt Zoennchen

before new data structure for triangles

parent bfc21eb5
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;
}
}
}
package org.vadere.util.triangulation;
package org.vadere.util.geometry.data;
import org.apache.commons.lang3.tuple.Triple;
import org.vadere.util.geometry.data.Face;
......
......@@ -102,6 +102,10 @@ public class Face<P extends IPoint> implements Iterable<HalfEdge<P>> {
destroyed = true;
}
public void toBorder() {
border = true;
}
/**
* Sets one of the half-edges bordering this face.
*
......@@ -211,7 +215,7 @@ public class Face<P extends IPoint> implements Iterable<HalfEdge<P>> {
@Override
public boolean hasNext() {
return currentHalfEdge != null && (!started || !currentHalfEdge.equals(edge));
return !started || !currentHalfEdge.equals(edge);
}
@Override
......
package org.vadere.util.triangulation;
package org.vadere.util.geometry.data;
import org.vadere.util.geometry.data.Face;
import org.vadere.util.geometry.data.HalfEdge;
......@@ -51,7 +51,7 @@ public class FaceIterator<P extends IPoint> implements Iterator<Face<P>> {
for(HalfEdge<P> he : nextFace) {
Face<P> twinFace = he.getTwin().getFace();
if(twinFace.isBorder() || twinFace.isDestroyed() || !facePredicate.test(twinFace)) {
if(twinFace.isBorder() || twinFace.isDestroyed() || !facePredicate.test(twinFace)) {
visitedFaces.add(twinFace);
}
......
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> extends Iterable<Face<P>> {
void compute();
Face<P> locate(final double x, final double y);
Face<P> locate(final IPoint point);
Stream<Face<P>> streamFaces();
Set<Face<P>> getFaces();
HalfEdge<P> insert(final P point);
void remove(final P point);
}
......@@ -25,6 +25,7 @@ import javax.swing.*;
* This class is for computing the DelaunayTriangulation using the BowyerWatson-Algorithm. In average the algorithm should perfom in O(n LOG(n)) but
* in degenerated cases its runtime can be in O(n^2) where n is the number of points.
*/
@Deprecated
public class BowyerWatson3 {
private List<VTriangle> triangles;
private Collection<VPoint> points;
......
......@@ -25,6 +25,7 @@ import java.util.stream.Stream;
* This class is for computing the DelaunayTriangulation using the BowyerWatson-Algorithm. In average the algorithm should perfom in O(n log(n)) but
* in degenerated cases its runtime can be in O(n^2) where n is the number of points.
*/
@Deprecated
public class BowyerWatsonSlow<P extends IPoint> {
private List<Triple<P, P, P>> triangles;
private Collection<P> points;
......
package org.vadere.util.triangulation;
import org.vadere.util.geometry.mesh.inter.IFace;
import org.vadere.util.geometry.mesh.inter.IHalfEdge;
import org.vadere.util.geometry.mesh.ITriConnectivity;
import org.vadere.util.geometry.data.Face;
import org.vadere.util.geometry.data.HalfEdge;
import org.vadere.util.geometry.shapes.IPoint;
import java.util.Set;
import java.util.stream.Stream;
public interface ITriangulation<P extends IPoint, E extends IHalfEdge<P>, F extends IFace<P>> extends Iterable<F>, ITriConnectivity<P, E, F> {
public interface ITriangulation<P extends IPoint> extends Iterable<Face<P>> {
void compute();
Stream<F> streamFaces();
Set<F> getFaces();
E insert(final P point);
Face<P> locate(final double x, final double y);
Face<P> locate(final IPoint point);
Stream<Face<P>> streamFaces();
Set<Face<P>> getFaces();
HalfEdge<P> insert(final P point);
void remove(final P point);
}
package org.vadere.util.triangulation;
import org.vadere.util.geometry.shapes.IPoint;
@FunctionalInterface
public interface PointConstructor<P extends IPoint> {
P create(double x, double y);
}
package org.vadere.util.triangulation;
import org.vadere.util.geometry.shapes.IPoint;
import org.vadere.util.geometry.shapes.VTriangle;
@FunctionalInterface
public interface TriangleConstructor<P extends IPoint> {
VTriangle create(P p1, P p2, P p3);
}
package org.vadere.util.triangulation;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.vadere.util.geometry.FixPointGenerator;
import org.vadere.util.geometry.data.Face;
import org.vadere.util.geometry.data.HalfEdge;
import org.vadere.util.geometry.shapes.IPoint;
import org.vadere.util.geometry.shapes.VLine;
import org.vadere.util.geometry.shapes.VPoint;
import org.vadere.util.geometry.shapes.VRectangle;
import org.vadere.util.geometry.shapes.VShape;
import org.vadere.util.geometry.shapes.VTriangle;
import org.vadere.util.triangulation.adaptive.IEdgeLengthFunction;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
* @author Benedikt Zoennchen
*
* @param <P>
*/
public class UniformRefinementTriangulation<P extends IPoint> {
private final Collection<VShape> boundary;
private final VRectangle bbox;
private final IEdgeLengthFunction lenFunc;
private final Set<HalfEdge<P>> refinedEdges;
private int splitCount;
private IncrementalTriangulation<P> triangulation;
private IPointConstructor<P> pointConstructor;
private Set<P> points;
private static final Logger logger = LogManager.getLogger(UniformRefinementTriangulation.class);
public UniformRefinementTriangulation(
final double minX,
final double minY,
final double width,
final double height,
final IPointConstructor<P> pointConstructor,
final Collection<VShape> boundary,
final IEdgeLengthFunction lenFunc) {
//Predicate<HalfEdge<P>> isIllegal = edge -> IncrementalTriangulation.isIllegalEdge(edge) && !flipEdgeCrossBoundary(edge);
this.triangulation = new IncrementalTriangulation<>(minX, minY, width, height, pointConstructor);
this.boundary = boundary;
this.pointConstructor = pointConstructor;
this.lenFunc = lenFunc;
this.bbox = new VRectangle(minX, minY, width, height);
this.refinedEdges = new HashSet<>();
this.points = new HashSet<>();
this.splitCount = 0;
}
public boolean isCompleted(final HalfEdge<P> edge) {
VTriangle triangle = edge.isBoundary() ? edge.getTwin().getFace().toTriangle() : edge.getFace().toTriangle();
//System.out.println(bbox.distance(triangle.midPoint()));
return !bbox.intersect(triangle) || boundary.stream().anyMatch(shape -> shape.contains(triangle.getBounds2D())) || edge.getEnd().distance(edge.getPrevious().getEnd()) <= lenFunc.apply(midPoint(edge));
}
public void compute() {
logger.info("start computation");
int count = 0;
LinkedList<HalfEdge<P>> toRefineEdges = new LinkedList<>();
List<HalfEdge<P>> edges = triangulation.superTriangle.getEdges();
for(HalfEdge<P> edge : edges) {
if(!isCompleted(edge) && !points.contains(edge.getEnd())) {
toRefineEdges.add(edge);
}
}
while (!toRefineEdges.isEmpty()) {
HalfEdge<P> edge = toRefineEdges.removeFirst();
count++;
for(HalfEdge<P> refinedHalfEdges : refine(edge)) {
if(!isCompleted(refinedHalfEdges)) {
toRefineEdges.addLast(refinedHalfEdges);
}
}
}
for(VShape shape : boundary) {
count = 0;
// 1. find a trinagle inside the boundary
Face<P> face = triangulation.locate(shape.getCentroid());
if(face != null) {
// 2. build a border-face: delete edges as long as they are inside the boundary
//face.toBorder();
boolean changed = true;
HalfEdge<P> startEdge = face.getEdge();
HalfEdge<P> edge = null;
while (!startEdge.equals(edge)) {
if (edge == null) {
edge = startEdge;
}
boolean eqNext = edge.getTwin().getFace().equals(edge.getNext().getTwin().getFace());
boolean eqPrev = edge.getTwin().getFace().equals(edge.getPrevious().getTwin().getFace());
if (eqNext || eqPrev) {
HalfEdge<P> h0 = eqNext ? edge : edge.getPrevious();
if (shape.intersects(h0.toLine()) || shape.intersects(h0.getNext().toLine())) {
// change the face
HalfEdge<P> middleEdge = h0.getTwin().getNext();
middleEdge.setFace(face);
// build connectivity
h0.getPrevious().setNext(middleEdge);
h0.getNext().getNext().setPrevious(middleEdge);
// change the edge of the face since we might destroy it
face.setEdge(h0.getNext().getNext());
edge = h0.getNext().getNext();
startEdge = middleEdge;
// destroy
h0.getNext().getTwin().destroy();
h0.getNext().destroy();
h0.getFace().destroy();
h0.getTwin().destroy();
h0.destroy();
} else {
edge = edge.getNext();
}
} else if (shape.intersects(edge.toLine())) {
HalfEdge<P> twin = edge.getTwin();
HalfEdge<P> destroyEdge = edge;
// change the face
twin.getNext().setFace(face);
twin.getPrevious().setFace(face);
// build connectivity
edge.getPrevious().setNext(twin.getNext());
edge.getNext().setPrevious(twin.getPrevious());
startEdge = twin.getPrevious();
// change the edge of the face since we might destroy it
face.setEdge(edge.getNext());
edge = edge.getNext();
// destroy
twin.getFace().destroy();
destroyEdge.destroy();
twin.destroy();
} else {
edge = edge.getNext();
}
}
}
}
logger.info("end computation");
}
public Set<VLine> getEdges() {
return triangulation.getEdges();
}
public Collection<HalfEdge<P>> refine(final HalfEdge<P> edge) {
VPoint midPoint = midPoint(edge);
P p = pointConstructor.create(midPoint.getX(), midPoint.getY());
if(points.contains(p)) {
return Collections.emptyList();
}
else {
points.add(p);
splitCount++;
return triangulation.splitEdgeDB(p, edge);
}
}
private boolean flipEdgeCrossBoundary(final HalfEdge<P> edge) {
P p1 = edge.getNext().getEnd();
P p2 = edge.getTwin().getNext().getEnd();
for(VShape shape : boundary) {
if(shape.intersects(new VLine(new VPoint(p1), new VPoint(p2)))) {
return true;
}
}
return false;
}
private VPoint midPoint(final HalfEdge<P> edge) {
VPoint p1 = new VPoint(edge.getEnd());
VPoint p2 = new VPoint(edge.getPrevious().getEnd());
return p2.add(p1).scalarMultiply(0.5);
}
}
......@@ -9,21 +9,21 @@ import java.util.List;
import java.util.Set;
public class UniformTriangulation<P extends IPoint> extends DelaunayTriangulation<P>{
public class UniformTriangulation<P extends IPoint> extends IncrementalTriangulation<P> {
private double left;
private double top;
private double width;
private double height;
private double minTriangleSideLength;
private PointConstructor<P> pointConstructor;
private IPointConstructor<P> pointConstructor;
public UniformTriangulation(final double minX,
final double minY,
final double width,
final double height,
final double minTriangleSideLength,
final PointConstructor<P> pointConstructor) {
final IPointConstructor<P> pointConstructor) {
super(minX, minY, width, height, pointConstructor);
this.left = minX;
this.top = minY;
......@@ -31,13 +31,18 @@ public class UniformTriangulation<P extends IPoint> extends DelaunayTriangulatio
this.height = height;
this.minTriangleSideLength = minTriangleSideLength;
this.pointConstructor = pointConstructor;
}
@Override
public void compute() {
List<P> pointList = new ArrayList<>(generatePointSet());
Collections.shuffle(pointList);
for(P point : pointList) {
insert(point);
}
super.compute();
}
private Set<P> generatePointSet() {
......
......@@ -4,13 +4,12 @@ import org.apache.commons.lang3.tuple.Triple;
import org.junit.Before;
import org.junit.Test;
import org.vadere.util.geometry.data.DAG;
import org.vadere.util.geometry.data.DAGElement;
import org.vadere.util.geometry.data.Face;
import org.vadere.util.geometry.data.HalfEdge;
import org.vadere.util.geometry.shapes.VPoint;
import org.vadere.util.geometry.shapes.VTriangle;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
......@@ -42,7 +41,7 @@ public class TestBoyerWatson {
points.add(p6);
points.add(p5);
DelaunayTriangulation<VPoint> boyerWatsonImproved = new DelaunayTriangulation<>(points, (x, y) -> new VPoint(x, y));
IncrementalTriangulation<VPoint> boyerWatsonImproved = new IncrementalTriangulation<>(points, (x, y) -> new VPoint(x, y));
boyerWatsonImproved.compute();
boyerWatsonImproved.finalize();
......@@ -96,7 +95,7 @@ public class TestBoyerWatson {
Face<VPoint> face = Face.of(p1,p2,p3);
DAG<DAGElement<VPoint>> dag = new DAG<>(new DAGElement<>(face, Triple.of(p1,p2,p3)));
DelaunayTriangulation<VPoint> triangulation = new DelaunayTriangulation<>(points, (x, y) -> new VPoint(x, y));
IncrementalTriangulation<VPoint> triangulation = new IncrementalTriangulation<>(points, (x, y) -> new VPoint(x, y));
triangulation.splitTriangleDB(centerPoint, dag);
triangulation.finalize();
......@@ -120,7 +119,7 @@ public class TestBoyerWatson {
}
long ms = System.currentTimeMillis();
DelaunayTriangulation<VPoint> bw = new DelaunayTriangulation<>(points, (x, y) -> new VPoint(x, y));
IncrementalTriangulation<VPoint> bw = new IncrementalTriangulation<>(points, (x, y) -> new VPoint(x, y));
bw.compute();
System.out.println("runtime of the BowyerWatson for " + numberOfPoints + " vertices =" + (System.currentTimeMillis() - ms));
}
......
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