Currently job artifacts in CI/CD pipelines on LRZ GitLab never expire. Starting from Wed 26.1.2022 the default expiration time will be 30 days (GitLab default). Currently existing artifacts in already completed jobs will not be affected by the change. The latest artifacts for all jobs in the latest successful pipelines will be kept. More information: https://gitlab.lrz.de/help/user/admin_area/settings/continuous_integration.html#default-artifacts-expiration

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(<