Commit 5571f382 authored by Luna Riegel's avatar Luna Riegel
Browse files

Merge branch 'dev' into 'master'

CityDoctor Version 3.18.0

See merge request !37
parents 87dba3fa 61859d4f
Pipeline #12247 passed with stage
in 2 minutes and 31 seconds
......@@ -20,9 +20,11 @@ package de.hft.stuttgart.citydoctor2.datastructure;
import de.hft.stuttgart.citydoctor2.math.Vector3d;
import de.hft.stuttgart.citydoctor2.utils.BoundingBoxCalculator;
import de.hft.stuttgart.citydoctor2.utils.visitors.MinMaxExtentVisitor;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
/**
* An axis aligned bounding box represented by its two corners
......@@ -47,6 +49,12 @@ public class BoundingBox {
return BoundingBoxCalculator.calculateBoundingBoxFromPoints(points);
}
public static BoundingBox of(CityObject co) {
MinMaxExtentVisitor mima = new MinMaxExtentVisitor();
co.accept(mima);
return BoundingBox.of(mima.getMinMaxExtent());
}
/**
* Creates an axis aligned bounding box of the whole model.
*
......@@ -161,4 +169,45 @@ public class BoundingBox {
public double getDiagonalLength() {
return bbox[1].getDistance(bbox[0]);
}
/**
* Returns whether this BoundinBox is undefined, meaning that one or all corners are infinite.
* @return True if the BoundingBox is undefined, false otherwise
*/
public boolean isUndefined(){
double x1 = bbox[0].getX();
double y1 = bbox[0].getY();
double x2 = bbox[1].getX();
double y2 = bbox[1].getY();
return (Double.isInfinite(x1) || Double.isInfinite(y1) || Double.isInfinite(x2) || Double.isInfinite(y2));
}
/**
* Returns an axis-aligned 2D polygon projection of this bbox as a WKT String.
* <p/>
* An undefined bbox will return an empty polygon.
* @return The 2D polygon WKT for this bbox
*/
public String to2DWkt() {
if (this.isUndefined()){
return "POLYGON EMPTY";
}
double x1 = bbox[0].getX();
double y1 = bbox[0].getY();
double x2 = bbox[1].getX();
double y2 = bbox[1].getY();
double minX = Math.min(x1, x2);
double minY = Math.min(y1, y2);
double maxX = Math.max(x1, x2);
double maxY = Math.max(y1, y2);
return String.format(Locale.ROOT,"POLYGON((%.3f %.3f, %.3f %.3f, %.3f %.3f, %.3f %.3f, %.3f %.3f))",
minX, minY,
maxX, minY,
maxX, maxY,
minX, maxY,
minX, minY
);
}
}
......@@ -61,15 +61,11 @@ public class BridgeObject extends CityObject {
private BridgeObject parent;
public BridgeObject(AbstractBridge ab) {
this.ab = ab;
this.type = BridgeType.BRIDGE;
this.parent = null;
this(BridgeType.BRIDGE, ab, null);
}
public BridgeObject(AbstractBridge ab, BridgeObject parent) {
this.ab = ab;
this.type = BridgeType.BRIDGE_PART;
this.parent = parent;
this(BridgeType.BRIDGE_PART, ab, parent);
}
private BridgeObject(BridgeType type, AbstractBridge ab, BridgeObject parent) {
......
package de.hft.stuttgart.citydoctor2.datastructure;
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;
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.model.deprecated.bridge.DeprecatedPropertiesOfBridgeConstructiveElement;
import org.citygml4j.core.util.geometry.GeometryFactory;
import org.xmlobjects.gml.model.geometry.GeometryProperty;
import org.xmlobjects.gml.model.geometry.aggregates.MultiSurface;
import org.xmlobjects.gml.model.geometry.aggregates.MultiSurfaceProperty;
import org.xmlobjects.gml.model.geometry.complexes.CompositeSurface;
import org.xmlobjects.gml.model.geometry.primitives.Solid;
import org.xmlobjects.gml.model.geometry.primitives.SolidProperty;
import org.xmlobjects.gml.model.geometry.primitives.SurfaceProperty;
import java.io.Serial;
import java.util.ArrayList;
import java.util.List;
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 {
......
......@@ -20,6 +20,8 @@ package de.hft.stuttgart.citydoctor2.datastructure;
import de.hft.stuttgart.citydoctor2.check.CheckableUtilsVisitor;
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.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.writer.CityGMLWriterUtils;
......@@ -45,15 +47,15 @@ import java.util.stream.Stream;
public class CityDoctorModel {
private static final String COULD_NOT_FIND_FEATURE = "Could not find feature: ";
private final List<Building> buildings;
private final List<Vegetation> vegetation;
private final List<BridgeObject> bridges;
private final List<CityFurniture> cityfurniture;
private final List<GenericCityObject> genericObjects;
private final List<CityObject> land;
private final List<TransportationObject> roads;
private final List<Tunnel> tunnels;
private final List<WaterObject> water;
private final List<GmlId> buildings;
private final List<GmlId> vegetation;
private final List<GmlId> bridges;
private final List<GmlId> cityfurniture;
private final List<GmlId> genericObjects;
private final List<GmlId> land;
private final List<GmlId> roads;
private final List<GmlId> tunnels;
private final List<GmlId> water;
private CityModel cModel;
private final ParserConfiguration config;
private final String fileName;
......@@ -62,11 +64,15 @@ public class CityDoctorModel {
private boolean isValidated = false;
private ValidationPlan plan;
private CityGMLVersion cityGMLVersion;
private final CityObjectCache cache;
public CityDoctorModel(ParserConfiguration config, File file) {
public CityDoctorModel(ParserConfiguration config, File file, CityObjectCache cache) {
if (config == 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.config = config;
this.file = file;
......@@ -80,6 +86,7 @@ public class CityDoctorModel {
cityfurniture = new ArrayList<>();
genericObjects = new ArrayList<>();
globalErrors = new ArrayList<>();
this.cache = cache;
}
public boolean isValidated() {
......@@ -117,8 +124,59 @@ public class CityDoctorModel {
}
public Stream<CityObject> createFeatureStream() {
return Stream.of(buildings.stream(), vegetation.stream(), bridges.stream(), land.stream(), roads.stream(),
tunnels.stream(), water.stream(), cityfurniture.stream(), genericObjects.stream()).flatMap(co -> co);
return Stream.of(getBuildings(), getVegetation(), getBridges(), getLand(), getTransportation(),
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 {
......@@ -136,6 +194,7 @@ public class CityDoctorModel {
}
}
private void exportAsGML(String file) throws CityDoctorWriteException {
CityGMLWriterUtils.writeCityModel(file, this);
}
......@@ -215,106 +274,201 @@ public class CityDoctorModel {
public Set<CheckError> collectErrors() {
List<CheckError> errors = new ArrayList<>();
collectErrorsFromList(errors, buildings);
collectErrorsFromList(errors, vegetation);
collectErrorsFromList(errors, bridges);
collectErrorsFromList(errors, land);
collectErrorsFromList(errors, roads);
collectErrorsFromList(errors, tunnels);
collectErrorsFromList(errors, water);
collectErrorsFromList(errors, cityfurniture);
collectErrorsFromList(errors, genericObjects);
createFeatureStream().forEach(cityObject -> cityObject.collectErrors(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() {
return fileName;
}
public void addBridge(BridgeObject coBridge) {
bridges.add(coBridge);
}
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;
}
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;
}
public List<CityFurniture> getCityFurniture() {
return cityfurniture;
public int getBridgeCount(){
return bridges.size();
}
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;
}
public void addGenericCityObject(GenericCityObject coGenericCityObject) {
genericObjects.add(coGenericCityObject);
public int getOtherCityObjectsCount(){
return genericObjects.size();
}
public void setCityModel(CityModel cModel) {
this.cModel = cModel;
public void addTransportation(TransportationObject to) {
roads.add(to.getGmlId());
cache.put(to);
}
public CityModel getCityModel() {
return cModel;
public Stream<TransportationObject> getTransportation() {
return roads.stream().map(co -> (TransportationObject) cache.get(co));
}
public List<TransportationObject> getTransportation() {
public List<GmlId> getTransportationIds() {
return roads;
}
public List<Tunnel> getTunnels() {
return tunnels;
public int getTransportationCount(){
return roads.size();
}
public List<WaterObject> getWater() {
return water;
public void addTunnel(Tunnel tunnel) {
tunnels.add(tunnel.getGmlId());
cache.put(tunnel);
}
public List<CityObject> getLand() {
return land;
public Stream<Tunnel> getTunnels() {
return tunnels.stream().map(co -> (Tunnel) cache.get(co));
}
public List<Vegetation> getVegetation() {
return vegetation;
public List<GmlId> getTunnelIds() {
return tunnels;
}
public int getTunnelCount(){
return tunnels.size();
}
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) {
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) {
vegetation.add(veg);
vegetation.add(veg.getGmlId());
cache.put(veg);
}
public void addTransportation(TransportationObject to) {
roads.add(to);
public Stream<Vegetation> getVegetation() {
return vegetation.stream().map(co -> (Vegetation) cache.get(co));
}
public void addTunnel(Tunnel tunnel) {
tunnels.add(tunnel);
public List<GmlId> getVegetationIds() {
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() {
......@@ -349,100 +503,109 @@ public class CityDoctorModel {
}
private void replaceWaterObject(CityObject currentFeature, CityObject nextFeature) {
int index = water.indexOf(currentFeature);
int index = water.indexOf(currentFeature.getGmlId());
if (index == -1) {
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) {
int index = land.indexOf(currentFeature);
int index = land.indexOf(currentFeature.getGmlId());
if (index == -1) {
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) {
int index = vegetation.indexOf(currentFeature);
int index = vegetation.indexOf(currentFeature.getGmlId());
if (index == -1) {
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) {
int index = cityfurniture.indexOf(currentFeature);
int index = cityfurniture.indexOf(currentFeature.getGmlId());
if (index == -1) {
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) {
int index = genericObjects.indexOf(currentFeature);
int index = genericObjects.indexOf(currentFeature.getGmlId());
if (index == -1) {
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) {
int index = roads.indexOf(currentFeature);
int index = roads.indexOf(currentFeature.getGmlId());
if (index == -1) {
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) {
int index = tunnels.indexOf(currentFeature);
int index = tunnels.indexOf(currentFeature.getGmlId());
if (index == -1) {
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) {
int index = bridges.indexOf(currentFeature);
int index = bridges.indexOf(currentFeature.getGmlId());
if (index == -1) {
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) {
int index = buildings.indexOf(currentFeature);
int index = buildings.indexOf(currentFeature.getGmlId());
if (index == -1) {
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) {
if (co instanceof Building b) {
buildings.add(b);
buildings.add(b.getGmlId());
} else if (co instanceof BridgeObject bo) {
bridges.add(bo);
bridges.add(bo.getGmlId());
} else if (co instanceof TransportationObject to) {
roads.add(to);
roads.add(to.getGmlId());
} else if (co instanceof Tunnel tu) {
tunnels.add(tu);
tunnels.add(tu.getGmlId());
} else if (co instanceof Vegetation veg) {
vegetation.add(veg);
vegetation.add(veg.getGmlId());
} else if (co instanceof LandObject lo) {
land.add(lo);
land.add(lo.getGmlId());
} else if (co instanceof WaterObject wo) {
water.add(wo);
water.add(wo.getGmlId());
} else if (co instanceof ReliefObject) {
land.add(co);
land.add(co.getGmlId());
} else if (co instanceof TinObject) {
land.add(co);
land.add(co.getGmlId());
} else if (co instanceof CityFurniture cf) {
cityfurniture.add(cf);
cityfurniture.add(cf.getGmlId());
} else if (co instanceof GenericCityObject gco) {
genericObjects.add(gco);
genericObjects.add(gco.getGmlId());
}
}
......@@ -454,11 +617,4 @@ public class CityDoctorModel {
return cityGMLVersion;
}
public void addRelief(ReliefObject relief) {
addCityObject(relief);
}
public void addTin(TinObject tin) {
addCityObject(tin);
}
}
......@@ -27,5 +27,5 @@ public enum FeatureType {
BUILDING, TRANSPORTATION, VEGETATION, BRIDGE, LAND, WATER, BOUNDARY_SURFACE, INSTALLATION, OPENING,
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,8 +5,16 @@ import org.apache.logging.log4j.Logger;
import org.citygml4j.core.model.core.AbstractGenericAttributeProperty;
import org.citygml4j.core.model.generics.*;
import java.io.Serial;
import java.io.Serializable;
public class GenericAttribute {
import java.util.List;
public class GenericAttribute implements Serializable {
@Serial
private static final long serialVersionUID = -4101408947632132328L;
private static final Logger logger = LogManager.getLogger(GenericAttribute.class);
......@@ -45,6 +53,22 @@ public class GenericAttribute {
} else if (attributeProperty.getObject() instanceof CodeAttribute ca) {
type = String.format("CodeAttribute (%s)", ca.getValue().getLanguage());
value = 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();
StringBuilder sb = new StringBuilder();
sb.append("{");
for (AbstractGenericAttributeProperty attribute : attributes) {
if (attribute.getObject() != null) {
sb.append(attribute.getObject().getName());
sb.append(" = ");
sb.append(attribute.getObject().getValue());
sb.append("; ");
}
}
sb.replace(sb.length() - 1, sb.length(), "}");
value = String.format("'%s'", sb);
} else {
logger.warn("GenericAttribute {} is of unknown type {}", attributeProperty, attributeProperty.getObject());
value = attributeProperty.getObject().getValue().toString();
......
......@@ -111,7 +111,7 @@ public class GenericCityObject extends CityObject {
cgmlGos.getDeprecatedProperties().setLod4Geometry(new SolidProperty(solid));
break;
default:
throw new IllegalStateException("Cannot add " + geom.getLod() + " solid to buildings");
throw new IllegalStateException("Cannot add " + geom.getLod() + " solid to generic city object");
}
}
@Override
......@@ -121,7 +121,7 @@ public class GenericCityObject extends CityObject {
@Override
public FeatureType getFeatureType() {
return FeatureType.GENERIC_CITY_OBJECT;
return FeatureType.OTHER_CITY_OBJECT;
}
public List<BoundarySurface> getBoundarySurfaces() {
......
......@@ -26,6 +26,8 @@ import de.hft.stuttgart.citydoctor2.utils.BoundingBoxCalculator;
import de.hft.stuttgart.citydoctor2.utils.SerializablePair;
import javafx.scene.paint.Color;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serial;
import java.util.*;
......@@ -53,9 +55,9 @@ public class Geometry extends GmlElement {
private CityObject parent;
private final List<Polygon> polygons = new ArrayList<>(2);
private List<Edge> edges;
private Map<SerializablePair<Vertex, Vertex>, Edge> edgeMap;
private List<Vertex> vertices;
private transient List<Edge> edges;
private transient Map<SerializablePair<Vertex, Vertex>, Edge> edgeMap;
private transient List<Vertex> vertices;
private Orientation orientation;
public Geometry(GeometryType type, Lod lod, Orientation orientation) {
......@@ -344,6 +346,12 @@ public class Geometry extends GmlElement {
return false;
}
@Serial
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
edges = new ArrayList<>();
edgeMap = new HashMap<>();
}
public void clearMetaData() {
if (vertices != null) {
......
package de.hft.stuttgart.citydoctor2.datastructure;
import java.io.Serial;
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 de.hft.stuttgart.citydoctor2.math.TransformationMatrix;
......@@ -16,9 +22,15 @@ public class ImplicitGeometryHolder extends Geometry {
@Serial
private static final long serialVersionUID = -8938931081577196349L;
private static final Logger logger = LogManager.getLogger(ImplicitGeometryHolder.class);
private ImplicitGeometry cgmlImplicitGeometry = null;
public enum PrototypeGeometryType {
LIBRARY_OBJECT, RELATIVE_GEOMETRY
}
private ImplicitGeometry cgmlImplicitGeometry = null;
private static ConcurrentHashMap<ImplicitGeometryHolder, ImplicitGeometry> deferredRelGeomObjects = new ConcurrentHashMap<>();
private final PrototypeGeometryType type;
private final Geometry prototypeGeometry;
......@@ -38,7 +50,46 @@ public class ImplicitGeometryHolder extends Geometry {
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");
}
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);
} else {
missingGeoms.add(gmlId);
}
}
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
* transformed geometry into this object.
......@@ -54,6 +105,30 @@ public class ImplicitGeometryHolder extends Geometry {
return type;
}
/**
* Resets the Object maps of {@link RelativeGeometry} and {@link LibraryObject} to prevent memory and data leaks
*/
public static void resetObjectMaps() {
RelativeGeometry.resetObjectMap();
LibraryObject.resetObjectMap();
}
/**
* Prepares the prototype geometries for checking and sets a lock to prevent clearing of metadata
*/
public static void preparePrototypeGeometriesForChecking(){
RelativeGeometry.preparePrototypeGeometriesForChecking();
LibraryObject.preparePrototypeGeometriesForChecking();
}
/**
* Clears metadata creating for checking of prototype geometries and releases the metadata lock
*/
public static void clearMetaDataOfPrototypeGeometries(){
RelativeGeometry.clearMetaDataOfPrototypeGeometries();
LibraryObject.clearMetaDataOfPrototypeGeometries();
}
@Override
public void accept(CheckableVisitor c) {
prototypeGeometry.accept(c);
......@@ -64,8 +139,5 @@ public class ImplicitGeometryHolder extends Geometry {
return prototypeGeometry.isValidated();
}
public enum PrototypeGeometryType {
LIBRARY_OBJECT, RELATIVE_GEOMETRY
}
}
......@@ -4,7 +4,7 @@ import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParser;
import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntry;
import de.hft.stuttgart.citydoctor2.utils.Localization;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
......@@ -26,8 +26,8 @@ public class LibraryObject extends Geometry {
private static final Logger logger = LogManager.getLogger(LibraryObject.class);
@Serial
private static final long serialVersionUID = -50293435187454911L;
private static Map<String, LibraryObject> libraryObjects = new ConcurrentHashMap<>();
private static boolean metadataLocked = false;
private static final Map<String, LibraryObject> libraryObjects = new ConcurrentHashMap<>();
public static LibraryObject of(Path path, ParserConfiguration config) {
if (libraryObjects.containsKey(path.toString())) {
......@@ -44,22 +44,6 @@ public class LibraryObject extends Geometry {
return libOb;
}
public static LibraryObject of(CityGmlZipEntry entry, ParserConfiguration config) {
String fileName = entry.getEntrySubPath();
if (libraryObjects.containsKey(fileName)){
return libraryObjects.get(fileName);
}
Geometry protoGeom = parseZipEntry(entry, 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(fileName, libOb);
return libOb;
}
private LibraryObject(GeometryType type, Lod lod, Orientation orientation) {
super(type, lod, orientation);
}
......@@ -69,31 +53,15 @@ public class LibraryObject extends Geometry {
Geometry geo = null;
if (Files.exists(path)) {
try {
geo = getProtoGeometry(CityGmlParser.parseCityGmlFileSilently(path.toString(), config));
geo = getProtoGeometry(CityGmlParser.nestedCityGmlFileParse(path.toString(), config));
} catch (CityGmlParseException e) {
logger.error(String.format(
"Encountered an error while parsing library object %s", path));
logger.error(Localization.getText("LibraryObject.parsingError"), path);
logger.error(e.getStackTrace());
} catch (InvalidGmlFileException e) {
logger.error(e.getStackTrace());
}
} else {
logger.error(String.format("Implicit geometry references non-existing library object file %s.", path));
}
return geo;
}
private static Geometry parseZipEntry(CityGmlZipEntry entry, ParserConfiguration config) {
Geometry geo = null;
try {
entry.loadEntry(config);
geo = getProtoGeometry(entry.getModel());
} catch (InvalidGmlFileException e) {
logger.error(e.getStackTrace());
} catch (CityGmlParseException e) {
logger.error(String.format(
"Encountered an error while parsing library object %s", entry.getEntrySubPath()));
logger.error(e.getStackTrace());
logger.error(Localization.getText("LibraryObject.fileMissing"), path);
}
return geo;
}
......@@ -111,4 +79,33 @@ public class LibraryObject extends Geometry {
return objects.get(0).getHighestLodGeometry();
}
public static void resetObjectMap() {
libraryObjects.clear();
}
public static void preparePrototypeGeometriesForChecking() {
libraryObjects.values().forEach(LibraryObject::updateEdgesAndVertices);
metadataLocked = true;
}
public static void clearMetaDataOfPrototypeGeometries() {
metadataLocked = false;
libraryObjects.values().forEach(LibraryObject::clearMetaData);
}
@Override
public void updateEdgesAndVertices(){
if (!metadataLocked) {
super.updateEdgesAndVertices();
}
}
@Override
public void clearMetaData(){
if (!metadataLocked) {
super.clearMetaData();
}
}
}
......@@ -44,17 +44,11 @@ public class Opening extends CityObject {
private BoundarySurface partOf;
private OpeningType type;
private SurfaceFeatureType featureType;
private AbstractFillingSurface ao;
private Opening(OpeningType type) {
this.type = type;
}
public Opening(OpeningType type, SurfaceFeatureType featureType, BoundarySurface partOf,
public Opening(OpeningType type, BoundarySurface partOf,
AbstractFillingSurface ao) {
this.featureType = featureType;
this.partOf = partOf;
this.type = type;
this.ao = ao;
......@@ -96,11 +90,6 @@ public class Opening extends CityObject {
}
}
public SurfaceFeatureType getSurfaceFeatureType() {
return featureType;
}
public BoundarySurface getPartOf() {
return partOf;
}
......
package de.hft.stuttgart.citydoctor2.datastructure;
import de.hft.stuttgart.citydoctor2.check.CheckableVisitor;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.utils.CityGmlUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.citygml4j.core.model.construction.OtherConstruction;
import org.citygml4j.core.model.core.AbstractCityObject;
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 java.io.Serial;
import java.util.ArrayList;
import java.util.List;
public class OtherConstructionObject extends CityObject{
@Serial
private static final long serialVersionUID = -3885206364978761701L;
private static final Logger logger = LogManager.getLogger(OtherConstructionObject.class);
private final List<BoundarySurface> boundarySurfaceList = new ArrayList<>();
private OtherConstruction gmlObject;
@Override
public void accept(CheckableVisitor c) {
super.accept(c);
if (c.canExecute(this)) {
c.check(this);
}
for (BoundarySurface bs : boundarySurfaceList) {
bs.accept(c);
}
}
public void setGmlObject(OtherConstruction gmlObject) {
this.gmlObject = gmlObject;
}
@Override
public void rebuildGeometries(GeometryFactory factory, ParserConfiguration config) {
for (Geometry geom : getGeometries()) {
if (geom instanceof ImplicitGeometryHolder) {
continue;
}
if (geom.getType() == GeometryType.MULTI_SURFACE) {
MultiSurface ms = CityGmlUtils.createMultiSurface(geom, factory, config);
setMultiSurfaceAccordingToLod(geom, ms);
} else {
Solid solid = CityGmlUtils.createSolid(geom, factory, config);
setSolidAccordingToLod(geom, solid);
}
}
removeEmptyBoundarySurfaces();
}
private void removeEmptyBoundarySurfaces() {
for (BoundarySurface bs : boundarySurfaceList) {
if (bs.getGeometries().isEmpty()) {
for (AbstractSpaceBoundaryProperty bsp : gmlObject.getBoundaries()) {
if (bsp.getObject() != null && bsp.getObject() == bs.getGmlObject()) {
logger.warn("Found empty boundary surface: {}, removing from feature", bs.getGmlId());
gmlObject.getBoundaries().remove(bsp);
break;
}
}
}
}
}
private void setMultiSurfaceAccordingToLod(Geometry geom, MultiSurface ms) {
switch (geom.getLod()) {
case LOD0:
gmlObject.setLod0MultiSurface(new MultiSurfaceProperty(ms));
break;
case LOD2:
gmlObject.setLod2MultiSurface(new MultiSurfaceProperty(ms));
break;
case LOD3:
gmlObject.setLod3MultiSurface(new MultiSurfaceProperty(ms));
break;
default:
throw new IllegalStateException("Cannot add " + geom.getLod() + " multi surface to other construction object");
}
}
private void setSolidAccordingToLod(Geometry geom, Solid solid) {
switch (geom.getLod()) {
case LOD1:
gmlObject.setLod1Solid(new SolidProperty(solid));
break;
case LOD2:
gmlObject.setLod2Solid(new SolidProperty(solid));
break;
case LOD3:
gmlObject.setLod3Solid(new SolidProperty(solid));
break;
default:
throw new IllegalStateException("Cannot add " + geom.getLod() + " solid to other construction object");
}
}
@Override
public OtherConstruction getGmlObject() {
return gmlObject;
}
@Override
public void unsetGmlGeometries() {
gmlObject.setLod0MultiSurface(null);
gmlObject.setLod2MultiSurface(null);
gmlObject.setLod3MultiSurface(null);
gmlObject.setLod1Solid(null);
gmlObject.setLod2Solid(null);
gmlObject.setLod3Solid(null);
}
@Override
public CityObject getTopLevelCityObject() {
return this;
}
@Override
public FeatureType getFeatureType() {
return FeatureType.OTHER_CITY_OBJECT;
}
public void addBoundarySurface(BoundarySurface bs) {
boundarySurfaceList.add(bs);
bs.setParent(this);
}
public List<BoundarySurface> getBoundarySurfaces() {
return boundarySurfaceList;
}
}
......@@ -14,20 +14,53 @@ public class RelativeGeometry extends Geometry {
@Serial
private static final long serialVersionUID = -686112245455298977L;
private static Map<Geometry, RelativeGeometry> relativeGeometries = new ConcurrentHashMap<>();
private static final Map<GmlId, RelativeGeometry> relativeGeometries = new ConcurrentHashMap<>();
private static boolean metadataLocked = false;
public static RelativeGeometry of(Geometry geom) {
if (relativeGeometries.containsKey(geom)) {
return relativeGeometries.get(geom);
public static RelativeGeometry of(GmlId gmlId, Geometry geom) {
if (relativeGeometries.containsKey(gmlId)) {
return relativeGeometries.get(gmlId);
}
RelativeGeometry relGeo = new RelativeGeometry(geom.getType(), geom.getLod(), geom.getOrientation());
geom.getPolygons().forEach(relGeo::addPolygon);
relGeo.updateEdgesAndVertices();
relativeGeometries.put(geom, relGeo);
relativeGeometries.put(gmlId, relGeo);
return relGeo;
}
public static RelativeGeometry of(GmlId gmlId) {
return relativeGeometries.getOrDefault(gmlId, null);
}
private RelativeGeometry(GeometryType type, Lod lod, Orientation orientation) {
super(type, lod, orientation);
}
public static void resetObjectMap() {
relativeGeometries.clear();
}
public static void preparePrototypeGeometriesForChecking() {
relativeGeometries.values().forEach(RelativeGeometry::updateEdgesAndVertices);
metadataLocked = true;
}
public static void clearMetaDataOfPrototypeGeometries() {
metadataLocked = false;
relativeGeometries.values().forEach(RelativeGeometry::clearMetaData);
}
@Override
public void updateEdgesAndVertices(){
if (!metadataLocked) {
super.updateEdgesAndVertices();
}
}
@Override
public void clearMetaData(){
if (!metadataLocked) {
super.clearMetaData();
}
}
}
......@@ -9,6 +9,8 @@ public class TunnelPart extends AbstractTunnel {
private Tunnel parent;
private TunnelPart() {
}
public TunnelPart(Tunnel parent) {
this.parent = parent;
......@@ -34,6 +36,4 @@ public class TunnelPart extends AbstractTunnel {
return "TunnelPart [id=" + getGmlId() + "]";
}
private TunnelPart() {
}
}
......@@ -21,6 +21,8 @@ package de.hft.stuttgart.citydoctor2.datastructure;
import de.hft.stuttgart.citydoctor2.math.Vector3d;
import de.hft.stuttgart.citydoctor2.utils.SerializablePair;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serial;
import java.util.ArrayList;
import java.util.HashSet;
......@@ -37,7 +39,7 @@ public class Vertex extends Vector3d {
@Serial
private static final long serialVersionUID = -5525361920397934892L;
private List<SerializablePair<Geometry, HashSet<LinearRing>>> adjacentRings = new ArrayList<>(2);
private transient List<SerializablePair<Geometry, HashSet<LinearRing>>> adjacentRings = new ArrayList<>(2);
public Vertex(double x, double y, double z) {
super(x, y, z);
......@@ -91,6 +93,12 @@ public class Vertex extends Vector3d {
throw new IllegalStateException("Requested adjacent polygons with Geometry not containing this vertex");
}
@Serial
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
clearAdjacentRings();
}
public Set<Polygon> getAdjacentPolygons(Geometry geom) {
return getAdjacentPolygonsWithoutNeighbor(geom);
}
......
......@@ -24,6 +24,9 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import de.hft.stuttgart.citydoctor2.database.FeatureCache;
import de.hft.stuttgart.citydoctor2.database.UnconnectedCache;
import de.hft.stuttgart.citydoctor2.datastructure.OtherConstructionObject;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.citygml4j.core.model.CityGMLVersion;
......@@ -45,6 +48,7 @@ import org.citygml4j.core.model.building.BuildingRoomProperty;
import org.citygml4j.core.model.building.BuildingUnit;
import org.citygml4j.core.model.building.Storey;
import org.citygml4j.core.model.construction.AbstractConstruction;
import org.citygml4j.core.model.construction.OtherConstruction;
import org.citygml4j.core.model.core.AbstractCityObject;
import org.citygml4j.core.model.core.AbstractFeatureWithLifespan;
import org.citygml4j.core.model.core.AbstractGenericAttributeProperty;
......@@ -157,35 +161,32 @@ import de.hft.stuttgart.citydoctor2.datastructure.WaterObject;
import de.hft.stuttgart.citydoctor2.math.graph.KDTree;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.utils.Localization;
import de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntry;
public class Citygml3FeatureMapper extends ObjectWalker {
private static final Logger logger = LogManager.getLogger(Citygml3FeatureMapper.class);
private static FeatureCache featureCache = new FeatureCache();
private final CityDoctorModel model;
private final ParserConfiguration config;
private final Path directory;
private final CityGmlZipEntry zipEntry;
private final double neighborDistance;
private Map<String, ConcretePolygon> polygonMap = new HashMap<>();
private Map<String, CompositeCollection> compositeMap = new HashMap<>();
private List<ResolvableReference> references = new ArrayList<>();
private Map<Vertex, Vertex> vertexMap = new HashMap<>();
public Citygml3FeatureMapper(ParserConfiguration config, Path path) {
public Citygml3FeatureMapper(ParserConfiguration config, Path path, boolean unconnected) {
this.config = config;
this.directory = path.getParent();
model = new CityDoctorModel(config, path.toFile());
neighborDistance = 1.8d / Math.pow(10, config.getNumberOfRoundingPlaces());
zipEntry = null;
}
public Citygml3FeatureMapper(ParserConfiguration config, CityGmlZipEntry entry) {
this.config = config;
this.directory = null;
this.zipEntry = entry;
model = new CityDoctorModel(config, Path.of(entry.getEntrySubPath()).toFile());
if (unconnected){
model = new CityDoctorModel(config, path.toFile(), new UnconnectedCache());
} else {
featureCache.resetCache();
ImplicitGeometryHolder.resetObjectMaps();
model = new CityDoctorModel(config, path.toFile(), featureCache);
}
neighborDistance = 1.8d / Math.pow(10, config.getNumberOfRoundingPlaces());
}
......@@ -203,6 +204,32 @@ public class Citygml3FeatureMapper extends ObjectWalker {
}
@Override
public void visit(OtherConstruction gmlOc){
OtherConstructionObject oco = new OtherConstructionObject();
oco.setGmlObject(gmlOc);
mapAbstractOccupiedSpace(gmlOc, oco, Orientation.OUTWARD);
SurfaceMapper surfaceMapper = new SurfaceMapper(polygonMap, references, compositeMap, vertexMap, config);
for (AbstractSpaceBoundaryProperty surfaceProp : gmlOc.getBoundaries()) {
if (!surfaceProp.isSetObject()) {
continue;
}
AbstractSpaceBoundary surface = surfaceProp.getObject();
surface.accept(surfaceMapper);
}
for (BoundarySurface bs : surfaceMapper.getSurfaces()) {
oco.addBoundarySurface(bs);
for (Geometry geom : bs.getGeometries()) {
for (Polygon p : geom.getPolygons()) {
p.setPartOfSurface(bs);
}
}
}
finishCityObjectConstruction(oco);
model.addOtherCityObject(oco);
}
@Override
public void visit(org.citygml4j.core.model.cityfurniture.CityFurniture gmlCityFurniture) {
CityFurniture cf = new CityFurniture();
......@@ -230,7 +257,7 @@ public class Citygml3FeatureMapper extends ObjectWalker {
}
mapAbstractOccupiedSpace(gos, gco, Orientation.OUTWARD);
finishCityObjectConstruction(gco);
model.addGenericCityObject(gco);
model.addOtherCityObject(gco);
}
@Override
......@@ -1024,30 +1051,39 @@ public class Citygml3FeatureMapper extends ObjectWalker {
if (directory != null){
Path libraryObjectPath = directory.resolve(ig.getLibraryObject());
libObj = LibraryObject.of(libraryObjectPath, config);
} else {
String libraryObjectPath = ig.getLibraryObject();
Path loPath = zipEntry.resolveLibraryObjectPath(libraryObjectPath);
CityGmlZipEntry libEntry = zipEntry.getArchive().getEntry(loPath.toString());
libObj = LibraryObject.of(libEntry, config);
}
if (libObj != null) {
igh = new ImplicitGeometryHolder(ig, libObj);
}
} else if (ig.getRelativeGeometry() != null) {
AbstractGeometry aGeom = ig.getRelativeGeometry().getObject();
Geometry geom = null;
Lod lod = Lod.values()[lodInt];
RelativeGeometry relGeo = null;
if (aGeom instanceof MultiSurface ms) {
geom = parseMultiSurface(ms, lod);
} else if (aGeom instanceof Solid s) {
geom = parseSolid(s, lod, orientation);
} else if (aGeom instanceof CompositeSurface cs) {
geom = parseCompositeSurface(cs, lod);
}
if (geom != null) {
relGeo = RelativeGeometry.of(geom);
igh = new ImplicitGeometryHolder(ig, relGeo);
if (aGeom != null) {
Geometry geom = null;
if (aGeom instanceof MultiSurface ms) {
geom = parseMultiSurface(ms, lod);
} else if (aGeom instanceof Solid s) {
geom = parseSolid(s, lod, orientation);
} else if (aGeom instanceof CompositeSurface cs) {
geom = parseCompositeSurface(cs, lod);
}
if (geom != null) {
geom.setGmlId(new GmlId(aGeom.getId()));
RelativeGeometry relGeo = RelativeGeometry.of(geom.getGmlId(), geom);
igh = new ImplicitGeometryHolder(ig, relGeo);
}
} else if (ig.getRelativeGeometry().getHref() != null) {
String hrefId = ig.getRelativeGeometry().getHref();
hrefId = hrefId.startsWith("#") ? hrefId.substring(1) : hrefId;
GmlId gmlId = new GmlId(hrefId);
RelativeGeometry relGeo = RelativeGeometry.of(gmlId);
if (relGeo == null) {
igh = ImplicitGeometryHolder.deferRelativeGeomParsing(ig, lod);
} else {
igh = new ImplicitGeometryHolder(ig, relGeo);
}
} else {
logger.warn("Relative geometry of GML-ID {} has neither geometry nor an href", ig.getId());
}
} else {
......
......@@ -54,8 +54,7 @@ public class SurfaceMapper extends ObjectWalker {
@Override
public void visit(WallSurface wallSurface) {
BoundarySurface surface = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.WALL,
wallSurface);
BoundarySurface surface = new BoundarySurface(BoundarySurfaceType.WALL, wallSurface);
handleConstructionSurface(wallSurface, surface);
surfaces.add(surface);
}
......@@ -74,11 +73,11 @@ public class SurfaceMapper extends ObjectWalker {
private void readAbstractFillingSurface(AbstractFillingSurface afs, BoundarySurface cdSurface) {
Opening o;
if (afs instanceof DoorSurface ds) {
o = new Opening(OpeningType.DOOR, SurfaceFeatureType.BUILDING, cdSurface, ds);
o = new Opening(OpeningType.DOOR, cdSurface, ds);
} else if (afs instanceof WindowSurface ws) {
o = new Opening(OpeningType.WINDOW, SurfaceFeatureType.BUILDING, cdSurface, ws);
o = new Opening(OpeningType.WINDOW, cdSurface, ws);
} else {
o = new Opening(OpeningType.UNKNOWN, SurfaceFeatureType.BUILDING, cdSurface, afs);
o = new Opening(OpeningType.UNKNOWN, cdSurface, afs);
}
cdSurface.addOpening(o);
parseAndAddMultiSurface(afs.getLod0MultiSurface(), Lod.LOD0, o);
......@@ -144,64 +143,56 @@ public class SurfaceMapper extends ObjectWalker {
@Override
public void visit(FloorSurface floorSurface) {
BoundarySurface surface = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.FLOOR,
floorSurface);
BoundarySurface surface = new BoundarySurface(BoundarySurfaceType.FLOOR, floorSurface);
handleConstructionSurface(floorSurface, surface);
surfaces.add(surface);
}
@Override
public void visit(CeilingSurface ceilingSurface) {
BoundarySurface surface = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.CEILING,
ceilingSurface);
BoundarySurface surface = new BoundarySurface(BoundarySurfaceType.CEILING, ceilingSurface);
handleConstructionSurface(ceilingSurface, surface);
surfaces.add(surface);
}
@Override
public void visit(GroundSurface groundSurface) {
BoundarySurface surface = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.GROUND,
groundSurface);
BoundarySurface surface = new BoundarySurface(BoundarySurfaceType.GROUND, groundSurface);
handleConstructionSurface(groundSurface, surface);
surfaces.add(surface);
}
@Override
public void visit(InteriorWallSurface interiorWallSurface) {
BoundarySurface surface = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.INTERIOR_WALL,
interiorWallSurface);
BoundarySurface surface = new BoundarySurface(BoundarySurfaceType.INTERIOR_WALL, interiorWallSurface);
handleConstructionSurface(interiorWallSurface, surface);
surfaces.add(surface);
}
@Override
public void visit(OuterCeilingSurface outerCeilingSurface) {
BoundarySurface surface = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.OUTER_CEILING,
outerCeilingSurface);
BoundarySurface surface = new BoundarySurface(BoundarySurfaceType.OUTER_CEILING, outerCeilingSurface);
handleConstructionSurface(outerCeilingSurface, surface);
surfaces.add(surface);
}
@Override
public void visit(OuterFloorSurface outerFloorSurface) {
BoundarySurface surface = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.OUTER_FLOOR,
outerFloorSurface);
BoundarySurface surface = new BoundarySurface(BoundarySurfaceType.OUTER_FLOOR, outerFloorSurface);
handleConstructionSurface(outerFloorSurface, surface);
surfaces.add(surface);
}
@Override
public void visit(RoofSurface roofSurface) {
BoundarySurface surface = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.ROOF,
roofSurface);
BoundarySurface surface = new BoundarySurface(BoundarySurfaceType.ROOF, roofSurface);
handleConstructionSurface(roofSurface, surface);
surfaces.add(surface);
}
@Override
public void visit(ClosureSurface closureSurface) {
BoundarySurface surface = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.CLOSURE,
closureSurface);
BoundarySurface surface = new BoundarySurface(BoundarySurfaceType.CLOSURE, closureSurface);
handleThematicSurface(closureSurface, surface);
surfaces.add(surface);
}
......
......@@ -87,8 +87,13 @@ public class Triangle3d implements Serializable {
Vector3d n2 = v1.cross(v2);
return new Plane(n2, p1);
}
public boolean doesIntersect(Triangle3d other) {
return doesIntersect(other, EPSILON);
}
public boolean doesIntersect(Triangle3d other, double epsilon) {
// plane of other triangle
Plane planeT2 = other.getPlane();
// check if all points are on one side of the plane
......@@ -96,13 +101,13 @@ public class Triangle3d implements Serializable {
double distanceP2T2 = planeT2.getSignedDistance(p2);
double distanceP3T2 = planeT2.getSignedDistance(p3);
if (Math.abs(distanceP1T2) < EPSILON) {
if (Math.abs(distanceP1T2) < epsilon) {
distanceP1T2 = 0.0;
}
if (Math.abs(distanceP2T2) < EPSILON) {
if (Math.abs(distanceP2T2) < epsilon) {
distanceP2T2 = 0.0;
}
if (Math.abs(distanceP3T2) < EPSILON) {
if (Math.abs(distanceP3T2) < epsilon) {
distanceP3T2 = 0.0;
}
......@@ -123,13 +128,13 @@ public class Triangle3d implements Serializable {
double distanceP2T1 = planeT1.getSignedDistance(other.getP2());
double distanceP3T1 = planeT1.getSignedDistance(other.getP3());
if (Math.abs(distanceP1T1) < EPSILON) {
if (Math.abs(distanceP1T1) < epsilon) {
distanceP1T1 = 0.0;
}
if (Math.abs(distanceP2T1) < EPSILON) {
if (Math.abs(distanceP2T1) < epsilon) {
distanceP2T1 = 0.0;
}
if (Math.abs(distanceP3T1) < EPSILON) {
if (Math.abs(distanceP3T1) < epsilon) {
distanceP3T1 = 0.0;
}
......@@ -139,11 +144,15 @@ public class Triangle3d implements Serializable {
return false;
}
return checkTriangleLineIntersection(other, p1, p2) || checkTriangleLineIntersection(other, p1, p3)
boolean intersects = checkTriangleLineIntersection(other, p1, p2) || checkTriangleLineIntersection(other, p1, p3)
|| checkTriangleLineIntersection(other, p2, p3)
|| checkTriangleLineIntersection(this, other.p1, other.p2)
|| checkTriangleLineIntersection(this, other.p1, other.p3)
|| checkTriangleLineIntersection(this, other.p2, other.p3);
if (intersects) {
System.out.println();
}
return intersects;
}
private boolean checkTriangleLineIntersection(Triangle3d other, Vector3d a, Vector3d b) {
......@@ -171,7 +180,11 @@ public class Triangle3d implements Serializable {
private boolean doesIntersectCoplanarTriangle(Triangle3d other) {
Triangle2d t1 = projectTo2d();
Triangle2d t2 = other.projectTo2d();
return t1.intersects(t2);
boolean intersects = t1.intersects(t2);
if (intersects) {
System.out.println();
}
return intersects;
}
public Triangle2d projectTo2d() {
......
......@@ -49,6 +49,15 @@ public class EarcutTesselator {
start = addRingToArray(innerRing, vertices, start, axis);
}
// center vertices?
// double[] projectedCenter = new double[2];
// Geometry geometry = p.getParent();
// Vector3d center = geometry.getCenter();
// axis.writeCoordinatesOfVectorInArray(center, projectedCenter, 0);
// for (int i = 0; i < vertices.length; i++) {
// vertices[i] = vertices[i] - projectedCenter[i % 2];
// }
// triangulation
List<Integer> indices = Earcut.earcut(vertices, holeStart, 2);
List<Triangle3d> triangles = new ArrayList<>();
......@@ -56,14 +65,15 @@ public class EarcutTesselator {
throw new IllegalStateException();
}
for (int i = 0; i < indices.size(); i = i + 3) {
Triangle3d t = new Triangle3d(vertexObjects.get(indices.get(i + 0)),
vertexObjects.get(indices.get(i + 1)),
vertexObjects.get(indices.get(i + 2)));
Vertex v1 = vertexObjects.get(indices.get(i + 0));
Vertex v2 = vertexObjects.get(indices.get(i + 1));
Vertex v3 = vertexObjects.get(indices.get(i + 2));
Triangle3d t = new Triangle3d(v1, v2, v3);
triangles.add(t);
}
return new TesselatedPolygon(triangles, p);
}
private static void addVerticesToList(LinearRing ring, List<Vertex> vertexObjects) {
List<Vertex> vertices = ring.getVertices();
for (int i = 0; i < vertices.size() - 1; i++) {
......
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