Commit 3f3c1884 authored by Matthias Betz's avatar Matthias Betz
Browse files

change to citygml4j 3.0.0 rc4

change to quality ade 0.1.4
parent 92f3e523
Pipeline #6596 failed with stage
in 17 seconds
......@@ -18,10 +18,11 @@
*/
package de.hft.stuttgart.citydoctor2.datastructure;
import org.citygml4j.factory.GMLGeometryFactory;
import org.citygml4j.model.citygml.core.AbstractCityObject;
import org.citygml4j.model.gml.geometry.aggregates.MultiSurface;
import org.citygml4j.model.gml.geometry.aggregates.MultiSurfaceProperty;
import org.citygml4j.core.model.construction.AbstractFillingSurface;
import org.citygml4j.core.model.core.AbstractCityObject;
import org.citygml4j.core.util.geometry.GeometryFactory;
import org.xmlobjects.gml.model.geometry.aggregates.MultiSurface;
import org.xmlobjects.gml.model.geometry.aggregates.MultiSurfaceProperty;
import de.hft.stuttgart.citydoctor2.check.Check;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
......@@ -45,21 +46,22 @@ public class Opening extends CityObject {
private OpeningType type;
private SurfaceFeatureType featureType;
private AbstractCityObject ao;
private AbstractFillingSurface ao;
private Opening(OpeningType type) {
this.type = type;
}
public Opening(OpeningType type, SurfaceFeatureType featureType, BoundarySurface partOf, AbstractCityObject ao) {
public Opening(OpeningType type, SurfaceFeatureType featureType, BoundarySurface partOf,
AbstractFillingSurface ao) {
this.featureType = featureType;
this.partOf = partOf;
this.type = type;
this.ao = ao;
}
public void reCreateGeometries(GMLGeometryFactory factory, ParserConfiguration config) {
if (!ao.isSetId()) {
public void reCreateGeometries(GeometryFactory factory, ParserConfiguration config) {
if (ao.getId() != null) {
ao.setId(getGmlId().getGmlString());
}
for (Geometry geom : getGeometries()) {
......@@ -67,55 +69,33 @@ public class Opening extends CityObject {
MultiSurface ms = CityGmlUtils.createMultiSurface(geom, factory, config);
setGeometryAccordingToLod(geom.getLod(), new MultiSurfaceProperty(ms));
} else {
throw new IllegalStateException("BoundarySurfaces can only have MultiSurface geometries");
throw new IllegalStateException("Openings can only have MultiSurface geometries");
}
}
}
private void setGeometryAccordingToLod(Lod lod, MultiSurfaceProperty ms) {
switch (lod) {
case LOD0:
ao.setLod0MultiSurface(ms);
break;
case LOD1:
ao.setLod1MultiSurface(ms);
break;
case LOD2:
ao.setLod2MultiSurface(ms);
break;
case LOD3:
setLod3Ms(ms);
ao.setLod3MultiSurface(ms);
break;
case LOD4:
setLod4Ms(ms);
ao.getDeprecatedProperties().setLod4MultiSurface(ms);
break;
default:
throw new IllegalStateException("Cannot add geometry to opening because lod is not allowed: " + lod);
}
}
private void setLod3Ms(MultiSurfaceProperty ms) {
switch (featureType) {
case BRIDGE:
org.citygml4j.model.citygml.bridge.AbstractOpening bridgeAo = (org.citygml4j.model.citygml.bridge.AbstractOpening) ao;
bridgeAo.setLod3MultiSurface(ms);
break;
case BUILDING:
org.citygml4j.model.citygml.building.AbstractOpening buildAo = (org.citygml4j.model.citygml.building.AbstractOpening) ao;
buildAo.setLod3MultiSurface(ms);
break;
case TUNNEL:
org.citygml4j.model.citygml.tunnel.AbstractOpening tunAo = (org.citygml4j.model.citygml.tunnel.AbstractOpening) ao;
tunAo.setLod3MultiSurface(ms);
}
}
private void setLod4Ms(MultiSurfaceProperty ms) {
switch (featureType) {
case BRIDGE:
org.citygml4j.model.citygml.bridge.AbstractOpening bridgeAo = (org.citygml4j.model.citygml.bridge.AbstractOpening) ao;
bridgeAo.setLod4MultiSurface(ms);
break;
case BUILDING:
org.citygml4j.model.citygml.building.AbstractOpening buildAo = (org.citygml4j.model.citygml.building.AbstractOpening) ao;
buildAo.setLod4MultiSurface(ms);
break;
case TUNNEL:
org.citygml4j.model.citygml.tunnel.AbstractOpening tunAo = (org.citygml4j.model.citygml.tunnel.AbstractOpening) ao;
tunAo.setLod4MultiSurface(ms);
}
}
public SurfaceFeatureType getSurfaceFeatureType() {
return featureType;
......@@ -147,22 +127,11 @@ public class Opening extends CityObject {
}
public void unsetGmlGeometries() {
switch (featureType) {
case BRIDGE:
org.citygml4j.model.citygml.bridge.AbstractOpening bridgeAo = (org.citygml4j.model.citygml.bridge.AbstractOpening) ao;
bridgeAo.unsetLod3MultiSurface();
bridgeAo.unsetLod4MultiSurface();
break;
case BUILDING:
org.citygml4j.model.citygml.building.AbstractOpening buildAo = (org.citygml4j.model.citygml.building.AbstractOpening) ao;
buildAo.unsetLod3MultiSurface();
buildAo.unsetLod4MultiSurface();
break;
case TUNNEL:
org.citygml4j.model.citygml.tunnel.AbstractOpening tunAo = (org.citygml4j.model.citygml.tunnel.AbstractOpening) ao;
tunAo.unsetLod3MultiSurface();
tunAo.unsetLod4MultiSurface();
}
ao.setLod0MultiSurface(null);
ao.setLod1MultiSurface(null);
ao.setLod2MultiSurface(null);
ao.setLod3MultiSurface(null);
ao.getDeprecatedProperties().setLod4MultiSurface(null);
}
@Override
......@@ -188,13 +157,13 @@ public class Opening extends CityObject {
public Copyable createCopyInstance() {
return new Opening(type);
}
@Override
public void collectInstances(CopyHandler handler) {
super.collectInstances(handler);
handler.addInstance(partOf);
}
@Override
public void fillValues(Copyable original, CopyHandler handler) {
super.fillValues(original, handler);
......
......@@ -77,5 +77,7 @@ public abstract class Polygon extends GmlElement {
abstract void anonymize();
public abstract ConcretePolygon getOriginal();
public abstract void remove();
}
\ No newline at end of file
......@@ -21,14 +21,14 @@ package de.hft.stuttgart.citydoctor2.datastructure;
import java.util.ArrayList;
import java.util.List;
import org.citygml4j.factory.GMLGeometryFactory;
import org.citygml4j.model.citygml.core.AbstractCityObject;
import org.citygml4j.model.citygml.transportation.AbstractTransportationObject;
import org.citygml4j.model.citygml.transportation.AuxiliaryTrafficArea;
import org.citygml4j.model.citygml.transportation.TrafficArea;
import org.citygml4j.model.citygml.transportation.TransportationComplex;
import org.citygml4j.model.gml.geometry.aggregates.MultiSurface;
import org.citygml4j.model.gml.geometry.aggregates.MultiSurfaceProperty;
import org.citygml4j.core.model.core.AbstractCityObject;
import org.citygml4j.core.model.core.AbstractSpace;
import org.citygml4j.core.model.transportation.AbstractTransportationSpace;
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 de.hft.stuttgart.citydoctor2.check.Check;
import de.hft.stuttgart.citydoctor2.check.CheckError;
......@@ -49,10 +49,10 @@ public class TransportationObject extends CityObject {
private static final long serialVersionUID = -2698907271726700390L;
public enum TransportationType {
ROAD, TRACK, RAILWAY, TRAFFIC_AREA, AUXILLIARY_TRAFFIC_AREA, TRANSPORTATION_COMPLEX, SQUARE
ROAD, TRACK, RAILWAY, TRAFFIC_AREA, AUXILLIARY_TRAFFIC_AREA, TRANSPORTATION_COMPLEX, SQUARE, AUXILLIARY_TRAFFIC_SPACE, TRAFFIC_SPACE
}
private AbstractTransportationObject ato;
private AbstractCityObject ato;
private List<TransportationObject> composesOf = new ArrayList<>(1);
private TransportationType type;
......@@ -66,17 +66,13 @@ public class TransportationObject extends CityObject {
}
@Override
public void reCreateGeometries(GMLGeometryFactory factory, ParserConfiguration config) {
public void reCreateGeometries(GeometryFactory factory, ParserConfiguration config) {
for (Geometry geom : getGeometries()) {
if (geom.getType() == GeometryType.MULTI_SURFACE) {
MultiSurface ms = CityGmlUtils.createMultiSurface(geom, factory, config);
switch (type) {
case ROAD:
case TRACK:
case RAILWAY:
case SQUARE:
case TRANSPORTATION_COMPLEX:
TransportationComplex tc = (TransportationComplex) ato;
case ROAD, TRACK, RAILWAY, SQUARE, TRANSPORTATION_COMPLEX:
AbstractTransportationSpace tc = (AbstractTransportationSpace) ato;
setMultiSurfaceAccordingToLod(tc, ms, geom.getLod());
break;
case TRAFFIC_AREA:
......@@ -87,6 +83,10 @@ public class TransportationObject extends CityObject {
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()
......@@ -98,10 +98,26 @@ public class TransportationObject extends CityObject {
}
}
private void setMultiSurfaceAccordingToLod(TransportationComplex tc, MultiSurface ms, Lod lod) {
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.setLod1MultiSurface(new MultiSurfaceProperty(ms));
tc.getDeprecatedProperties().setLod1MultiSurface(new MultiSurfaceProperty(ms));
break;
case LOD2:
tc.setLod2MultiSurface(new MultiSurfaceProperty(ms));
......@@ -110,7 +126,7 @@ public class TransportationObject extends CityObject {
tc.setLod3MultiSurface(new MultiSurfaceProperty(ms));
break;
case LOD4:
tc.setLod4MultiSurface(new MultiSurfaceProperty(ms));
tc.getDeprecatedProperties().setLod4MultiSurface(new MultiSurfaceProperty(ms));
break;
default:
throw new IllegalStateException("cannot set geometry with LOD for TransportationComplex: " + lod);
......@@ -119,6 +135,12 @@ public class TransportationObject extends CityObject {
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;
......@@ -126,7 +148,7 @@ public class TransportationObject extends CityObject {
ata.setLod3MultiSurface(new MultiSurfaceProperty(ms));
break;
case LOD4:
ata.setLod4MultiSurface(new MultiSurfaceProperty(ms));
ata.getDeprecatedProperties().setLod4MultiSurface(new MultiSurfaceProperty(ms));
break;
default:
throw new IllegalStateException("cannot set geometry with LOD for AuxiliaryTrafficArea: " + lod);
......@@ -142,7 +164,7 @@ public class TransportationObject extends CityObject {
ta.setLod3MultiSurface(new MultiSurfaceProperty(ms));
break;
case LOD4:
ta.setLod4MultiSurface(new MultiSurfaceProperty(ms));
ta.getDeprecatedProperties().setLod4MultiSurface(new MultiSurfaceProperty(ms));
break;
default:
throw new IllegalStateException("cannot set geometry with LOD for TrafficArea: " + lod);
......@@ -217,28 +239,36 @@ public class TransportationObject extends CityObject {
case RAILWAY:
case SQUARE:
case TRANSPORTATION_COMPLEX:
TransportationComplex tc = (TransportationComplex) ato;
tc.unsetLod1MultiSurface();
tc.unsetLod2MultiSurface();
tc.unsetLod3MultiSurface();
tc.unsetLod4MultiSurface();
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.unsetLod2MultiSurface();
ta.unsetLod3MultiSurface();
ta.unsetLod4MultiSurface();
ta.setLod2MultiSurface(null);
ta.setLod3MultiSurface(null);
ta.getDeprecatedProperties().setLod4MultiSurface(null);
break;
case AUXILLIARY_TRAFFIC_AREA:
AuxiliaryTrafficArea ata = (AuxiliaryTrafficArea) ato;
ata.unsetLod2MultiSurface();
ata.unsetLod3MultiSurface();
ata.unsetLod4MultiSurface();
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;
}
}
public void setGmlObject(AbstractTransportationObject tc) {
public void setGmlObject(AbstractCityObject tc) {
ato = tc;
}
......
......@@ -18,22 +18,23 @@
*/
package de.hft.stuttgart.citydoctor2.datastructure;
import org.citygml4j.factory.GMLGeometryFactory;
import org.citygml4j.model.citygml.core.AbstractCityObject;
import org.citygml4j.model.citygml.vegetation.AbstractVegetationObject;
import org.citygml4j.model.citygml.vegetation.PlantCover;
import org.citygml4j.model.citygml.vegetation.SolitaryVegetationObject;
import org.citygml4j.model.gml.geometry.aggregates.MultiSolid;
import org.citygml4j.model.gml.geometry.aggregates.MultiSolidProperty;
import org.citygml4j.model.gml.geometry.aggregates.MultiSurface;
import org.citygml4j.model.gml.geometry.aggregates.MultiSurfaceProperty;
import org.citygml4j.model.gml.geometry.primitives.Solid;
import org.citygml4j.model.gml.geometry.primitives.SolidProperty;
import java.util.Collections;
import org.citygml4j.core.model.core.AbstractCityObject;
import org.citygml4j.core.model.vegetation.AbstractVegetationObject;
import org.citygml4j.core.model.vegetation.PlantCover;
import org.citygml4j.core.model.vegetation.SolitaryVegetationObject;
import org.citygml4j.core.util.geometry.GeometryFactory;
import org.xmlobjects.gml.model.geometry.aggregates.MultiSolid;
import org.xmlobjects.gml.model.geometry.aggregates.MultiSolidProperty;
import org.xmlobjects.gml.model.geometry.aggregates.MultiSurface;
import org.xmlobjects.gml.model.geometry.aggregates.MultiSurfaceProperty;
import org.xmlobjects.gml.model.geometry.primitives.Solid;
import org.xmlobjects.gml.model.geometry.primitives.SolidProperty;
import de.hft.stuttgart.citydoctor2.check.Check;
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;
/**
......@@ -63,7 +64,7 @@ public class Vegetation extends CityObject {
}
@Override
public void reCreateGeometries(GMLGeometryFactory factory, ParserConfiguration config) {
public void reCreateGeometries(GeometryFactory factory, ParserConfiguration config) {
for (Geometry geom : getGeometries()) {
if (geom.getType() == GeometryType.MULTI_SURFACE) {
MultiSurface ms = CityGmlUtils.createMultiSurface(geom, factory, config);
......@@ -90,16 +91,16 @@ public class Vegetation extends CityObject {
private void setSolidAccordingToLod(PlantCover pc, Solid solid, Lod lod) {
switch (lod) {
case LOD1:
pc.setLod1MultiSolid(new MultiSolidProperty(new MultiSolid(solid)));
pc.getDeprecatedProperties().setLod1MultiSolid(new MultiSolidProperty(new MultiSolid(Collections.singletonList(new SolidProperty(solid)))));
break;
case LOD2:
pc.setLod2MultiSolid(new MultiSolidProperty(new MultiSolid(solid)));
pc.getDeprecatedProperties().setLod2MultiSolid(new MultiSolidProperty(new MultiSolid(Collections.singletonList(new SolidProperty(solid)))));
break;
case LOD3:
pc.setLod3MultiSolid(new MultiSolidProperty(new MultiSolid(solid)));
pc.getDeprecatedProperties().setLod3MultiSolid(new MultiSolidProperty(new MultiSolid(Collections.singletonList(new SolidProperty(solid)))));
break;
case LOD4:
pc.setLod4MultiSolid(new MultiSolidProperty(new MultiSolid(solid)));
pc.getDeprecatedProperties().setLod4MultiSolid(new MultiSolidProperty(new MultiSolid(Collections.singletonList(new SolidProperty(solid)))));
break;
default:
throw new IllegalStateException("Cannot set Solid with lod to PlantCover:" + lod);
......@@ -109,16 +110,16 @@ public class Vegetation extends CityObject {
private void setSolidAccordingToLod(SolitaryVegetationObject svo, Solid solid, Lod lod) {
switch (lod) {
case LOD1:
svo.setLod1Geometry(new SolidProperty(solid));
svo.getDeprecatedProperties().setLod1Geometry(new SolidProperty(solid));
break;
case LOD2:
svo.setLod2Geometry(new SolidProperty(solid));
svo.getDeprecatedProperties().setLod2Geometry(new SolidProperty(solid));
break;
case LOD3:
svo.setLod3Geometry(new SolidProperty(solid));
svo.getDeprecatedProperties().setLod3Geometry(new SolidProperty(solid));
break;
case LOD4:
svo.setLod4Geometry(new SolidProperty(solid));
svo.getDeprecatedProperties().setLod4Geometry(new SolidProperty(solid));
break;
default:
throw new IllegalStateException("Cannot set Solid with lod to SolitaryVegetationObject:" + lod);
......@@ -128,7 +129,7 @@ public class Vegetation extends CityObject {
private void setMultiSurfaceAccordingToLod(PlantCover pc, MultiSurface ms, Lod lod) {
switch (lod) {
case LOD1:
pc.setLod1MultiSurface(new MultiSurfaceProperty(ms));
pc.getDeprecatedProperties().setLod1MultiSurface(new MultiSurfaceProperty(ms));
break;
case LOD2:
pc.setLod2MultiSurface(new MultiSurfaceProperty(ms));
......@@ -137,7 +138,7 @@ public class Vegetation extends CityObject {
pc.setLod3MultiSurface(new MultiSurfaceProperty(ms));
break;
case LOD4:
pc.setLod4MultiSurface(new MultiSurfaceProperty(ms));
pc.getDeprecatedProperties().setLod4MultiSurface(new MultiSurfaceProperty(ms));
break;
default:
throw new IllegalStateException("Cannot set MultiSurface with lod to PlantCover:" + lod);
......@@ -148,16 +149,16 @@ public class Vegetation extends CityObject {
private void setMultiSurfaceAccordingToLod(SolitaryVegetationObject svo, MultiSurface ms, Lod lod) {
switch (lod) {
case LOD1:
svo.setLod1Geometry(new MultiSurfaceProperty(ms));
svo.getDeprecatedProperties().setLod1Geometry(new MultiSurfaceProperty(ms));
break;
case LOD2:
svo.setLod2Geometry(new MultiSurfaceProperty(ms));
svo.getDeprecatedProperties().setLod2Geometry(new MultiSurfaceProperty(ms));
break;
case LOD3:
svo.setLod3Geometry(new MultiSurfaceProperty(ms));
svo.getDeprecatedProperties().setLod3Geometry(new MultiSurfaceProperty(ms));
break;
case LOD4:
svo.setLod4Geometry(new MultiSurfaceProperty(ms));
svo.getDeprecatedProperties().setLod4Geometry(new MultiSurfaceProperty(ms));
break;
default:
throw new IllegalStateException("Cannot set MultiSurface with lod to SolitaryVegetationObject:" + lod);
......@@ -181,16 +182,16 @@ public class Vegetation extends CityObject {
public void unsetGmlGeometries() {
if (type == VegetationType.SOLITARY_VEGETATION_OBJECT) {
SolitaryVegetationObject svo = (SolitaryVegetationObject) citygmlVegetation;
svo.unsetLod1Geometry();
svo.unsetLod2Geometry();
svo.unsetLod3Geometry();
svo.unsetLod4Geometry();
svo.getDeprecatedProperties().setLod1Geometry(null);
svo.getDeprecatedProperties().setLod2Geometry(null);
svo.getDeprecatedProperties().setLod3Geometry(null);
svo.getDeprecatedProperties().setLod4Geometry(null);
} else {
PlantCover pc = (PlantCover) citygmlVegetation;
pc.unsetLod1MultiSurface();
pc.unsetLod2MultiSurface();
pc.unsetLod3MultiSurface();
pc.unsetLod4MultiSurface();
pc.getDeprecatedProperties().setLod1MultiSurface(null);
pc.setLod2MultiSurface(null);
pc.setLod3MultiSurface(null);
pc.getDeprecatedProperties().setLod4MultiSurface(null);
}
}
......@@ -211,11 +212,4 @@ public class Vegetation extends CityObject {
public Copyable createCopyInstance() {
return new Vegetation(type);
}
@Override
public void fillValues(Copyable original, CopyHandler handler) {
super.fillValues(original, handler);
}
}
......@@ -18,11 +18,14 @@
*/
package de.hft.stuttgart.citydoctor2.datastructure;
import org.citygml4j.factory.GMLGeometryFactory;
import org.citygml4j.model.citygml.core.AbstractCityObject;
import org.citygml4j.model.citygml.waterbody.WaterBody;
import org.citygml4j.model.gml.geometry.aggregates.MultiSurface;
import org.citygml4j.model.gml.geometry.aggregates.MultiSurfaceProperty;
import java.util.ArrayList;
import java.util.List;
import org.citygml4j.core.model.core.AbstractCityObject;
import org.citygml4j.core.model.waterbody.WaterBody;
import org.citygml4j.core.util.geometry.GeometryFactory;
import org.xmlobjects.gml.model.geometry.aggregates.MultiSurface;
import org.xmlobjects.gml.model.geometry.aggregates.MultiSurfaceProperty;
import de.hft.stuttgart.citydoctor2.check.Check;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
......@@ -41,16 +44,17 @@ public class WaterObject extends CityObject {
private static final long serialVersionUID = -3821060595086337424L;
private WaterBody gmlWater;
private List<BoundarySurface> boundarySurfaceList = new ArrayList<>();
@Override
public void reCreateGeometries(GMLGeometryFactory factory, ParserConfiguration config) {
public void reCreateGeometries(GeometryFactory factory, ParserConfiguration config) {
for (Geometry geom : getGeometries()) {
if (geom.getType() == GeometryType.MULTI_SURFACE) {
MultiSurface ms = CityGmlUtils.createMultiSurface(geom, factory, config);
if (geom.getLod() == Lod.LOD0) {
gmlWater.setLod0MultiSurface(new MultiSurfaceProperty(ms));
} else if (geom.getLod() == Lod.LOD1) {
gmlWater.setLod1MultiSurface(new MultiSurfaceProperty(ms));
gmlWater.getDeprecatedProperties().setLod1MultiSurface(new MultiSurfaceProperty(ms));
} else {
throw new IllegalStateException(
"Cannot add MultiSurface geometry with lod to WaterBody:" + geom.getLod());
......@@ -60,6 +64,20 @@ public class WaterObject extends CityObject {
}
}
}
/**
* Getter for all boundary surfaces contained in this building.
*
* @return the boundary surfaces
*/
public List<BoundarySurface> getBoundarySurfaces() {
return boundarySurfaceList;
}
public void addBoundarySurface(BoundarySurface bs) {
boundarySurfaceList.add(bs);
bs.setParent(this);
}
@Override
public FeatureType getFeatureType() {
......@@ -81,12 +99,8 @@ public class WaterObject extends CityObject {
@Override
public void unsetGmlGeometries() {
gmlWater.unsetLod0MultiSurface();
gmlWater.unsetLod1MultiSurface();
gmlWater.unsetLod1Solid();
gmlWater.unsetLod2Solid();
gmlWater.unsetLod3Solid();
gmlWater.unsetLod4Solid();
gmlWater.setLod0MultiSurface(null);
gmlWater.getDeprecatedProperties().setLod1MultiSurface(null);
}
public void setGmlObject(WaterBody waterBody) {
......
/*-
* 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 <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.exceptions;
public class CityDoctorWriteException extends Exception {
private static final long serialVersionUID = 2902212162405599516L;
public CityDoctorWriteException() {
super();
}
public CityDoctorWriteException(String message, Throwable cause, boolean enableSuppression,
boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
public CityDoctorWriteException(String message, Throwable cause) {
super(message, cause);
}
public CityDoctorWriteException(String message) {
super(message);
}
public CityDoctorWriteException(Throwable cause) {
super(cause);
}
}
/*-
* 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 <https://www.gnu.org/licenses/>.
*/
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<String, ConcretePolygon> polygons = new HashMap<>();
Map<Vertex, Vertex> vertexMap = new HashMap<>();
List<Pair<String, Geometry>> 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<String, ConcretePolygon> polygons,
List<Pair<String, Geometry>> linkedPolygons) {
for (Pair<String, Geometry> 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<Vertex> nodesInRange = tree.getNodesInRange(v, neighborDistance);
if (nodesInRange.isEmpty()) {
tree.add(v);
} else {
// replace other vertex with any 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<String, ConcretePolygon> polygons = new HashMap<>();
List<Pair<String, Geometry>> linkedPolygons = new ArrayList<>();
Map<Vertex, Vertex> 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<String, ConcretePolygon> polygons = new HashMap<>();
List<Pair<String, Geometry>> linkedPolygons = new ArrayList<>();
Map<Vertex, Vertex> 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<String, ConcretePolygon> polygons = new HashMap<>();
List<Pair<String, Geometry>> linkedPolygons = new ArrayList<>();
Map<Vertex, Vertex> 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<String, ConcretePolygon> polygons = new HashMap<>();
List<Pair<String, Geometry>> linkedPolygons = new ArrayList<>();
Map<Vertex, Vertex> 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<String, ConcretePolygon> polygons = new HashMap<>();
List<Pair<String, Geometry>> linkedPolygons = new ArrayList<>();
Map<Vertex, Vertex> 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<String, ConcretePolygon> polygons = new HashMap<>();
List<Pair<String, Geometry>> linkedPolygons = new ArrayList<>();
Map<Vertex, Vertex> 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<String, ConcretePolygon> polygons = new HashMap<>();
List<Pair<String, Geometry>> linkedPolygons = new ArrayList<>();
Map<Vertex, Vertex> 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<String, ConcretePolygon> polygons, List<Pair<String, Geometry>> linkedPolygons,
Map<Vertex, Vertex> 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<String, ConcretePolygon> polygons,
List<Pair<String, Geometry>> linkedPolygons, Map<Vertex, Vertex> 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<String, ConcretePolygon> polygons,
List<Pair<String, Geometry>> linkedPolygons, Map<Vertex, Vertex> 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<String, ConcretePolygon> polygons,
List<Pair<String, Geometry>> linkedPolygons, Map<Vertex, Vertex> 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<OpeningProperty> openings, BoundarySurface bs,
Map<String, ConcretePolygon> polygons, List<Pair<String, Geometry>> linkedPolygons,
Map<Vertex, Vertex> 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<String, ConcretePolygon> polygons, List<Pair<String, Geometry>> linkedPolygons,
Map<Vertex, Vertex> 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<String, ConcretePolygon> polygons,
List<Pair<String, Geometry>> linkedPolygons, Map<Vertex, Vertex> 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<String, ConcretePolygon> polygons,
List<Pair<String, Geometry>> linkedPolygons, Map<Vertex, Vertex> 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<String, ConcretePolygon> polygons, List<Pair<String, Geometry>> linkedPolygons,
Map<Vertex, Vertex> 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<String, ConcretePolygon> polygons = new HashMap<>();
List<Pair<String, Geometry>> linkedPolygons = new ArrayList<>();
Map<Vertex, Vertex> 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<String, ConcretePolygon> polygons, List<Pair<String, Geometry>> linkedPolygons,
Map<Vertex, Vertex> 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<String, ConcretePolygon> polygons, List<Pair<String, Geometry>> linkedPolygons,
Map<Vertex, Vertex> 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<String, ConcretePolygon> polygons, List<Pair<String, Geometry>> linkedPolygons,
Map<Vertex, Vertex> 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<org.citygml4j.model.citygml.bridge.OpeningProperty> openings,
BoundarySurface bs, Map<String, ConcretePolygon> polygons, List<Pair<String, Geometry>> linkedPolygons,
Map<Vertex, Vertex> 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<String, ConcretePolygon> polygons, List<Pair<String, Geometry>> linkedPolygons,
Map<Vertex, Vertex> 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);
}
}
/*-
* 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 <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.mapper;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Map;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.citygml4j.model.gml.geometry.AbstractGeometry;
import org.citygml4j.model.gml.geometry.GeometryProperty;
import org.citygml4j.model.gml.geometry.aggregates.MultiSurface;
import org.citygml4j.model.gml.geometry.aggregates.MultiSurfaceProperty;
import org.citygml4j.model.gml.geometry.complexes.CompositeSurface;
import org.citygml4j.model.gml.geometry.primitives.AbstractRing;
import org.citygml4j.model.gml.geometry.primitives.AbstractRingProperty;
import org.citygml4j.model.gml.geometry.primitives.Coord;
import org.citygml4j.model.gml.geometry.primitives.DirectPosition;
import org.citygml4j.model.gml.geometry.primitives.DirectPositionList;
import org.citygml4j.model.gml.geometry.primitives.PosOrPointPropertyOrPointRep;
import org.citygml4j.model.gml.geometry.primitives.SolidProperty;
import org.citygml4j.model.gml.geometry.primitives.SurfaceProperty;
import org.citygml4j.util.walker.GeometryWalker;
import org.locationtech.proj4j.BasicCoordinateTransform;
import org.locationtech.proj4j.ProjCoordinate;
import de.hft.stuttgart.citydoctor2.datastructure.BoundarySurface;
import de.hft.stuttgart.citydoctor2.datastructure.BuildingInstallation;
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.LinearRing;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing.LinearRingType;
import de.hft.stuttgart.citydoctor2.datastructure.Lod;
import de.hft.stuttgart.citydoctor2.datastructure.Vertex;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.utils.Localization;
import de.hft.stuttgart.citydoctor2.utils.Pair;
/**
*
* @author Matthias Betz
*
*/
public class GeometryMapper extends GeometryWalker {
private static final Logger logger = LogManager.getLogger(GeometryMapper.class);
private Geometry geom;
private ParserConfiguration config;
private Map<Vertex, Vertex> vertexMap;
private Map<String, ConcretePolygon> polygons;
private List<Pair<String, Geometry>> linkedPolygons;
private LinearRing currentRing;
private BoundarySurface bs;
private BuildingInstallation bi;
private ProjCoordinate p1 = new ProjCoordinate();
private ProjCoordinate p2 = new ProjCoordinate();
public GeometryMapper(Geometry geom, ParserConfiguration config, Map<String, ConcretePolygon> polygons,
List<Pair<String, Geometry>> linkedPolygons, Map<Vertex, Vertex> vertices) {
this.geom = geom;
this.config = config;
vertexMap = vertices;
this.polygons = polygons;
this.linkedPolygons = linkedPolygons;
}
public void setBoundarySurface(BoundarySurface bs) {
this.bs = bs;
}
public void setBuildingInstallation(BuildingInstallation bi) {
this.bi = bi;
}
@Override
public void visit(MultiSurface multiSurface) {
super.visit(multiSurface);
for (SurfaceProperty sp : multiSurface.getSurfaceMember()) {
if (sp.isSetHref()) {
String linkedPoly = sp.getHref();
if (linkedPoly.charAt(0) == '#') {
linkedPoly = linkedPoly.substring(1);
}
linkedPolygons.add(new Pair<>(linkedPoly, geom));
}
}
}
@Override
public void visit(CompositeSurface compositeSurface) {
super.visit(compositeSurface);
for (SurfaceProperty sp : compositeSurface.getSurfaceMember()) {
if (sp.isSetHref()) {
String linkedPoly = sp.getHref();
if (linkedPoly.charAt(0) == '#') {
linkedPoly = linkedPoly.substring(1);
}
linkedPolygons.add(new Pair<>(linkedPoly, geom));
}
}
}
@Override
public void visit(org.citygml4j.model.gml.geometry.primitives.Polygon gmlPoly) {
if (!gmlPoly.isSetExterior()) {
if (logger.isWarnEnabled()) {
logger.warn(Localization.getText("GeometryMapper.emptyPolygon"));
}
return;
}
ConcretePolygon cdPoly = new ConcretePolygon();
addPolygonToAvailablePolygons(gmlPoly, cdPoly);
geom.addPolygon(cdPoly);
if (bs != null) {
// polygon is part of a boundary surface
cdPoly.setPartOfSurface(bs);
if (bi != null) {
// polygon is part of a boundary surface in a building installation
cdPoly.setPartOfInstallation(bi);
}
} else {
if (bi != null) {
// polygon is only part of a building installation
cdPoly.setPartOfInstallation(bi);
}
}
// parse rings
LinearRing extRing = new LinearRing(LinearRingType.EXTERIOR);
cdPoly.setExteriorRing(extRing);
mapRing(gmlPoly.getExterior(), extRing);
if (gmlPoly.isSetInterior()) {
for (AbstractRingProperty arp : gmlPoly.getInterior()) {
if (arp.isSetRing()) {
LinearRing innerRing = new LinearRing(LinearRingType.INTERIOR);
cdPoly.addInteriorRing(innerRing);
mapRing(arp, innerRing);
}
}
}
}
private void addPolygonToAvailablePolygons(org.citygml4j.model.gml.geometry.primitives.Polygon gmlPoly,
ConcretePolygon cdPoly) {
if (gmlPoly.isSetId()) {
cdPoly.setGmlId(new GmlId(gmlPoly.getId()));
if (polygons.put(gmlPoly.getId(), cdPoly) != null) {
logger.warn("Found already existing polygon ID {}, duplicate IDs are not valid", gmlPoly.getId());
}
}
}
private void mapRing(AbstractRingProperty gmlRing, LinearRing cdRing) {
AbstractRing ringGeometry = gmlRing.getRing();
if (ringGeometry.isSetId()) {
cdRing.setGmlId(new GmlId(ringGeometry.getId()));
}
currentRing = cdRing;
// jump to LinearRing or Ring visit
ringGeometry.accept(this);
}
@Override
public void visit(org.citygml4j.model.gml.geometry.primitives.LinearRing linearRing) {
if (linearRing.isSetCoord()) {
List<Coord> coords = linearRing.getCoord();
for (Coord coord : coords) {
createVertex(coord.getX(), coord.getY(), coord.getZ());
}
}
if (linearRing.isSetPosList()) {
parsePosList(linearRing);
}
if (linearRing.isSetPosOrPointPropertyOrPointRep()) {
parsePoints(linearRing);
}
}
private void parsePoints(org.citygml4j.model.gml.geometry.primitives.LinearRing linearRing) {
List<PosOrPointPropertyOrPointRep> points = linearRing.getPosOrPointPropertyOrPointRep();
for (PosOrPointPropertyOrPointRep point : points) {
if (!point.isSetPos()) {
throw new UnsupportedOperationException("Cannot parse points for: " + linearRing.getId());
}
DirectPosition pos = point.getPos();
List<Double> coords = pos.getValue();
int dimension = getDimension(linearRing, pos, coords);
switch (dimension) {
case 1:
createVertex(coords.get(0), 0, 0);
break;
case 2:
createVertex(coords.get(0), coords.get(1), 0);
break;
case 3:
createVertex(coords.get(0), coords.get(1), coords.get(2));
break;
default:
throw new UnsupportedOperationException("Cannot parse Coordinates with dimension:" + dimension);
}
}
}
private void parsePosList(org.citygml4j.model.gml.geometry.primitives.LinearRing linearRing) {
DirectPositionList directPosList = linearRing.getPosList();
if (directPosList.isSetValue()) {
List<Double> coords = directPosList.getValue();
int dimension = getDimension(linearRing, directPosList, coords);
switch (dimension) {
case 1:
for (int i = 0; i < coords.size(); i++) {
createVertex(coords.get(i), 0, 0);
}
break;
case 2:
for (int i = 0; i < coords.size(); i = i + 2) {
createVertex(coords.get(i + 0), coords.get(i + 1), 0);
}
break;
case 3:
for (int i = 0; i < coords.size(); i = i + 3) {
createVertex(coords.get(i + 0), coords.get(i + 1), coords.get(i + 2));
}
break;
default:
throw new UnsupportedOperationException("Cannot parse Coordinates with dimension:" + dimension);
}
}
}
private int getDimension(org.citygml4j.model.gml.geometry.primitives.LinearRing linearRing, DirectPosition pos,
List<Double> coords) {
int dimension = 3;
if (pos.isSetSrsDimension()) {
dimension = pos.getSrsDimension();
}
if (coords.size() % dimension != 0) {
throw new IllegalStateException("Number of coordinates do not match dimension: " + dimension + ", ring: "
+ linearRing.getId() + ", polygon: " + currentRing.getParent().getGmlId().getGmlString());
}
return dimension;
}
private int getDimension(org.citygml4j.model.gml.geometry.primitives.LinearRing linearRing,
DirectPositionList directPosList, List<Double> coords) {
int dimension = 3;
if (directPosList.isSetSrsDimension()) {
dimension = directPosList.getSrsDimension();
}
if (coords.size() % dimension != 0) {
throw new IllegalStateException("Number of coordinates do not match dimension: " + dimension + ", ring: "
+ linearRing.getId() + ", polygon: " + currentRing.getParent().getGmlId().getGmlString());
}
return dimension;
}
private void createVertex(double x, double y, double z) {
// transform into utm, if available
BasicCoordinateTransform trans = config.getTargetTransform();
if (trans != null) {
p1.setValue(x, y);
trans.transform(p1, p2);
x = p2.x;
y = p2.y;
z = z / config.getFromMetres();
}
x = round(x, config.getNumberOfRoundingPlaces());
y = round(y, config.getNumberOfRoundingPlaces());
z = round(z, config.getNumberOfRoundingPlaces());
Vertex v = new Vertex(x, y, z);
Vertex duplicate = vertexMap.get(v);
if (duplicate == null) {
vertexMap.put(v, v);
} else {
v = duplicate;
}
currentRing.addVertex(v);
}
private double round(double value, int places) {
if (places < 0) {
throw new IllegalArgumentException();
}
BigDecimal bd = BigDecimal.valueOf(value);
bd = bd.setScale(places, RoundingMode.HALF_UP);
return bd.doubleValue();
}
private static GeometryMapper parseGeometry(AbstractGeometry gmlG, Geometry geom, CityObject co,
ParserConfiguration config, Map<String, ConcretePolygon> polygons,
List<Pair<String, Geometry>> linkedPolygons, Map<Vertex, Vertex> vertexMap) {
if (gmlG.isSetId()) {
geom.setGmlId(new GmlId(gmlG.getId()));
}
co.addGeometry(geom);
GeometryMapper geomMapper = new GeometryMapper(geom, config, polygons, linkedPolygons, vertexMap);
gmlG.accept(geomMapper);
return geomMapper;
}
private static void parseIntoGeometry(AbstractGeometry geometry, GeometryMapper geomMapper, BoundarySurface bs,
BuildingInstallation coBi) {
geomMapper.setBoundarySurface(bs);
geomMapper.setBuildingInstallation(coBi);
geometry.accept(geomMapper);
}
public static void mapLod0MultiSurface(MultiSurfaceProperty lod0ms, CityObject co, ParserConfiguration config,
Map<String, ConcretePolygon> polygons, List<Pair<String, Geometry>> linkedPolygons,
Map<Vertex, Vertex> vertexMap) {
if (lod0ms == null || !lod0ms.isSetMultiSurface()) {
return;
}
Geometry geom = new Geometry(GeometryType.MULTI_SURFACE, Lod.LOD0);
parseGeometry(lod0ms.getMultiSurface(), geom, co, config, polygons, linkedPolygons, vertexMap);
}
public static GeometryMapper mapLod1MultiSurface(MultiSurfaceProperty lod1ms, CityObject co,
ParserConfiguration config, Map<String, ConcretePolygon> polygons,
List<Pair<String, Geometry>> linkedPolygons, Map<Vertex, Vertex> vertexMap) {
if (lod1ms == null || !lod1ms.isSetMultiSurface()) {
return null;
}
Geometry geom = new Geometry(GeometryType.MULTI_SURFACE, Lod.LOD1);
return parseGeometry(lod1ms.getMultiSurface(), geom, co, config, polygons, linkedPolygons, vertexMap);
}
public static GeometryMapper mapLod2MultiSurface(MultiSurfaceProperty lod2MultiSurface, CityObject co,
ParserConfiguration config, Map<String, ConcretePolygon> polygons,
List<Pair<String, Geometry>> linkedPolygons, Map<Vertex, Vertex> vertexMap) {
if (lod2MultiSurface == null || !lod2MultiSurface.isSetMultiSurface()) {
return null;
}
Geometry geom = new Geometry(GeometryType.MULTI_SURFACE, Lod.LOD2);
return parseGeometry(lod2MultiSurface.getMultiSurface(), geom, co, config, polygons, linkedPolygons, vertexMap);
}
public static GeometryMapper mapLod3MultiSurface(MultiSurfaceProperty lod3MultiSurface, CityObject co,
ParserConfiguration config, Map<String, ConcretePolygon> polygons,
List<Pair<String, Geometry>> linkedPolygons, Map<Vertex, Vertex> vertexMap) {
if (lod3MultiSurface == null || !lod3MultiSurface.isSetMultiSurface()) {
return null;
}
Geometry geom = new Geometry(GeometryType.MULTI_SURFACE, Lod.LOD3);
return parseGeometry(lod3MultiSurface.getMultiSurface(), geom, co, config, polygons, linkedPolygons, vertexMap);
}
public static GeometryMapper mapLod4MultiSurface(MultiSurfaceProperty lod4MultiSurface, CityObject co,
ParserConfiguration config, Map<String, ConcretePolygon> polygons,
List<Pair<String, Geometry>> linkedPolygons, Map<Vertex, Vertex> vertexMap) {
if (lod4MultiSurface == null || !lod4MultiSurface.isSetMultiSurface()) {
return null;
}
Geometry geom = new Geometry(GeometryType.MULTI_SURFACE, Lod.LOD4);
return parseGeometry(lod4MultiSurface.getMultiSurface(), geom, co, config, polygons, linkedPolygons, vertexMap);
}
public static GeometryMapper mapLod1Solid(SolidProperty lod1Solid, CityObject co, ParserConfiguration config,
Map<String, ConcretePolygon> polygons, List<Pair<String, Geometry>> linkedPolygons,
Map<Vertex, Vertex> vertexMap) {
if (lod1Solid == null || !lod1Solid.isSetSolid()) {
return null;
}
Geometry geom = new Geometry(GeometryType.SOLID, Lod.LOD1);
return parseGeometry(lod1Solid.getSolid(), geom, co, config, polygons, linkedPolygons, vertexMap);
}
public static GeometryMapper mapLod2Solid(SolidProperty lod2Solid, CityObject co, ParserConfiguration config,
Map<String, ConcretePolygon> polygons, List<Pair<String, Geometry>> linkedPolygons,
Map<Vertex, Vertex> vertexMap) {
if (lod2Solid == null || !lod2Solid.isSetSolid()) {
return null;
}
Geometry geom = new Geometry(GeometryType.SOLID, Lod.LOD2);
return parseGeometry(lod2Solid.getSolid(), geom, co, config, polygons, linkedPolygons, vertexMap);
}
public static GeometryMapper mapLod3Solid(SolidProperty lod3Solid, CityObject co, ParserConfiguration config,
Map<String, ConcretePolygon> polygons, List<Pair<String, Geometry>> linkedPolygons,
Map<Vertex, Vertex> vertexMap) {
if (lod3Solid == null || !lod3Solid.isSetSolid()) {
return null;
}
Geometry geom = new Geometry(GeometryType.SOLID, Lod.LOD3);
return parseGeometry(lod3Solid.getSolid(), geom, co, config, polygons, linkedPolygons, vertexMap);
}
public static GeometryMapper mapLod4Solid(SolidProperty lod4Solid, CityObject co, ParserConfiguration config,
Map<String, ConcretePolygon> polygons, List<Pair<String, Geometry>> linkedPolygons,
Map<Vertex, Vertex> vertexMap) {
if (lod4Solid == null || !lod4Solid.isSetSolid()) {
return null;
}
Geometry geom = new Geometry(GeometryType.SOLID, Lod.LOD4);
return parseGeometry(lod4Solid.getSolid(), geom, co, config, polygons, linkedPolygons, vertexMap);
}
public static void mapLod1Geometry(GeometryProperty<? extends AbstractGeometry> lod1Geometry, CityObject co,
ParserConfiguration config, Map<String, ConcretePolygon> polygons,
List<Pair<String, Geometry>> linkedPolygons, Map<Vertex, Vertex> vertexMap) {
if (lod1Geometry == null || !lod1Geometry.isSetGeometry()) {
return;
}
Geometry geom = new Geometry(GeometryType.MULTI_SURFACE, Lod.LOD1);
parseGeometry(lod1Geometry.getGeometry(), geom, co, config, polygons, linkedPolygons, vertexMap);
}
public static void mapLod2Geometry(GeometryProperty<? extends AbstractGeometry> lod2Geometry, CityObject co,
ParserConfiguration config, Map<String, ConcretePolygon> polygons,
List<Pair<String, Geometry>> linkedPolygons, Map<Vertex, Vertex> vertexMap) {
if (lod2Geometry == null || !lod2Geometry.isSetGeometry()) {
return;
}
Geometry geom = new Geometry(GeometryType.MULTI_SURFACE, Lod.LOD2);
parseGeometry(lod2Geometry.getGeometry(), geom, co, config, polygons, linkedPolygons, vertexMap);
}
public static void mapLod3Geometry(GeometryProperty<? extends AbstractGeometry> lod3Geometry, CityObject co,
ParserConfiguration config, Map<String, ConcretePolygon> polygons,
List<Pair<String, Geometry>> linkedPolygons, Map<Vertex, Vertex> vertexMap) {
if (lod3Geometry == null || !lod3Geometry.isSetGeometry()) {
return;
}
Geometry geom = new Geometry(GeometryType.MULTI_SURFACE, Lod.LOD3);
parseGeometry(lod3Geometry.getGeometry(), geom, co, config, polygons, linkedPolygons, vertexMap);
}
public static void mapLod4Geometry(GeometryProperty<? extends AbstractGeometry> lod4Geometry, CityObject co,
ParserConfiguration config, Map<String, ConcretePolygon> polygons,
List<Pair<String, Geometry>> linkedPolygons, Map<Vertex, Vertex> vertexMap) {
if (lod4Geometry == null || !lod4Geometry.isSetGeometry()) {
return;
}
Geometry geom = new Geometry(GeometryType.MULTI_SURFACE, Lod.LOD4);
parseGeometry(lod4Geometry.getGeometry(), geom, co, config, polygons, linkedPolygons, vertexMap);
}
public static void mapBoundarySurfaceIntoGeometry(MultiSurfaceProperty msp, GeometryMapper geom, BoundarySurface bs,
BuildingInstallation coBi) {
if (msp == null || !msp.isSetGeometry()) {
return;
}
parseIntoGeometry(msp.getGeometry(), geom, bs, coBi);
}
public static void mapBuildingInstallationIntoGeometry(GeometryProperty<? extends AbstractGeometry> gp,
GeometryMapper geom, BuildingInstallation coBi) {
if (gp == null || !gp.isSetGeometry()) {
return;
}
parseIntoGeometry(gp.getGeometry(), geom, null, coBi);
}
public Geometry getGeometry() {
return geom;
}
}
/*-
* 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 <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.mapper.citygml3;
import java.nio.file.Path;
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.core.model.CityGMLVersion;
import org.citygml4j.core.model.bridge.AbstractBridge;
import org.citygml4j.core.model.bridge.Bridge;
import org.citygml4j.core.model.bridge.BridgePart;
import org.citygml4j.core.model.bridge.BridgePartProperty;
import org.citygml4j.core.model.building.BuildingInstallationProperty;
import org.citygml4j.core.model.building.BuildingPartProperty;
import org.citygml4j.core.model.construction.AbstractConstruction;
import org.citygml4j.core.model.core.AbstractCityObject;
import org.citygml4j.core.model.core.AbstractFeatureWithLifespan;
import org.citygml4j.core.model.core.AbstractOccupiedSpace;
import org.citygml4j.core.model.core.AbstractPhysicalSpace;
import org.citygml4j.core.model.core.AbstractSpace;
import org.citygml4j.core.model.core.AbstractSpaceBoundary;
import org.citygml4j.core.model.core.AbstractSpaceBoundaryProperty;
import org.citygml4j.core.model.core.AbstractThematicSurface;
import org.citygml4j.core.model.core.AbstractUnoccupiedSpace;
import org.citygml4j.core.model.core.CityModel;
import org.citygml4j.core.model.deprecated.transportation.TransportationComplex;
import org.citygml4j.core.model.landuse.LandUse;
import org.citygml4j.core.model.transportation.AbstractTransportationSpace;
import org.citygml4j.core.model.transportation.AuxiliaryTrafficArea;
import org.citygml4j.core.model.transportation.AuxiliaryTrafficSpace;
import org.citygml4j.core.model.transportation.AuxiliaryTrafficSpaceProperty;
import org.citygml4j.core.model.transportation.Railway;
import org.citygml4j.core.model.transportation.Road;
import org.citygml4j.core.model.transportation.Square;
import org.citygml4j.core.model.transportation.Track;
import org.citygml4j.core.model.transportation.TrafficArea;
import org.citygml4j.core.model.transportation.TrafficSpace;
import org.citygml4j.core.model.transportation.TrafficSpaceProperty;
import org.citygml4j.core.model.vegetation.AbstractVegetationObject;
import org.citygml4j.core.model.vegetation.PlantCover;
import org.citygml4j.core.model.waterbody.WaterBody;
import org.citygml4j.core.visitor.ObjectWalker;
import org.xmlobjects.gml.model.base.AbstractGML;
import org.xmlobjects.gml.model.feature.AbstractFeature;
import org.xmlobjects.gml.model.geometry.AbstractGeometry;
import org.xmlobjects.gml.model.geometry.GeometryProperty;
import org.xmlobjects.gml.model.geometry.aggregates.MultiSurface;
import org.xmlobjects.gml.model.geometry.aggregates.MultiSurfaceProperty;
import org.xmlobjects.gml.model.geometry.primitives.AbstractSolid;
import org.xmlobjects.gml.model.geometry.primitives.AbstractSurface;
import org.xmlobjects.gml.model.geometry.primitives.Shell;
import org.xmlobjects.gml.model.geometry.primitives.ShellProperty;
import org.xmlobjects.gml.model.geometry.primitives.Solid;
import org.xmlobjects.gml.model.geometry.primitives.SolidProperty;
import org.xmlobjects.gml.model.geometry.primitives.SurfaceProperty;
import de.hft.stuttgart.citydoctor2.datastructure.AbstractBuilding;
import de.hft.stuttgart.citydoctor2.datastructure.BoundarySurface;
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.GmlElement;
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.Polygon;
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;
public class Citygml3FeatureMapper extends ObjectWalker {
private static final Logger logger = LogManager.getLogger(Citygml3FeatureMapper.class);
private CityDoctorModel model;
private Map<String, ConcretePolygon> polygonMap = new HashMap<>();
private List<ResolvableReference> references = new ArrayList<>();
private Map<Vertex, Vertex> vertexMap = new HashMap<>();
private ParserConfiguration config;
private double neighborDistance;
public Citygml3FeatureMapper(ParserConfiguration config, Path path) {
this.config = config;
model = new CityDoctorModel(config, path.toFile());
neighborDistance = 1.8d / Math.pow(10, config.getNumberOfRoundingPlaces());
}
@Override
public void visit(AbstractSpace space) {
// if we are here, an AbstractSpace thing was read that is not handled in the
// other methods
}
@Override
public void visit(org.citygml4j.core.model.building.Building gmlBuilding) {
Building cdBuilding = new Building();
readAbstractBuilding(gmlBuilding, cdBuilding);
for (BuildingPartProperty bpProp : gmlBuilding.getBuildingParts()) {
if (!bpProp.isSetObject()) {
continue;
}
BuildingPart part = new BuildingPart(cdBuilding);
readAbstractBuilding(bpProp.getObject(), part);
cdBuilding.addBuildingPart(part);
}
model.addBuilding(cdBuilding);
}
@Override
public void visit(WaterBody waterBody) {
WaterObject wo = new WaterObject();
wo.setGmlObject(waterBody);
mapAbstractOccupiedSpace(waterBody, wo);
parseAndAddMultiSurface(waterBody.getDeprecatedProperties().getLod1MultiSurface(), Lod.LOD1, wo);
parseAndAddSolid(waterBody.getDeprecatedProperties().getLod4Solid(), Lod.LOD4, wo);
SurfaceMapper surfaceMapper = new SurfaceMapper(polygonMap, references, vertexMap, config);
for (AbstractSpaceBoundaryProperty surfaceProp : waterBody.getBoundaries()) {
if (!surfaceProp.isSetObject()) {
continue;
}
AbstractSpaceBoundary surface = surfaceProp.getObject();
surface.accept(surfaceMapper);
}
for (BoundarySurface bs : surfaceMapper.getSurfaces()) {
wo.addBoundarySurface(bs);
}
resolveAndClearReferences();
wo.unsetGmlGeometries();
updateEdgesAndVertices(wo);
for (BoundarySurface bs : surfaceMapper.getSurfaces()) {
updateEdgesAndVertices(bs);
}
model.addWater(wo);
}
@Override
public void visit(LandUse landUse) {
LandObject lo = new LandObject(landUse);
mapAbstractThematicSurface(landUse, lo);
finishCityObjectConstruction(lo);
model.addLand(lo);
}
@Override
public void visit(PlantCover plantCover) {
Vegetation veg = new Vegetation(VegetationType.PLANT_COVER);
veg.setGmlObject(plantCover);
mapAbstractVegetationObject(plantCover, veg);
parseAndAddMultiSurface(plantCover.getDeprecatedProperties().getLod1MultiSurface(), Lod.LOD1, veg);
parseAndAddMultiSurface(plantCover.getDeprecatedProperties().getLod4MultiSurface(), Lod.LOD4, veg);
finishCityObjectConstruction(veg);
model.addVegetation(veg);
}
private void mapAbstractVegetationObject(AbstractVegetationObject avo, Vegetation veg) {
mapAbstractOccupiedSpace(avo, veg);
}
private void mapAbstractOccupiedSpace(AbstractOccupiedSpace aos, CityObject co) {
mapAbstractPhysicalSpace(aos, co);
}
private void mapAbstractPhysicalSpace(AbstractPhysicalSpace aps, CityObject co) {
mapAbstractSpace(aps, co);
}
private void mapAbstractSpace(AbstractSpace as, CityObject co) {
mapAbstractFeature(as, co);
parseAndAddMultiSurface(as.getLod0MultiSurface(), Lod.LOD0, co);
parseAndAddMultiSurface(as.getLod2MultiSurface(), Lod.LOD2, co);
parseAndAddMultiSurface(as.getLod3MultiSurface(), Lod.LOD3, co);
parseAndAddSolid(as.getLod1Solid(), Lod.LOD1, co);
parseAndAddSolid(as.getLod2Solid(), Lod.LOD2, co);
parseAndAddSolid(as.getLod3Solid(), Lod.LOD3, co);
}
@Override
public void visit(Bridge bridge) {
BridgeObject bo = new BridgeObject(BridgeType.BRIDGE, bridge);
for (BridgePartProperty bPartProperty : bridge.getBridgeParts()) {
if (!bPartProperty.isSetObject()) {
continue;
}
BridgePart gmlBridgePart = bPartProperty.getObject();
BridgeObject bPart = new BridgeObject(BridgeType.BRIDGE_PART, gmlBridgePart);
mapAbstractBridge(gmlBridgePart, bPart);
bo.addBridgePart(bPart);
}
mapAbstractBridge(bridge, bo);
resolveAndClearReferences();
updateEdgesAndVertices(bo);
for (BridgeObject part : bo.getParts()) {
updateEdgesAndVertices(part);
}
model.addBridge(bo);
}
private void mapAbstractBridge(AbstractBridge ab, BridgeObject bo) {
mapAbstractConstruction(ab, bo);
bo.unsetGmlGeometries();
}
private void mapAbstractConstruction(AbstractConstruction ac, BridgeObject bo) {
mapAbstractOccupiedSpace(ac, bo);
}
@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);
}
private void mapAbstractThematicSurface(AbstractThematicSurface ats, CityObject co) {
mapAbstractSpaceBoundary(ats, co);
parseAndAddMultiSurface(ats.getLod0MultiSurface(), Lod.LOD0, co);
parseAndAddMultiSurface(ats.getLod1MultiSurface(), Lod.LOD1, co);
parseAndAddMultiSurface(ats.getLod2MultiSurface(), Lod.LOD2, co);
parseAndAddMultiSurface(ats.getLod3MultiSurface(), Lod.LOD3, co);
parseAndAddMultiSurface(ats.getDeprecatedProperties().getLod4MultiSurface(), Lod.LOD4, co);
}
private void mapAbstractSpaceBoundary(AbstractSpaceBoundary asb, CityObject co) {
mapAbstractCityObject(asb, co);
}
private void mapAbstractCityObject(AbstractCityObject aco, CityObject to) {
mapAbstractFeatureWithLifespan(aco, to);
}
private void mapAbstractFeatureWithLifespan(AbstractFeatureWithLifespan afwl, CityObject to) {
mapAbstractFeature(afwl, to);
}
private void mapAbstractFeature(AbstractFeature af, CityObject to) {
mapAbstractGML(af, to);
}
private void mapAbstractGML(AbstractGML ag, CityObject to) {
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);
model.addTransportation(to);
}
private void finishCityObjectConstruction(CityObject co) {
co.unsetGmlGeometries();
resolveAndClearReferences();
updateEdgesAndVertices(co);
}
private void mapAbstractTransportationSpace(AbstractTransportationSpace ats, TransportationObject to) {
to.setGmlObject(ats);
parseAbstractTransportationSpaceGeometries(ats, to);
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);
}
}
for (AuxiliaryTrafficSpaceProperty auxTrafficProp : ats.getAuxiliaryTrafficSpaces()) {
if (auxTrafficProp.isSetObject()) {
TransportationObject trafficSpace = parseAuxiliaryTrafficSpace(auxTrafficProp.getObject());
finishTransportationMapping(trafficSpace);
to.addChild(trafficSpace);
}
}
}
private void mapTrafficSpace(TrafficSpace ts, TransportationObject to) {
mapAbstractUnoccupiedSpace(ts, to);
}
private void mapAbstractUnoccupiedSpace(AbstractUnoccupiedSpace aus, TransportationObject to) {
mapAbstractPhysicalSpace(aus, to);
}
private TransportationObject parseAuxiliaryTrafficSpace(AuxiliaryTrafficSpace ats) {
TransportationObject to = new TransportationObject(TransportationType.AUXILLIARY_TRAFFIC_SPACE);
parseAbstractSpaceGeometries(ats, to);
finishCityObjectConstruction(to);
return to;
}
private void parseAbstractTransportationSpaceGeometries(AbstractTransportationSpace space, CityObject co) {
parseAndAddMultiSurface(space.getDeprecatedProperties().getLod1MultiSurface(), Lod.LOD1, co);
parseAndAddMultiSurface(space.getDeprecatedProperties().getLod4MultiSurface(), Lod.LOD4, co);
}
private void parseAbstractSpaceGeometries(AbstractSpace as, CityObject co) {
parseAndAddMultiSurface(as.getLod0MultiSurface(), Lod.LOD0, co);
parseAndAddMultiSurface(as.getLod2MultiSurface(), Lod.LOD2, co);
parseAndAddMultiSurface(as.getLod3MultiSurface(), Lod.LOD3, co);
parseAndAddSolid(as.getLod1Solid(), Lod.LOD1, co);
parseAndAddSolid(as.getLod2Solid(), Lod.LOD2, co);
parseAndAddSolid(as.getLod3Solid(), Lod.LOD3, co);
}
private void parseAndAddMultiSurface(MultiSurfaceProperty msp, Lod lod, CityObject co) {
if (msp == null || msp.getObject() == null) {
return;
}
Geometry geom = parseMultiSurface(msp.getObject(), lod);
co.addGeometry(geom);
}
private void parseAndAddSolid(SolidProperty sp, Lod lod, CityObject co) {
if (sp == null || sp.getObject() == null) {
return;
}
Geometry geom = parseSolid(sp.getObject(), lod);
if (geom != null) {
co.addGeometry(geom);
}
}
private void resolveAndClearReferences() {
for (ResolvableReference ref : references) {
String href = ref.href();
if (href.startsWith("#")) {
href = href.substring(1);
}
Geometry geom = ref.geometry();
ConcretePolygon concPoly = polygonMap.get(href);
if (concPoly == null) {
if (logger.isWarnEnabled()) {
logger.warn(Localization.getText("FeatureMapper.polygonUnreferenced"), href);
}
continue;
}
LinkedPolygon lPoly = new LinkedPolygon(concPoly, geom);
if (geom.getParent() instanceof BoundarySurface bs) {
lPoly.setPartOfSurface(bs);
if (bs.getParent() instanceof BuildingInstallation bi) {
lPoly.setPartOfInstallation(bi);
}
}
geom.addPolygon(lPoly);
}
// clear storage for polygons and vertices
// probably faster than .clear() ?
references = new ArrayList<>();
vertexMap = new HashMap<>();
polygonMap = new HashMap<>();
}
private void readAbstractBuilding(org.citygml4j.core.model.building.AbstractBuilding gmlAb,
AbstractBuilding cdBuilding) {
mapAbstractOccupiedSpace(gmlAb, cdBuilding);
cdBuilding.setGmlObject(gmlAb);
// parse deprecated geometries
parseAndAddMultiSurface(gmlAb.getDeprecatedProperties().getLod1MultiSurface(), Lod.LOD1, cdBuilding);
parseAndAddMultiSurface(gmlAb.getDeprecatedProperties().getLod4MultiSurface(), Lod.LOD4, cdBuilding);
parseAndAddSolid(gmlAb.getDeprecatedProperties().getLod4Solid(), Lod.LOD4, cdBuilding);
for (BuildingInstallationProperty biProp : gmlAb.getBuildingInstallations()) {
var gmlBi = biProp.getObject();
if (gmlBi == null) {
// ignore empty properties
continue;
}
BuildingInstallation bi = mapBuildingInstallation(gmlBi);
cdBuilding.addBuildingInstallation(bi);
}
SurfaceMapper surfaceMapper = new SurfaceMapper(polygonMap, references, vertexMap, config);
for (AbstractSpaceBoundaryProperty surfaceProp : gmlAb.getBoundaries()) {
if (!surfaceProp.isSetObject()) {
continue;
}
AbstractSpaceBoundary surface = surfaceProp.getObject();
surface.accept(surfaceMapper);
}
for (BoundarySurface bs : surfaceMapper.getSurfaces()) {
cdBuilding.addBoundarySurface(bs);
for (Geometry geom : bs.getGeometries()) {
for (Polygon p : geom.getPolygons()) {
p.setPartOfSurface(bs);
}
}
}
cdBuilding.unsetGmlGeometries();
resolveAndClearReferences();
updateEdgesAndVertices(cdBuilding);
for (BoundarySurface bs : surfaceMapper.getSurfaces()) {
updateEdgesAndVertices(bs);
}
for (BuildingInstallation bi : cdBuilding.getBuildingInstallations()) {
updateEdgesAndVertices(bi);
for (BoundarySurface bs : bi.getBoundarySurfaces()) {
updateEdgesAndVertices(bs);
}
}
}
public static void parseId(AbstractGML gml, GmlElement gmlElement) {
String id = gml.getId();
if (id != null) {
gmlElement.setGmlId(new GmlId(id));
}
}
private BuildingInstallation mapBuildingInstallation(org.citygml4j.core.model.building.BuildingInstallation gmlBi) {
BuildingInstallation bi = new BuildingInstallation();
bi.setGmlObject(gmlBi);
mapAbstractOccupiedSpace(gmlBi, bi);
GeometryProperty<?> lod2Prop = gmlBi.getDeprecatedProperties().getLod2Geometry();
parseAndAddAbstractGeometry(lod2Prop, Lod.LOD2, bi);
GeometryProperty<?> lod3Prop = gmlBi.getDeprecatedProperties().getLod3Geometry();
parseAndAddAbstractGeometry(lod3Prop, Lod.LOD3, bi);
GeometryProperty<?> lod4Prop = gmlBi.getDeprecatedProperties().getLod4Geometry();
parseAndAddAbstractGeometry(lod4Prop, Lod.LOD4, bi);
bi.unsetGmlGeometries();
SurfaceMapper surfaceMapper = new SurfaceMapper(polygonMap, references, vertexMap, config);
for (AbstractSpaceBoundaryProperty surfaceProp : gmlBi.getBoundaries()) {
if (!surfaceProp.isSetObject()) {
continue;
}
AbstractSpaceBoundary surface = surfaceProp.getObject();
surface.accept(surfaceMapper);
}
for (BoundarySurface bs : surfaceMapper.getSurfaces()) {
bi.addBoundarySurface(bs);
for (Geometry geom : bs.getGeometries()) {
for (Polygon p : geom.getPolygons()) {
p.setPartOfSurface(bs);
p.setPartOfInstallation(bi);
}
}
}
for (Geometry geom : bi.getGeometries()) {
for (Polygon p : geom.getPolygons()) {
p.setPartOfInstallation(bi);
}
}
return bi;
}
private void parseAndAddAbstractGeometry(GeometryProperty<?> geomProp, Lod lod, CityObject co) {
if (geomProp == null || geomProp.getObject() == null) {
return;
}
AbstractGeometry abstractGeometry = geomProp.getObject();
if (abstractGeometry instanceof MultiSurface ms) {
Geometry geom = parseMultiSurface(ms, lod);
co.addGeometry(geom);
} else if (abstractGeometry instanceof Solid solid) {
Geometry geom = parseSolid(solid, lod);
if (geom != null) {
co.addGeometry(geom);
}
} else {
logger.warn("Cannot handle geometry type {}, ignoring", abstractGeometry.getClass().getSimpleName());
}
}
private Geometry parseSolid(AbstractSolid abstractSolid, Lod lod) {
if (abstractSolid instanceof Solid s) {
return handleSolidGeometry(s, lod);
} else {
logger.warn("Cannot handle solid class {}, can only process pure solids",
abstractSolid.getClass().getSimpleName());
return null;
}
}
private Geometry handleSolidGeometry(Solid solid, Lod lod) {
ShellProperty exteriorProperty = solid.getExterior();
if (exteriorProperty == null || exteriorProperty.getObject() == null) {
logger.warn("Found solid {} without exterior hull, ignoring", solid.getId());
return null;
}
Geometry geom = new Geometry(GeometryType.SOLID, lod);
Shell exterior = solid.getExterior().getObject();
Citygml3GeometryMapper geometryMapper = new Citygml3GeometryMapper(config, vertexMap);
readSurfaceMember(geom, geometryMapper, exterior.getSurfaceMembers());
return geom;
}
private Geometry parseMultiSurface(MultiSurface ms, Lod lod) {
Geometry geom = new Geometry(GeometryType.MULTI_SURFACE, lod);
Citygml3GeometryMapper geometryMapper = new Citygml3GeometryMapper(config, vertexMap);
readSurfaceMember(geom, geometryMapper, ms.getSurfaceMember());
return geom;
}
private void readSurfaceMember(Geometry geom, Citygml3GeometryMapper geometryMapper,
List<SurfaceProperty> surfaceMember) {
for (SurfaceProperty prop : surfaceMember) {
if (prop.getHref() != null) {
references.add(new ResolvableReference(prop.getHref(), geom));
continue;
}
if (prop.getObject() != null) {
AbstractSurface as = prop.getObject();
as.accept(geometryMapper);
}
}
List<ConcretePolygon> polygons = geometryMapper.getPolygons();
for (ConcretePolygon concretePoly : polygons) {
geom.addPolygon(concretePoly);
if (concretePoly.hasExistingGmlId()) {
polygonMap.put(concretePoly.getGmlId().getGmlString(), concretePoly);
}
}
}
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<Vertex> nodesInRange = tree.getNodesInRange(v, neighborDistance);
if (nodesInRange.isEmpty()) {
tree.add(v);
} else {
// replace other vertex with any neighboring one
Vertex original = nodesInRange.get(0);
lr.setVertex(i, original);
}
}
}
public void setCityModel(CityModel cModel) {
model.setCityModel(cModel);
}
public CityDoctorModel getModel() {
return model;
}
public void setCityGMLVersion(CityGMLVersion cityGMLVersion) {
model.setParsedCityGMLVersion(cityGMLVersion);
}
}
/*-
* 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 <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.mapper.citygml3;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.locationtech.proj4j.BasicCoordinateTransform;
import org.locationtech.proj4j.ProjCoordinate;
import org.xmlobjects.gml.model.geometry.primitives.AbstractRing;
import org.xmlobjects.gml.model.geometry.primitives.AbstractRingProperty;
import org.xmlobjects.gml.model.geometry.primitives.Polygon;
import org.xmlobjects.gml.model.geometry.primitives.Ring;
import org.xmlobjects.gml.visitor.GeometryWalker;
import de.hft.stuttgart.citydoctor2.datastructure.ConcretePolygon;
import de.hft.stuttgart.citydoctor2.datastructure.GmlId;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing.LinearRingType;
import de.hft.stuttgart.citydoctor2.datastructure.Vertex;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.utils.Localization;
public class Citygml3GeometryMapper extends GeometryWalker {
private static final Logger logger = LogManager.getLogger(Citygml3GeometryMapper.class);
private List<ConcretePolygon> polygons = new ArrayList<>();
private LinearRing currentRing = null;
private ParserConfiguration config;
private ProjCoordinate p1 = new ProjCoordinate();
private ProjCoordinate p2 = new ProjCoordinate();
private Map<Vertex, Vertex> vertexMap;
public Citygml3GeometryMapper(ParserConfiguration config, Map<Vertex, Vertex> vertices) {
this.config = config;
this.vertexMap = vertices;
}
@Override
public void visit(Polygon polygon) {
parsePolygon(polygon.getId(), polygon.getExterior(), polygon.getInterior());
if (polygon.getExterior() == null) {
System.out.println("No exterior: " + polygon.getId());
}
}
private void parsePolygon(String id, AbstractRingProperty exterior, List<AbstractRingProperty> interior) {
if (exterior == null || exterior.getObject() == null) {
if (logger.isWarnEnabled()) {
logger.warn(Localization.getText("GeometryMapper.emptyPolygon"));
}
return;
}
ConcretePolygon cdPoly = new ConcretePolygon();
polygons.add(cdPoly);
if (id != null) {
cdPoly.setGmlId(new GmlId(id));
}
currentRing = new LinearRing(LinearRingType.EXTERIOR);
exterior.getObject().accept(this);
cdPoly.setExteriorRing(currentRing);
for (AbstractRingProperty interiorGmlRing : interior) {
AbstractRing gmlRing = interiorGmlRing.getObject();
if (gmlRing == null) {
continue;
}
currentRing = new LinearRing(LinearRingType.INTERIOR);
gmlRing.accept(this);
cdPoly.addInteriorRing(currentRing);
}
}
@Override
public void visit(org.xmlobjects.gml.model.geometry.primitives.LinearRing gmlRing) {
if (gmlRing.getSrsDimension() != null && gmlRing.getSrsDimension() != 3) {
logger.warn("Cannot handle geometry with srsDimension not 3");
return;
}
if (gmlRing.getId() != null) {
currentRing.setGmlId(new GmlId(gmlRing.getId()));
}
List<Double> coordinates = gmlRing.toCoordinateList3D();
handleCoordinateList(coordinates);
}
@Override
public void visit(Ring ring) {
if (ring.getSrsDimension() != null && ring.getSrsDimension() != 3) {
logger.warn("Cannot handle geometry with srsDimension not 3");
return;
}
if (ring.getId() != null) {
currentRing.setGmlId(new GmlId(ring.getId()));
}
List<Double> coordinates = ring.toCoordinateList3D();
handleCoordinateList(coordinates);
}
private void handleCoordinateList(List<Double> coordinates) {
if (coordinates.size() % 3 != 0) {
String id;
if (currentRing.hasExistingGmlId()) {
id = currentRing.getGmlId().getGmlString();
} else {
id = "";
}
logger.warn("The number of coordinates for linear ring {} do not result in fully 3D points", id);
}
for (int i = 0; i < coordinates.size(); i = i + 3) {
double x = coordinates.get(i + 0);
double y = coordinates.get(i + 1);
double z = coordinates.get(i + 2);
createVertex(x, y, z);
}
}
private void createVertex(double x, double y, double z) {
// transform into utm, if available
BasicCoordinateTransform trans = config.getTargetTransform();
if (trans != null) {
p1.setValue(x, y);
trans.transform(p1, p2);
x = p2.x;
y = p2.y;
z = z / config.getFromMetres();
}
x = round(x, config.getNumberOfRoundingPlaces());
y = round(y, config.getNumberOfRoundingPlaces());
z = round(z, config.getNumberOfRoundingPlaces());
Vertex v = new Vertex(x, y, z);
Vertex duplicate = vertexMap.get(v);
if (duplicate == null) {
vertexMap.put(v, v);
} else {
v = duplicate;
}
currentRing.addVertex(v);
}
private double round(double value, int places) {
if (places < 0) {
throw new IllegalArgumentException();
}
BigDecimal bd = BigDecimal.valueOf(value);
bd = bd.setScale(places, RoundingMode.HALF_UP);
return bd.doubleValue();
}
public List<ConcretePolygon> getPolygons() {
return polygons;
}
}
/*-
* Copyright 2022 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 <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.mapper.citygml3;
import java.util.ArrayList;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXParseException;
public class GMLValidationHandler implements ErrorHandler {
private static final Logger logger = LogManager.getLogger(GMLValidationHandler.class);
private List<String> messages = new ArrayList<>();
@Override
public void error(SAXParseException exception) {
String message = "[" + exception.getLineNumber() + ", " + exception.getColumnNumber() + "] "
+ exception.getMessage();
logger.error(message);
messages.add(message);
}
@Override
public void warning(SAXParseException exception) {
String message = "[" + exception.getLineNumber() + ", " + exception.getColumnNumber() + "] "
+ exception.getMessage();
logger.warn(message);
messages.add(message);
}
@Override
public void fatalError(SAXParseException exception) {
String message = "[" + exception.getLineNumber() + ", " + exception.getColumnNumber() + "] "
+ exception.getMessage();
logger.fatal(message);
messages.add(message);
}
public List<String> getMessages() {
return messages;
}
}
/*-
* Copyright 2022 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 <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.mapper.citygml3;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
public record ResolvableReference(String href, Geometry geometry) {
}
/*-
* Copyright 2022 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 <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.mapper.citygml3;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.citygml4j.core.model.construction.AbstractConstructionSurface;
import org.citygml4j.core.model.construction.AbstractFillingSurface;
import org.citygml4j.core.model.construction.AbstractFillingSurfaceProperty;
import org.citygml4j.core.model.construction.CeilingSurface;
import org.citygml4j.core.model.construction.DoorSurface;
import org.citygml4j.core.model.construction.FloorSurface;
import org.citygml4j.core.model.construction.GroundSurface;
import org.citygml4j.core.model.construction.InteriorWallSurface;
import org.citygml4j.core.model.construction.OuterCeilingSurface;
import org.citygml4j.core.model.construction.OuterFloorSurface;
import org.citygml4j.core.model.construction.RoofSurface;
import org.citygml4j.core.model.construction.WallSurface;
import org.citygml4j.core.model.construction.WindowSurface;
import org.citygml4j.core.model.core.AbstractThematicSurface;
import org.citygml4j.core.model.core.ClosureSurface;
import org.citygml4j.core.visitor.ObjectWalker;
import org.xmlobjects.gml.model.geometry.aggregates.MultiSurface;
import org.xmlobjects.gml.model.geometry.aggregates.MultiSurfaceProperty;
import org.xmlobjects.gml.model.geometry.primitives.AbstractSurface;
import org.xmlobjects.gml.model.geometry.primitives.SurfaceProperty;
import de.hft.stuttgart.citydoctor2.datastructure.BoundarySurface;
import de.hft.stuttgart.citydoctor2.datastructure.BoundarySurfaceType;
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.Lod;
import de.hft.stuttgart.citydoctor2.datastructure.Opening;
import de.hft.stuttgart.citydoctor2.datastructure.OpeningType;
import de.hft.stuttgart.citydoctor2.datastructure.SurfaceFeatureType;
import de.hft.stuttgart.citydoctor2.datastructure.Vertex;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
public class SurfaceMapper extends ObjectWalker {
private List<BoundarySurface> surfaces = new ArrayList<>();
private Map<String, ConcretePolygon> polygonMap;
private List<ResolvableReference> references;
private Map<Vertex, Vertex> vertexMap;
private ParserConfiguration config;
public SurfaceMapper(Map<String, ConcretePolygon> polygonMap, List<ResolvableReference> references,
Map<Vertex, Vertex> vertexMap, ParserConfiguration config) {
this.polygonMap = polygonMap;
this.references = references;
this.vertexMap = vertexMap;
this.config = config;
}
@Override
public void visit(WallSurface wallSurface) {
BoundarySurface surface = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.WALL,
wallSurface);
handleConstructionSurface(wallSurface, surface);
surfaces.add(surface);
}
private void handleConstructionSurface(AbstractConstructionSurface gmlSurface, BoundarySurface cdSurface) {
for (AbstractFillingSurfaceProperty fillingProp : gmlSurface.getFillingSurfaces()) {
if (fillingProp.isSetObject()) {
readAbstractFillingSurface(fillingProp.getObject(), cdSurface);
}
}
handleThematicSurface(gmlSurface, cdSurface);
cdSurface.unsetGmlGeometries();
}
private void readAbstractFillingSurface(AbstractFillingSurface afs, BoundarySurface cdSurface) {
Opening o;
if (afs instanceof DoorSurface ds) {
o = new Opening(OpeningType.DOOR, SurfaceFeatureType.BUILDING, cdSurface, ds);
} else if (afs instanceof WindowSurface ws){
o = new Opening(OpeningType.WINDOW, SurfaceFeatureType.BUILDING, cdSurface, ws);
} else {
o = new Opening(OpeningType.UNKNOWN, SurfaceFeatureType.BUILDING, cdSurface, afs);
}
cdSurface.addOpening(o);
parseAndAddMultiSurface(afs.getLod0MultiSurface(), Lod.LOD0, o);
parseAndAddMultiSurface(afs.getLod1MultiSurface(), Lod.LOD1, o);
parseAndAddMultiSurface(afs.getLod2MultiSurface(), Lod.LOD2, o);
parseAndAddMultiSurface(afs.getLod3MultiSurface(), Lod.LOD3, o);
parseAndAddMultiSurface(afs.getDeprecatedProperties().getLod4MultiSurface(), Lod.LOD4, o);
o.unsetGmlGeometries();
}
private void handleThematicSurface(AbstractThematicSurface gmlSurface, CityObject cdSurface) {
Citygml3FeatureMapper.parseId(gmlSurface, cdSurface);
parseAndAddMultiSurface(gmlSurface.getLod0MultiSurface(), Lod.LOD0, cdSurface);
parseAndAddMultiSurface(gmlSurface.getLod1MultiSurface(), Lod.LOD1, cdSurface);
parseAndAddMultiSurface(gmlSurface.getLod2MultiSurface(), Lod.LOD2, cdSurface);
parseAndAddMultiSurface(gmlSurface.getLod3MultiSurface(), Lod.LOD3, cdSurface);
parseAndAddMultiSurface(gmlSurface.getDeprecatedProperties().getLod4MultiSurface(), Lod.LOD4, cdSurface);
}
private void parseAndAddMultiSurface(MultiSurfaceProperty msp, Lod lod, CityObject cdSurface) {
if (msp == null || msp.getObject() == null) {
return;
}
Geometry geom = parseMultiSurface(msp.getObject(), lod);
cdSurface.addGeometry(geom);
}
private Geometry parseMultiSurface(MultiSurface ms, Lod lod) {
Geometry geom = new Geometry(GeometryType.MULTI_SURFACE, lod);
Citygml3GeometryMapper geometryMapper = new Citygml3GeometryMapper(config, vertexMap);
readSurfaceMember(geom, geometryMapper, ms.getSurfaceMember());
return geom;
}
private void readSurfaceMember(Geometry geom, Citygml3GeometryMapper geometryMapper,
List<SurfaceProperty> surfaceMember) {
for (SurfaceProperty prop : surfaceMember) {
if (prop.getHref() != null) {
references.add(new ResolvableReference(prop.getHref(), geom));
continue;
}
if (prop.getObject() != null) {
AbstractSurface as = prop.getObject();
as.accept(geometryMapper);
}
}
List<ConcretePolygon> polygons = geometryMapper.getPolygons();
for (ConcretePolygon concretePoly : polygons) {
geom.addPolygon(concretePoly);
if (concretePoly.hasExistingGmlId()) {
polygonMap.put(concretePoly.getGmlId().getGmlString(), concretePoly);
}
}
}
@Override
public void visit(FloorSurface floorSurface) {
BoundarySurface surface = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.FLOOR,
floorSurface);
handleConstructionSurface(floorSurface, surface);
surfaces.add(surface);
}
@Override
public void visit(CeilingSurface ceilingSurface) {
BoundarySurface surface = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.CEILING,
ceilingSurface);
handleConstructionSurface(ceilingSurface, surface);
surfaces.add(surface);
}
@Override
public void visit(GroundSurface groundSurface) {
BoundarySurface surface = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.GROUND,
groundSurface);
handleConstructionSurface(groundSurface, surface);
surfaces.add(surface);
}
@Override
public void visit(InteriorWallSurface interiorWallSurface) {
BoundarySurface surface = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.INTERIOR_WALL,
interiorWallSurface);
handleConstructionSurface(interiorWallSurface, surface);
surfaces.add(surface);
}
@Override
public void visit(OuterCeilingSurface outerCeilingSurface) {
BoundarySurface surface = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.OUTER_CEILING,
outerCeilingSurface);
handleConstructionSurface(outerCeilingSurface, surface);
surfaces.add(surface);
}
@Override
public void visit(OuterFloorSurface outerFloorSurface) {
BoundarySurface surface = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.OUTER_FLOOR,
outerFloorSurface);
handleConstructionSurface(outerFloorSurface, surface);
surfaces.add(surface);
}
@Override
public void visit(RoofSurface roofSurface) {
BoundarySurface surface = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.ROOF,
roofSurface);
handleConstructionSurface(roofSurface, surface);
surfaces.add(surface);
}
@Override
public void visit(ClosureSurface closureSurface) {
BoundarySurface surface = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.CLOSURE,
closureSurface);
handleThematicSurface(closureSurface, surface);
surfaces.add(surface);
}
public List<BoundarySurface> getSurfaces() {
return surfaces;
}
}
......@@ -18,7 +18,7 @@
*/
package de.hft.stuttgart.citydoctor2.parser;
import org.citygml4j.model.citygml.core.CityModel;
import org.citygml4j.core.model.core.CityModel;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
......
/*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
* Copyright 2022 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
*
* This file is part of CityDoctor2.
*
......@@ -23,72 +23,68 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.ServiceLoader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import javax.xml.XMLConstants;
import javax.xml.bind.ValidationEventHandler;
import javax.xml.namespace.QName;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.citygml4j.CityGMLContext;
import org.citygml4j.builder.jaxb.CityGMLBuilder;
import org.citygml4j.builder.jaxb.CityGMLBuilderException;
import org.citygml4j.model.citygml.CityGML;
import org.citygml4j.model.citygml.ade.ADEComponent;
import org.citygml4j.model.citygml.ade.ADEException;
import org.citygml4j.model.citygml.ade.binding.ADEContext;
import org.citygml4j.model.citygml.ade.generic.ADEGenericElement;
import org.citygml4j.model.citygml.bridge.Bridge;
import org.citygml4j.model.citygml.core.AbstractCityObject;
import org.citygml4j.model.citygml.core.CityModel;
import org.citygml4j.model.citygml.core.CityObjectMember;
import org.citygml4j.model.citygml.landuse.LandUse;
import org.citygml4j.model.citygml.transportation.AbstractTransportationObject;
import org.citygml4j.model.citygml.vegetation.AbstractVegetationObject;
import org.citygml4j.model.citygml.waterbody.WaterBody;
import org.citygml4j.model.gml.feature.AbstractFeature;
import org.citygml4j.model.module.citygml.CityGMLVersion;
import org.citygml4j.xml.io.CityGMLInputFactory;
import org.citygml4j.xml.io.CityGMLOutputFactory;
import org.citygml4j.xml.io.reader.CityGMLReadException;
import org.citygml4j.xml.io.reader.CityGMLReader;
import org.citygml4j.xml.io.reader.FeatureReadMode;
import org.citygml4j.xml.io.reader.ParentInfo;
import org.citygml4j.xml.io.writer.CityGMLWriteException;
import org.citygml4j.xml.io.writer.CityModelInfo;
import org.citygml4j.xml.io.writer.CityModelWriter;
import org.citygml4j.core.ade.ADEException;
import org.citygml4j.core.ade.ADERegistry;
import org.citygml4j.core.model.ade.ADEProperty;
import org.citygml4j.core.model.core.AbstractCityObject;
import org.citygml4j.core.model.core.AbstractCityObjectProperty;
import org.citygml4j.core.model.core.AbstractFeature;
import org.citygml4j.core.model.core.CityModel;
import org.citygml4j.core.util.CityGMLConstants;
import org.citygml4j.xml.CityGMLContext;
import org.citygml4j.xml.CityGMLContextException;
import org.citygml4j.xml.module.citygml.CityGMLModule;
import org.citygml4j.xml.module.citygml.CityGMLModules;
import org.citygml4j.xml.reader.ChunkOptions;
import org.citygml4j.xml.reader.CityGMLInputFactory;
import org.citygml4j.xml.reader.CityGMLReadException;
import org.citygml4j.xml.reader.CityGMLReader;
import org.citygml4j.xml.reader.FeatureInfo;
import org.citygml4j.xml.schema.CityGMLSchemaHandler;
import org.citygml4j.xml.writer.CityGMLChunkWriter;
import org.citygml4j.xml.writer.CityGMLOutputFactory;
import org.citygml4j.xml.writer.CityGMLWriteException;
import org.locationtech.proj4j.BasicCoordinateTransform;
import org.locationtech.proj4j.CRSFactory;
import org.locationtech.proj4j.CoordinateReferenceSystem;
import org.locationtech.proj4j.ProjCoordinate;
import org.locationtech.proj4j.proj.Projection;
import org.locationtech.proj4j.units.Units;
import org.w3c.dom.DOMException;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;
import org.xml.sax.SAXParseException;
import org.xmlobjects.schema.SchemaHandlerException;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.mapper.FeatureMapper;
import de.hft.stuttgart.citydoctor2.mapper.citygml3.Citygml3FeatureMapper;
import de.hft.stuttgart.citydoctor2.mapper.citygml3.GMLValidationHandler;
import de.hft.stuttgart.citydoctor2.math.Vector3d;
import de.hft.stuttgart.citydoctor2.utils.Localization;
import de.hft.stuttgart.quality.QualityADEContext;
import de.hft.stuttgart.quality.QualityADEModule;
/**
......@@ -99,6 +95,8 @@ import de.hft.stuttgart.quality.QualityADEModule;
*/
public class CityGmlParser {
private static final String CITY_OBJECT_MEMBER = "cityObjectMember";
private static final String WGS_84 = "EPSG:4326";
private static final Logger logger = LogManager.getLogger(CityGmlParser.class);
......@@ -119,6 +117,9 @@ public class CityGmlParser {
private static final SAXParserFactory FACTORY;
private static CityGMLContext context;
private static List<QName> chunkProperties = new ArrayList<>();
static {
FACTORY = SAXParserFactory.newInstance();
try {
......@@ -126,10 +127,31 @@ public class CityGmlParser {
} catch (SAXNotRecognizedException | SAXNotSupportedException | ParserConfigurationException e) {
logger.catching(e);
}
chunkProperties.add(new QName(CityGMLConstants.CITYGML_1_0_CORE_NAMESPACE, CITY_OBJECT_MEMBER));
chunkProperties.add(new QName(CityGMLConstants.CITYGML_2_0_CORE_NAMESPACE, CITY_OBJECT_MEMBER));
chunkProperties.add(new QName(CityGMLConstants.CITYGML_3_0_CORE_NAMESPACE, CITY_OBJECT_MEMBER));
}
private CityGmlParser() {
// only static access
}
public static synchronized CityGMLContext getContext() {
if (context == null) {
try {
context = CityGMLContext.newInstance(CityGmlParser.class.getClassLoader());
// also setup ades
ADERegistry adeRegistry = ADERegistry.getInstance();
adeRegistry.loadADE(new QualityADEContext());
} catch (CityGMLContextException e) {
logger.fatal("Unable to create citygml4j context", e);
throw new IllegalStateException("Unable to create citygml4j context");
} catch (ADEException e) {
logger.fatal("Unable to add ADE plugins to citygml4j", e);
throw new IllegalStateException("Unable to add ADE plugins to citygml4j");
}
}
return context;
}
public static CityDoctorModel parseCityGmlFile(String file, ParserConfiguration config)
......@@ -143,329 +165,99 @@ public class CityGmlParser {
}
public static CityDoctorModel parseCityGmlFile(String filePath, ParserConfiguration config, ProgressListener l,
ValidationEventHandler handler) throws CityGmlParseException, InvalidGmlFileException {
File file = new File(filePath);
GMLValidationHandler handler) throws CityGmlParseException, InvalidGmlFileException {
CityGMLContext context = getContext();
Path file = Paths.get(filePath);
if (config.getValidate()) {
List<String> messages = validateFile(context, handler, file);
if (!messages.isEmpty()) {
throw new InvalidGmlFileException("Invalid GML File. First error: \n" + messages.get(0));
}
}
try {
parseEpsgCodeFromFile(file, config);
CityGMLBuilder builder = setupCityGmlBuilder();
CityGMLInputFactory inputFactory = setupGmlReader(builder, config);
if (handler != null) {
inputFactory.setValidationEventHandler(handler);
}
// try with resources for automatic closing
try (ObservedInputStream ois = new ObservedInputStream(file)) {
CityGMLInputFactory in = context.createCityGMLInputFactory()
.withChunking(ChunkOptions.chunkByProperties(chunkProperties).skipCityModel(false));
try (ObservedInputStream ois = new ObservedInputStream(file.toFile())) {
if (l != null) {
ois.addListener(l::updateProgress);
}
return readAndKeepFeatures(config, file, inputFactory, ois);
}
} catch (CityGMLReadException e) {
if (e.getCause() instanceof SAXParseException) {
throw new InvalidGmlFileException(
Localization.getText("CityGmlParser.notValidGmlFile") + e.getCause().getMessage(), e);
}
throw new CityGmlParseException(e);
} catch (IOException | CityGMLBuilderException | ParserConfigurationException | SAXException | ADEException e) {
throw new CityGmlParseException(e);
} catch (DOMException e) {
// the citygml4j split per feature tries to insert an element
// this sometimes fails because of namespace mismatch
// fallback solution is to parse the whole file at once
// problems with memory consumption may arise
try {
if (logger.isWarnEnabled()) {
logger.warn(Localization.getText("CityGmlParser.chunkReadFailed"), e);
}
return parseCityGmlFileComplete(file, config, l);
} catch (CityGMLBuilderException | CityGMLReadException | IOException e1) {
throw new CityGmlParseException(e1);
}
}
}
private static CityDoctorModel readAndKeepFeatures(ParserConfiguration config, File file,
CityGMLInputFactory inputFactory, ObservedInputStream ois) throws CityGMLReadException {
try (CityGMLReader reader = inputFactory.createCityGMLReader(file.getAbsolutePath(), ois)) {
FeatureMapper mapper = new FeatureMapper(config, file);
// model is read in chunked mode
// object members are replaced by href in model
// need to remove the refs and re-add unparsed objects
List<AbstractCityObject> acos = new ArrayList<>();
List<ADEGenericElement> genericElements = new ArrayList<>();
while (reader.hasNext()) {
CityGML chunk = reader.nextFeature();
if (chunk instanceof AbstractCityObject aco) {
aco.accept(mapper);
acos.add(aco);
} else if (chunk instanceof CityModel cModel) {
((CityModel) chunk).unsetCityObjectMember();
// re-add all objects
for (AbstractCityObject aco : acos) {
cModel.addCityObjectMember(new CityObjectMember(aco));
}
// remove those that should have been parsed
unsetParsedCityObjectMembers(cModel);
for (ADEGenericElement ele : genericElements) {
cModel.addGenericADEElement(ele);
}
mapper.setCityModel(cModel);
} else if (chunk instanceof ADEGenericElement ge) {
genericElements.add(ge);
}
}
if (logger.isInfoEnabled()) {
logger.info(Localization.getText("CityGmlParser.parsedObjects"),
mapper.getModel().getNumberOfFeatures());
}
return mapper.getModel();
}
}
private static CityDoctorModel parseCityGmlFileComplete(File file, ParserConfiguration config, ProgressListener l)
throws CityGMLBuilderException, IOException, CityGMLReadException, CityGmlParseException {
CityGMLContext context = CityGMLContext.getInstance();
CityGMLBuilder builder = context.createCityGMLBuilder();
CityGMLInputFactory inputFactory = builder.createCityGMLInputFactory();
inputFactory.setProperty(CityGMLInputFactory.FAIL_ON_MISSING_ADE_SCHEMA, false);
inputFactory.setProperty(CityGMLInputFactory.USE_VALIDATION, config.getValidate());
try (ObservedInputStream ois = new ObservedInputStream(file)) {
if (l != null) {
ois.addListener(l::updateProgress);
}
try (CityGMLReader reader = inputFactory.createCityGMLReader(file.getAbsolutePath(), ois)) {
FeatureMapper mapper = new FeatureMapper(config, file);
CityGML chunk = reader.nextFeature();
if (!(chunk instanceof CityModel)) {
throw new CityGmlParseException("Did not read CityModel as first element of gml file.");
}
CityModel model = (CityModel) chunk;
mapper.setCityModel(model);
if (model.isSetCityObjectMember()) {
for (CityObjectMember com : model.getCityObjectMember()) {
if (com.isSetCityObject()) {
com.getCityObject().accept(mapper);
}
}
}
model.unsetCityObjectMember();
return mapper.getModel();
}
}
}
private static CityGMLInputFactory setupGmlReader(CityGMLBuilder builder, ParserConfiguration config)
throws CityGMLBuilderException {
CityGMLInputFactory inputFactory = builder.createCityGMLInputFactory();
inputFactory.setProperty(CityGMLInputFactory.FEATURE_READ_MODE, FeatureReadMode.SPLIT_PER_FEATURE);
if (config != null) {
inputFactory.setProperty(CityGMLInputFactory.USE_VALIDATION, config.getValidate());
}
inputFactory.setProperty(CityGMLInputFactory.FAIL_ON_MISSING_ADE_SCHEMA, false);
inputFactory.setProperty(CityGMLInputFactory.EXCLUDE_FROM_SPLITTING,
new QName[] { new QName("WallSurface"), new QName("RoofSurface"), new QName("GroundSurface"),
new QName("CeilingSurface"), new QName("ClosureSurface"), new QName("FloorSurface"),
new QName("InteriorWallSurface"), new QName("OuterCeilingSurface"),
new QName("OuterFloorSurface"), new QName("BuildingInstallation"), new QName("BuildingPart"),
new QName("Door"), new QName("Window") });
return inputFactory;
}
private static CityGMLBuilder setupCityGmlBuilder() throws ADEException, CityGMLBuilderException {
CityGMLContext context = CityGMLContext.getInstance();
// setup energy ade stuff, so the parser doesn't crash on encountering this
if (!context.hasADEContexts()) {
for (ADEContext adeContext : ServiceLoader.load(ADEContext.class)) {
context.registerADEContext(adeContext);
return readAndKeepFeatures(config, file, in, ois);
}
} catch (CityGMLReadException | IOException e) {
throw new CityGmlParseException("Failed to read CityGML file", e);
}
return context.createCityGMLBuilder(CityGmlParser.class.getClassLoader());
}
public static void streamCityGml(String file, ParserConfiguration config, CityGmlConsumer cityObjectConsumer,
String outputFile) throws CityGmlParseException {
File f = new File(file);
Path f = Paths.get(file);
streamCityGml(f, config, null, cityObjectConsumer, outputFile);
}
public static void streamCityGml(File file, ParserConfiguration config, ProgressListener l,
CityGmlConsumer cityObjectConsumer, String outputFile) throws CityGmlParseException {
try {
if (getExtension(file.getName()).equals("zip")) {
streamZipFile(file, config);
}
parseEpsgCodeFromFile(file, config);
CityGMLBuilder builder = setupCityGmlBuilder();
startReadingCityGml(file, config, l, cityObjectConsumer, builder, outputFile);
} catch (CityGMLBuilderException | IOException | ParserConfigurationException | SAXException | ADEException e) {
throw new CityGmlParseException(e);
}
}
private static void startReadingCityGml(File file, ParserConfiguration config, ProgressListener l,
CityGmlConsumer cityObjectConsumer, CityGMLBuilder builder, String outputFile)
throws CityGMLBuilderException {
try (ObservedInputStream ois = new ObservedInputStream(file)) {
if (l != null) {
ois.addListener(l::updateProgress);
}
readAndDiscardFeatures(file, config, builder, ois, cityObjectConsumer, outputFile);
} catch (IOException e) {
logger.error(Localization.getText("CityGmlParser.errorReadingGmlFile"), e.getMessage());
logger.catching(Level.ERROR, e);
}
}
private static void streamZipFile(File file, ParserConfiguration config) throws CityGmlParseException {
try (ZipFile zip = new ZipFile(file)) {
Enumeration<? extends ZipEntry> entries = zip.entries();
while (entries.hasMoreElements()) {
ZipEntry ze = entries.nextElement();
BufferedInputStream bis = new BufferedInputStream(zip.getInputStream(ze));
parseEpsgCodeFromStream(bis, config);
}
} catch (IOException e) {
throw new UncheckedIOException(e);
} catch (ParserConfigurationException | SAXException e) {
throw new CityGmlParseException(e);
}
}
private static String getExtension(String fileName) {
char ch;
int len;
if (fileName == null || (len = fileName.length()) == 0 || (ch = fileName.charAt(len - 1)) == '/' || ch == '\\'
|| ch == '.') {
return "";
}
int dotInd = fileName.lastIndexOf('.');
int sepInd = Math.max(fileName.lastIndexOf('/'), fileName.lastIndexOf('\\'));
if (dotInd <= sepInd)
return "";
else
return fileName.substring(dotInd + 1).toLowerCase();
}
public static void streamCityGml(File file, ParserConfiguration parserConfig, CityGmlConsumer cityObjectConsumer,
String outputFile) throws CityGmlParseException {
streamCityGml(file, parserConfig, null, cityObjectConsumer, outputFile);
streamCityGml(file.toPath(), parserConfig, null, cityObjectConsumer, outputFile);
}
/**
* The srsName (The name by which this reference system is identified) inside
* the CityGML file can have multiple formats. This method tries to parse the
* string and detect the corresponding reference system. If it is found, it
* returns a proj4j.CoordinateReferenceSystem. It throws an
* IllegalArgumentException otherwise.
*
* This method should be able to parse any EPSG id : e.g. "EPSG:1234". German
* Citygmls might also have "DE_DHDN_3GK3" or "ETRS89_UTM32" as srsName, so
* those are also included. It isn't guaranteed that those formats are correctly
* parsed, though.
*
* The EPSG ids and parameters are defined in resources ('nad/epsg') inside
* proj4j-0.1.0.jar. Some EPSG ids are missing though, e.g. 7415
*
* @param srsName
* @return CoordinateReferenceSystem
*/
private static CoordinateReferenceSystem crsFromSrsName(String srsName) {
srsName = srsName.trim();
Matcher mEPSG = P_EPSG.matcher(srsName);
if (mEPSG.find()) {
if ("EPSG:4979".contentEquals(srsName)) {
srsName = "EPSG:4236";
} else if ("EPSG:7415".contentEquals(srsName)) {
return CRS_FACTORY.createFromParameters("EPSG:7415",
"+proj=sterea +lat_0=52.15616055555555 +lon_0=5.38763888888889 +k=0.9999079 +x_0=155000 +y_0=463000 +ellps=bessel +towgs84=565.417,50.3319,465.552,-0.398957,0.343988,-1.8774,4.0725 +units=m +no_defs");
}
return CRS_FACTORY.createFromName(srsName);
}
Matcher mOGC = P_OGC.matcher(srsName);
if (mOGC.find()) {
return CRS_FACTORY.createFromName("EPSG:" + mOGC.group(1));
}
Matcher mOGC2 = P_OGC2.matcher(srsName);
if (mOGC2.find()) {
return CRS_FACTORY.createFromName("EPSG:" + mOGC2.group(1));
}
Matcher mURN = P_URN.matcher(srsName);
// NOTE: Could use a HashMap if the switch/case becomes too long.
if (mURN.find()) {
switch (mURN.group(1)) {
case "DE_DHDN_3GK2":
return CRS_FACTORY.createFromName("EPSG:31466");
case "DE_DHDN_3GK3":
return CRS_FACTORY.createFromName("EPSG:31467");
case "DE_DHDN_3GK4":
return CRS_FACTORY.createFromName("EPSG:31468");
case "DE_DHDN_3GK5":
return CRS_FACTORY.createFromName("EPSG:31469");
case "ETRS89_UTM32":
return CRS_FACTORY.createFromName("EPSG:25832");
default:
return null;
}
}
if (srsName.equals("http://www.opengis.net/def/crs/EPSG/0/6697")) {
return CRS_FACTORY.createFromParameters("EPSG:6697", "+proj=longlat +ellps=GRS80 +no_defs +axis=neu");
}
return null;
public static void streamCityGml(Path file, ParserConfiguration config, ProgressListener l,
CityGmlConsumer cityObjectConsumer, String outputFile) throws CityGmlParseException {
parseEpsgCodeFromFile(file, config);
startReadingCityGml(file, config, l, cityObjectConsumer, outputFile);
}
public static CityModel parseOnlyCityModel(File inputFile) throws CityGmlParseException {
try {
CityGMLBuilder setupCityGmlBuilder = setupCityGmlBuilder();
CityGMLInputFactory inputFactory = setupGmlReader(setupCityGmlBuilder, null);
CityGMLInputFactory inputFactory = context.createCityGMLInputFactory()
.withChunking(ChunkOptions.chunkByProperties(chunkProperties).skipCityModel(false));
try (CityGMLReader reader = inputFactory.createCityGMLReader(inputFile)) {
while (reader.hasNext()) {
CityGML chunk = reader.nextFeature();
AbstractFeature chunk = reader.next();
if (chunk instanceof CityModel cModel) {
unsetParsedCityObjectMembers(cModel);
cModel.setCityObjectMembers(null);
return cModel;
}
}
}
} catch (CityGMLBuilderException | CityGMLReadException | ADEException e) {
} catch (CityGMLReadException e) {
throw new CityGmlParseException(e);
}
throw new CityGmlParseException("Did not find any CityModel in CityGML file");
}
private static void unsetParsedCityObjectMembers(CityModel cModel) {
Iterator<CityObjectMember> iterator = cModel.getCityObjectMember().iterator();
while (iterator.hasNext()) {
CityObjectMember m = iterator.next();
AbstractCityObject aco = m.getCityObject();
if (aco instanceof Bridge || aco instanceof org.citygml4j.model.citygml.building.Building
|| aco instanceof AbstractTransportationObject || aco instanceof AbstractVegetationObject
|| aco instanceof WaterBody || aco instanceof LandUse) {
iterator.remove();
private static void startReadingCityGml(Path file, ParserConfiguration config, ProgressListener l,
CityGmlConsumer cityObjectConsumer, String outputFile) {
try (ObservedInputStream ois = new ObservedInputStream(file.toFile())) {
if (l != null) {
ois.addListener(l::updateProgress);
}
readAndDiscardFeatures(file, config, ois, cityObjectConsumer, outputFile);
} catch (IOException | CityGMLReadException e) {
logger.error(Localization.getText("CityGmlParser.errorReadingGmlFile"), e.getMessage());
logger.catching(Level.ERROR, e);
}
}
private static void readAndDiscardFeatures(File file, ParserConfiguration config, CityGMLBuilder builder,
ObservedInputStream ois, CityGmlConsumer cityObjectConsumer, String outputFile)
throws CityGMLBuilderException {
CityGMLInputFactory inputFactory = setupGmlReader(builder, config);
try (CityGMLReader reader = inputFactory.createCityGMLReader(file.getAbsolutePath(), ois);
CityModelWriter writer = createCityModelWriter(builder, outputFile)) {
FeatureMapper mapper = new FeatureMapper(config, file);
private static void readAndDiscardFeatures(Path file, ParserConfiguration config, ObservedInputStream ois,
CityGmlConsumer cityObjectConsumer, String outputFile) throws CityGMLReadException {
getContext();
CityGMLInputFactory inputFactory = context.createCityGMLInputFactory()
.withChunking(ChunkOptions.chunkByProperties(chunkProperties).skipCityModel(false));
CityGMLChunkWriter writer = null;
try (CityGMLReader reader = inputFactory.createCityGMLReader(ois)) {
Citygml3FeatureMapper mapper = new Citygml3FeatureMapper(config, file);
CityDoctorModel model = mapper.getModel();
boolean isInitialized = false;
CityModelInfo cityModelInfo = null;
while (reader.hasNext()) {
CityGML chunk = reader.nextFeature();
if (!isInitialized && writer != null) {
ParentInfo parentInfo = reader.getParentInfo();
cityModelInfo = new CityModelInfo(parentInfo);
writer.setCityModelInfo(cityModelInfo);
writer.writeStartDocument();
AbstractFeature chunk = reader.next();
if (writer == null) {
writer = createCityModelWriter(outputFile, reader);
}
if (!isInitialized && writer != null && reader.getParentInfo() != null
&& reader.getParentInfo().getTypeName().getLocalPart().equals("CityModel")) {
FeatureInfo parentInfo = reader.getParentInfo();
writer.withCityModelInfo(parentInfo);
isInitialized = true;
}
if (chunk instanceof AbstractCityObject ag) {
......@@ -473,14 +265,13 @@ public class CityGmlParser {
drainCityModel(model, cityObjectConsumer);
writeAbstractCityObject(writer, ag);
} else if (chunk instanceof CityModel cModel) {
cModel.unsetCityObjectMember();
cModel.setCityObjectMembers(null);
mapper.setCityModel(cModel);
cityObjectConsumer.accept(cModel);
writeCityModel(writer, cityModelInfo, cModel);
} else if (chunk instanceof AbstractFeature af && writer != null) {
writer.writeFeatureMember(af);
writeCityModel(writer, cModel);
} else if (writer != null) {
writer.writeMember(chunk);
}
}
// end of stream
logger.debug("End of gml file stream");
......@@ -488,49 +279,99 @@ public class CityGmlParser {
logger.error(Localization.getText("CityGmlParser.errorReadingGmlFile"), e.getMessage(), e);
} catch (CityGMLWriteException e) {
logger.error(Localization.getText("CityGmlParser.errorWritingGmlFile"), e.getMessage(), e);
} finally {
if (writer != null) {
try {
writer.close();
} catch (CityGMLWriteException e) {
// ignore
}
}
}
}
private static void writeAbstractCityObject(CityModelWriter writer, AbstractCityObject ag)
throws CityGMLWriteException {
private static void writeCityModel(CityGMLChunkWriter writer, CityModel cModel) {
if (writer != null) {
writer.writeFeatureMember(ag);
for (ADEProperty genEle : cModel.getADEProperties()) {
writer.getCityModelInfo().addADEProperty(genEle);
}
}
}
private static void writeCityModel(CityModelWriter writer, CityModelInfo cityModelInfo, CityModel cModel)
private static void writeAbstractCityObject(CityGMLChunkWriter writer, AbstractCityObject ag)
throws CityGMLWriteException {
if (writer != null) {
for (ADEGenericElement genEle : cModel.getGenericADEElement()) {
cityModelInfo.addGenericADEElement(genEle);
}
for (ADEComponent adeComp : cModel.getGenericApplicationPropertyOfCityModel()) {
cityModelInfo.addGenericApplicationPropertyOfCityModel(adeComp);
}
writer.writeEndDocument();
writer.writeMember(ag);
}
}
private static CityModelWriter createCityModelWriter(CityGMLBuilder builder, String outputFile)
private static CityGMLChunkWriter createCityModelWriter(String outputFile, CityGMLReader reader)
throws CityGMLWriteException {
if (outputFile == null) {
return null;
}
CityGMLOutputFactory factory = builder.createCityGMLOutputFactory();
CityModelWriter writer = factory.createCityModelWriter(new File(outputFile), "UTF-8");
writer.setPrefix("qual", QualityADEModule.NAMESPACE_URI);
writer.setSchemaLocation(QualityADEModule.NAMESPACE_URI,
QualityADEModule.NAMESPACE_URI + "/qualityAde.xsd");
writer.setIndentString(" ");
writer.setPrefixes(CityGMLVersion.DEFAULT);
writer.setSchemaLocations(CityGMLVersion.DEFAULT);
CityGMLContext gmlContext = CityGmlParser.getContext();
CityGMLModule module = CityGMLModules.getCityGMLModule(reader.getName().getNamespaceURI());
CityGMLOutputFactory factory = gmlContext.createCityGMLOutputFactory(module.getCityGMLVersion());
CityGMLChunkWriter writer = factory.createCityGMLChunkWriter(new File(outputFile),
StandardCharsets.UTF_8.name());
writer.withPrefix("qual", QualityADEModule.NAMESPACE_URI);
writer.withSchemaLocation(QualityADEModule.NAMESPACE_URI, QualityADEModule.NAMESPACE_URI + "/qualityAde.xsd");
writer.withIndent(" ");
writer.withDefaultPrefixes();
writer.withDefaultSchemaLocations();
return writer;
}
private static void parseEpsgCodeFromFile(File file, ParserConfiguration config)
throws IOException, ParserConfigurationException, SAXException {
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file))) {
private static CityDoctorModel readAndKeepFeatures(ParserConfiguration config, Path file,
CityGMLInputFactory inputFactory, ObservedInputStream ois) throws CityGMLReadException {
try (CityGMLReader reader = inputFactory.createCityGMLReader(ois)) {
Citygml3FeatureMapper mapper = new Citygml3FeatureMapper(config, file);
// model is read in chunked mode
// object members are replaced by href in model
// need to remove the refs and re-add unparsed objects
List<AbstractCityObject> acos = new ArrayList<>();
while (reader.hasNext()) {
AbstractFeature chunk = reader.next();
if (chunk instanceof CityModel cModel) {
cModel.setCityObjectMembers(null);
mapper.setCityModel(cModel);
CityGMLModule module = CityGMLModules.getCityGMLModule(reader.getName().getNamespaceURI());
mapper.setCityGMLVersion(module.getCityGMLVersion());
} else if (chunk instanceof AbstractCityObject aco) {
acos.add(aco);
aco.accept(mapper);
}
}
if (mapper.getModel().getCityModel() == null) {
// file does not contain a city model?
// create it for now
mapper.setCityModel(new CityModel());
}
CityModel cModel = mapper.getModel().getCityModel();
// remove those that should have been parsed
List<AbstractCityObject> parsedCityObjects = mapper.getModel().createFeatureStream()
.map(CityObject::getGmlObject).toList();
acos.removeAll(parsedCityObjects);
// re-add all not parsed objects
for (AbstractCityObject aco : acos) {
cModel.getCityObjectMembers().add(new AbstractCityObjectProperty(aco));
}
if (logger.isInfoEnabled()) {
logger.info(Localization.getText("CityGmlParser.parsedObjects"),
mapper.getModel().getNumberOfFeatures());
}
return mapper.getModel();
}
}
private static void parseEpsgCodeFromFile(Path file, ParserConfiguration config) throws CityGmlParseException {
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file.toFile()))) {
parseEpsgCodeFromStream(bis, config);
} catch (ParserConfigurationException | SAXException | IOException e) {
throw new CityGmlParseException("Failed to read CityGML file", e);
}
}
......@@ -615,6 +456,89 @@ public class CityGmlParser {
}
}
/**
* The srsName (The name by which this reference system is identified) inside
* the CityGML file can have multiple formats. This method tries to parse the
* string and detect the corresponding reference system. If it is found, it
* returns a proj4j.CoordinateReferenceSystem. It throws an
* IllegalArgumentException otherwise.
*
* This method should be able to parse any EPSG id : e.g. "EPSG:1234". German
* Citygmls might also have "DE_DHDN_3GK3" or "ETRS89_UTM32" as srsName, so
* those are also included. It isn't guaranteed that those formats are correctly
* parsed, though.
*
* The EPSG ids and parameters are defined in resources ('nad/epsg') inside
* proj4j-0.1.0.jar. Some EPSG ids are missing though, e.g. 7415
*
* @param srsName
* @return CoordinateReferenceSystem
*/
private static CoordinateReferenceSystem crsFromSrsName(String srsName) {
srsName = srsName.trim();
Matcher mEPSG = P_EPSG.matcher(srsName);
if (mEPSG.find()) {
if ("EPSG:4979".contentEquals(srsName)) {
srsName = "EPSG:4236";
} else if ("EPSG:7415".contentEquals(srsName)) {
return CRS_FACTORY.createFromParameters("EPSG:7415",
"+proj=sterea +lat_0=52.15616055555555 +lon_0=5.38763888888889 +k=0.9999079 +x_0=155000 +y_0=463000 +ellps=bessel +towgs84=565.417,50.3319,465.552,-0.398957,0.343988,-1.8774,4.0725 +units=m +no_defs");
}
return CRS_FACTORY.createFromName(srsName);
}
Matcher mOGC = P_OGC.matcher(srsName);
if (mOGC.find()) {
return CRS_FACTORY.createFromName("EPSG:" + mOGC.group(1));
}
Matcher mOGC2 = P_OGC2.matcher(srsName);
if (mOGC2.find()) {
return CRS_FACTORY.createFromName("EPSG:" + mOGC2.group(1));
}
Matcher mURN = P_URN.matcher(srsName);
// NOTE: Could use a HashMap if the switch/case becomes too long.
if (mURN.find()) {
switch (mURN.group(1)) {
case "DE_DHDN_3GK2":
return CRS_FACTORY.createFromName("EPSG:31466");
case "DE_DHDN_3GK3":
return CRS_FACTORY.createFromName("EPSG:31467");
case "DE_DHDN_3GK4":
return CRS_FACTORY.createFromName("EPSG:31468");
case "DE_DHDN_3GK5":
return CRS_FACTORY.createFromName("EPSG:31469");
case "ETRS89_UTM32":
return CRS_FACTORY.createFromName("EPSG:25832");
default:
return null;
}
}
if (srsName.equals("http://www.opengis.net/def/crs/EPSG/0/6697")) {
return CRS_FACTORY.createFromParameters("EPSG:6697", "+proj=longlat +ellps=GRS80 +no_defs +axis=neu");
}
return null;
}
private static List<String> validateFile(CityGMLContext context, GMLValidationHandler handler, Path file)
throws CityGmlParseException {
if (handler == null) {
handler = new GMLValidationHandler();
}
try {
CityGMLSchemaHandler schemaHandler = context.getDefaultSchemaHandler();
Source[] schemas = schemaHandler.getSchemas();
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
schemaFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
Schema schema = schemaFactory.newSchema(schemas);
Validator validator = schema.newValidator();
validator.setErrorHandler(handler);
validator.validate(new StreamSource(file.toFile()));
return handler.getMessages();
} catch (SchemaHandlerException | SAXException | IOException e) {
throw new CityGmlParseException("Failed to validate CityGML file", e);
}
}
private static void drainCityModel(CityDoctorModel model, CityGmlConsumer cityObjectConsumer) {
drainCityObjectList(model.getBuildings(), cityObjectConsumer);
drainCityObjectList(model.getBridges(), cityObjectConsumer);
......@@ -630,4 +554,5 @@ public class CityGmlParser {
}
objects.clear();
}
}
......@@ -21,17 +21,16 @@ package de.hft.stuttgart.citydoctor2.utils;
import java.util.ArrayList;
import java.util.List;
import org.citygml4j.factory.DimensionMismatchException;
import org.citygml4j.factory.GMLGeometryFactory;
import org.citygml4j.model.gml.geometry.aggregates.MultiSurface;
import org.citygml4j.model.gml.geometry.complexes.CompositeSurface;
import org.citygml4j.model.gml.geometry.primitives.AbstractSurface;
import org.citygml4j.model.gml.geometry.primitives.Exterior;
import org.citygml4j.model.gml.geometry.primitives.Interior;
import org.citygml4j.model.gml.geometry.primitives.Solid;
import org.citygml4j.model.gml.geometry.primitives.SurfaceProperty;
import org.citygml4j.core.util.geometry.GeometryFactory;
import org.locationtech.proj4j.BasicCoordinateTransform;
import org.locationtech.proj4j.ProjCoordinate;
import org.xmlobjects.gml.model.geometry.aggregates.MultiSurface;
import org.xmlobjects.gml.model.geometry.complexes.CompositeSurface;
import org.xmlobjects.gml.model.geometry.primitives.AbstractRingProperty;
import org.xmlobjects.gml.model.geometry.primitives.Shell;
import org.xmlobjects.gml.model.geometry.primitives.ShellProperty;
import org.xmlobjects.gml.model.geometry.primitives.Solid;
import org.xmlobjects.gml.model.geometry.primitives.SurfaceProperty;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.datastructure.GeometryType;
......@@ -52,33 +51,28 @@ public final class CityGmlUtils {
// util class
}
public static org.citygml4j.model.gml.geometry.primitives.Polygon createGmlPolygon(GMLGeometryFactory factory,
public static org.xmlobjects.gml.model.geometry.primitives.Polygon createGmlPolygon(GeometryFactory factory,
Polygon cdPoly, ParserConfiguration config) {
if (cdPoly.getExteriorRing() == null) {
return null;
}
org.citygml4j.model.gml.geometry.primitives.Polygon gmlPoly = new org.citygml4j.model.gml.geometry.primitives.Polygon();
try {
// exterior ring
LinearRing extLr = cdPoly.getExteriorRing();
org.citygml4j.model.gml.geometry.primitives.LinearRing gmlLr = createGmlRing(factory, config, extLr);
gmlPoly.setExterior(new Exterior(gmlLr));
org.xmlobjects.gml.model.geometry.primitives.Polygon gmlPoly = new org.xmlobjects.gml.model.geometry.primitives.Polygon();
// exterior ring
LinearRing extLr = cdPoly.getExteriorRing();
org.xmlobjects.gml.model.geometry.primitives.LinearRing gmlLr = createGmlRing(factory, config, extLr);
gmlPoly.setExterior(new AbstractRingProperty(gmlLr));
// interior rings
for (LinearRing lr : cdPoly.getInnerRings()) {
gmlLr = createGmlRing(factory, config, lr);
gmlPoly.addInterior(new Interior(gmlLr));
}
gmlPoly.setId(cdPoly.getGmlId().getGmlString());
return gmlPoly;
} catch (DimensionMismatchException e) {
// cannot happen as every vertex has 3 coordinates
return null;
// interior rings
for (LinearRing lr : cdPoly.getInnerRings()) {
gmlLr = createGmlRing(factory, config, lr);
gmlPoly.getInterior().add(new AbstractRingProperty(gmlLr));
}
gmlPoly.setId(cdPoly.getGmlId().getGmlString());
return gmlPoly;
}
private static org.citygml4j.model.gml.geometry.primitives.LinearRing createGmlRing(GMLGeometryFactory factory,
ParserConfiguration config, LinearRing lr) throws DimensionMismatchException {
private static org.xmlobjects.gml.model.geometry.primitives.LinearRing createGmlRing(GeometryFactory factory,
ParserConfiguration config, LinearRing lr) {
ProjCoordinate p1 = new ProjCoordinate();
ProjCoordinate p2 = new ProjCoordinate();
List<Double> ringValues = new ArrayList<>();
......@@ -99,20 +93,21 @@ public final class CityGmlUtils {
ringValues.add(y);
ringValues.add(z);
}
org.citygml4j.model.gml.geometry.primitives.LinearRing gmlLr = factory.createLinearRing(ringValues, 3);
org.xmlobjects.gml.model.geometry.primitives.LinearRing gmlLr = factory.createLinearRing(ringValues, 3);
gmlLr.setId(lr.getGmlId().getGmlString());
return gmlLr;
}
public static Solid createSolid(Geometry geom, GMLGeometryFactory factory, ParserConfiguration config) {
public static Solid createSolid(Geometry geom, GeometryFactory factory, ParserConfiguration config) {
if (geom.getType() != GeometryType.SOLID) {
throw new IllegalArgumentException("Only solids are allowed");
}
List<SurfaceProperty> surfaceMember = new ArrayList<>();
CompositeSurface comp = new CompositeSurface();
List<SurfaceProperty> surfaceMember = comp.getSurfaceMembers();
for (Polygon cdPoly : geom.getPolygons()) {
if (!cdPoly.isLink()) {
org.citygml4j.model.gml.geometry.primitives.Polygon gmlPoly = createGmlPolygon(factory, cdPoly, config);
org.xmlobjects.gml.model.geometry.primitives.Polygon gmlPoly = createGmlPolygon(factory, cdPoly, config);
if (gmlPoly != null) {
surfaceMember.add(new SurfaceProperty(gmlPoly));
}
......@@ -125,32 +120,29 @@ public final class CityGmlUtils {
if (surfaceMember.isEmpty()) {
return null;
}
CompositeSurface comp = new CompositeSurface();
comp.setSurfaceMember(surfaceMember);
Solid solid = new Solid();
solid.setExterior(new SurfaceProperty(comp));
Shell shell = new Shell(surfaceMember);
solid.setExterior(new ShellProperty(shell));
solid.setId(geom.getGmlId().getGmlString());
return solid;
}
public static MultiSurface createMultiSurface(Geometry geom, GMLGeometryFactory factory,
public static MultiSurface createMultiSurface(Geometry geom, GeometryFactory factory,
ParserConfiguration config) {
if (geom.getType() != GeometryType.MULTI_SURFACE) {
throw new IllegalArgumentException("This can only handle MultiSurfaces");
}
List<AbstractSurface> surfaces = new ArrayList<>();
List<SurfaceProperty> surfaces = new ArrayList<>();
for (Polygon cdPoly : geom.getPolygons()) {
if (!cdPoly.isLink()) {
// is not part of a boundary surface
org.citygml4j.model.gml.geometry.primitives.Polygon gmlPoly = createGmlPolygon(factory, cdPoly, config);
org.xmlobjects.gml.model.geometry.primitives.Polygon gmlPoly = createGmlPolygon(factory, cdPoly, config);
if (gmlPoly != null) {
surfaces.add(gmlPoly);
surfaces.add(new SurfaceProperty(gmlPoly));
}
} else {
// add reference to polygon
CompositeSurface cs = new CompositeSurface();
cs.addSurfaceMember(new SurfaceProperty("#" + cdPoly.getGmlId().getGmlString()));
surfaces.add(cs);
surfaces.add(new SurfaceProperty("#" + cdPoly.getGmlId().getGmlString()));
}
}
if (surfaces.isEmpty()) {
......@@ -161,13 +153,13 @@ public final class CityGmlUtils {
return ms;
}
public static MultiSurface createMultiSurface(List<Polygon> polygons, GMLGeometryFactory factory,
public static MultiSurface createMultiSurface(List<Polygon> polygons, GeometryFactory factory,
ParserConfiguration config) {
List<AbstractSurface> surfaces = new ArrayList<>();
List<SurfaceProperty> surfaces = new ArrayList<>();
for (Polygon cdPoly : polygons) {
org.citygml4j.model.gml.geometry.primitives.Polygon gmlPoly = createGmlPolygon(factory, cdPoly, config);
org.xmlobjects.gml.model.geometry.primitives.Polygon gmlPoly = createGmlPolygon(factory, cdPoly, config);
if (gmlPoly != null) {
surfaces.add(gmlPoly);
surfaces.add(new SurfaceProperty(gmlPoly));
}
}
if (surfaces.isEmpty()) {
......@@ -176,13 +168,13 @@ public final class CityGmlUtils {
return new MultiSurface(surfaces);
}
public static CompositeSurface createCompositeSurface(Geometry geom, GMLGeometryFactory factory,
public static CompositeSurface createCompositeSurface(Geometry geom, GeometryFactory factory,
ParserConfiguration config) {
List<AbstractSurface> surfaces = new ArrayList<>();
List<SurfaceProperty> surfaces = new ArrayList<>();
for (Polygon cdPoly : geom.getPolygons()) {
org.citygml4j.model.gml.geometry.primitives.Polygon gmlPoly = createGmlPolygon(factory, cdPoly, config);
org.xmlobjects.gml.model.geometry.primitives.Polygon gmlPoly = createGmlPolygon(factory, cdPoly, config);
if (gmlPoly != null) {
surfaces.add(gmlPoly);
surfaces.add(new SurfaceProperty(gmlPoly));
}
}
if (surfaces.isEmpty()) {
......
......@@ -23,19 +23,20 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.citygml4j.model.citygml.ade.ADEComponent;
import org.citygml4j.model.citygml.core.CityModel;
import org.citygml4j.model.gml.geometry.primitives.DirectPosition;
import org.xmlobjects.gml.model.base.Reference;
import org.xmlobjects.gml.model.geometry.DirectPosition;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.ErrorId;
import de.hft.stuttgart.citydoctor2.check.error.UnknownCheckError;
import de.hft.stuttgart.citydoctor2.check.QualityAdeErrorVisitor;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.math.Vector3d;
import de.hft.stuttgart.quality.model.Edge;
import de.hft.stuttgart.quality.model.Validation;
import de.hft.stuttgart.quality.model.ValidationResult;
import de.hft.stuttgart.quality.model.jaxb.ResultType;
import de.hft.stuttgart.quality.model.enums.ResultType;
import de.hft.stuttgart.quality.model.properties.ValidationResultProperty;
import de.hft.stuttgart.quality.model.types.CityObjectProperties;
import de.hft.stuttgart.quality.model.types.Edge;
import de.hft.stuttgart.quality.model.types.Validation;
import de.hft.stuttgart.quality.model.types.ValidationResult;
public class QualityADEUtils {
......@@ -59,97 +60,76 @@ public class QualityADEUtils {
return result;
}
public static void writeQualityAde(CityObject co) {
public static void writeQualityAde(CityObject co, Validation val) {
ValidationResult res = new ValidationResult();
res.setValidationPlanID(new Reference(val));
if (co.isValidated()) {
List<CheckError> errors = new ArrayList<>();
co.collectContainedErrors(errors);
if (errors.isEmpty()) {
res.setResult(ResultType.OK);
res.setResultType(ResultType.OK);
} else {
res.setResult(ResultType.ERROR);
res.setResultType(ResultType.ERROR);
Set<CheckError> errorSet = new HashSet<>(errors);
for (CheckError e : errorSet) {
if (e instanceof UnknownCheckError) {
// an error happened while checking
// set to not checked
res.setResult(ResultType.NOT_CHECKED);
} else {
e.convertToQualityAdeDatastructure().ifPresent(res.getErrors()::add);
}
QualityAdeErrorVisitor visitor = new QualityAdeErrorVisitor(res);
e.accept(visitor);
}
}
} else {
res.setResult(ResultType.NOT_CHECKED);
res.setResultType(ResultType.NOT_CHECKED);
}
co.getGmlObject().addGenericApplicationPropertyOfCityObject(res);
CityObjectProperties property = new CityObjectProperties();
property.setValidationResult(new ValidationResultProperty(res));
co.getGmlObject().addADEProperty(property);
}
public static void removeValidationResult(CityObject co) {
for (ADEComponent comp : co.getGmlObject().getGenericApplicationPropertyOfCityObject()) {
if (comp instanceof ValidationResult) {
co.getGmlObject().getGenericApplicationPropertyOfCityObject().remove(comp);
return;
}
}
}
public static void removeValidation(CityModel cm) {
for (ADEComponent comp : cm.getGenericApplicationPropertyOfCityModel()) {
if (comp instanceof Validation) {
cm.getGenericApplicationPropertyOfCityModel().remove(comp);
return;
}
}
}
public static de.hft.stuttgart.quality.model.jaxb.ErrorId mapErrorIdToAdeId(ErrorId key) {
public static de.hft.stuttgart.quality.model.enums.ErrorId mapErrorIdToAdeId(ErrorId key) {
switch (key.getIdString()) {
case "GE_R_NOT_CLOSED":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.GE_R_NOT_CLOSED;
return de.hft.stuttgart.quality.model.enums.ErrorId.GE_R_NOT_CLOSED;
case "GE_R_TOO_FEW_POINTS":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.GE_R_TOO_FEW_POINTS;
return de.hft.stuttgart.quality.model.enums.ErrorId.GE_R_TOO_FEW_POINTS;
case "GE_R_CONSECUTIVE_POINTS_SAME":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.GE_R_CONSECUTIVE_POINTS_SAME;
return de.hft.stuttgart.quality.model.enums.ErrorId.GE_R_CONSECUTIVE_POINTS_SAME;
case "GE_R_SELF_INTERSECTION":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.GE_R_SELF_INTERSECTION;
return de.hft.stuttgart.quality.model.enums.ErrorId.GE_R_SELF_INTERSECTION;
case "GE_P_NON_PLANAR_POLYGON_NORMALS_DEVIATION":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.GE_P_NON_PLANAR_POLYGON_NORMALS_DEVIATION;
return de.hft.stuttgart.quality.model.enums.ErrorId.GE_P_NON_PLANAR_POLYGON_NORMALS_DEVIATION;
case "GE_P_NON_PLANAR_POLYGON_DISTANCE_PLANE":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.GE_P_NON_PLANAR_POLYGON_DISTANCE_PLANE;
return de.hft.stuttgart.quality.model.enums.ErrorId.GE_P_NON_PLANAR_POLYGON_DISTANCE_PLANE;
case "GE_P_INTERIOR_DISCONNECTED":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.GE_P_INTERIOR_DISCONNECTED;
return de.hft.stuttgart.quality.model.enums.ErrorId.GE_P_INTERIOR_DISCONNECTED;
case "GE_P_INTERSECTING_RINGS":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.GE_P_INTERSECTING_RINGS;
return de.hft.stuttgart.quality.model.enums.ErrorId.GE_P_INTERSECTING_RINGS;
case "GE_P_HOLE_OUTSIDE":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.GE_P_HOLE_OUTSIDE;
return de.hft.stuttgart.quality.model.enums.ErrorId.GE_P_HOLE_OUTSIDE;
case "GE_P_ORIENTATION_RINGS_SAME":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.GE_P_ORIENTATION_RINGS_SAME;
return de.hft.stuttgart.quality.model.enums.ErrorId.GE_P_ORIENTATION_RINGS_SAME;
case "GE_P_INNER_RINGS_NESTED":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.GE_P_INNER_RINGS_NESTED;
return de.hft.stuttgart.quality.model.enums.ErrorId.GE_P_INNER_RINGS_NESTED;
case "GE_S_TOO_FEW_POLYGONS":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.GE_S_TOO_FEW_POLYGONS;
return de.hft.stuttgart.quality.model.enums.ErrorId.GE_S_TOO_FEW_POLYGONS;
case "GE_S_NOT_CLOSED":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.GE_S_NOT_CLOSED;
return de.hft.stuttgart.quality.model.enums.ErrorId.GE_S_NOT_CLOSED;
case "GE_S_NON_MANIFOLD_EDGE":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.GE_S_NON_MANIFOLD_EDGE;
return de.hft.stuttgart.quality.model.enums.ErrorId.GE_S_NON_MANIFOLD_EDGE;
case "GE_S_POLYGON_WRONG_ORIENTATION":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.GE_S_POLYGON_WRONG_ORIENTATION;
return de.hft.stuttgart.quality.model.enums.ErrorId.GE_S_POLYGON_WRONG_ORIENTATION;
case "GE_S_ALL_POLYGONS_WRONG_ORIENTATION":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.GE_S_ALL_POLYGONS_WRONG_ORIENTATION;
return de.hft.stuttgart.quality.model.enums.ErrorId.GE_S_ALL_POLYGONS_WRONG_ORIENTATION;
case "GE_S_NON_MANIFOLD_VERTEX":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.GE_S_NON_MANIFOLD_VERTEX;
return de.hft.stuttgart.quality.model.enums.ErrorId.GE_S_NON_MANIFOLD_VERTEX;
case "GE_S_SELF_INTERSECTION":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.GE_S_SELF_INTERSECTION;
return de.hft.stuttgart.quality.model.enums.ErrorId.GE_S_SELF_INTERSECTION;
case "GE_S_MULTIPLE_CONNECTED_COMPONENTS":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.GE_S_MULTIPLE_CONNECTED_COMPONENTS;
return de.hft.stuttgart.quality.model.enums.ErrorId.GE_S_MULTIPLE_CONNECTED_COMPONENTS;
case "SE_ATTRIBUTE_WRONG_VALUE":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.SE_ATTRIBUTE_WRONG_VALUE;
return de.hft.stuttgart.quality.model.enums.ErrorId.SE_ATTRIBUTE_WRONG_VALUE;
case "SE_ATTRIBUTE_MISSING":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.SE_ATTRIBUTE_MISSING;
return de.hft.stuttgart.quality.model.enums.ErrorId.SE_ATTRIBUTE_MISSING;
default:
return null;
// throw new IllegalStateException("Cannot map " + key + " to ADE Error Id");
}
}
......
/*-
* 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 <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.writer;
import java.io.File;
import java.time.ZonedDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import org.citygml4j.core.model.CityGMLVersion;
import org.citygml4j.core.model.core.AbstractCityObjectProperty;
import org.citygml4j.core.model.core.AbstractFeatureProperty;
import org.citygml4j.core.model.core.CityModel;
import org.citygml4j.core.util.geometry.GeometryFactory;
import org.citygml4j.xml.CityGMLContext;
import org.citygml4j.xml.writer.CityGMLOutputFactory;
import org.citygml4j.xml.writer.CityGMLWriteException;
import org.citygml4j.xml.writer.CityGMLWriter;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.ErrorId;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.exceptions.CityDoctorWriteException;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParser;
import de.hft.stuttgart.citydoctor2.utils.Localization;
import de.hft.stuttgart.citydoctor2.utils.QualityADEUtils;
import de.hft.stuttgart.quality.QualityADEModule;
import de.hft.stuttgart.quality.model.properties.ErrorProperty;
import de.hft.stuttgart.quality.model.properties.FeatureStatisticsProperty;
import de.hft.stuttgart.quality.model.properties.StatisticsProperty;
import de.hft.stuttgart.quality.model.properties.ValidationPlanProperty;
import de.hft.stuttgart.quality.model.types.FeatureStatistics;
import de.hft.stuttgart.quality.model.types.Statistics;
import de.hft.stuttgart.quality.model.types.Validation;
public class CityGMLWriterUtils {
public static void writeCityModel(String file, CityDoctorModel model) throws CityDoctorWriteException {
CityGMLContext gmlContext = CityGmlParser.getContext();
CityModel cModel = model.getCityModel();
CityGMLOutputFactory factory = gmlContext.createCityGMLOutputFactory(CityGMLVersion.v2_0);
try (CityGMLWriter writer = factory.createCityGMLWriter(new File(file))) {
writer.withIndent(" ");
writer.withDefaultPrefixes();
writer.withDefaultSchemaLocations();
Validation val = null;
if (model.isValidated()) {
writer.withPrefix("qual", QualityADEModule.NAMESPACE_URI);
writer.withSchemaLocation(QualityADEModule.NAMESPACE_URI,
QualityADEModule.NAMESPACE_URI + "/qualityAde.xsd");
// create new quality ade validation datastructures
val = createValidation(model);
// add to city model
cModel.getFeatureMembers().add(new AbstractFeatureProperty(val));
}
GeometryFactory gmlFactory = GeometryFactory.newInstance();
storeCityObjects(model.getBuildings(), gmlFactory, model, cModel, val);
storeCityObjects(model.getVegetation(), gmlFactory, model, cModel, val);
storeCityObjects(model.getBridges(), gmlFactory, model, cModel, val);
storeCityObjects(model.getLand(), gmlFactory, model, cModel, val);
storeCityObjects(model.getTransportation(), gmlFactory, model, cModel, val);
storeCityObjects(model.getWater(), gmlFactory, model, cModel, val);
writer.write(cModel);
} catch (CityGMLWriteException e) {
throw new CityDoctorWriteException(e);
}
}
private static Validation createValidation(CityDoctorModel model) {
Validation val = new Validation();
val.setId("CD" + UUID.randomUUID().toString());
val.setValidationDate(ZonedDateTime.now());
val.setValidationSoftware("CityDoctor " + Localization.getText(Localization.VERSION));
Statistics statistics = new Statistics();
Set<CheckError> errors = model.collectErrors();
Map<ErrorId, AtomicInteger> errorCount = new HashMap<>();
for (CheckError e : errors) {
errorCount.compute(e.getErrorId(), (k, v) -> {
if (v == null) {
return new AtomicInteger(1);
}
v.incrementAndGet();
return v;
});
}
for (Entry<ErrorId, AtomicInteger> e : errorCount.entrySet()) {
de.hft.stuttgart.quality.model.types.Error stats = new de.hft.stuttgart.quality.model.types.Error();
stats.setOccurrences(e.getValue().get());
de.hft.stuttgart.quality.model.enums.ErrorId adeId = QualityADEUtils.mapErrorIdToAdeId(e.getKey());
if (adeId == null) {
// error that is not part of the ade standard
continue;
}
stats.setName(adeId);
statistics.getErrors().add(new ErrorProperty(stats));
}
statistics.setNumErrorBuildings(new FeatureStatisticsProperty(countValidatedCityObjects(model.getBuildings())));
statistics.setNumErrorBridgeObjects(new FeatureStatisticsProperty(countValidatedCityObjects(model.getBridges())));
statistics.setNumErrorLandObjects(new FeatureStatisticsProperty(countValidatedCityObjects(model.getLand())));
statistics.setNumErrorTransportation(new FeatureStatisticsProperty(countValidatedCityObjects(model.getTransportation())));
statistics.setNumErrorVegetation(new FeatureStatisticsProperty(countValidatedCityObjects(model.getVegetation())));
statistics.setNumErrorWaterObjects(new FeatureStatisticsProperty(countValidatedCityObjects(model.getWater())));
val.setStatistics(new StatisticsProperty(statistics));
val.setValidationPlan(new ValidationPlanProperty(model.getValidationPlan()));
return val;
}
private static FeatureStatistics countValidatedCityObjects(List<? extends CityObject> cos) {
int numChecked = 0;
int numError = 0;
for (CityObject co : cos) {
if (co.isValidated()) {
numChecked++;
if (co.containsAnyError()) {
numError++;
}
}
}
return new FeatureStatistics(numChecked, numError);
}
private static void storeCityObjects(List<? extends CityObject> cos, GeometryFactory gmlFactory, CityDoctorModel model, CityModel cModel, Validation val) {
for (CityObject co : cos) {
if (model.isValidated() && val != null) {
QualityADEUtils.writeQualityAde(co, val);
}
co.reCreateGeometries(gmlFactory, model.getParserConfig());
cModel.getCityObjectMembers().add(new AbstractCityObjectProperty(co.getGmlObject()));
}
}
}
......@@ -97,7 +97,7 @@ WriteReportDialog.xAxisLabel=Fehler
WriteReportDialog.yAxisLabel=Anzahl
Unit.Radian=Radiant
Unit.Degree=Grad
FeatureMapper.polygonUnreferenced=Polygon {} ist referenziert wurde aber nicht in gefunden
FeatureMapper.polygonUnreferenced=Polygon {} ist referenziert wurde aber nicht gefunden
GeometryMapper.emptyPolygon=Polygon ohne externen Ring gefunden, ignoriere
CityGmlParser.parsedObjects=Modell mit {} Objekten gelesen
CityGmlParser.chunkReadFailed=Konnte Datei nicht in St\u00fccken lesen, versuche komplett zu lesen
......
......@@ -19,19 +19,21 @@
package de.hft.stuttgart.citydoctor2.check.error;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.util.Optional;
import java.util.List;
import org.junit.Test;
import de.hft.stuttgart.citydoctor2.check.QualityAdeErrorVisitor;
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.Lod;
import de.hft.stuttgart.quality.model.AllPolygonsWrongOrientation;
import de.hft.stuttgart.quality.model.ValidationError;
import de.hft.stuttgart.quality.model.properties.AbstractErrorProperty;
import de.hft.stuttgart.quality.model.types.AbstractError;
import de.hft.stuttgart.quality.model.types.AllPolygonsOrientedWrongError;
import de.hft.stuttgart.quality.model.types.ValidationResult;
public class AllPolygonsWrongOrientationErrorTest {
......@@ -41,14 +43,19 @@ public class AllPolygonsWrongOrientationErrorTest {
GmlId gmlId = new GmlId("testId");
geom.setGmlId(gmlId);
AllPolygonsWrongOrientationError err = new AllPolygonsWrongOrientationError(geom);
Optional<ValidationError> ade = err.convertToQualityAdeDatastructure();
assertNotNull(ade);
assertTrue(ade.isPresent());
ValidationError validationError = ade.get();
assertTrue(validationError instanceof AllPolygonsWrongOrientation);
AllPolygonsWrongOrientation adeErr = (AllPolygonsWrongOrientation) validationError;
ValidationResult result = new ValidationResult();
QualityAdeErrorVisitor visitor = new QualityAdeErrorVisitor(result);
err.accept(visitor);
List<AbstractErrorProperty> errors = result.getErrors();
assertEquals(1, errors.size());
AbstractError validationError = errors.get(0).getObject();
assertTrue(validationError instanceof AllPolygonsOrientedWrongError);
AllPolygonsOrientedWrongError adeErr = (AllPolygonsOrientedWrongError) validationError;
String geometryId = adeErr.getGeometryId();
assertEquals(gmlId.getGmlString(), geometryId);
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment