GE_S_NOT_CLOSED/GE_S_MULTIPLE_CONNECTED_COMPONENTS due to unresolved TriangulatedSurface X-Link reference
Report from HTWD
Zusammenfassung
Referenziert ein gml:Solid per XLink eine gml:TriangulatedSurface, wird diese Referenz beim
Einlesen nie aufgelöst — die Fläche fehlt in der internen Solid-Hülle, was fälschlich als offene
Hülle (GE_S_NOT_CLOSED) bzw. als getrennte Komponente
(GE_S_MULTIPLE_CONNECTED_COMPONENTS) gemeldet wird, obwohl die Fläche tatsächlich vorhanden und
korrekt referenziert ist.
Beispiel (schema-valide, echte Ausgabe)
<bldg:lod3MultiSurface>
<gml:MultiSurface gml:id="Face_0003H5B_0_7_MS">
<gml:surfaceMember>
<gml:TriangulatedSurface gml:id="DESNALK0pF001g4s_0_6_TIN">
<gml:trianglePatches>
<gml:Triangle>
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="3">417951.504 5657231.633 245.128 417951.635 5657232.984 245.118 417951.635 5657232.984 232.98 417951.504 5657231.633 245.128</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Triangle>
<!-- weitere gml:Triangle-Elemente -->
</gml:trianglePatches>
</gml:TriangulatedSurface>
</gml:surfaceMember>
</gml:MultiSurface>
</bldg:lod3MultiSurface>
Referenziert vom Solid der übergeordneten AbstractBuilding per
<gml:surfaceMember xlink:href="#DESNALK0pF001g4s_0_6_TIN"/> (bzw. äquivalent über die
umschließende Fläche). gml:TriangulatedSurface ist laut GML-3.1.1-Schema eine _Surface
(TriangulatedSurface → Surface → _Surface), surfaceMember akzeptiert _Surface — die
Referenz ist damit schema-konform.
Root Cause (Quellcode-Nachweis)
de.hft.stuttgart.citydoctor2.mapper.citygml3.Citygml3GeometryMapper:
@Override
public void visit(Surface surface) {
if (surface.getPatches() != null && !surface.getPatches().isSetObjects()) {
logger.warn("Surface {} has no PolygonPatches.", surface.getId());
return;
}
PatchCollection patchCollection = new PatchCollection();
GeometryWalker patchCollector = new GeometryWalker() {
@Override
public void visit(PolygonPatch patch) {
parsePolygonPatch(patch, patchCollection);
}
@Override
public void visit(Triangle tri) {
parsePolygon(null, tri.getExterior(), Collections.emptyList());
}
};
surface.getPatches().getObjects().forEach(abstractSurfacePatch -> abstractSurfacePatch.accept(patchCollector));
}
Zwei Probleme in diesem einen Methodenkörper:
-
visit(Triangle tri)übergibtnullals gml:id (parsePolygon(null, ...)) statt der ID der umschließendenTriangulatedSurfaceoder einer generierten ID. InparsePolygon:private void parsePolygon(String id, AbstractRingProperty exterior, List<AbstractRingProperty> interior) { ... ConcretePolygon cdPoly = new ConcretePolygon(); polygons.add(cdPoly); if (id != null) { cdPoly.setGmlId(new GmlId(id)); } ...Ohne
idbekommt das resultierende Polygon nie eineGmlId— es kann später über keinen XLink-href gefunden werden. -
patchCollectionwird fürTriangle-Patches nie befüllt — nurvisit(PolygonPatch)ruftparsePolygonPatch(patch, patchCollection)auf. Die lokale VariablepatchCollectionwird nach der Schleife nirgends weiterverwendet (nicht zurückgegeben, keiner Map hinzugefügt) — toter Code für den Triangle-Fall.
Beim späteren Auflösen der XLink-Referenzen
(de.hft.stuttgart.citydoctor2.mapper.citygml3.Citygml3FeatureMapper.resolveAndClearReferences)
wird der href weder in compositeMap (da nie befüllt, s.o.) noch in polygonMap (da die
Dreieck-Polygone nie eine GmlId erhielten, mit der sie in polygonMap indiziert werden könnten)
gefunden:
private void handlePolygonReference(String href, Geometry geom) {
ConcretePolygon concPoly = polygonMap.get(href);
if (concPoly == null) {
List<GmlId> featureList = unresolvedPolyRefIDMap.computeIfAbsent(href, k -> new ArrayList<>());
...
Die Referenz landet in unresolvedPolyRefIDMap, CityDoctor2 loggt selbst
unresolvedReferencesDetected — die Fläche fehlt danach in der Solid-Hülle.
Empirische Verifikation
Dieselben 14 Testgebäude einmal mit gml:TriangulatedSurface, einmal mit denselben Flächen als einzelne gml:Polygon-Elemente (gleiche
Geometrie, andere Repräsentation) durch dieselbe CityDoctor2-CLI geprüft:
| Repräsentation | GE_S_NOT_CLOSED |
GE_S_MULTIPLE_CONNECTED_COMPONENTS |
|---|---|---|
gml:TriangulatedSurface (XLink vom Solid) |
6 | zusätzlich vorhanden |
Dieselbe Geometrie als gml:Polygon
|
0 | 0 |
Zusätzlich mit citygml-tools 2.5.0 validate bestätigt: beide Repräsentationen sind
XSD-schema-valide.
Erwartetes vs. tatsächliches Verhalten
-
Erwartet: eine per XLink referenzierte
gml:TriangulatedSurfacewird wie jede andere_Surfaceaufgelöst und ist Teil der geprüften Solid-Hülle. - Tatsächlich: die Referenz bleibt unauflösbar, die Fläche fehlt in der Hülle, was als Geometriefehler statt als Parser-Lücke erscheint.
Vorschlag
-
Citygml3GeometryMapper.visit(Surface): fürTriangle-Patches ebenfalls eineGmlIdvergeben (z. B. von der umschließendenTriangulatedSurfaceableiten oder pro Dreieck generieren) und die entstehenden Polygone inpolygonMapbzw. äquivalent incompositeMapauffindbar machen, analog zum bereits funktionierendenPolygonPatch-Pfad.