Commit 8bafe709 authored by Matthias Betz's avatar Matthias Betz
Browse files

Added citygml4j quality ade integration

Removed produce consumer from stream reading
Added -out parameter to validation streams for writing quality ade stuff
parent b0bdd91b
Pipeline #1910 failed with stage
in 38 seconds
......@@ -18,6 +18,8 @@
*/
package de.hft.stuttgart.citydoctor2.check.error;
import java.util.Optional;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.ErrorId;
import de.hft.stuttgart.citydoctor2.check.ErrorReport;
......@@ -29,6 +31,9 @@ import de.hft.stuttgart.citydoctor2.datastructure.Edge;
import de.hft.stuttgart.citydoctor2.datastructure.GmlElement;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing;
import de.hft.stuttgart.citydoctor2.math.Vector3d;
import de.hft.stuttgart.citydoctor2.utils.QualityADEUtils;
import de.hft.stuttgart.quality.model.RingSelfIntersection;
import de.hft.stuttgart.quality.model.ValidationError;
/**
* When two edges of the same linear ring are intersecting with each other this
......@@ -111,4 +116,14 @@ public class RingEdgeIntersectionError implements CheckError {
return getRing();
}
@Override
public Optional<ValidationError> convertToQualityAdeDatastructure() {
RingSelfIntersection err = new RingSelfIntersection();
err.setLinearRingId(lr.getGmlId().getGmlString());
err.setEdge1(QualityADEUtils.convertEdge(e1));
err.setEdge2(QualityADEUtils.convertEdge(e2));
err.setVertex1(QualityADEUtils.convertVertex(intersection));
return Optional.of(err);
}
}
......@@ -18,6 +18,8 @@
*/
package de.hft.stuttgart.citydoctor2.check.error;
import java.util.Optional;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.ErrorId;
import de.hft.stuttgart.citydoctor2.check.ErrorReport;
......@@ -27,6 +29,8 @@ import de.hft.stuttgart.citydoctor2.check.HealingMethod;
import de.hft.stuttgart.citydoctor2.check.ModificationListener;
import de.hft.stuttgart.citydoctor2.datastructure.GmlElement;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing;
import de.hft.stuttgart.quality.model.RingNotClosed;
import de.hft.stuttgart.quality.model.ValidationError;
/**
* If the first and last point of a linear ring are not the same, this error is
......@@ -83,4 +87,11 @@ public class RingNotClosedError implements CheckError {
public GmlElement getFeature() {
return getRing();
}
}
@Override
public Optional<ValidationError> convertToQualityAdeDatastructure() {
RingNotClosed err = new RingNotClosed();
err.setLinearRingId(ring.getGmlId().getGmlString());
return Optional.of(err);
}
}
......@@ -18,6 +18,8 @@
*/
package de.hft.stuttgart.citydoctor2.check.error;
import java.util.Optional;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.ErrorId;
import de.hft.stuttgart.citydoctor2.check.ErrorReport;
......@@ -27,6 +29,8 @@ import de.hft.stuttgart.citydoctor2.check.HealingMethod;
import de.hft.stuttgart.citydoctor2.check.ModificationListener;
import de.hft.stuttgart.citydoctor2.datastructure.GmlElement;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing;
import de.hft.stuttgart.quality.model.TooFewPoints;
import de.hft.stuttgart.quality.model.ValidationError;
/**
* If a linear ring has less than 4 distinct points, it is has too few points.
......@@ -82,4 +86,11 @@ public class RingTooFewPointsError implements CheckError {
public GmlElement getFeature() {
return getRing();
}
@Override
public Optional<ValidationError> convertToQualityAdeDatastructure() {
TooFewPoints err = new TooFewPoints();
err.setLinearRingId(lr.getGmlId().getGmlString());
return Optional.of(err);
}
}
......@@ -100,5 +100,4 @@ public class SchematronError implements CheckError {
public GmlElement getFeature() {
return null;
}
}
......@@ -19,6 +19,7 @@
package de.hft.stuttgart.citydoctor2.check.error;
import java.util.List;
import java.util.Optional;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.ErrorId;
......@@ -30,6 +31,9 @@ import de.hft.stuttgart.citydoctor2.check.ModificationListener;
import de.hft.stuttgart.citydoctor2.datastructure.Edge;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.datastructure.GmlElement;
import de.hft.stuttgart.citydoctor2.utils.QualityADEUtils;
import de.hft.stuttgart.quality.model.SolidNotClosed;
import de.hft.stuttgart.quality.model.ValidationError;
/**
* If a geometry has holes in it, it results in edges being traversed only once.
......@@ -93,4 +97,14 @@ public class SolidNotClosedError implements CheckError {
public GmlElement getFeature() {
return getGeometry();
}
@Override
public Optional<ValidationError> convertToQualityAdeDatastructure() {
SolidNotClosed err = new SolidNotClosed();
err.setGeometryId(g.getGmlId().getGmlString());
for (Edge e : errorEdges) {
err.getEdges().add(QualityADEUtils.convertEdge(e));
}
return Optional.of(err);
}
}
......@@ -19,6 +19,7 @@
package de.hft.stuttgart.citydoctor2.check.error;
import java.util.List;
import java.util.Optional;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.ErrorId;
......@@ -30,6 +31,8 @@ import de.hft.stuttgart.citydoctor2.check.ModificationListener;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.datastructure.GmlElement;
import de.hft.stuttgart.citydoctor2.utils.PolygonIntersection;
import de.hft.stuttgart.quality.model.SolidSelfIntersection;
import de.hft.stuttgart.quality.model.ValidationError;
/**
* When two polygons of the same geometry are intersecting each other.
......@@ -92,4 +95,14 @@ public class SolidSelfIntError implements CheckError {
public GmlElement getFeature() {
return getGeometry();
}
@Override
public Optional<ValidationError> convertToQualityAdeDatastructure() {
SolidSelfIntersection err = new SolidSelfIntersection();
err.setGeometryId(g.getGmlId().getGmlString());
PolygonIntersection polygonIntersection = intersections.get(0);
err.setPolygonId1(polygonIntersection.getP1().getGmlId().getGmlString());
err.setPolygonId2(polygonIntersection.getP2().getGmlId().getGmlString());
return Optional.of(err);
}
}
......@@ -18,6 +18,8 @@
*/
package de.hft.stuttgart.citydoctor2.check.error;
import java.util.Optional;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.ErrorId;
import de.hft.stuttgart.citydoctor2.check.ErrorReport;
......@@ -27,6 +29,8 @@ import de.hft.stuttgart.citydoctor2.check.HealingMethod;
import de.hft.stuttgart.citydoctor2.check.ModificationListener;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.datastructure.GmlElement;
import de.hft.stuttgart.quality.model.TooFewPolygons;
import de.hft.stuttgart.quality.model.ValidationError;
/**
* When a geometry has less than 4 polygons, it cannot form a valid solid.
......@@ -83,4 +87,11 @@ public class TooFewPolygonsError implements CheckError {
public GmlElement getFeature() {
return getGeometry();
}
@Override
public Optional<ValidationError> convertToQualityAdeDatastructure() {
TooFewPolygons err = new TooFewPolygons();
err.setGeometryId(g.getGmlId().getGmlString());
return Optional.of(err);
}
}
......@@ -19,8 +19,15 @@
package de.hft.stuttgart.citydoctor2.datastructure;
import java.io.File;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;
import org.citygml4j.CityGMLContext;
......@@ -28,14 +35,23 @@ import org.citygml4j.builder.jaxb.CityGMLBuilder;
import org.citygml4j.builder.jaxb.CityGMLBuilderException;
import org.citygml4j.factory.GMLGeometryFactory;
import org.citygml4j.model.citygml.core.CityModel;
import org.citygml4j.model.citygml.core.CityObjectMember;
import org.citygml4j.model.module.citygml.CityGMLVersion;
import org.citygml4j.xml.io.CityGMLOutputFactory;
import org.citygml4j.xml.io.writer.CityGMLWriteException;
import org.citygml4j.xml.io.writer.CityModelInfo;
import org.citygml4j.xml.io.writer.CityModelWriter;
import org.citygml4j.xml.io.writer.CityGMLWriter;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.ErrorId;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.utils.Localization;
import de.hft.stuttgart.citydoctor2.utils.QualityADEUtils;
import de.hft.stuttgart.quality.QualityADEModule;
import de.hft.stuttgart.quality.model.Validation;
import de.hft.stuttgart.quality.model.jaxb.ErrorStatistics;
import de.hft.stuttgart.quality.model.jaxb.FeatureStatistics;
import de.hft.stuttgart.quality.model.jaxb.Statistics;
import de.hft.stuttgart.quality.model.jaxb.ValidationPlan;
/**
* The complete CityGML model containing all features that are used in
......@@ -58,6 +74,8 @@ public class CityDoctorModel {
private String fileName;
private File file;
private List<CheckError> globalErrors;
private boolean isValidated = false;
private ValidationPlan plan;
public CityDoctorModel(ParserConfiguration config, File file) {
if (config == null) {
......@@ -75,6 +93,15 @@ public class CityDoctorModel {
globalErrors = new ArrayList<>();
}
public boolean isValidated() {
return isValidated;
}
public void setValidated(ValidationPlan plan) {
this.plan = plan;
this.isValidated = true;
}
public void addGlobalError(CheckError err) {
globalErrors.add(err);
}
......@@ -100,30 +127,108 @@ public class CityDoctorModel {
CityGMLContext gmlContext = CityGMLContext.getInstance();
CityGMLBuilder builder = gmlContext.createCityGMLBuilder();
CityGMLOutputFactory factory = builder.createCityGMLOutputFactory();
try (CityModelWriter writer = factory.createCityModelWriter(new File(file))) {
writer.setCityModelInfo(new CityModelInfo(cModel));
try (CityGMLWriter writer = factory.createCityGMLWriter(new File(file))) {
if (isValidated) {
writer.setPrefix("qual", QualityADEModule.NAMESPACE_URI);
writer.setSchemaLocation(QualityADEModule.NAMESPACE_URI,
"https://transfer.hft-stuttgart.de/pages/qualityade/0.1/qualityAde.xsd");
// remove old model if available
QualityADEUtils.removeValidation(cModel);
// create new quality ade validation datastructures
Validation val = createValidation();
// add to city model
cModel.addGenericApplicationPropertyOfCityModel(val);
}
writer.setIndentString(" ");
writer.setPrefixes(CityGMLVersion.DEFAULT);
writer.setSchemaLocations(CityGMLVersion.DEFAULT);
writer.writeStartDocument();
GMLGeometryFactory gmlFactory = new GMLGeometryFactory();
storeCityObjects(writer, buildings, gmlFactory);
storeCityObjects(writer, vegetation, gmlFactory);
storeCityObjects(writer, bridges, gmlFactory);
storeCityObjects(writer, land, gmlFactory);
storeCityObjects(writer, roads, gmlFactory);
storeCityObjects(writer, water, gmlFactory);
writer.writeEndDocument();
storeCityObjects(buildings, gmlFactory);
storeCityObjects(vegetation, gmlFactory);
storeCityObjects(bridges, gmlFactory);
storeCityObjects(land, gmlFactory);
storeCityObjects(roads, gmlFactory);
storeCityObjects(water, gmlFactory);
writer.write(cModel);
cModel.unsetCityObjectMember();
}
}
private void storeCityObjects(CityModelWriter writer, List<? extends CityObject> cos, GMLGeometryFactory gmlFactory)
throws CityGMLWriteException {
private void storeCityObjects(List<? extends CityObject> cos, GMLGeometryFactory gmlFactory) {
for (CityObject co : cos) {
QualityADEUtils.removeValidationResult(co);
if (isValidated) {
QualityADEUtils.writeQualityAde(co);
}
co.reCreateGeometries(gmlFactory, config);
writer.writeFeatureMember(co.getGmlObject());
co.unsetGmlGeometries();
cModel.addCityObjectMember(new CityObjectMember(co.getGmlObject()));
}
}
private Validation createValidation() {
Validation val = new Validation();
val.setValidationDate(ZonedDateTime.now());
val.setValidationSoftware("CityDoctor " + Localization.getText(Localization.VERSION));
Statistics statistics = new Statistics();
Set<CheckError> errors = collectErrors();
Map<ErrorId, AtomicInteger> errorCount = new HashMap<>();
for (CheckError e : errors) {
errorCount.compute(e.getErrorId(), (k, v) -> {
if (v == null) {
return new AtomicInteger(1);
}
v.incrementAndGet();
return v;
});
}
for (Entry<ErrorId, AtomicInteger> e : errorCount.entrySet()) {
ErrorStatistics stats = new ErrorStatistics();
stats.setAmount(e.getValue().get());
stats.setName(QualityADEUtils.mapErrorIdToAdeId(e.getKey()));
statistics.getErrorStatistics().add(stats);
}
statistics.setNumErrorBuildings(countValidatedCityObjects(buildings));
statistics.setNumErrorBridgeObjects(countValidatedCityObjects(bridges));
statistics.setNumErrorLandObjects(countValidatedCityObjects(land));
statistics.setNumErrorTransportation(countValidatedCityObjects(roads));
statistics.setNumErrorVegetation(countValidatedCityObjects(vegetation));
statistics.setNumErrorWaterObjects(countValidatedCityObjects(water));
val.setStatistics(statistics);
val.setValidationPlan(plan);
return val;
}
public Set<CheckError> collectErrors() {
List<CheckError> errors = new ArrayList<>();
collectErrorsFromList(errors, buildings);
collectErrorsFromList(errors, vegetation);
collectErrorsFromList(errors, bridges);
collectErrorsFromList(errors, land);
collectErrorsFromList(errors, roads);
collectErrorsFromList(errors, water);
return new HashSet<>(errors);
}
private void collectErrorsFromList(List<CheckError> errors, List<? extends CityObject> cos) {
for (CityObject co : cos) {
co.collectContainedErrors(errors);
}
}
private FeatureStatistics countValidatedCityObjects(List<? extends CityObject> cos) {
int numChecked = 0;
int numError = 0;
for (CityObject co : cos) {
if (co.isValidated()) {
numChecked++;
if (co.containsAnyError()) {
numError++;
}
}
}
return new FeatureStatistics(numChecked, numError);
}
public String getFileName() {
......
......@@ -188,7 +188,7 @@ public class ConcretePolygon extends Polygon {
if (super.containsAnyError()) {
return true;
}
if (exterior.containsAnyError()) {
if (exterior != null && exterior.containsAnyError()) {
return true;
}
if (innerRings != null) {
......
/*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
*
* This file is part of CityDoctor2.
*
* CityDoctor2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CityDoctor2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with CityDoctor2. If not, see <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.parser;
import org.citygml4j.model.citygml.core.CityModel;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
public interface CityGmlConsumer {
public default void accept(CityObject co) {
}
public default void accept(CityModel cm) {
}
}
......@@ -27,13 +27,13 @@ import java.io.UncheckedIOException;
import java.util.Enumeration;
import java.util.List;
import java.util.ServiceLoader;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import javax.xml.XMLConstants;
import javax.xml.bind.ValidationEventHandler;
import javax.xml.namespace.QName;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
......@@ -46,15 +46,24 @@ import org.citygml4j.CityGMLContext;
import org.citygml4j.builder.jaxb.CityGMLBuilder;
import org.citygml4j.builder.jaxb.CityGMLBuilderException;
import org.citygml4j.model.citygml.CityGML;
import org.citygml4j.model.citygml.ade.ADEComponent;
import org.citygml4j.model.citygml.ade.ADEException;
import org.citygml4j.model.citygml.ade.binding.ADEContext;
import org.citygml4j.model.citygml.ade.generic.ADEGenericElement;
import org.citygml4j.model.citygml.core.AbstractCityObject;
import org.citygml4j.model.citygml.core.CityModel;
import org.citygml4j.model.citygml.core.CityObjectMember;
import org.citygml4j.model.gml.feature.AbstractFeature;
import org.citygml4j.model.module.citygml.CityGMLVersion;
import org.citygml4j.xml.io.CityGMLInputFactory;
import org.citygml4j.xml.io.CityGMLOutputFactory;
import org.citygml4j.xml.io.reader.CityGMLReadException;
import org.citygml4j.xml.io.reader.CityGMLReader;
import org.citygml4j.xml.io.reader.FeatureReadMode;
import org.citygml4j.xml.io.reader.ParentInfo;
import org.citygml4j.xml.io.writer.CityGMLWriteException;
import org.citygml4j.xml.io.writer.CityModelInfo;
import org.citygml4j.xml.io.writer.CityModelWriter;
import org.osgeo.proj4j.BasicCoordinateTransform;
import org.osgeo.proj4j.CRSFactory;
import org.osgeo.proj4j.CoordinateReferenceSystem;
......@@ -73,6 +82,7 @@ import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.mapper.FeatureMapper;
import de.hft.stuttgart.citydoctor2.math.Vector3d;
import de.hft.stuttgart.citydoctor2.utils.Localization;
import de.hft.stuttgart.quality.QualityADEModule;
/**
* Utility class to parse CityGML files.
......@@ -115,43 +125,35 @@ public class CityGmlParser {
public static CityDoctorModel parseCityGmlFile(String file, ParserConfiguration config)
throws CityGmlParseException, InvalidGmlFileException {
return parseCityGmlFile(file, config, null);
return parseCityGmlFile(file, config, null, null);
}
public static CityDoctorModel parseCityGmlFile(String filePath, ParserConfiguration config, ProgressListener l)
public static CityDoctorModel parseCityGmlFile(String file, ParserConfiguration config, ProgressListener l)
throws CityGmlParseException, InvalidGmlFileException {
return parseCityGmlFile(file, config, l, null);
}
public static CityDoctorModel parseCityGmlFile(String filePath, ParserConfiguration config, ProgressListener l,
ValidationEventHandler handler) throws CityGmlParseException, InvalidGmlFileException {
File file = new File(filePath);
try {
parseEpsgCodeFromFile(file, config);
CityGMLInputFactory inputFactory = setupGmlReader(config);
CityGMLBuilder builder = setupCityGmlBuilder();
CityGMLInputFactory inputFactory = setupGmlReader(builder, config);
if (handler != null) {
inputFactory.setValidationEventHandler(handler);
}
// try with resources for automatic closing
try (ObservedInputStream ois = new ObservedInputStream(file)) {
if (l != null) {
ois.addListener(l::updateProgress);
}
try (CityGMLReader reader = inputFactory.createCityGMLReader(file.getAbsolutePath(), ois)) {
FeatureMapper mapper = new FeatureMapper(config, file);
while (reader.hasNext()) {
CityGML chunk = reader.nextFeature();
if (chunk instanceof AbstractCityObject) {
AbstractCityObject ag = (AbstractCityObject) chunk;
ag.accept(mapper);
} else if (chunk instanceof CityModel) {
CityModel cModel = (CityModel) chunk;
cModel.unsetCityObjectMember();
mapper.setCityModel(cModel);
}
}
if (logger.isInfoEnabled()) {
logger.info(Localization.getText("CityGmlParser.parsedObjects"), mapper.getModel().getNumberOfFeatures());
}
return mapper.getModel();
}
return readAndKeepFeatures(config, file, inputFactory, ois);
}
} catch (CityGMLReadException e) {
if (e.getCause() instanceof SAXParseException) {
throw new InvalidGmlFileException(Localization.getText("CityGmlParser.notValidGmlFile") + e.getCause().getMessage(), e);
throw new InvalidGmlFileException(
Localization.getText("CityGmlParser.notValidGmlFile") + e.getCause().getMessage(), e);
}
throw new CityGmlParseException(e);
} catch (IOException | CityGMLBuilderException | ParserConfigurationException | SAXException | ADEException e) {
......@@ -172,6 +174,29 @@ public class CityGmlParser {
}
}
private static CityDoctorModel readAndKeepFeatures(ParserConfiguration config, File file,
CityGMLInputFactory inputFactory, ObservedInputStream ois) throws CityGMLReadException {
try (CityGMLReader reader = inputFactory.createCityGMLReader(file.getAbsolutePath(), ois)) {
FeatureMapper mapper = new FeatureMapper(config, file);
while (reader.hasNext()) {
CityGML chunk = reader.nextFeature();
if (chunk instanceof AbstractCityObject) {
AbstractCityObject ag = (AbstractCityObject) chunk;
ag.accept(mapper);
} else if (chunk instanceof CityModel) {
CityModel cModel = (CityModel) chunk;
cModel.unsetCityObjectMember();
mapper.setCityModel(cModel);
}
}
if (logger.isInfoEnabled()) {
logger.info(Localization.getText("CityGmlParser.parsedObjects"),
mapper.getModel().getNumberOfFeatures());
}
return mapper.getModel();
}
}
private static CityDoctorModel parseCityGmlFileComplete(File file, ParserConfiguration config, ProgressListener l)
throws CityGMLBuilderException, IOException, CityGMLReadException, CityGmlParseException {
CityGMLContext context = CityGMLContext.getInstance();
......@@ -207,17 +232,8 @@ public class CityGmlParser {
}
private static CityGMLInputFactory setupGmlReader(ParserConfiguration config)
private static CityGMLInputFactory setupGmlReader(CityGMLBuilder builder, ParserConfiguration config)
throws CityGMLBuilderException, ADEException {
CityGMLContext context = CityGMLContext.getInstance();
// setup energy ade stuff, so the parser doesn't crash on encountering this
if (!context.hasADEContexts()) {
for (ADEContext adeContext : ServiceLoader.load(ADEContext.class)) {
context.registerADEContext(adeContext);
}
}
CityGMLBuilder builder = context.createCityGMLBuilder(CityGmlParser.class.getClassLoader());
CityGMLInputFactory inputFactory = builder.createCityGMLInputFactory();
inputFactory.setProperty(CityGMLInputFactory.FEATURE_READ_MODE, FeatureReadMode.SPLIT_PER_FEATURE);
if (config != null) {
......@@ -233,41 +249,53 @@ public class CityGmlParser {
return inputFactory;
}
public static FeatureStream streamCityGml(String file, ParserConfiguration config) throws CityGmlParseException {
private static CityGMLBuilder setupCityGmlBuilder() throws ADEException, CityGMLBuilderException {
CityGMLContext context = CityGMLContext.getInstance();
// setup energy ade stuff, so the parser doesn't crash on encountering this
if (!context.hasADEContexts()) {
for (ADEContext adeContext : ServiceLoader.load(ADEContext.class)) {
context.registerADEContext(adeContext);
}
}
CityGMLBuilder builder = context.createCityGMLBuilder(CityGmlParser.class.getClassLoader());
return builder;
}
public static void streamCityGml(String file, ParserConfiguration config, CityGmlConsumer cityObjectConsumer,
String outputFile) throws CityGmlParseException {
File f = new File(file);
return streamCityGml(f, config, null, f.getName());
streamCityGml(f, config, null, cityObjectConsumer, outputFile);
}
public static FeatureStream streamCityGml(File file, ParserConfiguration config, ProgressListener l,
String fileName) throws CityGmlParseException {
public static void streamCityGml(File file, ParserConfiguration config, ProgressListener l,
CityGmlConsumer cityObjectConsumer, String outputFile) throws CityGmlParseException {
try {
if (getExtension(file.getName()).equals("zip")) {
streamZipFile(file, config);
}
parseEpsgCodeFromFile(file, config);
CityGMLInputFactory inputFactory = setupGmlReader(config);
ArrayBlockingQueue<CityObject> queue = new ArrayBlockingQueue<>(1);
FeatureStream stream = new FeatureStream(queue, fileName, file);
Thread readThread = new Thread(() -> {
// try with resources for automatic closing
try (ObservedInputStream ois = new ObservedInputStream(file)) {
if (l != null) {
ois.addListener(l::updateProgress);
}
readFeatures(file, config, inputFactory, queue, ois, stream);
} catch (IOException e) {
logger.error(Localization.getText("CityGmlParser.errorReadingGmlFile"), e.getMessage());
logger.catching(Level.ERROR, e);
}
});
stream.setThread(readThread);
readThread.start();
return stream;
CityGMLBuilder builder = setupCityGmlBuilder();
startReadingCityGml(file, config, l, cityObjectConsumer, builder, outputFile);
} catch (CityGMLBuilderException | IOException | ParserConfigurationException | SAXException | ADEException e) {
throw new CityGmlParseException(e);
}
}
private static void startReadingCityGml(File file, ParserConfiguration config, ProgressListener l,
CityGmlConsumer cityObjectConsumer, CityGMLBuilder builder, String outputFile)
throws CityGMLBuilderException, ADEException {
try (ObservedInputStream ois = new ObservedInputStream(file)) {
if (l != null) {
ois.addListener(l::updateProgress);
}
readAndDiscardFeatures(file, config, builder, ois, cityObjectConsumer, outputFile);
} catch (IOException e) {
logger.error(Localization.getText("CityGmlParser.errorReadingGmlFile"), e.getMessage());
logger.catching(Level.ERROR, e);
}
}
private static void streamZipFile(File file, ParserConfiguration config) throws CityGmlParseException {
try (ZipFile zip = new ZipFile(file)) {
Enumeration<? extends ZipEntry> entries = zip.entries();
......@@ -298,9 +326,9 @@ public class CityGmlParser {
return fileName.substring(dotInd + 1).toLowerCase();
}
public static FeatureStream streamCityGml(File file, ParserConfiguration parserConfig, String fileName)
throws CityGmlParseException {
return streamCityGml(file, parserConfig, null, fileName);
public static void streamCityGml(File file, ParserConfiguration parserConfig, CityGmlConsumer cityObjectConsumer,
String outputFile) throws CityGmlParseException {
streamCityGml(file, parserConfig, null, cityObjectConsumer, outputFile);
}
/**
......@@ -322,6 +350,7 @@ public class CityGmlParser {
* @return CoordinateReferenceSystem
*/
private static CoordinateReferenceSystem crsFromSrsName(String srsName) {
srsName = srsName.trim();
Matcher mEPSG = P_EPSG.matcher(srsName);
if (mEPSG.find()) {
if ("EPSG:4979".contentEquals(srsName)) {
......@@ -361,10 +390,11 @@ public class CityGmlParser {
}
return null;
}
public static CityModel parseOnlyCityModel(File inputFile) throws CityGmlParseException {
try {
CityGMLInputFactory inputFactory = setupGmlReader(null);
CityGMLBuilder setupCityGmlBuilder = setupCityGmlBuilder();
CityGMLInputFactory inputFactory = setupGmlReader(setupCityGmlBuilder, null);
try (CityGMLReader reader = inputFactory.createCityGMLReader(inputFile)) {
while (reader.hasNext()) {
CityGML chunk = reader.nextFeature();
......@@ -381,33 +411,83 @@ public class CityGmlParser {
throw new CityGmlParseException("Did not find any CityModel in CityGML file");
}
private static void readFeatures(File file, ParserConfiguration config, CityGMLInputFactory inputFactory,
ArrayBlockingQueue<CityObject> queue, ObservedInputStream ois, FeatureStream stream) {
try (CityGMLReader reader = inputFactory.createCityGMLReader(file.getAbsolutePath(), ois)) {
private static void readAndDiscardFeatures(File file, ParserConfiguration config, CityGMLBuilder builder,
ObservedInputStream ois, CityGmlConsumer cityObjectConsumer, String outputFile)
throws CityGMLBuilderException, ADEException {
CityGMLInputFactory inputFactory = setupGmlReader(builder, config);
try (CityGMLReader reader = inputFactory.createCityGMLReader(file.getAbsolutePath(), ois);
CityModelWriter writer = createCityModelWriter(builder, outputFile)) {
FeatureMapper mapper = new FeatureMapper(config, file);
CityDoctorModel model = mapper.getModel();
while (reader.hasNext() && !stream.isClosed()) {
boolean isInitialized = false;
CityModelInfo cityModelInfo = null;
while (reader.hasNext()) {
CityGML chunk = reader.nextFeature();
if (!isInitialized && writer != null) {
ParentInfo parentInfo = reader.getParentInfo();
cityModelInfo = new CityModelInfo(parentInfo);
writer.setCityModelInfo(cityModelInfo);
writer.writeStartDocument();
isInitialized = true;
}
if (chunk instanceof AbstractCityObject) {
AbstractCityObject ag = (AbstractCityObject) chunk;
ag.accept(mapper);
drainCityModel(model, cityObjectConsumer);
writeAbstractCityObject(writer, ag);
} else if (chunk instanceof CityModel) {
CityModel cModel = (CityModel) chunk;
cModel.unsetCityObjectMember();
mapper.setCityModel(cModel);
stream.setCityDoctorModel(model);
cityObjectConsumer.accept(cModel);
writeCityModel(writer, cityModelInfo, cModel);
} else if (chunk instanceof AbstractFeature && writer != null) {
writer.writeFeatureMember((AbstractFeature) chunk);
}
drainCityModel(model, queue);
}
// end of stream
queue.put(FeatureStream.POISON);
logger.debug("End of gml file stream");
} catch (CityGMLReadException e) {
logger.error(Localization.getText("CityGmlParser.errorReadingGmlFile"), e.getMessage(), e);
} catch (InterruptedException e) {
logger.warn("Interrupted while streaming gml file");
Thread.currentThread().interrupt();
} catch (CityGMLWriteException e) {
logger.error(Localization.getText("CityGmlParser.errorWritingGmlFile"), e.getMessage(), e);
}
}
private static void writeAbstractCityObject(CityModelWriter writer, AbstractCityObject ag)
throws CityGMLWriteException {
if (writer != null) {
writer.writeFeatureMember(ag);
}
}
private static void writeCityModel(CityModelWriter writer, CityModelInfo cityModelInfo, CityModel cModel)
throws CityGMLWriteException {
if (writer != null) {
for (ADEGenericElement genEle : cModel.getGenericADEElement()) {
cityModelInfo.addGenericADEElement(genEle);
}
for (ADEComponent adeComp : cModel.getGenericApplicationPropertyOfCityModel()) {
cityModelInfo.addGenericApplicationPropertyOfCityModel(adeComp);
}
writer.writeEndDocument();
}
}
private static CityModelWriter createCityModelWriter(CityGMLBuilder builder, String outputFile) throws CityGMLWriteException {
if (outputFile == null) {
return null;
}
CityGMLOutputFactory factory = builder.createCityGMLOutputFactory();
CityModelWriter writer = factory.createCityModelWriter(new File(outputFile));
writer.setPrefix("qual", QualityADEModule.NAMESPACE_URI);
writer.setSchemaLocation(QualityADEModule.NAMESPACE_URI,
"https://transfer.hft-stuttgart.de/pages/qualityade/0.1/qualityAde.xsd");
writer.setIndentString(" ");
writer.setPrefixes(CityGMLVersion.DEFAULT);
writer.setSchemaLocations(CityGMLVersion.DEFAULT);
return writer;
}
private static void parseEpsgCodeFromFile(File file, ParserConfiguration config)
......@@ -497,26 +577,19 @@ public class CityGmlParser {
}
}
private static void drainCityModel(CityDoctorModel model, ArrayBlockingQueue<CityObject> queue)
throws InterruptedException {
drainCityObjectList(model.getBuildings(), queue);
drainCityObjectList(model.getBridges(), queue);
drainCityObjectList(model.getVegetation(), queue);
drainCityObjectList(model.getLand(), queue);
drainCityObjectList(model.getTransportation(), queue);
drainCityObjectList(model.getWater(), queue);
model.getBuildings().clear();
model.getBridges().clear();
model.getVegetation().clear();
model.getLand().clear();
model.getTransportation().clear();
model.getWater().clear();
private static void drainCityModel(CityDoctorModel model, CityGmlConsumer cityObjectConsumer) {
drainCityObjectList(model.getBuildings(), cityObjectConsumer);
drainCityObjectList(model.getBridges(), cityObjectConsumer);
drainCityObjectList(model.getVegetation(), cityObjectConsumer);
drainCityObjectList(model.getLand(), cityObjectConsumer);
drainCityObjectList(model.getTransportation(), cityObjectConsumer);
drainCityObjectList(model.getWater(), cityObjectConsumer);
}
private static void drainCityObjectList(List<? extends CityObject> buildings, ArrayBlockingQueue<CityObject> queue)
throws InterruptedException {
for (CityObject co : buildings) {
queue.put(co);
private static void drainCityObjectList(List<? extends CityObject> objects, CityGmlConsumer cityObjectConsumer) {
for (CityObject co : objects) {
cityObjectConsumer.accept(co);
}
objects.clear();
}
}
/*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
*
* This file is part of CityDoctor2.
*
* CityDoctor2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CityDoctor2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with CityDoctor2. If not, see <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.parser;
import java.io.File;
import java.util.concurrent.ArrayBlockingQueue;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.citygml4j.factory.GMLGeometryFactory;
import org.citygml4j.model.citygml.core.AbstractCityObject;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.datastructure.FeatureType;
/**
* Handler when the CityGML files is split up into seperate features.
*
* @author Matthias Betz
*
*/
public class FeatureStream {
private static final Logger logger = LogManager.getLogger(FeatureStream.class);
private ArrayBlockingQueue<CityObject> queue;
private String fileName;
private CityDoctorModel model;
private boolean closed;
private Thread readThread;
private File file;
static final CityObject POISON = new CityObject() {
private static final long serialVersionUID = -3476076957438256265L;
@Override
public FeatureType getFeatureType() {
return FeatureType.BUILDING;
}
@Override
public void reCreateGeometries(GMLGeometryFactory factory, ParserConfiguration config) {
throw new UnsupportedOperationException();
}
@Override
public AbstractCityObject getGmlObject() {
throw new UnsupportedOperationException();
}
@Override
public void unsetGmlGeometries() {
throw new UnsupportedOperationException();
}
};
FeatureStream(ArrayBlockingQueue<CityObject> queue, String fileName, File file) {
this.queue = queue;
this.fileName = fileName;
this.file = file;
closed = false;
}
public void setThread(Thread readThread) {
this.readThread = readThread;
}
public String getFileName() {
return fileName;
}
/**
* Returns the next element that is parsed or null if no more elements are
* available
*
* @return the next element or null
* @throws InterruptedException if the parsing thread is interrupted
*/
public CityObject next() throws InterruptedException {
CityObject co = queue.take();
if (co == POISON) {
if (readThread != null) {
readThread.join();
}
return null;
}
return co;
}
public void setCityDoctorModel(CityDoctorModel model) {
this.model = model;
}
public CityDoctorModel getCityDoctorModel() {
return model;
}
public void close() {
if (readThread != null) {
readThread.interrupt();
}
closed = true;
if (!queue.isEmpty()) {
queue.poll();
boolean validOffer = queue.offer(POISON);
logger.trace("Stream closed while queue not empty, removing element and adding poison element");
if (!validOffer) {
logger.trace("Could not add poison element to queue");
}
}
}
public boolean isClosed() {
return closed;
}
public File getFile() {
return file;
}
}
/*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
*
* This file is part of CityDoctor2.
*
* CityDoctor2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CityDoctor2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with CityDoctor2. If not, see <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.utils;
import java.util.ArrayList;
import java.util.List;
import org.citygml4j.model.citygml.ade.ADEComponent;
import org.citygml4j.model.citygml.core.CityModel;
import org.citygml4j.model.gml.geometry.primitives.DirectPosition;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.ErrorId;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.math.Vector3d;
import de.hft.stuttgart.quality.model.Edge;
import de.hft.stuttgart.quality.model.Validation;
import de.hft.stuttgart.quality.model.ValidationResult;
import de.hft.stuttgart.quality.model.jaxb.ResultType;
public class QualityADEUtils {
private QualityADEUtils() {
}
public static Edge convertEdge(de.hft.stuttgart.citydoctor2.datastructure.Edge e) {
DirectPosition from = convertVertex(e.getFrom());
DirectPosition to = convertVertex(e.getTo());
Edge result = new Edge();
result.setFrom(from);
result.setTo(to);
return result;
}
public static DirectPosition convertVertex(Vector3d v) {
DirectPosition result = new DirectPosition();
result.getValue().add(v.getX());
result.getValue().add(v.getY());
result.getValue().add(v.getZ());
return result;
}
public static void writeQualityAde(CityObject co) {
ValidationResult res = new ValidationResult();
if (co.isValidated()) {
List<CheckError> errors = new ArrayList<>();
co.collectContainedErrors(errors);
if (errors.isEmpty()) {
res.setResult(ResultType.OK);
} else {
res.setResult(ResultType.ERROR);
for (CheckError e : errors) {
e.convertToQualityAdeDatastructure().ifPresent(res.getErrors()::add);
}
}
} else {
res.setResult(ResultType.NOT_CHECKED);
}
co.getGmlObject().addGenericApplicationPropertyOfCityObject(res);
}
public static void removeValidationResult(CityObject co) {
for (ADEComponent comp : co.getGmlObject().getGenericApplicationPropertyOfCityObject()) {
if (comp instanceof ValidationResult) {
co.getGmlObject().getGenericApplicationPropertyOfCityObject().remove(comp);
return;
}
}
}
public static void removeValidation(CityModel cm) {
for (ADEComponent comp : cm.getGenericApplicationPropertyOfCityModel()) {
if (comp instanceof Validation) {
cm.getGenericApplicationPropertyOfCityModel().remove(comp);
return;
}
}
}
public static de.hft.stuttgart.quality.model.jaxb.ErrorId mapErrorIdToAdeId(ErrorId key) {
switch (key.getIdString()) {
case "GE_R_NOT_CLOSED":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.GE_R_NOT_CLOSED;
case "GE_R_TOO_FEW_POINTS":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.GE_R_TOO_FEW_POINTS;
case "GE_R_CONSECUTIVE_POINTS_SAME":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.GE_R_CONSECUTIVE_POINTS_SAME;
case "GE_R_SELF_INTERSECTION":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.GE_R_SELF_INTERSECTION;
case "GE_P_NON_PLANAR_POLYGON_NORMALS_DEVIATION":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.GE_P_NON_PLANAR_POLYGON_NORMALS_DEVIATION;
case "GE_P_NON_PLANAR_POLYGON_DISTANCE_PLANE":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.GE_P_NON_PLANAR_POLYGON_DISTANCE_PLANE;
case "GE_P_INTERIOR_DISCONNECTED":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.GE_P_INTERIOR_DISCONNECTED;
case "GE_P_INTERSECTING_RINGS":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.GE_P_INTERSECTING_RINGS;
case "GE_P_HOLE_OUTSIDE":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.GE_P_HOLE_OUTSIDE;
case "GE_P_ORIENTATION_RINGS_SAME":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.GE_P_ORIENTATION_RINGS_SAME;
case "GE_P_INNER_RINGS_NESTED":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.GE_P_INNER_RINGS_NESTED;
case "GE_S_TOO_FEW_POLYGONS":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.GE_S_TOO_FEW_POLYGONS;
case "GE_S_NOT_CLOSED":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.GE_S_NOT_CLOSED;
case "GE_S_NON_MANIFOLD_EDGE":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.GE_S_NON_MANIFOLD_EDGE;
case "GE_S_POLYGON_WRONG_ORIENTATION":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.GE_S_POLYGON_WRONG_ORIENTATION;
case "GE_S_ALL_POLYGONS_WRONG_ORIENTATION":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.GE_S_ALL_POLYGONS_WRONG_ORIENTATION;
case "GE_S_NON_MANIFOLD_VERTEX":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.GE_S_NON_MANIFOLD_VERTEX;
case "GE_S_SELF_INTERSECTION":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.GE_S_SELF_INTERSECTION;
case "GE_S_MULTIPLE_CONNECTED_COMPONENTS":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.GE_S_MULTIPLE_CONNECTED_COMPONENTS;
case "SEM_ATTRIBUTE_WRONG_VALUE":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.SEM_ATTRIBUTE_WRONG_VALUE;
case "SEM_ATTRIBUTE_MISSING":
return de.hft.stuttgart.quality.model.jaxb.ErrorId.SEM_ATTRIBUTE_MISSING;
default:
throw new IllegalStateException("Cannot map " + key + " to ADE Error Id");
}
}
}
......@@ -105,6 +105,7 @@ CityGmlParser.parsedObjects=Parsed model with {} objects
CityGmlParser.chunkReadFailed=Failed to read GML file in chunks, falling back to reading the complete file
CityGmlParser.notValidGmlFile=This is not a valid GML-File\n
CityGmlParser.errorReadingGmlFile=Error while reading city gml file\n{}
CityGmlParser.errorWritingGmlFile=Error while writing city gml file\n{}
CityGmlParser.noConversionNeeded=Coordinate system is in meters, no conversion done
CityGmlParser.noEPSG=Could not read EPSG code, assuming metric system
OpenFileDialog.loadFailed=Failed to load CityGML File
......
......@@ -103,6 +103,7 @@ CityGmlParser.parsedObjects=Modell mit {} Objekten gelesen
CityGmlParser.chunkReadFailed=Konnte Datei nicht in St\u00fccken lesen, versuche komplett zu lesen
CityGmlParser.notValidGmlFile=Dies ist keine korrekte CityGML Datei\n
CityGmlParser.errorReadingGmlFile=Fehler beim lesen der CityGML Datei\n{}
CityGmlParser.errorWritingGmlFile=Fehler beim schreiben der CityGML Datei\n{}
CityGmlParser.noConversionNeeded=Koordinatensystem in Metern, keine Konvertierung notwendig
CityGmlParser.noEPSG=Konnte EPSG Code nicht lesen, nehme metrisches System an
OpenFileDialog.loadFailed=Konnte CityGML Datei nicht laden
......
/*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
*
* This file is part of CityDoctor2.
*
* CityDoctor2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CityDoctor2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with CityDoctor2. If not, see <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.check.error;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.util.Optional;
import org.junit.Test;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.datastructure.GeometryType;
import de.hft.stuttgart.citydoctor2.datastructure.GmlId;
import de.hft.stuttgart.citydoctor2.datastructure.Lod;
import de.hft.stuttgart.quality.model.AllPolygonsWrongOrientation;
import de.hft.stuttgart.quality.model.ValidationError;
public class AllPolygonsWrongOrientationErrorTest {
@Test
public void testAddToValidationResult() {
Geometry geom = new Geometry(GeometryType.SOLID, Lod.LOD2);
GmlId gmlId = new GmlId("testId");
geom.setGmlId(gmlId);
AllPolygonsWrongOrientationError err = new AllPolygonsWrongOrientationError(geom);
Optional<ValidationError> ade = err.convertToQualityAdeDatastructure();
assertNotNull(ade);
assertTrue(ade.isPresent());
ValidationError validationError = ade.get();
assertTrue(validationError instanceof AllPolygonsWrongOrientation);
AllPolygonsWrongOrientation adeErr = (AllPolygonsWrongOrientation) validationError;
String geometryId = adeErr.getGeometryId();
assertEquals(gmlId.getGmlString(), geometryId);
}
}
/*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
*
* This file is part of CityDoctor2.
*
* CityDoctor2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CityDoctor2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with CityDoctor2. If not, see <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.check.error;
import static org.junit.Assert.*;
import java.util.Optional;
import org.junit.Test;
import de.hft.stuttgart.citydoctor2.datastructure.Building;
import de.hft.stuttgart.citydoctor2.datastructure.GmlId;
import de.hft.stuttgart.quality.model.AttributeMissing;
import de.hft.stuttgart.quality.model.ValidationError;
public class AttributeMissingErrorTest {
@Test
public void testConvertToQualityAdeDatastructure() {
Building b = new Building();
GmlId id = new GmlId("testid");
b.setGmlId(id);
AttributeMissingError err = new AttributeMissingError(b, "childid", "attr", false);
Optional<ValidationError> opt = err.convertToQualityAdeDatastructure();
assertTrue(opt.isPresent());
ValidationError validationError = opt.get();
AttributeMissing adeErr = (AttributeMissing) validationError;
assertEquals("childid", adeErr.getChildId());
assertEquals("attr", adeErr.getAttributeName());
assertFalse(adeErr.isGeneric());
}
}
/*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
*
* This file is part of CityDoctor2.
*
* CityDoctor2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CityDoctor2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with CityDoctor2. If not, see <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.check.error;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.Optional;
import org.junit.Test;
import de.hft.stuttgart.citydoctor2.datastructure.Building;
import de.hft.stuttgart.citydoctor2.datastructure.GmlId;
import de.hft.stuttgart.quality.model.AttributeWrongValue;
import de.hft.stuttgart.quality.model.ValidationError;
public class AttributeValueWrongErrorTest {
@Test
public void testConvertToQualityAdeDatastructure() {
Building b = new Building();
GmlId id = new GmlId("testid");
b.setGmlId(id);
AttributeValueWrongError err = new AttributeValueWrongError(b, "childid", "attr", false);
Optional<ValidationError> opt = err.convertToQualityAdeDatastructure();
assertTrue(opt.isPresent());
ValidationError validationError = opt.get();
AttributeWrongValue adeErr = (AttributeWrongValue) validationError;
assertEquals("childid", adeErr.getChildId());
assertEquals("attr", adeErr.getAttributeName());
assertFalse(adeErr.isGeneric());
}
}
/*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
*
* This file is part of CityDoctor2.
*
* CityDoctor2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CityDoctor2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with CityDoctor2. If not, see <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.check.error;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.Optional;
import org.junit.Test;
import de.hft.stuttgart.citydoctor2.datastructure.GmlId;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing.LinearRingType;
import de.hft.stuttgart.citydoctor2.datastructure.Vertex;
import de.hft.stuttgart.quality.model.ConsecutivePointsSame;
import de.hft.stuttgart.quality.model.ValidationError;
public class ConsecutivePointSameErrorTest {
@Test
public void testConvertToQualityAdeDatastructure() {
LinearRing lr = new LinearRing(LinearRingType.EXTERIOR);
GmlId id = new GmlId("id");
lr.setGmlId(id);
Vertex p1 = new Vertex(1, 2, 3);
Vertex p2 = new Vertex(4, 5, 6);
ConsecutivePointSameError err = new ConsecutivePointSameError(lr, p1, p2);
Optional<ValidationError> optional = err.convertToQualityAdeDatastructure();
assertTrue(optional.isPresent());
ConsecutivePointsSame validationError = (ConsecutivePointsSame) optional.get();
assertEquals(id.getGmlString(), validationError.getLinearRingId());
assertEquals(1, validationError.getVertex1().getValue().get(0), 0.00001);
assertEquals(4, validationError.getVertex2().getValue().get(0), 0.00001);
}
}
/*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
*
* This file is part of CityDoctor2.
*
* CityDoctor2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CityDoctor2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with CityDoctor2. If not, see <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.check.error;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.junit.Test;
import de.hft.stuttgart.citydoctor2.datastructure.ConcretePolygon;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.datastructure.GeometryType;
import de.hft.stuttgart.citydoctor2.datastructure.GmlId;
import de.hft.stuttgart.citydoctor2.datastructure.Lod;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
import de.hft.stuttgart.quality.model.MultipleConnectedComponents;
import de.hft.stuttgart.quality.model.ValidationError;
import de.hft.stuttgart.quality.model.jaxb.Component;
public class MultipleConnectedComponentsErrorTest {
@Test
public void testConvertToQualityAdeDatastructure() {
Geometry geom = new Geometry(GeometryType.SOLID, Lod.LOD2);
GmlId geomId = new GmlId("geomId");
geom.setGmlId(geomId);
Polygon p1 = new ConcretePolygon();
GmlId p1Id = new GmlId("p1Id");
p1.setGmlId(p1Id);
Polygon p2 = new ConcretePolygon();
GmlId p2Id = new GmlId("p2Id");
p2.setGmlId(p2Id);
Polygon p3 = new ConcretePolygon();
GmlId p3Id = new GmlId("p3Id");
p3.setGmlId(p3Id);
List<List<Polygon>> components = new ArrayList<>();
List<Polygon> component1 = new ArrayList<>();
component1.add(p1);
component1.add(p2);
components.add(component1);
List<Polygon> component2 = new ArrayList<>();
component2.add(p3);
components.add(component2);
MultipleConnectedComponentsError err = new MultipleConnectedComponentsError(geom, components);
Optional<ValidationError> optional = err.convertToQualityAdeDatastructure();
assertTrue(optional.isPresent());
MultipleConnectedComponents validationError = (MultipleConnectedComponents) optional.get();
assertEquals(geomId.getGmlString(), validationError.getGeometryId());
List<Component> adeComponents = validationError.getComponents();
assertEquals(2, adeComponents.size());
Component adeComponent1 = adeComponents.get(0);
assertEquals(2, adeComponent1.getPolygonIds().size());
assertEquals(p1Id.getGmlString(), adeComponent1.getPolygonIds().get(0));
assertEquals(p2Id.getGmlString(), adeComponent1.getPolygonIds().get(1));
Component adeComponent2 = adeComponents.get(1);
assertEquals(p3Id.getGmlString(), adeComponent2.getPolygonIds().get(0));
}
}
Markdown is supported
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