Commit a27795de authored by Riegel's avatar Riegel
Browse files

Bugfix for found false positives of C_GE_S_SELF_INTERSECTION

parent 216ab18a
Pipeline #9981 passed with stage
in 1 minute and 14 seconds
...@@ -78,6 +78,43 @@ public class PolyLine extends BaseEntity { ...@@ -78,6 +78,43 @@ public class PolyLine extends BaseEntity {
return mpLast; return mpLast;
} }
public Boolean isNullLine() {
return isNullLine(0.00);
}
public Boolean isNullLine(Double tolerance) {
// If either start or end Segment is null, return immediately
if (mpFirst == null || mpLast == null) {
return true;
}
PolyLineSegment currentSegment = mpFirst;
Double length = 0.00;
// Add length of all segments, starting from mpFirst
do {
Double segmentLength = currentSegment.getLengthVector().getLength();
if (segmentLength > tolerance) {
length += segmentLength;
}
if (currentSegment.getNext() != null) {
currentSegment = currentSegment.getNext();
}
} while (currentSegment.getNext() != null);
// Since mpLast will be missed due to loop condition add its length afterwards
Double segmentLength = mpLast.getLengthVector().getLength();
if (segmentLength > tolerance) {
length += segmentLength;
}
// Check if total length is less than the set tolerance
if (length <= tolerance) {
return true;
}
return false;
}
@Override @Override
public String toString() { public String toString() {
return "PolyLine [mpFirst=" + mpFirst + ", mpLast=" + mpLast + "]"; return "PolyLine [mpFirst=" + mpFirst + ", mpLast=" + mpLast + "]";
......
...@@ -58,6 +58,11 @@ public class PolyLineSegment extends BaseEntity { ...@@ -58,6 +58,11 @@ public class PolyLineSegment extends BaseEntity {
return mpNext; return mpNext;
} }
public Vector3d getLengthVector() {
Vector3d representation = mpEnd.getPoint().minus(mpStart.getPoint());
return representation;
}
@Override @Override
public String toString() { public String toString() {
return "PolyLineSegment [mpStart=" + mpStart + ", mpEnd=" + mpEnd + "]"; return "PolyLineSegment [mpStart=" + mpStart + ", mpEnd=" + mpEnd + "]";
......
...@@ -34,9 +34,12 @@ import de.hft.stuttgart.citydoctor2.check.ResultStatus; ...@@ -34,9 +34,12 @@ import de.hft.stuttgart.citydoctor2.check.ResultStatus;
import de.hft.stuttgart.citydoctor2.check.error.SolidSelfIntError; import de.hft.stuttgart.citydoctor2.check.error.SolidSelfIntError;
import de.hft.stuttgart.citydoctor2.checks.util.CollectionUtils; import de.hft.stuttgart.citydoctor2.checks.util.CollectionUtils;
import de.hft.stuttgart.citydoctor2.checks.util.SelfIntersectionUtil; import de.hft.stuttgart.citydoctor2.checks.util.SelfIntersectionUtil;
import de.hft.stuttgart.citydoctor2.datastructure.ConcretePolygon;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry; import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.datastructure.GeometryType; import de.hft.stuttgart.citydoctor2.datastructure.GeometryType;
import de.hft.stuttgart.citydoctor2.math.Segment3d;
import de.hft.stuttgart.citydoctor2.utils.PolygonIntersection; import de.hft.stuttgart.citydoctor2.utils.PolygonIntersection;
import de.hft.stuttgart.citydoctor2.utils.PolygonIntersection.IntersectionType;
/** /**
* Check for self intersecting solids * Check for self intersecting solids
......
...@@ -118,13 +118,20 @@ public class SelfIntersectionUtil { ...@@ -118,13 +118,20 @@ public class SelfIntersectionUtil {
Polygon p1, Polygon p2) { Polygon p1, Polygon p2) {
EdgePolygon edgeP1 = edgePolyMap.get(p1); EdgePolygon edgeP1 = edgePolyMap.get(p1);
EdgePolygon edgeP2 = edgePolyMap.get(p2); EdgePolygon edgeP2 = edgePolyMap.get(p2);
List<PolygonPolygonIntersection> result = IntersectPlanarPolygons.intersectPolygons(edgeP1, edgeP2, 0.000001, 0.001); List<PolygonPolygonIntersection> results = IntersectPlanarPolygons.intersectPolygons(edgeP1, edgeP2, 0.000001, 0.001);
if (!result.isEmpty()) { if (!results.isEmpty()) {
// at least one intersection happened // at least one intersection happened
for (PolygonPolygonIntersection result: results) {
// Ensure that Intersection-Edge is not a Null-Line.
// If it is a Null-Line, detected Intersection is a False-Positive.
if (!result.getPolyLine().isNullLine()) {
intersections.add(PolygonIntersection.lines(Collections.emptyList(), p1, p2)); intersections.add(PolygonIntersection.lines(Collections.emptyList(), p1, p2));
} }
} }
}
}
/** /**
* Checks if two polygons are intersecting. Result may be nothing, a line or a * Checks if two polygons are intersecting. Result may be nothing, a line or a
* polygon if they are planar and intersecting. * polygon if they are planar and intersecting.
......
...@@ -197,4 +197,6 @@ public class RingSelfIntCheckTest { ...@@ -197,4 +197,6 @@ public class RingSelfIntCheckTest {
} }
} }
...@@ -18,8 +18,15 @@ ...@@ -18,8 +18,15 @@
*/ */
package de.hft.stuttgart.citydoctor2.checks.geometry; package de.hft.stuttgart.citydoctor2.checks.geometry;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.List;
import org.apache.logging.log4j.core.util.internal.Status;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
...@@ -28,8 +35,11 @@ import de.hft.stuttgart.citydoctor2.check.Checker; ...@@ -28,8 +35,11 @@ import de.hft.stuttgart.citydoctor2.check.Checker;
import de.hft.stuttgart.citydoctor2.check.ResultStatus; import de.hft.stuttgart.citydoctor2.check.ResultStatus;
import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration; import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration;
import de.hft.stuttgart.citydoctor2.checks.util.GeometryTestUtils; import de.hft.stuttgart.citydoctor2.checks.util.GeometryTestUtils;
import de.hft.stuttgart.citydoctor2.datastructure.Building;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel; import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry; import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.datastructure.GeometryType;
import de.hft.stuttgart.citydoctor2.datastructure.Lod;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException; import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParser; import de.hft.stuttgart.citydoctor2.parser.CityGmlParser;
import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException; import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException;
...@@ -73,4 +83,96 @@ public class SolidSelfIntCheckTest { ...@@ -73,4 +83,96 @@ public class SolidSelfIntCheckTest {
assertFalse(m.getBuildings().get(0).containsAnyError()); assertFalse(m.getBuildings().get(0).containsAnyError());
} }
@Test
public void testKnownFalsePositiveExample1() throws CityGmlParseException, InvalidGmlFileException {
ValidationConfiguration config = ValidationConfiguration.loadStandardValidationConfig();
config.setSchematronFilePathInGlobalParameters(null);
CityDoctorModel m = CityGmlParser.parseCityGmlFile("src/test/resources/SolidSelfIntTest-known_false_positive1.gml", config.getParserConfiguration());
Checker c = new Checker(config, m);
c.runChecks();
Building building = m.getBuildings().get(0);
System.out.println(building.containsAnyError());
// Example1 Building has some BuildingInstallations, which throw semantic errors
if (building.containsAnyError()) {
Geometry buildingGeom = building.getGeometry(GeometryType.SOLID, Lod.LOD2);
buildingGeom.clearCheckResults();
SolidSelfIntCheck check = new SolidSelfIntCheck();
check.check(buildingGeom);
CheckResult cr = buildingGeom.getCheckResult(check);
assertNotNull(cr);
//Ensure that checker did not find a self intersection
assertEquals("Known False-Positive self-intersection was detected as error", ResultStatus.OK, cr.getResultStatus());
}
}
@Test
public void testKnownFalsePositiveExample2() throws CityGmlParseException, InvalidGmlFileException {
ValidationConfiguration config = ValidationConfiguration.loadStandardValidationConfig();
config.setSchematronFilePathInGlobalParameters(null);
CityDoctorModel m = CityGmlParser.parseCityGmlFile("src/test/resources/SolidSelfIntTest-known_false_positive2.gml", config.getParserConfiguration());
Checker c = new Checker(config, m);
c.runChecks();
Building building = m.getBuildings().get(0);
// If an error was found, check if error is SolidSelfInt
if (building.containsAnyError()) {
Geometry buildingGeom = building.getGeometry(GeometryType.SOLID, Lod.LOD2);
buildingGeom.clearCheckResults();
SolidSelfIntCheck check = new SolidSelfIntCheck();
check.check(buildingGeom);
CheckResult cr = buildingGeom.getCheckResult(check);
assertNotNull(cr);
assertEquals("Known False-Positive self-intersection was detected as error", ResultStatus.OK, cr.getResultStatus());
}
}
@Test
public void testKnownFalsePositiveExample3() throws CityGmlParseException, InvalidGmlFileException {
ValidationConfiguration config = ValidationConfiguration.loadStandardValidationConfig();
config.setSchematronFilePathInGlobalParameters(null);
CityDoctorModel m = CityGmlParser.parseCityGmlFile("src/test/resources/SolidSelfIntTest-known_false_positive3.gml", config.getParserConfiguration());
Checker c = new Checker(config, m);
c.runChecks();
Building building = m.getBuildings().get(0);
// If an error was found, check if error is SolidSelfInt
if (building.containsAnyError()) {
Geometry buildingGeom = building.getGeometry(GeometryType.SOLID, Lod.LOD2);
buildingGeom.clearCheckResults();
SolidSelfIntCheck check = new SolidSelfIntCheck();
check.check(buildingGeom);
CheckResult cr = buildingGeom.getCheckResult(check);
assertNotNull(cr);
//Ensure that checker did not find the false-positive self intersection
assertEquals("Known False-Positive self-intersection was detected as error", ResultStatus.OK, cr.getResultStatus());
}
}
@Test
public void testKnownFalsePositiveExample4() throws CityGmlParseException, InvalidGmlFileException {
ValidationConfiguration config = ValidationConfiguration.loadStandardValidationConfig();
config.setSchematronFilePathInGlobalParameters(null);
CityDoctorModel m = CityGmlParser.parseCityGmlFile("src/test/resources/SolidSelfIntTest-known_false_positive4.gml", config.getParserConfiguration());
Checker c = new Checker(config, m);
c.runChecks();
Building building = m.getBuildings().get(0);
// If an error was found, check if error is SolidSelfInt
if (building.containsAnyError()) {
Geometry buildingGeom = building.getGeometry(GeometryType.SOLID, Lod.LOD2);
buildingGeom.clearCheckResults();
SolidSelfIntCheck check = new SolidSelfIntCheck();
check.check(buildingGeom);
CheckResult cr = buildingGeom.getCheckResult(check);
assertNotNull(cr);
//Ensure that checker did not find the false-positive self intersection
assertEquals("Known False-Positive self-intersection was detected as error", ResultStatus.OK, cr.getResultStatus());
}
}
} }
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