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

Commit fff7a7b3 authored by Stefan Schuhbaeck's avatar Stefan Schuhbaeck
Browse files

Merge branch 'master' into 181_gnm_linkedCellGridAssertion

parents 10ae9e85 5f80dd44
......@@ -184,7 +184,7 @@
</executions>
</plugin>
<plugin>
<!-- Maven Surefire is used to execute unit tests. -->
<!-- Maven Surefire is used to cup unit tests. -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19</version>
......
......@@ -137,7 +137,7 @@ public class ClassFinder {
* Scans all classes accessible from the context class loader which belong to the given package
* and subpackages.
*
* Deprecated since this method is slow if we have to access jar file, which is the case if we execute the project via vadere.jar!
* Deprecated since this method is slow if we have to access jar file, which is the case if we cup the project via vadere.jar!
*
* @param packageName The base package
* @return The classes
......
......@@ -5,7 +5,7 @@ import java.awt.event.ActionEvent;
import org.vadere.gui.topographycreator.model.IDrawPanelModel;
/**
* A ActionBasic is the last action in the decorator pattern which will be execute.
* A ActionBasic is the last action in the decorator pattern which will be cup.
* Action: Notify all Observers.
*
*/
......
......@@ -42,7 +42,7 @@ public class ActionMergeObstacles extends TopographyAction {
.collect(Collectors.toList());
WeilerAtherton weilerAtherton = new WeilerAtherton(polygons);
List<VPolygon> mergedPolygons = weilerAtherton.execute();
List<VPolygon> mergedPolygons = weilerAtherton.cup();
// remove polygon obstacles
getScenarioPanelModel().removeObstacleIf(obstacle ->
......
......@@ -53,6 +53,6 @@ public class EditMergeObstacles extends AbstractUndoableEdit {
@Override
public String getPresentationName() {
return "merge obstacles";
return "cup obstacles";
}
}
......@@ -78,7 +78,7 @@
</executions>
</plugin>
<plugin>
<!-- Maven Surefire is used to execute unit tests. -->
<!-- Maven Surefire is used to cup unit tests. -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19</version>
......
......@@ -9,15 +9,18 @@ import org.vadere.meshing.mesh.gen.PMesh;
import org.vadere.meshing.mesh.gen.PVertex;
import org.vadere.meshing.mesh.inter.IPolyConnectivity;
import org.vadere.util.geometry.GeometryUtils;
import org.vadere.util.geometry.shapes.IPoint;
import org.vadere.util.geometry.shapes.VLine;
import org.vadere.util.geometry.shapes.VPoint;
import org.vadere.util.geometry.shapes.VPolygon;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
......@@ -125,7 +128,9 @@ public class WeilerAtherton {
// compute intersections and add those to the two faces, this implementation is rather slow!
boolean intersectionFound = true;
int count = 0;
while (intersectionFound) {
List<PHalfEdge<WeilerPoint>> clippingEdges = clippingMesh.getEdges(clippingFace);
List<PHalfEdge<WeilerPoint>> subjectEdges = subjectMesh.getEdges(subjectFace);
intersectionFound = false;
......@@ -133,7 +138,6 @@ public class WeilerAtherton {
for(PHalfEdge<WeilerPoint> clippingEdge : clippingEdges) {
for(PHalfEdge<WeilerPoint> subjectEdge : subjectEdges) {
Optional<VPoint> optIntersectionPoint = equalIntersectionPoints(subjectEdge, subjectMesh, clippingEdge, clippingMesh);
if(!optIntersectionPoint.isPresent()) {
VLine l1 = subjectMesh.toLine(subjectEdge);
VLine l2 = clippingMesh.toLine(clippingEdge);
......@@ -165,6 +169,9 @@ public class WeilerAtherton {
PVertex<WeilerPoint> ip1 = IPolyConnectivity.splitEdge(subjectEdge, wp1, subjectMesh);
PVertex<WeilerPoint> ip2 = IPolyConnectivity.splitEdge(clippingEdge, wp2, clippingMesh);
subjectMesh.getPoint(ip1).setInside(true);
clippingMesh.getPoint(ip2).setInside(true);
wp1.setTwinPoint(ip2);
wp2.setTwinPoint(ip1);
......@@ -263,7 +270,7 @@ public class WeilerAtherton {
*
* @return a list of merged polygons
*/
public List<VPolygon> execute() {
public List<VPolygon> cup() {
boolean merged = true;
List<VPolygon> newPolygons = new ArrayList<>();
......@@ -273,17 +280,18 @@ public class WeilerAtherton {
int ii = -1;
int jj = -1;
merged = false;
Pair<VPolygon, VPolygon> mergeResult = null;
List<VPolygon> cupResult = null;
for(int i = 0; i < newPolygons.size(); i++) {
VPolygon first = newPolygons.get(i);
for(int j = i+1; j < newPolygons.size(); j++) {
VPolygon second = newPolygons.get(j);
mergeResult = merge(first, second);
cupResult = cup(first, second);
assert cupResult.size() <= 2;
// something got merged
if(mergeResult.getSecond() == null) {
if(cupResult.size() <= 1) {
merged = true;
ii = i;
jj = j;
......@@ -299,7 +307,7 @@ public class WeilerAtherton {
if(merged) {
newPolygons.remove(ii);
newPolygons.remove(jj-1);
newPolygons.add(mergeResult.getFirst());
newPolygons.add(cupResult.get(0));
}
}
......@@ -307,50 +315,209 @@ public class WeilerAtherton {
}
/**
* Executes the Weiler-Atherton-Algorithm for two polygons.
* Executes the Weiler-Atherton-Algorithm for all of its polygons.
*
* @param subjectCandidat the first polygon
* @param clippingCandidat the second polygon
* @return a pair of polygon where the second element is null if the polygons got merged. This is not the case if there do not overlap.
* @return a list of merged polygons
*/
public Pair<VPolygon, VPolygon> merge(@NotNull final VPolygon subjectCandidat, @NotNull final VPolygon clippingCandidat) {
public Optional<VPolygon> cap() {
List<VPolygon> newPolygons = new ArrayList<>();
newPolygons.addAll(polygons);
if(polygons.size() == 0) {
return Optional.empty();
}
else if(polygons.size() == 1) {
return Optional.of(polygons.get(0));
}
else {
LinkedList<VPolygon> toDo = new LinkedList<>();
toDo.addAll(polygons);
VPolygon subject = GeometryUtils.isCCW(subjectCandidat) ? subjectCandidat.revertOrder() : subjectCandidat;
VPolygon clipping = GeometryUtils.isCCW(clippingCandidat) ? clippingCandidat.revertOrder() : clippingCandidat;
while (toDo.size() >= 2) {
VPolygon poly1 = toDo.remove();
VPolygon poly2 = toDo.remove();
List<VPolygon> capResult = cap(poly1, poly2);
if(capResult.isEmpty()) {
return Optional.empty();
}
toDo.addAll(capResult);
}
assert toDo.size() == 1;
return Optional.of(toDo.remove());
}
}
private boolean contains(@NotNull final VPolygon polygon, @NotNull final IPoint point) {
return polygon.contains(point) || Math.abs(polygon.distance(point)) <= GeometryUtils.DOUBLE_EPS;
}
private List<VPolygon> construct(
@NotNull final VPolygon subjectCandidat,
@NotNull final VPolygon clippingCandidat,
final boolean cap) {
//Predicate<WeilerPoint> startEdgeCondition = cap ? p -> p.isInside() : p -> !p.isInside();
VPolygon subject = GeometryUtils.isCCW(subjectCandidat) ? subjectCandidat : subjectCandidat.revertOrder();
VPolygon clipping = GeometryUtils.isCCW(clippingCandidat) ? clippingCandidat : clippingCandidat.revertOrder();
PMesh<WeilerPoint> subjectMesh = new PMesh<>((x,y) -> new WeilerPoint(new VPoint(x,y), false, false));
PMesh<WeilerPoint> clippingMesh = new PMesh<>((x,y) -> new WeilerPoint(new VPoint(x,y), false, false));
List<VPolygon> result = new ArrayList<>(2);
//List<VPolygon> result = new ArrayList<>(2);
/**
* (1) construct the list connections
*/
Pair<PFace<WeilerPoint>, PFace<WeilerPoint>> pair = constructIntersectionFaces(subject, subjectMesh, clipping, clippingMesh);
PFace<WeilerPoint> subjectFace = pair.getFirst();
PFace<WeilerPoint> clippingFace = pair.getSecond();
Set<PHalfEdge<WeilerPoint>> subjectExitingEdges = subjectMesh
.streamEdges(subjectFace)
.filter(edge -> subjectMesh.getPoint(edge).isIntersectionPoint())
.filter(edge ->
contains(clipping, subjectMesh.getPoint(subjectMesh.getPrev(edge))) &&
!contains(clipping, subjectMesh.getPoint(subjectMesh.getNext(edge))))
.collect(Collectors.toSet());
Set<PHalfEdge<WeilerPoint>> subjectEnteringEdges = subjectMesh
.streamEdges(subjectFace)
.filter(edge -> subjectMesh.getPoint(edge).isIntersectionPoint())
.filter(edge ->
contains(clipping, subjectMesh.getPoint(subjectMesh.getNext(edge))) &&
!contains(clipping, subjectMesh.getPoint(subjectMesh.getPrev(edge)))
)
.collect(Collectors.toSet());
List<VPoint> points = new ArrayList<>();
List<VPolygon> polygons = new ArrayList<>();
PMesh<WeilerPoint> mesh = subjectMesh;
Set<PHalfEdge<WeilerPoint>> intersectionSet = cap ? subjectEnteringEdges : subjectExitingEdges;
// cup will preserve the polyons.
if(intersectionSet.isEmpty()) {
boolean subInClip = subjectMesh
.streamPoints(subjectFace)
.allMatch(p -> contains(clipping, p));
boolean clipInSub = clippingMesh
.streamPoints(clippingFace)
.allMatch(p -> contains(subject, p));
if(cap) {
if(subInClip) {
polygons.add(subjectCandidat);
}
else if(clipInSub) {
polygons.add(clippingCandidat);
}
}
else {
if(subInClip) {
polygons.add(clippingCandidat);
}
else if(clipInSub) {
polygons.add(subjectCandidat);
}
else {
polygons.add(subjectCandidat);
polygons.add(clippingCandidat);
}
}
return polygons;
}
while (!intersectionSet.isEmpty()) {
PHalfEdge<WeilerPoint> subjectEdge = intersectionSet.iterator().next();
PHalfEdge<WeilerPoint> subjectTwin = clippingMesh.getEdge(subjectMesh.getPoint(subjectEdge).getTwinPoint());
PHalfEdge<WeilerPoint> next = subjectEdge;
intersectionSet.remove(subjectEdge);
do {
next = mesh.getNext(next);
// adaptPath
if(mesh.getPoint(next).isIntersectionPoint()) {
/*
* Special case!
*/
PVertex<WeilerPoint> twinPoint = mesh.getPoint(next).getTwinPoint();
PMesh<WeilerPoint> twinMesh = mesh.equals(subjectMesh) ? clippingMesh : subjectMesh;
PHalfEdge<WeilerPoint> twinPointEdge = twinMesh.getEdge(twinPoint);
VPoint prevTwinPoint = new VPoint(twinMesh.getPoint(twinMesh.getPrev(twinPointEdge)));
VPoint prevPoint = new VPoint(mesh.getPoint(mesh.getPrev(next)));
intersectionSet.remove(next);
intersectionSet.remove(twinMesh.getEdge(twinPoint));
if(!prevTwinPoint.equals(prevPoint)) {
mesh = mesh.equals(subjectMesh) ? clippingMesh : subjectMesh;
next = mesh.getEdge(mesh.getPoint(next).getTwinPoint());
}
}
points.add(new VPoint(mesh.getPoint(next)));
} while (!next.equals(subjectEdge) && !next.equals(subjectTwin));
polygons.add(GeometryUtils.toPolygon(GeometryUtils.filterUselessPoints(points, EPSILON)));
}
return polygons;
/*PFace<WeilerPoint> subjectFace = pair.getFirst();
PFace<WeilerPoint> clippingFace = pair.getSecond();
// phase (2)
Optional<PHalfEdge<WeilerPoint>> intersectionEdges = subjectMesh.findAnyEdge(p -> p.isIntersectionPoint());
Optional<PHalfEdge<WeilerPoint>> optStartPointSub = subjectMesh.findAnyEdge(p -> !p.isIntersectionPoint() && !p.isInside());
Optional<PHalfEdge<WeilerPoint>> optStartPointClip = clippingMesh.findAnyEdge(p -> !p.isIntersectionPoint() && !p.isInside());
Optional<PHalfEdge<WeilerPoint>> optStartPointSub = subjectMesh.findAnyEdge(startEdgeCondition);
Optional<PHalfEdge<WeilerPoint>> optStartPointClip = clippingMesh.findAnyEdge(startEdgeCondition);
Optional<PHalfEdge<WeilerPoint>> subInsideEdge = subjectMesh.findAnyEdge(p -> p.isInside());
Optional<PHalfEdge<WeilerPoint>> clipInsideEdge = clippingMesh.findAnyEdge(p -> p.isInside());
Optional<PHalfEdge<WeilerPoint>> subOutsideEdge = subjectMesh.findAnyEdge(p -> !p.isInside());
Optional<PHalfEdge<WeilerPoint>> clipOutsideEdge = clippingMesh.findAnyEdge(p -> !p.isInside());
// no point intersection and no point is contained in the other polygon => polygons do not overlap at all
if(optStartPointSub.isPresent() && optStartPointClip.isPresent() && !intersectionEdges.isPresent()) {
result.add(subject);
result.add(clipping);
return Pair.create(subject, clipping);
if(!subInsideEdge.isPresent() && !clipInsideEdge.isPresent() && !intersectionEdges.isPresent()) {
// complete merge
if(!cap) {
return Pair.create(subject, clipping);
}
else {
return Pair.create(null, null);
}
}
// no point intersections and there is a point of the subject outside of the clipping => clipping is fully contained in subject
if(optStartPointSub.isPresent() && !intersectionEdges.isPresent()) {
result.add(subject);
return Pair.create(subject, null);
if(subOutsideEdge.isPresent() && !intersectionEdges.isPresent()) {
// cup is the subject
if(!cap) {
return Pair.create(subject, null);
} // cap is the clipping
else {
return Pair.create(clipping, null);
}
}
// no point intersections and there is a point of the clipping outside of the subject => subject is fully contained in clipping
if(optStartPointClip.isPresent() && !intersectionEdges.isPresent()) {
result.add(clipping);
return pair.create(clipping, null);
if(clipOutsideEdge.isPresent() && !intersectionEdges.isPresent()) {
// cup is the subject
if(!cap) {
return Pair.create(clipping, null);
} // cap is the clipping
else {
return Pair.create(subject, null);
}
}
PHalfEdge<WeilerPoint> first = null;
......@@ -374,24 +541,61 @@ public class WeilerAtherton {
PMesh<WeilerPoint> mesh = mesh1;
List<VPoint> points = new ArrayList<>();
int count = 0;
boolean foundDiff = false;
do {
next = mesh.getNext(next);
count++;
//next = mesh.getNext(next);
WeilerPoint wp = mesh.getPoint(next);
// walk into the other mesh / polygon
if(wp.isIntersectionPoint()) {
// swap meshes
mesh = mesh == mesh1 ? mesh2 : mesh1;
mesh = (mesh == mesh1 ? mesh2 : mesh1);
// swap edges
next = mesh.getEdge(wp.twinPoint);
}
if(count > 1000) {
System.out.println(count + " (2)");
constructIntersectionFaces(subject, subjectMesh, clipping, clippingMesh);
}
try {
next = mesh.getNext(next);
}
catch (NullPointerException e) {
System.out.println("shit");
}
points.add(new VPoint(wp));
if(!points.get(0).equals(mesh.getPoint(next))) {
foundDiff = true;
}
}
while (!foundDiff || !points.get(0).equals(mesh.getPoint(next)));
try{
Pair.create(GeometryUtils.toPolygon(GeometryUtils.filterUselessPoints(points, EPSILON)), null);
}
while (!next.equals(first));
catch (Exception e) {
System.out.println("baba");
}
return Pair.create(GeometryUtils.toPolygon(GeometryUtils.filterUselessPoints(points, EPSILON)), null);*/
}
return Pair.create(GeometryUtils.toPolygon(GeometryUtils.filterUselessPoints(points, EPSILON)), null);
public List<VPolygon> cap(@NotNull final VPolygon subjectCandidat, @NotNull final VPolygon clippingCandidat) {
return construct(subjectCandidat, clippingCandidat, true);
}
/**
* Executes the Weiler-Atherton-Algorithm for two polygons.
*
* @param subjectCandidat the first polygon
* @param clippingCandidat the second polygon
* @return a pair of polygon where the second element is null if the polygons got merged. This is not the case if there do not overlap.
*/
public List<VPolygon> cup(@NotNull final VPolygon subjectCandidat, @NotNull final VPolygon clippingCandidat) {
return construct(subjectCandidat, clippingCandidat, false);
}
}
......@@ -491,7 +491,7 @@ public class AMesh<P extends IPoint> implements IMesh<P, AVertex<P>, AHalfEdge<P
// clone the old one!
AMesh<P> cMesh = clone();
// merge some of them?
// cup some of them?
int nullIdentifier = -2;
// rebuild
......@@ -554,7 +554,7 @@ public class AMesh<P extends IPoint> implements IMesh<P, AVertex<P>, AHalfEdge<P
}
private void copyFace(@NotNull final AFace<P> face, @NotNull int[] vertexMap, @NotNull int[] edgeMap, @NotNull int[] faceMap, @NotNull final AMesh<P> cMesh) {
// merge some of them?
// cup some of them?
int nullIdentifier = -2;
// face not jet copied
......
......@@ -160,11 +160,22 @@ public interface IPolyConnectivity<P extends IPoint, V extends IVertex<P>, E ext
*/
static <P extends IPoint, V extends IVertex<P>, E extends IHalfEdge<P>, F extends IFace<P>> V splitEdge(
@NotNull final E edge, @NotNull P p, @NotNull IMesh<P, V, E, F> mesh) {
V u = mesh.createVertex(p);
E twin = mesh.getTwin(edge);
if(mesh.getPoint(edge).equals(p)) {
return mesh.getVertex(edge);
}
if(mesh.getPoint(twin).equals(p)) {
return mesh.getVertex(mesh.getPrev(edge));
}
E prev = mesh.getPrev(edge);
E tNext = mesh.getNext(twin);
V u = mesh.createVertex(p);
E e = mesh.createEdge(u);
mesh.setFace(e, mesh.getFace(edge));
E t = mesh.createEdge(mesh.getVertex(twin));
......@@ -411,10 +422,10 @@ public interface IPolyConnectivity<P extends IPoint, V extends IVertex<P>, E ext
* <p>Changes the connectivity.</p>
*
* @param face the face
* @param mergeCondition the merge condition
* @param mergeCondition the cup condition
* @param deleteIsolatedVertices if true, vertices with degree zero will be removed from the mesh data structure otherwise they will not.
*
* @return the merge result i.e. the resulting face.
* @return the cup result i.e. the resulting face.
*/
default Optional<F> mergeFaces(@NotNull final F face, @NotNull final Predicate<F> mergeCondition, final boolean deleteIsolatedVertices) {
return mergeFaces(face, mergeCondition, deleteIsolatedVertices, -1);
......@@ -430,11 +441,11 @@ public interface IPolyConnectivity<P extends IPoint, V extends IVertex<P>, E ext
* <p>Changes the connectivity.</p>
*
* @param face the face
* @param mergeCondition the merge condition
* @param mergeCondition the cup 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.
* @return the cup 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;
......@@ -480,14 +491,14 @@ public interface IPolyConnectivity<P extends IPoint, V extends IVertex<P>, E ext
/**
* Creates a new hole or extends an existing hole by removing neighbouring faces as
* long as the merge condition holds.
* long as the cup condition holds.
*
* Changes the connectivity.
*
* @param face they face which will be transformed into a hole
* @param mergeCondition the merge condition
* @param mergeCondition the cup condition
* @param deleteIsoletedVertices if true isolated vertices, i.e. vertices without any edges, will be removed from the mesh
* @return (optional) 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 cup condition
* or empty if due to the creation of the hole all faces will be removed!
*/
default Optional<F> createHole(@NotNull final F face, @NotNull final Predicate<F> mergeCondition, final boolean deleteIsoletedVertices) {
......
......@@ -253,7 +253,7 @@ public class EikMesh<P extends EikMeshPoint, V extends IVertex<P>, E extends IHa
//removeTrianglesInsideObstacles();
}
/*public void execute() {
/*public void cup() {
double quality = getQuality();
while (quality < Parameters.qualityMeasurement) {
improve();
......
......@@ -603,7 +603,7 @@ public class UniformRefinementTriangulatorSFC<P extends IPoint, V extends IVerte
F twin = getMesh().getTwinFace(edge);
VTriangle triangle = getMesh().toTriangle(face);
return (!triangle.intersects(bbox) && (getMesh().isBoundary(twin) || !getMesh().toTriangle(twin).intersects(bbox)));
return (!triangle.intersectsRectangleLine(bbox) && (getMesh().isBoundary(twin) || !getMesh().toTriangle(twin).intersectsRectangleLine(bbox)));
}
/**
......
......@@ -212,7 +212,7 @@ public class UniformSFCTriangulator<P extends IPoint, V extends IVertex<P>, E ex
VLine line = mesh.toLine(edge);
return (line.length() <= lenFunc.apply(line.midPoint()) && random.nextDouble() < 0.96)
|| (!triangle.intersects(bbox) && (mesh.isBoundary(twin) || !mesh.toTriangle(twin).intersects(bbox)))
|| (!triangle.intersectsRectangleLine(bbox) && (mesh.isBoundary(twin) || !mesh.toTriangle(twin).intersectsRectangleLine(bbox)))
|| boundary.stream().anyMatch(shape -> shape.contains(triangle.getBounds2D()) || (!mesh.isBoundary(twin) && shape.contains(mesh.toTriangle(twin).getBounds2D())));
}
......
......@@ -9,10 +9,13 @@ import org.vadere.meshing.mesh.gen.PMesh;
import org.vadere.util.geometry.GeometryUtils;
import org.vadere.util.geometry.shapes.VPoint;
import org.vadere.util.geometry.shapes.VPolygon;
import org.vadere.util.geometry.shapes.VRectangle;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
......@@ -24,6 +27,31 @@ public class TestWeilerAtherton {
@Before
public void setUp() throws Exception {}
@Test
public void testRectangleIntersectionSpecialCase() {
VRectangle rec1 = new VRectangle(0, 0, 5, 5);
VRectangle rec2 = new VRectangle(2, 0, 5, 5);
VRectangle expectedResult = new VRectangle(2,0,3,5);
List<VPolygon> originalList = Arrays.asList(new VPolygon(rec1), new VPolygon(rec2));
WeilerAtherton weilerAtherton = new WeilerAtherton(originalList);