Commit 68c77dbc authored by Numanoglu's avatar Numanoglu
Browse files

WIP realGml Tests for Sweep

parent 854aab9b
Pipeline #12444 passed with stage
in 2 minutes and 59 seconds
package de.hft.stuttgart.citydoctor2.healing;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.Test;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.CheckId;
import de.hft.stuttgart.citydoctor2.check.CheckResult;
import de.hft.stuttgart.citydoctor2.check.ErrorId;
import de.hft.stuttgart.citydoctor2.check.ResultStatus;
import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration;
import de.hft.stuttgart.citydoctor2.check.error.NonPlanarPolygonDistancePlaneError;
import de.hft.stuttgart.citydoctor2.checks.geometry.PlanarCheck;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
import de.hft.stuttgart.citydoctor2.datastructure.Vertex;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException;
/*
* @Numanoglu
*
* WIP !
*
* Die empfohlenen Daten liegen im Ordner:
* src/test/resources/sweep/non-planar-distance-plane
*
* Aktuell sind folgende Probleme
* Validation via GUI (rendert nicht aber)
* zeigt GebäudeElemente mit NonPlanar-Fehlern an.
* Export ebendieser Gebäude führt zu leeren gml-Objekten
*
* Hierunten lief ich deshalb über das ganze Model anstatt einzelner fehlerhafte Buildings dessen!
* Doch scheinen die Modelle de facto keine Nonplanar-Fehler zu enthalten
*
* Den Test habe ich dennoch weiter entwickelt, sodass im Falle anständiger Daten das Konzept schon steht.
* Fortsetzung folgt...
*
* */
public class SweepUtilitiesRealGmlTest {
private static final double POINT_ON_PLANE_TOLERANCE = 0.001;
private static final double SWEEP_EDGE_AND_ANGLE_TOLERANCE = 0.001;
private static final String STRICT_PLANAR_DISTANCE_TOLERANCE = "0.001";
/**
* Reales ganzes CityGML . Der Test lädt die Datei über den
* normalen Parser, lässt den PlanarCheck laufen und versucht die gefundenen
* DistancePlane-Fehler mit dem aktuellen Sweep-Stand zu heilen.
*/
@Test
public void reportsAndTriesSweepForNpR1() throws CityGmlParseException, IOException, InvalidGmlFileException {
checkRealGmlAndTrySweepHealing("src/test/resources/sweep/non-planar-distance-plane/NP_R_1.gml");
}
/**
* Reales größeres GML mit bekannten val3dity-Volumenfehlern(AG-Qual). Für den Sweep ist
* hier zuerst wichtig, ob zusätzlich passende nicht-planare Polygonfehler vom
* Typ DistancePlane gefunden werden. (Da einzelne Gebäude-Exports mit solchen Fehler 0byte-Daten)
*/
@Test
public void reportsAndTriesSweepForLoD21005WithVal3dityErrors()
throws CityGmlParseException, IOException, InvalidGmlFileException {
checkRealGmlAndTrySweepHealing(
"src/test/resources/sweep/non-planar-distance-plane/LoD2_10_05_mit_val3dity_volumenfehlern.gml");
}
private void checkRealGmlAndTrySweepHealing(String path)
throws CityGmlParseException, IOException, InvalidGmlFileException {
ValidationConfiguration config = ValidationConfiguration.loadStandardValidationConfig();
config.setSchematronFilePathInGlobalParameters(null);
CityDoctorModel model = TestUtil.loadCityModel(path, config);
runPlanarCheck(model);
List<NonPlanarPolygonDistancePlaneError> errors = collectDistancePlaneErrors(model);
Map<ErrorId, Integer> errorCounts = countErrorsById(model);
System.out.println();
System.out.println("=== Real-GML Sweep-Test ===");
System.out.println("Datei: " + path);
System.out.println("PlanarCheck: Typ distance, distanceTolerance = " + STRICT_PLANAR_DISTANCE_TOLERANCE);
System.out.println("Fehlerzählung nach ErrorId: " + errorCounts);
System.out.println("Gefundene NonPlanarDistancePlane-Fehler: " + errors.size());
assertFalse("Die Datei muss mindestens einen NonPlanarPolygonDistancePlaneError enthalten.", errors.isEmpty());
int healedCount = 0;
int unhealedCount = 0;
for (int i = 0; i < errors.size(); i++) {
NonPlanarPolygonDistancePlaneError error = errors.get(i);
SweepUtilities utilities = new SweepUtilities(error, POINT_ON_PLANE_TOLERANCE,
SWEEP_EDGE_AND_ANGLE_TOLERANCE);
System.out.println();
System.out.println("Fehler " + (i + 1) + " von " + errors.size());
printErrorSummary(error);
utilities.initialize();
printSweepVertexSummary(utilities.getSweepVertices());
boolean calculated = utilities.calculate();
System.out.println("calculate(): " + calculated);
if (calculated) {
utilities.doHeal();
boolean polygonPlanarAfterHealing = isPolygonPlanar(error.getPolygon());
System.out.println("PlanarCheck nach doHeal() für diese Fazette: " + polygonPlanarAfterHealing);
if (polygonPlanarAfterHealing) {
healedCount++;
} else {
unhealedCount++;
}
} else {
unhealedCount++;
}
}
System.out.println();
System.out.println("Geheilte NonPlanarDistancePlane-Fehler: " + healedCount);
System.out.println("Noch nicht geheilte DistancePlane-Fehler: " + unhealedCount);
System.out.println();
assertTrue("Mindestens ein realer NonPlanarDistancePlane-Fehler sollte vom aktuellen Sweep-Stand heilbar sein.",
healedCount > 0);
}
private void runPlanarCheck(CityDoctorModel model) {
PlanarCheck check = createStrictDistancePlanarCheck();
for (CityObject cityObject : model.createFeatureStream().toList()) {
for (Geometry geometry : cityObject.getGeometries()) {
geometry.accept(check);
check.check(geometry);
}
}
}
private PlanarCheck createStrictDistancePlanarCheck() {
PlanarCheck check = new PlanarCheck();
Map<CheckId, Map<String, String>> parameters = new HashMap<>();
Map<String, String> planarParameters = new HashMap<>();
planarParameters.put(PlanarCheck.TYPE, PlanarCheck.DISTANCE);
planarParameters.put(PlanarCheck.DISTANCE_TOLERANCE, STRICT_PLANAR_DISTANCE_TOLERANCE);
parameters.put(CheckId.C_GE_P_NON_PLANAR, planarParameters);
check.init(parameters, null);
return check;
}
private List<NonPlanarPolygonDistancePlaneError> collectDistancePlaneErrors(CityDoctorModel model) {
List<CheckError> allErrors = new ArrayList<>();
for (CityObject cityObject : model.createFeatureStream().toList()) {
cityObject.collectContainedErrors(allErrors);
}
List<NonPlanarPolygonDistancePlaneError> distancePlaneErrors = new ArrayList<>();
for (CheckError error : allErrors) {
if (error.getErrorId() == ErrorId.GE_P_NON_PLANAR_POLYGON_DISTANCE_PLANE) {
distancePlaneErrors.add((NonPlanarPolygonDistancePlaneError) error);
}
}
return distancePlaneErrors;
}
private Map<ErrorId, Integer> countErrorsById(CityDoctorModel model) {
List<CheckError> allErrors = new ArrayList<>();
for (CityObject cityObject : model.createFeatureStream().toList()) {
cityObject.collectContainedErrors(allErrors);
}
Map<ErrorId, Integer> errorCounts = new HashMap<>();
for (CheckError error : allErrors) {
errorCounts.merge(error.getErrorId(), 1, Integer::sum);
}
return errorCounts;
}
private boolean isPolygonPlanar(Polygon polygon) {
polygon.clearAllContainedCheckResults();
PlanarCheck check = createStrictDistancePlanarCheck();
check.check(polygon);
CheckResult checkResult = polygon.getCheckResult(check);
return checkResult == null || checkResult.getResultStatus() != ResultStatus.ERROR;
}
private void printErrorSummary(NonPlanarPolygonDistancePlaneError error) {
Polygon polygon = error.getPolygon();
Geometry geometry = polygon.getParent();
CityObject cityObject = geometry.getParent();
System.out.println("Gebäude/Feature: " + cityObject.getGmlId().getGmlString());
System.out.println("Geometrie: " + geometry.getGmlId().getGmlString());
System.out.println("Kaputte Fazette: " + polygon.getGmlId().getGmlString());
System.out.println("Maximaler Abstand laut Error: " + error.getDistance());
Vertex errorVertex = error.getVertex();
if (errorVertex != null) {
System.out.println("Error-Vertex: x=" + errorVertex.getX() + ", y=" + errorVertex.getY() + ", z="
+ errorVertex.getZ());
}
}
private void printSweepVertexSummary(List<SweepVertex> sweepVertices) {
if (sweepVertices == null) {
System.out.println("initialize(): keine SweepVertices erzeugt.");
return;
}
Map<SweepVertexStatus, Integer> statusCounts = new EnumMap<>(SweepVertexStatus.class);
for (SweepVertexStatus status : SweepVertexStatus.values()) {
statusCounts.put(status, 0);
}
for (SweepVertex sweepVertex : sweepVertices) {
SweepVertexStatus status = sweepVertex.getStatus();
statusCounts.put(status, statusCounts.get(status) + 1);
}
System.out.println("initialize(): SweepVertices gesamt: " + sweepVertices.size());
System.out.println("Statuszählung: " + statusCounts);
for (int i = 0; i < sweepVertices.size(); i++) {
SweepVertex sweepVertex = sweepVertices.get(i);
Vertex vertex = sweepVertex.getSweepVertex();
System.out.println(" SweepVertex " + i + ": Status " + sweepVertex.getStatus() + ", abführende Kanten "
+ sweepVertex.countOutgoingEdges() + ", Punkt x=" + vertex.getX() + ", y=" + vertex.getY()
+ ", z=" + vertex.getZ());
}
}
}
Supports Markdown
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