Commit 219d36ea authored by Luna Riegel's avatar Luna Riegel
Browse files

Merge branch 'refs/heads/dev' into dev_advanced_db_management

# Conflicts:
#	CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/database/EmbeddedDatabaseHandler.java
parents 1c665219 5df59c7a
...@@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file. ...@@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [3.18.1] (2025-12-10)
### Hotfix
This hotfix removes the AUTO_SERVER flag from the embedded database, which causes a Firewall popup when the database is
started, due to opening local ports for accessing the database while CityDoctor is running.
The Firewall request can be safely denied, as CityDoctor uses the database-file for connections to the database.
Accepting the request does not open up remote connections to the database, as H2 by default only allows connections from
the local machine.
## [3.18.0] (2025-12-05) ## [3.18.0] (2025-12-05)
**Semi-breaking change:** This MR introduces breaking changes to the CityDoctorModel and CityObject classes. Usage of the CityDoctorValidation API and CLI remain backwards compatible. **Semi-breaking change:** This MR introduces breaking changes to the CityDoctorModel and CityObject classes. Usage of the CityDoctorValidation API and CLI remain backwards compatible.
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<parent> <parent>
<groupId>de.hft.stuttgart</groupId> <groupId>de.hft.stuttgart</groupId>
<artifactId>CityDoctorParent</artifactId> <artifactId>CityDoctorParent</artifactId>
<version>3.18.0</version> <version>3.18.1</version>
</parent> </parent>
<artifactId>CityDoctorCheckResult</artifactId> <artifactId>CityDoctorCheckResult</artifactId>
<dependencies> <dependencies>
......
...@@ -22,6 +22,7 @@ import java.io.BufferedReader; ...@@ -22,6 +22,7 @@ import java.io.BufferedReader;
import java.io.FileReader; import java.io.FileReader;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.file.Path;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
...@@ -65,7 +66,11 @@ public class CheckReport { ...@@ -65,7 +66,11 @@ public class CheckReport {
private Map<String, FeatureReport> featureReports; private Map<String, FeatureReport> featureReports;
public static CheckReport load(String file) throws CheckReportParseException { public static CheckReport load(String file) throws CheckReportParseException {
try (BufferedReader reader = new BufferedReader(new FileReader(file))) { return load(Path.of(file));
}
public static CheckReport load(Path path) throws CheckReportParseException {
try (BufferedReader reader = new BufferedReader(new FileReader(path.toFile()))) {
CheckReport report = (CheckReport) getContext().createUnmarshaller().unmarshal(new InputSource(reader)); CheckReport report = (CheckReport) getContext().createUnmarshaller().unmarshal(new InputSource(reader));
enrichReportStructure(report); enrichReportStructure(report);
return report; return report;
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<parent> <parent>
<groupId>de.hft.stuttgart</groupId> <groupId>de.hft.stuttgart</groupId>
<artifactId>CityDoctorParent</artifactId> <artifactId>CityDoctorParent</artifactId>
<version>3.18.0</version> <version>3.18.1</version>
</parent> </parent>
<artifactId>CityDoctorEdge</artifactId> <artifactId>CityDoctorEdge</artifactId>
<dependencies> <dependencies>
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<parent> <parent>
<groupId>de.hft.stuttgart</groupId> <groupId>de.hft.stuttgart</groupId>
<artifactId>CityDoctorParent</artifactId> <artifactId>CityDoctorParent</artifactId>
<version>3.18.0</version> <version>3.18.1</version>
</parent> </parent>
<properties> <properties>
<versionString>${project.version}-${git.commit.id.abbrev}</versionString> <versionString>${project.version}-${git.commit.id.abbrev}</versionString>
......
...@@ -40,6 +40,7 @@ import de.hft.stuttgart.citydoctor2.check.error.SolidSelfIntError; ...@@ -40,6 +40,7 @@ import de.hft.stuttgart.citydoctor2.check.error.SolidSelfIntError;
import de.hft.stuttgart.citydoctor2.check.error.SurfaceUnfragmentedError; import de.hft.stuttgart.citydoctor2.check.error.SurfaceUnfragmentedError;
import de.hft.stuttgart.citydoctor2.check.error.TooFewPolygonsError; import de.hft.stuttgart.citydoctor2.check.error.TooFewPolygonsError;
import de.hft.stuttgart.citydoctor2.check.error.UnknownCheckError; import de.hft.stuttgart.citydoctor2.check.error.UnknownCheckError;
import de.hft.stuttgart.citydoctor2.check.error.XMLValidationError;
public abstract class AbstractErrorVisitor implements ErrorVisitor { public abstract class AbstractErrorVisitor implements ErrorVisitor {
...@@ -206,5 +207,9 @@ public abstract class AbstractErrorVisitor implements ErrorVisitor { ...@@ -206,5 +207,9 @@ public abstract class AbstractErrorVisitor implements ErrorVisitor {
@Override @Override
public void visit(SolidError err) { public void visit(SolidError err) {
} }
@Override
public void visit(XMLValidationError err) {
}
} }
...@@ -83,4 +83,8 @@ public interface CheckError extends Serializable { ...@@ -83,4 +83,8 @@ public interface CheckError extends Serializable {
*/ */
public void report(ErrorReport report); public void report(ErrorReport report);
public default boolean isParsingError() {
return false;
}
} }
...@@ -26,7 +26,7 @@ import java.util.Map; ...@@ -26,7 +26,7 @@ import java.util.Map;
import de.hft.stuttgart.citydoctor2.utils.CheckErrorFound; import de.hft.stuttgart.citydoctor2.utils.CheckErrorFound;
import de.hft.stuttgart.citydoctor2.utils.visitors.CheckableErrorCollector; import de.hft.stuttgart.citydoctor2.utils.visitors.CheckableErrorCollector;
import de.hft.stuttgart.citydoctor2.utils.visitors.ClearVisitorResultsVisitor; import de.hft.stuttgart.citydoctor2.utils.visitors.ClearResultsVisitor;
import de.hft.stuttgart.citydoctor2.utils.visitors.ClearMetaInformationVisitor; import de.hft.stuttgart.citydoctor2.utils.visitors.ClearMetaInformationVisitor;
import de.hft.stuttgart.citydoctor2.utils.visitors.ContainsAnyErrorVisitor; import de.hft.stuttgart.citydoctor2.utils.visitors.ContainsAnyErrorVisitor;
import de.hft.stuttgart.citydoctor2.utils.visitors.ContainsErrorVisitor; import de.hft.stuttgart.citydoctor2.utils.visitors.ContainsErrorVisitor;
...@@ -221,18 +221,23 @@ public abstract class Checkable implements Serializable { ...@@ -221,18 +221,23 @@ public abstract class Checkable implements Serializable {
} }
/** /**
* Clears the checkResults list of this checkable. * Clears the checkResults of this checkable unless the error occured during parsing.
*/ */
public void clearCheckResults() { public void clearCheckResults() {
setValidated(false); checkResults.entrySet().removeIf(e -> {
checkResults.clear(); if (e.getValue().getError() == null) {
return true;
}
return !e.getValue().getError().isParsingError();
});
setValidated(!checkResults.isEmpty());
} }
/** /**
* Clears the checkResults list of this checkable and all child objects in its datastructure. * Clears the checkResults list of this checkable and all child objects in its datastructure.
*/ */
public final void clearAllContainedCheckResults() { public final void clearAllContainedCheckResults() {
this.accept(new ClearVisitorResultsVisitor()); this.accept(new ClearResultsVisitor());
} }
/** /**
......
...@@ -66,6 +66,7 @@ public record ErrorId(String name) implements Serializable { ...@@ -66,6 +66,7 @@ public record ErrorId(String name) implements Serializable {
public static final ErrorId SE_BS_UNFRAGMENTED = new ErrorId("SE_BS_UNFRAGMENTED"); public static final ErrorId SE_BS_UNFRAGMENTED = new ErrorId("SE_BS_UNFRAGMENTED");
public static final ErrorId GE_P_DEGENERATED_RING = new ErrorId("GE_P_DEGENERATED_POLYGON"); public static final ErrorId GE_P_DEGENERATED_RING = new ErrorId("GE_P_DEGENERATED_POLYGON");
public static final ErrorId SE_POLYGON_WITHOUT_SURFACE = new ErrorId("SE_POLYGON_WITHOUT_SURFACE"); public static final ErrorId SE_POLYGON_WITHOUT_SURFACE = new ErrorId("SE_POLYGON_WITHOUT_SURFACE");
public static final ErrorId SC_SCHEMA_VALIDATION = new ErrorId("SC_SCHEMA_VALIDATION");
......
...@@ -58,6 +58,7 @@ import de.hft.stuttgart.citydoctor2.check.error.SolidSelfIntError; ...@@ -58,6 +58,7 @@ import de.hft.stuttgart.citydoctor2.check.error.SolidSelfIntError;
import de.hft.stuttgart.citydoctor2.check.error.SurfaceUnfragmentedError; import de.hft.stuttgart.citydoctor2.check.error.SurfaceUnfragmentedError;
import de.hft.stuttgart.citydoctor2.check.error.TooFewPolygonsError; import de.hft.stuttgart.citydoctor2.check.error.TooFewPolygonsError;
import de.hft.stuttgart.citydoctor2.check.error.UnknownCheckError; import de.hft.stuttgart.citydoctor2.check.error.UnknownCheckError;
import de.hft.stuttgart.citydoctor2.check.error.XMLValidationError;
/** /**
* Visitor pattern interface to access errors. This is to determine the type of * Visitor pattern interface to access errors. This is to determine the type of
...@@ -149,5 +150,7 @@ public interface ErrorVisitor { ...@@ -149,5 +150,7 @@ public interface ErrorVisitor {
public void visit(CheckError err); public void visit(CheckError err);
public void visit(SolidError err); public void visit(SolidError err);
public void visit(XMLValidationError err);
} }
...@@ -51,6 +51,7 @@ import de.hft.stuttgart.citydoctor2.check.error.SolidSelfIntError; ...@@ -51,6 +51,7 @@ import de.hft.stuttgart.citydoctor2.check.error.SolidSelfIntError;
import de.hft.stuttgart.citydoctor2.check.error.SurfaceUnfragmentedError; import de.hft.stuttgart.citydoctor2.check.error.SurfaceUnfragmentedError;
import de.hft.stuttgart.citydoctor2.check.error.TooFewPolygonsError; import de.hft.stuttgart.citydoctor2.check.error.TooFewPolygonsError;
import de.hft.stuttgart.citydoctor2.check.error.UnknownCheckError; import de.hft.stuttgart.citydoctor2.check.error.UnknownCheckError;
import de.hft.stuttgart.citydoctor2.check.error.XMLValidationError;
/** /**
* Visitor pattern interface used in the healing procedures. The modification * Visitor pattern interface used in the healing procedures. The modification
...@@ -199,6 +200,10 @@ public interface HealingMethod { ...@@ -199,6 +200,10 @@ public interface HealingMethod {
default boolean visit(PolygonWithoutSurfaceError err, ModificationListener l) { default boolean visit(PolygonWithoutSurfaceError err, ModificationListener l) {
return false; return false;
} }
default boolean visit(XMLValidationError err, ModificationListener l) {
return false;
}
public HealingMethod createNew(); public HealingMethod createNew();
......
...@@ -58,6 +58,7 @@ import de.hft.stuttgart.citydoctor2.check.error.SolidSelfIntError; ...@@ -58,6 +58,7 @@ import de.hft.stuttgart.citydoctor2.check.error.SolidSelfIntError;
import de.hft.stuttgart.citydoctor2.check.error.SurfaceUnfragmentedError; import de.hft.stuttgart.citydoctor2.check.error.SurfaceUnfragmentedError;
import de.hft.stuttgart.citydoctor2.check.error.TooFewPolygonsError; import de.hft.stuttgart.citydoctor2.check.error.TooFewPolygonsError;
import de.hft.stuttgart.citydoctor2.check.error.UnknownCheckError; import de.hft.stuttgart.citydoctor2.check.error.UnknownCheckError;
import de.hft.stuttgart.citydoctor2.check.error.XMLValidationError;
import de.hft.stuttgart.citydoctor2.datastructure.Edge; import de.hft.stuttgart.citydoctor2.datastructure.Edge;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing; import de.hft.stuttgart.citydoctor2.datastructure.LinearRing;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon; import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
...@@ -403,5 +404,10 @@ public class QualityAdeErrorVisitor extends AbstractErrorVisitor { ...@@ -403,5 +404,10 @@ public class QualityAdeErrorVisitor extends AbstractErrorVisitor {
public void visit(PolygonWithoutSurfaceError err) { public void visit(PolygonWithoutSurfaceError err) {
// not translated // not translated
} }
@Override
public void visit(XMLValidationError err) {
// not translated
}
} }
package de.hft.stuttgart.citydoctor2.check.error;
import java.io.Serial;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.ErrorId;
import de.hft.stuttgart.citydoctor2.check.ErrorReport;
import de.hft.stuttgart.citydoctor2.check.ErrorType;
import de.hft.stuttgart.citydoctor2.check.ErrorVisitor;
import de.hft.stuttgart.citydoctor2.check.HealingMethod;
import de.hft.stuttgart.citydoctor2.check.ModificationListener;
import de.hft.stuttgart.citydoctor2.datastructure.GmlElement;
public class XMLValidationError implements CheckError {
@Serial
private static final long serialVersionUID = 4002356100680460598L;
private String message;
public XMLValidationError(String message) {
this.message = message;
}
@Override
public ErrorType getType() {
return ErrorType.ERROR;
}
@Override
public ErrorId getErrorId() {
return ErrorId.SC_SCHEMA_VALIDATION;
}
@Override
public GmlElement getFeature() {
return null;
}
@Override
public void accept(ErrorVisitor errorVisitor) {
errorVisitor.visit(this);
}
@Override
public boolean accept(HealingMethod method, ModificationListener l) {
return method.visit(this, l);
}
public String getMessage() {
return message;
}
@Override
public void report(ErrorReport report) {
report.add("message", message);
}
@Override
public boolean isParsingError() {
return true;
}
}
...@@ -18,13 +18,10 @@ ...@@ -18,13 +18,10 @@
*/ */
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.Logger;
import org.citygml4j.core.model.core.AbstractSpaceBoundaryProperty;
import org.citygml4j.core.model.deprecated.bridge.DeprecatedPropertiesOfBridgeConstructiveElement; 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.GeometryProperty;
...@@ -34,14 +31,13 @@ import org.xmlobjects.gml.model.geometry.complexes.CompositeSurface; ...@@ -34,14 +31,13 @@ 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 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 BridgeConstructiveElement extends CityObject { public class BridgeConstructiveElement extends CityObject {
private static final Logger logger = LogManager.getLogger(BridgeConstructiveElement.class);
private static final String CANNOT_ADD = "Cannot add "; private static final String CANNOT_ADD = "Cannot add ";
@Serial @Serial
...@@ -105,20 +101,6 @@ public class BridgeConstructiveElement extends CityObject { ...@@ -105,20 +101,6 @@ public class BridgeConstructiveElement extends CityObject {
} }
} }
private void reCreateBoundarySurface(GeometryFactory factory, ParserConfiguration config, BoundarySurface bs) {
if (bs.getGeometries().isEmpty()) {
for (AbstractSpaceBoundaryProperty bsp : gmlBridgeElement.getBoundaries()) {
if (bsp.getObject() != null && bsp.getObject() == bs.getGmlObject()) {
logger.warn("Found empty boundary surface: {}, removing from BridgeConstructiveElement", bs.getGmlId());
gmlBridgeElement.getBoundaries().remove(bsp);
break;
}
}
return;
}
bs.reCreateGeometries(factory, config);
}
private void setCompositeSurfaceAccordingToLod(Geometry geom, CompositeSurface cs) { private void setCompositeSurfaceAccordingToLod(Geometry geom, CompositeSurface cs) {
switch (geom.getLod()) { switch (geom.getLod()) {
case LOD1: case LOD1:
......
...@@ -23,6 +23,8 @@ import java.util.ArrayList; ...@@ -23,6 +23,8 @@ import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.StringJoiner;
import java.util.function.Function;
import de.hft.stuttgart.citydoctor2.database.FeatureCache; import de.hft.stuttgart.citydoctor2.database.FeatureCache;
import de.hft.stuttgart.citydoctor2.database.UnconnectedCache; import de.hft.stuttgart.citydoctor2.database.UnconnectedCache;
...@@ -172,10 +174,13 @@ public class Citygml3FeatureMapper extends ObjectWalker { ...@@ -172,10 +174,13 @@ public class Citygml3FeatureMapper extends ObjectWalker {
private final Path directory; private final Path directory;
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<>();
private Map<String, List<GmlId>> unresolvedPolyRefIDMap = new HashMap<>();
private Map<String, GmlId> parsedPolygonsIdMap = new HashMap<>();
public Citygml3FeatureMapper(ParserConfiguration config, Path path, boolean unconnected) { public Citygml3FeatureMapper(ParserConfiguration config, Path path, boolean unconnected) {
this.config = config; this.config = config;
this.directory = path.getParent(); this.directory = path.getParent();
...@@ -197,6 +202,37 @@ public class Citygml3FeatureMapper extends ObjectWalker { ...@@ -197,6 +202,37 @@ public class Citygml3FeatureMapper extends ObjectWalker {
} }
} }
public void checkUnresolvedReferences() {
if (unresolvedPolyRefIDMap.isEmpty()) {
return;
}
boolean xLinkGlobalError = false;
List<String> crossRefs = new ArrayList<>();
for (Map.Entry<String, List<GmlId>> entry : unresolvedPolyRefIDMap.entrySet()) {
String id = entry.getKey();
boolean emptyCrossFeatureReference = parsedPolygonsIdMap.containsKey(id);
xLinkGlobalError = xLinkGlobalError || emptyCrossFeatureReference;
if (emptyCrossFeatureReference) {
List<GmlId> gmlIds = entry.getValue();
StringJoiner joiner = new StringJoiner(", ");
gmlIds.forEach(gmlId -> joiner.add(gmlId.toString()));
GmlId crossFeatureId = parsedPolygonsIdMap.get(id);
//TODO: Localize String
logger.warn("Polygon {} of Feature {} is being referenced in other Features: {}", id, crossFeatureId, joiner);
crossRefs.add(id);
}
}
if (xLinkGlobalError) {
//TODO: Localize String
logger.warn("Model has Features containing cross-feature references without their own copies of the referenced polygons");
}
crossRefs.forEach(unresolvedPolyRefIDMap::remove);
if(!unresolvedPolyRefIDMap.isEmpty()) {
logger.warn("Model contains polygon references that could not be found");
}
}
@Override @Override
public void visit(AbstractSpace space) { public void visit(AbstractSpace space) {
// if we are here, an AbstractSpace thing was read that is not handled in the // if we are here, an AbstractSpace thing was read that is not handled in the
...@@ -903,7 +939,7 @@ public class Citygml3FeatureMapper extends ObjectWalker { ...@@ -903,7 +939,7 @@ public class Citygml3FeatureMapper extends ObjectWalker {
private void finishCityObjectConstruction(CityObject co) { private void finishCityObjectConstruction(CityObject co) {
parseId(co.getGmlObject(), co); parseId(co.getGmlObject(), co);
co.clearGmlGeometries(); co.clearGmlGeometries();
resolveAndClearReferences(); resolveAndClearReferences(co);
updateEdgesAndVertices(co); updateEdgesAndVertices(co);
} }
...@@ -1092,7 +1128,7 @@ public class Citygml3FeatureMapper extends ObjectWalker { ...@@ -1092,7 +1128,7 @@ public class Citygml3FeatureMapper extends ObjectWalker {
return igh; return igh;
} }
private void resolveAndClearReferences() { private void resolveAndClearReferences(CityObject co) {
for (ResolvableReference ref : references) { for (ResolvableReference ref : references) {
String href = ref.href(); String href = ref.href();
if (href.startsWith("#")) { if (href.startsWith("#")) {
...@@ -1107,6 +1143,9 @@ public class Citygml3FeatureMapper extends ObjectWalker { ...@@ -1107,6 +1143,9 @@ public class Citygml3FeatureMapper extends ObjectWalker {
handlePolygonReference(href, geom); handlePolygonReference(href, geom);
} }
} }
for(String polygonId: polygonMap.keySet()){
parsedPolygonsIdMap.put(polygonId, co.getGmlId());
}
// clear storage for polygons and vertices // clear storage for polygons and vertices
references = new ArrayList<>(); references = new ArrayList<>();
...@@ -1117,9 +1156,12 @@ public class Citygml3FeatureMapper extends ObjectWalker { ...@@ -1117,9 +1156,12 @@ public class Citygml3FeatureMapper extends ObjectWalker {
private void handlePolygonReference(String href, Geometry geom) { private void handlePolygonReference(String href, Geometry geom) {
ConcretePolygon concPoly = polygonMap.get(href); ConcretePolygon concPoly = polygonMap.get(href);
if (concPoly == null) { if (concPoly == null) {
if (logger.isWarnEnabled()) { List<GmlId> featureList = unresolvedPolyRefIDMap.computeIfAbsent(href, k -> new ArrayList<>());
logger.warn(Localization.getText("FeatureMapper.polygonUnreferenced"), href); GmlId featureId = geom.getParent().getTopLevelCityObject().getGmlId();
} featureList.add(featureId);
// if (logger.isWarnEnabled()) {
// logger.warn(Localization.getText("FeatureMapper.polygonUnreferenced"), href);
// }
} else { } else {
LinkedPolygon lPoly = new LinkedPolygon(concPoly, geom); LinkedPolygon lPoly = new LinkedPolygon(concPoly, geom);
if (geom.getParent() instanceof BoundarySurface bs) { if (geom.getParent() instanceof BoundarySurface bs) {
......
...@@ -28,29 +28,38 @@ import org.xml.sax.SAXParseException; ...@@ -28,29 +28,38 @@ import org.xml.sax.SAXParseException;
public class GMLValidationHandler implements ErrorHandler { public class GMLValidationHandler implements ErrorHandler {
private static final int MAX_LINE_SIZE = 200;
private static final Logger logger = LogManager.getLogger(GMLValidationHandler.class); private static final Logger logger = LogManager.getLogger(GMLValidationHandler.class);
private final List<String> messages = new ArrayList<>(); private final List<String> messages = new ArrayList<>();
@Override @Override
public void error(SAXParseException exception) { public void error(SAXParseException exception) {
String message = "[" + exception.getLineNumber() + ", " + exception.getColumnNumber() + "] " String message = constructMessage(exception);
+ exception.getMessage();
logger.error(message); logger.error(message);
messages.add(message); messages.add(message);
} }
private String constructMessage(SAXParseException exception) {
String exceptionMessage = exception.getMessage();
String message = "[line: " + exception.getLineNumber() + "] "
+ exceptionMessage.substring(0, Math.min(exceptionMessage.length(), MAX_LINE_SIZE));
if (exceptionMessage.length() > MAX_LINE_SIZE) {
message += "...";
}
return message;
}
@Override @Override
public void warning(SAXParseException exception) { public void warning(SAXParseException exception) {
String message = "[" + exception.getLineNumber() + ", " + exception.getColumnNumber() + "] " String message = constructMessage(exception);
+ exception.getMessage();
logger.warn(message); logger.warn(message);
messages.add(message); messages.add(message);
} }
@Override @Override
public void fatalError(SAXParseException exception) { public void fatalError(SAXParseException exception) {
String message = "[" + exception.getLineNumber() + ", " + exception.getColumnNumber() + "] " String message = constructMessage(exception);
+ exception.getMessage();
logger.fatal(message); logger.fatal(message);
messages.add(message); messages.add(message);
} }
......
...@@ -32,6 +32,5 @@ public interface CityGmlConsumer { ...@@ -32,6 +32,5 @@ public interface CityGmlConsumer {
} }
// public void endOfFile();
} }
...@@ -41,175 +41,174 @@ import java.util.Set; ...@@ -41,175 +41,174 @@ import java.util.Set;
*/ */
public final class CityGmlUtils { public final class CityGmlUtils {
private CityGmlUtils() {
private CityGmlUtils() { // util class
// util class }
}
public static org.xmlobjects.gml.model.geometry.primitives.Polygon createGmlPolygon(GeometryFactory factory,
public static org.xmlobjects.gml.model.geometry.primitives.Polygon createGmlPolygon(GeometryFactory factory, Polygon cdPoly, ParserConfiguration config) {
Polygon cdPoly, ParserConfiguration config) { if (cdPoly.getExteriorRing() == null) {
if (cdPoly.getExteriorRing() == null) { return null;
return null; }
} org.xmlobjects.gml.model.geometry.primitives.Polygon gmlPoly = new org.xmlobjects.gml.model.geometry.primitives.Polygon();
org.xmlobjects.gml.model.geometry.primitives.Polygon gmlPoly = new org.xmlobjects.gml.model.geometry.primitives.Polygon(); // exterior ring
// exterior ring LinearRing extLr = cdPoly.getExteriorRing();
LinearRing extLr = cdPoly.getExteriorRing(); if (extLr.getVertices().size() < 3) {
if (extLr.getVertices().size() < 3) { // this ring does not have enough points in it
// this ring does not have enough points in it // this leads to errors when exporting therefore ignore it
// this leads to errors when exporting therefore ignore it return null;
return null; }
} org.xmlobjects.gml.model.geometry.primitives.LinearRing gmlLr = createGmlRing(factory, config, extLr);
org.xmlobjects.gml.model.geometry.primitives.LinearRing gmlLr = createGmlRing(factory, config, extLr); gmlPoly.setExterior(new AbstractRingProperty(gmlLr));
gmlPoly.setExterior(new AbstractRingProperty(gmlLr));
// interior rings
// interior rings for (LinearRing lr : cdPoly.getInnerRings()) {
for (LinearRing lr : cdPoly.getInnerRings()) { gmlLr = createGmlRing(factory, config, lr);
gmlLr = createGmlRing(factory, config, lr); if (lr.getVertices().size() < 3) {
if (lr.getVertices().size() < 3) { // this ring does not have enough points in it
// this ring does not have enough points in it // this leads to errors when exporting therefore ignore it
// this leads to errors when exporting therefore ignore it return null;
return null; }
} gmlPoly.getInterior().add(new AbstractRingProperty(gmlLr));
gmlPoly.getInterior().add(new AbstractRingProperty(gmlLr)); }
} gmlPoly.setId(cdPoly.getGmlId().getGmlString());
gmlPoly.setId(cdPoly.getGmlId().getGmlString()); return gmlPoly;
return gmlPoly; }
}
public static CompositeSurface createGmlComposite(GeometryFactory factory, CompositeCollection comp,
public static CompositeSurface createGmlComposite(GeometryFactory factory, CompositeCollection comp, ParserConfiguration config) {
ParserConfiguration config) { List<SurfaceProperty> surfaces = new ArrayList<>();
List<SurfaceProperty> surfaces = new ArrayList<>(); for (ConcretePolygon cd : comp.getNonRecursiveCompositeMembers()) {
for (ConcretePolygon cd : comp.getNonRecursiveCompositeMembers()) { surfaces.add(new SurfaceProperty(createGmlPolygon(factory, cd, config)));
surfaces.add(new SurfaceProperty(createGmlPolygon(factory, cd, config))); }
} for (CompositeCollection cc : comp.getChildComposites()) {
for (CompositeCollection cc : comp.getChildComposites()) { surfaces.add(new SurfaceProperty(createGmlComposite(factory, cc, config)));
surfaces.add(new SurfaceProperty(createGmlComposite(factory, cc, config))); }
} if (surfaces.isEmpty()) {
if (surfaces.isEmpty()) { return null;
return null; }
} return new CompositeSurface(surfaces);
return new CompositeSurface(surfaces); }
}
public static org.xmlobjects.gml.model.geometry.primitives.LinearRing createGmlRing(GeometryFactory factory,
ParserConfiguration config, LinearRing lr) {
public static org.xmlobjects.gml.model.geometry.primitives.LinearRing createGmlRing(GeometryFactory factory,
ParserConfiguration config, LinearRing lr) { ProjCoordinate p1 = new ProjCoordinate();
ProjCoordinate p2 = new ProjCoordinate();
ProjCoordinate p1 = new ProjCoordinate(); List<Double> ringValues = new ArrayList<>();
ProjCoordinate p2 = new ProjCoordinate(); BasicCoordinateTransform trans = config.getOriginalTransform();
List<Double> ringValues = new ArrayList<>(); for (Vertex v : lr.getVertices()) {
BasicCoordinateTransform trans = config.getOriginalTransform(); double x = v.getX();
for (Vertex v : lr.getVertices()) { double y = v.getY();
double x = v.getX(); double z = v.getZ();
double y = v.getY(); if (trans != null) {
double z = v.getZ(); p1.x = x;
if (trans != null) { p1.y = y;
p1.x = x; trans.transform(p1, p2);
p1.y = y; x = p2.x;
trans.transform(p1, p2); y = p2.y;
x = p2.x; z = z * config.getFromMeters();
y = p2.y; }
z = z * config.getFromMeters(); ringValues.add(x);
} ringValues.add(y);
ringValues.add(x); ringValues.add(z);
ringValues.add(y); }
ringValues.add(z);
} org.xmlobjects.gml.model.geometry.primitives.LinearRing gmlLr = factory.createLinearRing(ringValues, 3);
gmlLr.setId(lr.getGmlId().getGmlString());
org.xmlobjects.gml.model.geometry.primitives.LinearRing gmlLr = factory.createLinearRing(ringValues, 3); return gmlLr;
gmlLr.setId(lr.getGmlId().getGmlString()); }
return gmlLr;
} public static Solid createSolid(Geometry geom, GeometryFactory factory, ParserConfiguration config) {
if (geom.getType() != GeometryType.SOLID) {
public static Solid createSolid(Geometry geom, GeometryFactory factory, ParserConfiguration config) { throw new IllegalArgumentException("Only solids are allowed");
if (geom.getType() != GeometryType.SOLID) { }
throw new IllegalArgumentException("Only solids are allowed");
} CompositeSurface comp = new CompositeSurface();
List<SurfaceProperty> surfaceMember = comp.getSurfaceMembers();
CompositeSurface comp = new CompositeSurface(); for (Polygon cdPoly : geom.getPolygons()) {
List<SurfaceProperty> surfaceMember = comp.getSurfaceMembers(); if (!cdPoly.isLink()) {
for (Polygon cdPoly : geom.getPolygons()) { org.xmlobjects.gml.model.geometry.primitives.Polygon gmlPoly = createGmlPolygon(factory, cdPoly,
if (!cdPoly.isLink()) { config);
org.xmlobjects.gml.model.geometry.primitives.Polygon gmlPoly = createGmlPolygon(factory, cdPoly, config); if (gmlPoly != null) {
if (gmlPoly != null) { surfaceMember.add(new SurfaceProperty(gmlPoly));
surfaceMember.add(new SurfaceProperty(gmlPoly)); }
} } else {
} else { // add reference to polygon
// add reference to polygon surfaceMember.add(new SurfaceProperty("#" + cdPoly.getGmlId().getGmlString()));
surfaceMember.add(new SurfaceProperty("#" + cdPoly.getGmlId().getGmlString())); }
} }
}
if (surfaceMember.isEmpty()) {
if (surfaceMember.isEmpty()) { return null;
return null; }
} Solid solid = new Solid();
Solid solid = new Solid(); Shell shell = new Shell(surfaceMember);
Shell shell = new Shell(surfaceMember); solid.setExterior(new ShellProperty(shell));
solid.setExterior(new ShellProperty(shell)); solid.setId(geom.getGmlId().getGmlString());
solid.setId(geom.getGmlId().getGmlString()); return solid;
return solid; }
}
public static MultiSurface createMultiSurface(Geometry geom, GeometryFactory factory, ParserConfiguration config) {
public static MultiSurface createMultiSurface(Geometry geom, GeometryFactory factory, if (geom.getType() != GeometryType.MULTI_SURFACE && geom.getType() != GeometryType.COMPOSITE_SURFACE) {
ParserConfiguration config) { throw new IllegalArgumentException("This can only handle MultiSurfaces");
if (geom.getType() != GeometryType.MULTI_SURFACE && geom.getType() != GeometryType.COMPOSITE_SURFACE) { }
throw new IllegalArgumentException("This can only handle MultiSurfaces"); List<SurfaceProperty> surfaces = new ArrayList<>();
} Set<CompositeCollection> compositeCollections = new HashSet<>();
List<SurfaceProperty> surfaces = new ArrayList<>(); for (Polygon cdPoly : geom.getPolygons()) {
Set<CompositeCollection> compositeCollections = new HashSet<>(); if (cdPoly instanceof ConcretePolygon conc && conc.isCompositeMember()) {
for (Polygon cdPoly : geom.getPolygons()) { compositeCollections.add(conc.getPartOfComposite());
if (cdPoly instanceof ConcretePolygon conc && conc.isCompositeMember()) { } else if (!cdPoly.isLink()) {
compositeCollections.add(conc.getPartOfComposite()); // is not part of a boundary surface
} else if (!cdPoly.isLink()) { org.xmlobjects.gml.model.geometry.primitives.Polygon gmlPoly = createGmlPolygon(factory, cdPoly,
// is not part of a boundary surface config);
org.xmlobjects.gml.model.geometry.primitives.Polygon gmlPoly = createGmlPolygon(factory, cdPoly, config); if (gmlPoly != null) {
if (gmlPoly != null) { surfaces.add(new SurfaceProperty(gmlPoly));
surfaces.add(new SurfaceProperty(gmlPoly)); }
} } else {
} else { // add reference to polygon
// add reference to polygon surfaces.add(new SurfaceProperty("#" + cdPoly.getGmlId().getGmlString()));
surfaces.add(new SurfaceProperty("#" + cdPoly.getGmlId().getGmlString())); }
} }
} for (CompositeCollection cdPoly : compositeCollections) {
for (CompositeCollection cdPoly : compositeCollections) { surfaces.add(new SurfaceProperty(createGmlComposite(factory, cdPoly, config)));
surfaces.add(new SurfaceProperty(createGmlComposite(factory, cdPoly, config))); }
} if (surfaces.isEmpty()) {
if (surfaces.isEmpty()) { return null;
return null; }
} MultiSurface ms = new MultiSurface(surfaces);
MultiSurface ms = new MultiSurface(surfaces); ms.setId(geom.getGmlId().getGmlString());
ms.setId(geom.getGmlId().getGmlString()); return ms;
return ms; }
}
public static MultiSurface createMultiSurface(List<Polygon> polygons, GeometryFactory factory,
public static MultiSurface createMultiSurface(List<Polygon> polygons, GeometryFactory factory, ParserConfiguration config) {
ParserConfiguration config) { List<SurfaceProperty> surfaces = new ArrayList<>();
List<SurfaceProperty> surfaces = new ArrayList<>(); for (Polygon cdPoly : polygons) {
for (Polygon cdPoly : polygons) { org.xmlobjects.gml.model.geometry.primitives.Polygon gmlPoly = createGmlPolygon(factory, cdPoly, config);
org.xmlobjects.gml.model.geometry.primitives.Polygon gmlPoly = createGmlPolygon(factory, cdPoly, config); if (gmlPoly != null) {
if (gmlPoly != null) { surfaces.add(new SurfaceProperty(gmlPoly));
surfaces.add(new SurfaceProperty(gmlPoly)); }
} }
} if (surfaces.isEmpty()) {
if (surfaces.isEmpty()) { return null;
return null; }
} return new MultiSurface(surfaces);
return new MultiSurface(surfaces); }
}
public static CompositeSurface createCompositeSurface(Geometry geom, GeometryFactory factory,
public static CompositeSurface createCompositeSurface(Geometry geom, GeometryFactory factory, ParserConfiguration config) {
ParserConfiguration config) { List<SurfaceProperty> surfaces = new ArrayList<>();
List<SurfaceProperty> surfaces = new ArrayList<>(); for (Polygon cdPoly : geom.getPolygons()) {
for (Polygon cdPoly : geom.getPolygons()) { org.xmlobjects.gml.model.geometry.primitives.Polygon gmlPoly = createGmlPolygon(factory, cdPoly, config);
org.xmlobjects.gml.model.geometry.primitives.Polygon gmlPoly = createGmlPolygon(factory, cdPoly, config); if (gmlPoly != null) {
if (gmlPoly != null) { surfaces.add(new SurfaceProperty(gmlPoly));
surfaces.add(new SurfaceProperty(gmlPoly)); }
} }
} if (surfaces.isEmpty()) {
if (surfaces.isEmpty()) { return null;
return null; }
} return new CompositeSurface(surfaces);
return new CompositeSurface(surfaces); }
}
} }
...@@ -6,7 +6,7 @@ import de.hft.stuttgart.citydoctor2.check.Checkable; ...@@ -6,7 +6,7 @@ import de.hft.stuttgart.citydoctor2.check.Checkable;
/** /**
* This Visitor removes the check results from a CityObject and the objects in its datastructure. * This Visitor removes the check results from a CityObject and the objects in its datastructure.
*/ */
public class ClearVisitorResultsVisitor extends CheckableUtilsVisitor { public class ClearResultsVisitor extends CheckableUtilsVisitor {
@Override @Override
public void check(Checkable checkable) { public void check(Checkable checkable) {
......
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