Commit 38b5f9b1 authored by Benedikt Zoennchen's avatar Benedikt Zoennchen
Browse files

fix getNumberOfX in PMesh and fix JUnit test TestMeshManipulations.

parent bccf4bbc
Pipeline #72803 failed with stages
in 74 minutes and 49 seconds
......@@ -396,6 +396,11 @@ public class AMesh<P extends IPoint> implements IMesh<P, AVertex<P>, AHalfEdge<P
return numberOfEdges;
}
@Override
public int getNumberOfHoles() {
return numberOfHoles;
}
@Override
public boolean tryLock(@NotNull AVertex<P> vertex) {
return vertex.getLock().tryLock();
......
......@@ -280,7 +280,7 @@ public class CLGatherer {
* <li>the index of the face of the half-edge or -1 if there is no face, i.e. the half-edge is a boundary edge</li>
* <li>the index of the face of the twin of the half-edge or - if thre is no face, i.e. the half-edge is a boundary edge</li>
* </ol>
* to the heap memory {@link IntBuffer} in order of the mesh-ordering of {@link AMesh}.</p>
* to the heap memory {@link IntBuffer} in order of the mesh-ordering of {@link AMesh}.
*
* @param mesh the mesh from which the boundary information is received
* @param <P> the type of the points (containers)
......
......@@ -415,6 +415,10 @@ public class IncrementalTriangulation<P extends IPoint, V extends IVertex<P>, E
@Override
public E insert(P point) {
if(!initialized) {
init();
}
if(contains(point)) {
F face = this.pointLocator.locatePoint(point);
return insert(point, face);
......
......@@ -21,6 +21,11 @@ public class PMesh<P extends IPoint> implements IMesh<P, PVertex<P>, PHalfEdge<P
private static Logger log = LogManager.getLogger(PMesh.class);
private int numberOfEdges;
private int numberOfFaces;
private int numberOfHoles;
private int numberOfVertices;
private List<PFace<P>> faces;
private List<PFace<P>> holes;
private PFace<P> boundary;
......@@ -40,6 +45,10 @@ public class PMesh<P extends IPoint> implements IMesh<P, PVertex<P>, PHalfEdge<P
this.edges = new ArrayList<>();
this.vertices = new ArrayList<>();
this.boundary = new PFace<>(true);
this.numberOfEdges = 0;
this.numberOfFaces = 0;
this.numberOfHoles = 0;
this.numberOfVertices = 0;
}
@Override
......@@ -80,27 +89,27 @@ public class PMesh<P extends IPoint> implements IMesh<P, PVertex<P>, PHalfEdge<P
}
@Override
public PHalfEdge<P> getEdge(@NotNull PVertex<P> vertex) {
public PHalfEdge<P> getEdge(@NotNull final PVertex<P> vertex) {
return vertex.getEdge();
}
@Override
public PHalfEdge<P> getEdge(PFace<P> face) {
public PHalfEdge<P> getEdge(@NotNull final PFace<P> face) {
return face.getEdge();
}
@Override
public P getPoint(@NotNull PHalfEdge<P> halfEdge) {
public P getPoint(@NotNull final PHalfEdge<P> halfEdge) {
return getVertex(halfEdge).getPoint();
}
@Override
public PVertex<P> getVertex(@NotNull PHalfEdge<P> halfEdge) {
public PVertex<P> getVertex(@NotNull final PHalfEdge<P> halfEdge) {
return halfEdge.getEnd();
}
@Override
public P getPoint(@NotNull PVertex<P> vertex) {
public P getPoint(@NotNull final PVertex<P> vertex) {
return vertex.getPoint();
}
......@@ -110,32 +119,32 @@ public class PMesh<P extends IPoint> implements IMesh<P, PVertex<P>, PHalfEdge<P
}
@Override
public boolean isBoundary(@NotNull PFace<P> face) {
public boolean isBoundary(@NotNull final PFace<P> face) {
return face.isBoundary();
}
@Override
public boolean isHole(@NotNull PFace<P> face) {
public boolean isHole(@NotNull final PFace<P> face) {
return isBoundary(face) && face != boundary;
}
@Override
public boolean isBoundary(@NotNull PHalfEdge<P> halfEdge) {
public boolean isBoundary(@NotNull final PHalfEdge<P> halfEdge) {
return halfEdge.isBoundary();
}
@Override
public boolean isDestroyed(@NotNull PFace<P> face) {
public boolean isDestroyed(@NotNull final PFace<P> face) {
return face.isDestroyed();
}
@Override
public boolean isDestroyed(@NotNull PHalfEdge<P> edge) {
public boolean isDestroyed(@NotNull final PHalfEdge<P> edge) {
return !edge.isValid();
}
@Override
public boolean isDestroyed(@NotNull PVertex<P> vertex) {
public boolean isDestroyed(@NotNull final PVertex<P> vertex) {
return vertex.isDestroyed();
}
......@@ -152,23 +161,23 @@ public class PMesh<P extends IPoint> implements IMesh<P, PVertex<P>, PHalfEdge<P
}
@Override
public void setPrev(final PHalfEdge<P> halfEdge, final PHalfEdge<P> prev) {
public void setPrev(@NotNull final PHalfEdge<P> halfEdge, @NotNull final PHalfEdge<P> prev) {
halfEdge.setPrevious(prev);
prev.setNext(halfEdge);
}
@Override
public void setFace(final PHalfEdge<P> halfEdge, final PFace<P> face) {
public void setFace(@NotNull final PHalfEdge<P> halfEdge, @NotNull final PFace<P> face) {
halfEdge.setFace(face);
}
@Override
public void setEdge(final PFace<P> face, final PHalfEdge<P> edge) {
public void setEdge(@NotNull final PFace<P> face, @NotNull final PHalfEdge<P> edge) {
face.setEdge(edge);
}
@Override
public void setEdge(@NotNull PVertex<P> vertex, @NotNull PHalfEdge<P> edge) {
public void setEdge(@NotNull final PVertex<P> vertex, @NotNull final PHalfEdge<P> edge) {
assert edge.getEnd().equals(vertex);
if(!edge.getEnd().equals(vertex)) {
throw new IllegalArgumentException("end of the edge is not equals to the vertex:" + vertex + " != " + edge.getEnd());
......@@ -177,7 +186,7 @@ public class PMesh<P extends IPoint> implements IMesh<P, PVertex<P>, PHalfEdge<P
}
@Override
public void setVertex(@NotNull PHalfEdge<P> halfEdge, @NotNull PVertex<P> vertex) {
public void setVertex(@NotNull final PHalfEdge<P> halfEdge, @NotNull final PVertex<P> vertex) {
/*if(halfEdge.getEnd().getEdge() == halfEdge) {
System.out.println("error44");
}
......@@ -197,12 +206,12 @@ public class PMesh<P extends IPoint> implements IMesh<P, PVertex<P>, PHalfEdge<P
@Override
public int getNumberOfVertices() {
return vertices.size();
return numberOfVertices;
}
@Override
public int getNumberOfFaces() {
return faces.size()-holes.size();
return numberOfFaces;
}
@Override
......@@ -216,16 +225,18 @@ public class PMesh<P extends IPoint> implements IMesh<P, PVertex<P>, PHalfEdge<P
}
@Override
public PHalfEdge<P> createEdge(@NotNull PVertex<P> vertex) {
public PHalfEdge<P> createEdge(@NotNull final PVertex<P> vertex) {
PHalfEdge<P> edge = new PHalfEdge<>(vertex);
edges.add(edge);
numberOfEdges++;
return edge;
}
@Override
public PHalfEdge<P> createEdge(@NotNull PVertex<P> vertex, @NotNull PFace<P> face) {
public PHalfEdge<P> createEdge(@NotNull final PVertex<P> vertex, @NotNull final PFace<P> face) {
PHalfEdge<P> edge = new PHalfEdge<>(vertex, face);
edges.add(edge);
numberOfEdges++;
return edge;
}
......@@ -235,13 +246,17 @@ public class PMesh<P extends IPoint> implements IMesh<P, PVertex<P>, PHalfEdge<P
}
@Override
public PFace<P> createFace(boolean hole) {
public PFace<P> createFace(final boolean hole) {
PFace<P> face = new PFace<>(hole);
faces.add(face);
if(hole) {
numberOfHoles++;
holes.add(face);
}
else {
numberOfFaces++;
}
return face;
}
......@@ -258,7 +273,7 @@ public class PMesh<P extends IPoint> implements IMesh<P, PVertex<P>, PHalfEdge<P
}
@Override
public PVertex<P> createVertex(P point) {
public PVertex<P> createVertex(@NotNull final P point) {
return new PVertex<>(point);
}
......@@ -268,57 +283,67 @@ public class PMesh<P extends IPoint> implements IMesh<P, PVertex<P>, PHalfEdge<P
}
@Override
public void insert(final PVertex<P> vertex) {
public void insert(@NotNull final PVertex<P> vertex) {
numberOfVertices++;
vertices.add(vertex);
}
@Override
public void insertVertex(final PVertex<P> vertex) {
public void insertVertex(@NotNull final PVertex<P> vertex) {
numberOfVertices++;
vertices.add(vertex);
}
@Override
public void toHole(@NotNull PFace<P> face) {
public void toHole(@NotNull final PFace<P> face) {
assert !isHole(face);
if(!isHole(face)) {
holes.add(face);
face.setBoundary(true);
numberOfHoles++;
numberOfFaces--;
}
}
@Override
public void destroyFace(@NotNull PFace<P> face) {
public void destroyFace(@NotNull final PFace<P> face) {
//faces.remove(face);
if(isHole(face)) {
// holes.remove(face);
//holes.remove(face);
numberOfHoles--;
}
else {
numberOfFaces--;
}
face.destroy();
}
@Override
public void destroyEdge(@NotNull PHalfEdge<P> edge) {
public void destroyEdge(@NotNull final PHalfEdge<P> edge) {
//edges.remove(edge);
edge.destroy();
numberOfEdges--; // we destroy the edge and its twin!
}
@Override
public void setDown(@NotNull PVertex<P> up, @NotNull PVertex<P> down) {
public void setDown(@NotNull final PVertex<P> up, @NotNull final PVertex<P> down) {
up.setDown(down);
}
@Override
public PVertex<P> getDown(@NotNull PVertex<P> vertex) {
public PVertex<P> getDown(@NotNull final PVertex<P> vertex) {
return vertex.getDown();
}
@Override
public void destroyVertex(@NotNull PVertex<P> vertex) {
public void destroyVertex(@NotNull final PVertex<P> vertex) {
//vertices.remove(vertex);
vertex.destroy();
numberOfVertices--;
}
@Override
public void setPoint(PVertex<P> vertex, P point) {
public void setPoint(@NotNull final PVertex<P> vertex, @NotNull final P point) {
vertex.setPoint(point);
}
......@@ -346,7 +371,7 @@ public class PMesh<P extends IPoint> implements IMesh<P, PVertex<P>, PHalfEdge<P
}
@Override
public Stream<PFace<P>> streamFaces(@NotNull Predicate<PFace<P>> predicate) {
public Stream<PFace<P>> streamFaces(@NotNull final Predicate<PFace<P>> predicate) {
return faces.stream().filter(predicate);
}
......@@ -356,17 +381,22 @@ public class PMesh<P extends IPoint> implements IMesh<P, PVertex<P>, PHalfEdge<P
}
@Override
public int getNumberOfEdges() {
return edges.size();
}
public int getNumberOfEdges() {
return numberOfEdges;
}
@Override
public int getNumberOfHoles() {
return numberOfHoles;
}
@Override
public IIncrementalTriangulation<P, PVertex<P>, PHalfEdge<P>, PFace<P>> toTriangulation(final @NotNull IPointLocator.Type type) {
public IIncrementalTriangulation<P, PVertex<P>, PHalfEdge<P>, PFace<P>> toTriangulation(@NotNull final IPointLocator.Type type) {
return IIncrementalTriangulation.createPTriangulation(type, this);
}
@Override
public void arrangeMemory(@NotNull Iterable<PFace<P>> faceOrder) {
public void arrangeMemory(@NotNull final Iterable<PFace<P>> faceOrder) {
try {
throw new UnsupportedOperationException("not jet implemented.");
} catch (UnsupportedOperationException e) {
......@@ -383,6 +413,10 @@ public class PMesh<P extends IPoint> implements IMesh<P, PVertex<P>, PHalfEdge<P
clone.holes = new ArrayList<>();
clone.edges = new ArrayList<>();
clone.vertices = new ArrayList<>();
clone.numberOfVertices = numberOfVertices;
clone.numberOfEdges = numberOfEdges;
clone.numberOfHoles = numberOfHoles;
clone.numberOfFaces = numberOfFaces;
Map<PVertex<P>, PVertex<P>> vertexMap = new HashMap<>();
Map<PHalfEdge<P>, PHalfEdge<P>> edgeMap = new HashMap<>();
......
......@@ -1645,12 +1645,19 @@ public interface IMesh<P extends IPoint, V extends IVertex<P>, E extends IHalfEd
int getNumberOfVertices();
/**
* Returns the number of alive faces in O(1).
* Returns the number of alive interior faces in O(1), i.e. holes and the border are excluded.
*
* @return the number of alive faces
*/
int getNumberOfFaces();
/**
* Returns the number of alive holes in O(1).
*
* @return the number of alive faces
*/
int getNumberOfHoles();
/**
* Returns the number of alive edges in O(1).
*
......
......@@ -303,7 +303,8 @@ public interface IPolyConnectivity<P extends IPoint, V extends IVertex<P>, E ext
* @param face face one
* @param otherFace face two
* @param deleteIsolatedVertices if true, vertices with degree zero will be removed from the mesh data structure otherwise they will not.
* @return the remaining face (which might be face or otherFace)
* @return (optional) the remaining face (which might be face or otherFace)
* or empty if both edges share no common edge and therefore nothing changes
*/
default Optional<F> removeEdges(@NotNull final F face, @NotNull F otherFace, final boolean deleteIsolatedVertices) {
// TODO: test it!
......@@ -325,7 +326,10 @@ public interface IPolyConnectivity<P extends IPoint, V extends IVertex<P>, E ext
}
final F finalFace = delFace;
List<E> toDeleteEdges = getMesh().streamEdges(remFace).filter(e -> getMesh().getTwinFace(e).equals(finalFace)).collect(Collectors.toList());
List<E> toDeleteEdges = getMesh().getEdges(remFace).stream().filter(e -> getMesh().getTwinFace(e).equals(finalFace)).collect(Collectors.toList());
assert getMesh().getEdges(remFace).size() > toDeleteEdges.size() : "can not remove all of the edges, since this could lead to an invalid mesh";
//List<E> survivalEdges = getMesh().streamEdges(remFace).filter(e -> !getMesh().getTwinFace(e).equals(finalFace)).collect(Collectors.toList());
// face and otherFace share no common edge.
......@@ -396,11 +400,9 @@ public interface IPolyConnectivity<P extends IPoint, V extends IVertex<P>, E ext
}
getMesh().destroyFace(delFace);
return Optional.of(remFace);
}
// TODO: improve performance by remembering faces
/**
* <p>A virus like working algorithm which merges neighbouring faces by starting at the face until
* the mergeCondition does no longer hold. This requires in the worst case O(n), where n is the number
......@@ -414,14 +416,38 @@ public interface IPolyConnectivity<P extends IPoint, V extends IVertex<P>, E ext
*
* @return the merge result i.e. the resulting face.
*/
default F mergeFaces(@NotNull final F face, @NotNull final Predicate<F> mergeCondition, final boolean deleteIsolatedVertices) {
default Optional<F> mergeFaces(@NotNull final F face, @NotNull final Predicate<F> mergeCondition, final boolean deleteIsolatedVertices) {
return mergeFaces(face, mergeCondition, deleteIsolatedVertices, -1);
}
// TODO: improve performance by remembering faces
/**
* <p>A virus like working algorithm which merges neighbouring faces by starting at the face until
* the mergeCondition does no longer hold or the maximal dept is reached.
* This requires in the worst case O(n), where n is the number of edges of all involved faces
* (i.e. the face and the merged faces).</p>
*
* <p>Changes the connectivity.</p>
*
* @param face the face
* @param mergeCondition the merge condition
* @param deleteIsolatedVertices if true, vertices with degree zero will be removed from the mesh data structure otherwise they will not.
* @param maxDept the maximum dept / neighbouring distance at which faces can be removed
*
* @return the merge result i.e. the resulting face.
*/
default Optional<F> mergeFaces(@NotNull final F face, @NotNull final Predicate<F> mergeCondition, final boolean deleteIsolatedVertices, final int maxDept) {
boolean modified = true;
F currentFace = face;
int dept = 0;
while (modified) {
modified = false;
dept++;
List<F> neighbouringFaces = getMesh().getFaces(currentFace);
assert neighbouringFaces.isEmpty() || neighbouringFaces.stream().anyMatch(f -> !f.equals(neighbouringFaces.get(0))) : "each edge of both faces is a link to the other face";
for(F neighbouringFace : neighbouringFaces) {
// the face might be destroyed by an operation before
if(!getMesh().isDestroyed(neighbouringFace) && mergeCondition.test(neighbouringFace)) {
......@@ -431,11 +457,25 @@ public interface IPolyConnectivity<P extends IPoint, V extends IVertex<P>, E ext
modified = true;
currentFace = optionalMergeResult.get();
}
else {
if(getMesh().isDestroyed(currentFace)) {
return Optional.empty();
}
}
}
}
if(maxDept > 0 && dept >= maxDept) {
if(getMesh().isDestroyed(currentFace)) {
return Optional.empty();
}
else {
return Optional.of(currentFace);
}
}
}
return currentFace;
return Optional.of(currentFace);
}
/**
......@@ -447,16 +487,20 @@ public interface IPolyConnectivity<P extends IPoint, V extends IVertex<P>, E ext
* @param face they face which will be transformed into a hole
* @param mergeCondition the merge condition
* @param deleteIsoletedVertices if true isolated vertices, i.e. vertices without any edges, will be removed from the mesh
* @return the hole or face itself it the face does not fulfill the merge condition
* @return (optional) the hole or face itself it the face does not fulfill the merge condition
* or empty if due to the creation of the hole all faces will be removed!
*/
default F createHole(@NotNull final F face, @NotNull final Predicate<F> mergeCondition, final boolean deleteIsoletedVertices) {
default Optional<F> createHole(@NotNull final F face, @NotNull final Predicate<F> mergeCondition, final boolean deleteIsoletedVertices) {
if(mergeCondition.test(face)) {
F remainingFace = mergeFaces(face, mergeCondition, deleteIsoletedVertices);
getMesh().toHole(remainingFace);
Optional<F> remainingFace = mergeFaces(face, mergeCondition, deleteIsoletedVertices);
if(remainingFace.isPresent()) {
getMesh().toHole(remainingFace.get());
}
return remainingFace;
}
else {
return face;
return Optional.of(face);
}
}
......@@ -959,10 +1003,24 @@ public interface IPolyConnectivity<P extends IPoint, V extends IVertex<P>, E ext
// no such candidate was found. This can happen if an island will be deleted.
if(twinFace.equals(face)) {
log.warn("no boundary candidate was found, we search through all edges of the mesh.");
boundaryEdge = getMesh().streamEdges()
Optional<E> optBoundaryEdge = getMesh().streamEdges()
.filter(e -> getMesh().getFace(e).equals(boundary))
.filter(e -> !getMesh().getTwinFace(e).equals(face))
.findAny().get();
.findAny();
if(!optBoundaryEdge.isPresent()) {
if(getMesh().getEdges(boundary).size() == delEdges.size()) {
log.warn(face + " is the last remaining face which will be deletes as well, therefore the mesh will be emoty!");
assert getMesh().getNumberOfFaces() == 1;
getMesh().clear();
return;
}
else {
}
} else {
boundaryEdge = optBoundaryEdge.get();
}
}
getMesh().setFace(boundaryEdge, boundary);
......
package org.vadere.meshing.mesh.iterators;
import org.jetbrains.annotations.NotNull;
import org.vadere.meshing.mesh.inter.IFace;
import org.vadere.meshing.mesh.inter.IHalfEdge;
import org.vadere.meshing.mesh.inter.IMesh;
......@@ -22,7 +23,8 @@ public class SurroundingFaceIterator<P extends IPoint, V extends IVertex<P>, E e
private EdgeIterator<P, V, E, F> edgeIterator;
private IMesh<P, V, E, F> mesh;
public SurroundingFaceIterator(final IMesh<P, V, E, F> mesh, final F face) {
public SurroundingFaceIterator(@NotNull final IMesh<P, V, E, F> mesh, @NotNull final F face) {
assert mesh.isAlive(face);
this.mesh = mesh;
this.edgeIterator = new EdgeIterator<>(mesh, face);
}
......
......@@ -2,20 +2,16 @@ package org.vadere.geometry.mesh;
import org.junit.Before;
import org.junit.Test;
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.impl.VPTriangulation;
import org.vadere.meshing.mesh.inter.IIncrementalTriangulation;
import org.vadere.util.geometry.shapes.VPoint;
import org.vadere.util.geometry.shapes.VRectangle;
import org.vadere.meshing.mesh.gen.MeshPanel;
import java.util.List;
import java.util.function.Predicate;
import javax.swing.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* @author Benedikt Zoennchen
......@@ -49,40 +45,38 @@ public class TestMeshManipulations {
}
@Test
public void testRemoveFace() {
public void testRemoveSomeFacesByHoleCreation() {
int numberOfFaces = triangulation.getMesh().getNumberOfFaces();
// locate a face / triangle containing (4, 5)
PFace<VPoint> face = triangulation.locateFace(6, 6).get();
// merge faces until infinity, therefore consumes all faces!
Predicate<PFace<VPoint>> mergePredicate = f -> true;
int maxDept = 1;
// since max dept is equal to 1 we merge 4 (the face and its 3 neighbours) triangles into 1 polygon
assertTrue(triangulation.mergeFaces(face, mergePredicate, true, maxDept).isPresent());