Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
CityDoctor
CityDoctor2
Commits
68c77dbc
Commit
68c77dbc
authored
Sep 15, 2026
by
Numanoglu
Browse files
WIP realGml Tests for Sweep
parent
854aab9b
Pipeline
#12444
passed with stage
in 2 minutes and 59 seconds
Changes
3
Pipelines
1
Expand all
Hide whitespace changes
Inline
Side-by-side
CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/SweepUtilitiesRealGmlTest.java
0 → 100644
View file @
68c77dbc
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
());
}
}
}
CityDoctorParent/Extensions/CityDoctorHealer/src/test/resources/sweep/non-planar-distance-plane/LoD2_10_05_mit_val3dity_volumenfehlern.gml
0 → 100644
View file @
68c77dbc
This diff is collapsed.
Click to expand it.
CityDoctorParent/Extensions/CityDoctorHealer/src/test/resources/sweep/non-planar-distance-plane/NP_R_1.gml
0 → 100644
View file @
68c77dbc
This diff is collapsed.
Click to expand it.
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment