"...moodle-assignsubmission_dta.git" did not exist on "891d09e67cf3f761ac237dd7469048d475e05fb7"
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; ...@@ -20,9 +20,11 @@ package de.hft.stuttgart.citydoctor2.datastructure;
import de.hft.stuttgart.citydoctor2.math.Vector3d; import de.hft.stuttgart.citydoctor2.math.Vector3d;
import de.hft.stuttgart.citydoctor2.utils.BoundingBoxCalculator; import de.hft.stuttgart.citydoctor2.utils.BoundingBoxCalculator;
import de.hft.stuttgart.citydoctor2.utils.visitors.MinMaxExtentVisitor;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Locale;
/** /**
* An axis aligned bounding box represented by its two corners * An axis aligned bounding box represented by its two corners
...@@ -47,6 +49,12 @@ public class BoundingBox { ...@@ -47,6 +49,12 @@ public class BoundingBox {
return BoundingBoxCalculator.calculateBoundingBoxFromPoints(points); 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. * Creates an axis aligned bounding box of the whole model.
* *
...@@ -161,4 +169,45 @@ public class BoundingBox { ...@@ -161,4 +169,45 @@ public class BoundingBox {
public double getDiagonalLength() { public double getDiagonalLength() {
return bbox[1].getDistance(bbox[0]); 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 { ...@@ -61,15 +61,11 @@ public class BridgeObject extends CityObject {
private BridgeObject parent; private BridgeObject parent;
public BridgeObject(AbstractBridge ab) { public BridgeObject(AbstractBridge ab) {
this.ab = ab; this(BridgeType.BRIDGE, ab, null);
this.type = BridgeType.BRIDGE;
this.parent = null;
} }
public BridgeObject(AbstractBridge ab, BridgeObject parent) { public BridgeObject(AbstractBridge ab, BridgeObject parent) {
this.ab = ab; this(BridgeType.BRIDGE_PART, ab, parent);
this.type = BridgeType.BRIDGE_PART;
this.parent = parent;
} }
private BridgeObject(BridgeType type, AbstractBridge ab, BridgeObject parent) { private BridgeObject(BridgeType type, AbstractBridge ab, BridgeObject parent) {
......
package de.hft.stuttgart.citydoctor2.datastructure; package de.hft.stuttgart.citydoctor2.datastructure;
import de.hft.stuttgart.citydoctor2.check.CheckableVisitor; import java.io.Serial;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; import java.util.ArrayList;
import de.hft.stuttgart.citydoctor2.utils.CityGmlUtils; import java.util.List;
import javafx.scene.paint.Color;
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.AbstractSpaceBoundaryProperty; import org.citygml4j.core.model.core.AbstractSpaceBoundaryProperty;
import org.citygml4j.core.model.deprecated.bridge.DeprecatedPropertiesOfBridgeConstructiveElement;
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.aggregates.MultiSurface; import org.xmlobjects.gml.model.geometry.aggregates.MultiSurface;
import org.xmlobjects.gml.model.geometry.aggregates.MultiSurfaceProperty; 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.Solid;
import org.xmlobjects.gml.model.geometry.primitives.SolidProperty; import org.xmlobjects.gml.model.geometry.primitives.SolidProperty;
import org.xmlobjects.gml.model.geometry.primitives.SurfaceProperty;
import java.io.Serial; import de.hft.stuttgart.citydoctor2.check.CheckableVisitor;
import java.util.ArrayList; import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import java.util.List; import de.hft.stuttgart.citydoctor2.utils.CityGmlUtils;
import javafx.scene.paint.Color;
public class BuildingConstructiveElement extends CityObject { public class BuildingConstructiveElement extends CityObject {
......
...@@ -20,6 +20,8 @@ package de.hft.stuttgart.citydoctor2.datastructure; ...@@ -20,6 +20,8 @@ package de.hft.stuttgart.citydoctor2.datastructure;
import de.hft.stuttgart.citydoctor2.check.CheckableUtilsVisitor; import de.hft.stuttgart.citydoctor2.check.CheckableUtilsVisitor;
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;
...@@ -45,15 +47,15 @@ import java.util.stream.Stream; ...@@ -45,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;
...@@ -62,11 +64,15 @@ public class CityDoctorModel { ...@@ -62,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;
...@@ -80,6 +86,7 @@ public class CityDoctorModel { ...@@ -80,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() {
...@@ -117,8 +124,59 @@ public class CityDoctorModel { ...@@ -117,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 {
...@@ -136,6 +194,7 @@ public class CityDoctorModel { ...@@ -136,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);
} }
...@@ -215,106 +274,201 @@ public class CityDoctorModel { ...@@ -215,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() {
...@@ -349,100 +503,109 @@ public class CityDoctorModel { ...@@ -349,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());
} }
} }
...@@ -454,11 +617,4 @@ public class CityDoctorModel { ...@@ -454,11 +617,4 @@ public class CityDoctorModel {
return cityGMLVersion; return cityGMLVersion;
} }
public void addRelief(ReliefObject relief) {
addCityObject(relief);
}
public void addTin(TinObject tin) {
addCityObject(tin);
}
} }
...@@ -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,8 +5,16 @@ import org.apache.logging.log4j.Logger; ...@@ -5,8 +5,16 @@ 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;
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);
...@@ -45,6 +53,22 @@ public class GenericAttribute { ...@@ -45,6 +53,22 @@ public class GenericAttribute {
} else if (attributeProperty.getObject() instanceof CodeAttribute ca) { } else if (attributeProperty.getObject() instanceof CodeAttribute ca) {
type = String.format("CodeAttribute (%s)", ca.getValue().getLanguage()); type = String.format("CodeAttribute (%s)", ca.getValue().getLanguage());
value = String.format("'''%s''' %n CodeSpace: %s", ca.getValue().getValue(), ca.getValue().getCodeSpace()); 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 { } 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();
......
...@@ -111,7 +111,7 @@ public class GenericCityObject extends CityObject { ...@@ -111,7 +111,7 @@ public class GenericCityObject extends CityObject {
cgmlGos.getDeprecatedProperties().setLod4Geometry(new SolidProperty(solid)); cgmlGos.getDeprecatedProperties().setLod4Geometry(new SolidProperty(solid));
break; 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 @Override
...@@ -121,7 +121,7 @@ public class GenericCityObject extends CityObject { ...@@ -121,7 +121,7 @@ public class GenericCityObject extends CityObject {
@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() {
......
...@@ -26,6 +26,8 @@ import de.hft.stuttgart.citydoctor2.utils.BoundingBoxCalculator; ...@@ -26,6 +26,8 @@ import de.hft.stuttgart.citydoctor2.utils.BoundingBoxCalculator;
import de.hft.stuttgart.citydoctor2.utils.SerializablePair; import de.hft.stuttgart.citydoctor2.utils.SerializablePair;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serial; import java.io.Serial;
import java.util.*; import java.util.*;
...@@ -53,9 +55,9 @@ public class Geometry extends GmlElement { ...@@ -53,9 +55,9 @@ public class Geometry extends GmlElement {
private CityObject parent; private CityObject parent;
private final List<Polygon> polygons = new ArrayList<>(2); private final List<Polygon> polygons = new ArrayList<>(2);
private List<Edge> edges; private transient List<Edge> edges;
private Map<SerializablePair<Vertex, Vertex>, Edge> edgeMap; private transient Map<SerializablePair<Vertex, Vertex>, Edge> edgeMap;
private List<Vertex> vertices; private transient List<Vertex> vertices;
private Orientation orientation; private Orientation orientation;
public Geometry(GeometryType type, Lod lod, Orientation orientation) { public Geometry(GeometryType type, Lod lod, Orientation orientation) {
...@@ -344,6 +346,12 @@ public class Geometry extends GmlElement { ...@@ -344,6 +346,12 @@ public class Geometry extends GmlElement {
return false; return false;
} }
@Serial
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
edges = new ArrayList<>();
edgeMap = new HashMap<>();
}
public void clearMetaData() { public void clearMetaData() {
if (vertices != null) { if (vertices != null) {
......
package de.hft.stuttgart.citydoctor2.datastructure; package de.hft.stuttgart.citydoctor2.datastructure;
import java.io.Serial; 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.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.math.TransformationMatrix; import de.hft.stuttgart.citydoctor2.math.TransformationMatrix;
...@@ -16,9 +22,15 @@ public class ImplicitGeometryHolder extends Geometry { ...@@ -16,9 +22,15 @@ 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);
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 PrototypeGeometryType type;
private final Geometry prototypeGeometry; private final Geometry prototypeGeometry;
...@@ -38,7 +50,46 @@ public class ImplicitGeometryHolder extends Geometry { ...@@ -38,7 +50,46 @@ public class ImplicitGeometryHolder extends Geometry {
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");
}
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 * 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.
...@@ -54,6 +105,30 @@ public class ImplicitGeometryHolder extends Geometry { ...@@ -54,6 +105,30 @@ public class ImplicitGeometryHolder extends Geometry {
return type; 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 @Override
public void accept(CheckableVisitor c) { public void accept(CheckableVisitor c) {
prototypeGeometry.accept(c); prototypeGeometry.accept(c);
...@@ -64,8 +139,5 @@ public class ImplicitGeometryHolder extends Geometry { ...@@ -64,8 +139,5 @@ public class ImplicitGeometryHolder extends Geometry {
return prototypeGeometry.isValidated(); return prototypeGeometry.isValidated();
} }
public enum PrototypeGeometryType {
LIBRARY_OBJECT, RELATIVE_GEOMETRY
}
} }
...@@ -4,7 +4,7 @@ import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException; ...@@ -4,7 +4,7 @@ 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.zip.CityGmlZipEntry; 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;
...@@ -26,8 +26,8 @@ public class LibraryObject extends Geometry { ...@@ -26,8 +26,8 @@ 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 boolean metadataLocked = false;
private static Map<String, LibraryObject> libraryObjects = new ConcurrentHashMap<>(); private static final Map<String, LibraryObject> libraryObjects = new ConcurrentHashMap<>();
public static LibraryObject of(Path path, ParserConfiguration config) { public static LibraryObject of(Path path, ParserConfiguration config) {
if (libraryObjects.containsKey(path.toString())) { if (libraryObjects.containsKey(path.toString())) {
...@@ -44,22 +44,6 @@ public class LibraryObject extends Geometry { ...@@ -44,22 +44,6 @@ public class LibraryObject extends Geometry {
return libOb; 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) { private LibraryObject(GeometryType type, Lod lod, Orientation orientation) {
super(type, lod, orientation); super(type, lod, orientation);
} }
...@@ -69,31 +53,15 @@ public class LibraryObject extends Geometry { ...@@ -69,31 +53,15 @@ public class LibraryObject extends Geometry {
Geometry geo = null; Geometry geo = null;
if (Files.exists(path)) { if (Files.exists(path)) {
try { try {
geo = getProtoGeometry(CityGmlParser.parseCityGmlFileSilently(path.toString(), config)); geo = getProtoGeometry(CityGmlParser.nestedCityGmlFileParse(path.toString(), config));
} catch (CityGmlParseException e) { } catch (CityGmlParseException e) {
logger.error(String.format( logger.error(Localization.getText("LibraryObject.parsingError"), path);
"Encountered an error while parsing library object %s", path));
logger.error(e.getStackTrace()); logger.error(e.getStackTrace());
} catch (InvalidGmlFileException e) { } catch (InvalidGmlFileException e) {
logger.error(e.getStackTrace()); logger.error(e.getStackTrace());
} }
} else { } else {
logger.error(String.format("Implicit geometry references non-existing library object file %s.", path)); logger.error(Localization.getText("LibraryObject.fileMissing"), 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());
} }
return geo; return geo;
} }
...@@ -111,4 +79,33 @@ public class LibraryObject extends Geometry { ...@@ -111,4 +79,33 @@ public class LibraryObject extends Geometry {
return objects.get(0).getHighestLodGeometry(); 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 { ...@@ -44,17 +44,11 @@ public class Opening extends CityObject {
private BoundarySurface partOf; private BoundarySurface partOf;
private OpeningType type; private OpeningType type;
private SurfaceFeatureType featureType;
private AbstractFillingSurface ao; private AbstractFillingSurface ao;
private Opening(OpeningType type) { public Opening(OpeningType type, BoundarySurface partOf,
this.type = type;
}
public Opening(OpeningType type, SurfaceFeatureType featureType, BoundarySurface partOf,
AbstractFillingSurface ao) { AbstractFillingSurface ao) {
this.featureType = featureType;
this.partOf = partOf; this.partOf = partOf;
this.type = type; this.type = type;
this.ao = ao; this.ao = ao;
...@@ -96,11 +90,6 @@ public class Opening extends CityObject { ...@@ -96,11 +90,6 @@ public class Opening extends CityObject {
} }
} }
public SurfaceFeatureType getSurfaceFeatureType() {
return featureType;
}
public BoundarySurface getPartOf() { public BoundarySurface getPartOf() {
return partOf; 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 { ...@@ -14,20 +14,53 @@ public class RelativeGeometry extends Geometry {
@Serial @Serial
private static final long serialVersionUID = -686112245455298977L; 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) { public static RelativeGeometry of(GmlId gmlId, Geometry geom) {
if (relativeGeometries.containsKey(geom)) { if (relativeGeometries.containsKey(gmlId)) {
return relativeGeometries.get(geom); return relativeGeometries.get(gmlId);
} }
RelativeGeometry relGeo = new RelativeGeometry(geom.getType(), geom.getLod(), geom.getOrientation()); RelativeGeometry relGeo = new RelativeGeometry(geom.getType(), geom.getLod(), geom.getOrientation());
geom.getPolygons().forEach(relGeo::addPolygon); geom.getPolygons().forEach(relGeo::addPolygon);
relGeo.updateEdgesAndVertices(); relGeo.updateEdgesAndVertices();
relativeGeometries.put(geom, relGeo); relativeGeometries.put(gmlId, relGeo);
return relGeo; return relGeo;
} }
public static RelativeGeometry of(GmlId gmlId) {
return relativeGeometries.getOrDefault(gmlId, null);
}
private RelativeGeometry(GeometryType type, Lod lod, Orientation orientation) { private RelativeGeometry(GeometryType type, Lod lod, Orientation orientation) {
super(type, lod, 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 { ...@@ -9,6 +9,8 @@ public class TunnelPart extends AbstractTunnel {
private Tunnel parent; private Tunnel parent;
private TunnelPart() {
}
public TunnelPart(Tunnel parent) { public TunnelPart(Tunnel parent) {
this.parent = parent; this.parent = parent;
...@@ -34,6 +36,4 @@ public class TunnelPart extends AbstractTunnel { ...@@ -34,6 +36,4 @@ public class TunnelPart extends AbstractTunnel {
return "TunnelPart [id=" + getGmlId() + "]"; return "TunnelPart [id=" + getGmlId() + "]";
} }
private TunnelPart() {
}
} }
...@@ -21,6 +21,8 @@ package de.hft.stuttgart.citydoctor2.datastructure; ...@@ -21,6 +21,8 @@ package de.hft.stuttgart.citydoctor2.datastructure;
import de.hft.stuttgart.citydoctor2.math.Vector3d; import de.hft.stuttgart.citydoctor2.math.Vector3d;
import de.hft.stuttgart.citydoctor2.utils.SerializablePair; import de.hft.stuttgart.citydoctor2.utils.SerializablePair;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serial; import java.io.Serial;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
...@@ -37,7 +39,7 @@ public class Vertex extends Vector3d { ...@@ -37,7 +39,7 @@ public class Vertex extends Vector3d {
@Serial @Serial
private static final long serialVersionUID = -5525361920397934892L; 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) { public Vertex(double x, double y, double z) {
super(x, y, z); super(x, y, z);
...@@ -91,6 +93,12 @@ public class Vertex extends Vector3d { ...@@ -91,6 +93,12 @@ public class Vertex extends Vector3d {
throw new IllegalStateException("Requested adjacent polygons with Geometry not containing this vertex"); 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) { public Set<Polygon> getAdjacentPolygons(Geometry geom) {
return getAdjacentPolygonsWithoutNeighbor(geom); return getAdjacentPolygonsWithoutNeighbor(geom);
} }
......
...@@ -24,6 +24,9 @@ import java.util.HashMap; ...@@ -24,6 +24,9 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; 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.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.citygml4j.core.model.CityGMLVersion; import org.citygml4j.core.model.CityGMLVersion;
...@@ -45,6 +48,7 @@ import org.citygml4j.core.model.building.BuildingRoomProperty; ...@@ -45,6 +48,7 @@ import org.citygml4j.core.model.building.BuildingRoomProperty;
import org.citygml4j.core.model.building.BuildingUnit; import org.citygml4j.core.model.building.BuildingUnit;
import org.citygml4j.core.model.building.Storey; import org.citygml4j.core.model.building.Storey;
import org.citygml4j.core.model.construction.AbstractConstruction; 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.AbstractCityObject;
import org.citygml4j.core.model.core.AbstractFeatureWithLifespan; import org.citygml4j.core.model.core.AbstractFeatureWithLifespan;
import org.citygml4j.core.model.core.AbstractGenericAttributeProperty; import org.citygml4j.core.model.core.AbstractGenericAttributeProperty;
...@@ -157,35 +161,32 @@ import de.hft.stuttgart.citydoctor2.datastructure.WaterObject; ...@@ -157,35 +161,32 @@ import de.hft.stuttgart.citydoctor2.datastructure.WaterObject;
import de.hft.stuttgart.citydoctor2.math.graph.KDTree; import de.hft.stuttgart.citydoctor2.math.graph.KDTree;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.utils.Localization; import de.hft.stuttgart.citydoctor2.utils.Localization;
import de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntry;
public class Citygml3FeatureMapper extends ObjectWalker { public class Citygml3FeatureMapper extends ObjectWalker {
private static final Logger logger = LogManager.getLogger(Citygml3FeatureMapper.class); private static final Logger logger = LogManager.getLogger(Citygml3FeatureMapper.class);
private static FeatureCache featureCache = new FeatureCache();
private final CityDoctorModel model; private final CityDoctorModel model;
private final ParserConfiguration config; private final ParserConfiguration config;
private final Path directory; private final Path directory;
private final CityGmlZipEntry zipEntry;
private final double neighborDistance; private final double neighborDistance;
private Map<String, ConcretePolygon> polygonMap = new HashMap<>(); private Map<String, ConcretePolygon> polygonMap = new HashMap<>();
private Map<String, CompositeCollection> compositeMap = new HashMap<>(); private Map<String, CompositeCollection> compositeMap = new HashMap<>();
private List<ResolvableReference> references = new ArrayList<>(); private List<ResolvableReference> references = new ArrayList<>();
private Map<Vertex, Vertex> vertexMap = new HashMap<>(); 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.config = config;
this.directory = path.getParent(); 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) { if (unconnected){
this.config = config; model = new CityDoctorModel(config, path.toFile(), new UnconnectedCache());
this.directory = null; } else {
this.zipEntry = entry; featureCache.resetCache();
model = new CityDoctorModel(config, Path.of(entry.getEntrySubPath()).toFile()); ImplicitGeometryHolder.resetObjectMaps();
model = new CityDoctorModel(config, path.toFile(), featureCache);
}
neighborDistance = 1.8d / Math.pow(10, config.getNumberOfRoundingPlaces()); neighborDistance = 1.8d / Math.pow(10, config.getNumberOfRoundingPlaces());
} }
...@@ -203,6 +204,32 @@ public class Citygml3FeatureMapper extends ObjectWalker { ...@@ -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 @Override
public void visit(org.citygml4j.core.model.cityfurniture.CityFurniture gmlCityFurniture) { public void visit(org.citygml4j.core.model.cityfurniture.CityFurniture gmlCityFurniture) {
CityFurniture cf = new CityFurniture(); CityFurniture cf = new CityFurniture();
...@@ -230,7 +257,7 @@ public class Citygml3FeatureMapper extends ObjectWalker { ...@@ -230,7 +257,7 @@ public class Citygml3FeatureMapper extends ObjectWalker {
} }
mapAbstractOccupiedSpace(gos, gco, Orientation.OUTWARD); mapAbstractOccupiedSpace(gos, gco, Orientation.OUTWARD);
finishCityObjectConstruction(gco); finishCityObjectConstruction(gco);
model.addGenericCityObject(gco); model.addOtherCityObject(gco);
} }
@Override @Override
...@@ -1024,30 +1051,39 @@ public class Citygml3FeatureMapper extends ObjectWalker { ...@@ -1024,30 +1051,39 @@ public class Citygml3FeatureMapper extends ObjectWalker {
if (directory != null){ if (directory != null){
Path libraryObjectPath = directory.resolve(ig.getLibraryObject()); Path libraryObjectPath = directory.resolve(ig.getLibraryObject());
libObj = LibraryObject.of(libraryObjectPath, config); 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) { if (libObj != null) {
igh = new ImplicitGeometryHolder(ig, libObj); igh = new ImplicitGeometryHolder(ig, libObj);
} }
} else if (ig.getRelativeGeometry() != null) { } else if (ig.getRelativeGeometry() != null) {
AbstractGeometry aGeom = ig.getRelativeGeometry().getObject(); AbstractGeometry aGeom = ig.getRelativeGeometry().getObject();
Geometry geom = null;
Lod lod = Lod.values()[lodInt]; Lod lod = Lod.values()[lodInt];
RelativeGeometry relGeo = null; if (aGeom != null) {
if (aGeom instanceof MultiSurface ms) { Geometry geom = null;
geom = parseMultiSurface(ms, lod); if (aGeom instanceof MultiSurface ms) {
} else if (aGeom instanceof Solid s) { geom = parseMultiSurface(ms, lod);
geom = parseSolid(s, lod, orientation); } else if (aGeom instanceof Solid s) {
} else if (aGeom instanceof CompositeSurface cs) { geom = parseSolid(s, lod, orientation);
geom = parseCompositeSurface(cs, lod); } else if (aGeom instanceof CompositeSurface cs) {
} geom = parseCompositeSurface(cs, lod);
if (geom != null) { }
relGeo = RelativeGeometry.of(geom); if (geom != null) {
igh = new ImplicitGeometryHolder(ig, relGeo); 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 { } else {
......
...@@ -54,8 +54,7 @@ public class SurfaceMapper extends ObjectWalker { ...@@ -54,8 +54,7 @@ public class SurfaceMapper extends ObjectWalker {
@Override @Override
public void visit(WallSurface wallSurface) { public void visit(WallSurface wallSurface) {
BoundarySurface surface = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.WALL, BoundarySurface surface = new BoundarySurface(BoundarySurfaceType.WALL, wallSurface);
wallSurface);
handleConstructionSurface(wallSurface, surface); handleConstructionSurface(wallSurface, surface);
surfaces.add(surface); surfaces.add(surface);
} }
...@@ -74,11 +73,11 @@ public class SurfaceMapper extends ObjectWalker { ...@@ -74,11 +73,11 @@ public class SurfaceMapper extends ObjectWalker {
private void readAbstractFillingSurface(AbstractFillingSurface afs, BoundarySurface cdSurface) { private void readAbstractFillingSurface(AbstractFillingSurface afs, BoundarySurface cdSurface) {
Opening o; Opening o;
if (afs instanceof DoorSurface ds) { 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) { } else if (afs instanceof WindowSurface ws) {
o = new Opening(OpeningType.WINDOW, SurfaceFeatureType.BUILDING, cdSurface, ws); o = new Opening(OpeningType.WINDOW, cdSurface, ws);
} else { } else {
o = new Opening(OpeningType.UNKNOWN, SurfaceFeatureType.BUILDING, cdSurface, afs); o = new Opening(OpeningType.UNKNOWN, cdSurface, afs);
} }
cdSurface.addOpening(o); cdSurface.addOpening(o);
parseAndAddMultiSurface(afs.getLod0MultiSurface(), Lod.LOD0, o); parseAndAddMultiSurface(afs.getLod0MultiSurface(), Lod.LOD0, o);
...@@ -144,64 +143,56 @@ public class SurfaceMapper extends ObjectWalker { ...@@ -144,64 +143,56 @@ public class SurfaceMapper extends ObjectWalker {
@Override @Override
public void visit(FloorSurface floorSurface) { public void visit(FloorSurface floorSurface) {
BoundarySurface surface = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.FLOOR, BoundarySurface surface = new BoundarySurface(BoundarySurfaceType.FLOOR, floorSurface);
floorSurface);
handleConstructionSurface(floorSurface, surface); handleConstructionSurface(floorSurface, surface);
surfaces.add(surface); surfaces.add(surface);
} }
@Override @Override
public void visit(CeilingSurface ceilingSurface) { public void visit(CeilingSurface ceilingSurface) {
BoundarySurface surface = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.CEILING, BoundarySurface surface = new BoundarySurface(BoundarySurfaceType.CEILING, ceilingSurface);
ceilingSurface);
handleConstructionSurface(ceilingSurface, surface); handleConstructionSurface(ceilingSurface, surface);
surfaces.add(surface); surfaces.add(surface);
} }
@Override @Override
public void visit(GroundSurface groundSurface) { public void visit(GroundSurface groundSurface) {
BoundarySurface surface = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.GROUND, BoundarySurface surface = new BoundarySurface(BoundarySurfaceType.GROUND, groundSurface);
groundSurface);
handleConstructionSurface(groundSurface, surface); handleConstructionSurface(groundSurface, surface);
surfaces.add(surface); surfaces.add(surface);
} }
@Override @Override
public void visit(InteriorWallSurface interiorWallSurface) { public void visit(InteriorWallSurface interiorWallSurface) {
BoundarySurface surface = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.INTERIOR_WALL, BoundarySurface surface = new BoundarySurface(BoundarySurfaceType.INTERIOR_WALL, interiorWallSurface);
interiorWallSurface);
handleConstructionSurface(interiorWallSurface, surface); handleConstructionSurface(interiorWallSurface, surface);
surfaces.add(surface); surfaces.add(surface);
} }
@Override @Override
public void visit(OuterCeilingSurface outerCeilingSurface) { public void visit(OuterCeilingSurface outerCeilingSurface) {
BoundarySurface surface = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.OUTER_CEILING, BoundarySurface surface = new BoundarySurface(BoundarySurfaceType.OUTER_CEILING, outerCeilingSurface);
outerCeilingSurface);
handleConstructionSurface(outerCeilingSurface, surface); handleConstructionSurface(outerCeilingSurface, surface);
surfaces.add(surface); surfaces.add(surface);
} }
@Override @Override
public void visit(OuterFloorSurface outerFloorSurface) { public void visit(OuterFloorSurface outerFloorSurface) {
BoundarySurface surface = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.OUTER_FLOOR, BoundarySurface surface = new BoundarySurface(BoundarySurfaceType.OUTER_FLOOR, outerFloorSurface);
outerFloorSurface);
handleConstructionSurface(outerFloorSurface, surface); handleConstructionSurface(outerFloorSurface, surface);
surfaces.add(surface); surfaces.add(surface);
} }
@Override @Override
public void visit(RoofSurface roofSurface) { public void visit(RoofSurface roofSurface) {
BoundarySurface surface = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.ROOF, BoundarySurface surface = new BoundarySurface(BoundarySurfaceType.ROOF, roofSurface);
roofSurface);
handleConstructionSurface(roofSurface, surface); handleConstructionSurface(roofSurface, surface);
surfaces.add(surface); surfaces.add(surface);
} }
@Override @Override
public void visit(ClosureSurface closureSurface) { public void visit(ClosureSurface closureSurface) {
BoundarySurface surface = new BoundarySurface(SurfaceFeatureType.BUILDING, BoundarySurfaceType.CLOSURE, BoundarySurface surface = new BoundarySurface(BoundarySurfaceType.CLOSURE, closureSurface);
closureSurface);
handleThematicSurface(closureSurface, surface); handleThematicSurface(closureSurface, surface);
surfaces.add(surface); surfaces.add(surface);
} }
......
...@@ -87,8 +87,13 @@ public class Triangle3d implements Serializable { ...@@ -87,8 +87,13 @@ public class Triangle3d implements Serializable {
Vector3d n2 = v1.cross(v2); Vector3d n2 = v1.cross(v2);
return new Plane(n2, p1); return new Plane(n2, p1);
} }
public boolean doesIntersect(Triangle3d other) { public boolean doesIntersect(Triangle3d other) {
return doesIntersect(other, EPSILON);
}
public boolean doesIntersect(Triangle3d other, double epsilon) {
// plane of other triangle // plane of other triangle
Plane planeT2 = other.getPlane(); Plane planeT2 = other.getPlane();
// check if all points are on one side of the plane // check if all points are on one side of the plane
...@@ -96,13 +101,13 @@ public class Triangle3d implements Serializable { ...@@ -96,13 +101,13 @@ public class Triangle3d implements Serializable {
double distanceP2T2 = planeT2.getSignedDistance(p2); double distanceP2T2 = planeT2.getSignedDistance(p2);
double distanceP3T2 = planeT2.getSignedDistance(p3); double distanceP3T2 = planeT2.getSignedDistance(p3);
if (Math.abs(distanceP1T2) < EPSILON) { if (Math.abs(distanceP1T2) < epsilon) {
distanceP1T2 = 0.0; distanceP1T2 = 0.0;
} }
if (Math.abs(distanceP2T2) < EPSILON) { if (Math.abs(distanceP2T2) < epsilon) {
distanceP2T2 = 0.0; distanceP2T2 = 0.0;
} }
if (Math.abs(distanceP3T2) < EPSILON) { if (Math.abs(distanceP3T2) < epsilon) {
distanceP3T2 = 0.0; distanceP3T2 = 0.0;
} }
...@@ -123,13 +128,13 @@ public class Triangle3d implements Serializable { ...@@ -123,13 +128,13 @@ public class Triangle3d implements Serializable {
double distanceP2T1 = planeT1.getSignedDistance(other.getP2()); double distanceP2T1 = planeT1.getSignedDistance(other.getP2());
double distanceP3T1 = planeT1.getSignedDistance(other.getP3()); double distanceP3T1 = planeT1.getSignedDistance(other.getP3());
if (Math.abs(distanceP1T1) < EPSILON) { if (Math.abs(distanceP1T1) < epsilon) {
distanceP1T1 = 0.0; distanceP1T1 = 0.0;
} }
if (Math.abs(distanceP2T1) < EPSILON) { if (Math.abs(distanceP2T1) < epsilon) {
distanceP2T1 = 0.0; distanceP2T1 = 0.0;
} }
if (Math.abs(distanceP3T1) < EPSILON) { if (Math.abs(distanceP3T1) < epsilon) {
distanceP3T1 = 0.0; distanceP3T1 = 0.0;
} }
...@@ -139,11 +144,15 @@ public class Triangle3d implements Serializable { ...@@ -139,11 +144,15 @@ public class Triangle3d implements Serializable {
return false; 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(other, p2, p3)
|| checkTriangleLineIntersection(this, other.p1, other.p2) || checkTriangleLineIntersection(this, other.p1, other.p2)
|| checkTriangleLineIntersection(this, other.p1, other.p3) || checkTriangleLineIntersection(this, other.p1, other.p3)
|| checkTriangleLineIntersection(this, other.p2, other.p3); || checkTriangleLineIntersection(this, other.p2, other.p3);
if (intersects) {
System.out.println();
}
return intersects;
} }
private boolean checkTriangleLineIntersection(Triangle3d other, Vector3d a, Vector3d b) { private boolean checkTriangleLineIntersection(Triangle3d other, Vector3d a, Vector3d b) {
...@@ -171,7 +180,11 @@ public class Triangle3d implements Serializable { ...@@ -171,7 +180,11 @@ public class Triangle3d implements Serializable {
private boolean doesIntersectCoplanarTriangle(Triangle3d other) { private boolean doesIntersectCoplanarTriangle(Triangle3d other) {
Triangle2d t1 = projectTo2d(); Triangle2d t1 = projectTo2d();
Triangle2d t2 = other.projectTo2d(); Triangle2d t2 = other.projectTo2d();
return t1.intersects(t2); boolean intersects = t1.intersects(t2);
if (intersects) {
System.out.println();
}
return intersects;
} }
public Triangle2d projectTo2d() { public Triangle2d projectTo2d() {
......
...@@ -49,6 +49,15 @@ public class EarcutTesselator { ...@@ -49,6 +49,15 @@ public class EarcutTesselator {
start = addRingToArray(innerRing, vertices, start, axis); 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 // triangulation
List<Integer> indices = Earcut.earcut(vertices, holeStart, 2); List<Integer> indices = Earcut.earcut(vertices, holeStart, 2);
List<Triangle3d> triangles = new ArrayList<>(); List<Triangle3d> triangles = new ArrayList<>();
...@@ -56,14 +65,15 @@ public class EarcutTesselator { ...@@ -56,14 +65,15 @@ public class EarcutTesselator {
throw new IllegalStateException(); throw new IllegalStateException();
} }
for (int i = 0; i < indices.size(); i = i + 3) { for (int i = 0; i < indices.size(); i = i + 3) {
Triangle3d t = new Triangle3d(vertexObjects.get(indices.get(i + 0)), Vertex v1 = vertexObjects.get(indices.get(i + 0));
vertexObjects.get(indices.get(i + 1)), Vertex v2 = vertexObjects.get(indices.get(i + 1));
vertexObjects.get(indices.get(i + 2))); Vertex v3 = vertexObjects.get(indices.get(i + 2));
Triangle3d t = new Triangle3d(v1, v2, v3);
triangles.add(t); triangles.add(t);
} }
return new TesselatedPolygon(triangles, p); return new TesselatedPolygon(triangles, p);
} }
private static void addVerticesToList(LinearRing ring, List<Vertex> vertexObjects) { private static void addVerticesToList(LinearRing ring, List<Vertex> vertexObjects) {
List<Vertex> vertices = ring.getVertices(); List<Vertex> vertices = ring.getVertices();
for (int i = 0; i < vertices.size() - 1; i++) { 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