Currently job artifacts in CI/CD pipelines on LRZ GitLab never expire. Starting from Wed 26.1.2022 the default expiration time will be 30 days (GitLab default). Currently existing artifacts in already completed jobs will not be affected by the change. The latest artifacts for all jobs in the latest successful pipelines will be kept. More information: https://gitlab.lrz.de/help/user/admin_area/settings/continuous_integration.html#default-artifacts-expiration

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

before new data structure for triangles

parent 38b380fc
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,8 +4,7 @@ import org.vadere.util.geometry.shapes.VRectangle;
import org.vadere.util.geometry.shapes.VShape;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.*;
/**
......
......@@ -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