Commit 54b88621 authored by Benedikt Zoennchen's avatar Benedikt Zoennchen

DistMesh on the GPU

parent 875c7cb7
......@@ -40,11 +40,13 @@ public class DelaunayHierarchy<P extends IPoint, V extends IVertex<P>, E extends
private Supplier<ITriangulation<P, V, E, F>> triangulationSupplier;
// see delaunay-hierarchy paper!
private double alpha = 30;
/*private double alpha = 30;
private int maxLevel = 5;
private int minSize = 20;*/
private int minSize = 20;
private double alpha = 30;
private int maxLevel = 5;
private int minSize = 20;
private LinkedList<F> prevLocationResult;
......@@ -125,6 +127,8 @@ public class DelaunayHierarchy<P extends IPoint, V extends IVertex<P>, E extends
prev = v;
}
}
//System.out.println(this);
}
private ITriangulation<P, V, E, F> getLevel(final int level) {
......@@ -140,7 +144,8 @@ public class DelaunayHierarchy<P extends IPoint, V extends IVertex<P>, E extends
}
private V getDown(V src, int srcLevel) {
return getLevel(srcLevel).getMesh().getDown(src);
// srcLevel-1 since the resulting vertex is contained in the mesh one level below the src vertex!
return getLevel(srcLevel-1).getMesh().getDown(src);
}
private int randomLevel() {
......@@ -230,7 +235,16 @@ public class DelaunayHierarchy<P extends IPoint, V extends IVertex<P>, E extends
}
}
/**
@Override
public String toString() {
StringBuilder builder = new StringBuilder("");
for(int i = 0; i < hierarchySets.size(); i++) {
builder.append("["+i+"]:" + hierarchySets.get(i).getMesh().getNumberOfVertices()+"\n");
}
return builder.toString();
}
/**
* Returns vertex of the triangulation of the face with the smallest distance to point.
* Assumption: The face has to be part of the mesh of the triangulation.
*
......
......@@ -384,7 +384,7 @@ public class IncrementalTriangulation<P extends IPoint, V extends IVertex<P>, E
*/
@Override
public boolean isIllegal(E edge, V p) {
if(!mesh.isBoundary(mesh.getTwinFace(edge))) {
if(!mesh.isAtBoundary(edge)) {
//assert mesh.getVertex(mesh.getNext(edge)).equals(p);
//V p = mesh.getVertex(mesh.getNext(edge));
E t0 = mesh.getTwin(edge);
......@@ -547,7 +547,7 @@ public class IncrementalTriangulation<P extends IPoint, V extends IVertex<P>, E
points.add(new VPoint(80,70));*/
Random r = new Random();
for(int i=0; i< 1000000; i++) {
for(int i=0; i< 10000; i++) {
VPoint point = new VPoint(width*r.nextDouble(), height*r.nextDouble());
points.add(point);
}
......@@ -560,11 +560,9 @@ public class IncrementalTriangulation<P extends IPoint, V extends IVertex<P>, E
IPointLocator.Type.DELAUNAY_HIERARCHY,
points,
pointConstructor);
new IncrementalTriangulation<>(points);
bw.finalize();
Set<VLine> edges = bw.getEdges();
System.out.println(System.currentTimeMillis() - ms);
Set<VLine> edges = bw.getEdges();
JFrame window = new JFrame();
window.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
......@@ -572,6 +570,22 @@ public class IncrementalTriangulation<P extends IPoint, V extends IVertex<P>, E
window.getContentPane().add(new Lines(edges, points, max));
window.setVisible(true);
ms = System.currentTimeMillis();
ITriangulation<VPoint, AVertex<VPoint>, AHalfEdge<VPoint>, AFace<VPoint>> bw2 = ITriangulation.createATriangulation(
IPointLocator.Type.DELAUNAY_HIERARCHY,
points,
pointConstructor);
bw2.finalize();
System.out.println(System.currentTimeMillis() - ms);
Set<VLine> edges2 = bw2.getEdges();
JFrame window2 = new JFrame();
window2.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
window2.setBounds(0, 0, max, max);
window2.getContentPane().add(new Lines(edges2, points, max));
window2.setVisible(true);
/*ms = System.currentTimeMillis();
BowyerWatsonSlow<VPoint> bw2 = new BowyerWatsonSlow<VPoint>(points, (x, y) -> new VPoint(x, y));
bw2.execute();
......@@ -600,7 +614,7 @@ public class IncrementalTriangulation<P extends IPoint, V extends IVertex<P>, E
window3.getContentPane().add(new Lines(edges3, edges3.stream().flatMap(edge -> edge.streamPoints()).collect(Collectors.toSet()), max));
window3.setVisible(true);*/
VRectangle bound = new VRectangle(0, 0, width, height);
/*VRectangle bound = new VRectangle(0, 0, width, height);
ITriangulation triangulation = ITriangulation.createVPTriangulation(bound);
VPUniformRefinement uniformRefinement = new VPUniformRefinement(
triangulation,
......@@ -615,7 +629,7 @@ public class IncrementalTriangulation<P extends IPoint, V extends IVertex<P>, E
window4.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
window4.setBounds(0, 0, max, max);
window4.getContentPane().add(new Lines(edges4, edges4.stream().flatMap(edge -> edge.streamPoints()).collect(Collectors.toSet()), max));
window4.setVisible(true);
window4.setVisible(true);*/
}
private static class Lines extends JComponent{
......
......@@ -180,6 +180,16 @@ public class PMesh<P extends IPoint> implements IMesh<P, PVertex<P>, PHalfEdge<P
return faces.size();
}
@Override
public boolean tryLock(@NotNull PVertex<P> vertex) {
return vertex.getLock().tryLock();
}
@Override
public void unlock(@NotNull PVertex<P> vertex) {
vertex.getLock().unlock();
}
@Override
public PHalfEdge<P> createEdge(@NotNull PVertex<P> vertex) {
PHalfEdge<P> edge = new PHalfEdge<>(vertex);
......@@ -273,11 +283,21 @@ public class PMesh<P extends IPoint> implements IMesh<P, PVertex<P>, PHalfEdge<P
@Override
public Stream<PHalfEdge<P>> streamEdges() {
return edges.stream();
return edges.stream().filter(e -> !isDestroyed(e));
}
@Override
public Stream<PVertex<P>> streamVertices() { return vertices.stream(); };
public Stream<PHalfEdge<P>> streamEdgesParallel() {
return edges.parallelStream().filter(e -> !isDestroyed(e));
}
@Override
public Stream<PVertex<P>> streamVertices() { return vertices.stream().filter(v -> !isDestroyed(v)); }
@Override
public Stream<PVertex<P>> streamVerticesParallel() {
return vertices.parallelStream().filter(v -> !isDestroyed(v));
}
@Override
public Iterable<PHalfEdge<P>> getEdgeIt() {
......@@ -303,4 +323,8 @@ public class PMesh<P extends IPoint> implements IMesh<P, PVertex<P>, PHalfEdge<P
return faces.stream().filter(predicate);
}
@Override
public int getNumberOfEdges() {
return edges.size();
}
}
......@@ -3,12 +3,16 @@ package org.vadere.util.geometry.mesh.gen;
import org.vadere.util.geometry.mesh.inter.IVertex;
import org.vadere.util.geometry.shapes.IPoint;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author Benedikt Zoennchen
* @param <P>
*/
public class PVertex<P extends IPoint> implements IVertex<P> {
private final Lock lock;
private final P point;
private PVertex<P> down;
private PHalfEdge<P> halfEdge;
......@@ -18,6 +22,7 @@ public class PVertex<P extends IPoint> implements IVertex<P> {
this.point = point;
this.destroyed = false;
this.down = null;
this.lock = new ReentrantLock();
}
@Override
......@@ -62,6 +67,10 @@ public class PVertex<P extends IPoint> implements IVertex<P> {
destroyed = true;
}
public Lock getLock() {
return lock;
}
@Override
public int hashCode() {
return point.hashCode();
......
......@@ -5,12 +5,15 @@ import org.apache.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import org.vadere.util.geometry.GeometryUtils;
import org.vadere.util.geometry.Vector2D;
import org.vadere.util.geometry.mesh.iterators.Ring1Iterator;
import org.vadere.util.geometry.shapes.IPoint;
import org.vadere.util.geometry.shapes.VPoint;
import java.util.List;
import java.util.Optional;
import java.util.Random;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Predicate;
//TODO: check unused methods!
......@@ -38,6 +41,10 @@ public interface ITriConnectivity<P extends IPoint, V extends IVertex<P>, E exte
default void splitEdgeEvent(F original, F f1, F f2) {}
default Iterable<E> getRing1It(V vertex) {
return () -> new Ring1Iterator<>(getMesh(), getMesh().getEdge(vertex));
}
/**
* Inserts a point into the mesh which is contained in the boundary. The point will be
* connected by the start and end point of the edge. Note that the user has to make sure
......@@ -280,6 +287,65 @@ public interface ITriConnectivity<P extends IPoint, V extends IVertex<P>, E exte
return splitEdge(p, halfEdge, true);
}
/*default void flipLock(@NotNull final E edge) {
}*/
default void flipSync(@NotNull final E edge) {
IMesh<P, V, E, F> mesh = getMesh();
E a0 = edge;
E a1 = mesh.getNext(a0);
E a2 = mesh.getNext(a1);
E b0 = mesh.getTwin(edge);
E b1 = mesh.getNext(b0);
V v1 = mesh.getVertex(a0);
V v2 = mesh.getVertex(a1);
V v3 = mesh.getVertex(a2);
V v4 = mesh.getVertex(b1);
// TODO: a very first and simple aquire all locks implementation => improve it
while (true) {
// lock all 4 involved vertices
if (mesh.tryLock(v1)) {
if (mesh.tryLock(v2)) {
if (mesh.tryLock(v3)) {
if (mesh.tryLock(v4)) {
break;
}
else {
mesh.unlock(v3);
mesh.unlock(v2);
mesh.unlock(v1);
}
}
else {
mesh.unlock(v2);
mesh.unlock(v1);
}
} else {
mesh.unlock(v1);
}
}
}
try {
// if everything is locked flip
flip(edge);
}
// unlock all locks
finally {
mesh.unlock(v4);
mesh.unlock(v3);
mesh.unlock(v2);
mesh.unlock(v1);
}
}
/**
* Flips an edge in the triangulation assuming the egdge which will be
* created is not jet there.
......@@ -288,6 +354,7 @@ public interface ITriConnectivity<P extends IPoint, V extends IVertex<P>, E exte
* @param edge the edge which will be flipped.
*/
default void flip(@NotNull final E edge) {
IMesh<P, V, E, F> mesh = getMesh();
// 1. gather all the references required
......@@ -345,6 +412,22 @@ public interface ITriConnectivity<P extends IPoint, V extends IVertex<P>, E exte
flipEdgeEvent(fa, fb);
}
/**
* Tests if the face is counter-clockwise oriented.
* Assumption: The face is a triangle!
*
* @param triangleFace
* @return
*/
default boolean isCCW(F triangleFace) {
E edge = getMesh().getEdge(triangleFace);
P p1 = getMesh().getPoint(edge);
P p2 = getMesh().getPoint(getMesh().getNext(edge));
P p3 = getMesh().getPoint(getMesh().getPrev(edge));
return GeometryUtils.isCCW(p1, p2, p3);
}
default boolean isTriangle(F face) {
IMesh<P, V, E, F> mesh = getMesh();
List<E> edges = mesh.getEdges(face);
......
package org.vadere.util.opencl.examples;
import org.lwjgl.*;
import org.lwjgl.glfw.*;
import org.lwjgl.opengl.*;
import org.lwjgl.system.MemoryStack;
import java.nio.IntBuffer;
import static org.lwjgl.glfw.Callbacks.*;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.system.MemoryStack.stackPush;
import static org.lwjgl.system.MemoryUtil.NULL;
public class HelloWorld {
// The window handle
private long window;
public void run() {
System.out.println("Hello LWJGL " + Version.getVersion() + "!");
init();
loop();
// Free the window callbacks and destroy the window
glfwFreeCallbacks(window);
glfwDestroyWindow(window);
// Terminate GLFW and free the error callback
glfwTerminate();
glfwSetErrorCallback(null).free();
}
private void init() {
// Setup an error callback. The default implementation
// will print the error message in System.err.
GLFWErrorCallback.createPrint(System.err).set();
// Initialize GLFW. Most GLFW functions will not work before doing this.
if ( !glfwInit() )
throw new IllegalStateException("Unable to initialize GLFW");
// Configure GLFW
glfwDefaultWindowHints(); // optional, the current window hints are already the default
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); // the window will stay hidden after creation
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); // the window will be resizable
// Create the window
window = glfwCreateWindow(300, 300, "Hello World!", NULL, NULL);
if ( window == NULL )
throw new RuntimeException("Failed to create the GLFW window");
// Setup a key callback. It will be called every time a key is pressed, repeated or released.
glfwSetKeyCallback(window, (window, key, scancode, action, mods) -> {
if ( key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE )
glfwSetWindowShouldClose(window, true); // We will detect this in the rendering loop
});
// Get the thread stack and push a new frame
try ( MemoryStack stack = stackPush() ) {
IntBuffer pWidth = stack.mallocInt(1); // int*
IntBuffer pHeight = stack.mallocInt(1); // int*
// Get the window size passed to glfwCreateWindow
glfwGetWindowSize(window, pWidth, pHeight);
// Get the resolution of the primary monitor
GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
// Center the window
glfwSetWindowPos(
window,
(vidmode.width() - pWidth.get(0)) / 2,
(vidmode.height() - pHeight.get(0)) / 2
);
} // the stack frame is popped automatically
// Make the OpenGL context current
glfwMakeContextCurrent(window);
// Enable v-sync
glfwSwapInterval(1);
// Make the window visible
glfwShowWindow(window);
}
private void loop() {
// This line is critical for LWJGL's interoperation with GLFW's
// OpenGL context, or any context that is managed externally.
// LWJGL detects the context that is current in the current thread,
// creates the GLCapabilities instance and makes the OpenGL
// bindings available for use.
GL.createCapabilities();
// Set the clear color
glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
// Run the rendering loop until the user has attempted to close
// the window or has pressed the ESCAPE key.
while ( !glfwWindowShouldClose(window) ) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear the framebuffer
glfwSwapBuffers(window); // swap the color buffers
// Poll for window events. The key callback above will only be
// invoked during this call.
glfwPollEvents();
}
}
public static void main(String[] args) {
new HelloWorld().run();
}
}
\ No newline at end of file
package org.vadere.util.geometry;
import org.junit.Before;
import org.junit.Test;
import org.vadere.util.geometry.mesh.gen.PFace;
import org.vadere.util.geometry.mesh.gen.PHalfEdge;
import org.vadere.util.geometry.mesh.gen.PMesh;
import org.vadere.util.geometry.mesh.gen.PVertex;
import org.vadere.util.geometry.mesh.inter.IMesh;
import org.vadere.util.geometry.shapes.VPoint;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static org.junit.Assert.assertEquals;
public class TestFace {
/**
* Building a geometry containing 2 triangles
* xyz and wyx
*/
private IMesh<VPoint, PVertex<VPoint>, PHalfEdge<VPoint>, PFace<VPoint>> mesh;
private PFace face1;
private PFace face2;
private PFace border;
private PVertex<VPoint> x, y, z, w;
private PHalfEdge<VPoint> zx ;
private PHalfEdge<VPoint> xy;
private PHalfEdge<VPoint> yz;
private PHalfEdge<VPoint> wx;
private PHalfEdge<VPoint> xz;
private PHalfEdge<VPoint> yw;
private PHalfEdge<VPoint> zy;
@Before
public void setUp() throws Exception {
mesh = new PMesh<>((x, y) -> new VPoint(x, y));
border = mesh.createFace(true);
// first triangle xyz
face1 = mesh.createFace();
x = mesh.insertVertex(0, 0);
y = mesh.insertVertex(3, 0);
z = mesh.insertVertex(1.5,3.0);
zx = mesh.createEdge(x, face1);
mesh.setEdge(x, zx);
xy = mesh.createEdge(y, face1);
mesh.setEdge(y, xy);
yz = mesh.createEdge(z, face1);
mesh.setEdge(z, yz);
mesh.setNext(zx, xy);
mesh.setNext(xy, yz);
mesh.setNext(yz, zx);
mesh.setEdge(face1, xy);
// second triangle yxw
face2 = mesh.createFace();
w = mesh.createVertex(1.5,-1.5);
PHalfEdge yx = mesh.createEdge(x, face2);
PHalfEdge xw = mesh.createEdge(w, face2);
PHalfEdge wy = mesh.createEdge(y, face2);
mesh.setNext(yx, xw);
mesh.setNext(xw, wy);
mesh.setNext(wy, yx);
mesh.setEdge(face2, yx);
mesh.setTwin(xy, yx);
// border twins
zy = mesh.createEdge(y, border);
xz = mesh.createEdge(z, border);
mesh.setTwin(yz, zy);
mesh.setTwin(zx, xz);
wx = mesh.createEdge(x, border);
yw = mesh.createEdge(w, border);
mesh.setEdge(w, yw);
mesh.setEdge(border, wx);
mesh.setTwin(xw, wx);
mesh.setTwin(wy, yw);
mesh.setNext(zy, yw);
mesh.setNext(yw, wx);
mesh.setNext(wx, xz);
mesh.setNext(xz, zy);
}
@Test
public void testFaceIterator() {
mesh.getAdjacentFacesIt(xy);
List<PFace<VPoint>> incidentFaces = mesh.getAdjacentFaces(xy);;
assertEquals(incidentFaces.size(), 3);
}
@Test
public void testPointIterator() {
assertEquals(new ArrayList(Arrays.asList(y, z, x)), mesh.getVertices(face1));
}
@Test
public void testEdgeOfVertex() {
mesh.streamEdges().forEach(edge -> assertEquals(mesh.getVertex(edge), mesh.getVertex(mesh.getEdge(mesh.getVertex(edge)))));
}
@Test
public void testEdgeIterator() {
List<PVertex<VPoint>> adjacentVertices = mesh.getAdjacentVertices(zx);
Set<PVertex<VPoint>> neighbours = new HashSet<>(adjacentVertices);
Set<PVertex<VPoint>> expectedNeighbours = new HashSet<>();
expectedNeighbours.add(z);
expectedNeighbours.add(y);
expectedNeighbours.add(w);
assertEquals(expectedNeighbours, neighbours);
}
}
......@@ -8,15 +8,15 @@ import org.vadere.util.geometry.mesh.gen.PMesh;
import org.vadere.util.geometry.mesh.gen.PVertex;
import org.vadere.util.geometry.mesh.inter.IMesh;
import org.vadere.util.geometry.shapes.VPoint;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertEquals;
public class TestPFace {
......@@ -108,7 +108,6 @@ public class TestPFace {
assertEquals(incidentFaces.size(), 3);
}
@Test
public void testPointIterator() {
assertEquals(new ArrayList(Arrays.asList(y, z, x)), mesh.getVertices(face1));
......
......@@ -8,9 +8,7 @@ import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;