16.12.2021, 9:00 - 11:00: Due to updates GitLab may be unavailable for some minutes between 09:00 and 11:00.

Commit 46b94f04 authored by Benedikt Zoennchen's avatar Benedikt Zoennchen
Browse files

implement edge collapse to further improve eikmesh.

parent 6540e923
Pipeline #138166 passed with stages
in 103 minutes and 41 seconds
......@@ -61,14 +61,14 @@ public class EikMeshPoly {
pslg.getAllPolygons()
);
var meshPanel = new PMeshPanel(meshImprover.getMesh()/*, f -> distanceFunction.apply(meshImprover.getMesh().toTriangle(f).midPoint()) > 0*/, 1000, 800);
var meshPanel = new PMeshPanel(meshImprover.getMesh(), f -> meshImprover.getMesh().getBooleanData(f, "frozen"), 1000, 800);
meshPanel.display("Combined distance functions " + h0);
meshImprover.improve();
while (!meshImprover.isFinished()) {
synchronized (meshImprover.getMesh()) {
meshImprover.improve();
}
//Thread.sleep(200);
//Thread.sleep(2000);
meshPanel.repaint();
}
//meshImprover.generate();
......
......@@ -15,7 +15,6 @@ import org.vadere.util.geometry.shapes.VTriangle;
import org.vadere.util.logging.Logger;
import org.vadere.util.math.IDistanceFunction;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
......@@ -29,7 +28,7 @@ import java.util.stream.Collectors;
/**
* <p>A tri-connectivity {@link ITriConnectivity} is the connectivity of a mesh of non-intersecting connected triangles including holes.
* A hole can be an arbitrary simple polygon. So it is more concrete than a poly-connectivity {@link IPolyConnectivity}.
* The mesh {@link IMesh} stores all the date of the base elements (points {@link P}, vertices {@link V}, half-edges {@link E}
* The mesh {@link IMesh} stores all the date of the base elements (vertices {@link V}, half-edges {@link E}
* and faces {@link F}) and offers factory method to create new base elements.
* The connectivities, i.e. {@link IPolyConnectivity} and {@link ITriConnectivity} offers all the operations manipulating
* the connectivity of the mesh. The connectivity is the relation between vertices and edges which define faces which therefore define the mesh structure.</p>
......@@ -205,6 +204,20 @@ public interface ITriConnectivity<V extends IVertex, E extends IHalfEdge, F exte
return getMesh().toLine(next).lengthSq() <= lenSq && getMesh().toLine(prev).lengthSq() <= lenSq;
}
default boolean isShortestHalfEdge(@NotNull final E edge) {
E e = edge;
if(getMesh().isBoundary(e)) {
e = getMesh().getTwin(e);
}
E next = getMesh().getNext(e);
E prev = getMesh().getPrev(e);
VLine line = getMesh().toLine(e);
double lenSq = line.lengthSq();
return getMesh().toLine(next).lengthSq() >= lenSq && getMesh().toLine(prev).lengthSq() >= lenSq;
}
/**
* <p>Inserts a point into the mesh which is contained in a boundary by connecting the boundaryEdge
* to the point in O(1) time. This will create 4 new half-edges, one new vertex and one face.</p>
......@@ -1223,6 +1236,104 @@ public interface ITriConnectivity<V extends IVertex, E extends IHalfEdge, F exte
return splitTriangle(face, p, true);
}
default V collapseEdge(@NotNull final E edge, final boolean deleteIsolatededVertex) {
IMesh<V, E, F> mesh = getMesh();
E twin = mesh.getTwin(edge);
// before changing connectivity change vertices.
V replacedVertex = getMesh().getVertex(twin);
V survivedVertex = getMesh().getVertex(edge);
for(E e : getMesh().getEdgeIt(replacedVertex)) {
getMesh().setVertex(e, survivedVertex);
}
if(getMesh().getEdge(survivedVertex).equals(edge)) {
getMesh().setEdge(survivedVertex, getMesh().getTwin(getMesh().getNext(edge)));
}
F fa = mesh.getFace(edge);
F fb = mesh.getFace(twin);
F f4 = getMesh().getTwinFace(getMesh().getPrev(edge));
F f5 = getMesh().getTwinFace(getMesh().getNext(twin));
boolean isF4Boundary = getMesh().isBoundary(f4);
boolean isF5Boundary = getMesh().isBoundary(f5);
// survives
E aNext = mesh.getNext(edge);
E bNext = mesh.getNext(twin);
E aPrev = mesh.getPrev(edge);
// survives
E bPrev = mesh.getPrev(twin);
if(!getMesh().isBoundary(edge)) {
E aPrevTwin = mesh.getTwin(aPrev);
E aPrevTwinPrev = mesh.getPrev(aPrevTwin);
E aPrevTwinNext = mesh.getNext(aPrevTwin);
E next = getMesh().getNext(edge);
V nextVertex = getMesh().getVertex(next);
if(getMesh().getEdge(nextVertex).equals(aPrevTwin)) {
getMesh().setEdge(nextVertex, next);
}
// adjust pointers
getMesh().setNext(aNext, aPrevTwinNext);
getMesh().setPrev(aNext, aPrevTwinPrev);
getMesh().setFace(aNext, f4);
getMesh().setEdge(f4, aNext);
// destroy the rest
getMesh().destroyFace(fa);
getMesh().destroyEdge(aPrev);
getMesh().destroyEdge(aPrevTwin);
} else {
getMesh().setNext(getMesh().getPrev(edge), getMesh().getNext(edge));
}
if(!getMesh().isBoundary(twin)) {
E bNextTwin = mesh.getTwin(bNext);
E bNextTwinNext = mesh.getNext(bNextTwin);
E bNextTwinPrev = mesh.getPrev(bNextTwin);
E prevTwin = getMesh().getTwin(mesh.getPrev(twin));
V nextVertex = getMesh().getVertex(prevTwin);
if(getMesh().getEdge(nextVertex).equals(bNext)) {
getMesh().setEdge(nextVertex, prevTwin);
}
// adjust pointers
getMesh().setNext(bPrev, bNextTwinNext);
getMesh().setPrev(bPrev, bNextTwinPrev);
getMesh().setFace(bPrev, f5);
getMesh().setEdge(f5, bPrev);
// destroy the rest
getMesh().destroyFace(fb);
getMesh().destroyEdge(bNext);
getMesh().destroyEdge(bNextTwin);
} else {
getMesh().setNext(getMesh().getPrev(twin), getMesh().getNext(twin));
}
// destroy the rest
getMesh().destroyEdge(edge);
getMesh().destroyEdge(twin);
if(deleteIsolatededVertex) {
getMesh().destroyVertex(replacedVertex);
} else {
getMesh().setEdge(replacedVertex, null);
}
adjustVertex(survivedVertex);
assert getMesh().isValid();
return survivedVertex;
}
/**
* <p>This method collapses a three degree vertex which is at the boundary by removing the
* one edge (a simple link) which is not a boundary edge and by merging the two other boundary edges,
......
......@@ -14,7 +14,7 @@ public class Parameters {
public final static double h0 = 0.15;
public final static boolean uniform = false;
public final static String method = "Distmesh"; // "Distmesh" or "Density"
public final static double qualityMeasurement = 0.90;
public final static double qualityMeasurement = 0.85;
public final static double MINIMUM = 0.25;
public final static double DENSITYWEIGHT = 2;
public final static int NPOINTS = 100000;
......
package org.vadere.meshing.mesh.triangulation.improver.eikmesh.gen;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.vadere.meshing.mesh.IllegalMeshException;
import org.vadere.meshing.mesh.inter.IFace;
import org.vadere.meshing.mesh.inter.IHalfEdge;
......@@ -90,15 +89,21 @@ public class GenEikMesh<V extends IVertex, E extends IHalfEdge, F extends IFace>
// different options
private boolean allowEdgeSplits = true;
private boolean allowVertexCollapse = true;
private boolean allowEdgeCollapse = true;
private boolean removeLowBoundaryTriangles = false;
private boolean useVirtualEdges = true;
private boolean smoothBorder = false;
private boolean freezeVertices = true;
//private boolean splitFaces = true;
//private boolean useFixPoints = false;
// only for logging
private static final Logger log = Logger.getLogger(GenEikMesh.class);
static {
log.setDebug();
}
// properties saved for different mesh elements i.e. vertices, edges and faces
private static final String propFixPoint = "fixPoint";
......@@ -348,6 +353,13 @@ public class GenEikMesh<V extends IVertex, E extends IHalfEdge, F extends IFace>
return getTriangulation().getMesh();
}
private void freezeVertices() {
if(freezeVertices) {
getMesh().streamVertices().filter(v -> getMesh().streamFaces(v).filter(f -> !getMesh().isBoundary(f)).allMatch(f -> faceToQuality(f) > Parameters.qualityMeasurement)).forEach(v -> setFixPoint(v, true));
getMesh().streamFaces().filter(f -> getMesh().streamVertices(f).allMatch(v -> isFixPoint(v))).forEach(f -> getMesh().setBooleanData(f, "frozen", true));
}
}
@Override
public void improve() {
synchronized (getMesh()) {
......@@ -390,6 +402,7 @@ public class GenEikMesh<V extends IVertex, E extends IHalfEdge, F extends IFace>
//computeBoundaryForces();
updateEdges();
updateVertices();
freezeVertices();
nSteps++;
......@@ -752,7 +765,45 @@ public class GenEikMesh<V extends IVertex, E extends IHalfEdge, F extends IFace>
* Updates all boundary edges. Some of those edges might get split.
*/
private void updateEdges() {
getMesh().getBoundaryEdges().forEach(e -> updateEdge(e));
getMesh().getBoundaryEdges().forEach(e -> updateBoundaryEdges(e));
if(allowEdgeCollapse) {
for(E e : getMesh().getEdges()) {
if(!getMesh().isDestroyed(e) && !getMesh().isAtBoundary(e)) {
if(updateEdge(e)) {
}
}
}
}
}
private boolean updateEdge(@NotNull final E edge) {
if(getTriangulation().isShortestHalfEdge(edge) &&
(faceToQuality(getMesh().getFace(edge)) < Parameters.MIN_SPLIT_TRIANGLE_QUALITY
|| faceToQuality(getMesh().getTwinFace(edge)) < Parameters.MIN_SPLIT_TRIANGLE_QUALITY)) {
V v1 = getMesh().getVertex(edge);
V v2 = getMesh().getTwinVertex(edge);
if(!getMesh().isAtBoundary(v1) || !getMesh().isAtBoundary(v2)) {
VPoint newPosition;
if(getMesh().isAtBoundary(v1)) {
newPosition = new VPoint(v1.getX(), v1.getY());
} else if(getMesh().isAtBoundary(v2)) {
newPosition = new VPoint(v2.getX(), v2.getY());
} else {
newPosition = new VPoint((v1.getX() + v2.getX()) * 0.5, (v1.getY() + v2.getY()) * 0.5);
}
if(isLegalMove(getMesh().getVertex(edge), newPosition.getX(), newPosition.getY()) &&
isLegalMove(getMesh().getTwinVertex(edge), newPosition.getX(), newPosition.getY())) {
V v = getTriangulation().collapseEdge(edge, true);
getMesh().setPoint(v, newPosition);
log.debug("edge collapse");
}
return true;
}
}
return false;
}
/**
......@@ -760,7 +811,7 @@ public class GenEikMesh<V extends IVertex, E extends IHalfEdge, F extends IFace>
*
* @param edge the edge
*/
private void updateEdge(@NotNull final E edge) {
private void updateBoundaryEdges(@NotNull final E edge) {
if(canBreak(edge) && isBreaking(edge)) {
//if(distanceFunc == null) {
V v1 = getMesh().getVertex(edge);
......
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