/*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
*
* This file is part of CityDoctor2.
*
* CityDoctor2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CityDoctor2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with CityDoctor2. If not, see .
*/
package de.hft.stuttgart.citydoctor2.mapper;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.citygml4j.model.citygml.bridge.AbstractBridge;
import org.citygml4j.model.citygml.bridge.Bridge;
import org.citygml4j.model.citygml.bridge.BridgePart;
import org.citygml4j.model.citygml.building.BuildingInstallationProperty;
import org.citygml4j.model.citygml.building.BuildingPartProperty;
import org.citygml4j.model.citygml.building.OpeningProperty;
import org.citygml4j.model.citygml.core.CityModel;
import org.citygml4j.model.citygml.landuse.LandUse;
import org.citygml4j.model.citygml.transportation.AuxiliaryTrafficArea;
import org.citygml4j.model.citygml.transportation.AuxiliaryTrafficAreaProperty;
import org.citygml4j.model.citygml.transportation.Railway;
import org.citygml4j.model.citygml.transportation.Road;
import org.citygml4j.model.citygml.transportation.Square;
import org.citygml4j.model.citygml.transportation.Track;
import org.citygml4j.model.citygml.transportation.TrafficArea;
import org.citygml4j.model.citygml.transportation.TrafficAreaProperty;
import org.citygml4j.model.citygml.transportation.TransportationComplex;
import org.citygml4j.model.citygml.vegetation.PlantCover;
import org.citygml4j.model.citygml.vegetation.SolitaryVegetationObject;
import org.citygml4j.model.citygml.waterbody.WaterBody;
import org.citygml4j.model.gml.geometry.AbstractGeometry;
import org.citygml4j.model.gml.geometry.GeometryProperty;
import org.citygml4j.model.gml.geometry.complexes.CompositeSurface;
import org.citygml4j.model.gml.geometry.primitives.AbstractSolid;
import org.citygml4j.util.walker.FeatureWalker;
import de.hft.stuttgart.citydoctor2.datastructure.AbstractBuilding;
import de.hft.stuttgart.citydoctor2.datastructure.BoundarySurface;
import de.hft.stuttgart.citydoctor2.datastructure.BoundarySurfaceType;
import de.hft.stuttgart.citydoctor2.datastructure.BridgeObject;
import de.hft.stuttgart.citydoctor2.datastructure.BridgeObject.BridgeType;
import de.hft.stuttgart.citydoctor2.datastructure.Building;
import de.hft.stuttgart.citydoctor2.datastructure.BuildingInstallation;
import de.hft.stuttgart.citydoctor2.datastructure.BuildingPart;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.datastructure.ConcretePolygon;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.datastructure.GeometryType;
import de.hft.stuttgart.citydoctor2.datastructure.GmlId;
import de.hft.stuttgart.citydoctor2.datastructure.LandObject;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing;
import de.hft.stuttgart.citydoctor2.datastructure.LinkedPolygon;
import de.hft.stuttgart.citydoctor2.datastructure.Lod;
import de.hft.stuttgart.citydoctor2.datastructure.Opening;
import de.hft.stuttgart.citydoctor2.datastructure.OpeningType;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
import de.hft.stuttgart.citydoctor2.datastructure.SurfaceFeatureType;
import de.hft.stuttgart.citydoctor2.datastructure.TransportationObject;
import de.hft.stuttgart.citydoctor2.datastructure.TransportationObject.TransportationType;
import de.hft.stuttgart.citydoctor2.datastructure.Vegetation;
import de.hft.stuttgart.citydoctor2.datastructure.Vegetation.VegetationType;
import de.hft.stuttgart.citydoctor2.datastructure.Vertex;
import de.hft.stuttgart.citydoctor2.datastructure.WaterObject;
import de.hft.stuttgart.citydoctor2.math.graph.KDTree;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.utils.Localization;
import de.hft.stuttgart.citydoctor2.utils.Pair;
/**
* This walker maps all cityGML4j features to the respective CityDoctor data
* structure.
*
* @author Matthias Betz
*
*/
public class FeatureMapper extends FeatureWalker {
private static final Logger logger = LogManager.getLogger(FeatureMapper.class);
private CityDoctorModel model;
private ParserConfiguration config;
private double neighborDistance;
public FeatureMapper(ParserConfiguration config, File file) {
this.config = config;
neighborDistance = 1.8d / Math.pow(10, config.getNumberOfRoundingPlaces());
model = new CityDoctorModel(config, file);
}
@Override
public void visit(WaterBody waterBody) {
WaterObject wo = new WaterObject();
model.addWater(wo);
wo.setGmlObject(waterBody);
if (waterBody.isSetId()) {
wo.setGmlId(new GmlId(waterBody.getId()));
}
mapWaterBodyGeometries(waterBody, wo);
}
private void mapWaterBodyGeometries(WaterBody waterBody, WaterObject wo) {
Map polygons = new HashMap<>();
Map vertexMap = new HashMap<>();
List> linkedPolygons = new ArrayList<>();
GeometryMapper.mapLod0MultiSurface(waterBody.getLod0MultiSurface(), wo, config, polygons, linkedPolygons,
vertexMap);
waterBody.unsetLod0MultiSurface();
GeometryMapper.mapLod1MultiSurface(waterBody.getLod1MultiSurface(), wo, config, polygons, linkedPolygons,
vertexMap);
waterBody.unsetLod1MultiSurface();
GeometryMapper.mapLod1Solid(waterBody.getLod1Solid(), wo, config, polygons, linkedPolygons, vertexMap);
waterBody.unsetLod1Solid();
GeometryMapper.mapLod2Solid(waterBody.getLod2Solid(), wo, config, polygons, linkedPolygons, vertexMap);
waterBody.unsetLod2Solid();
GeometryMapper.mapLod3Solid(waterBody.getLod3Solid(), wo, config, polygons, linkedPolygons, vertexMap);
waterBody.unsetLod3Solid();
GeometryMapper.mapLod4Solid(waterBody.getLod4Solid(), wo, config, polygons, linkedPolygons, vertexMap);
waterBody.unsetLod4Solid();
createLinkedPolygons(polygons, linkedPolygons);
updateEdgesAndVertices(wo);
}
private void createLinkedPolygons(Map polygons,
List> linkedPolygons) {
for (Pair link : linkedPolygons) {
ConcretePolygon concPoly = polygons.get(link.getValue0());
if (concPoly == null) {
if (logger.isWarnEnabled()) {
logger.warn(Localization.getText("FeatureMapper.polygonUnreferenced"), link.getValue0());
}
continue;
}
Geometry geom = link.getValue1();
LinkedPolygon lPoly = new LinkedPolygon(concPoly, geom);
if (geom.getParent() instanceof BoundarySurface) {
BoundarySurface bs = (BoundarySurface) geom.getParent();
lPoly.setPartOfSurface(bs);
if (bs.getParent() instanceof BuildingInstallation) {
lPoly.setPartOfInstallation((BuildingInstallation) bs.getParent());
}
}
geom.addPolygon(lPoly);
}
}
private void updateEdgesAndVertices(CityObject co) {
// searching for neighboring vertices, replacing them with one single vertex to
// avoid later problems with edges and manifold problems
for (Geometry geom : co.getGeometries()) {
KDTree tree = new KDTree();
for (Polygon poly : geom.getPolygons()) {
LinearRing lr = poly.getExteriorRing();
updateRing(tree, lr);
for (LinearRing innerRing : poly.getInnerRings()) {
updateRing(tree, innerRing);
}
}
if (!config.useLowMemoryConsumption()) {
// no low memory consumption mode meaning create all meta information in geometry
geom.updateEdgesAndVertices();
}
}
}
private void updateRing(KDTree tree, LinearRing lr) {
for (int i = 0; i < lr.getVertices().size(); i++) {
Vertex v = lr.getVertices().get(i);
List nodesInRange = tree.getNodesInRange(v, neighborDistance);
if (nodesInRange.isEmpty()) {
tree.add(v);
} else {
if (nodesInRange.size() != 1) {
throw new IllegalStateException(
"Found more than one vertex in range of " + v + " this should never happen here");
}
// replace other vertex with neighboring one
Vertex original = nodesInRange.get(0);
lr.setVertex(i, original);
}
}
}
@Override
public void visit(PlantCover plantCover) {
Vegetation veg = new Vegetation(VegetationType.PLANT_COVER);
model.addVegetation(veg);
mapPlantCover(plantCover, veg);
}
private void mapPlantCover(PlantCover plantCover, Vegetation veg) {
veg.setGmlObject(plantCover);
if (plantCover.isSetId()) {
veg.setGmlId(new GmlId(plantCover.getId()));
}
mapPlantCoverGeometries(plantCover, veg);
}
private void mapPlantCoverGeometries(PlantCover plantCover, Vegetation veg) {
Map polygons = new HashMap<>();
List> linkedPolygons = new ArrayList<>();
Map vertexMap = new HashMap<>();
GeometryMapper.mapLod1MultiSurface(plantCover.getLod1MultiSurface(), veg, config, polygons, linkedPolygons,
vertexMap);
plantCover.unsetLod1MultiSurface();
GeometryMapper.mapLod2MultiSurface(plantCover.getLod2MultiSurface(), veg, config, polygons, linkedPolygons,
vertexMap);
plantCover.unsetLod2MultiSurface();
GeometryMapper.mapLod3MultiSurface(plantCover.getLod3MultiSurface(), veg, config, polygons, linkedPolygons,
vertexMap);
plantCover.unsetLod3MultiSurface();
GeometryMapper.mapLod4MultiSurface(plantCover.getLod4MultiSurface(), veg, config, polygons, linkedPolygons,
vertexMap);
plantCover.unsetLod4MultiSurface();
createLinkedPolygons(polygons, linkedPolygons);
updateEdgesAndVertices(veg);
}
@Override
public void visit(SolitaryVegetationObject solitaryVegetationObject) {
Vegetation veg = new Vegetation(VegetationType.SOLITARY_VEGETATION_OBJECT);
model.addVegetation(veg);
mapSolitaryVegObject(solitaryVegetationObject, veg);
}
private void mapSolitaryVegObject(SolitaryVegetationObject svo, Vegetation veg) {
veg.setGmlObject(svo);
if (svo.isSetId()) {
veg.setGmlId(new GmlId(svo.getId()));
}
mapSolitaryVegGeometries(svo, veg);
}
private void mapSolitaryVegGeometries(SolitaryVegetationObject svo, Vegetation veg) {
Map polygons = new HashMap<>();
List> linkedPolygons = new ArrayList<>();
Map vertexMap = new HashMap<>();
GeometryMapper.mapLod1Geometry(svo.getLod1Geometry(), veg, config, polygons, linkedPolygons, vertexMap);
svo.unsetLod1Geometry();
GeometryMapper.mapLod2Geometry(svo.getLod2Geometry(), veg, config, polygons, linkedPolygons, vertexMap);
svo.unsetLod2Geometry();
GeometryMapper.mapLod3Geometry(svo.getLod3Geometry(), veg, config, polygons, linkedPolygons, vertexMap);
svo.unsetLod3Geometry();
GeometryMapper.mapLod4Geometry(svo.getLod4Geometry(), veg, config, polygons, linkedPolygons, vertexMap);
svo.unsetLod4Geometry();
createLinkedPolygons(polygons, linkedPolygons);
updateEdgesAndVertices(veg);
}
@Override
public void visit(LandUse landUse) {
LandObject lo = new LandObject(landUse);
model.addLand(lo);
mapLandUse(landUse, lo);
}
private void mapLandUse(LandUse landUse, LandObject lo) {
lo.setGmlObject(landUse);
if (landUse.isSetId()) {
lo.setGmlId(new GmlId(landUse.getId()));
}
mapLandUseGeometries(landUse, lo);
}
private void mapLandUseGeometries(LandUse landUse, LandObject lo) {
Map polygons = new HashMap<>();
List> linkedPolygons = new ArrayList<>();
Map vertexMap = new HashMap<>();
GeometryMapper.mapLod0MultiSurface(landUse.getLod0MultiSurface(), lo, config, polygons, linkedPolygons,
vertexMap);
landUse.unsetLod0MultiSurface();
GeometryMapper.mapLod1MultiSurface(landUse.getLod1MultiSurface(), lo, config, polygons, linkedPolygons,
vertexMap);
landUse.unsetLod1MultiSurface();
GeometryMapper.mapLod2MultiSurface(landUse.getLod2MultiSurface(), lo, config, polygons, linkedPolygons,
vertexMap);
landUse.unsetLod2MultiSurface();
GeometryMapper.mapLod3MultiSurface(landUse.getLod3MultiSurface(), lo, config, polygons, linkedPolygons,
vertexMap);
landUse.unsetLod3MultiSurface();
GeometryMapper.mapLod4MultiSurface(landUse.getLod4MultiSurface(), lo, config, polygons, linkedPolygons,
vertexMap);
landUse.unsetLod4MultiSurface();
createLinkedPolygons(polygons, linkedPolygons);
updateEdgesAndVertices(lo);
}
@Override
public void visit(Road road) {
TransportationObject trans = new TransportationObject(TransportationType.ROAD);
mapTransportationComplex(road, trans);
}
@Override
public void visit(Railway railway) {
TransportationObject trans = new TransportationObject(TransportationType.RAILWAY);
mapTransportationComplex(railway, trans);
}
@Override
public void visit(Square square) {
TransportationObject trans = new TransportationObject(TransportationType.SQUARE);
mapTransportationComplex(square, trans);
}
@Override
public void visit(Track track) {
TransportationObject trans = new TransportationObject(TransportationType.TRACK);
mapTransportationComplex(track, trans);
}
@Override
public void visit(AuxiliaryTrafficArea auxiliaryTrafficArea) {
TransportationObject trans = new TransportationObject(TransportationType.AUXILLIARY_TRAFFIC_AREA);
mapAuxTrafficArea(auxiliaryTrafficArea, trans);
}
@Override
public void visit(TransportationComplex tc) {
TransportationObject trans = new TransportationObject(TransportationType.TRANSPORTATION_COMPLEX);
model.addTransportation(trans);
mapTransportationComplex(tc, trans);
if (tc.isSetAuxiliaryTrafficArea()) {
for (AuxiliaryTrafficAreaProperty atap : tc.getAuxiliaryTrafficArea()) {
if (atap.isSetAuxiliaryTrafficArea()) {
TransportationObject subTrans = new TransportationObject(
TransportationType.AUXILLIARY_TRAFFIC_AREA);
trans.addChild(subTrans);
mapAuxTrafficArea(atap.getAuxiliaryTrafficArea(), subTrans);
}
}
}
if (tc.isSetTrafficArea()) {
for (TrafficAreaProperty tap : tc.getTrafficArea()) {
if (tap.isSetTrafficArea()) {
TransportationObject subTrans = new TransportationObject(TransportationType.TRAFFIC_AREA);
trans.addChild(subTrans);
mapTrafficArea(tap.getTrafficArea(), subTrans);
}
}
}
}
@Override
public void visit(TrafficArea trafficArea) {
TransportationObject trans = new TransportationObject(TransportationType.TRAFFIC_AREA);
model.addTransportation(trans);
mapTrafficArea(trafficArea, trans);
}
private void mapTrafficArea(TrafficArea ta, TransportationObject to) {
to.setGmlObject(ta);
if (ta.isSetId()) {
to.setGmlId(new GmlId(ta.getId()));
}
mapTrafficAreaGeometries(ta, to);
}
private void mapTrafficAreaGeometries(TrafficArea ta, TransportationObject to) {
Map polygons = new HashMap<>();
List> linkedPolygons = new ArrayList<>();
Map vertexMap = new HashMap<>();
GeometryMapper.mapLod2MultiSurface(ta.getLod2MultiSurface(), to, config, polygons, linkedPolygons, vertexMap);
ta.unsetLod2MultiSurface();
GeometryMapper.mapLod3MultiSurface(ta.getLod3MultiSurface(), to, config, polygons, linkedPolygons, vertexMap);
ta.unsetLod3MultiSurface();
GeometryMapper.mapLod4MultiSurface(ta.getLod4MultiSurface(), to, config, polygons, linkedPolygons, vertexMap);
ta.unsetLod4MultiSurface();
createLinkedPolygons(polygons, linkedPolygons);
updateEdgesAndVertices(to);
}
private void mapAuxTrafficArea(AuxiliaryTrafficArea ata, TransportationObject to) {
to.setGmlObject(ata);
if (ata.isSetId()) {
to.setGmlId(new GmlId(ata.getId()));
}
mapAuxTrafficAreaGeometries(ata, to);
}
private void mapAuxTrafficAreaGeometries(AuxiliaryTrafficArea ata, TransportationObject to) {
Map polygons = new HashMap<>();
List> linkedPolygons = new ArrayList<>();
Map vertexMap = new HashMap<>();
GeometryMapper.mapLod2MultiSurface(ata.getLod2MultiSurface(), to, config, polygons, linkedPolygons, vertexMap);
ata.unsetLod2MultiSurface();
GeometryMapper.mapLod3MultiSurface(ata.getLod3MultiSurface(), to, config, polygons, linkedPolygons, vertexMap);
ata.unsetLod3MultiSurface();
GeometryMapper.mapLod4MultiSurface(ata.getLod4MultiSurface(), to, config, polygons, linkedPolygons, vertexMap);
ata.unsetLod4MultiSurface();
createLinkedPolygons(polygons, linkedPolygons);
updateEdgesAndVertices(to);
}
private void mapTransportationComplex(TransportationComplex tc, TransportationObject to) {
model.addTransportation(to);
to.setGmlObject(tc);
if (tc.isSetId()) {
to.setGmlId(new GmlId(tc.getId()));
}
mapTransportationComplexGeometries(tc, to);
}
private void mapTransportationComplexGeometries(TransportationComplex tc, TransportationObject to) {
Map polygons = new HashMap<>();
List> linkedPolygons = new ArrayList<>();
Map vertexMap = new HashMap<>();
GeometryMapper.mapLod1MultiSurface(tc.getLod1MultiSurface(), to, config, polygons, linkedPolygons, vertexMap);
tc.unsetLod1MultiSurface();
GeometryMapper.mapLod2MultiSurface(tc.getLod2MultiSurface(), to, config, polygons, linkedPolygons, vertexMap);
tc.unsetLod2MultiSurface();
GeometryMapper.mapLod3MultiSurface(tc.getLod3MultiSurface(), to, config, polygons, linkedPolygons, vertexMap);
tc.unsetLod3MultiSurface();
GeometryMapper.mapLod4MultiSurface(tc.getLod4MultiSurface(), to, config, polygons, linkedPolygons, vertexMap);
tc.unsetLod4MultiSurface();
createLinkedPolygons(polygons, linkedPolygons);
updateEdgesAndVertices(to);
}
@Override
public void visit(org.citygml4j.model.citygml.building.Building building) {
Building coBuilding = new Building();
model.addBuilding(coBuilding);
mapAbstractBuilding(building, coBuilding);
if (building.isSetConsistsOfBuildingPart()) {
for (BuildingPartProperty bpp : building.getConsistsOfBuildingPart()) {
if (bpp.isSetBuildingPart()) {
BuildingPart coBuildingPart = new BuildingPart(coBuilding);
mapAbstractBuilding(bpp.getBuildingPart(), coBuildingPart);
}
}
}
}
private void mapAbstractBuilding(org.citygml4j.model.citygml.building.AbstractBuilding ab,
AbstractBuilding coBuilding) {
coBuilding.setGmlObject(ab);
if (ab.isSetId()) {
coBuilding.setGmlId(new GmlId(ab.getId()));
}
Map polygons = new HashMap<>();
List> linkedPolygons = new ArrayList<>();
Map vertexMap = new HashMap<>();
mapBuildingMultiSurfaceGeometries(ab, coBuilding, polygons, linkedPolygons, vertexMap);
mapBuildingSolidGeometries(ab, coBuilding, polygons, linkedPolygons, vertexMap);
// handle boundary surfaces
if (ab.isSetBoundedBySurface()) {
for (org.citygml4j.model.citygml.building.BoundarySurfaceProperty bsp : ab.getBoundedBySurface()) {
mapBuildingSurface(bsp, coBuilding, polygons, linkedPolygons, vertexMap);
}
}
// handle outer building installations
if (ab.isSetOuterBuildingInstallation()) {
for (BuildingInstallationProperty bip : ab.getOuterBuildingInstallation()) {
mapBuildingInstallation(bip, coBuilding, polygons, linkedPolygons, vertexMap);
}
}
createLinkedPolygons(polygons, linkedPolygons);
updateEdgesAndVertices(coBuilding);
}
private void mapBuildingInstallation(BuildingInstallationProperty bip, AbstractBuilding coBuilding,
Map polygons, List> linkedPolygons,
Map vertexMap) {
if (!bip.isSetBuildingInstallation()) {
return;
}
BuildingInstallation coBi = new BuildingInstallation();
coBuilding.addBuildingInstallation(coBi);
org.citygml4j.model.citygml.building.BuildingInstallation gmlBi = bip.getBuildingInstallation();
coBi.setGmlObject(gmlBi);
if (gmlBi.isSetLod2Geometry()) {
GeometryProperty extends AbstractGeometry> abstractGeometry = gmlBi.getLod2Geometry();
GeometryType type = extractGeometryType(abstractGeometry);
Geometry geom = new Geometry(type, Lod.LOD2);
GeometryMapper mapper = new GeometryMapper(geom, config, polygons, linkedPolygons, vertexMap);
GeometryMapper.mapBuildingInstallationIntoGeometry(abstractGeometry, mapper, coBi);
coBi.addGeometry(geom);
gmlBi.unsetLod2Geometry();
}
if (gmlBi.isSetLod3Geometry()) {
GeometryProperty extends AbstractGeometry> abstractGeometry = gmlBi.getLod3Geometry();
GeometryType type = extractGeometryType(abstractGeometry);
Geometry geom = new Geometry(type, Lod.LOD3);
GeometryMapper mapper = new GeometryMapper(geom, config, polygons, linkedPolygons, vertexMap);
GeometryMapper.mapBuildingInstallationIntoGeometry(abstractGeometry, mapper, coBi);
coBi.addGeometry(geom);
gmlBi.unsetLod3Geometry();
}
if (gmlBi.isSetLod4Geometry()) {
GeometryProperty extends AbstractGeometry> abstractGeometry = gmlBi.getLod4Geometry();
GeometryType type = extractGeometryType(abstractGeometry);
Geometry geom = new Geometry(type, Lod.LOD4);
GeometryMapper mapper = new GeometryMapper(geom, config, polygons, linkedPolygons, vertexMap);
GeometryMapper.mapBuildingInstallationIntoGeometry(abstractGeometry, mapper, coBi);
coBi.addGeometry(geom);
gmlBi.unsetLod4Geometry();
}
// handle boundary surfaces
if (gmlBi.isSetBoundedBySurface()) {
for (org.citygml4j.model.citygml.building.BoundarySurfaceProperty bsp : gmlBi.getBoundedBySurface()) {
mapBuildingInstallationSurface(bsp, coBi, polygons, linkedPolygons, vertexMap);
}
}
updateEdgesAndVertices(coBi);
}
private GeometryType extractGeometryType(GeometryProperty extends AbstractGeometry> agp) {
AbstractGeometry abstractGeometry = agp.getObject();
if (abstractGeometry instanceof CompositeSurface) {
return GeometryType.COMPOSITE_SURFACE;
} else if (abstractGeometry instanceof AbstractSolid) {
return GeometryType.SOLID;
}
return GeometryType.MULTI_SURFACE;
}
private void mapBuildingSolidGeometries(org.citygml4j.model.citygml.building.AbstractBuilding ab,
AbstractBuilding coBuilding, Map polygons,
List> linkedPolygons, Map vertexMap) {
GeometryMapper.mapLod1Solid(ab.getLod1Solid(), coBuilding, config, polygons, linkedPolygons, vertexMap);
ab.unsetLod1Solid();
GeometryMapper.mapLod2Solid(ab.getLod2Solid(), coBuilding, config, polygons, linkedPolygons, vertexMap);
ab.unsetLod2Solid();
GeometryMapper.mapLod3Solid(ab.getLod3Solid(), coBuilding, config, polygons, linkedPolygons, vertexMap);
ab.unsetLod3Solid();
GeometryMapper.mapLod4Solid(ab.getLod4Solid(), coBuilding, config, polygons, linkedPolygons, vertexMap);
ab.unsetLod4Solid();
}
private void mapBuildingMultiSurfaceGeometries(org.citygml4j.model.citygml.building.AbstractBuilding ab,
AbstractBuilding coBuilding, Map polygons,
List> linkedPolygons, Map vertexMap) {
GeometryMapper.mapLod1MultiSurface(ab.getLod1MultiSurface(), coBuilding, config, polygons, linkedPolygons,
vertexMap);
ab.unsetLod1MultiSurface();
GeometryMapper.mapLod2MultiSurface(ab.getLod2MultiSurface(), coBuilding, config, polygons, linkedPolygons,
vertexMap);
ab.unsetLod2MultiSurface();
GeometryMapper.mapLod3MultiSurface(ab.getLod3MultiSurface(), coBuilding, config, polygons, linkedPolygons,
vertexMap);
ab.unsetLod3MultiSurface();
GeometryMapper.mapLod4MultiSurface(ab.getLod4MultiSurface(), coBuilding, config, polygons, linkedPolygons,
vertexMap);
ab.unsetLod4MultiSurface();
}
private void mapBuildingSurface(org.citygml4j.model.citygml.building.BoundarySurfaceProperty bsp,
AbstractBuilding coBuilding, Map polygons,
List> linkedPolygons, Map vertexMap) {
if (!bsp.isSetBoundarySurface()) {
return;
}
org.citygml4j.model.citygml.building.AbstractBoundarySurface abs = bsp.getBoundarySurface();
BoundarySurfaceType surfaceType = mapSurfaceType(abs);
BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.BUILDING, surfaceType, abs);
if (abs.isSetId()) {
bs.setGmlId(new GmlId(abs.getId()));
}
coBuilding.addBoundarySurface(bs);
createBoundarySurfaceGeometries(abs, bs, null, polygons, linkedPolygons, vertexMap);
mapBuildingOpenings(abs.getOpening(), bs, polygons, linkedPolygons, vertexMap);
updateEdgesAndVertices(bs);
}
private void mapBuildingOpenings(List openings, BoundarySurface bs,
Map polygons, List> linkedPolygons,
Map vertexMap) {
if (openings == null || openings.isEmpty()) {
return;
}
for (org.citygml4j.model.citygml.building.OpeningProperty op : openings) {
if (!op.isSetOpening()) {
continue;
}
org.citygml4j.model.citygml.building.AbstractOpening ap = op.getOpening();
OpeningType type = mapOpeningType(ap);
Opening opening = new Opening(type, SurfaceFeatureType.BUILDING, bs, ap);
bs.addOpening(opening);
createOpeningGeometries(ap, opening, polygons, linkedPolygons, vertexMap);
updateEdgesAndVertices(opening);
}
}
private void createOpeningGeometries(org.citygml4j.model.citygml.building.AbstractOpening ap, Opening opening,
Map polygons, List> linkedPolygons,
Map vertexMap) {
if (ap.isSetLod3MultiSurface()) {
GeometryMapper.mapLod3MultiSurface(ap.getLod3MultiSurface(), opening, config, polygons, linkedPolygons,
vertexMap);
ap.unsetLod3MultiSurface();
}
if (ap.isSetLod4MultiSurface()) {
GeometryMapper.mapLod4MultiSurface(ap.getLod3MultiSurface(), opening, config, polygons, linkedPolygons,
vertexMap);
ap.unsetLod4MultiSurface();
}
}
private OpeningType mapOpeningType(org.citygml4j.model.citygml.building.AbstractOpening ap) {
if (ap instanceof org.citygml4j.model.citygml.building.Door) {
return OpeningType.DOOR;
}
if (ap instanceof org.citygml4j.model.citygml.building.Window) {
return OpeningType.WINDOW;
}
return OpeningType.UNKNOWN;
}
private void mapBuildingInstallationSurface(org.citygml4j.model.citygml.building.BoundarySurfaceProperty bsp,
BuildingInstallation coBi, Map polygons,
List> linkedPolygons, Map vertexMap) {
if (!bsp.isSetBoundarySurface()) {
return;
}
org.citygml4j.model.citygml.building.AbstractBoundarySurface abs = bsp.getBoundarySurface();
BoundarySurfaceType surfaceType = mapSurfaceType(abs);
BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.BUILDING, surfaceType, abs);
if (abs.isSetId()) {
bs.setGmlId(new GmlId(abs.getId()));
}
coBi.addBoundarySurface(bs);
createBoundarySurfaceGeometries(abs, bs, coBi, polygons, linkedPolygons, vertexMap);
mapBuildingOpenings(abs.getOpening(), bs, polygons, linkedPolygons, vertexMap);
updateEdgesAndVertices(bs);
}
private void createBoundarySurfaceGeometries(org.citygml4j.model.citygml.building.AbstractBoundarySurface abs,
BoundarySurface bs, BuildingInstallation coBi, Map polygons,
List> linkedPolygons, Map vertexMap) {
if (abs.isSetLod2MultiSurface()) {
Geometry geom = new Geometry(GeometryType.MULTI_SURFACE, Lod.LOD2);
GeometryMapper mapper = new GeometryMapper(geom, config, polygons, linkedPolygons, vertexMap);
GeometryMapper.mapBoundarySurfaceIntoGeometry(abs.getLod2MultiSurface(), mapper, bs, coBi);
bs.addGeometry(geom);
abs.unsetLod2MultiSurface();
}
if (abs.isSetLod3MultiSurface()) {
Geometry geom = new Geometry(GeometryType.MULTI_SURFACE, Lod.LOD3);
GeometryMapper mapper = new GeometryMapper(geom, config, polygons, linkedPolygons, vertexMap);
GeometryMapper.mapBoundarySurfaceIntoGeometry(abs.getLod3MultiSurface(), mapper, bs, coBi);
bs.addGeometry(geom);
abs.unsetLod3MultiSurface();
}
if (abs.isSetLod4MultiSurface()) {
Geometry geom = new Geometry(GeometryType.MULTI_SURFACE, Lod.LOD4);
GeometryMapper mapper = new GeometryMapper(geom, config, polygons, linkedPolygons, vertexMap);
GeometryMapper.mapBoundarySurfaceIntoGeometry(abs.getLod4MultiSurface(), mapper, bs, coBi);
bs.addGeometry(geom);
abs.unsetLod4MultiSurface();
}
}
private void createBoundarySurfaceGeometries(org.citygml4j.model.citygml.bridge.AbstractBoundarySurface abs,
BoundarySurface bs, Map polygons, List> linkedPolygons,
Map vertexMap) {
if (abs.isSetLod2MultiSurface()) {
Geometry geom = new Geometry(GeometryType.MULTI_SURFACE, Lod.LOD2);
GeometryMapper mapper = new GeometryMapper(geom, config, polygons, linkedPolygons, vertexMap);
GeometryMapper.mapBoundarySurfaceIntoGeometry(abs.getLod2MultiSurface(), mapper, bs, null);
bs.addGeometry(geom);
abs.unsetLod2MultiSurface();
}
if (abs.isSetLod3MultiSurface()) {
Geometry geom = new Geometry(GeometryType.MULTI_SURFACE, Lod.LOD3);
GeometryMapper mapper = new GeometryMapper(geom, config, polygons, linkedPolygons, vertexMap);
GeometryMapper.mapBoundarySurfaceIntoGeometry(abs.getLod3MultiSurface(), mapper, bs, null);
bs.addGeometry(geom);
abs.unsetLod3MultiSurface();
}
if (abs.isSetLod4MultiSurface()) {
Geometry geom = new Geometry(GeometryType.MULTI_SURFACE, Lod.LOD4);
GeometryMapper mapper = new GeometryMapper(geom, config, polygons, linkedPolygons, vertexMap);
GeometryMapper.mapBoundarySurfaceIntoGeometry(abs.getLod4MultiSurface(), mapper, bs, null);
bs.addGeometry(geom);
abs.unsetLod4MultiSurface();
}
}
private BoundarySurfaceType mapSurfaceType(org.citygml4j.model.citygml.building.AbstractBoundarySurface abs) {
switch (abs.getCityGMLClass()) {
case BUILDING_WALL_SURFACE:
return BoundarySurfaceType.WALL;
case BUILDING_ROOF_SURFACE:
return BoundarySurfaceType.ROOF;
case BUILDING_GROUND_SURFACE:
return BoundarySurfaceType.GROUND;
case BUILDING_CLOSURE_SURFACE:
return BoundarySurfaceType.CLOSURE;
case BUILDING_FLOOR_SURFACE:
return BoundarySurfaceType.OUTER_FLOOR;
case OUTER_BUILDING_FLOOR_SURFACE:
return BoundarySurfaceType.OUTER_FLOOR;
case BUILDING_CEILING_SURFACE:
return BoundarySurfaceType.OUTER_CEILING;
case OUTER_BUILDING_CEILING_SURFACE:
return BoundarySurfaceType.OUTER_CEILING;
default:
return BoundarySurfaceType.UNDEFINED;
}
}
@Override
public void visit(Bridge bridge) {
BridgeObject coBridge = new BridgeObject(BridgeType.BRIDGE, bridge);
mapBridge(bridge, coBridge);
}
@Override
public void visit(BridgePart bridgePart) {
BridgeObject coBridge = new BridgeObject(BridgeType.BRIDGE_PART, bridgePart);
mapBridge(bridgePart, coBridge);
}
private void mapBridge(AbstractBridge aBridge, BridgeObject coBridge) {
model.addBridge(coBridge);
coBridge.setGmlObject(aBridge);
if (aBridge.isSetId()) {
coBridge.setGmlId(new GmlId(aBridge.getId()));
}
Map polygons = new HashMap<>();
List> linkedPolygons = new ArrayList<>();
Map vertexMap = new HashMap<>();
// map geometries
mapBridgeMultiSurfaceGeometries(aBridge, coBridge, polygons, linkedPolygons, vertexMap);
mapBridgeSolidGeometries(aBridge, coBridge, polygons, linkedPolygons, vertexMap);
// handle boundary surfaces
if (aBridge.isSetBoundedBySurface()) {
for (org.citygml4j.model.citygml.bridge.BoundarySurfaceProperty bsp : aBridge.getBoundedBySurface()) {
mapBridgeSurface(bsp, coBridge, polygons, linkedPolygons, vertexMap);
}
}
createLinkedPolygons(polygons, linkedPolygons);
updateEdgesAndVertices(coBridge);
}
private void mapBridgeMultiSurfaceGeometries(AbstractBridge aBridge, BridgeObject coBridge,
Map polygons, List> linkedPolygons,
Map vertexMap) {
GeometryMapper.mapLod1MultiSurface(aBridge.getLod1MultiSurface(), coBridge, config, polygons, linkedPolygons,
vertexMap);
aBridge.unsetLod1MultiSurface();
GeometryMapper.mapLod2MultiSurface(aBridge.getLod2MultiSurface(), coBridge, config, polygons, linkedPolygons,
vertexMap);
aBridge.unsetLod2MultiSurface();
GeometryMapper.mapLod3MultiSurface(aBridge.getLod3MultiSurface(), coBridge, config, polygons, linkedPolygons,
vertexMap);
aBridge.unsetLod3MultiSurface();
GeometryMapper.mapLod4MultiSurface(aBridge.getLod4MultiSurface(), coBridge, config, polygons, linkedPolygons,
vertexMap);
aBridge.unsetLod4MultiSurface();
}
private void mapBridgeSolidGeometries(AbstractBridge aBridge, BridgeObject coBridge,
Map polygons, List> linkedPolygons,
Map vertexMap) {
GeometryMapper.mapLod1Solid(aBridge.getLod1Solid(), coBridge, config, polygons, linkedPolygons, vertexMap);
aBridge.unsetLod1Solid();
GeometryMapper.mapLod2Solid(aBridge.getLod2Solid(), coBridge, config, polygons, linkedPolygons, vertexMap);
aBridge.unsetLod2Solid();
GeometryMapper.mapLod3Solid(aBridge.getLod3Solid(), coBridge, config, polygons, linkedPolygons, vertexMap);
aBridge.unsetLod3Solid();
GeometryMapper.mapLod4Solid(aBridge.getLod4Solid(), coBridge, config, polygons, linkedPolygons, vertexMap);
aBridge.unsetLod4Solid();
}
private void mapBridgeSurface(org.citygml4j.model.citygml.bridge.BoundarySurfaceProperty bsp, BridgeObject coBridge,
Map polygons, List> linkedPolygons,
Map vertexMap) {
if (!bsp.isSetBoundarySurface()) {
return;
}
org.citygml4j.model.citygml.bridge.AbstractBoundarySurface abs = bsp.getBoundarySurface();
BoundarySurfaceType surfaceType = mapSurfaceType(abs);
BoundarySurface bs = new BoundarySurface(SurfaceFeatureType.BRIDGE, surfaceType, abs);
bs.setGmlObject(abs);
coBridge.addBoundarySurface(bs);
mapBridgeOpenings(abs.getOpening(), bs, polygons, linkedPolygons, vertexMap);
createBoundarySurfaceGeometries(abs, bs, polygons, linkedPolygons, vertexMap);
updateEdgesAndVertices(bs);
}
private void mapBridgeOpenings(List openings,
BoundarySurface bs, Map polygons, List> linkedPolygons,
Map vertexMap) {
if (openings == null || openings.isEmpty()) {
return;
}
for (org.citygml4j.model.citygml.bridge.OpeningProperty op : openings) {
if (!op.isSetOpening()) {
continue;
}
org.citygml4j.model.citygml.bridge.AbstractOpening ap = op.getOpening();
OpeningType type = mapOpeningType(ap);
Opening opening = new Opening(type, SurfaceFeatureType.BRIDGE, bs, ap);
bs.addOpening(opening);
createOpeningGeometries(ap, opening, polygons, linkedPolygons, vertexMap);
updateEdgesAndVertices(opening);
}
}
private void createOpeningGeometries(org.citygml4j.model.citygml.bridge.AbstractOpening ap, Opening opening,
Map polygons, List> linkedPolygons,
Map vertexMap) {
if (ap.isSetLod3MultiSurface()) {
GeometryMapper.mapLod3MultiSurface(ap.getLod3MultiSurface(), opening, config, polygons, linkedPolygons,
vertexMap);
ap.unsetLod3MultiSurface();
}
if (ap.isSetLod4MultiSurface()) {
GeometryMapper.mapLod4MultiSurface(ap.getLod3MultiSurface(), opening, config, polygons, linkedPolygons,
vertexMap);
ap.unsetLod4MultiSurface();
}
}
private OpeningType mapOpeningType(org.citygml4j.model.citygml.bridge.AbstractOpening ap) {
if (ap instanceof org.citygml4j.model.citygml.bridge.Door) {
return OpeningType.DOOR;
}
if (ap instanceof org.citygml4j.model.citygml.bridge.Window) {
return OpeningType.WINDOW;
}
return OpeningType.UNKNOWN;
}
private BoundarySurfaceType mapSurfaceType(org.citygml4j.model.citygml.bridge.AbstractBoundarySurface abs) {
switch (abs.getCityGMLClass()) {
case BRIDGE_CEILING_SURFACE:
return BoundarySurfaceType.CEILING;
case BRIDGE_CLOSURE_SURFACE:
return BoundarySurfaceType.CLOSURE;
case BRIDGE_FLOOR_SURFACE:
return BoundarySurfaceType.FLOOR;
case BRIDGE_GROUND_SURFACE:
return BoundarySurfaceType.GROUND;
case BRIDGE_ROOF_SURFACE:
return BoundarySurfaceType.ROOF;
case BRIDGE_WALL_SURFACE:
return BoundarySurfaceType.WALL;
case INTERIOR_BRIDGE_WALL_SURFACE:
return BoundarySurfaceType.INTERIOR_WALL;
case OUTER_BRIDGE_CEILING_SURFACE:
return BoundarySurfaceType.OUTER_CEILING;
case OUTER_BUILDING_FLOOR_SURFACE:
return BoundarySurfaceType.OUTER_FLOOR;
default:
return BoundarySurfaceType.UNDEFINED;
}
}
public CityDoctorModel getModel() {
return model;
}
public void setCityModel(CityModel cModel) {
model.setCityModel(cModel);
}
}