Commit 297334ab authored by Matthias Betz's avatar Matthias Betz
Browse files

Add design spec for OpenGL 3D view



Replaces the JavaFX SubScene/MeshView rendering with an OpenGL viewport
(openglfx-jogl, GL 3.3 core), single global VBO, GPU color-picking, and
baked fake shading. Windows/Linux targets; JavaFX 3D path removed.

Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
parents 5c2847ef bd40b396
package de.hft.stuttgart.citydoctor2.datastructure;
import java.io.Serial;
import java.util.ArrayList;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.citygml4j.core.model.core.AbstractSpaceBoundaryProperty;
import org.citygml4j.core.util.geometry.GeometryFactory;
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.CheckableVisitor;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.utils.CityGmlUtils;
import javafx.scene.paint.Color;
public class BuildingConstructiveElement extends CityObject {
private static final Logger logger = LogManager.getLogger(BuildingConstructiveElement.class);
private static final String CANNOT_ADD = "Cannot add ";
@Serial
private static final long serialVersionUID = 7353233899458901155L;
private final org.citygml4j.core.model.building.BuildingConstructiveElement gmlBuildingElement;
private final List<BoundarySurface> boundarySurfaceList = new ArrayList<>();
private AbstractBuilding parent;
public BuildingConstructiveElement(org.citygml4j.core.model.building.BuildingConstructiveElement gmlObject) {
this.gmlBuildingElement = gmlObject;
}
public void setParent(AbstractBuilding parent) {
this.parent = parent;
}
public AbstractBuilding getParent() {
return parent;
}
@Override
public Color getRenderColor() {
return parent.getRenderColor().brighter();
}
@Override
public void rebuildGeometries(GeometryFactory factory, ParserConfiguration config) {
// only handles CityGML2 for now
// unknown which CityGML is handled here
// need context information to decide
for (Geometry geom : getGeometries()) {
if (geom instanceof ImplicitGeometryHolder) {
continue;
}
switch (geom.getType()) {
case SOLID:
Solid solid = CityGmlUtils.createSolid(geom, factory, config);
setSolidAccordingToLod(geom, solid);
break;
case MULTI_SURFACE:
MultiSurface ms = CityGmlUtils.createMultiSurface(geom, factory, config);
setMultiSurfaceAccordingToLod(geom, ms);
break;
}
}
}
@Override
public void accept(CheckableVisitor c) {
super.accept(c);
if (c.canExecute(this)) {
c.check(this);
}
for (BoundarySurface bs : boundarySurfaceList) {
bs.accept(c);
}
}
private void reCreateBoundarySurface(GeometryFactory factory, ParserConfiguration config, BoundarySurface bs) {
if (bs.getGeometries().isEmpty()) {
for (AbstractSpaceBoundaryProperty bsp : gmlBuildingElement.getBoundaries()) {
if (bsp.getObject() != null && bsp.getObject() == bs.getGmlObject()) {
logger.warn("Found empty boundary surface: {}, removing from BridgeConstructiveElement", bs.getGmlId());
gmlBuildingElement.getBoundaries().remove(bsp);
break;
}
}
return;
}
bs.reCreateGeometries(factory, config);
}
private void setSolidAccordingToLod(Geometry geom, Solid solid) {
switch (geom.getLod()) {
case LOD1:
gmlBuildingElement.setLod1Solid(new SolidProperty(solid));
break;
case LOD2:
gmlBuildingElement.setLod2Solid(new SolidProperty(solid));
break;
case LOD3:
gmlBuildingElement.setLod3Solid(new SolidProperty(solid));
break;
default:
throw new IllegalStateException(CANNOT_ADD + geom.getLod() + " solid to buildings");
}
}
private void setMultiSurfaceAccordingToLod(Geometry geom, MultiSurface ms) {
switch (geom.getLod()) {
case LOD0:
gmlBuildingElement.setLod0MultiSurface(new MultiSurfaceProperty(ms));
break;
case LOD2:
gmlBuildingElement.setLod2MultiSurface(new MultiSurfaceProperty(ms));
break;
case LOD3:
gmlBuildingElement.setLod3MultiSurface(new MultiSurfaceProperty(ms));
break;
default:
throw new IllegalStateException(CANNOT_ADD + geom.getLod() + " multi surface to buildings");
}
}
@Override
public org.citygml4j.core.model.building.BuildingConstructiveElement getGmlObject() {
return gmlBuildingElement;
}
@Override
public void unsetGmlGeometries() {
gmlBuildingElement.setLod0MultiSurface(null);
gmlBuildingElement.setLod2MultiSurface(null);
gmlBuildingElement.setLod3MultiSurface(null);
gmlBuildingElement.setLod1Solid(null);
gmlBuildingElement.setLod2Solid(null);
gmlBuildingElement.setLod3Solid(null);
}
@Override
public CityObject getTopLevelCityObject() {
return getParent().getTopLevelCityObject();
}
@Override
public FeatureType getFeatureType() {
return FeatureType.BRIDGE_CONSTRUCTION_ELEMENT;
}
public void addBoundarySurface(BoundarySurface bs) {
boundarySurfaceList.add(bs);
bs.setParent(this);
}
public List<BoundarySurface> getBoundarySurfaces() {
return boundarySurfaceList;
}
}
...@@ -18,9 +18,6 @@ ...@@ -18,9 +18,6 @@
*/ */
package de.hft.stuttgart.citydoctor2.datastructure; package de.hft.stuttgart.citydoctor2.datastructure;
import de.hft.stuttgart.citydoctor2.utils.CopyHandler;
import de.hft.stuttgart.citydoctor2.utils.Copyable;
import java.io.Serial; import java.io.Serial;
public class BuildingPart extends AbstractBuilding { public class BuildingPart extends AbstractBuilding {
...@@ -42,6 +39,11 @@ public class BuildingPart extends AbstractBuilding { ...@@ -42,6 +39,11 @@ public class BuildingPart extends AbstractBuilding {
return parent; return parent;
} }
@Override
public CityObject getTopLevelCityObject() {
return getParent().getTopLevelCityObject();
}
@Override @Override
public FeatureType getFeatureType() { public FeatureType getFeatureType() {
return FeatureType.BUILDING_PART; return FeatureType.BUILDING_PART;
...@@ -52,22 +54,4 @@ public class BuildingPart extends AbstractBuilding { ...@@ -52,22 +54,4 @@ public class BuildingPart extends AbstractBuilding {
return "BuildingPart [id=" + getGmlId() + "]"; return "BuildingPart [id=" + getGmlId() + "]";
} }
@Override
public void fillValues(Copyable original, CopyHandler handler) {
super.fillValues(original, handler);
BuildingPart originalPart = (BuildingPart) original;
parent = handler.getCopyInstance(originalPart.parent);
}
@Override
public void collectInstances(CopyHandler handler) {
super.collectInstances(handler);
handler.addInstance(parent);
}
@Override
public Copyable createCopyInstance() {
return new BuildingPart();
}
} }
package de.hft.stuttgart.citydoctor2.datastructure; package de.hft.stuttgart.citydoctor2.datastructure;
import de.hft.stuttgart.citydoctor2.utils.CopyHandler; import javafx.scene.paint.Color;
import de.hft.stuttgart.citydoctor2.utils.Copyable;
import org.citygml4j.core.model.building.BuildingFurnitureProperty; import org.citygml4j.core.model.building.BuildingFurnitureProperty;
import java.io.Serial; import java.io.Serial;
...@@ -43,21 +42,12 @@ public class BuildingRoom extends AbstractRoom { ...@@ -43,21 +42,12 @@ public class BuildingRoom extends AbstractRoom {
} }
@Override @Override
public void fillValues(Copyable original, CopyHandler handler) { public CityObject getTopLevelCityObject() {
super.fillValues(original, handler); return getParent().getTopLevelCityObject();
BuildingRoom oRoom = (BuildingRoom) original;
parent = handler.getCopyInstance(oRoom.getParent());
}
@Override
public void collectInstances(CopyHandler handler) {
super.collectInstances(handler);
handler.addInstance(parent);
} }
@Override @Override
public Copyable createCopyInstance() { public Color getRenderColor() {
return new BuildingRoom(); return parent.getRenderColor();
} }
} }
package de.hft.stuttgart.citydoctor2.datastructure; package de.hft.stuttgart.citydoctor2.datastructure;
import de.hft.stuttgart.citydoctor2.utils.Copyable;
import org.citygml4j.core.model.building.BuildingFurniture; import org.citygml4j.core.model.building.BuildingFurniture;
import java.io.Serial; import java.io.Serial;
...@@ -15,10 +14,5 @@ public class BuildingRoomFurniture extends AbstractFurniture { ...@@ -15,10 +14,5 @@ public class BuildingRoomFurniture extends AbstractFurniture {
super.setGmlObject(gmlObject); super.setGmlObject(gmlObject);
} }
@Override
public Copyable createCopyInstance() {
return new BuildingRoomFurniture();
}
} }
package de.hft.stuttgart.citydoctor2.datastructure; package de.hft.stuttgart.citydoctor2.datastructure;
import de.hft.stuttgart.citydoctor2.check.Check; import de.hft.stuttgart.citydoctor2.check.CheckableVisitor;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.CheckId;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.utils.CopyHandler;
import de.hft.stuttgart.citydoctor2.utils.Copyable;
import org.citygml4j.core.util.geometry.GeometryFactory;
import java.io.Serial; import java.io.Serial;
import java.util.ArrayList; import java.util.ArrayList;
...@@ -20,110 +14,16 @@ public class BuildingUnit extends AbstractBuildingSubdivision { ...@@ -20,110 +14,16 @@ public class BuildingUnit extends AbstractBuildingSubdivision {
private final List<Storey> storeys = new ArrayList<>(); private final List<Storey> storeys = new ArrayList<>();
@Override @Override
public Copyable createCopyInstance() { public void accept(CheckableVisitor c) {
return new BuildingUnit();
}
@Override
public void unsetGmlGeometries() {
super.unsetGmlGeometries();
for (Storey storey : storeys) {
storey.unsetGmlGeometries();
}
}
@Override
public void reCreateGeometries(GeometryFactory factory, ParserConfiguration config) {
super.reCreateGeometries(factory, config);
for (Storey storey : storeys) {
storey.reCreateGeometries(factory, config);
}
}
@Override
public void accept(Check c) {
super.accept(c); super.accept(c);
for (Storey storey : storeys) { for (Storey storey : storeys) {
storey.accept(c); storey.accept(c);
} }
} }
@Override
public void collectContainedErrors(List<CheckError> errors) {
super.collectContainedErrors(errors);
for (Storey storey : storeys) {
storey.collectContainedErrors(errors);
}
}
@Override
public void clearAllContainedCheckResults() {
super.clearAllContainedCheckResults();
for (Storey storey : storeys) {
storey.clearAllContainedCheckResults();
}
}
@Override public List<Storey> getStoreys() {
public boolean containsError(CheckId checkIdentifier) { return storeys;
boolean hasError = super.containsError(checkIdentifier);
if (hasError) {
return true;
}
for (Storey storey : storeys) {
if (storey.containsError(checkIdentifier)) {
return true;
}
}
return false;
}
@Override
public boolean containsAnyError() {
boolean hasError = super.containsAnyError();
if (hasError) {
return true;
}
for (Storey storey : storeys) {
if (storey.containsAnyError()) {
return true;
}
}
return false;
}
@Override
public void prepareForChecking() {
super.prepareForChecking();
for (Storey storey : storeys) {
storey.prepareForChecking();
}
}
@Override
public void clearMetaInformation() {
super.clearMetaInformation();
for (Storey storey : storeys) {
storey.clearMetaInformation();
}
}
@Override
public void collectInstances(CopyHandler handler) {
super.collectInstances(handler);
for (Storey storey : storeys) {
storey.collectInstances(handler);
}
}
@Override
public void fillValues(Copyable original, CopyHandler handler) {
super.fillValues(original, handler);
BuildingUnit originalBu = (BuildingUnit) original;
for (Storey storey : originalBu.storeys) {
storeys.add(handler.getCopyInstance(storey));
}
this.abs = originalBu.abs;
} }
} }
...@@ -18,9 +18,10 @@ ...@@ -18,9 +18,10 @@
*/ */
package de.hft.stuttgart.citydoctor2.datastructure; package de.hft.stuttgart.citydoctor2.datastructure;
import de.hft.stuttgart.citydoctor2.check.AbstractCheck; import de.hft.stuttgart.citydoctor2.check.CheckableUtilsVisitor;
import de.hft.stuttgart.citydoctor2.check.Check;
import de.hft.stuttgart.citydoctor2.check.CheckError; import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.CheckableVisitor;
import de.hft.stuttgart.citydoctor2.database.CityObjectCache;
import de.hft.stuttgart.citydoctor2.exceptions.CityDoctorWriteException; import de.hft.stuttgart.citydoctor2.exceptions.CityDoctorWriteException;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.writer.CityGMLWriterUtils; import de.hft.stuttgart.citydoctor2.writer.CityGMLWriterUtils;
...@@ -46,15 +47,15 @@ import java.util.stream.Stream; ...@@ -46,15 +47,15 @@ import java.util.stream.Stream;
public class CityDoctorModel { public class CityDoctorModel {
private static final String COULD_NOT_FIND_FEATURE = "Could not find feature: "; private static final String COULD_NOT_FIND_FEATURE = "Could not find feature: ";
private final List<Building> buildings; private final List<GmlId> buildings;
private final List<Vegetation> vegetation; private final List<GmlId> vegetation;
private final List<BridgeObject> bridges; private final List<GmlId> bridges;
private final List<CityFurniture> cityfurniture; private final List<GmlId> cityfurniture;
private final List<GenericCityObject> genericObjects; private final List<GmlId> genericObjects;
private final List<CityObject> land; private final List<GmlId> land;
private final List<TransportationObject> roads; private final List<GmlId> roads;
private final List<Tunnel> tunnels; private final List<GmlId> tunnels;
private final List<WaterObject> water; private final List<GmlId> water;
private CityModel cModel; private CityModel cModel;
private final ParserConfiguration config; private final ParserConfiguration config;
private final String fileName; private final String fileName;
...@@ -63,11 +64,15 @@ public class CityDoctorModel { ...@@ -63,11 +64,15 @@ public class CityDoctorModel {
private boolean isValidated = false; private boolean isValidated = false;
private ValidationPlan plan; private ValidationPlan plan;
private CityGMLVersion cityGMLVersion; private CityGMLVersion cityGMLVersion;
private final CityObjectCache cache;
public CityDoctorModel(ParserConfiguration config, File file) { public CityDoctorModel(ParserConfiguration config, File file, CityObjectCache cache) {
if (config == null) { if (config == null) {
throw new IllegalArgumentException("Parser configuration may not be null"); throw new IllegalArgumentException("Parser configuration may not be null");
} }
if( file == null ) {
throw new IllegalArgumentException("File may not be null");
}
this.fileName = file.getName(); this.fileName = file.getName();
this.config = config; this.config = config;
this.file = file; this.file = file;
...@@ -81,6 +86,7 @@ public class CityDoctorModel { ...@@ -81,6 +86,7 @@ public class CityDoctorModel {
cityfurniture = new ArrayList<>(); cityfurniture = new ArrayList<>();
genericObjects = new ArrayList<>(); genericObjects = new ArrayList<>();
globalErrors = new ArrayList<>(); globalErrors = new ArrayList<>();
this.cache = cache;
} }
public boolean isValidated() { public boolean isValidated() {
...@@ -118,8 +124,59 @@ public class CityDoctorModel { ...@@ -118,8 +124,59 @@ public class CityDoctorModel {
} }
public Stream<CityObject> createFeatureStream() { public Stream<CityObject> createFeatureStream() {
return Stream.of(buildings.stream(), vegetation.stream(), bridges.stream(), land.stream(), roads.stream(), return Stream.of(getBuildings(), getVegetation(), getBridges(), getLand(), getTransportation(),
tunnels.stream(), water.stream(), cityfurniture.stream(), genericObjects.stream()).flatMap(co -> co); getTunnels(), getWater(), getCityFurniture(), getOtherCityObjects()).flatMap(co -> co);
}
public List<GmlId> getFeatureIds() {
List<GmlId> featureIds = new ArrayList<>();
featureIds.addAll(buildings);
featureIds.addAll(vegetation);
featureIds.addAll(bridges);
featureIds.addAll(land);
featureIds.addAll(roads);
featureIds.addAll(tunnels);
featureIds.addAll(water);
featureIds.addAll(cityfurniture);
featureIds.addAll(genericObjects);
return featureIds;
}
public boolean containsGmlId(String id) {
if (id == null) {
return false;
}
GmlId gmlId = new GmlId(id);
if (buildings.contains(gmlId)) {
return true;
}
if (vegetation.contains(gmlId)) {
return true;
}
if (bridges.contains(gmlId)) {
return true;
}
if (land.contains(gmlId)) {
return true;
}
if (roads.contains(gmlId)) {
return true;
}
if (tunnels.contains(gmlId)) {
return true;
}
if (water.contains(gmlId)) {
return true;
}
if (cityfurniture.contains(gmlId)) {
return true;
}
return genericObjects.contains(gmlId);
}
public void accept(CheckableVisitor visitor) {
createFeatureStream().forEach(cityObject -> cityObject.accept(visitor));
} }
public void saveAs(String file, boolean saveQualityAde) throws CityDoctorWriteException { public void saveAs(String file, boolean saveQualityAde) throws CityDoctorWriteException {
...@@ -137,6 +194,7 @@ public class CityDoctorModel { ...@@ -137,6 +194,7 @@ public class CityDoctorModel {
} }
} }
private void exportAsGML(String file) throws CityDoctorWriteException { private void exportAsGML(String file) throws CityDoctorWriteException {
CityGMLWriterUtils.writeCityModel(file, this); CityGMLWriterUtils.writeCityModel(file, this);
} }
...@@ -147,7 +205,7 @@ public class CityDoctorModel { ...@@ -147,7 +205,7 @@ public class CityDoctorModel {
folder.mkdirs(); folder.mkdirs();
createFeatureStream().forEach(co -> { createFeatureStream().forEach(co -> {
Map<Lod, Set<Polygon>> polygonMap = new EnumMap<>(Lod.class); Map<Lod, Set<Polygon>> polygonMap = new EnumMap<>(Lod.class);
Check c = new AbstractCheck() { CheckableUtilsVisitor c = new CheckableUtilsVisitor() {
@Override @Override
public void check(Geometry geom) { public void check(Geometry geom) {
...@@ -216,106 +274,201 @@ public class CityDoctorModel { ...@@ -216,106 +274,201 @@ public class CityDoctorModel {
public Set<CheckError> collectErrors() { public Set<CheckError> collectErrors() {
List<CheckError> errors = new ArrayList<>(); List<CheckError> errors = new ArrayList<>();
collectErrorsFromList(errors, buildings); createFeatureStream().forEach(cityObject -> cityObject.collectErrors(errors));
collectErrorsFromList(errors, vegetation);
collectErrorsFromList(errors, bridges);
collectErrorsFromList(errors, land);
collectErrorsFromList(errors, roads);
collectErrorsFromList(errors, tunnels);
collectErrorsFromList(errors, water);
collectErrorsFromList(errors, cityfurniture);
collectErrorsFromList(errors, genericObjects);
return new HashSet<>(errors); return new HashSet<>(errors);
} }
private void collectErrorsFromList(List<CheckError> errors, List<? extends CityObject> cos) {
for (CityObject co : cos) {
co.collectContainedErrors(errors);
}
}
public String getFileName() { public String getFileName() {
return fileName; return fileName;
} }
public void addBridge(BridgeObject coBridge) {
bridges.add(coBridge);
}
public void addBuilding(Building coBuilding) { public void addBuilding(Building coBuilding) {
buildings.add(coBuilding); buildings.add(coBuilding.getGmlId());
cache.put(coBuilding);
} }
public List<Building> getBuildings() { public void removeFeature(GmlId id){
buildings.remove(id);
vegetation.remove(id);
bridges.remove(id);
land.remove(id);
roads.remove(id);
tunnels.remove(id);
water.remove(id);
cityfurniture.remove(id);
genericObjects.remove(id);
}
public Stream<Building> getBuildings() {
return buildings.stream().map(co -> (Building) cache.get(co));
}
public List<GmlId> getBuildingIds() {
return buildings; return buildings;
} }
public List<BridgeObject> getBridges() { public int getBuildingCount(){
return buildings.size();
}
public void addBridge(BridgeObject coBridge) {
bridges.add(coBridge.getGmlId());
cache.put(coBridge);
}
public Stream<BridgeObject> getBridges() {
return bridges.stream().map(co -> (BridgeObject) cache.get(co));
}
public List<GmlId> getBridgeIds() {
return bridges; return bridges;
} }
public List<CityFurniture> getCityFurniture() { public int getBridgeCount(){
return cityfurniture; return bridges.size();
} }
public void addCityFurniture(CityFurniture coFurniture) { public void addCityFurniture(CityFurniture coFurniture) {
cityfurniture.add(coFurniture); cityfurniture.add(coFurniture.getGmlId());
cache.put(coFurniture);
}
public Stream<CityFurniture> getCityFurniture() {
return cityfurniture.stream().map(co -> (CityFurniture) cache.get(co));
}
public List<GmlId> getCityFurnitureIds() {
return cityfurniture;
}
public int getCityFurnitureCount(){
return cityfurniture.size();
}
public void addOtherCityObject(CityObject otherCityObject) {
genericObjects.add(otherCityObject.getGmlId());
cache.put(otherCityObject);
} }
public List<GenericCityObject> getGenericCityObjects() { public Stream<CityObject> getOtherCityObjects() {
return genericObjects.stream().map(cache::get);
}
public List<GmlId> getOtherCityObjectsIds() {
return genericObjects; return genericObjects;
} }
public void addGenericCityObject(GenericCityObject coGenericCityObject) { public int getOtherCityObjectsCount(){
genericObjects.add(coGenericCityObject); return genericObjects.size();
} }
public void setCityModel(CityModel cModel) { public void addTransportation(TransportationObject to) {
this.cModel = cModel; roads.add(to.getGmlId());
cache.put(to);
} }
public CityModel getCityModel() { public Stream<TransportationObject> getTransportation() {
return cModel; return roads.stream().map(co -> (TransportationObject) cache.get(co));
} }
public List<TransportationObject> getTransportation() { public List<GmlId> getTransportationIds() {
return roads; return roads;
} }
public List<Tunnel> getTunnels() { public int getTransportationCount(){
return tunnels; return roads.size();
} }
public List<WaterObject> getWater() { public void addTunnel(Tunnel tunnel) {
return water; tunnels.add(tunnel.getGmlId());
cache.put(tunnel);
} }
public List<CityObject> getLand() { public Stream<Tunnel> getTunnels() {
return land; return tunnels.stream().map(co -> (Tunnel) cache.get(co));
} }
public List<Vegetation> getVegetation() { public List<GmlId> getTunnelIds() {
return vegetation; return tunnels;
}
public int getTunnelCount(){
return tunnels.size();
} }
public void addWater(WaterObject wo) { public void addWater(WaterObject wo) {
water.add(wo); water.add(wo.getGmlId());
cache.put(wo);
}
public Stream<WaterObject> getWater() {
return water.stream().map(co -> (WaterObject) cache.get(co));
}
public List<GmlId> getWaterIds() {
return water;
}
public int getWaterCount(){
return water.size();
} }
public void addLand(LandObject lo) { public void addLand(LandObject lo) {
land.add(lo); land.add(lo.getGmlId());
cache.put(lo);
}
public void addRelief(ReliefObject relief) {
land.add(relief.getGmlId());
cache.put(relief);
}
public void addTin(TinObject tin) {
land.add(tin.getGmlId());
cache.put(tin);
}
public Stream<CityObject> getLand() {
return land.stream().map(cache::get);
}
public List<GmlId> getLandIds() {
return land;
}
public int getLandCount(){
return land.size();
} }
public void addVegetation(Vegetation veg) { public void addVegetation(Vegetation veg) {
vegetation.add(veg); vegetation.add(veg.getGmlId());
cache.put(veg);
} }
public void addTransportation(TransportationObject to) { public Stream<Vegetation> getVegetation() {
roads.add(to); return vegetation.stream().map(co -> (Vegetation) cache.get(co));
} }
public void addTunnel(Tunnel tunnel) { public List<GmlId> getVegetationIds() {
tunnels.add(tunnel); return vegetation;
}
public int getVegetationCount(){
return vegetation.size();
}
public void setCityModel(CityModel cModel) {
this.cModel = cModel;
}
public CityModel getCityModel() {
return cModel;
}
public CityObjectCache getCache(){
return cache;
} }
public int getNumberOfFeatures() { public int getNumberOfFeatures() {
...@@ -350,100 +503,109 @@ public class CityDoctorModel { ...@@ -350,100 +503,109 @@ public class CityDoctorModel {
} }
private void replaceWaterObject(CityObject currentFeature, CityObject nextFeature) { private void replaceWaterObject(CityObject currentFeature, CityObject nextFeature) {
int index = water.indexOf(currentFeature); int index = water.indexOf(currentFeature.getGmlId());
if (index == -1) { if (index == -1) {
throw new IllegalStateException(COULD_NOT_FIND_FEATURE + currentFeature + " in water objects"); throw new IllegalStateException(COULD_NOT_FIND_FEATURE + currentFeature + " in water objects");
} }
water.set(index, (WaterObject) nextFeature); cache.replace(currentFeature.getGmlId(), nextFeature);
water.set(index, nextFeature.getGmlId());
} }
private void replaceLandObject(CityObject currentFeature, CityObject nextFeature) { private void replaceLandObject(CityObject currentFeature, CityObject nextFeature) {
int index = land.indexOf(currentFeature); int index = land.indexOf(currentFeature.getGmlId());
if (index == -1) { if (index == -1) {
throw new IllegalStateException(COULD_NOT_FIND_FEATURE + currentFeature + " in land objects"); throw new IllegalStateException(COULD_NOT_FIND_FEATURE + currentFeature + " in land objects");
} }
land.set(index, nextFeature); cache.replace(currentFeature.getGmlId(), nextFeature);
land.set(index, nextFeature.getGmlId());
} }
private void replaceVegetation(CityObject currentFeature, CityObject nextFeature) { private void replaceVegetation(CityObject currentFeature, CityObject nextFeature) {
int index = vegetation.indexOf(currentFeature); int index = vegetation.indexOf(currentFeature.getGmlId());
if (index == -1) { if (index == -1) {
throw new IllegalStateException(COULD_NOT_FIND_FEATURE + currentFeature + " in vegetation"); throw new IllegalStateException(COULD_NOT_FIND_FEATURE + currentFeature + " in vegetation");
} }
vegetation.set(index, (Vegetation) nextFeature); cache.replace(currentFeature.getGmlId(), nextFeature);
vegetation.set(index, nextFeature.getGmlId());
} }
private void replaceCityFurniture(CityObject currentFeature, CityObject nextFeature) { private void replaceCityFurniture(CityObject currentFeature, CityObject nextFeature) {
int index = cityfurniture.indexOf(currentFeature); int index = cityfurniture.indexOf(currentFeature.getGmlId());
if (index == -1) { if (index == -1) {
throw new IllegalStateException(COULD_NOT_FIND_FEATURE + currentFeature + " in vegetation"); throw new IllegalStateException(COULD_NOT_FIND_FEATURE + currentFeature + " in vegetation");
} }
cityfurniture.set(index, (CityFurniture) nextFeature); cache.replace(currentFeature.getGmlId(), nextFeature);
cityfurniture.set(index, nextFeature.getGmlId());
} }
private void replaceGenericCityObject(CityObject currentFeature, CityObject nextFeature) { private void replaceGenericCityObject(CityObject currentFeature, CityObject nextFeature) {
int index = genericObjects.indexOf(currentFeature); int index = genericObjects.indexOf(currentFeature.getGmlId());
if (index == -1) { if (index == -1) {
throw new IllegalStateException(COULD_NOT_FIND_FEATURE + currentFeature + " in generic city objects"); throw new IllegalStateException(COULD_NOT_FIND_FEATURE + currentFeature + " in generic city objects");
} }
genericObjects.set(index, (GenericCityObject) nextFeature); cache.replace(currentFeature.getGmlId(), nextFeature);
genericObjects.set(index, nextFeature.getGmlId());
} }
private void replaceTransportationObject(CityObject currentFeature, CityObject nextFeature) { private void replaceTransportationObject(CityObject currentFeature, CityObject nextFeature) {
int index = roads.indexOf(currentFeature); int index = roads.indexOf(currentFeature.getGmlId());
if (index == -1) { if (index == -1) {
throw new IllegalStateException(COULD_NOT_FIND_FEATURE + currentFeature + " in transportation objects"); throw new IllegalStateException(COULD_NOT_FIND_FEATURE + currentFeature + " in transportation objects");
} }
roads.set(index, (TransportationObject) nextFeature); cache.replace(currentFeature.getGmlId(), nextFeature);
roads.set(index, nextFeature.getGmlId());
} }
private void replaceTunnel(CityObject currentFeature, CityObject nextFeature) { private void replaceTunnel(CityObject currentFeature, CityObject nextFeature) {
int index = tunnels.indexOf(currentFeature); int index = tunnels.indexOf(currentFeature.getGmlId());
if (index == -1) { if (index == -1) {
throw new IllegalStateException(COULD_NOT_FIND_FEATURE + currentFeature + " in tunnels"); throw new IllegalStateException(COULD_NOT_FIND_FEATURE + currentFeature + " in tunnels");
} }
tunnels.set(index, (Tunnel) nextFeature); cache.replace(currentFeature.getGmlId(), nextFeature);
tunnels.set(index, nextFeature.getGmlId());
} }
private void replaceBridge(CityObject currentFeature, CityObject nextFeature) { private void replaceBridge(CityObject currentFeature, CityObject nextFeature) {
int index = bridges.indexOf(currentFeature); int index = bridges.indexOf(currentFeature.getGmlId());
if (index == -1) { if (index == -1) {
throw new IllegalStateException(COULD_NOT_FIND_FEATURE + currentFeature + " in bridges"); throw new IllegalStateException(COULD_NOT_FIND_FEATURE + currentFeature + " in bridges");
} }
bridges.set(index, (BridgeObject) nextFeature); cache.replace(currentFeature.getGmlId(), nextFeature);
bridges.set(index, nextFeature.getGmlId());
} }
private void replaceBuilding(CityObject currentFeature, CityObject nextFeature) { private void replaceBuilding(CityObject currentFeature, CityObject nextFeature) {
int index = buildings.indexOf(currentFeature); int index = buildings.indexOf(currentFeature.getGmlId());
if (index == -1) { if (index == -1) {
throw new IllegalStateException(COULD_NOT_FIND_FEATURE + currentFeature + " in buildings"); throw new IllegalStateException(COULD_NOT_FIND_FEATURE + currentFeature + " in buildings");
} }
buildings.set(index, (Building) nextFeature); cache.replace(currentFeature.getGmlId(), nextFeature);
buildings.set(index, nextFeature.getGmlId());
} }
public void addCityObject(CityObject co) { public void addCityObject(CityObject co) {
if (co instanceof Building b) { if (co instanceof Building b) {
buildings.add(b); buildings.add(b.getGmlId());
} else if (co instanceof BridgeObject bo) { } else if (co instanceof BridgeObject bo) {
bridges.add(bo); bridges.add(bo.getGmlId());
} else if (co instanceof TransportationObject to) { } else if (co instanceof TransportationObject to) {
roads.add(to); roads.add(to.getGmlId());
} else if (co instanceof Tunnel tu) { } else if (co instanceof Tunnel tu) {
tunnels.add(tu); tunnels.add(tu.getGmlId());
} else if (co instanceof Vegetation veg) { } else if (co instanceof Vegetation veg) {
vegetation.add(veg); vegetation.add(veg.getGmlId());
} else if (co instanceof LandObject lo) { } else if (co instanceof LandObject lo) {
land.add(lo); land.add(lo.getGmlId());
} else if (co instanceof WaterObject wo) { } else if (co instanceof WaterObject wo) {
water.add(wo); water.add(wo.getGmlId());
} else if (co instanceof ReliefObject) { } else if (co instanceof ReliefObject) {
land.add(co); land.add(co.getGmlId());
} else if (co instanceof TinObject) { } else if (co instanceof TinObject) {
land.add(co); land.add(co.getGmlId());
} else if (co instanceof CityFurniture cf) { } else if (co instanceof CityFurniture cf) {
cityfurniture.add(cf); cityfurniture.add(cf.getGmlId());
} else if (co instanceof GenericCityObject gco) { } else if (co instanceof GenericCityObject gco) {
genericObjects.add(gco); genericObjects.add(gco.getGmlId());
} }
} }
...@@ -455,11 +617,4 @@ public class CityDoctorModel { ...@@ -455,11 +617,4 @@ public class CityDoctorModel {
return cityGMLVersion; return cityGMLVersion;
} }
public void addRelief(ReliefObject relief) {
addCityObject(relief);
}
public void addTin(TinObject tin) {
addCityObject(tin);
}
} }
package de.hft.stuttgart.citydoctor2.datastructure; package de.hft.stuttgart.citydoctor2.datastructure;
import de.hft.stuttgart.citydoctor2.check.Check; import de.hft.stuttgart.citydoctor2.check.CheckableVisitor;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.utils.CityGmlUtils; import de.hft.stuttgart.citydoctor2.utils.CityGmlUtils;
import de.hft.stuttgart.citydoctor2.utils.CopyHandler; import javafx.scene.paint.Color;
import de.hft.stuttgart.citydoctor2.utils.Copyable;
import org.citygml4j.core.model.core.AbstractCityObject; import org.citygml4j.core.model.core.AbstractCityObject;
import org.citygml4j.core.util.geometry.GeometryFactory; import org.citygml4j.core.util.geometry.GeometryFactory;
import org.xmlobjects.gml.model.geometry.aggregates.MultiSurface; import org.xmlobjects.gml.model.geometry.aggregates.MultiSurface;
...@@ -22,7 +21,7 @@ public class CityFurniture extends CityObject { ...@@ -22,7 +21,7 @@ public class CityFurniture extends CityObject {
private org.citygml4j.core.model.cityfurniture.CityFurniture cgmlCityFurniture; private org.citygml4j.core.model.cityfurniture.CityFurniture cgmlCityFurniture;
@Override @Override
public void accept(Check c) { public void accept(CheckableVisitor c) {
super.accept(c); super.accept(c);
if (c.canExecute(this)) { if (c.canExecute(this)) {
c.check(this); c.check(this);
...@@ -35,6 +34,11 @@ public class CityFurniture extends CityObject { ...@@ -35,6 +34,11 @@ public class CityFurniture extends CityObject {
return cgmlCityFurniture; return cgmlCityFurniture;
} }
@Override
public Color getRenderColor() {
return Color.THISTLE;
}
public void setGmlObject(org.citygml4j.core.model.cityfurniture.CityFurniture gmlCityFurniture) { public void setGmlObject(org.citygml4j.core.model.cityfurniture.CityFurniture gmlCityFurniture) {
cgmlCityFurniture = gmlCityFurniture; cgmlCityFurniture = gmlCityFurniture;
} }
...@@ -47,11 +51,19 @@ public class CityFurniture extends CityObject { ...@@ -47,11 +51,19 @@ public class CityFurniture extends CityObject {
cgmlCityFurniture.setLod1Solid(null); cgmlCityFurniture.setLod1Solid(null);
cgmlCityFurniture.setLod2Solid(null); cgmlCityFurniture.setLod2Solid(null);
cgmlCityFurniture.setLod3Solid(null); cgmlCityFurniture.setLod3Solid(null);
cgmlCityFurniture.getDeprecatedProperties().setLod1Geometry(null);
cgmlCityFurniture.getDeprecatedProperties().setLod2Geometry(null);
cgmlCityFurniture.getDeprecatedProperties().setLod3Geometry(null);
cgmlCityFurniture.getDeprecatedProperties().setLod4Geometry(null); cgmlCityFurniture.getDeprecatedProperties().setLod4Geometry(null);
} }
@Override @Override
public void reCreateGeometries(GeometryFactory factory, ParserConfiguration config) { public CityObject getTopLevelCityObject() {
return this;
}
@Override
public void rebuildGeometries(GeometryFactory factory, ParserConfiguration config) {
for (Geometry geom : getGeometries()) { for (Geometry geom : getGeometries()) {
if (geom instanceof ImplicitGeometryHolder) { if (geom instanceof ImplicitGeometryHolder) {
continue; continue;
...@@ -71,12 +83,18 @@ public class CityFurniture extends CityObject { ...@@ -71,12 +83,18 @@ public class CityFurniture extends CityObject {
case LOD0: case LOD0:
cgmlCityFurniture.setLod0MultiSurface(new MultiSurfaceProperty(ms)); cgmlCityFurniture.setLod0MultiSurface(new MultiSurfaceProperty(ms));
break; break;
case LOD1:
cgmlCityFurniture.getDeprecatedProperties().setLod1Geometry(new MultiSurfaceProperty(ms));
break;
case LOD2: case LOD2:
cgmlCityFurniture.setLod2MultiSurface(new MultiSurfaceProperty(ms)); cgmlCityFurniture.setLod2MultiSurface(new MultiSurfaceProperty(ms));
break; break;
case LOD3: case LOD3:
cgmlCityFurniture.setLod3MultiSurface(new MultiSurfaceProperty(ms)); cgmlCityFurniture.setLod3MultiSurface(new MultiSurfaceProperty(ms));
break; break;
case LOD4:
cgmlCityFurniture.getDeprecatedProperties().setLod4Geometry(new MultiSurfaceProperty(ms));
break;
default: default:
throw new IllegalStateException("Cannot add " + geom.getLod() + " multi surface to buildings"); throw new IllegalStateException("Cannot add " + geom.getLod() + " multi surface to buildings");
} }
...@@ -93,6 +111,8 @@ public class CityFurniture extends CityObject { ...@@ -93,6 +111,8 @@ public class CityFurniture extends CityObject {
case LOD3: case LOD3:
cgmlCityFurniture.setLod3Solid(new SolidProperty(solid)); cgmlCityFurniture.setLod3Solid(new SolidProperty(solid));
break; break;
case LOD4:
cgmlCityFurniture.getDeprecatedProperties().setLod4Geometry(new SolidProperty(solid));
default: default:
throw new IllegalStateException("Cannot add " + geom.getLod() + " solid to buildings"); throw new IllegalStateException("Cannot add " + geom.getLod() + " solid to buildings");
} }
...@@ -103,15 +123,4 @@ public class CityFurniture extends CityObject { ...@@ -103,15 +123,4 @@ public class CityFurniture extends CityObject {
return FeatureType.CITY_FURNITURE; return FeatureType.CITY_FURNITURE;
} }
@Override
public Copyable createCopyInstance() {
return new CityFurniture();
}
@Override
public void fillValues(Copyable original, CopyHandler handler) {
super.fillValues(original, handler);
CityFurniture originalCF = (CityFurniture) original;
cgmlCityFurniture = originalCF.cgmlCityFurniture;
}
} }
...@@ -18,12 +18,11 @@ ...@@ -18,12 +18,11 @@
*/ */
package de.hft.stuttgart.citydoctor2.datastructure; package de.hft.stuttgart.citydoctor2.datastructure;
import de.hft.stuttgart.citydoctor2.check.Check; import de.hft.stuttgart.citydoctor2.check.CheckableVisitor;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.CheckId;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.utils.CopyHandler; import de.hft.stuttgart.citydoctor2.utils.visitors.GmlGeometryRebuilder;
import de.hft.stuttgart.citydoctor2.utils.Copyable; import de.hft.stuttgart.citydoctor2.utils.visitors.UnsetGeometriesVisitor;
import javafx.scene.paint.Color;
import org.citygml4j.core.model.core.AbstractCityObject; import org.citygml4j.core.model.core.AbstractCityObject;
import org.citygml4j.core.util.geometry.GeometryFactory; import org.citygml4j.core.util.geometry.GeometryFactory;
...@@ -44,20 +43,30 @@ public abstract class CityObject extends GmlElement { ...@@ -44,20 +43,30 @@ public abstract class CityObject extends GmlElement {
@Serial @Serial
private static final long serialVersionUID = 651712070755024188L; private static final long serialVersionUID = 651712070755024188L;
private BoundingBox bbox;
private final List<Geometry> geometryList = new ArrayList<>(); private final List<Geometry> geometryList = new ArrayList<>();
private final List<GenericAttribute> genericAttributeList = new ArrayList<>(); private final List<GenericAttribute> genericAttributeList = new ArrayList<>();
/**
* Recreates the CityGML4j geometry in this object's datastructure using the CityDoctor geometries.
* The original CityGML4j geometry is deleted after parsing to reduce the memory overhead of {@link CityObject CityObjects}.
* <p/>
* Recreation of the geometries is needed for writing validation results to the QualityADE, as well as for the export
* of repaired geometries from CityDoctor's internal datastructure.
* @param factory the GeometryFactory used for creation of CityGml4j geometry objects
* @param config the configuration settings of the parser
*/
public final void reCreateGeometries(GeometryFactory factory, ParserConfiguration config) {
this.accept(new GmlGeometryRebuilder(factory, config));
}
/** /**
* Recreates the CityGML4j geometry in this object. The CityGML4j geometry is * Rebuilds the CityGML4j geometries of this object.
* deleted from the data structure as was mapped to the city doctor data
* structure. For writing CityGML files the geometry has to be restored. Also
* maps changes to geometry back to CityGML4j
* *
* @param factory needed to create CityGML4j data structures * @param factory the GeometryFactory used for creation of CityGml4j geometry objects
* @param config contains information whether a city doctor point was * @param config the configuration settings of the parser
* transformed to a different coordinate system. It would need to
* be transformed to the original coordinate system
*/ */
public abstract void reCreateGeometries(GeometryFactory factory, ParserConfiguration config); public abstract void rebuildGeometries(GeometryFactory factory, ParserConfiguration config);
/** /**
* Getter for the CityGML4j data object * Getter for the CityGML4j data object
...@@ -67,29 +76,69 @@ public abstract class CityObject extends GmlElement { ...@@ -67,29 +76,69 @@ public abstract class CityObject extends GmlElement {
public abstract AbstractCityObject getGmlObject(); public abstract AbstractCityObject getGmlObject();
/** /**
* Remove the CityGML4j geometries from the data structure to save memory. * Remove the CityGML4j geometries from this CityObject to reduce memory overhead.
*/ */
public abstract void unsetGmlGeometries(); public abstract void unsetGmlGeometries();
/**
* Removes all CityGML4J geometries from this CityObject and child objects of its datastructure to reduce
* the memory overhead.
*/
public final void clearGmlGeometries() {
this.accept(new UnsetGeometriesVisitor());
}
public void setBbox(BoundingBox bbox){
this.bbox = bbox;
}
public synchronized BoundingBox getBbox(){
if (bbox == null){
this.setBbox(BoundingBox.of(this));
}
return bbox;
}
/**
* Adds a Geometry to this object.
* @param geom the Geometry to add.
*/
public void addGeometry(Geometry geom) { public void addGeometry(Geometry geom) {
Objects.requireNonNull(geom); Objects.requireNonNull(geom);
geometryList.add(geom); geometryList.add(geom);
geom.setParent(this); geom.setParent(this);
} }
/**
* Returns all Geometries of this object.
* @return a list of the Geometries.
*/
public List<Geometry> getGeometries() { public List<Geometry> getGeometries() {
return geometryList; return geometryList;
} }
/**
* Removes a Geometry from this object.
* @param lod the {@link Lod} of the Geometry.
*/
public void removeGeometry(Lod lod) { public void removeGeometry(Lod lod) {
geometryList.removeIf(geom -> geom.getLod() == lod); geometryList.removeIf(geom -> geom.getLod() == lod);
} }
/**
* Removes a Geometry from this object.
* @param lod the {@link Lod} of the Geometry.
* @param type the {@link GeometryType} of the Geometry.
*/
public void removeGeometry(Lod lod, GeometryType type) { public void removeGeometry(Lod lod, GeometryType type) {
geometryList.removeIf(geom -> geom.getLod() == lod && geom.getType() == type); geometryList.removeIf(geom -> geom.getLod() == lod && geom.getType() == type);
} }
/**
* Returns the Geometry with the highest LOD of this object. If multiple Geometries share the highest LOD, the one
* that was added first will be returned.
* @return the Geometry with the highest LOD
*/
public Geometry getHighestLodGeometry() { public Geometry getHighestLodGeometry() {
Geometry highestLodGeometry = null; Geometry highestLodGeometry = null;
Lod highestLod = null; Lod highestLod = null;
...@@ -102,18 +151,52 @@ public abstract class CityObject extends GmlElement { ...@@ -102,18 +151,52 @@ public abstract class CityObject extends GmlElement {
return highestLodGeometry; return highestLodGeometry;
} }
/**
* Returns the top-level CityObject (e.g. Building, Tunnel, Vegetation etc.) belonging to this object.
*/
public abstract CityObject getTopLevelCityObject();
/**
* Returns a String representation of this object for display in the featuretab TreeViews in the format of
* "[FeatureType] Gml-ID"
* @return the String representation.
*/
public String getDisplayText() {
return String.format("[%s] %s", this.getClass().getSimpleName(), this.getGmlId().toString());
}
/**
* Returns the color for rendering of this object's polygons.
* @return color for this object
*/
public Color getRenderColor() {
return Color.WHITE;
}
/**
* Adds a GenericAttribute to this object.
* @param genericAttribute the attribute to add.
*/
public void addGenericAttribute(GenericAttribute genericAttribute) { public void addGenericAttribute(GenericAttribute genericAttribute) {
genericAttributeList.add(genericAttribute); genericAttributeList.add(genericAttribute);
} }
/**
* Returns all GenericAttributes of this object.
* @return a list of the GenericAttributes.
*/
public List<GenericAttribute> getGenericAttributes() { public List<GenericAttribute> getGenericAttributes() {
return genericAttributeList; return genericAttributeList;
} }
/**
* Returns the CityGML FeatureType of this object.
* @return this object's FeatureType.
*/
public abstract FeatureType getFeatureType(); public abstract FeatureType getFeatureType();
@Override @Override
public void accept(Check c) { public void accept(CheckableVisitor c) {
super.accept(c); super.accept(c);
if (c.canExecute(this)) { if (c.canExecute(this)) {
c.check(this); c.check(this);
...@@ -123,50 +206,6 @@ public abstract class CityObject extends GmlElement { ...@@ -123,50 +206,6 @@ public abstract class CityObject extends GmlElement {
} }
} }
@Override
public boolean containsError(CheckId checkIdentifier) {
boolean hasError = super.containsError(checkIdentifier);
if (hasError) {
return true;
}
for (Geometry geom : geometryList) {
if (geom.containsError(checkIdentifier)) {
return true;
}
}
return false;
}
@Override
public void clearAllContainedCheckResults() {
super.clearCheckResults();
for (Geometry geom : geometryList) {
geom.clearAllContainedCheckResults();
}
}
@Override
public void collectContainedErrors(List<CheckError> errors) {
super.collectContainedErrors(errors);
for (Geometry geom : geometryList) {
geom.collectContainedErrors(errors);
}
}
@Override
public boolean containsAnyError() {
boolean hasError = super.containsAnyError();
if (hasError) {
return true;
}
for (Geometry geom : geometryList) {
if (geom.containsAnyError()) {
return true;
}
}
return false;
}
public Geometry getGeometry(GeometryType type, Lod lod) { public Geometry getGeometry(GeometryType type, Lod lod) {
for (Geometry geom : geometryList) { for (Geometry geom : geometryList) {
if (geom.getType() == type && geom.getLod() == lod) { if (geom.getType() == type && geom.getLod() == lod) {
...@@ -176,33 +215,5 @@ public abstract class CityObject extends GmlElement { ...@@ -176,33 +215,5 @@ public abstract class CityObject extends GmlElement {
return null; return null;
} }
@Override
public void prepareForChecking() {
for (Geometry geom : geometryList) {
geom.prepareForChecking();
}
}
@Override
public void clearMetaInformation() {
for (Geometry geom : geometryList) {
geom.clearMetaInformation();
}
}
@Override
public void collectInstances(CopyHandler handler) {
for (Geometry geom : geometryList) {
handler.addInstance(geom);
}
}
@Override
public void fillValues(Copyable original, CopyHandler handler) {
super.fillValues(original, handler);
CityObject originalCo = (CityObject) original;
for (Geometry geom : originalCo.geometryList) {
geometryList.add(handler.getCopyInstance(geom));
}
}
} }
...@@ -2,6 +2,7 @@ package de.hft.stuttgart.citydoctor2.datastructure; ...@@ -2,6 +2,7 @@ package de.hft.stuttgart.citydoctor2.datastructure;
import java.io.Serial; import java.io.Serial;
import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
...@@ -9,7 +10,7 @@ import java.util.List; ...@@ -9,7 +10,7 @@ import java.util.List;
* *
* @author Riegel * @author Riegel
*/ */
public final class CompositeCollection { public final class CompositeCollection implements Serializable {
@Serial @Serial
private static final long serialVersionUID = -1867197873443341287L; private static final long serialVersionUID = -1867197873443341287L;
...@@ -31,6 +32,7 @@ public final class CompositeCollection { ...@@ -31,6 +32,7 @@ public final class CompositeCollection {
return childComposites; return childComposites;
} }
//TODO stream
public List<ConcretePolygon> getCompositeMembers() { public List<ConcretePolygon> getCompositeMembers() {
List<ConcretePolygon> copy = new ArrayList<>(compositeMembers); List<ConcretePolygon> copy = new ArrayList<>(compositeMembers);
for (CompositeCollection c : childComposites) { for (CompositeCollection c : childComposites) {
......
...@@ -18,15 +18,12 @@ ...@@ -18,15 +18,12 @@
*/ */
package de.hft.stuttgart.citydoctor2.datastructure; package de.hft.stuttgart.citydoctor2.datastructure;
import de.hft.stuttgart.citydoctor2.check.Check;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.CheckId;
import de.hft.stuttgart.citydoctor2.check.Checkable; import de.hft.stuttgart.citydoctor2.check.Checkable;
import de.hft.stuttgart.citydoctor2.check.CheckableVisitor;
import de.hft.stuttgart.citydoctor2.math.Vector3d; import de.hft.stuttgart.citydoctor2.math.Vector3d;
import de.hft.stuttgart.citydoctor2.tesselation.JoglTesselator; import de.hft.stuttgart.citydoctor2.tesselation.JoglTesselator;
import de.hft.stuttgart.citydoctor2.tesselation.TesselatedPolygon; import de.hft.stuttgart.citydoctor2.tesselation.TesselatedPolygon;
import de.hft.stuttgart.citydoctor2.utils.CopyHandler; import javafx.scene.paint.Color;
import de.hft.stuttgart.citydoctor2.utils.Copyable;
import java.io.Serial; import java.io.Serial;
import java.util.ArrayList; import java.util.ArrayList;
...@@ -50,6 +47,7 @@ public class ConcretePolygon extends Polygon { ...@@ -50,6 +47,7 @@ public class ConcretePolygon extends Polygon {
private BoundarySurface partOfSurface; private BoundarySurface partOfSurface;
private Installation partfOfInstallation; private Installation partfOfInstallation;
private CompositeCollection partOfComposite = null; private CompositeCollection partOfComposite = null;
private PatchCollection partOfPatch = null;
private Geometry parent; private Geometry parent;
private LinkedPolygon linkedFromPolygon; private LinkedPolygon linkedFromPolygon;
...@@ -141,6 +139,18 @@ public class ConcretePolygon extends Polygon { ...@@ -141,6 +139,18 @@ public class ConcretePolygon extends Polygon {
this.partOfComposite = comp; this.partOfComposite = comp;
} }
protected void setPartOfPatch(PatchCollection pc) {
this.partOfPatch = pc;
}
public PatchCollection getPartOfPatch(PatchCollection pc) {
return partOfPatch;
}
public boolean isPatchMember() {
return partOfPatch != null;
}
public CompositeCollection getPartOfComposite() { public CompositeCollection getPartOfComposite() {
return partOfComposite; return partOfComposite;
} }
...@@ -170,7 +180,8 @@ public class ConcretePolygon extends Polygon { ...@@ -170,7 +180,8 @@ public class ConcretePolygon extends Polygon {
* citydoctor2.check.Check) * citydoctor2.check.Check)
*/ */
@Override @Override
public void accept(Check c) { public void accept(CheckableVisitor c) {
super.accept(c);
if (c.canExecute(this)) { if (c.canExecute(this)) {
c.check(this); c.check(this);
} }
...@@ -182,7 +193,6 @@ public class ConcretePolygon extends Polygon { ...@@ -182,7 +193,6 @@ public class ConcretePolygon extends Polygon {
lr.accept(c); lr.accept(c);
} }
} }
setValidated(true);
} }
@Override @Override
...@@ -202,93 +212,6 @@ public class ConcretePolygon extends Polygon { ...@@ -202,93 +212,6 @@ public class ConcretePolygon extends Polygon {
return exterior.isRingConnectedViaPoint(other.getExteriorRing()); return exterior.isRingConnectedViaPoint(other.getExteriorRing());
} }
/*
* (non-Javadoc)
*
* @see de.hft.stuttgart.citydoctor2.datastructure.Polygon#containsAnyError()
*/
@Override
public boolean containsAnyError() {
if (super.containsAnyError()) {
return true;
}
if (exterior != null && exterior.containsAnyError()) {
return true;
}
if (innerRings != null) {
for (LinearRing lr : innerRings) {
if (lr.containsAnyError()) {
return true;
}
}
}
return false;
}
/*
* (non-Javadoc)
*
* @see
* de.hft.stuttgart.citydoctor2.datastructure.Polygon#collectContainedErrors(
* java.util.List)
*/
@Override
public void collectContainedErrors(List<CheckError> errors) {
super.collectContainedErrors(errors);
if (exterior != null) {
exterior.collectContainedErrors(errors);
}
if (innerRings != null) {
for (LinearRing lr : innerRings) {
lr.collectContainedErrors(errors);
}
}
}
/*
* (non-Javadoc)
*
* @see de.hft.stuttgart.citydoctor2.datastructure.Polygon#
* clearAllContainedCheckResults()
*/
@Override
public void clearAllContainedCheckResults() {
super.clearCheckResults();
if (exterior != null) {
exterior.clearAllContainedCheckResults();
}
if (innerRings != null) {
for (LinearRing lr : innerRings) {
lr.clearAllContainedCheckResults();
}
}
}
/*
* (non-Javadoc)
*
* @see de.hft.stuttgart.citydoctor2.datastructure.Polygon#containsError(de.hft.
* stuttgart.citydoctor2.check.CheckId)
*/
@Override
public boolean containsError(CheckId checkIdentifier) {
boolean hasError = super.containsError(checkIdentifier);
if (hasError) {
return true;
}
if (exterior != null && exterior.containsError(checkIdentifier)) {
return true;
}
if (innerRings != null) {
for (LinearRing lr : innerRings) {
if (lr.containsError(checkIdentifier)) {
return true;
}
}
}
return false;
}
/* /*
* (non-Javadoc) * (non-Javadoc)
* *
...@@ -466,51 +389,10 @@ public class ConcretePolygon extends Polygon { ...@@ -466,51 +389,10 @@ public class ConcretePolygon extends Polygon {
} }
@Override @Override
public void prepareForChecking() { public void prepareLowMemoryUsageMode() {
parent.prepareForChecking(); parent.updateEdgesAndVertices();
}
@Override
public void clearMetaInformation() {
parent.clearMetaInformation();
}
@Override
public void collectInstances(CopyHandler handler) {
handler.addInstance(exterior);
if (innerRings != null) {
for (LinearRing lr : innerRings) {
handler.addInstance(lr);
}
}
handler.addInstance(partOfSurface);
handler.addInstance(partfOfInstallation);
handler.addInstance(parent);
handler.addInstance(linkedFromPolygon);
} }
@Override
public Copyable createCopyInstance() {
return new ConcretePolygon();
}
@Override
public void fillValues(Copyable original, CopyHandler handler) {
super.fillValues(original, handler);
ConcretePolygon originalPoly = (ConcretePolygon) original;
exterior = handler.getCopyInstance(originalPoly.exterior);
if (originalPoly.innerRings != null) {
innerRings = new ArrayList<>(originalPoly.innerRings.size());
for (LinearRing originalRing : originalPoly.innerRings) {
innerRings.add(handler.getCopyInstance(originalRing));
}
}
parent = handler.getCopyInstance(originalPoly.parent);
partfOfInstallation = handler.getCopyInstance(originalPoly.partfOfInstallation);
partOfSurface = handler.getCopyInstance(originalPoly.partOfSurface);
linkedFromPolygon = handler.getCopyInstance(originalPoly.linkedFromPolygon);
}
@Override @Override
public void remove() { public void remove() {
...@@ -531,6 +413,11 @@ public class ConcretePolygon extends Polygon { ...@@ -531,6 +413,11 @@ public class ConcretePolygon extends Polygon {
} }
return area; return area;
} }
@Override
public Color getRenderColor() {
return parent.getRenderColor();
}
......
...@@ -18,9 +18,6 @@ ...@@ -18,9 +18,6 @@
*/ */
package de.hft.stuttgart.citydoctor2.datastructure; package de.hft.stuttgart.citydoctor2.datastructure;
import de.hft.stuttgart.citydoctor2.utils.CopyHandler;
import de.hft.stuttgart.citydoctor2.utils.Copyable;
import java.io.Serial; import java.io.Serial;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
...@@ -31,7 +28,7 @@ import java.util.List; ...@@ -31,7 +28,7 @@ import java.util.List;
* *
* @author Matthias Betz * @author Matthias Betz
*/ */
public class Edge implements Serializable, Copyable { public class Edge implements Serializable {
@Serial @Serial
private static final long serialVersionUID = -504694863498128296L; private static final long serialVersionUID = -504694863498128296L;
...@@ -51,9 +48,6 @@ public class Edge implements Serializable, Copyable { ...@@ -51,9 +48,6 @@ public class Edge implements Serializable, Copyable {
this.to = to; this.to = to;
} }
private Edge() {
}
public Vertex getFrom() { public Vertex getFrom() {
return from; return from;
} }
...@@ -186,33 +180,7 @@ public class Edge implements Serializable, Copyable { ...@@ -186,33 +180,7 @@ public class Edge implements Serializable, Copyable {
} }
return null; return null;
} }
}
@Override
public void collectInstances(CopyHandler handler) {
handler.addInstance(from);
handler.addInstance(to);
handler.addInstance(adjacentPolygons);
handler.addInstance(adjacentRings);
}
@Override
public Copyable createCopyInstance() {
return new Edge();
}
@Override
public void fillValues(Copyable original, CopyHandler handler) {
Edge originalEdge = (Edge) original;
from = handler.getCopyInstance(originalEdge.from);
to = handler.getCopyInstance(originalEdge.to);
numberOfHalfEdges = originalEdge.numberOfHalfEdges;
numberOfOppositeHalfEdges = originalEdge.numberOfOppositeHalfEdges;
for (Polygon originalPoly : originalEdge.adjacentPolygons) {
adjacentPolygons.add(handler.getCopyInstance(originalPoly));
}
for (LinearRing originalRing : originalEdge.adjacentRings) {
adjacentRings.add(handler.getCopyInstance(originalRing));
}
}
}
...@@ -27,5 +27,5 @@ public enum FeatureType { ...@@ -27,5 +27,5 @@ public enum FeatureType {
BUILDING, TRANSPORTATION, VEGETATION, BRIDGE, LAND, WATER, BOUNDARY_SURFACE, INSTALLATION, OPENING, BUILDING, TRANSPORTATION, VEGETATION, BRIDGE, LAND, WATER, BOUNDARY_SURFACE, INSTALLATION, OPENING,
BUILDING_PART, BUILDING_SUBDIVISION, BRIDGE_CONSTRUCTION_ELEMENT, BRIDGE_INSTALLATION, ROOM, FURNITURE, CITY_FURNITURE, BUILDING_PART, BUILDING_SUBDIVISION, BRIDGE_CONSTRUCTION_ELEMENT, BRIDGE_INSTALLATION, ROOM, FURNITURE, CITY_FURNITURE,
GENERIC_CITY_OBJECT, TUNNEL, TUNNEL_PART, TUNNEL_CONSTRUCTION_ELEMENT, TUNNEL_INSTALLATION, OTHER_CITY_OBJECT, TUNNEL, TUNNEL_PART, TUNNEL_CONSTRUCTION_ELEMENT, TUNNEL_INSTALLATION,
} }
...@@ -5,10 +5,21 @@ import org.apache.logging.log4j.Logger; ...@@ -5,10 +5,21 @@ import org.apache.logging.log4j.Logger;
import org.citygml4j.core.model.core.AbstractGenericAttributeProperty; import org.citygml4j.core.model.core.AbstractGenericAttributeProperty;
import org.citygml4j.core.model.generics.*; import org.citygml4j.core.model.generics.*;
import java.io.Serial;
import java.io.Serializable;
public class GenericAttribute { import java.util.List;
import java.util.StringJoiner;
import java.util.function.Supplier;
public class GenericAttribute implements Serializable {
@Serial
private static final long serialVersionUID = -4101408947632132328L;
private static final Logger logger = LogManager.getLogger(GenericAttribute.class); private static final Logger logger = LogManager.getLogger(GenericAttribute.class);
private static final String NULL_VALUE_STRING= "NULL OR INVALID VALUE";
private final AbstractGenericAttributeProperty original; private final AbstractGenericAttributeProperty original;
...@@ -16,6 +27,7 @@ public class GenericAttribute { ...@@ -16,6 +27,7 @@ public class GenericAttribute {
private String name; private String name;
private String value; private String value;
public GenericAttribute(AbstractGenericAttributeProperty attributeProperty) { public GenericAttribute(AbstractGenericAttributeProperty attributeProperty) {
original = attributeProperty; original = attributeProperty;
if (attributeProperty.getObject() == null) { if (attributeProperty.getObject() == null) {
...@@ -26,25 +38,43 @@ public class GenericAttribute { ...@@ -26,25 +38,43 @@ public class GenericAttribute {
if (attributeProperty.getObject() instanceof StringAttribute sa) { if (attributeProperty.getObject() instanceof StringAttribute sa) {
type = "StringAttribute"; type = "StringAttribute";
value = sa.getValue(); value = extractValue(() -> String.format("\"%s\"", sa.getValue()));
} else if (attributeProperty.getObject() instanceof IntAttribute ia) { } else if (attributeProperty.getObject() instanceof IntAttribute ia) {
type = "IntAttribute"; type = "IntAttribute";
value = ia.getValue().toString(); value = extractValue(() -> ia.getValue().toString());
} else if (attributeProperty.getObject() instanceof DoubleAttribute da) { } else if (attributeProperty.getObject() instanceof DoubleAttribute da) {
type = "DoubleAttribute"; type = "DoubleAttribute";
value = da.getValue().toString(); value = extractValue(() -> da.getValue().toString());
} else if (attributeProperty.getObject() instanceof DateAttribute date) { } else if (attributeProperty.getObject() instanceof DateAttribute date) {
type = "DateAttribute"; type = "DateAttribute";
value = date.getValue().toString(); value = extractValue(() -> date.getValue().toString());
} else if (attributeProperty.getObject() instanceof UriAttribute ua) { } else if (attributeProperty.getObject() instanceof UriAttribute ua) {
type = "UriAttribute"; type = "UriAttribute";
value = ua.getValue(); value = extractValue(ua::getValue);
} else if (attributeProperty.getObject() instanceof MeasureAttribute ma) { } else if (attributeProperty.getObject() instanceof MeasureAttribute ma) {
type = "MeasureAttribute"; type = "MeasureAttribute";
value = ma.getValue().toString(); value = extractValue(() ->
String.format("%s %s", ma.getValue().getValue().toString(), ma.getValue().getUom()));
} else if (attributeProperty.getObject() instanceof CodeAttribute ca) { } else if (attributeProperty.getObject() instanceof CodeAttribute ca) {
type = "CodeAttribute"; type = String.format("CodeAttribute (%s)", ca.getValue().getLanguage());
value = ca.getValue().toString(); value = extractValue(() ->
String.format("'''%s''' %n CodeSpace: %s", ca.getValue().getValue(), ca.getValue().getCodeSpace()));
} else if (attributeProperty.getObject() instanceof GenericAttributeSet gas) {
type = "GenericAttributeSet";
List<AbstractGenericAttributeProperty> attributes = gas.getValue();
if(attributes == null || attributes.isEmpty()){
value = NULL_VALUE_STRING;
return;
}
StringJoiner sj = new StringJoiner("; ","{","}");
sj.setEmptyValue("EMPTY_SET");
for (AbstractGenericAttributeProperty attribute : attributes) {
if (attribute.getObject() != null) {
sj.add(String.format("%1$s = %2$s",attribute.getObject().getName(), attribute.getObject().getValue()));
}
}
value = sj.toString();
} else { } else {
logger.warn("GenericAttribute {} is of unknown type {}", attributeProperty, attributeProperty.getObject()); logger.warn("GenericAttribute {} is of unknown type {}", attributeProperty, attributeProperty.getObject());
value = attributeProperty.getObject().getValue().toString(); value = attributeProperty.getObject().getValue().toString();
...@@ -53,6 +83,14 @@ public class GenericAttribute { ...@@ -53,6 +83,14 @@ public class GenericAttribute {
} }
private String extractValue(Supplier<String> supply){
try{
return supply.get();
}catch (NullPointerException e){
return NULL_VALUE_STRING;
}
}
public AbstractGenericAttributeProperty getOriginal() { public AbstractGenericAttributeProperty getOriginal() {
return original; return original;
} }
......
package de.hft.stuttgart.citydoctor2.datastructure; package de.hft.stuttgart.citydoctor2.datastructure;
import de.hft.stuttgart.citydoctor2.check.Check; import de.hft.stuttgart.citydoctor2.check.CheckableVisitor;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.CheckId;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.utils.CityGmlUtils; import de.hft.stuttgart.citydoctor2.utils.CityGmlUtils;
import de.hft.stuttgart.citydoctor2.utils.CopyHandler; import javafx.scene.paint.Color;
import de.hft.stuttgart.citydoctor2.utils.Copyable;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.citygml4j.core.model.core.AbstractCityObject; import org.citygml4j.core.model.core.AbstractCityObject;
...@@ -36,7 +33,7 @@ public class GenericCityObject extends CityObject { ...@@ -36,7 +33,7 @@ public class GenericCityObject extends CityObject {
private final List<BoundarySurface> boundarySurfaceList = new ArrayList<>(); private final List<BoundarySurface> boundarySurfaceList = new ArrayList<>();
@Override @Override
public void accept(Check c) { public void accept(CheckableVisitor c) {
super.accept(c); super.accept(c);
if (c.canExecute(this)) { if (c.canExecute(this)) {
c.check(this); c.check(this);
...@@ -47,7 +44,7 @@ public class GenericCityObject extends CityObject { ...@@ -47,7 +44,7 @@ public class GenericCityObject extends CityObject {
} }
@Override @Override
public void reCreateGeometries(GeometryFactory factory, ParserConfiguration config) { public void rebuildGeometries(GeometryFactory factory, ParserConfiguration config) {
for (Geometry geom : getGeometries()) { for (Geometry geom : getGeometries()) {
if (geom instanceof ImplicitGeometryHolder) { if (geom instanceof ImplicitGeometryHolder) {
continue; continue;
...@@ -60,23 +57,21 @@ public class GenericCityObject extends CityObject { ...@@ -60,23 +57,21 @@ public class GenericCityObject extends CityObject {
setSolidAccordingToLod(geom, solid); setSolidAccordingToLod(geom, solid);
} }
} }
for (BoundarySurface bs : boundarySurfaceList) { removeEmptyBoundarySurfaces();
reCreateBoundarySurface(factory, config, bs);
}
} }
private void reCreateBoundarySurface(GeometryFactory factory, ParserConfiguration config, BoundarySurface bs) { private void removeEmptyBoundarySurfaces() {
if (bs.getGeometries().isEmpty()) { for (BoundarySurface bs : boundarySurfaceList) {
for (AbstractSpaceBoundaryProperty bsp : cgmlGos.getBoundaries()) { if (bs.getGeometries().isEmpty()) {
if (bsp.getObject() != null && bsp.getObject() == bs.getGmlObject()) { for (AbstractSpaceBoundaryProperty bsp : cgmlGos.getBoundaries()) {
logger.warn("Found empty boundary surface: {}, removing from generic object", bs.getGmlId()); if (bsp.getObject() != null && bsp.getObject() == bs.getGmlObject()) {
cgmlGos.getBoundaries().remove(bsp); logger.warn("Found empty boundary surface: {}, removing from feature", bs.getGmlId());
break; cgmlGos.getBoundaries().remove(bsp);
break;
}
} }
} }
return;
} }
bs.reCreateGeometries(factory, config);
} }
private void setMultiSurfaceAccordingToLod(Geometry geom, MultiSurface ms) { private void setMultiSurfaceAccordingToLod(Geometry geom, MultiSurface ms) {
...@@ -84,14 +79,20 @@ public class GenericCityObject extends CityObject { ...@@ -84,14 +79,20 @@ public class GenericCityObject extends CityObject {
case LOD0: case LOD0:
cgmlGos.setLod0MultiSurface(new MultiSurfaceProperty(ms)); cgmlGos.setLod0MultiSurface(new MultiSurfaceProperty(ms));
break; break;
case LOD1:
cgmlGos.getDeprecatedProperties().setLod1Geometry(new MultiSurfaceProperty(ms));
break;
case LOD2: case LOD2:
cgmlGos.setLod2MultiSurface(new MultiSurfaceProperty(ms)); cgmlGos.setLod2MultiSurface(new MultiSurfaceProperty(ms));
break; break;
case LOD3: case LOD3:
cgmlGos.setLod3MultiSurface(new MultiSurfaceProperty(ms)); cgmlGos.setLod3MultiSurface(new MultiSurfaceProperty(ms));
break; break;
case LOD4:
cgmlGos.getDeprecatedProperties().setLod4Geometry(new MultiSurfaceProperty(ms));
break;
default: default:
throw new IllegalStateException("Cannot add " + geom.getLod() + " multi surface to buildings"); throw new IllegalStateException("Cannot add " + geom.getLod() + " multi surface to generic city object");
} }
} }
...@@ -106,111 +107,49 @@ public class GenericCityObject extends CityObject { ...@@ -106,111 +107,49 @@ public class GenericCityObject extends CityObject {
case LOD3: case LOD3:
cgmlGos.setLod3Solid(new SolidProperty(solid)); cgmlGos.setLod3Solid(new SolidProperty(solid));
break; break;
case LOD4:
cgmlGos.getDeprecatedProperties().setLod4Geometry(new SolidProperty(solid));
break;
default: default:
throw new IllegalStateException("Cannot add " + geom.getLod() + " solid to buildings"); throw new IllegalStateException("Cannot add " + geom.getLod() + " solid to generic city object");
}
}
@Override
public void collectContainedErrors(List<CheckError> errors) {
super.collectContainedErrors(errors);
for (BoundarySurface bs : boundarySurfaceList) {
bs.collectContainedErrors(errors);
}
}
@Override
public void clearAllContainedCheckResults() {
super.clearAllContainedCheckResults();
for (BoundarySurface bs : boundarySurfaceList) {
bs.clearAllContainedCheckResults();
}
}
@Override
public boolean containsError(CheckId checkIdentifier) {
boolean hasError = super.containsError(checkIdentifier);
if (hasError) {
return true;
}
for (BoundarySurface bs : boundarySurfaceList) {
if (bs.containsError(checkIdentifier)) {
return true;
}
}
return false;
}
@Override
public boolean containsAnyError() {
boolean hasError = super.containsAnyError();
if (hasError) {
return true;
}
for (BoundarySurface bs : boundarySurfaceList) {
if (bs.containsAnyError()) {
return true;
}
}
return false;
}
@Override
public void prepareForChecking() {
super.prepareForChecking();
for (BoundarySurface bs : boundarySurfaceList) {
bs.prepareForChecking();
}
}
@Override
public void clearMetaInformation() {
super.clearMetaInformation();
for (BoundarySurface bs : boundarySurfaceList) {
bs.clearMetaInformation();
}
}
@Override
public void collectInstances(CopyHandler handler) {
super.collectInstances(handler);
handler.addInstance(boundarySurfaceList);
}
@Override
public void fillValues(Copyable original, CopyHandler handler) {
super.fillValues(original, handler);
GenericCityObject originalGos = (GenericCityObject) original;
for (BoundarySurface originalBs : originalGos.boundarySurfaceList) {
boundarySurfaceList.add(handler.getCopyInstance(originalBs));
} }
cgmlGos = originalGos.cgmlGos;
} }
@Override @Override
public AbstractCityObject getGmlObject() { public AbstractCityObject getGmlObject() {
return null; return cgmlGos;
} }
@Override @Override
public FeatureType getFeatureType() { public FeatureType getFeatureType() {
return FeatureType.GENERIC_CITY_OBJECT; return FeatureType.OTHER_CITY_OBJECT;
} }
public List<BoundarySurface> getBoundarySurfaces() { public List<BoundarySurface> getBoundarySurfaces() {
return boundarySurfaceList; return boundarySurfaceList;
} }
@Override
public Color getRenderColor() {
return Color.DARKGOLDENROD;
}
@Override @Override
public void unsetGmlGeometries() { public void unsetGmlGeometries() {
cgmlGos.setLod1Solid(null); cgmlGos.setLod1Solid(null);
cgmlGos.setLod2Solid(null); cgmlGos.setLod2Solid(null);
cgmlGos.setLod3Solid(null); cgmlGos.setLod3Solid(null);
cgmlGos.setLod0MultiSurface(null);
cgmlGos.setLod2MultiSurface(null); cgmlGos.setLod2MultiSurface(null);
cgmlGos.setLod3MultiSurface(null); cgmlGos.setLod3MultiSurface(null);
for (BoundarySurface bs : boundarySurfaceList) { cgmlGos.getDeprecatedProperties().setLod1Geometry(null);
bs.unsetGmlGeometries(); cgmlGos.getDeprecatedProperties().setLod2Geometry(null);
} cgmlGos.getDeprecatedProperties().setLod3Geometry(null);
cgmlGos.getDeprecatedProperties().setLod4Geometry(null);
}
@Override
public CityObject getTopLevelCityObject() {
return this;
} }
public void setGmlObject(org.citygml4j.core.model.generics.GenericOccupiedSpace gos) { public void setGmlObject(org.citygml4j.core.model.generics.GenericOccupiedSpace gos) {
...@@ -222,9 +161,4 @@ public class GenericCityObject extends CityObject { ...@@ -222,9 +161,4 @@ public class GenericCityObject extends CityObject {
bs.setParent(this); bs.setParent(this);
} }
@Override
public Copyable createCopyInstance() {
return new GenericCityObject();
}
} }
...@@ -18,20 +18,23 @@ ...@@ -18,20 +18,23 @@
*/ */
package de.hft.stuttgart.citydoctor2.datastructure; package de.hft.stuttgart.citydoctor2.datastructure;
import de.hft.stuttgart.citydoctor2.check.Check; import java.io.Serial;
import de.hft.stuttgart.citydoctor2.check.CheckError; import java.util.ArrayList;
import de.hft.stuttgart.citydoctor2.check.CheckId; import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
import java.util.Set;
import de.hft.stuttgart.citydoctor2.check.CheckableVisitor;
import de.hft.stuttgart.citydoctor2.math.Triangle3d; import de.hft.stuttgart.citydoctor2.math.Triangle3d;
import de.hft.stuttgart.citydoctor2.math.Vector3d; import de.hft.stuttgart.citydoctor2.math.Vector3d;
import de.hft.stuttgart.citydoctor2.tesselation.TesselatedPolygon; import de.hft.stuttgart.citydoctor2.tesselation.TesselatedPolygon;
import de.hft.stuttgart.citydoctor2.utils.BoundingBoxCalculator; import de.hft.stuttgart.citydoctor2.utils.BoundingBoxCalculator;
import de.hft.stuttgart.citydoctor2.utils.CopyHandler;
import de.hft.stuttgart.citydoctor2.utils.Copyable;
import de.hft.stuttgart.citydoctor2.utils.SerializablePair; import de.hft.stuttgart.citydoctor2.utils.SerializablePair;
import javafx.scene.paint.Color;
import java.io.Serial;
import java.util.*;
import java.util.Map.Entry;
/** /**
* Representation of a geometry containing the polygons and edges * Representation of a geometry containing the polygons and edges
...@@ -44,6 +47,10 @@ public class Geometry extends GmlElement { ...@@ -44,6 +47,10 @@ public class Geometry extends GmlElement {
@Serial @Serial
private static final long serialVersionUID = 2539031030917731575L; private static final long serialVersionUID = 2539031030917731575L;
public enum Orientation {
INWARD, OUTWARD
}
private static final Random r = new Random(); private static final Random r = new Random();
...@@ -56,11 +63,31 @@ public class Geometry extends GmlElement { ...@@ -56,11 +63,31 @@ public class Geometry extends GmlElement {
private List<Edge> edges; private List<Edge> edges;
private Map<SerializablePair<Vertex, Vertex>, Edge> edgeMap; private Map<SerializablePair<Vertex, Vertex>, Edge> edgeMap;
private List<Vertex> vertices; private List<Vertex> vertices;
private Map<Vertex, Set<LinearRing>> adjacentRingsOfVertices = new HashMap<>();
public Geometry(GeometryType type, Lod lod) { private Orientation orientation;
public Geometry(GeometryType type, Lod lod, Orientation orientation) {
this.lod = lod; this.lod = lod;
this.type = type; this.type = type;
} if (type == GeometryType.SOLID) {
Objects.requireNonNull(orientation);
}
this.orientation = orientation;
}
public Set<LinearRing> getAdjacentRingsOfVertex(Vertex v) {
return adjacentRingsOfVertices.compute(v, (vertex, set) -> {
if (set == null) {
return new HashSet<>(4);
}
return set;
});
}
public Orientation getOrientation() {
return orientation;
}
void setParent(CityObject parent) { void setParent(CityObject parent) {
this.parent = parent; this.parent = parent;
...@@ -207,52 +234,9 @@ public class Geometry extends GmlElement { ...@@ -207,52 +234,9 @@ public class Geometry extends GmlElement {
+ a[0] * b[1] * c[2]; + a[0] * b[1] * c[2];
} }
@Override
public boolean containsError(CheckId checkIdentifier) {
boolean hasError = super.containsError(checkIdentifier);
if (hasError) {
return true;
}
for (Polygon p : polygons) {
if (p.containsError(checkIdentifier)) {
return true;
}
}
return false;
}
@Override @Override
public void clearAllContainedCheckResults() { public void accept(CheckableVisitor c) {
super.clearCheckResults();
for (Polygon p : polygons) {
p.clearAllContainedCheckResults();
}
}
@Override
public void collectContainedErrors(List<CheckError> errors) {
super.collectContainedErrors(errors);
for (Polygon p : polygons) {
p.collectContainedErrors(errors);
}
}
@Override
public boolean containsAnyError() {
boolean hasError = super.containsAnyError();
if (hasError) {
return true;
}
for (Polygon p : polygons) {
if (p.containsAnyError()) {
return true;
}
}
return false;
}
@Override
public void accept(Check c) {
super.accept(c); super.accept(c);
if (c.canExecute(this)) { if (c.canExecute(this)) {
c.check(this); c.check(this);
...@@ -378,74 +362,16 @@ public class Geometry extends GmlElement { ...@@ -378,74 +362,16 @@ public class Geometry extends GmlElement {
return false; return false;
} }
@Override public void clearMetaData() {
public void prepareForChecking() {
updateEdgesAndVertices();
}
@Override
public void clearMetaInformation() {
if (vertices != null) { if (vertices != null) {
for (Vertex v : vertices) { adjacentRingsOfVertices = new HashMap<>();
v.clearAdjacentRings();
}
vertices = null; vertices = null;
} }
edges = null; edges = null;
edgeMap = null; edgeMap = null;
} }
@Override public Color getRenderColor() {
public void collectInstances(CopyHandler handler) { return parent.getRenderColor();
handler.addInstance(parent);
handler.addInstance(polygons);
handler.addInstance(edges);
handler.addInstance(vertices);
if (edgeMap != null) {
for (Entry<SerializablePair<Vertex, Vertex>, Edge> e : edgeMap.entrySet()) {
handler.addInstance(e.getKey().getValue0());
handler.addInstance(e.getKey().getValue1());
handler.addInstance(e.getValue());
}
}
}
@Override
public Copyable createCopyInstance() {
return new Geometry(type, lod);
}
@Override
public void fillValues(Copyable original, CopyHandler handler) {
super.fillValues(original, handler);
Geometry originalGeometry = (Geometry) original;
for (Polygon originalPoly : originalGeometry.polygons) {
polygons.add(handler.getCopyInstance(originalPoly));
}
if (originalGeometry.edges != null) {
edges = new ArrayList<>(originalGeometry.edges.size());
for (Edge originalEdge : originalGeometry.edges) {
edges.add(handler.getCopyInstance(originalEdge));
}
}
if (originalGeometry.edgeMap != null) {
edgeMap = new HashMap<>(originalGeometry.edgeMap.size());
for (Entry<SerializablePair<Vertex, Vertex>, Edge> originalEntry : originalGeometry.edgeMap.entrySet()) {
Vertex copyV0 = handler.getCopyInstance(originalEntry.getKey().getValue0());
Vertex copyV1 = handler.getCopyInstance(originalEntry.getKey().getValue1());
SerializablePair<Vertex, Vertex> pair = new SerializablePair<>(copyV0, copyV1);
Edge copyEdge = handler.getCopyInstance(originalEntry.getValue());
edgeMap.put(pair, copyEdge);
}
}
if (originalGeometry.vertices != null) {
vertices = new ArrayList<>(originalGeometry.vertices.size());
for (Vertex originalVertex : originalGeometry.vertices) {
vertices.add(handler.getCopyInstance(originalVertex));
}
}
parent = handler.getCopyInstance(originalGeometry.parent);
} }
} }
...@@ -19,8 +19,6 @@ ...@@ -19,8 +19,6 @@
package de.hft.stuttgart.citydoctor2.datastructure; package de.hft.stuttgart.citydoctor2.datastructure;
import de.hft.stuttgart.citydoctor2.check.Checkable; import de.hft.stuttgart.citydoctor2.check.Checkable;
import de.hft.stuttgart.citydoctor2.utils.CopyHandler;
import de.hft.stuttgart.citydoctor2.utils.Copyable;
import java.io.Serial; import java.io.Serial;
...@@ -29,7 +27,7 @@ import java.io.Serial; ...@@ -29,7 +27,7 @@ import java.io.Serial;
* *
* @author Matthias Betz * @author Matthias Betz
*/ */
public abstract class GmlElement extends Checkable implements Copyable { public abstract class GmlElement extends Checkable {
@Serial @Serial
private static final long serialVersionUID = -3242505393303017359L; private static final long serialVersionUID = -3242505393303017359L;
...@@ -52,11 +50,5 @@ public abstract class GmlElement extends Checkable implements Copyable { ...@@ -52,11 +50,5 @@ public abstract class GmlElement extends Checkable implements Copyable {
return gmlId != null && !gmlId.isGenerated(); return gmlId != null && !gmlId.isGenerated();
} }
@Override
public void fillValues(Copyable original, CopyHandler handler) {
GmlElement originalElement = (GmlElement) original;
// generate gml id before copying
gmlId = originalElement.getGmlId();
}
} }
package de.hft.stuttgart.citydoctor2.datastructure; package de.hft.stuttgart.citydoctor2.datastructure;
import java.io.Serial; import java.io.Serial;
import java.util.List; import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import de.hft.stuttgart.citydoctor2.check.CheckableVisitor;
import de.hft.stuttgart.citydoctor2.database.CityObjectCache;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.citygml4j.core.model.core.ImplicitGeometry; import org.citygml4j.core.model.core.ImplicitGeometry;
import de.hft.stuttgart.citydoctor2.check.Check;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.CheckId;
import de.hft.stuttgart.citydoctor2.math.TransformationMatrix; import de.hft.stuttgart.citydoctor2.math.TransformationMatrix;
/** /**
...@@ -19,14 +22,20 @@ public class ImplicitGeometryHolder extends Geometry { ...@@ -19,14 +22,20 @@ public class ImplicitGeometryHolder extends Geometry {
@Serial @Serial
private static final long serialVersionUID = -8938931081577196349L; private static final long serialVersionUID = -8938931081577196349L;
private static final Logger logger = LogManager.getLogger(ImplicitGeometryHolder.class);
public enum PrototypeGeometryType {
LIBRARY_OBJECT, RELATIVE_GEOMETRY
}
private ImplicitGeometry cgmlImplicitGeometry = null;
private ImplicitGeometry cgmlImplicitGeometry = null;
private static ConcurrentHashMap<ImplicitGeometryHolder, ImplicitGeometry> deferredRelGeomObjects = new ConcurrentHashMap<>();
private final PrototypeGeometryType type; private final PrototypeGeometryType type;
private final Geometry prototypeGeometry; private final Geometry prototypeGeometry;
public ImplicitGeometryHolder(ImplicitGeometry cgmlImplicitGeometry, LibraryObject libObject) { public ImplicitGeometryHolder(ImplicitGeometry cgmlImplicitGeometry, LibraryObject libObject) {
super(libObject.getType(), libObject.getLod()); super(libObject.getType(), libObject.getLod(), libObject.getOrientation());
prototypeGeometry = libObject; prototypeGeometry = libObject;
type = PrototypeGeometryType.LIBRARY_OBJECT; type = PrototypeGeometryType.LIBRARY_OBJECT;
this.cgmlImplicitGeometry = cgmlImplicitGeometry; this.cgmlImplicitGeometry = cgmlImplicitGeometry;
...@@ -34,14 +43,59 @@ public class ImplicitGeometryHolder extends Geometry { ...@@ -34,14 +43,59 @@ public class ImplicitGeometryHolder extends Geometry {
} }
public ImplicitGeometryHolder(ImplicitGeometry cgmlImplicitGeometry, RelativeGeometry relativeGeometry) { public ImplicitGeometryHolder(ImplicitGeometry cgmlImplicitGeometry, RelativeGeometry relativeGeometry) {
super(relativeGeometry.getType(), relativeGeometry.getLod()); super(relativeGeometry.getType(), relativeGeometry.getLod(), relativeGeometry.getOrientation());
prototypeGeometry = relativeGeometry; prototypeGeometry = relativeGeometry;
type = PrototypeGeometryType.RELATIVE_GEOMETRY; type = PrototypeGeometryType.RELATIVE_GEOMETRY;
this.cgmlImplicitGeometry = cgmlImplicitGeometry; this.cgmlImplicitGeometry = cgmlImplicitGeometry;
applyTransformation(); applyTransformation();
} }
public static ImplicitGeometryHolder deferRelativeGeomParsing(ImplicitGeometry ig, Lod lod) {
ImplicitGeometryHolder igh = new ImplicitGeometryHolder(lod);
deferredRelGeomObjects.put(igh, ig);
return igh;
}
public static void resolveDeferredObjects(CityObjectCache cache) {
Set<GmlId> missingGeoms = new HashSet<>();
if(!deferredRelGeomObjects.isEmpty()) {
logger.info("Resolving deferred relative geometries");
}
Set<GmlId> changedFeatures = new HashSet<>();
for (ImplicitGeometryHolder key : deferredRelGeomObjects.keySet()) {
ImplicitGeometry ig = deferredRelGeomObjects.get(key);
String hrefId = ig.getRelativeGeometry().getHref();
hrefId = hrefId.startsWith("#") ? hrefId.substring(1) : hrefId;
GmlId gmlId = new GmlId(hrefId);
RelativeGeometry relGeom = RelativeGeometry.of(gmlId);
if (relGeom != null) {
ImplicitGeometryHolder igh = new ImplicitGeometryHolder(ig, relGeom);
CityObject parent = cache.get(key.getParent().getGmlId());
parent.removeGeometry(igh.getLod(), igh.getType());
parent.addGeometry(igh);
changedFeatures.add(parent.getTopLevelCityObject().getGmlId());
} else {
missingGeoms.add(gmlId);
}
}
changedFeatures.forEach(gmlId -> {
CityObject co = cache.get(gmlId);
co.setBbox(BoundingBox.of(co));
});
if (!missingGeoms.isEmpty()) {
logger.warn("RelativeGeometries of the following gmlIDs could not be resolved: {}", missingGeoms);
}
deferredRelGeomObjects.clear();
if (logger.isDebugEnabled()) {
logger.debug("Resolving HRef geometries finished");
}
}
private ImplicitGeometryHolder(Lod lod) {
super(null, lod, null);
type = null;
prototypeGeometry = new Geometry(null, lod, null);
}
/** /**
* Applies the transformation matrix of the implicit geometry to a copy of the reference geometry and copies the resulting * Applies the transformation matrix of the implicit geometry to a copy of the reference geometry and copies the resulting
* transformed geometry into this object. * transformed geometry into this object.
...@@ -57,44 +111,14 @@ public class ImplicitGeometryHolder extends Geometry { ...@@ -57,44 +111,14 @@ public class ImplicitGeometryHolder extends Geometry {
return type; return type;
} }
@Override /**
public void accept(Check c) { * Resets the Object maps of {@link RelativeGeometry} and {@link LibraryObject} to prevent memory and data leaks
prototypeGeometry.accept(c); */
} public static void resetObjectMaps() {
RelativeGeometry.resetObjectMap();
@Override LibraryObject.resetObjectMap();
public boolean containsError(CheckId checkIdentifier) {
return prototypeGeometry.containsError(checkIdentifier);
}
@Override
public void clearAllContainedCheckResults() {
prototypeGeometry.clearAllContainedCheckResults();
}
@Override
public void collectContainedErrors(List<CheckError> errors) {
prototypeGeometry.clearAllContainedCheckResults();
}
@Override
public boolean containsAnyError() {
return prototypeGeometry.containsAnyError();
}
@Override
public void prepareForChecking() {
this.updateEdgesAndVertices();
prototypeGeometry.prepareForChecking();
} }
@Override
public boolean isValidated() {
return prototypeGeometry.isValidated();
}
public enum PrototypeGeometryType {
LIBRARY_OBJECT, RELATIVE_GEOMETRY
}
} }
...@@ -18,16 +18,16 @@ ...@@ -18,16 +18,16 @@
*/ */
package de.hft.stuttgart.citydoctor2.datastructure; package de.hft.stuttgart.citydoctor2.datastructure;
import de.hft.stuttgart.citydoctor2.check.Check; import de.hft.stuttgart.citydoctor2.check.CheckableVisitor;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.CheckId;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.utils.CityGmlUtils; import de.hft.stuttgart.citydoctor2.utils.CityGmlUtils;
import de.hft.stuttgart.citydoctor2.utils.CopyHandler; import javafx.scene.paint.Color;
import de.hft.stuttgart.citydoctor2.utils.Copyable; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.citygml4j.core.model.bridge.BridgeInstallation; import org.citygml4j.core.model.bridge.BridgeInstallation;
import org.citygml4j.core.model.construction.AbstractInstallation; import org.citygml4j.core.model.construction.AbstractInstallation;
import org.citygml4j.core.model.core.AbstractSpaceBoundaryProperty; import org.citygml4j.core.model.core.AbstractSpaceBoundaryProperty;
import org.citygml4j.core.model.tunnel.TunnelInstallation;
import org.citygml4j.core.util.geometry.GeometryFactory; import org.citygml4j.core.util.geometry.GeometryFactory;
import org.xmlobjects.gml.model.geometry.GeometryProperty; import org.xmlobjects.gml.model.geometry.GeometryProperty;
import org.xmlobjects.gml.model.geometry.aggregates.MultiSurface; import org.xmlobjects.gml.model.geometry.aggregates.MultiSurface;
...@@ -44,13 +44,15 @@ public class Installation extends CityObject { ...@@ -44,13 +44,15 @@ public class Installation extends CityObject {
@Serial @Serial
private static final long serialVersionUID = 1576237433322680191L; private static final long serialVersionUID = 1576237433322680191L;
private static final Logger logger = LogManager.getLogger(Installation.class);
private List<BoundarySurface> boundarySurfaces = new ArrayList<>(4); private List<BoundarySurface> boundarySurfaces = new ArrayList<>(4);
private AbstractInstallation gmlBi; private AbstractInstallation gmlBi;
private CityObject parent; private CityObject parent;
public void reCreateGeometries(GeometryFactory factory, ParserConfiguration config) { public void rebuildGeometries(GeometryFactory factory, ParserConfiguration config) {
for (Geometry geom : getGeometries()) { for (Geometry geom : getGeometries()) {
if (geom.getType() == GeometryType.MULTI_SURFACE) { if (geom.getType() == GeometryType.MULTI_SURFACE) {
MultiSurface ms = CityGmlUtils.createMultiSurface(geom, factory, config); MultiSurface ms = CityGmlUtils.createMultiSurface(geom, factory, config);
...@@ -66,8 +68,20 @@ public class Installation extends CityObject { ...@@ -66,8 +68,20 @@ public class Installation extends CityObject {
throw new IllegalStateException("BuildingInstallation not have Solid geometries"); throw new IllegalStateException("BuildingInstallation not have Solid geometries");
} }
} }
removeEmptyBoundarySurfaces();
}
private void removeEmptyBoundarySurfaces() {
for (BoundarySurface bs : boundarySurfaces) { for (BoundarySurface bs : boundarySurfaces) {
bs.reCreateGeometries(factory, config); if (bs.getGeometries().isEmpty()) {
for (AbstractSpaceBoundaryProperty bsp : gmlBi.getBoundaries()) {
if (bsp.getObject() != null && bsp.getObject() == bs.getGmlObject()) {
logger.warn("Found empty boundary surface: {}, removing from feature", bs.getGmlId());
gmlBi.getBoundaries().remove(bsp);
break;
}
}
}
} }
} }
...@@ -115,7 +129,7 @@ public class Installation extends CityObject { ...@@ -115,7 +129,7 @@ public class Installation extends CityObject {
} }
@Override @Override
public void accept(Check c) { public void accept(CheckableVisitor c) {
super.accept(c); super.accept(c);
if (c.canExecute(this)) { if (c.canExecute(this)) {
c.check(this); c.check(this);
...@@ -125,50 +139,6 @@ public class Installation extends CityObject { ...@@ -125,50 +139,6 @@ public class Installation extends CityObject {
} }
} }
@Override
public void clearAllContainedCheckResults() {
super.clearAllContainedCheckResults();
for (BoundarySurface bs : boundarySurfaces) {
bs.clearAllContainedCheckResults();
}
}
@Override
public void collectContainedErrors(List<CheckError> errors) {
super.collectContainedErrors(errors);
for (BoundarySurface bs : boundarySurfaces) {
bs.collectContainedErrors(errors);
}
}
@Override
public boolean containsAnyError() {
boolean hasError = super.containsAnyError();
if (hasError) {
return true;
}
for (BoundarySurface bs : boundarySurfaces) {
if (bs.containsAnyError()) {
return true;
}
}
return false;
}
@Override
public boolean containsError(CheckId checkIdentifier) {
boolean hasError = super.containsError(checkIdentifier);
if (hasError) {
return true;
}
for (BoundarySurface bs : boundarySurfaces) {
if (bs.containsError(checkIdentifier)) {
return true;
}
}
return false;
}
public void setParent(CityObject parent) { public void setParent(CityObject parent) {
this.parent = parent; this.parent = parent;
} }
...@@ -177,30 +147,45 @@ public class Installation extends CityObject { ...@@ -177,30 +147,45 @@ public class Installation extends CityObject {
return parent; return parent;
} }
@Override
public Color getRenderColor() {
return parent.getRenderColor().darker();
}
public void addBoundarySurface(BoundarySurface bs) { public void addBoundarySurface(BoundarySurface bs) {
boundarySurfaces.add(bs); boundarySurfaces.add(bs);
bs.setParent(this); bs.setParent(this);
} }
@Override
public void unsetGmlGeometries() { public void unsetGmlGeometries() {
if (gmlBi instanceof org.citygml4j.core.model.building.BuildingInstallation localBi) { gmlBi.setLod0MultiSurface(null);
localBi.getDeprecatedProperties().setLod2Geometry(null); gmlBi.setLod2MultiSurface(null);
localBi.getDeprecatedProperties().setLod3Geometry(null); gmlBi.setLod3MultiSurface(null);
localBi.getDeprecatedProperties().setLod4Geometry(null); gmlBi.setLod1Solid(null);
} else if (gmlBi instanceof BridgeInstallation localBi) { gmlBi.setLod2Solid(null);
removeGeometriesFromBridgeInstallation(localBi); gmlBi.setLod3Solid(null);
} if (gmlBi instanceof org.citygml4j.core.model.building.BuildingInstallation buildingInstallation) {
for (BoundarySurface bs : boundarySurfaces) { buildingInstallation.getDeprecatedProperties().setLod2Geometry(null);
bs.unsetGmlGeometries(); buildingInstallation.getDeprecatedProperties().setLod3Geometry(null);
buildingInstallation.getDeprecatedProperties().setLod4Geometry(null);
} else if (gmlBi instanceof BridgeInstallation bridgeInstallation) {
bridgeInstallation.getDeprecatedProperties().setLod2Geometry(null);
bridgeInstallation.getDeprecatedProperties().setLod3Geometry(null);
bridgeInstallation.getDeprecatedProperties().setLod4Geometry(null);
} else if (gmlBi instanceof TunnelInstallation tunnelInstallation) {
tunnelInstallation.getDeprecatedProperties().setLod2Geometry(null);
tunnelInstallation.getDeprecatedProperties().setLod3Geometry(null);
tunnelInstallation.getDeprecatedProperties().setLod4Geometry(null);
} }
} }
private void removeGeometriesFromBridgeInstallation(BridgeInstallation localBi) { @Override
localBi.getDeprecatedProperties().setLod2Geometry(null); public CityObject getTopLevelCityObject() {
localBi.getDeprecatedProperties().setLod3Geometry(null); return getParent().getTopLevelCityObject();
localBi.getDeprecatedProperties().setLod4Geometry(null);
} }
public void setGmlObject(AbstractInstallation gmlBi) { public void setGmlObject(AbstractInstallation gmlBi) {
this.gmlBi = gmlBi; this.gmlBi = gmlBi;
} }
...@@ -237,46 +222,4 @@ public class Installation extends CityObject { ...@@ -237,46 +222,4 @@ public class Installation extends CityObject {
} }
return boundarySurfaces; return boundarySurfaces;
} }
@Override
public void clearMetaInformation() {
super.clearMetaInformation();
for (BoundarySurface bs : boundarySurfaces) {
bs.clearMetaInformation();
}
}
@Override
public void prepareForChecking() {
super.prepareForChecking();
for (BoundarySurface bs : boundarySurfaces) {
bs.prepareForChecking();
}
}
@Override
public void fillValues(Copyable original, CopyHandler handler) {
super.fillValues(original, handler);
Installation originalBi = (Installation) original;
for (BoundarySurface originalBs : originalBi.boundarySurfaces) {
boundarySurfaces.add(handler.getCopyInstance(originalBs));
}
gmlBi = originalBi.gmlBi;
parent = handler.getCopyInstance(parent);
}
@Override
public void collectInstances(CopyHandler handler) {
super.collectInstances(handler);
for (BoundarySurface bs : boundarySurfaces) {
handler.addInstance(bs);
}
handler.addInstance(parent);
}
@Override
public Copyable createCopyInstance() {
return new Installation();
}
} }
...@@ -18,10 +18,10 @@ ...@@ -18,10 +18,10 @@
*/ */
package de.hft.stuttgart.citydoctor2.datastructure; package de.hft.stuttgart.citydoctor2.datastructure;
import de.hft.stuttgart.citydoctor2.check.Check; import de.hft.stuttgart.citydoctor2.check.CheckableVisitor;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.utils.CityGmlUtils; import de.hft.stuttgart.citydoctor2.utils.CityGmlUtils;
import de.hft.stuttgart.citydoctor2.utils.Copyable; import javafx.scene.paint.Color;
import org.citygml4j.core.model.core.AbstractCityObject; import org.citygml4j.core.model.core.AbstractCityObject;
import org.citygml4j.core.model.landuse.LandUse; import org.citygml4j.core.model.landuse.LandUse;
import org.citygml4j.core.util.geometry.GeometryFactory; import org.citygml4j.core.util.geometry.GeometryFactory;
...@@ -47,7 +47,7 @@ public class LandObject extends CityObject { ...@@ -47,7 +47,7 @@ public class LandObject extends CityObject {
} }
@Override @Override
public void reCreateGeometries(GeometryFactory factory, ParserConfiguration config) { public void rebuildGeometries(GeometryFactory factory, ParserConfiguration config) {
for (Geometry geom : getGeometries()) { for (Geometry geom : getGeometries()) {
if (geom.getType() == GeometryType.MULTI_SURFACE) { if (geom.getType() == GeometryType.MULTI_SURFACE) {
MultiSurface ms = CityGmlUtils.createMultiSurface(geom, factory, config); MultiSurface ms = CityGmlUtils.createMultiSurface(geom, factory, config);
...@@ -63,6 +63,11 @@ public class LandObject extends CityObject { ...@@ -63,6 +63,11 @@ public class LandObject extends CityObject {
return FeatureType.LAND; return FeatureType.LAND;
} }
@Override
public Color getRenderColor() {
return Color.TAN;
}
private void setMultiSurfaceAccordingToLod(Geometry geom, MultiSurface ms) { private void setMultiSurfaceAccordingToLod(Geometry geom, MultiSurface ms) {
switch (geom.getLod()) { switch (geom.getLod()) {
case LOD0: case LOD0:
...@@ -84,7 +89,7 @@ public class LandObject extends CityObject { ...@@ -84,7 +89,7 @@ public class LandObject extends CityObject {
} }
@Override @Override
public void accept(Check c) { public void accept(CheckableVisitor c) {
super.accept(c); super.accept(c);
if (c.canExecute(this)) { if (c.canExecute(this)) {
c.check(this); c.check(this);
...@@ -105,6 +110,11 @@ public class LandObject extends CityObject { ...@@ -105,6 +110,11 @@ public class LandObject extends CityObject {
lu.getDeprecatedProperties().setLod4MultiSurface(null); lu.getDeprecatedProperties().setLod4MultiSurface(null);
} }
@Override
public CityObject getTopLevelCityObject() {
return this;
}
public void setGmlObject(LandUse landUse) { public void setGmlObject(LandUse landUse) {
lu = landUse; lu = landUse;
} }
...@@ -114,9 +124,4 @@ public class LandObject extends CityObject { ...@@ -114,9 +124,4 @@ public class LandObject extends CityObject {
return "LandObject [id=" + getGmlId() + "]"; return "LandObject [id=" + getGmlId() + "]";
} }
@Override
public Copyable createCopyInstance() {
return new LandObject(lu);
}
} }
...@@ -4,10 +4,12 @@ import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException; ...@@ -4,10 +4,12 @@ import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParser; import de.hft.stuttgart.citydoctor2.parser.CityGmlParser;
import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException; import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.utils.Localization;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import java.io.Serial; import java.io.Serial;
import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
...@@ -24,56 +26,60 @@ public class LibraryObject extends Geometry { ...@@ -24,56 +26,60 @@ public class LibraryObject extends Geometry {
private static final Logger logger = LogManager.getLogger(LibraryObject.class); private static final Logger logger = LogManager.getLogger(LibraryObject.class);
@Serial @Serial
private static final long serialVersionUID = -50293435187454911L; private static final long serialVersionUID = -50293435187454911L;
private static final Map<String, LibraryObject> libraryObjects = new ConcurrentHashMap<>();
private static Map<String, LibraryObject> libraryObjects = new ConcurrentHashMap<>(); public static LibraryObject of(Path path, ParserConfiguration config) {
if (libraryObjects.containsKey(path.toString())) {
return libraryObjects.get(path.toString());
}
Geometry protoGeom = parseFile(path, config);
if (protoGeom == null) {
return null;
}
LibraryObject libOb = new LibraryObject(protoGeom.getType(), protoGeom.getLod(), protoGeom.getOrientation());
protoGeom.getPolygons().forEach(libOb::addPolygon);
libOb.updateEdgesAndVertices();
libraryObjects.put(path.toString(), libOb);
return libOb;
}
public static LibraryObject of(Path path, ParserConfiguration config) { private LibraryObject(GeometryType type, Lod lod, Orientation orientation) {
if (libraryObjects.containsKey(path.toString())) { super(type, lod, orientation);
return libraryObjects.get(path.toString()); }
}
Geometry protoGeom = parseFile(path, config);
if (protoGeom == null) {
return null;
}
LibraryObject libOb = new LibraryObject(protoGeom.getType(), protoGeom.getLod());
protoGeom.getPolygons().forEach(libOb::addPolygon);
libOb.updateEdgesAndVertices();
libraryObjects.put(path.toString(), libOb);
return libOb;
}
private LibraryObject(GeometryType type, Lod lod) {
super(type, lod);
}
private static Geometry parseFile(Path path, ParserConfiguration config) { private static Geometry parseFile(Path path, ParserConfiguration config) {
Geometry geo = null; Geometry geo = null;
if (path.toFile().exists()) { if (Files.exists(path)) {
try { try {
CityGmlParser.gagLogger(true); geo = getProtoGeometry(CityGmlParser.nestedCityGmlFileParse(path.toString(), config));
CityDoctorModel model = CityGmlParser.parseCityGmlFile(path.toString(), config); } catch (CityGmlParseException e) {
List<CityObject> objects = model.createFeatureStream().toList(); logger.error(Localization.getText("LibraryObject.parsingError"), path);
if (objects.isEmpty()) { logger.error(e.getStackTrace());
throw new InvalidGmlFileException( } catch (InvalidGmlFileException e) {
"Referenced library-object's gml file does not contain a CityGML object!"); logger.error(e.getStackTrace());
} else if (objects.size() > 1) { }
throw new InvalidGmlFileException( } else {
"Referenced library-object's gml file contains more than one CityGML object!"); logger.error(Localization.getText("LibraryObject.fileMissing"), path);
} }
geo = objects.get(0).getHighestLodGeometry(); return geo;
} catch (CityGmlParseException e) { }
logger.error("Encountered an error while parsing library object {}", path);
logger.error(e.getStackTrace()); private static Geometry getProtoGeometry(CityDoctorModel model) throws InvalidGmlFileException, CityGmlParseException {
} catch (InvalidGmlFileException e) { if (model == null) {
logger.error(e.getStackTrace()); throw new CityGmlParseException("CityDoctorModel of referenced LibraryObject is null");
} finally { }
// Failsafe to remove gag should parsing fail List<CityObject> objects = model.createFeatureStream().toList();
CityGmlParser.gagLogger(false); if (objects.isEmpty()) {
} throw new InvalidGmlFileException("Referenced library-object gml file does not contain any CityGML objects!");
} else { } else if (objects.size() > 1) {
logger.error("Implicit geometry references non-existing library object file {}.", path); throw new InvalidGmlFileException("Referenced library-object gml file contains more than one CityGML object!");
} }
return geo; return objects.get(0).getHighestLodGeometry();
} }
public static void resetObjectMap() {
libraryObjects.clear();
}
} }
Supports Markdown
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