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

refactoring the meshing package, adding some very basic examples.

parent adbcd1b9
......@@ -20,7 +20,7 @@ import org.vadere.util.geometry.shapes.VShape;
import org.vadere.meshing.mesh.gen.PFace;
import org.vadere.meshing.mesh.gen.PHalfEdge;
import org.vadere.meshing.mesh.gen.PVertex;
import org.vadere.meshing.mesh.inter.ITriangulation;
import org.vadere.meshing.mesh.inter.IIncrementalTriangulation;
import org.vadere.util.geometry.shapes.IPoint;
import org.vadere.util.geometry.shapes.VPolygon;
import org.vadere.util.geometry.shapes.VTriangle;
......@@ -87,7 +87,7 @@ public abstract class DefaultModel<T extends DefaultConfig> extends Observable i
public T config;
private ITriangulation<EikMeshPoint, PVertex<EikMeshPoint>, PHalfEdge<EikMeshPoint>, PFace<EikMeshPoint>> triangulation;
private IIncrementalTriangulation<EikMeshPoint, PVertex<EikMeshPoint>, PHalfEdge<EikMeshPoint>, PFace<EikMeshPoint>> triangulation;
private Collection<VTriangle> triangles;
......
......@@ -14,7 +14,7 @@ import org.vadere.util.geometry.shapes.VRectangle;
import org.vadere.util.geometry.shapes.VShape;
import org.vadere.util.math.DistanceFunction;
import org.vadere.meshing.mesh.triangulation.improver.eikmesh.EikMeshPoint;
import org.vadere.meshing.mesh.triangulation.improver.eikmesh.EikMeshPanel;
import org.vadere.meshing.mesh.gen.MeshPanel;
import org.vadere.meshing.mesh.triangulation.improver.eikmesh.AEikMesh;
import java.awt.*;
......@@ -61,7 +61,7 @@ public class RecordTriangulationMovie {
//ColorHelper.numberToHurColor((float)f.getId() / meshImprover.getMesh().getNumberOfFaces());
//new ColorHelper(meshImprover.getMesh().getNumberOfFaces()).numberToColor(f.getId());
EikMeshPanel<EikMeshPoint, AVertex<EikMeshPoint>, AHalfEdge<EikMeshPoint>, AFace<EikMeshPoint>> distmeshPanel = new EikMeshPanel<>(
MeshPanel<EikMeshPoint, AVertex<EikMeshPoint>, AHalfEdge<EikMeshPoint>, AFace<EikMeshPoint>> distmeshPanel = new MeshPanel<>(
meshImprover.getMesh(), f -> false, bbound.getWidth()*1000, bbound.getHeight()*1000, bbound, colorFunction1);
JFrame frame = distmeshPanel.display();
......@@ -114,7 +114,7 @@ public class RecordTriangulationMovie {
}
public static void addPictures(Recorder recorder,
EikMeshPanel<EikMeshPoint, AVertex<EikMeshPoint>, AHalfEdge<EikMeshPoint>, AFace<EikMeshPoint>> distmeshPanel,
MeshPanel<EikMeshPoint, AVertex<EikMeshPoint>, AHalfEdge<EikMeshPoint>, AFace<EikMeshPoint>> distmeshPanel,
int frames) throws IOException {
for(int i = 0; i < frames; i++) {
......
package org.vadere.meshing.examples;
import org.vadere.meshing.mesh.gen.MeshPanel;
import org.vadere.meshing.mesh.impl.VPTriangulation;
import org.vadere.meshing.mesh.inter.IIncrementalTriangulation;
import org.vadere.meshing.mesh.triangulation.triangulator.RandomPointsSetTriangulator;
import org.vadere.util.geometry.shapes.VRectangle;
public class DelaunayTriangulationExamples {
public static void main(String... args) {
randomDelaunayTriangulation();
}
/**
* An example of how to construct and display a Delaunay triangulation of random points.
*/
public static void randomDelaunayTriangulation() {
// define a bound of the mesh / triangulation
VRectangle bound = new VRectangle(0, 0, 100, 100);
// define your triangulation which is based on VPoint
VPTriangulation triangulation = IIncrementalTriangulation.createVPTriangulation(bound);
// define a random point set triangulator
int numberOfPoint = 5000;
RandomPointsSetTriangulator randomTriangulator = new RandomPointsSetTriangulator(triangulation, numberOfPoint, bound);
// fill in the points into the empty triangulation
randomTriangulator.generate();
// display the result
MeshPanel meshPanel = new MeshPanel(triangulation.getMesh(), 500, 500, bound);
meshPanel.display();
}
}
......@@ -4,7 +4,7 @@ import org.vadere.util.geometry.GeometryUtils;
import org.vadere.meshing.mesh.gen.PFace;
import org.vadere.meshing.mesh.gen.PHalfEdge;
import org.vadere.meshing.mesh.gen.PVertex;
import org.vadere.meshing.mesh.triangulation.improver.eikmesh.EikMeshPanel;
import org.vadere.meshing.mesh.gen.MeshPanel;
import org.vadere.meshing.mesh.triangulation.improver.eikmesh.EikMeshPoint;
import org.vadere.meshing.mesh.triangulation.improver.eikmesh.PEikMesh;
import org.vadere.util.geometry.shapes.VPoint;
......@@ -17,7 +17,12 @@ import java.util.List;
import javax.swing.*;
public class Example {
/**
* Shows a very basic example how {@link org.vadere.meshing.mesh.triangulation.improver.eikmesh.EikMesh} can be used
* to mesh a simple geometry.
*/
public class EikMeshExamples {
public static void main(String... args) {
// define a bounding box
......@@ -39,18 +44,15 @@ public class Example {
0.1,
obstacleShapes);
// (optional) define the gui only to display the mesh
EikMeshPanel<EikMeshPoint, PVertex<EikMeshPoint>, PHalfEdge<EikMeshPoint>, PFace<EikMeshPoint>> eikMeshPanel = new EikMeshPanel<>(
meshImprover.getMesh(),
f -> false, 1000, 800,
// (optional) define the gui to display the mesh
MeshPanel<EikMeshPoint, PVertex<EikMeshPoint>, PHalfEdge<EikMeshPoint>, PFace<EikMeshPoint>> meshPanel = new MeshPanel<>(
meshImprover.getMesh(), 1000, 800,
new VRectangle(boundary.getBounds()));
JFrame frame = eikMeshPanel.display();
frame.setVisible(true);
frame.setTitle("uniformRing()");
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
// generate the mesh
meshImprover.generate();
eikMeshPanel.repaint();
// display the mesh
meshPanel.display();
}
}
......@@ -5,31 +5,40 @@ import org.vadere.meshing.mesh.inter.IFace;
import org.vadere.util.geometry.shapes.IPoint;
/**
* An array-based implementation of {@link IFace}.
*
* @author Benedikt Zoennchen
*/
public class AFace<P extends IPoint> implements IFace<P>, Cloneable {
/**
* One of the half-edges bordering this face.
* One of the array index of the half-edges bordering this face.
*/
private int edge;
/**
* The array-index of this face
*/
private int id;
/**
* If true this face is a border face, otherwise its not.
*/
private boolean border;
/**
* If true the face is destroyed which means it can be removed from the array-based mesh data structure.
*/
private boolean destroyed = false;
/**
* Default constructor. To construct a face where you have already some half-edges
* bordering this face.
*
* @param edge one of the half-edges bordering this face.
* @param id the array-index of this face
* @param edge the array-index of one edge of this face
* @param border indicator if this face is a border face or not
*/
AFace(@NotNull final int id, @NotNull final int edge) {
this(id, edge, false);
}
AFace(@NotNull final int id,@NotNull final int edge, boolean border) {
this.border = border;
this.edge = edge;
......@@ -46,10 +55,18 @@ public class AFace<P extends IPoint> implements IFace<P>, Cloneable {
this.id = id;
}
/**
* Returns true if this face is a border face, false otherwise.
*
* @return true if this face is a border face, false otherwise
*/
boolean isBorder() {
return border;
}
/**
* Destroys the face. After this call the face can be removed from the array based mesh data structure.
*/
void destroy() {
setEdge(-1);
destroyed = true;
......@@ -58,32 +75,57 @@ public class AFace<P extends IPoint> implements IFace<P>, Cloneable {
/**
* Sets one of the half-edges bordering this face.
*
* @param edge half-edge bordering this face
* @param edge the array-index of a half-edge bordering this face
*/
void setEdge(@NotNull final int edge) {
this.edge = edge;
}
/**
* This method should only be called by the garbage collector in AMesh.
* @param id
* Sets the array-index of this face. Note that this method should
* only be called by the garbage collector in {@link AMesh} which
* adjust indices to remove destroyed base elements.
*
* @param id the new array-index of this face
*/
void setId(@NotNull final int id) {
this.id = id;
}
/**
* Returns the array-index of an half-edge of this face.
*
* @return the array-index of an half-edge of this face
*/
int getEdge() {
return edge;
}
/**
* Returns the array-indedx of this face.
*
* @return the array-indedx of this face.
*/
public int getId() {
return id;
}
/**
* Returns true if this face is destroyed and can be removed from the mesh data structure,
* false otherwise.
*
* @return true if this face is destroyed, false otherwise
*/
boolean isDestroyed() {
return destroyed;
}
/**
* Sets this face to be a border face or a non-border face with respect to
* the parameter border.
*
* @param border if true this face becomes a border face, otherwise it becomes a non-border face
*/
public void setBorder(boolean border) {
this.border = border;
}
......
......@@ -5,34 +5,45 @@ import org.vadere.meshing.mesh.inter.IHalfEdge;
import org.vadere.util.geometry.shapes.IPoint;
/**
* An array-based implementation of {@link IHalfEdge}.
*
* @author Benedikt Zoennchen
*/
public class AHalfEdge<P extends IPoint> implements IHalfEdge<P>, Cloneable {
/**
* The array-index of this half-edge
*/
private int id;
/**
* point at the end of the half edge.
* The array-index of the point at the end of the half edge.
*/
private int end;
/**
* next half-edge around the face.
* The array-index of the next half-edge around the face.
*/
private int next;
/**
* previous half-edge around the face.
* The array-index of the previous half-edge around the face.
*/
private int previous;
/**
* The array-index of the twin half-edge
*/
private int twin;
/**
* the face the half-edge borders.
* The array-index of the face the half-edge borders.
*/
private int face;
/**
* Indicates that the half-edge is destroyed and can be removed from the array-based data structure.
*/
private boolean destroyed;
protected AHalfEdge(@NotNull final int id, @NotNull final int end, @NotNull final int face) {
......@@ -114,10 +125,13 @@ public class AHalfEdge<P extends IPoint> implements IHalfEdge<P>, Cloneable {
return destroyed;
}
/**
* This method should only be called by the garbage collector in AMesh.
* @param id
*/
/**
* Sets the array-index of this half-edge. Note that this method should
* only be called by the garbage collector in {@link AMesh} which
* adjust indices to remove destroyed base elements.
*
* @param id the new array-index of this face
*/
void setId(@NotNull final int id) {
this.id = id;
}
......
......@@ -6,7 +6,7 @@ import org.jetbrains.annotations.NotNull;
import org.vadere.meshing.mesh.inter.IMesh;
import org.vadere.meshing.mesh.inter.IPointConstructor;
import org.vadere.meshing.mesh.inter.IPointLocator;
import org.vadere.meshing.mesh.inter.ITriangulation;
import org.vadere.meshing.mesh.inter.IIncrementalTriangulation;
import org.vadere.util.geometry.GeometryUtils;
import org.vadere.meshing.SpaceFillingCurve;
import org.vadere.util.geometry.shapes.IPoint;
......@@ -20,7 +20,11 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* An array-based implementation of {@link IMesh}.
*
* @author Benedikt Zoennchen
*
* @param <P> the type of the points (containers)
*/
public class AMesh<P extends IPoint> implements IMesh<P, AVertex<P>, AHalfEdge<P>, AFace<P>>, Cloneable {
private final static Logger log = LogManager.getLogger(AMesh.class);
......@@ -426,8 +430,8 @@ public class AMesh<P extends IPoint> implements IMesh<P, AVertex<P>, AHalfEdge<P
}
@Override
public ITriangulation<P, AVertex<P>, AHalfEdge<P>, AFace<P>> toTriangulation(final @NotNull IPointLocator.Type type) {
return ITriangulation.createATriangulation(type, this);
public IIncrementalTriangulation<P, AVertex<P>, AHalfEdge<P>, AFace<P>> toTriangulation(final @NotNull IPointLocator.Type type) {
return IIncrementalTriangulation.createATriangulation(type, this);
}
public void setPositions(final List<P> positions) {
......@@ -574,10 +578,10 @@ public class AMesh<P extends IPoint> implements IMesh<P, AVertex<P>, AHalfEdge<P
}
/**
* This method rearranges the indices of faces, vertices and edges according to their positions.
* After the call, neighbouring faces are near arrange inside the face {@link ArrayList}.
* <p>This method rearranges the indices of faces, vertices and edges according to their positions.
* After the call, neighbouring faces are near arrange inside the face {@link ArrayList}.</p>
*
* Note: that any mapping id to vertex or id to halfEdge or id to face has to be recomputed!
* <p>Note: that any mapping id to vertex or id to halfEdge or id to face has to be recomputed!</p>
*/
public void spatialSort() {
// get the bound for the space filling curve!
......@@ -622,9 +626,9 @@ public class AMesh<P extends IPoint> implements IMesh<P, AVertex<P>, AHalfEdge<P
/**
* removes all destroyed object from this mesh and re-arranges all indices.
* <p>Removes all destroyed object from this mesh and re-arranges all indices.</p>
*
* Note: that any mapping id to vertex or id to halfEdge or id to face has to be recomputed!
* <p>Note: that any mapping id to vertex or id to halfEdge or id to face has to be recomputed!</p>
*/
public void garbageCollection() {
Map<Integer, Integer> faceIdMap = new HashMap<>();
......@@ -706,7 +710,7 @@ public class AMesh<P extends IPoint> implements IMesh<P, AVertex<P>, AHalfEdge<P
}
/**
* Creates a very simple mesh consisting of two triangles ((-100, 0), (100, 0), (0, 1)) and ((0, -1), (-100, 0), (100, 0)).
* <p>Creates a very simple mesh consisting of two triangles ((-100, 0), (100, 0), (0, 1)) and ((0, -1), (-100, 0), (100, 0)).</p>
*
* @return the created mesh
*/
......
......@@ -8,17 +8,49 @@ import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* An array-based implementation of {@link IVertex}.
*
* @author Benedikt Zoennchen
*/
public class AVertex<P extends IPoint> implements IVertex<P>, Cloneable {
private final Lock lock;
/**
* A lock for flipping edges in parallel
*/
private final Lock lock;
/**
* The point of the vertex
*/
private P point;
private int down;
/**
* The array-index of the down vertex. This is only required by if one uses the {@link DelaunayHierarchy} as the
* point location algorithm of the mesh / the triangulation.
*/
private int down;
/**
* The array-index of the half-edge which ends in this vertex.
*/
private int halfEdge;
private int id;
private boolean destroyed;
/**
* The array-index of this vertex.
*/
private int id;
/**
* Indicates that the vertex is destroyed and can be removed from the array-based data structure.
*/
private boolean destroyed;
/**
* Default constructor.
*
* @param id the array-index of this vertex
* @param point the point / container of this vertex
*/
public AVertex(@NotNull final int id, @NotNull final P point) {
this.point = point;
this.id = id;
......@@ -56,8 +88,11 @@ public class AVertex<P extends IPoint> implements IVertex<P>, Cloneable {
}
/**
* This method should only be called by the garbage collector in AMesh.
* @param id
* Sets the array-index of this vertex. Note that this method should
* only be called by the garbage collector in {@link AMesh} which
* adjust indices to remove destroyed base elements.
*
* @param id the new array-index of this face
*/
void setId(@NotNull final int id) {
this.id = id;
......
......@@ -12,11 +12,10 @@ import java.util.Optional;
/**
* @author Benedikt Zoennchen
*
* The BasePointLocatetor only uses the mesh itself and does not use any additional data structure
* to find the face for a given point. It runs a march starting from some (not known) face of the
* mesh and end up at the face that triangleContains the point. In worst case this is not faster than
* checking each each face of the mesh but it is more clever and faste in the most cases.
*
* The {@link BasePointLocator} only uses the mesh itself and does not use any additional data structure
* to find the face for a given point. It runs a march starting from some arbitrary face of the
* mesh and end up at the face that contains the point, if there is one. In worst case this is not faster than
* checking each face of the mesh but it is more clever and faste in most cases.
*
* @param <P> the type of the points (containers)
* @param <V> the type of the vertices
......
......@@ -4,6 +4,7 @@ import org.jetbrains.annotations.NotNull;
import org.lwjgl.system.MemoryUtil;
import org.vadere.util.geometry.shapes.IPoint;
import java.nio.Buffer;
import java.nio.DoubleBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
......@@ -11,10 +12,28 @@ import java.util.Collection;
import java.util.List;
/**
* The {@link CLGatherer} gathers and scatters data between a {@link AMesh}
* and the heap memory represented by buffers ({@link Buffer}) such that one
* can transfer the {@link Buffer} and therefore the elements of {@link AMesh}
* to the Graphical Processing Unit (GPU) via OpenCL.
*
* @author Benedikt Zoennchen
*/
public class CLGatherer {
/**
* <p>Writes all coordinates of vertices / points p1 = (x1, y1), p2 = (x2, y2), ... pn = (xn, yn) successively,
* i.e. (x1,y1,x2,y2,...,xn,yn) into the {@link DoubleBuffer}.</p>
*
* <p>Assumption: The {@link DoubleBuffer} vertexBuffer is correctly sized,
* i.e. 2*n where n is the number of vertices of the mesh.</p>
*
* @param mesh the mesh which contains the points.
* @param vertexBuffer the memory in which the coordinates of the vertices / points will be written.
* @param <P> the type of the points (containers)
*
* @return the heap memory {@link DoubleBuffer} containing all coordinates of all all vertices / points in a successive order
*/
public static <P extends IPoint> DoubleBuffer getVerticesD(@NotNull final AMesh<P> mesh, @NotNull final DoubleBuffer vertexBuffer) {
Collection<AVertex<P>> vertices = mesh.getVertices();
int index = 0;
......@@ -28,12 +47,33 @@ public class CLGatherer {
return vertexBuffer;
}
public static <P extends IPoint> DoubleBuffer getVerticesD(@NotNull final AMesh<P> mesh) {
/**
* <p>Writes all coordinates of vertices / points p1 = (x1, y1), p2 = (x2, y2), ... pn = (xn, yn) successively,
* i.e. (x1,y1,x2,y2,...,xn,yn) into the {@link DoubleBuffer}.</p>
*
* @param mesh the mesh which contains the points.
* @param <P> the type of the points (containers)
*
* @return the heap memory {@link DoubleBuffer} containing all coordinates of all all vertices / points in a successive order
*/
public static <P extends IPoint> DoubleBuffer getVerticesD(@NotNull final AMesh<P> mesh) {
Collection<AVertex<P>> vertices = mesh.getVertices();
return getVerticesD(mesh, MemoryUtil.memAllocDouble(vertices.size()*2));
}
/**
* <p>Writes all coordinates of vertices / points p1 = (x1, y1), p2 = (x2, y2), ... pn = (xn, yn) successively,
* i.e. (x1,y1,x2,y2,...,xn,yn) into the {@link FloatBuffer} by casting double to float</p>
*
* <p>Assumption: The {@link FloatBuffer} vertexBuffer is correctly sized,
* i.e. 2*n where n is the number of vertices of the mesh.</p>
*
* @param mesh the mesh which contains the points.
* @param vertexBuffer the memory in which the coordinates of the vertices / points will be written.
* @param <P> the type of the points (containers)
*
* @return the heap memory {@link FloatBuffer} containing all coordinates of all all vertices / points in a successive order
*/
public static <P extends IPoint> FloatBuffer getVerticesF(@NotNull final AMesh<P> mesh, @NotNull final FloatBuffer vertexBuffer) {
Collection<AVertex<P>> vertices = mesh.getVertices();
int index = 0;
......@@ -47,12 +87,33 @@ public class CLGatherer {
return vertexBuffer;
}
/**
* <p>Writes all coordinates of vertices / points p1 = (x1, y1), p2 = (x2, y2), ... pn = (xn, yn) successively,
* i.e. (x1,y1,x2,y2,...,xn,yn) into the {@link FloatBuffer} by casting double to float</p>
*
* @param mesh the mesh which contains the points.
* @param <P> the type of the points (containers)
*
* @return the heap memory {@link FloatBuffer} containing all coordinates of all all vertices / points in a successive order
*/
public static <P extends IPoint> FloatBuffer getVerticesF(@NotNull final AMesh<P> mesh) {
Collection<AVertex<P>> vertices = mesh.getVertices();
return getVerticesF(mesh, MemoryUtil.memAllocFloat(vertices.size()*2));
}
public static <P extends IPoint> void scatterHalfEdges(@NotNull final AMesh<P> mesh, @NotNull final IntBuffer edgeBuffer) {
/**
* <p>Scatters / writes / sets the array-indices of half-edges ({@link AHalfEdge}) at the heap memory {@link IntBuffer}
* to the mesh in order of the mesh-ordering. This is the reverse operation of {@link CLGatherer#getHalfEdges(AMesh)}</p>
*
* <p>Assumption: The i-th half-edge in the heap memory represents the i-th half-edge of the {@link AMesh}. The heap memory
* has to look like (edgeId1, vertexId1, nextId1, twinId1, faceId1, edgeId2, vertexId2, nextId2, twinId2, faceId2,