From afe11adc0f4da793297697f97fba3695f8f1c84e Mon Sep 17 00:00:00 2001
From: Riegel <alexander.riegel@hft-stuttgart.de>
Date: Mon, 10 Mar 2025 10:41:17 +0100
Subject: [PATCH] Refactor: Rework model of TransportationObject

---
 .../TopLevelTransportFeature.java             | 230 ++++++++++++++++
 .../datastructure/TrafficAreaObject.java      | 123 +++++++++
 .../datastructure/TrafficSpaceObject.java     | 190 ++++++++++++++
 .../datastructure/TransportSection.java       |  17 ++
 .../datastructure/TransportationObject.java   | 247 +-----------------
 .../datastructure/TransportationSpace.java    | 229 ++++++++++++++++
 .../citygml3/Citygml3FeatureMapper.java       | 177 ++++++++-----
 .../citygml3/Citygml3GeometryMapper.java      |  47 ++++
 .../reporting/pdf/PdfStreamReporter.java      |   3 -
 9 files changed, 955 insertions(+), 308 deletions(-)
 create mode 100644 CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/TopLevelTransportFeature.java
 create mode 100644 CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/TrafficAreaObject.java
 create mode 100644 CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/TrafficSpaceObject.java
 create mode 100644 CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/TransportSection.java
 create mode 100644 CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/TransportationSpace.java

diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/TopLevelTransportFeature.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/TopLevelTransportFeature.java
new file mode 100644
index 0000000..8551fca
--- /dev/null
+++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/TopLevelTransportFeature.java
@@ -0,0 +1,230 @@
+package de.hft.stuttgart.citydoctor2.datastructure;
+
+import de.hft.stuttgart.citydoctor2.check.Check;
+import de.hft.stuttgart.citydoctor2.check.CheckError;
+import de.hft.stuttgart.citydoctor2.check.CheckId;
+import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
+import de.hft.stuttgart.citydoctor2.utils.CopyHandler;
+import de.hft.stuttgart.citydoctor2.utils.Copyable;
+import org.citygml4j.core.model.transportation.AbstractTransportationSpace;
+import org.citygml4j.core.model.transportation.Intersection;
+import org.citygml4j.core.model.transportation.Railway;
+import org.citygml4j.core.model.transportation.Road;
+import org.citygml4j.core.model.transportation.Section;
+import org.citygml4j.core.model.transportation.Square;
+import org.citygml4j.core.model.transportation.Track;
+import org.citygml4j.core.model.transportation.Waterway;
+import org.citygml4j.core.util.geometry.GeometryFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class TopLevelTransportFeature extends TransportationSpace {
+
+    private final List<TransportSection> sections = new ArrayList<>();
+    private final List<TransportSection> intersections = new ArrayList<>();
+
+    public static TopLevelTransportFeature from(AbstractTransportationSpace abs) {
+        TransportationType type = null;
+        if (abs instanceof Track) {
+            type = TransportationType.TRACK;
+        } else if (abs instanceof Road) {
+            type = TransportationType.ROAD;
+        } else if (abs instanceof Waterway) {
+            type = TransportationType.WATERWAY;
+        } else if (abs instanceof Railway) {
+            type = TransportationType.RAILWAY;
+        } else if (abs instanceof Square) {
+            type = TransportationType.SQUARE;
+        } else if (abs instanceof Section || abs instanceof Intersection) {
+            return null;
+        } else {
+            throw new IllegalArgumentException("TransportationType: " + abs.getClass() + " is not a TopLevelTransportFeature");
+        }
+        TopLevelTransportFeature top = new TopLevelTransportFeature(type);
+        top.setGmlObject(abs);
+        return top;
+    }
+
+    private TopLevelTransportFeature(TransportationType type) {
+        super(type);
+    }
+
+
+    public void addSection(TransportSection section) {
+        sections.add(section);
+    }
+
+    public void addIntersection(TransportSection section) {
+        intersections.add(section);
+    }
+
+    public List<TransportSection> getSections() {
+        return sections;
+    }
+
+    public List<TransportSection> getIntersections() {
+        return intersections;
+    }
+
+    @Override
+    public void reCreateGeometries(GeometryFactory factory, ParserConfiguration config) {
+        super.reCreateGeometries(factory, config);
+        for (TransportSection section : sections) {
+            section.reCreateGeometries(factory, config);
+        }
+        for (TransportSection section : intersections) {
+            section.reCreateGeometries(factory, config);
+        }
+    }
+
+
+    @Override
+    public boolean containsError(CheckId checkIdentifier) {
+        boolean hasError = super.containsError(checkIdentifier);
+        if (hasError) {
+            return true;
+        }
+        for (TransportSection section : sections) {
+            if (section.containsError(checkIdentifier)) {
+                return true;
+            }
+        }
+        for (TransportSection section : intersections) {
+            if (section.containsError(checkIdentifier)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public void clearAllContainedCheckResults() {
+        super.clearAllContainedCheckResults();
+        for (TransportSection section : sections) {
+            section.clearAllContainedCheckResults();
+        }
+        for (TransportSection section : intersections) {
+            section.clearAllContainedCheckResults();
+        }
+    }
+
+    @Override
+    public void collectContainedErrors(List<CheckError> errors) {
+        super.collectContainedErrors(errors);
+        for (TransportSection section : sections) {
+            section.collectContainedErrors(errors);
+        }
+        for (TransportSection section : intersections) {
+            section.collectContainedErrors(errors);
+        }
+    }
+
+    @Override
+    public boolean containsAnyError() {
+        boolean hasError = super.containsAnyError();
+        if (hasError) {
+            return true;
+        }
+        for (TransportSection section : sections) {
+            if (section.containsAnyError()) {
+                return true;
+            }
+        }
+        for (TransportSection section : intersections) {
+            if (section.containsAnyError()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public void accept(Check c) {
+        super.accept(c);
+        if (c.canExecute(this)) {
+            c.check(this);
+        }
+        for (TransportSection section : sections) {
+            section.accept(c);
+        }
+        for (TransportSection section : intersections) {
+            section.accept(c);
+        }
+    }
+
+
+    @Override
+    public void unsetGmlGeometries() {
+        super.unsetGmlGeometries();
+        for (TransportSection section : sections) {
+            section.unsetGmlGeometries();
+        }
+        for (TransportSection section : intersections) {
+            section.unsetGmlGeometries();
+        }
+    }
+
+    @Override
+    public CityObject getTopLevelCityObject() {
+        return this;
+    }
+
+
+    @Override
+    public String toString() {
+        return "TopLevelTransportFeature [id=" + getGmlId() + "]";
+    }
+
+    @Override
+    public void prepareForChecking() {
+        super.prepareForChecking();
+        for (TransportSection section : sections) {
+            section.prepareForChecking();
+        }
+        for (TransportSection section : intersections) {
+            section.prepareForChecking();
+        }
+    }
+
+    @Override
+    public void clearMetaInformation() {
+        super.clearMetaInformation();
+        for (TransportSection section : sections) {
+            section.clearMetaInformation();
+        }
+        for (TransportSection section : intersections) {
+            section.clearMetaInformation();
+        }
+    }
+
+    @Override
+    public void collectInstances(CopyHandler handler) {
+        super.collectInstances(handler);
+        for (TransportSection section : sections) {
+            section.collectInstances(handler);
+        }
+        for (TransportSection section : intersections) {
+            section.collectInstances(handler);
+        }
+    }
+
+    @Override
+    public void fillValues(Copyable original, CopyHandler handler) {
+        super.fillValues(original, handler);
+        TransportationObject originalTo = (TransportationObject) original;
+        for (TransportSection section : sections) {
+            section.fillValues(originalTo, handler);
+        }
+        for (TransportSection section : intersections) {
+            section.fillValues(originalTo, handler);
+        }
+    }
+
+    @Override
+    public Copyable createCopyInstance() {
+        return new TopLevelTransportFeature(type);
+    }
+
+
+}
diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/TrafficAreaObject.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/TrafficAreaObject.java
new file mode 100644
index 0000000..9824513
--- /dev/null
+++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/TrafficAreaObject.java
@@ -0,0 +1,123 @@
+package de.hft.stuttgart.citydoctor2.datastructure;
+
+import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
+import de.hft.stuttgart.citydoctor2.utils.CityGmlUtils;
+import org.citygml4j.core.model.transportation.AuxiliaryTrafficArea;
+import org.citygml4j.core.model.transportation.TrafficArea;
+import org.citygml4j.core.util.geometry.GeometryFactory;
+import org.xmlobjects.gml.model.geometry.aggregates.MultiSurface;
+import org.xmlobjects.gml.model.geometry.aggregates.MultiSurfaceProperty;
+
+import java.util.List;
+
+public class TrafficAreaObject extends TransportationObject {
+
+    public enum TrafficAreaType {
+        TRAFFIC_AREA, AUXILIARY_TRAFFIC_AREA
+    }
+
+    public TrafficAreaObject(TrafficAreaType trafficAreaType) {
+        if (trafficAreaType == TrafficAreaType.TRAFFIC_AREA) {
+            setType(TransportationType.TRAFFIC_AREA);
+        } else {
+            setType(TransportationType.AUXILLIARY_TRAFFIC_AREA);
+        }
+    }
+
+    @Override
+    public void reCreateGeometries(GeometryFactory factory, ParserConfiguration config) {
+        for (Geometry geom : getGeometries()) {
+            if (geom instanceof ImplicitGeometryHolder) {
+                continue;
+            }
+            if (geom.getType() == GeometryType.MULTI_SURFACE) {
+                MultiSurface ms = CityGmlUtils.createMultiSurface(geom, factory, config);
+                switch (type) {
+                    case TRAFFIC_AREA:
+                        TrafficArea ta = (TrafficArea) super.getGmlObject();
+                        setMultiSurfaceAccordingToLod(ta, ms, geom.getLod());
+                        break;
+                    case AUXILLIARY_TRAFFIC_AREA:
+                        AuxiliaryTrafficArea ata = (AuxiliaryTrafficArea) super.getGmlObject();
+                        setMultiSurfaceAccordingToLod(ata, ms, geom.getLod());
+                        break;
+                }
+            } else {
+                throw new IllegalStateException("Geometry in TransportationObject cannot be of type " + geom.getType()
+                        + ". Only MultiSurface allowed");
+            }
+        }
+    }
+
+
+    private void setMultiSurfaceAccordingToLod(AuxiliaryTrafficArea ata, MultiSurface ms, Lod lod) {
+        switch (lod) {
+            case LOD0:
+                ata.setLod0MultiSurface(new MultiSurfaceProperty(ms));
+                break;
+            case LOD1:
+                ata.setLod1MultiSurface(new MultiSurfaceProperty(ms));
+                break;
+            case LOD2:
+                ata.setLod2MultiSurface(new MultiSurfaceProperty(ms));
+                break;
+            case LOD3:
+                ata.setLod3MultiSurface(new MultiSurfaceProperty(ms));
+                break;
+            case LOD4:
+                ata.getDeprecatedProperties().setLod4MultiSurface(new MultiSurfaceProperty(ms));
+                break;
+            default:
+                throw new IllegalStateException("cannot set geometry with LOD for AuxiliaryTrafficArea: " + lod);
+        }
+    }
+
+    private void setMultiSurfaceAccordingToLod(TrafficArea ta, MultiSurface ms, Lod lod) {
+        switch (lod) {
+            case LOD2:
+                ta.setLod2MultiSurface(new MultiSurfaceProperty(ms));
+                break;
+            case LOD3:
+                ta.setLod3MultiSurface(new MultiSurfaceProperty(ms));
+                break;
+            case LOD4:
+                ta.getDeprecatedProperties().setLod4MultiSurface(new MultiSurfaceProperty(ms));
+                break;
+            default:
+                throw new IllegalStateException("cannot set geometry with LOD for TrafficArea: " + lod);
+        }
+    }
+
+
+    @Override
+    public void unsetGmlGeometries() {
+        switch (type) {
+            case TRAFFIC_AREA:
+                TrafficArea ta = (TrafficArea) super.getGmlObject();
+                ta.setLod2MultiSurface(null);
+                ta.setLod3MultiSurface(null);
+                ta.getDeprecatedProperties().setLod4MultiSurface(null);
+                break;
+            case AUXILLIARY_TRAFFIC_AREA:
+                AuxiliaryTrafficArea ata = (AuxiliaryTrafficArea) super.getGmlObject();
+                ata.setLod0MultiSurface(null);
+                ata.setLod1MultiSurface(null);
+                ata.setLod2MultiSurface(null);
+                ata.setLod3MultiSurface(null);
+                ata.getDeprecatedProperties().setLod4MultiSurface(null);
+                break;
+        }
+    }
+
+    @Override
+    public CityObject getTopLevelCityObject() {
+        return this;
+    }
+
+    @Override
+    public String toString() {
+        return "TrafficArea [id=" + getGmlId() + "]";
+    }
+
+
+}
diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/TrafficSpaceObject.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/TrafficSpaceObject.java
new file mode 100644
index 0000000..fb07843
--- /dev/null
+++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/TrafficSpaceObject.java
@@ -0,0 +1,190 @@
+package de.hft.stuttgart.citydoctor2.datastructure;
+
+import de.hft.stuttgart.citydoctor2.check.Check;
+import de.hft.stuttgart.citydoctor2.check.CheckError;
+import de.hft.stuttgart.citydoctor2.check.CheckId;
+import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
+import de.hft.stuttgart.citydoctor2.utils.CityGmlUtils;
+import de.hft.stuttgart.citydoctor2.utils.CopyHandler;
+import de.hft.stuttgart.citydoctor2.utils.Copyable;
+import org.citygml4j.core.model.core.AbstractSpace;
+import org.citygml4j.core.util.geometry.GeometryFactory;
+import org.xmlobjects.gml.model.geometry.aggregates.MultiSurface;
+import org.xmlobjects.gml.model.geometry.aggregates.MultiSurfaceProperty;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class TrafficSpaceObject extends TransportationObject {
+
+    private final List<TrafficAreaObject> trafficAreas = new ArrayList<>();
+
+    public enum TrafficSpaceType {
+        TRAFFIC_SPACE, AUXILIARY_TRAFFIC_SPACE
+    }
+
+    public TrafficSpaceObject(TrafficSpaceType trafficSpaceType) {
+        if (trafficSpaceType == TrafficSpaceType.TRAFFIC_SPACE) {
+            super.setType(TransportationType.TRAFFIC_SPACE);
+        } else {
+            super.setType(TransportationType.AUXILLIARY_TRAFFIC_SPACE);
+        }
+    }
+
+    public List<TrafficAreaObject> getTrafficAreas() {
+        return trafficAreas;
+    }
+
+    public void addTrafficArea(TrafficAreaObject trafficAreaObject) {
+        trafficAreas.add(trafficAreaObject);
+    }
+
+    @Override
+    public void reCreateGeometries(GeometryFactory factory, ParserConfiguration config) {
+        for (Geometry geom : getGeometries()) {
+            if (geom instanceof ImplicitGeometryHolder) {
+                continue;
+            }
+            MultiSurface ms = CityGmlUtils.createMultiSurface(geom, factory, config);
+            AbstractSpace ats = (AbstractSpace) super.getGmlObject();
+            setMultiSurfaceAccordingToLod(ats, ms, geom.getLod());
+        }
+        for (TrafficAreaObject tao : trafficAreas) {
+            tao.reCreateGeometries(factory, config);
+        }
+    }
+
+    private void setMultiSurfaceAccordingToLod(AbstractSpace ats, MultiSurface ms, Lod lod) {
+        switch (lod) {
+            case LOD0:
+                ats.setLod0MultiSurface(new MultiSurfaceProperty(ms));
+                break;
+            case LOD2:
+                ats.setLod2MultiSurface(new MultiSurfaceProperty(ms));
+                break;
+            case LOD3:
+                ats.setLod3MultiSurface(new MultiSurfaceProperty(ms));
+                break;
+            default:
+                throw new IllegalStateException("cannot set geometry with LOD for AuxiliaryTrafficSpace: " + lod);
+        }
+    }
+
+    @Override
+    public boolean containsError(CheckId checkIdentifier) {
+        boolean hasError = super.containsError(checkIdentifier);
+        if (hasError) {
+            return true;
+        }
+        for (TrafficAreaObject tao : trafficAreas) {
+            if (tao.containsError(checkIdentifier)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public void clearAllContainedCheckResults() {
+        super.clearAllContainedCheckResults();
+        for (TrafficAreaObject tao : trafficAreas) {
+            tao.clearAllContainedCheckResults();
+        }
+    }
+
+    @Override
+    public void collectContainedErrors(List<CheckError> errors) {
+        super.collectContainedErrors(errors);
+        for (TrafficAreaObject tao : trafficAreas) {
+            tao.collectContainedErrors(errors);
+        }
+    }
+
+    @Override
+    public boolean containsAnyError() {
+        boolean hasError = super.containsAnyError();
+        if (hasError) {
+            return true;
+        }
+        for (TrafficAreaObject tao : trafficAreas) {
+            if (tao.containsAnyError()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public void accept(Check c) {
+        super.accept(c);
+        if (c.canExecute(this)) {
+            c.check(this);
+        }
+        for (TrafficAreaObject tao : trafficAreas) {
+            tao.accept(c);
+        }
+    }
+
+    @Override
+    public void unsetGmlGeometries() {
+        AbstractSpace ats = (AbstractSpace) super.getGmlObject();
+        ats.setLod0MultiSurface(null);
+        ats.setLod2MultiSurface(null);
+        ats.setLod3MultiSurface(null);
+        for (TrafficAreaObject tao : trafficAreas) {
+            tao.unsetGmlGeometries();
+        }
+    }
+
+    @Override
+    public CityObject getTopLevelCityObject() {
+        return this;
+    }
+
+
+    @Override
+    public String toString() {
+        return "TransportationSpaceObject [id=" + getGmlId() + "]";
+    }
+
+    @Override
+    public void prepareForChecking() {
+        super.prepareForChecking();
+        for (TrafficAreaObject tao : trafficAreas) {
+            tao.prepareForChecking();
+        }
+    }
+
+    @Override
+    public void clearMetaInformation() {
+        super.clearMetaInformation();
+        for (TrafficAreaObject tao : trafficAreas) {
+            tao.clearMetaInformation();
+        }
+    }
+
+    @Override
+    public void collectInstances(CopyHandler handler) {
+        super.collectInstances(handler);
+        for (TrafficAreaObject tao : trafficAreas) {
+            handler.addInstance(tao);
+        }
+    }
+
+    @Override
+    public void fillValues(Copyable original, CopyHandler handler) {
+        super.fillValues(original, handler);
+        TrafficSpaceObject originalTao = (TrafficSpaceObject) original;
+        for (TrafficAreaObject tao : originalTao.trafficAreas) {
+            trafficAreas.add(handler.getCopyInstance(tao));
+        }
+        super.setGmlObject(originalTao.getGmlObject());
+    }
+
+    @Override
+    public Copyable createCopyInstance() {
+        return new TrafficSpaceObject(null);
+    }
+
+
+}
diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/TransportSection.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/TransportSection.java
new file mode 100644
index 0000000..86631f6
--- /dev/null
+++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/TransportSection.java
@@ -0,0 +1,17 @@
+package de.hft.stuttgart.citydoctor2.datastructure;
+
+public class TransportSection extends TransportationSpace {
+
+    public enum SectionType {
+        SECTION, INTERSECTION
+    }
+
+    public TransportSection(SectionType sectionType) {
+        super(TransportationType.SECTION);
+        if (sectionType == SectionType.INTERSECTION) {
+            super.setType(TransportationType.INTERSECTION);
+        }
+    }
+
+
+}
diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/TransportationObject.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/TransportationObject.java
index 8cd16b6..9ca662d 100644
--- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/TransportationObject.java
+++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/TransportationObject.java
@@ -43,190 +43,33 @@ import java.util.List;
  *
  * @author Matthias Betz
  */
-public class TransportationObject extends CityObject {
+public abstract class TransportationObject extends CityObject {
 
     @Serial
     private static final long serialVersionUID = -2698907271726700390L;
 
     public enum TransportationType {
-        ROAD, TRACK, RAILWAY, TRAFFIC_AREA, AUXILLIARY_TRAFFIC_AREA, TRANSPORTATION_COMPLEX, SQUARE, AUXILLIARY_TRAFFIC_SPACE, TRAFFIC_SPACE
+        ROAD, TRACK, RAILWAY, TRAFFIC_AREA, AUXILLIARY_TRAFFIC_AREA, TRANSPORTATION_COMPLEX, SQUARE, AUXILLIARY_TRAFFIC_SPACE,
+        TRAFFIC_SPACE, WATERWAY, SECTION, INTERSECTION
     }
 
     private AbstractCityObject ato;
-    private final List<TransportationObject> composesOf = new ArrayList<>(1);
-    private final TransportationType type;
+    protected TransportationType type;
 
     public TransportationObject(TransportationType type) {
         this.type = type;
     }
 
-    @Override
-    public FeatureType getFeatureType() {
-        return FeatureType.TRANSPORTATION;
-    }
-
-    @Override
-    public void reCreateGeometries(GeometryFactory factory, ParserConfiguration config) {
-        for (Geometry geom : getGeometries()) {
-            if (geom instanceof ImplicitGeometryHolder) {
-                continue;
-            }
-            if (geom.getType() == GeometryType.MULTI_SURFACE) {
-                MultiSurface ms = CityGmlUtils.createMultiSurface(geom, factory, config);
-                switch (type) {
-                    case ROAD, TRACK, RAILWAY, SQUARE, TRANSPORTATION_COMPLEX:
-                        AbstractTransportationSpace tc = (AbstractTransportationSpace) ato;
-                        setMultiSurfaceAccordingToLod(tc, ms, geom.getLod());
-                        break;
-                    case TRAFFIC_AREA:
-                        TrafficArea ta = (TrafficArea) ato;
-                        setMultiSurfaceAccordingToLod(ta, ms, geom.getLod());
-                        break;
-                    case AUXILLIARY_TRAFFIC_AREA:
-                        AuxiliaryTrafficArea ata = (AuxiliaryTrafficArea) ato;
-                        setMultiSurfaceAccordingToLod(ata, ms, geom.getLod());
-                        break;
-                    case AUXILLIARY_TRAFFIC_SPACE, TRAFFIC_SPACE:
-                        AbstractSpace ats = (AbstractSpace) ato;
-                        setMultiSurfaceAccordingToLod(ats, ms, geom.getLod());
-                        break;
-                }
-            } else {
-                throw new IllegalStateException("Geometry in TransportationObject cannot be of type " + geom.getType()
-                        + ". Only MultiSurface allowed");
-            }
-        }
-        for (TransportationObject children : composesOf) {
-            children.reCreateGeometries(factory, config);
-        }
-    }
-
-    private void setMultiSurfaceAccordingToLod(AbstractSpace ats, MultiSurface ms, Lod lod) {
-        switch (lod) {
-            case LOD0:
-                ats.setLod0MultiSurface(new MultiSurfaceProperty(ms));
-                break;
-            case LOD2:
-                ats.setLod2MultiSurface(new MultiSurfaceProperty(ms));
-                break;
-            case LOD3:
-                ats.setLod3MultiSurface(new MultiSurfaceProperty(ms));
-                break;
-            default:
-                throw new IllegalStateException("cannot set geometry with LOD for AuxiliaryTrafficSpace: " + lod);
-        }
-    }
-
-    private void setMultiSurfaceAccordingToLod(AbstractTransportationSpace tc, MultiSurface ms, Lod lod) {
-        switch (lod) {
-            case LOD1:
-                tc.getDeprecatedProperties().setLod1MultiSurface(new MultiSurfaceProperty(ms));
-                break;
-            case LOD2:
-                tc.setLod2MultiSurface(new MultiSurfaceProperty(ms));
-                break;
-            case LOD3:
-                tc.setLod3MultiSurface(new MultiSurfaceProperty(ms));
-                break;
-            case LOD4:
-                tc.getDeprecatedProperties().setLod4MultiSurface(new MultiSurfaceProperty(ms));
-                break;
-            default:
-                throw new IllegalStateException("cannot set geometry with LOD for TransportationComplex: " + lod);
-        }
-    }
-
-    private void setMultiSurfaceAccordingToLod(AuxiliaryTrafficArea ata, MultiSurface ms, Lod lod) {
-        switch (lod) {
-            case LOD0:
-                ata.setLod0MultiSurface(new MultiSurfaceProperty(ms));
-                break;
-            case LOD1:
-                ata.setLod1MultiSurface(new MultiSurfaceProperty(ms));
-                break;
-            case LOD2:
-                ata.setLod2MultiSurface(new MultiSurfaceProperty(ms));
-                break;
-            case LOD3:
-                ata.setLod3MultiSurface(new MultiSurfaceProperty(ms));
-                break;
-            case LOD4:
-                ata.getDeprecatedProperties().setLod4MultiSurface(new MultiSurfaceProperty(ms));
-                break;
-            default:
-                throw new IllegalStateException("cannot set geometry with LOD for AuxiliaryTrafficArea: " + lod);
-        }
-    }
-
-    private void setMultiSurfaceAccordingToLod(TrafficArea ta, MultiSurface ms, Lod lod) {
-        switch (lod) {
-            case LOD2:
-                ta.setLod2MultiSurface(new MultiSurfaceProperty(ms));
-                break;
-            case LOD3:
-                ta.setLod3MultiSurface(new MultiSurfaceProperty(ms));
-                break;
-            case LOD4:
-                ta.getDeprecatedProperties().setLod4MultiSurface(new MultiSurfaceProperty(ms));
-                break;
-            default:
-                throw new IllegalStateException("cannot set geometry with LOD for TrafficArea: " + lod);
-        }
-    }
-
-    @Override
-    public boolean containsError(CheckId checkIdentifier) {
-        boolean hasError = super.containsError(checkIdentifier);
-        if (hasError) {
-            return true;
-        }
-        for (TransportationObject to : composesOf) {
-            if (to.containsError(checkIdentifier)) {
-                return true;
-            }
-        }
-        return false;
+    protected TransportationObject() {
     }
 
-    @Override
-    public void clearAllContainedCheckResults() {
-        super.clearAllContainedCheckResults();
-        for (TransportationObject to : composesOf) {
-            to.clearAllContainedCheckResults();
-        }
-    }
-
-    @Override
-    public void collectContainedErrors(List<CheckError> errors) {
-        super.collectContainedErrors(errors);
-        for (TransportationObject to : composesOf) {
-            to.collectContainedErrors(errors);
-        }
-    }
-
-    @Override
-    public boolean containsAnyError() {
-        boolean hasError = super.containsAnyError();
-        if (hasError) {
-            return true;
-        }
-        for (TransportationObject to : composesOf) {
-            if (to.containsAnyError()) {
-                return true;
-            }
-        }
-        return false;
+    void setType(TransportationType type) {
+        this.type = type;
     }
 
     @Override
-    public void accept(Check c) {
-        super.accept(c);
-        if (c.canExecute(this)) {
-            c.check(this);
-        }
-        for (TransportationObject to : composesOf) {
-            to.accept(c);
-        }
+    public FeatureType getFeatureType() {
+        return FeatureType.TRANSPORTATION;
     }
 
     @Override
@@ -234,55 +77,11 @@ public class TransportationObject extends CityObject {
         return ato;
     }
 
-    @Override
-    public void unsetGmlGeometries() {
-        switch (type) {
-            case ROAD, TRACK, RAILWAY, SQUARE, TRANSPORTATION_COMPLEX:
-                AbstractTransportationSpace tc = (AbstractTransportationSpace) ato;
-                tc.getDeprecatedProperties().setLod1MultiSurface(null);
-                tc.setLod2MultiSurface(null);
-                tc.setLod3MultiSurface(null);
-                tc.getDeprecatedProperties().setLod4MultiSurface(null);
-                break;
-            case TRAFFIC_AREA:
-                TrafficArea ta = (TrafficArea) ato;
-                ta.setLod2MultiSurface(null);
-                ta.setLod3MultiSurface(null);
-                ta.getDeprecatedProperties().setLod4MultiSurface(null);
-                break;
-            case AUXILLIARY_TRAFFIC_AREA:
-                AuxiliaryTrafficArea ata = (AuxiliaryTrafficArea) ato;
-                ata.setLod0MultiSurface(null);
-                ata.setLod1MultiSurface(null);
-                ata.setLod2MultiSurface(null);
-                ata.setLod3MultiSurface(null);
-                ata.getDeprecatedProperties().setLod4MultiSurface(null);
-                break;
-            case AUXILLIARY_TRAFFIC_SPACE, TRAFFIC_SPACE:
-                AbstractSpace ats = (AbstractSpace) ato;
-                ats.setLod0MultiSurface(null);
-                ats.setLod2MultiSurface(null);
-                ats.setLod3MultiSurface(null);
-                break;
-        }
-    }
-
-    @Override
-    public CityObject getTopLevelCityObject() {
-        return this;
-    }
 
     public void setGmlObject(AbstractCityObject tc) {
         ato = tc;
     }
 
-    public void addChild(TransportationObject subTrans) {
-        composesOf.add(subTrans);
-    }
-
-    public List<TransportationObject> getChildren() {
-        return composesOf;
-    }
 
     public TransportationType getTransportationType() {
         return type;
@@ -293,43 +92,17 @@ public class TransportationObject extends CityObject {
         return "TransportationObject [id=" + getGmlId() + "]";
     }
 
-    @Override
-    public void prepareForChecking() {
-        super.prepareForChecking();
-        for (TransportationObject child : composesOf) {
-            child.prepareForChecking();
-        }
-    }
-
-    @Override
-    public void clearMetaInformation() {
-        super.clearMetaInformation();
-        for (TransportationObject child : composesOf) {
-            child.clearMetaInformation();
-        }
-    }
-
-    @Override
-    public void collectInstances(CopyHandler handler) {
-        super.collectInstances(handler);
-        for (TransportationObject to : composesOf) {
-            handler.addInstance(to);
-        }
-    }
 
     @Override
     public void fillValues(Copyable original, CopyHandler handler) {
         super.fillValues(original, handler);
         TransportationObject originalTo = (TransportationObject) original;
-        for (TransportationObject to : originalTo.composesOf) {
-            composesOf.add(handler.getCopyInstance(to));
-        }
         ato = originalTo.ato;
     }
 
     @Override
     public Copyable createCopyInstance() {
-        return new TransportationObject(type);
+        return null;
     }
 
 }
diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/TransportationSpace.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/TransportationSpace.java
new file mode 100644
index 0000000..db66a38
--- /dev/null
+++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/TransportationSpace.java
@@ -0,0 +1,229 @@
+package de.hft.stuttgart.citydoctor2.datastructure;
+
+import de.hft.stuttgart.citydoctor2.check.Check;
+import de.hft.stuttgart.citydoctor2.check.CheckError;
+import de.hft.stuttgart.citydoctor2.check.CheckId;
+import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
+import de.hft.stuttgart.citydoctor2.utils.CityGmlUtils;
+import de.hft.stuttgart.citydoctor2.utils.CopyHandler;
+import de.hft.stuttgart.citydoctor2.utils.Copyable;
+import org.citygml4j.core.model.core.AbstractSpace;
+import org.citygml4j.core.util.geometry.GeometryFactory;
+import org.xmlobjects.gml.model.geometry.aggregates.MultiSurface;
+import org.xmlobjects.gml.model.geometry.aggregates.MultiSurfaceProperty;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public abstract class TransportationSpace extends TransportationObject {
+
+    private final List<TrafficSpaceObject> trafficSpaces = new ArrayList<>();
+    private final List<TrafficSpaceObject> auxTrafficSpaces = new ArrayList<>();
+
+    protected TransportationSpace(TransportationType type) {
+        super(type);
+    }
+
+    public List<TrafficSpaceObject> getTrafficSpaces() {
+        return trafficSpaces;
+    }
+
+    public List<TrafficSpaceObject> getAuxTrafficSpaces() {
+        return auxTrafficSpaces;
+    }
+
+    public void addTrafficSpace(TrafficSpaceObject t) {
+        trafficSpaces.add(t);
+    }
+
+    public void addAuxTrafficSpace(TrafficSpaceObject t) {
+        auxTrafficSpaces.add(t);
+    }
+
+    @Override
+    public void reCreateGeometries(GeometryFactory factory, ParserConfiguration config) {
+        for (Geometry geom : getGeometries()) {
+            if (geom instanceof ImplicitGeometryHolder) {
+                continue;
+            }
+            if (geom.getType() == GeometryType.MULTI_SURFACE) {
+                MultiSurface ms = CityGmlUtils.createMultiSurface(geom, factory, config);
+                AbstractSpace ats = (AbstractSpace) super.getGmlObject();
+                setMultiSurfaceAccordingToLod(ats, ms, geom.getLod());
+            } else {
+                throw new IllegalStateException("Geometry in TransportationObject cannot be of type " + geom.getType()
+                        + ". Only MultiSurface allowed");
+            }
+        }
+        for (TrafficSpaceObject spaces : trafficSpaces) {
+            spaces.reCreateGeometries(factory, config);
+        }
+        for (TrafficSpaceObject spaces : auxTrafficSpaces) {
+            spaces.reCreateGeometries(factory, config);
+        }
+    }
+
+    private void setMultiSurfaceAccordingToLod(AbstractSpace ats, MultiSurface ms, Lod lod) {
+        switch (lod) {
+            case LOD0:
+                ats.setLod0MultiSurface(new MultiSurfaceProperty(ms));
+                break;
+            case LOD2:
+                ats.setLod2MultiSurface(new MultiSurfaceProperty(ms));
+                break;
+            case LOD3:
+                ats.setLod3MultiSurface(new MultiSurfaceProperty(ms));
+                break;
+            default:
+                throw new IllegalStateException("cannot set geometry with LOD for AuxiliaryTrafficSpace: " + lod);
+        }
+    }
+
+
+    @Override
+    public boolean containsError(CheckId checkIdentifier) {
+        boolean hasError = super.containsError(checkIdentifier);
+        if (hasError) {
+            return true;
+        }
+        for (TrafficSpaceObject to : trafficSpaces) {
+            if (to.containsError(checkIdentifier)) {
+                return true;
+            }
+        }
+        for (TrafficSpaceObject to : auxTrafficSpaces) {
+            if (to.containsError(checkIdentifier)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public void clearAllContainedCheckResults() {
+        super.clearAllContainedCheckResults();
+        for (TrafficSpaceObject to : trafficSpaces) {
+            to.clearAllContainedCheckResults();
+        }
+        for (TrafficSpaceObject to : auxTrafficSpaces) {
+            to.clearAllContainedCheckResults();
+        }
+    }
+
+    @Override
+    public void collectContainedErrors(List<CheckError> errors) {
+        super.collectContainedErrors(errors);
+        for (TrafficSpaceObject to : trafficSpaces) {
+            to.collectContainedErrors(errors);
+        }
+        for (TrafficSpaceObject to : auxTrafficSpaces) {
+            to.collectContainedErrors(errors);
+        }
+    }
+
+    @Override
+    public boolean containsAnyError() {
+        boolean hasError = super.containsAnyError();
+        if (hasError) {
+            return true;
+        }
+        for (TrafficSpaceObject to : trafficSpaces) {
+            if (to.containsAnyError()) {
+                return true;
+            }
+        }
+        for (TrafficSpaceObject to : auxTrafficSpaces) {
+            if (to.containsAnyError()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public void accept(Check c) {
+        super.accept(c);
+        if (c.canExecute(this)) {
+            c.check(this);
+        }
+        for (TrafficSpaceObject to : trafficSpaces) {
+            to.accept(c);
+        }
+        for (TrafficSpaceObject to : auxTrafficSpaces) {
+            to.accept(c);
+        }
+    }
+
+
+    @Override
+    public void unsetGmlGeometries() {
+        AbstractSpace ats = (AbstractSpace) super.getGmlObject();
+        ats.setLod0MultiSurface(null);
+        ats.setLod2MultiSurface(null);
+        ats.setLod3MultiSurface(null);
+        for (TrafficSpaceObject to : trafficSpaces) {
+            to.unsetGmlGeometries();
+        }
+        for (TrafficSpaceObject to : auxTrafficSpaces) {
+            to.unsetGmlGeometries();
+        }
+    }
+
+    @Override
+    public CityObject getTopLevelCityObject() {
+        return this;
+    }
+
+
+    @Override
+    public String toString() {
+        return "TransportationSpace [id=" + getGmlId() + "]";
+    }
+
+    @Override
+    public void prepareForChecking() {
+        super.prepareForChecking();
+        for (TrafficSpaceObject to : trafficSpaces) {
+            to.prepareForChecking();
+        }
+        for (TrafficSpaceObject to : auxTrafficSpaces) {
+            to.prepareForChecking();
+        }
+    }
+
+    @Override
+    public void clearMetaInformation() {
+        super.clearMetaInformation();
+        for (TrafficSpaceObject to : trafficSpaces) {
+            to.clearMetaInformation();
+        }
+        for (TrafficSpaceObject to : auxTrafficSpaces) {
+            to.clearMetaInformation();
+        }
+    }
+
+    @Override
+    public void collectInstances(CopyHandler handler) {
+        super.collectInstances(handler);
+        for (TrafficSpaceObject to : trafficSpaces) {
+            to.collectInstances(handler);
+        }
+        for (TrafficSpaceObject to : auxTrafficSpaces) {
+            to.collectInstances(handler);
+        }
+    }
+
+    @Override
+    public void fillValues(Copyable original, CopyHandler handler) {
+        super.fillValues(original, handler);
+        TransportationObject originalTo = (TransportationObject) original;
+        for (TrafficSpaceObject to : trafficSpaces) {
+            to.fillValues(originalTo, handler);
+        }
+        for (TrafficSpaceObject to : auxTrafficSpaces) {
+            to.fillValues(originalTo, handler);
+        }
+    }
+
+
+}
diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/mapper/citygml3/Citygml3FeatureMapper.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/mapper/citygml3/Citygml3FeatureMapper.java
index 3fe786f..eb958a5 100644
--- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/mapper/citygml3/Citygml3FeatureMapper.java
+++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/mapper/citygml3/Citygml3FeatureMapper.java
@@ -30,7 +30,6 @@ import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
 import de.hft.stuttgart.citydoctor2.datastructure.TunnelConstructiveElement;
 import de.hft.stuttgart.citydoctor2.datastructure.TunnelFurniture;
 import de.hft.stuttgart.citydoctor2.datastructure.TunnelPart;
-import de.hft.stuttgart.citydoctor2.datastructure.TransportationObject.TransportationType;
 import de.hft.stuttgart.citydoctor2.datastructure.Vegetation.VegetationType;
 import de.hft.stuttgart.citydoctor2.math.graph.KDTree;
 import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
@@ -45,7 +44,6 @@ import org.citygml4j.core.model.building.Storey;
 import org.citygml4j.core.model.building.*;
 import org.citygml4j.core.model.construction.AbstractConstruction;
 import org.citygml4j.core.model.core.*;
-import org.citygml4j.core.model.deprecated.transportation.TransportationComplex;
 import org.citygml4j.core.model.landuse.LandUse;
 import org.citygml4j.core.model.transportation.*;
 import org.citygml4j.core.model.tunnel.Tunnel;
@@ -658,24 +656,14 @@ public class Citygml3FeatureMapper extends ObjectWalker {
 	}
 
 	@Override
-	public void visit(AuxiliaryTrafficArea ata) {
-		TransportationObject to = new TransportationObject(TransportationType.AUXILLIARY_TRAFFIC_AREA);
-		mapAbstractThematicSurface(ata, to);
-		finishTransportationMapping(to);
-	}
-
-	@Override
-	public void visit(TrafficArea ta) {
-		TransportationObject to = new TransportationObject(TransportationType.TRAFFIC_AREA);
-		mapAbstractThematicSurface(ta, to);
-		finishTransportationMapping(to);
-	}
-
-	@Override
-	public void visit(Road road) {
-		TransportationObject to = new TransportationObject(TransportationType.ROAD);
-		mapAbstractTransportationSpace(road, to);
-		finishTransportationMapping(to);
+	public void visit(AbstractTransportationSpace ats) {
+		TopLevelTransportFeature top = TopLevelTransportFeature.from(ats);
+		if (top == null) {
+			return;
+		}
+		top.setGmlObject(ats);
+		mapAbstractTransportationSpace(ats, top);
+		model.addTransportation(top);
 	}
 
 	private void mapAbstractThematicSurface(AbstractThematicSurface ats, CityObject co) {
@@ -707,33 +695,6 @@ public class Citygml3FeatureMapper extends ObjectWalker {
 		parseId(ag, to);
 	}
 
-	@Override
-	public void visit(Railway railway) {
-		TransportationObject to = new TransportationObject(TransportationType.RAILWAY);
-		mapAbstractTransportationSpace(railway, to);
-		finishTransportationMapping(to);
-	}
-
-	@Override
-	public void visit(Square square) {
-		TransportationObject to = new TransportationObject(TransportationType.SQUARE);
-		mapAbstractTransportationSpace(square, to);
-		finishTransportationMapping(to);
-	}
-
-	@Override
-	public void visit(Track track) {
-		TransportationObject to = new TransportationObject(TransportationType.TRACK);
-		mapAbstractTransportationSpace(track, to);
-		finishTransportationMapping(to);
-	}
-
-	@Override
-	public void visit(TransportationComplex transportationComplex) {
-		TransportationObject to = new TransportationObject(TransportationType.TRANSPORTATION_COMPLEX);
-		mapAbstractTransportationSpace(transportationComplex, to);
-		finishTransportationMapping(to);
-	}
 
 	private void finishTransportationMapping(TransportationObject to) {
 		finishCityObjectConstruction(to);
@@ -746,39 +707,119 @@ public class Citygml3FeatureMapper extends ObjectWalker {
 		updateEdgesAndVertices(co);
 	}
 
-	private void mapAbstractTransportationSpace(AbstractTransportationSpace ats, TransportationObject to) {
-		to.setGmlObject(ats);
-		parseAbstractTransportationSpaceGeometries(ats, to);
+	private void mapAbstractTransportationSpace(AbstractTransportationSpace ats, TransportationSpace trsp) {
+		parseAbstractTransportationSpaceGeometries(ats, trsp);
+		if (trsp instanceof TopLevelTransportFeature top) {
+			mapSectionsAndIntersections(ats, top);
+		}
 		for (TrafficSpaceProperty tsp : ats.getTrafficSpaces()) {
 			if (tsp.isSetObject()) {
-				TransportationObject trafficSpace = new TransportationObject(TransportationType.TRAFFIC_SPACE);
-				mapTrafficSpace(tsp.getObject(), trafficSpace);
-				finishTransportationMapping(trafficSpace);
-				to.getChildren().add(trafficSpace);
+				TrafficSpaceObject tso = new TrafficSpaceObject(TrafficSpaceObject.TrafficSpaceType.TRAFFIC_SPACE);
+				mapTrafficSpace(tsp.getObject(), tso);
+				trsp.addTrafficSpace(tso);
+			}
+		}
+		for (AuxiliaryTrafficSpaceProperty atsp : ats.getAuxiliaryTrafficSpaces()) {
+			if (atsp.isSetObject()) {
+				TrafficSpaceObject atso = new TrafficSpaceObject(TrafficSpaceObject.TrafficSpaceType.AUXILIARY_TRAFFIC_SPACE);
+				mapAuxiliaryTrafficSpace(atsp.getObject(), atso);
+				trsp.addTrafficSpace(atso);
+			}
+		}
+	}
+
+	private void mapSectionsAndIntersections(AbstractTransportationSpace ats, TopLevelTransportFeature top) {
+		List<SectionProperty> sectionProps;
+		List<IntersectionProperty> intersectionProps;
+		if (ats instanceof Track tr) {
+			sectionProps = tr.getSections();
+			intersectionProps = tr.getIntersections();
+		} else if (ats instanceof Road ro) {
+			sectionProps = ro.getSections();
+			intersectionProps = ro.getIntersections();
+		} else if (ats instanceof Waterway wa) {
+			sectionProps = wa.getSections();
+			intersectionProps = wa.getIntersections();
+		} else if (ats instanceof Railway rw) {
+			sectionProps = rw.getSections();
+			intersectionProps = rw.getIntersections();
+		} else if (ats instanceof Square || ats instanceof Section || ats instanceof Intersection) {
+			return;
+		} else {
+			logger.error("Mapping of Sections and Intersections failed, {} is not a TopLevelTransportFeature",
+					ats.getClass().getSimpleName());
+			return;
+		}
+		for (SectionProperty sectionProp : sectionProps) {
+			if (sectionProp.isSetObject()) {
+				TransportSection sect = new TransportSection(TransportSection.SectionType.SECTION);
+				sect.setGmlObject(sectionProp.getObject());
+				mapAbstractTransportationSpace(sectionProp.getObject(), sect);
+				finishCityObjectConstruction(sect);
+				top.addSection(sect);
 			}
 		}
-		for (AuxiliaryTrafficSpaceProperty auxTrafficProp : ats.getAuxiliaryTrafficSpaces()) {
-			if (auxTrafficProp.isSetObject()) {
-				TransportationObject trafficSpace = parseAuxiliaryTrafficSpace(auxTrafficProp.getObject());
-				finishTransportationMapping(trafficSpace);
-				to.addChild(trafficSpace);
+		for (IntersectionProperty intersectionProp : intersectionProps) {
+			if (intersectionProp.isSetObject()) {
+				TransportSection isect = new TransportSection(TransportSection.SectionType.INTERSECTION);
+				isect.setGmlObject(intersectionProp.getObject());
+				mapAbstractTransportationSpace(intersectionProp.getObject(), isect);
+				finishCityObjectConstruction(isect);
+				top.addIntersection(isect);
 			}
 		}
 	}
 
-	private void mapTrafficSpace(TrafficSpace ts, TransportationObject to) {
-		mapAbstractUnoccupiedSpace(ts, to);
+
+	private void mapTrafficSpace(TrafficSpace ts, TrafficSpaceObject tso) {
+		tso.setGmlObject(ts);
+		mapAbstractUnoccupiedSpace(ts, tso);
+		for (AbstractSpaceBoundaryProperty boundary : ts.getBoundaries()) {
+			if (boundary.isSetObject()) {
+				TrafficArea area = (TrafficArea) boundary.getObject();
+				TrafficAreaObject tao = new TrafficAreaObject(TrafficAreaObject.TrafficAreaType.TRAFFIC_AREA);
+				mapTrafficArea(area, tao);
+				tso.addTrafficArea(tao);
+			}
+		}
+		finishCityObjectConstruction(tso);
 	}
 
-	private void mapAbstractUnoccupiedSpace(AbstractUnoccupiedSpace aus, CityObject co) {
-		mapAbstractPhysicalSpace(aus, co);
+	private void mapAuxiliaryTrafficSpace(AuxiliaryTrafficSpace ats, TrafficSpaceObject tso) {
+		tso.setGmlObject(ats);
+		mapAbstractUnoccupiedSpace(ats, tso);
+		for (AbstractSpaceBoundaryProperty boundary : ats.getBoundaries()) {
+			if (boundary.isSetObject()) {
+				AuxiliaryTrafficArea area = (AuxiliaryTrafficArea) boundary.getObject();
+				TrafficAreaObject tao = new TrafficAreaObject(TrafficAreaObject.TrafficAreaType.AUXILIARY_TRAFFIC_AREA);
+				mapAuxiliaryTrafficArea(area, tao);
+				tso.addTrafficArea(tao);
+			}
+		}
 	}
 
-	private TransportationObject parseAuxiliaryTrafficSpace(AuxiliaryTrafficSpace ats) {
-		TransportationObject to = new TransportationObject(TransportationType.AUXILLIARY_TRAFFIC_SPACE);
-		parseAbstractSpaceGeometries(ats, to);
-		finishCityObjectConstruction(to);
-		return to;
+	private void mapTrafficArea(TrafficArea ta, TrafficAreaObject tao) {
+		tao.setGmlObject(ta);
+		parseAndAddMultiSurface(ta.getLod0MultiSurface(), Lod.LOD0, tao);
+		parseAndAddMultiSurface(ta.getLod1MultiSurface(), Lod.LOD1, tao);
+		parseAndAddMultiSurface(ta.getLod2MultiSurface(), Lod.LOD2, tao);
+		parseAndAddMultiSurface(ta.getLod3MultiSurface(), Lod.LOD3, tao);
+		parseAndAddMultiSurface(ta.getDeprecatedProperties().getLod4MultiSurface(), Lod.LOD4, tao);
+		finishCityObjectConstruction(tao);
+	}
+
+	private void mapAuxiliaryTrafficArea(AuxiliaryTrafficArea ats, TrafficAreaObject tao) {
+		tao.setGmlObject(ats);
+		parseAndAddMultiSurface(ats.getLod0MultiSurface(), Lod.LOD0, tao);
+		parseAndAddMultiSurface(ats.getLod1MultiSurface(), Lod.LOD1, tao);
+		parseAndAddMultiSurface(ats.getLod2MultiSurface(), Lod.LOD2, tao);
+		parseAndAddMultiSurface(ats.getLod3MultiSurface(), Lod.LOD3, tao);
+		parseAndAddMultiSurface(ats.getDeprecatedProperties().getLod4MultiSurface(), Lod.LOD4, tao);
+		finishCityObjectConstruction(tao);
+	}
+
+	private void mapAbstractUnoccupiedSpace(AbstractUnoccupiedSpace aus, CityObject co) {
+		mapAbstractPhysicalSpace(aus, co);
 	}
 
 	private void parseAbstractTransportationSpaceGeometries(AbstractTransportationSpace space, CityObject co) {
diff --git a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/mapper/citygml3/Citygml3GeometryMapper.java b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/mapper/citygml3/Citygml3GeometryMapper.java
index 10fc353..4b99f27 100644
--- a/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/mapper/citygml3/Citygml3GeometryMapper.java
+++ b/CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/mapper/citygml3/Citygml3GeometryMapper.java
@@ -63,6 +63,53 @@ public class Citygml3GeometryMapper extends GeometryWalker {
         }
     }
 
+    @Override
+    public void visit(Surface surface) {
+
+        // TODO: Implement like CompositeSurfaces, just with PolygonPatches
+        if (surface.getPatches() != null && !surface.getPatches().isSetObjects()) {
+            logger.warn("Surface {} has no PolygonPatches.", surface.getId());
+            return;
+        }
+        CompositeCollection comp = new CompositeCollection();
+        List<PolygonPatch> polygonPatches = (List<PolygonPatch>) surface.getPatches().getObjects();
+        Citygml3GeometryMapper recursiveMapper = new Citygml3GeometryMapper(config, vertexMap);
+        for (PolygonPatch patch : polygonPatches) {
+            recursiveMapper.parsePolygonPatch(patch.getExterior(), patch.getInterior());
+        }
+
+        List<ConcretePolygon> compPolys = recursiveMapper.getPolygons();
+        compPolys.forEach(comp::addCompositeMember);
+        comp.addAllChildComposites(recursiveMapper.getComposites());
+        composites.add(comp);
+        polygons.addAll(compPolys);
+
+    }
+
+    private void parsePolygonPatch(AbstractRingProperty exterior, List<AbstractRingProperty> interior) {
+        if (exterior == null || exterior.getObject() == null) {
+            if (logger.isWarnEnabled()) {
+                logger.warn(Localization.getText("GeometryMapper.emptyPolygon"));
+            }
+            return;
+        }
+        ConcretePolygon conc = new ConcretePolygon();
+        polygons.add(conc);
+
+        currentRing = new LinearRing(LinearRingType.EXTERIOR);
+        exterior.getObject().accept(this);
+        conc.setExteriorRing(currentRing);
+        for (AbstractRingProperty interiorGmlRing : interior) {
+            AbstractRing gmlRing = interiorGmlRing.getObject();
+            if (gmlRing == null) {
+                continue;
+            }
+            currentRing = new LinearRing(LinearRingType.INTERIOR);
+            gmlRing.accept(this);
+            conc.addInteriorRing(currentRing);
+        }
+    }
+
     private void parsePolygon(String id, AbstractRingProperty exterior, List<AbstractRingProperty> interior) {
         if (exterior == null || exterior.getObject() == null) {
             if (logger.isWarnEnabled()) {
diff --git a/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/reporting/pdf/PdfStreamReporter.java b/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/reporting/pdf/PdfStreamReporter.java
index d863282..45a5fc7 100644
--- a/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/reporting/pdf/PdfStreamReporter.java
+++ b/CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/reporting/pdf/PdfStreamReporter.java
@@ -286,9 +286,6 @@ public class PdfStreamReporter implements StreamReporter {
 		}
 		writeErrorForCityObject(co, tSection);
 		TransportationObject to = (TransportationObject) co;
-		for (TransportationObject transO : to.getChildren()) {
-			writeCheckResultForTransportationObject(transO, tSection);
-		}
 	}
 
 	private void reportVegetation(CityObject co, boolean hasError) {
-- 
GitLab