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 2db821e0 authored by Benedikt Zoennchen's avatar Benedikt Zoennchen
Browse files

add adpative triangulation implementation

parent 43e77c48
package org.vadere.util.delaunay;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.ImmutableTriple;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.lang3.tuple.Triple;
import org.vadere.util.geometry.shapes.VCircle;
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.VTriangle;
import javax.swing.*;
import java.awt.*;
import java.util.*;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
/**
* @author Benedikt Zoennchen
*
* 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.
*/
public class BowyerWatson<P extends VPoint> {
private List<Triple<P, P, P>> triangles;
private Collection<P> points;
private List<P> initPoints;
private final BiFunction<Double, Double, P> pointConstructor;
public BowyerWatson(final Collection<P> points, final BiFunction<Double, Double, P> pointConstructor) {
this.points = points;
this.pointConstructor = pointConstructor;
}
public void execute() {
P max = points.parallelStream().reduce(pointConstructor.apply(Double.MIN_VALUE, Double.MIN_VALUE), (a, b) -> pointConstructor.apply(Math.max(a.getX(), b.getX()), Math.max(a.getY(), b.getY())));
P min = points.parallelStream().reduce(pointConstructor.apply(Double.MIN_VALUE, Double.MIN_VALUE), (a, b) -> pointConstructor.apply(Math.min(a.getX(), b.getX()), Math.min(a.getY(), b.getY())));
VRectangle bound = new VRectangle(min.getX(), min.getY(), max.getX()-min.getX(), max.getY()- min.getY());
init(bound);
points.stream().forEach(point -> handle(point));
cleanUp();
}
public List<Triple<P, P, P>> getTriangles() {
return triangles;
}
public List<VTriangle> getVTriangles() {
return triangles.stream().map(this::pointsToTriangle).collect(Collectors.toList());
}
public Set<VLine> getEdges() {
return triangles.parallelStream().flatMap(triangle -> Stream.of(new VTriangle(triangle.getLeft(), triangle.getMiddle(), triangle.getRight()).getLines())).collect(Collectors.toSet());
}
private void init(final VRectangle bound) {
triangles = new ArrayList<>();
initPoints = new ArrayList<>();
Triple<P, P, P> superTriangle = getSuperTriangle(bound);
triangles.add(superTriangle);
initPoints.add(superTriangle.getLeft());
initPoints.add(superTriangle.getMiddle());
initPoints.add(superTriangle.getRight());
}
private Triple<P, P, P> getSuperTriangle(final VRectangle bound) {
double gap = 1.0;
double max = Math.max(bound.getWidth(), bound.getHeight());
P p1 = pointConstructor.apply(bound.getX() - max - gap, bound.getY() - gap);
P p2 = pointConstructor.apply(bound.getX() + 2 * max + gap, bound.getY() - gap);
P p3 = pointConstructor.apply(bound.getX() + (max+2*gap)/2, bound.getY() + 2 * max+ gap);
return ImmutableTriple.of(p1, p2, p3);
}
private void handle(final P point) {
HashSet<Line> edges = new HashSet<>();
Map<Boolean, List<Triple<P, P, P>>> partition = triangles.parallelStream().collect(Collectors.partitioningBy(t -> pointsToTriangle(t).isInCircumscribedCycle(point)));
List<Triple<P, P, P>> badTriangles = partition.get(true);
triangles = partition.get(false);
IntStream s;
HashSet<Line> toRemove = new HashSet<>();
// duplicated edges
badTriangles.stream().flatMap(t -> getEdges(t).stream()).forEach(line -> {
if(!edges.add(line)) {
toRemove.add(line);
}
});
toRemove.stream().forEach(removeEdge -> edges.remove(removeEdge));
// identifier ?
edges.stream().forEach(edge -> triangles.add(Triple.of(edge.p1, edge.p2, point)));
}
private List<Line> getEdges(Triple<P, P, P> triangle) {
List<Line> list = new ArrayList<>();
list.add(new Line(triangle.getLeft(), triangle.getMiddle()));
list.add(new Line(triangle.getMiddle(), triangle.getRight()));
list.add(new Line(triangle.getRight(), triangle.getLeft()));
return list;
}
private void cleanUp() {
triangles = triangles.stream().filter(triangle -> !isTriangleConnectedToInitialPoints(triangle)).collect(Collectors.toList());
}
private boolean isTriangleConnectedToInitialPoints(final Triple<P, P, P> trianglePoints) {
return Stream.of(pointsToTriangle(trianglePoints).getLines()).anyMatch(edge -> {
VPoint p1 = new VPoint(edge.getP1().getX(), edge.getP1().getY());
VPoint p2 = new VPoint(edge.getP2().getX(), edge.getP2().getY());
return initPoints.stream().anyMatch(initPoint -> p1.equals(initPoint) || p2.equals(initPoint));
});
}
private VTriangle pointsToTriangle(Triple<P, P, P> points) {
return new VTriangle(points.getLeft(), points.getMiddle(), points.getRight());
}
private class Line {
final P p1;
final P p2;
private Line(P p1, P p2) {
this.p1 = p1;
this.p2 = p2;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Line line = (Line) o;
return (p1.equals(line.p1) && p2.equals(line.p2)) || (p2.equals(line.p1) && p1.equals(line.p2));
}
@Override
public int hashCode() {
return p1.hashCode() * p2.hashCode();
}
}
// TODO: the following code can be deleted, this is only for visual checks
public static void main(String[] args) {
// TODO Auto-generated method stub
int height = 1000;
int width = 1000;
int max = Math.max(height, width);
Set<VPoint> points = new HashSet<>();
/*points.add(new VPoint(20,20));
points.add(new VPoint(20,40));
points.add(new VPoint(75,53));
points.add(new VPoint(80,70));*/
Random r = new Random();
for(int i=0; i<10000; i++) {
VPoint point = new VPoint(width*r.nextDouble(), height*r.nextDouble());
points.add(point);
}
BowyerWatson<VPoint> bw = new BowyerWatson<VPoint>(points, (x, y) -> new VPoint(x, y));
bw.execute();
Set<VLine> edges = bw.getEdges();
JFrame window = new JFrame();
window.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
window.setBounds(0, 0, max, max);
window.getContentPane().add(new Lines(edges, points, max));
window.setVisible(true);
}
private static class Lines extends JComponent{
private Set<VLine> edges;
private Set<VPoint> points;
private final int max;
public Lines(final Set<VLine> edges, final Set<VPoint> points, final int max){
this.edges = edges;
this.points = points;
this.max = max;
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setBackground(Color.white);
g2.setStroke(new BasicStroke(1.0f));
g2.setColor(Color.gray);
edges.stream().forEach(edge -> {
Shape k = new VLine(edge.getP1().getX(), edge.getP1().getY(), edge.getP2().getX(), edge.getP2().getY());
g2.draw(k);
});
points.stream().forEach(point -> {
VCircle k = new VCircle(point.getX(), point.getY(), 1.0);
g2.draw(k);
});
}
}
public void removeTriangleIf(final Predicate<Triple<P, P, P>> predicate) {
triangles.removeIf(predicate);
}
}
...@@ -171,6 +171,10 @@ public class VTriangle extends VPolygon { ...@@ -171,6 +171,10 @@ public class VTriangle extends VPolygon {
return getCircumcenter().distance(point) < getCircumscribedRadius(); return getCircumcenter().distance(point) < getCircumscribedRadius();
} }
public boolean isInCircumscribedCycle(final VPoint point) {
return getCircumcenter().distance(point) < getCircumscribedRadius();
}
/** /**
* Computes the inward facing normal vector for the given points of the * Computes the inward facing normal vector for the given points of the
* triangle. * triangle.
...@@ -196,10 +200,6 @@ public class VTriangle extends VPolygon { ...@@ -196,10 +200,6 @@ public class VTriangle extends VPolygon {
return this.p1.equals(point) || this.p2.equals(point) || this.p3.equals(point); return this.p1.equals(point) || this.p2.equals(point) || this.p3.equals(point);
} }
public VLine[] getLines() {
return lines;
}
public Stream<VLine> getLineStream() { public Stream<VLine> getLineStream() {
return Arrays.stream(getLines()); return Arrays.stream(getLines());
} }
...@@ -215,4 +215,8 @@ public class VTriangle extends VPolygon { ...@@ -215,4 +215,8 @@ public class VTriangle extends VPolygon {
public String toString() { public String toString() {
return p1 + "-" + p2 + "-" + p3; return p1 + "-" + p2 + "-" + p3;
} }
public VLine[] getLines() {
return lines;
}
} }
package org.vadere.util.triangulation.adaptive;
import org.apache.commons.lang3.tuple.Pair;
import org.vadere.util.geometry.shapes.VLine;
public class IndexedVLine extends VLine {
private final IndexedVPoint p1;
private final IndexedVPoint p2;
public IndexedVLine(IndexedVPoint p1, IndexedVPoint p2) {
super(p1, p2);
this.p1 = p1;
this.p2 = p2;
}
@Override
public boolean equals(Object obj) {
if(obj == null) return false;
if(obj == this) return true;
if(obj.getClass() != getClass()) return false;
IndexedVLine line = (IndexedVLine) obj;
return line.getP1().equals(getP1()) && line.getP2().equals(getP2()) || line.getP2().equals(getP1()) && line.getP1().equals(getP2());
}
@Override
public int hashCode() {
return p1.hashCode() * p2.hashCode();
}
public Pair<Integer, Integer> getId() {
return Pair.of(p1.getId(), p2.getId());
}
}
package org.vadere.util.triangulation.adaptive;
import org.vadere.util.geometry.shapes.VPoint;
/**
* Created by bzoennchen on 10.11.16.
*/
public class IndexedVPoint extends VPoint {
private int id;
public IndexedVPoint(final VPoint point, final int id){
this(point.getX(), point.getY(), id);
}
public IndexedVPoint(final double x, final double y, final int id){
super(x, y);
this.id = id;
}
public IndexedVPoint subtract(VPoint point) {
return new IndexedVPoint(super.subtract(point), id);
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
...@@ -20,7 +20,7 @@ import java.util.*; ...@@ -20,7 +20,7 @@ import java.util.*;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class PSDistmesh { public class PSDistmesh {
private Set<MeshPoint> points = new HashSet<>(); private Set<MeshPoint> points = new HashSet<>();
private Set<MLine<MeshPoint>> lines = new HashSet<>(); private Set<MLine<MeshPoint>> lines = new HashSet<>();
private IncrementalTriangulation<MeshPoint, PHalfEdge<MeshPoint>, PFace<MeshPoint>> bowyerWatson; private IncrementalTriangulation<MeshPoint, PHalfEdge<MeshPoint>, PFace<MeshPoint>> bowyerWatson;
...@@ -96,7 +96,7 @@ public class PSDistmesh { ...@@ -96,7 +96,7 @@ public class PSDistmesh {
} }
public boolean hasMaximalSteps() { public boolean hasMaximalSteps() {
return steps >= Parameters.MAX_NUMBER_OF_STEPS; return steps >= 1000;
} }
/** /**
......
...@@ -4,18 +4,17 @@ package org.vadere.util.triangulation.adaptive; ...@@ -4,18 +4,17 @@ package org.vadere.util.triangulation.adaptive;
* Created by Matimati-ka on 27.09.2016. * Created by Matimati-ka on 27.09.2016.
*/ */
public class Parameters { public class Parameters {
final static double TOL = .1; final static double TOL = .1;
final static double FSCALE = 1.0; final static double FSCALE = 1.2;
final static double DELTAT = 0.2; final static double DELTAT = 0.2;
public final static double h0 = 0.15; public final static double h0 = 0.15;
public final static boolean uniform = false; public final static boolean uniform = false;
public final static String method = "Distmesh"; // "Distmesh" or "Density" public final static String method = "Density"; // "Distmesh" or "Density"
final static double qualityMeasurement = 0.95; final static double qualityMeasurement = 0.875;
final static double MINIMUM = 0.25; final static double MINIMUM = 0.25;
final static double DENSITYWEIGHT = 2; final static double DENSITYWEIGHT = 2;
final static int NPOINTS = 100000; final static int NPOINTS = 100000;
final static int SAMPLENUMBER = 10; final static int SAMPLENUMBER = 10;
final static int SAMPLEDIVISION = 10; final static int SAMPLEDIVISION = 10;
static final int SEGMENTDIVISION = 0; static final int SEGMENTDIVISION = 0;
final static int MAX_NUMBER_OF_STEPS = 20;
} }
...@@ -4,25 +4,23 @@ import org.vadere.util.geometry.shapes.VRectangle; ...@@ -4,25 +4,23 @@ import org.vadere.util.geometry.shapes.VRectangle;
import org.vadere.util.geometry.shapes.VShape; import org.vadere.util.geometry.shapes.VShape;
import javax.swing.*; import javax.swing.*;
import java.awt.*;
import java.util.*; import java.util.ArrayList;
/** /**
* Created by Matimati-ka on 27.09.2016. * Created by Matimati-ka on 27.09.2016.
*/ */
public class TestEnhancedVersion extends JFrame { public class TestEnhancedVersion extends JFrame {
ArrayList<VShape> obstacles;
private TestEnhancedVersion() private TestEnhancedVersion()
{ {
// VRectangle bbox = new VRectangle(0,0,100,100); // VRectangle bbox = new VRectangle(0,0,100,100);
// ArrayList<VRectangle> obs = new ArrayList<VRectangle>() {{ add(new VRectangle(20,20,20,20));}}; // ArrayList<VRectangle> obs = new ArrayList<VRectangle>() {{ add(new VRectangle(20,20,20,20));}};
double h0 = 3.0;
long now = System.currentTimeMillis(); double h0 = 1;
VRectangle bbox = new VRectangle(0, 0, 300, 300); long now = System.currentTimeMillis();
VRectangle bbox = new VRectangle(0, 0, 300, 300);
// Path2D.Double test = new Path2D.Double(); // Path2D.Double test = new Path2D.Double();
// test.moveTo(30,30); // test.moveTo(30,30);
// test.lineTo(90,80); // test.lineTo(90,80);
...@@ -32,39 +30,56 @@ public class TestEnhancedVersion extends JFrame { ...@@ -32,39 +30,56 @@ public class TestEnhancedVersion extends JFrame {
// test.lineTo(30,30); // test.lineTo(30,30);
// VPolygon p = new VPolygon(test); // VPolygon p = new VPolygon(test);
double height = 300; ArrayList<VShape> obstacles = new ArrayList<VShape>() {{
double width = 300; // add(new VRectangle(0.6*400, 0.6*400, 0.2*400, 5));
// add(new VRectangle(0.6*400, 0.65*400, 0.2*400, 5));
java.util.List<VShape> boundingBox = new ArrayList<VShape>() {{ add(new VRectangle(0.65*300, -5, 0.1*300, 0.6*300));
add(new VRectangle(0, 0, 5, width)); add(new VRectangle(0.65*300, 0.7*300, 0.1*300, 0.3*300));
add(new VRectangle(0, 0, width, 5)); // add(p);
add(new VRectangle(width-5, 0, 5, height)); }};
add(new VRectangle(0, height-5, 5, height)); ArrayList<VShape> fhIncluded = new ArrayList<VShape>() {{
}}; // add(p);
// add(new VRectangle(0.6*400, 0.6*400, 0.2*400, 5));
PSDistmesh meshGenerator = new PSDistmesh(bbox, boundingBox, h0,false); // add(new VRectangle(0.6*400, 0.65*400, 0.2*400, 5));
add(new VRectangle(0.65*300, -5, 0.1*300, 0.6*300));
add(new VRectangle(0.65*300, 0.7*300, 0.1*300, 0.3*300));
}};
PerssonStrangDistmesh psd = new PerssonStrangDistmesh(
bbox,
obstacles,
h0,
false,
l -> 0.0,
"Distmesh");
System.out.println(System.currentTimeMillis()-now); System.out.println(System.currentTimeMillis()-now);
now = System.currentTimeMillis(); now = System.currentTimeMillis();
System.out.println(System.currentTimeMillis()-now); System.out.println(System.currentTimeMillis()-now);
PSDistmeshPanel distmeshPanel = new PSDistmeshPanel(meshGenerator, 1000, 800); DrawPanel JPanel = new DrawPanel(psd);
JFrame frame = distmeshPanel.display(); setSize(1000, 800);
frame.setVisible(true); add(JPanel);
double quality = meshGenerator.qualityCheck(); setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setVisible(true);
}
private class DrawPanel extends Canvas {
private PerssonStrangDistmesh t;
while (quality < 0.95) { private DrawPanel(PerssonStrangDistmesh t) {
System.out.println("quality:"+ quality); this.t = t;
meshGenerator.step();
/*try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
distmeshPanel.repaint();
quality = meshGenerator.qualityCheck();
} }
}
@Override
public void paint(Graphics g) {
Graphics2D graphics = (Graphics2D) g;
graphics.translate(125,125);
graphics.setColor(Color.BLACK);
t.getTriangulation().getVTriangles().parallelStream().forEach(t -> graphics.draw(t));
// graphics.setColor(Color.RED);
// tc.triangulation.getTriangles().parallelStream().forEach(graphics::draw);
}
}
public static void main(String[] args) { public static void main(String[] args) {
new TestEnhancedVersion(); new TestEnhancedVersion();
......
...@@ -65,8 +65,6 @@ public class TestEnhancedVersion2 extends JFrame { ...@@ -65,8 +65,6 @@ public class TestEnhancedVersion2 extends JFrame {
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setVisible(true); setVisible(true);
new Thread(() -> meshGenerator.execude()).start();
while(true) { while(true) {
try { try {
Thread.sleep(1000); Thread.sleep(1000);
...@@ -99,7 +97,7 @@ public class TestEnhancedVersion2 extends JFrame { ...@@ -99,7 +97,7 @@ public class TestEnhancedVersion2 extends JFrame {
graphics.translate(5,5); graphics.translate(5,5);
graphics.setColor(Color.BLACK); graphics.setColor(Color.BLACK);
meshGenerator.getTriangulation().getTriangles().parallelStream().forEach(t -> graphics.draw(t)); //meshGenerator.getTriangulation().getTriangles().parallelStream().forEach(t -> graphics.draw(t));
graphics.setColor(Color.GRAY); graphics.setColor(Color.GRAY);
for(VShape obstacle : obstacles) { for(VShape obstacle : obstacles) {
......
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