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 {
...@@ -207,4 +208,8 @@ public abstract class AbstractErrorVisitor implements ErrorVisitor { ...@@ -207,4 +208,8 @@ public abstract class AbstractErrorVisitor implements ErrorVisitor {
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
...@@ -150,4 +151,6 @@ public interface ErrorVisitor { ...@@ -150,4 +151,6 @@ public interface ErrorVisitor {
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
...@@ -200,6 +201,10 @@ public interface HealingMethod { ...@@ -200,6 +201,10 @@ public interface HealingMethod {
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;
...@@ -404,4 +405,9 @@ public class QualityAdeErrorVisitor extends AbstractErrorVisitor { ...@@ -404,4 +405,9 @@ public class QualityAdeErrorVisitor extends AbstractErrorVisitor {
// 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();
} }
...@@ -28,6 +28,7 @@ import java.nio.file.Path; ...@@ -28,6 +28,7 @@ import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
...@@ -43,8 +44,6 @@ import javax.xml.validation.Schema; ...@@ -43,8 +44,6 @@ import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory; import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator; import javax.xml.validation.Validator;
import de.hft.stuttgart.citydoctor2.datastructure.GmlId;
import de.hft.stuttgart.citydoctor2.datastructure.ImplicitGeometryHolder;
import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
...@@ -84,8 +83,11 @@ import org.xmlobjects.schema.SchemaHandlerException; ...@@ -84,8 +83,11 @@ import org.xmlobjects.schema.SchemaHandlerException;
import org.xmlobjects.stream.XMLReader; import org.xmlobjects.stream.XMLReader;
import org.xmlobjects.stream.XMLReaderFactory; import org.xmlobjects.stream.XMLReaderFactory;
import de.hft.stuttgart.citydoctor2.check.error.XMLValidationError;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel; import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject; import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.datastructure.GmlId;
import de.hft.stuttgart.citydoctor2.datastructure.ImplicitGeometryHolder;
import de.hft.stuttgart.citydoctor2.mapper.citygml3.Citygml3FeatureMapper; import de.hft.stuttgart.citydoctor2.mapper.citygml3.Citygml3FeatureMapper;
import de.hft.stuttgart.citydoctor2.mapper.citygml3.GMLValidationHandler; import de.hft.stuttgart.citydoctor2.mapper.citygml3.GMLValidationHandler;
import de.hft.stuttgart.citydoctor2.math.Vector3d; import de.hft.stuttgart.citydoctor2.math.Vector3d;
...@@ -129,9 +131,9 @@ public class CityGmlParser { ...@@ -129,9 +131,9 @@ public class CityGmlParser {
private static CityGMLContext context; private static CityGMLContext context;
private static List<QName> chunkProperties = new ArrayList<>(); private static List<QName> chunkProperties = new ArrayList<>();
static { static {
System.setProperty("javax.xml.transform.TransformerFactory", "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl"); System.setProperty("javax.xml.transform.TransformerFactory",
"com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl");
FACTORY = SAXParserFactory.newInstance(); FACTORY = SAXParserFactory.newInstance();
try { try {
FACTORY.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, false); FACTORY.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, false);
...@@ -147,7 +149,7 @@ public class CityGmlParser { ...@@ -147,7 +149,7 @@ public class CityGmlParser {
private CityGmlParser() { private CityGmlParser() {
} }
public static synchronized CityGMLContext getContext() { public static synchronized CityGMLContext setupContext() {
if (context == null) { if (context == null) {
try { try {
context = CityGMLContext.newInstance(CityGmlParser.class.getClassLoader()); context = CityGMLContext.newInstance(CityGmlParser.class.getClassLoader());
...@@ -166,13 +168,17 @@ public class CityGmlParser { ...@@ -166,13 +168,17 @@ public class CityGmlParser {
} }
/** /**
* Parses a given CityGML file and collects the contained CityObject Features in a {@link CityDoctorModel}. * Parses a given CityGML file and collects the contained CityObject Features in
* a {@link CityDoctorModel}.
* <p/> * <p/>
* The nested parse uses an {@link de.hft.stuttgart.citydoctor2.database.UnconnectedCache UnconnectedCache}, which * The nested parse uses an
* is not connected to the database. * {@link de.hft.stuttgart.citydoctor2.database.UnconnectedCache
* UnconnectedCache}, which is not connected to the database.
* <p/> * <p/>
* Nested parsing should only be used for accessing Features in auxiliary, small CityGML files, e.g. parsing of * Nested parsing should only be used for accessing Features in auxiliary, small
* {@link de.hft.stuttgart.citydoctor2.datastructure.LibraryObject LibraryObject} files. * CityGML files, e.g. parsing of
* {@link de.hft.stuttgart.citydoctor2.datastructure.LibraryObject
* LibraryObject} files.
* *
* @param filePath String path to the file * @param filePath String path to the file
* @param config Configuration of the parser * @param config Configuration of the parser
...@@ -186,10 +192,12 @@ public class CityGmlParser { ...@@ -186,10 +192,12 @@ public class CityGmlParser {
} }
/** /**
* Parses a given CityGML file and collects the contained CityObject Features in a {@link CityDoctorModel}. * Parses a given CityGML file and collects the contained CityObject Features in
* a {@link CityDoctorModel}.
* <p/> * <p/>
* Features are held in a non-persistent, embedded Database with an in-memory upstream cache. Thus, strong references * Features are held in a non-persistent, embedded Database with an in-memory
* to {@link CityObject} are to be avoided, to allow for the memory management of the cache. * upstream cache. Thus, strong references to {@link CityObject} are to be
* avoided, to allow for the memory management of the cache.
* *
* @param filePath String path to the file * @param filePath String path to the file
* @param config Configuration of the parser * @param config Configuration of the parser
...@@ -202,12 +210,13 @@ public class CityGmlParser { ...@@ -202,12 +210,13 @@ public class CityGmlParser {
return parseCityGmlFile(filePath, config, null, null); return parseCityGmlFile(filePath, config, null, null);
} }
/** /**
* Parses a given CityGML file and collects the contained CityObject Features in a {@link CityDoctorModel}. * Parses a given CityGML file and collects the contained CityObject Features in
* a {@link CityDoctorModel}.
* <p/> * <p/>
* Features are held in a non-persistent, embedded Database with an in-memory upstream cache. Thus, strong references * Features are held in a non-persistent, embedded Database with an in-memory
* to {@link CityObject} are to be avoided, to allow for the memory management of the cache. * upstream cache. Thus, strong references to {@link CityObject} are to be
* avoided, to allow for the memory management of the cache.
* *
* @param filePath String path to the file * @param filePath String path to the file
* @param config Configuration of the parser * @param config Configuration of the parser
...@@ -222,10 +231,12 @@ public class CityGmlParser { ...@@ -222,10 +231,12 @@ public class CityGmlParser {
} }
/** /**
* Parses a given CityGML file and collects the contained CityObject Features in a {@link CityDoctorModel}. * Parses a given CityGML file and collects the contained CityObject Features in
* a {@link CityDoctorModel}.
* <p/> * <p/>
* Features are held in a non-persistent, embedded Database with an in-memory upstream cache. Thus, strong references * Features are held in a non-persistent, embedded Database with an in-memory
* to {@link CityObject} are to be avoided, to allow for the memory management of the cache. * upstream cache. Thus, strong references to {@link CityObject} are to be
* avoided, to allow for the memory management of the cache.
* *
* @param filePath String path to the file * @param filePath String path to the file
* @param config Configuration of the parser * @param config Configuration of the parser
...@@ -241,18 +252,22 @@ public class CityGmlParser { ...@@ -241,18 +252,22 @@ public class CityGmlParser {
} }
/** /**
* Parses a given CityGML file and collects the contained CityObject Features in a {@link CityDoctorModel}. * Parses a given CityGML file and collects the contained CityObject Features in
* a {@link CityDoctorModel}.
* <p/> * <p/>
* Features are held in a non-persistent, embedded Database with an in-memory upstream cache. Thus, strong references * Features are held in a non-persistent, embedded Database with an in-memory
* to {@link CityObject} are to be avoided, to allow for the memory management of the cache. * upstream cache. Thus, strong references to {@link CityObject} are to be
* avoided, to allow for the memory management of the cache.
* *
* @param filePath String path to the file * @param filePath String path to the file
* @param config Configuration of the parser * @param config Configuration of the parser
* @param l Listener hook for tracking of parsing progress * @param l Listener hook for tracking of parsing progress
* @param handler Validation handler for GML-file validation * @param handler Validation handler for GML-file validation
* @param verbose If verbosity is enabled the parser will write info logs to the logger * @param verbose If verbosity is enabled the parser will write info logs to
* @param unconnected If true the parser will use an {@link de.hft.stuttgart.citydoctor2.database.UnconnectedCache UnconnectedCache} * the logger
* to collect the parsed CityObjects * @param unconnected If true the parser will use an
* {@link de.hft.stuttgart.citydoctor2.database.UnconnectedCache
* UnconnectedCache} to collect the parsed CityObjects
* @return A {@link CityDoctorModel} object with the parsed Features * @return A {@link CityDoctorModel} object with the parsed Features
* @throws CityGmlParseException if parsing of the CityGML-file failed * @throws CityGmlParseException if parsing of the CityGML-file failed
* @throws InvalidGmlFileException if the GMLValidationHandler found an error * @throws InvalidGmlFileException if the GMLValidationHandler found an error
...@@ -260,15 +275,12 @@ public class CityGmlParser { ...@@ -260,15 +275,12 @@ public class CityGmlParser {
private static CityDoctorModel parseCityGmlFile(String filePath, ParserConfiguration config, ProgressListener l, private static CityDoctorModel parseCityGmlFile(String filePath, ParserConfiguration config, ProgressListener l,
GMLValidationHandler handler, boolean verbose, boolean unconnected) GMLValidationHandler handler, boolean verbose, boolean unconnected)
throws CityGmlParseException, InvalidGmlFileException { throws CityGmlParseException, InvalidGmlFileException {
CityGMLContext context = getContext(); CityGMLContext context = setupContext();
Path file = Paths.get(filePath); Path file = Paths.get(filePath);
List<String> validationIssues = Collections.emptyList();
if (config.getValidate()) { if (config.getValidate()) {
List<String> messages = validateFile(context, handler, file); validationIssues = validateFile(handler, file);
if (!messages.isEmpty()) {
throw new InvalidGmlFileException("Invalid GML File. First error: \n" + messages.get(0));
} }
}
try { try {
parseEpsgCodeFromFile(file, config, verbose); parseEpsgCodeFromFile(file, config, verbose);
CityGMLInputFactory in = context.createCityGMLInputFactory() CityGMLInputFactory in = context.createCityGMLInputFactory()
...@@ -277,15 +289,17 @@ public class CityGmlParser { ...@@ -277,15 +289,17 @@ public class CityGmlParser {
if (l != null) { if (l != null) {
ois.addListener(l::updateProgress); ois.addListener(l::updateProgress);
} }
return readAndKeepFeatures(config, file, in, ois, verbose, unconnected); CityDoctorModel model = readAndKeepFeatures(config, file, in, ois, verbose, unconnected);
for (String xmlError : validationIssues) {
model.addGlobalError(new XMLValidationError(xmlError));
}
return model;
} }
} catch (CityGMLReadException | IOException e) { } catch (CityGMLReadException | IOException e) {
throw new CityGmlParseException("Failed to read CityGML file", e); throw new CityGmlParseException("Failed to read CityGML file", e);
} }
} }
public static void streamCityGml(String file, ParserConfiguration config, CityGmlConsumer cityObjectConsumer, public static void streamCityGml(String file, ParserConfiguration config, CityGmlConsumer cityObjectConsumer,
String outputFile) throws CityGmlParseException { String outputFile) throws CityGmlParseException {
Path f = Paths.get(file); Path f = Paths.get(file);
...@@ -338,18 +352,18 @@ public class CityGmlParser { ...@@ -338,18 +352,18 @@ public class CityGmlParser {
private static void readAndDiscardFeatures(Path file, ParserConfiguration config, ObservedInputStream ois, private static void readAndDiscardFeatures(Path file, ParserConfiguration config, ObservedInputStream ois,
CityGmlConsumer cityObjectConsumer, String outputFile) throws CityGMLReadException { CityGmlConsumer cityObjectConsumer, String outputFile) throws CityGMLReadException {
Citygml3FeatureMapper mapper = new Citygml3FeatureMapper(config, file, false); Citygml3FeatureMapper mapper = new Citygml3FeatureMapper(config, file, false);
readAndDiscardModel(mapper, ois, cityObjectConsumer, outputFile); readAndDiscardModel(mapper, ois, cityObjectConsumer, outputFile, config, file);
} }
private static void readAndDiscardModel(Citygml3FeatureMapper mapper, ObservedInputStream ois, private static void readAndDiscardModel(Citygml3FeatureMapper mapper, ObservedInputStream ois,
CityGmlConsumer cityObjectConsumer, String outputFile) throws CityGMLReadException { CityGmlConsumer cityObjectConsumer, String outputFile, ParserConfiguration config, Path file)
getContext(); throws CityGMLReadException {
setupContext();
CityGMLInputFactory inputFactory = context.createCityGMLInputFactory() CityGMLInputFactory inputFactory = context.createCityGMLInputFactory()
.withChunking(ChunkOptions.chunkByProperties(chunkProperties).skipCityModel(false)); .withChunking(ChunkOptions.chunkByProperties(chunkProperties).skipCityModel(false));
CityGMLChunkWriter writer = null; CityGMLChunkWriter writer = null;
try (CityGMLReader reader = inputFactory.createCityGMLReader(ois)) { try (CityGMLReader reader = inputFactory.createCityGMLReader(ois)) {
CityDoctorModel model = mapper.getModel(); CityDoctorModel model = mapper.getModel();
boolean isInitialized = false; boolean isInitialized = false;
while (reader.hasNext()) { while (reader.hasNext()) {
...@@ -414,7 +428,7 @@ public class CityGmlParser { ...@@ -414,7 +428,7 @@ public class CityGmlParser {
if (outputFile == null) { if (outputFile == null) {
return null; return null;
} }
CityGMLContext gmlContext = CityGmlParser.getContext(); CityGMLContext gmlContext = CityGmlParser.setupContext();
CityGMLVersion version = CityGMLModules.getCityGMLVersion(reader.getName().getNamespaceURI()); CityGMLVersion version = CityGMLModules.getCityGMLVersion(reader.getName().getNamespaceURI());
CityGMLOutputFactory factory = gmlContext.createCityGMLOutputFactory(version); CityGMLOutputFactory factory = gmlContext.createCityGMLOutputFactory(version);
CityGMLChunkWriter writer = factory.createCityGMLChunkWriter(new File(outputFile), CityGMLChunkWriter writer = factory.createCityGMLChunkWriter(new File(outputFile),
...@@ -428,8 +442,8 @@ public class CityGmlParser { ...@@ -428,8 +442,8 @@ public class CityGmlParser {
} }
private static CityDoctorModel readAndKeepFeatures(ParserConfiguration config, Path file, private static CityDoctorModel readAndKeepFeatures(ParserConfiguration config, Path file,
CityGMLInputFactory inputFactory, ObservedInputStream ois, CityGMLInputFactory inputFactory, ObservedInputStream ois, boolean verbose, boolean unconnected)
boolean verbose, boolean unconnected) throws CityGMLReadException { throws CityGMLReadException {
return readAndKeepModel(new Citygml3FeatureMapper(config, file, unconnected), inputFactory, ois, verbose); return readAndKeepModel(new Citygml3FeatureMapper(config, file, unconnected), inputFactory, ois, verbose);
} }
...@@ -444,7 +458,7 @@ public class CityGmlParser { ...@@ -444,7 +458,7 @@ public class CityGmlParser {
CityModel cgmlModel = null; CityModel cgmlModel = null;
CityDoctorModel cdModel = mapper.getModel(); CityDoctorModel cdModel = mapper.getModel();
AutoCloseable parsingContext = cdModel.getCache().startParsingMode(); AutoCloseable parsingContext = cdModel.getCache().startParsingMode();
try (parsingContext){ try (parsingContext) {
List<AbstractCityObject> queuedObjects = new ArrayList<>(); List<AbstractCityObject> queuedObjects = new ArrayList<>();
while (reader.hasNext()) { while (reader.hasNext()) {
AbstractFeature chunk = reader.next(); AbstractFeature chunk = reader.next();
...@@ -469,7 +483,7 @@ public class CityGmlParser { ...@@ -469,7 +483,7 @@ public class CityGmlParser {
if (cgmlModel == null) { if (cgmlModel == null) {
// Add object to queue till the CityModel has been parsed // Add object to queue till the CityModel has been parsed
queuedObjects.add(aco); queuedObjects.add(aco);
}else if (!cdModel.containsGmlId(id)){ } else if (!cdModel.containsGmlId(id)) {
cgmlModel.getCityObjectMembers().add(new AbstractCityObjectProperty(aco)); cgmlModel.getCityObjectMembers().add(new AbstractCityObjectProperty(aco));
} }
} }
...@@ -482,7 +496,8 @@ public class CityGmlParser { ...@@ -482,7 +496,8 @@ public class CityGmlParser {
mapper.setCityModel(new CityModel()); mapper.setCityModel(new CityModel());
for (AbstractCityObject aco : queuedObjects) { for (AbstractCityObject aco : queuedObjects) {
if (!cdModel.containsGmlId(aco.getId())) { if (!cdModel.containsGmlId(aco.getId())) {
mapper.getModel().getCityModel().getCityObjectMembers().add(new AbstractCityObjectProperty(aco)); mapper.getModel().getCityModel().getCityObjectMembers()
.add(new AbstractCityObjectProperty(aco));
} }
} }
} }
...@@ -492,6 +507,7 @@ public class CityGmlParser { ...@@ -492,6 +507,7 @@ public class CityGmlParser {
logger.info(Localization.getText("CityGmlParser.parsedObjects"), logger.info(Localization.getText("CityGmlParser.parsedObjects"),
mapper.getModel().getNumberOfFeatures()); mapper.getModel().getNumberOfFeatures());
} }
mapper.checkUnresolvedReferences();
mapper.setCityGMLVersion(version); mapper.setCityGMLVersion(version);
return mapper.getModel(); return mapper.getModel();
} catch (Exception e) { } catch (Exception e) {
...@@ -501,7 +517,8 @@ public class CityGmlParser { ...@@ -501,7 +517,8 @@ public class CityGmlParser {
} }
} }
private static void parseEpsgCodeFromFile(Path file, ParserConfiguration config, boolean verbose) throws CityGmlParseException { private static void parseEpsgCodeFromFile(Path file, ParserConfiguration config, boolean verbose)
throws CityGmlParseException {
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file.toFile()))) { try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file.toFile()))) {
parseEpsgCodeFromStream(bis, config, verbose); parseEpsgCodeFromStream(bis, config, verbose);
} catch (ParserConfigurationException | SAXException | IOException e) { } catch (ParserConfigurationException | SAXException | IOException e) {
...@@ -668,11 +685,12 @@ public class CityGmlParser { ...@@ -668,11 +685,12 @@ public class CityGmlParser {
return CRS_FACTORY.createFromParameters(crsName, params.toArray(new String[0])); return CRS_FACTORY.createFromParameters(crsName, params.toArray(new String[0]));
} }
private static List<String> validateFile(CityGMLContext context, GMLValidationHandler handler, Path file) public static List<String> validateFile(GMLValidationHandler handler, Path file)
throws CityGmlParseException { throws CityGmlParseException {
if (handler == null) { if (handler == null) {
handler = new GMLValidationHandler(); handler = new GMLValidationHandler();
} }
setupContext();
try { try {
SchemaHandler schemaHandler = new ValidationSchemaHandler(context.getDefaultSchemaHandler()); SchemaHandler schemaHandler = new ValidationSchemaHandler(context.getDefaultSchemaHandler());
readAdditionalSchemaDefinitions(context, file, schemaHandler); readAdditionalSchemaDefinitions(context, file, schemaHandler);
...@@ -691,8 +709,7 @@ public class CityGmlParser { ...@@ -691,8 +709,7 @@ public class CityGmlParser {
private static void readAdditionalSchemaDefinitions(CityGMLContext context, Path file, SchemaHandler schemaHandler) private static void readAdditionalSchemaDefinitions(CityGMLContext context, Path file, SchemaHandler schemaHandler)
throws CityGmlParseException { throws CityGmlParseException {
try (XMLReader reader = XMLReaderFactory.newInstance(context.getXMLObjects()) try (XMLReader reader = XMLReaderFactory.newInstance(context.getXMLObjects()).withSchemaHandler(schemaHandler)
.withSchemaHandler(schemaHandler)
.createReader(file)) { .createReader(file)) {
reader.nextTag(); reader.nextTag();
} catch (Exception e) { } catch (Exception e) {
...@@ -710,5 +727,4 @@ public class CityGmlParser { ...@@ -710,5 +727,4 @@ public class CityGmlParser {
} }
} }
...@@ -41,7 +41,6 @@ import java.util.Set; ...@@ -41,7 +41,6 @@ import java.util.Set;
*/ */
public final class CityGmlUtils { public final class CityGmlUtils {
private CityGmlUtils() { private CityGmlUtils() {
// util class // util class
} }
...@@ -91,7 +90,6 @@ public final class CityGmlUtils { ...@@ -91,7 +90,6 @@ public final class CityGmlUtils {
return new CompositeSurface(surfaces); return new CompositeSurface(surfaces);
} }
public static org.xmlobjects.gml.model.geometry.primitives.LinearRing createGmlRing(GeometryFactory factory, public static org.xmlobjects.gml.model.geometry.primitives.LinearRing createGmlRing(GeometryFactory factory,
ParserConfiguration config, LinearRing lr) { ParserConfiguration config, LinearRing lr) {
...@@ -130,7 +128,8 @@ public final class CityGmlUtils { ...@@ -130,7 +128,8 @@ public final class CityGmlUtils {
List<SurfaceProperty> surfaceMember = comp.getSurfaceMembers(); List<SurfaceProperty> surfaceMember = comp.getSurfaceMembers();
for (Polygon cdPoly : geom.getPolygons()) { for (Polygon cdPoly : geom.getPolygons()) {
if (!cdPoly.isLink()) { if (!cdPoly.isLink()) {
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) {
surfaceMember.add(new SurfaceProperty(gmlPoly)); surfaceMember.add(new SurfaceProperty(gmlPoly));
} }
...@@ -150,8 +149,7 @@ public final class CityGmlUtils { ...@@ -150,8 +149,7 @@ public final class CityGmlUtils {
return solid; return solid;
} }
public static MultiSurface createMultiSurface(Geometry geom, GeometryFactory factory, public static MultiSurface createMultiSurface(Geometry geom, GeometryFactory factory, ParserConfiguration config) {
ParserConfiguration config) {
if (geom.getType() != GeometryType.MULTI_SURFACE && geom.getType() != GeometryType.COMPOSITE_SURFACE) { if (geom.getType() != GeometryType.MULTI_SURFACE && geom.getType() != GeometryType.COMPOSITE_SURFACE) {
throw new IllegalArgumentException("This can only handle MultiSurfaces"); throw new IllegalArgumentException("This can only handle MultiSurfaces");
} }
...@@ -162,7 +160,8 @@ public final class CityGmlUtils { ...@@ -162,7 +160,8 @@ public final class CityGmlUtils {
compositeCollections.add(conc.getPartOfComposite()); compositeCollections.add(conc.getPartOfComposite());
} else if (!cdPoly.isLink()) { } else if (!cdPoly.isLink()) {
// is not part of a boundary surface // is not part of a boundary surface
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));
} }
......
...@@ -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