Commit d3fb0ee6 authored by Matthias Betz's avatar Matthias Betz
Browse files

fixing some linting issues

added test for degenerated polygon
renaming degenerated polygon error
parent 09470a4d
Pipeline #2012 canceled with stage
...@@ -46,15 +46,16 @@ import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; ...@@ -46,15 +46,16 @@ import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
* The general check class containing the methods which will be called by check * The general check class containing the methods which will be called by check
* engine. To create a new check override one or more check(...) methods and * engine. To create a new check override one or more check(...) methods and
* implement the {@link Check#getApplicableToClasses()} method by returning a * implement the {@link Check#getApplicableToClasses()} method by returning a
* list of classes you wish to check. CheckResult objects can be attached to * list of classes you wish to check.<br>
* every Checkable. If the check has parameters override the * CheckResult objects can be attached to every Checkable. If the check has
* {@link Check#init(Map, ParserConfiguration)} method to get the value of a * parameters override the {@link Check#init(Map, ParserConfiguration)} method
* parameter if a user has specified one in the validation plan. It will be * to get the value of a parameter if a user has specified one in the validation
* contained in the Map as a string. If you have parameters you will need to * plan. It will be contained in the Map as a string. If you have parameters you
* override the {@link Check#getDefaultParameter()} method as well to declare * will need to override the {@link Check#getDefaultParameter()} method as well
* which parameters you have, which name and default value they have. The name * to declare which parameters you have, which name and default value they have.
* will be the key for the Map in the init method previously mentioned. If your * The name will be the key for the Map in the init method previously
* check has dependencies you can declare them in the * mentioned.<br>
* If your check has dependencies you can declare them in the
* {@link Check#getDependencies()} method. Be sure not to create cyclic * {@link Check#getDependencies()} method. Be sure not to create cyclic
* dependencies as that would result in undefined behavior. * dependencies as that would result in undefined behavior.
* *
...@@ -66,7 +67,7 @@ public abstract class Check { ...@@ -66,7 +67,7 @@ public abstract class Check {
private List<Class<Checkable>> applicableToClasses = new ArrayList<>(2); private List<Class<Checkable>> applicableToClasses = new ArrayList<>(2);
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public Check() { protected Check() {
Method[] declaredMethods = getClass().getDeclaredMethods(); Method[] declaredMethods = getClass().getDeclaredMethods();
for (Method m : declaredMethods) { for (Method m : declaredMethods) {
if ("check".equals(m.getName())) { if ("check".equals(m.getName())) {
...@@ -145,7 +146,7 @@ public abstract class Check { ...@@ -145,7 +146,7 @@ public abstract class Check {
} }
return true; return true;
} }
private boolean canBeApplied(Checkable c) { private boolean canBeApplied(Checkable c) {
for (Class<Checkable> checkableClass : getApplicableToClasses()) { for (Class<Checkable> checkableClass : getApplicableToClasses()) {
if (checkableClass.isAssignableFrom(c.getCheckClass())) { if (checkableClass.isAssignableFrom(c.getCheckClass())) {
......
...@@ -63,7 +63,7 @@ public class ErrorId implements Serializable { ...@@ -63,7 +63,7 @@ public class ErrorId implements Serializable {
public static final ErrorId SEM_BS_NOT_GROUND = new ErrorId("SEM_BS_NOT_GROUND"); public static final ErrorId SEM_BS_NOT_GROUND = new ErrorId("SEM_BS_NOT_GROUND");
public static final ErrorId SEM_SCHEMATRON_ERROR = new ErrorId("SEM_SCHEMATRON_ERROR"); public static final ErrorId SEM_SCHEMATRON_ERROR = new ErrorId("SEM_SCHEMATRON_ERROR");
public static final ErrorId SEM_BS_UNFRAGMENTED = new ErrorId("SEM_BS_UNFRAGMENTED"); public static final ErrorId SEM_BS_UNFRAGMENTED = new ErrorId("SEM_BS_UNFRAGMENTED");
public static final ErrorId GE_P_TINY_EDGE = new ErrorId("GE_P_TINY_EDGE"); public static final ErrorId GE_P_DEGENERATED_POLYGON = new ErrorId("GE_P_DEGENERATED_POLYGON");
private String name; private String name;
......
...@@ -64,7 +64,7 @@ public class DegeneratedPolygonError implements CheckError { ...@@ -64,7 +64,7 @@ public class DegeneratedPolygonError implements CheckError {
@Override @Override
public ErrorId getErrorId() { public ErrorId getErrorId() {
return ErrorId.GE_P_TINY_EDGE; return ErrorId.GE_P_DEGENERATED_POLYGON;
} }
@Override @Override
......
...@@ -55,10 +55,10 @@ public class OrthogonalRegressionPlane { ...@@ -55,10 +55,10 @@ public class OrthogonalRegressionPlane {
double eig2 = eigenvalues.getZ(); double eig2 = eigenvalues.getZ();
Matrix v = ed.getV(); Matrix v = ed.getV();
Matrix eigenVector; Matrix eigenVector;
if (eig0 < eig1 && eig0 < eig2) { if (eig0 <= eig1 && eig0 <= eig2) {
// the first eigenvalue is the lowest // the first eigenvalue is the lowest
eigenVector = v.getMatrix(0, 2, 0, 0); eigenVector = v.getMatrix(0, 2, 0, 0);
} else if (eig1 < eig0 && eig1 < eig2) { } else if (eig1 <= eig0 && eig1 <= eig2) {
// the second eigenvalue is the lowest // the second eigenvalue is the lowest
eigenVector = v.getMatrix(0, 2, 1, 1); eigenVector = v.getMatrix(0, 2, 1, 1);
} else { } else {
......
...@@ -23,7 +23,6 @@ import java.io.File; ...@@ -23,7 +23,6 @@ import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.time.ZonedDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
...@@ -33,7 +32,6 @@ import java.util.List; ...@@ -33,7 +32,6 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream; import java.util.stream.Stream;
import javax.xml.XMLConstants; import javax.xml.XMLConstants;
...@@ -47,8 +45,6 @@ import javax.xml.transform.stream.StreamSource; ...@@ -47,8 +45,6 @@ import javax.xml.transform.stream.StreamSource;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.citygml4j.factory.GMLGeometryFactory;
import org.citygml4j.model.citygml.core.CityModel;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import de.hft.stuttgart.citydoctor2.check.error.AttributeMissingError; import de.hft.stuttgart.citydoctor2.check.error.AttributeMissingError;
...@@ -60,15 +56,9 @@ import de.hft.stuttgart.citydoctor2.checks.CheckPrototype; ...@@ -60,15 +56,9 @@ import de.hft.stuttgart.citydoctor2.checks.CheckPrototype;
import de.hft.stuttgart.citydoctor2.checks.Checks; import de.hft.stuttgart.citydoctor2.checks.Checks;
import de.hft.stuttgart.citydoctor2.checks.SvrlContentHandler; import de.hft.stuttgart.citydoctor2.checks.SvrlContentHandler;
import de.hft.stuttgart.citydoctor2.checks.util.FeatureCheckedListener; import de.hft.stuttgart.citydoctor2.checks.util.FeatureCheckedListener;
import de.hft.stuttgart.citydoctor2.datastructure.BridgeObject;
import de.hft.stuttgart.citydoctor2.datastructure.Building;
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.FeatureType; import de.hft.stuttgart.citydoctor2.datastructure.FeatureType;
import de.hft.stuttgart.citydoctor2.datastructure.LandObject;
import de.hft.stuttgart.citydoctor2.datastructure.TransportationObject;
import de.hft.stuttgart.citydoctor2.datastructure.Vegetation;
import de.hft.stuttgart.citydoctor2.datastructure.WaterObject;
import de.hft.stuttgart.citydoctor2.parser.CityGmlConsumer; import de.hft.stuttgart.citydoctor2.parser.CityGmlConsumer;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException; import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParser; import de.hft.stuttgart.citydoctor2.parser.CityGmlParser;
...@@ -81,15 +71,10 @@ import de.hft.stuttgart.citydoctor2.reporting.XmlValidationReporter; ...@@ -81,15 +71,10 @@ import de.hft.stuttgart.citydoctor2.reporting.XmlValidationReporter;
import de.hft.stuttgart.citydoctor2.reporting.pdf.PdfReporter; import de.hft.stuttgart.citydoctor2.reporting.pdf.PdfReporter;
import de.hft.stuttgart.citydoctor2.reporting.pdf.PdfStreamReporter; import de.hft.stuttgart.citydoctor2.reporting.pdf.PdfStreamReporter;
import de.hft.stuttgart.citydoctor2.utils.Localization; import de.hft.stuttgart.citydoctor2.utils.Localization;
import de.hft.stuttgart.citydoctor2.utils.QualityADEUtils;
import de.hft.stuttgart.quality.model.Validation;
import de.hft.stuttgart.quality.model.jaxb.Checking; import de.hft.stuttgart.quality.model.jaxb.Checking;
import de.hft.stuttgart.quality.model.jaxb.ErrorStatistics;
import de.hft.stuttgart.quality.model.jaxb.FeatureStatistics;
import de.hft.stuttgart.quality.model.jaxb.Parameter; import de.hft.stuttgart.quality.model.jaxb.Parameter;
import de.hft.stuttgart.quality.model.jaxb.Requirement; import de.hft.stuttgart.quality.model.jaxb.Requirement;
import de.hft.stuttgart.quality.model.jaxb.RequirementId; import de.hft.stuttgart.quality.model.jaxb.RequirementId;
import de.hft.stuttgart.quality.model.jaxb.Statistics;
import de.hft.stuttgart.quality.model.jaxb.TopLevelFeatureType; import de.hft.stuttgart.quality.model.jaxb.TopLevelFeatureType;
import de.hft.stuttgart.quality.model.jaxb.ValidationPlan; import de.hft.stuttgart.quality.model.jaxb.ValidationPlan;
import net.sf.saxon.s9api.DOMDestination; import net.sf.saxon.s9api.DOMDestination;
...@@ -235,7 +220,7 @@ public class Checker { ...@@ -235,7 +220,7 @@ public class Checker {
}); });
} }
private static void handleSchematronErrorsForCityObject(List<SchematronError> v, CityObject co) { static void handleSchematronErrorsForCityObject(List<SchematronError> v, CityObject co) {
int count = 0; int count = 0;
for (SchematronError se : v) { for (SchematronError se : v) {
CheckError err; CheckError err;
...@@ -252,7 +237,7 @@ public class Checker { ...@@ -252,7 +237,7 @@ public class Checker {
} }
} }
private ValidationPlan createValidationPlan() { ValidationPlan createValidationPlan() {
ValidationPlan plan = new ValidationPlan(); ValidationPlan plan = new ValidationPlan();
List<Checking> filter = createFilter(); List<Checking> filter = createFilter();
...@@ -475,6 +460,8 @@ public class Checker { ...@@ -475,6 +460,8 @@ public class Checker {
expandTransformer.setDestination(xslt2Transformer); expandTransformer.setDestination(xslt2Transformer);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
Document doc = factory.newDocumentBuilder().newDocument(); Document doc = factory.newDocumentBuilder().newDocument();
DOMDestination domDestination = new DOMDestination(doc); DOMDestination domDestination = new DOMDestination(doc);
...@@ -724,97 +711,18 @@ public class Checker { ...@@ -724,97 +711,18 @@ public class Checker {
BufferedOutputStream pdfBos = getPdfOutputMaybe(pdfOutput)) { BufferedOutputStream pdfBos = getPdfOutputMaybe(pdfOutput)) {
Checker c = new Checker(config, null); Checker c = new Checker(config, null);
String fileName = inputFile.getName(); String fileName = inputFile.getName();
// create reporter if available // create reporter if available
XmlStreamReporter xmlReporter = getXmlReporter(config, xmlBos, fileName); XmlStreamReporter xmlReporter = getXmlReporter(config, xmlBos, fileName);
PdfStreamReporter pdfReporter = getPdfReporter(config, logoLocation, pdfBos, fileName); PdfStreamReporter pdfReporter = getPdfReporter(config, logoLocation, pdfBos, fileName);
// create quality ade structures
Validation val = new Validation();
val.setValidationDate(ZonedDateTime.now());
val.setValidationSoftware("CityDoctor " + Localization.getText(Localization.VERSION));
Statistics statistics = new Statistics();
FeatureStatistics buildingStatistics = new FeatureStatistics();
statistics.setNumErrorBuildings(buildingStatistics);
FeatureStatistics bridgeStatistics = new FeatureStatistics();
statistics.setNumErrorBridgeObjects(bridgeStatistics);
FeatureStatistics transportationStatistics = new FeatureStatistics();
statistics.setNumErrorTransportation(transportationStatistics);
FeatureStatistics vegetationStatistics = new FeatureStatistics();
statistics.setNumErrorVegetation(vegetationStatistics);
FeatureStatistics landStatistics = new FeatureStatistics();
statistics.setNumErrorLandObjects(landStatistics);
FeatureStatistics waterStatistics = new FeatureStatistics();
statistics.setNumErrorWaterObjects(waterStatistics);
// map for counting individual error counts
Map<ErrorId, AtomicInteger> errorCount = new HashMap<>();
GMLGeometryFactory gmlFactory = new GMLGeometryFactory();
// execute schematron first // execute schematron first
SvrlContentHandler handler = executeSchematronValidationIfAvailable(config, inputFile); SvrlContentHandler handler = executeSchematronValidationIfAvailable(config, inputFile);
CityGmlConsumer con = new StreamCityGmlConsumer(c, xmlReporter, pdfReporter, handler, config, l);
CityGmlConsumer con = new CityGmlConsumer() {
@Override
public void accept(CityObject co) {
c.checkFeature(xmlReporter, pdfReporter, co);
if (handler != null) {
List<SchematronError> errors = handler.getFeatureErrors().get(co.getGmlId().getGmlString());
if (errors != null) {
handleSchematronErrorsForCityObject(errors, co);
}
}
// remove existing quality ade datastructure if existing
QualityADEUtils.removeValidationResult(co);
// store quality ade datastructures in cityobject
QualityADEUtils.writeQualityAde(co);
// recreate geometry
co.reCreateGeometries(gmlFactory, config.getParserConfiguration());
// store result in statistics
applyToStatistics(buildingStatistics, bridgeStatistics, transportationStatistics,
vegetationStatistics, landStatistics, waterStatistics, co);
// add errors to statistics
List<CheckError> errorList = new ArrayList<>();
co.collectContainedErrors(errorList);
Set<CheckError> errors = new HashSet<>(errorList);
for (CheckError e : errors) {
errorCount.compute(e.getErrorId(), (k, v) -> {
if (v == null) {
return new AtomicInteger(1);
}
v.incrementAndGet();
return v;
});
}
if (l != null) {
l.featureChecked(co);
}
}
@Override
public void accept(CityModel cm) {
QualityADEUtils.removeValidation(cm);
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);
}
val.setStatistics(statistics);
val.setValidationPlan(c.createValidationPlan());
cm.addGenericApplicationPropertyOfCityModel(val);
}
};
// parse and validate // parse and validate
CityGmlParser.streamCityGml(inputFile, config.getParserConfiguration(), con, outputFile); CityGmlParser.streamCityGml(inputFile, config.getParserConfiguration(), con, outputFile);
// write reports if available // write reports if available
writeReport(xmlReporter, handler); writeReport(xmlReporter, handler);
writeReport(pdfReporter, handler); writeReport(pdfReporter, handler);
...@@ -822,33 +730,6 @@ public class Checker { ...@@ -822,33 +730,6 @@ public class Checker {
logger.error(Localization.getText("Checker.failReports"), e); logger.error(Localization.getText("Checker.failReports"), e);
} }
} }
private static void applyToStatistics(FeatureStatistics buildingStatistics, FeatureStatistics bridgeStatistics,
FeatureStatistics transportationStatistics, FeatureStatistics vegetationStatistics,
FeatureStatistics landStatistics, FeatureStatistics waterStatistics, CityObject co) {
if (co.isValidated()) {
if (co instanceof Building) {
countForFeatureStatistics(buildingStatistics, co);
} else if (co instanceof TransportationObject) {
countForFeatureStatistics(transportationStatistics, co);
} else if (co instanceof BridgeObject) {
countForFeatureStatistics(bridgeStatistics, co);
} else if (co instanceof WaterObject) {
countForFeatureStatistics(waterStatistics, co);
} else if (co instanceof LandObject) {
countForFeatureStatistics(landStatistics, co);
} else if (co instanceof Vegetation) {
countForFeatureStatistics(vegetationStatistics, co);
}
}
}
private static void countForFeatureStatistics(FeatureStatistics featureStatistics, CityObject co) {
featureStatistics.setNumChecked(featureStatistics.getNumChecked() + 1);
if (co.containsAnyError()) {
featureStatistics.setNumErrors(featureStatistics.getNumErrors() + 1);
}
}
private static XmlStreamReporter getXmlReporter(ValidationConfiguration config, BufferedOutputStream xmlBos, private static XmlStreamReporter getXmlReporter(ValidationConfiguration config, BufferedOutputStream xmlBos,
String fileName) { String fileName) {
......
/*-
* 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;
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.Set;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicInteger;
import org.citygml4j.factory.GMLGeometryFactory;
import org.citygml4j.model.citygml.core.CityModel;
import de.hft.stuttgart.citydoctor2.check.error.SchematronError;
import de.hft.stuttgart.citydoctor2.checks.SvrlContentHandler;
import de.hft.stuttgart.citydoctor2.checks.util.FeatureCheckedListener;
import de.hft.stuttgart.citydoctor2.datastructure.BridgeObject;
import de.hft.stuttgart.citydoctor2.datastructure.Building;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.datastructure.LandObject;
import de.hft.stuttgart.citydoctor2.datastructure.TransportationObject;
import de.hft.stuttgart.citydoctor2.datastructure.Vegetation;
import de.hft.stuttgart.citydoctor2.datastructure.WaterObject;
import de.hft.stuttgart.citydoctor2.parser.CityGmlConsumer;
import de.hft.stuttgart.citydoctor2.reporting.XmlStreamReporter;
import de.hft.stuttgart.citydoctor2.reporting.pdf.PdfStreamReporter;
import de.hft.stuttgart.citydoctor2.utils.Localization;
import de.hft.stuttgart.citydoctor2.utils.QualityADEUtils;
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;
public class StreamCityGmlConsumer implements CityGmlConsumer {
private Checker c;
private XmlStreamReporter xmlReporter;
private PdfStreamReporter pdfReporter;
private SvrlContentHandler handler;
private Map<ErrorId, AtomicInteger> errorCount;
private GMLGeometryFactory gmlFactory;
private ValidationConfiguration config;
private Statistics statistics;
private FeatureStatistics buildingStatistics;
private FeatureStatistics bridgeStatistics;
private FeatureStatistics transportationStatistics;
private FeatureStatistics vegetationStatistics;
private FeatureStatistics landStatistics;
private FeatureStatistics waterStatistics;
private Validation val;
private FeatureCheckedListener l;
public StreamCityGmlConsumer(Checker c, XmlStreamReporter xmlReporter, PdfStreamReporter pdfReporter,
SvrlContentHandler handler, ValidationConfiguration config, FeatureCheckedListener l) {
this.c = c;
this.xmlReporter = xmlReporter;
this.pdfReporter = pdfReporter;
this.handler = handler;
this.config = config;
this.l = l;
errorCount = new HashMap<>();
gmlFactory = new GMLGeometryFactory();
val = new Validation();
val.setValidationDate(ZonedDateTime.now());
val.setValidationSoftware("CityDoctor " + Localization.getText(Localization.VERSION));
statistics = new Statistics();
buildingStatistics = new FeatureStatistics();
statistics.setNumErrorBuildings(buildingStatistics);
bridgeStatistics = new FeatureStatistics();
statistics.setNumErrorBridgeObjects(bridgeStatistics);
transportationStatistics = new FeatureStatistics();
statistics.setNumErrorTransportation(transportationStatistics);
vegetationStatistics = new FeatureStatistics();
statistics.setNumErrorVegetation(vegetationStatistics);
landStatistics = new FeatureStatistics();
statistics.setNumErrorLandObjects(landStatistics);
waterStatistics = new FeatureStatistics();
statistics.setNumErrorWaterObjects(waterStatistics);
}
@Override
public void accept(CityObject co) {
c.checkFeature(xmlReporter, pdfReporter, co);
if (handler != null) {
List<SchematronError> errors = handler.getFeatureErrors().get(co.getGmlId().getGmlString());
if (errors != null) {
Checker.handleSchematronErrorsForCityObject(errors, co);
}
}
// remove existing quality ade datastructure if existing
QualityADEUtils.removeValidationResult(co);
// store quality ade datastructures in cityobject
QualityADEUtils.writeQualityAde(co);
// recreate geometry
co.reCreateGeometries(gmlFactory, config.getParserConfiguration());
// store result in statistics
applyToStatistics(buildingStatistics, bridgeStatistics, transportationStatistics, vegetationStatistics,
landStatistics, waterStatistics, co);
// add errors to statistics
List<CheckError> errorList = new ArrayList<>();
co.collectContainedErrors(errorList);
Set<CheckError> errors = new HashSet<>(errorList);
for (CheckError e : errors) {
errorCount.compute(e.getErrorId(), (k, v) -> {
if (v == null) {
return new AtomicInteger(1);
}
v.incrementAndGet();
return v;
});
}
if (l != null) {
l.featureChecked(co);
}
}
@Override
public void accept(CityModel cm) {
QualityADEUtils.removeValidation(cm);
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);
}
val.setStatistics(statistics);
val.setValidationPlan(c.createValidationPlan());
cm.addGenericApplicationPropertyOfCityModel(val);
}
private static void applyToStatistics(FeatureStatistics buildingStatistics, FeatureStatistics bridgeStatistics,
FeatureStatistics transportationStatistics, FeatureStatistics vegetationStatistics,
FeatureStatistics landStatistics, FeatureStatistics waterStatistics, CityObject co) {
if (co.isValidated()) {
if (co instanceof Building) {
countForFeatureStatistics(buildingStatistics, co);
} else if (co instanceof TransportationObject) {
countForFeatureStatistics(transportationStatistics, co);
} else if (co instanceof BridgeObject) {
countForFeatureStatistics(bridgeStatistics, co);
} else if (co instanceof WaterObject) {
countForFeatureStatistics(waterStatistics, co);
} else if (co instanceof LandObject) {
countForFeatureStatistics(landStatistics, co);
} else if (co instanceof Vegetation) {
countForFeatureStatistics(vegetationStatistics, co);
}
}
}
private static void countForFeatureStatistics(FeatureStatistics featureStatistics, CityObject co) {
featureStatistics.setNumChecked(featureStatistics.getNumChecked() + 1);
if (co.containsAnyError()) {
featureStatistics.setNumErrors(featureStatistics.getNumErrors() + 1);
}
}
}
...@@ -62,6 +62,8 @@ import de.hft.stuttgart.citydoctor2.utils.Localization; ...@@ -62,6 +62,8 @@ import de.hft.stuttgart.citydoctor2.utils.Localization;
* *
*/ */
public class Checks { public class Checks {
public static final double MIN_VERTEX_DISTANCE_DEFAULT = 0.0001;
private static final Logger logger = LogManager.getLogger(Checks.class); private static final Logger logger = LogManager.getLogger(Checks.class);
...@@ -75,16 +77,21 @@ public class Checks { ...@@ -75,16 +77,21 @@ public class Checks {
prototypeMap = new HashMap<>(); prototypeMap = new HashMap<>();
// add new checks here // add new checks here
// ring checks
publish(new NumPointsCheck()); publish(new NumPointsCheck());
publish(new RingNotClosedCheck()); publish(new RingNotClosedCheck());
publish(new DuplicatePointsCheck()); publish(new DuplicatePointsCheck());
publish(new RingSelfIntCheck()); publish(new RingSelfIntCheck());
// polygon checks
publish(new PlanarCheck()); publish(new PlanarCheck());
publish(new PolygonSameOrientationCheck()); publish(new PolygonSameOrientationCheck());
publish(new HoleOutsideCheck()); publish(new HoleOutsideCheck());
publish(new NestedRingsCheck()); publish(new NestedRingsCheck());
publish(new PolygonIntersectingRingsCheck()); publish(new PolygonIntersectingRingsCheck());
publish(new InteriorDisconnectedCheck()); publish(new InteriorDisconnectedCheck());
// solid checks
publish(new MultipleConnectedComponentCheck()); publish(new MultipleConnectedComponentCheck());
publish(new SolidNotClosedCheck()); publish(new SolidNotClosedCheck());
publish(new NonManifoldEdgeCheck()); publish(new NonManifoldEdgeCheck());
......
...@@ -68,9 +68,7 @@ public class DuplicatePointsCheck extends Check { ...@@ -68,9 +68,7 @@ public class DuplicatePointsCheck extends Check {
@Override @Override
public void init(Map<String, String> params, ParserConfiguration config) { public void init(Map<String, String> params, ParserConfiguration config) {
String epsilonString = params.get(EPSILON_NAME); String epsilonString = params.get(EPSILON_NAME);
if (epsilonString == null) { if (epsilonString != null) {
epsilon = 0.0001;
} else {
epsilon = Double.parseDouble(epsilonString); epsilon = Double.parseDouble(epsilonString);
} }
} }
...@@ -99,8 +97,8 @@ public class DuplicatePointsCheck extends Check { ...@@ -99,8 +97,8 @@ public class DuplicatePointsCheck extends Check {
// ignore last point, because last point = first, but this is allowed // ignore last point, because last point = first, but this is allowed
for (int i = 0; i < pointList.size() - 2; i++) { for (int i = 0; i < pointList.size() - 2; i++) {
Vertex point1 = pointList.get(i);
for (int j = i + 2; j < pointList.size() - 1; j++) { for (int j = i + 2; j < pointList.size() - 1; j++) {
Vertex point1 = pointList.get(i);
Vertex point2 = pointList.get(j); Vertex point2 = pointList.get(j);
if (point1.equalsWithEpsilon(point2, epsilon)) { if (point1.equalsWithEpsilon(point2, epsilon)) {
// non consecutive points same // non consecutive points same
......
...@@ -115,10 +115,7 @@ public class PlanarCheck extends Check { ...@@ -115,10 +115,7 @@ public class PlanarCheck extends Check {
} else if ("angle".equals(planarCheckType)) { } else if ("angle".equals(planarCheckType)) {
// check for tiny edge as well // check for tiny edge as well
// store all used points in temporary list // store all used points in temporary list
ArrayList<Vertex> vertices = collectVertices(p); Vector3d eigenvalues = calculatedEigenvalues(p);
Vector3d centroid = CovarianceMatrix.getCentroid(vertices);
EigenvalueDecomposition ed = OrthogonalRegressionPlane.decompose(vertices, centroid);
Vector3d eigenvalues = OrthogonalRegressionPlane.getEigenvalues(ed);
if (checkEigenvalues(p, eigenvalues)) { if (checkEigenvalues(p, eigenvalues)) {
// found tiny edge error, abort further checking // found tiny edge error, abort further checking
return; return;
...@@ -133,6 +130,13 @@ public class PlanarCheck extends Check { ...@@ -133,6 +130,13 @@ public class PlanarCheck extends Check {
} }
} }
private Vector3d calculatedEigenvalues(Polygon p) {
ArrayList<Vertex> vertices = collectVertices(p);
Vector3d centroid = CovarianceMatrix.getCentroid(vertices);
EigenvalueDecomposition ed = OrthogonalRegressionPlane.decompose(vertices, centroid);
return OrthogonalRegressionPlane.getEigenvalues(ed);
}
private void planarNormalDeviation(Polygon p) { private void planarNormalDeviation(Polygon p) {
TesselatedPolygon tp = JoglTesselator.tesselatePolygon(p); TesselatedPolygon tp = JoglTesselator.tesselatePolygon(p);
ArrayList<Vector3d> normals = new ArrayList<>(); ArrayList<Vector3d> normals = new ArrayList<>();
......
...@@ -31,6 +31,7 @@ import de.hft.stuttgart.citydoctor2.check.CheckType; ...@@ -31,6 +31,7 @@ import de.hft.stuttgart.citydoctor2.check.CheckType;
import de.hft.stuttgart.citydoctor2.check.ResultStatus; import de.hft.stuttgart.citydoctor2.check.ResultStatus;
import de.hft.stuttgart.citydoctor2.check.error.PointTouchesEdgeError; import de.hft.stuttgart.citydoctor2.check.error.PointTouchesEdgeError;
import de.hft.stuttgart.citydoctor2.check.error.RingEdgeIntersectionError; import de.hft.stuttgart.citydoctor2.check.error.RingEdgeIntersectionError;
import de.hft.stuttgart.citydoctor2.checks.Checks;
import de.hft.stuttgart.citydoctor2.datastructure.Edge; import de.hft.stuttgart.citydoctor2.datastructure.Edge;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry; import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing; import de.hft.stuttgart.citydoctor2.datastructure.LinearRing;
...@@ -40,13 +41,11 @@ import de.hft.stuttgart.citydoctor2.math.Segment3d; ...@@ -40,13 +41,11 @@ import de.hft.stuttgart.citydoctor2.math.Segment3d;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
public class RingSelfIntCheck extends Check { public class RingSelfIntCheck extends Check {
private static final String EPSILON_NAME = "minVertexDistance"; private static final String EPSILON_NAME = "minVertexDistance";
private static final List<CheckId> dependencies; private static final List<CheckId> dependencies;
static { static {
ArrayList<CheckId> deps = new ArrayList<>(); ArrayList<CheckId> deps = new ArrayList<>();
deps.add(CheckId.C_GE_R_TOO_FEW_POINTS); deps.add(CheckId.C_GE_R_TOO_FEW_POINTS);
...@@ -55,14 +54,12 @@ public class RingSelfIntCheck extends Check { ...@@ -55,14 +54,12 @@ public class RingSelfIntCheck extends Check {
dependencies = Collections.unmodifiableList(deps); dependencies = Collections.unmodifiableList(deps);
} }
private double epsilon = 0.0001; private double epsilon = Checks.MIN_VERTEX_DISTANCE_DEFAULT;
@Override @Override
public void init(Map<String, String> parameters, ParserConfiguration config) { public void init(Map<String, String> parameters, ParserConfiguration config) {
String epsilonString = parameters.get(EPSILON_NAME); String epsilonString = parameters.get(EPSILON_NAME);
if (epsilonString == null) { if (epsilonString != null) {
epsilon = 0.0001;
} else {
epsilon = Double.parseDouble(epsilonString); epsilon = Double.parseDouble(epsilonString);
} }
} }
...@@ -74,16 +71,16 @@ public class RingSelfIntCheck extends Check { ...@@ -74,16 +71,16 @@ public class RingSelfIntCheck extends Check {
private void checkRingJava(LinearRing lr) { private void checkRingJava(LinearRing lr) {
List<Edge> edges = getEdgesForRing(lr); List<Edge> edges = getEdgesForRing(lr);
for (Edge e : edges) { for (Edge e : edges) {
if (checkForPointsTouchingEdge(lr, e)) { if (checkForPointsTouchingEdge(lr, e)) {
return; return;
} }
} }
for (int i = 0; i < edges.size() - 1; i++) { for (int i = 0; i < edges.size() - 1; i++) {
Edge e1 = edges.get(i); Edge e1 = edges.get(i);
for (int j = i + 1; j < edges.size(); j++) { for (int j = i + 1; j < edges.size(); j++) {
Edge e2 = edges.get(j); Edge e2 = edges.get(j);
if (e1.getConnectionPoint(e2) != null) { if (e1.getConnectionPoint(e2) != null) {
...@@ -101,7 +98,7 @@ public class RingSelfIntCheck extends Check { ...@@ -101,7 +98,7 @@ public class RingSelfIntCheck extends Check {
} }
} }
} }
// no errors detected // no errors detected
CheckResult cr = new CheckResult(this, ResultStatus.OK, null); CheckResult cr = new CheckResult(this, ResultStatus.OK, null);
lr.addCheckResult(cr); lr.addCheckResult(cr);
......
/*-
* 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.checks.geometry;
import static org.junit.Assert.assertEquals;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.Test;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.CheckId;
import de.hft.stuttgart.citydoctor2.check.Checker;
import de.hft.stuttgart.citydoctor2.check.ErrorId;
import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration;
import de.hft.stuttgart.citydoctor2.datastructure.Building;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
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.LinearRing;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing.LinearRingType;
import de.hft.stuttgart.citydoctor2.datastructure.Lod;
import de.hft.stuttgart.citydoctor2.datastructure.Vertex;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
public class DegeneratedPolygonCheckTest {
@Test
public void testDegeneratedPolygon() {
Geometry geom = new Geometry(GeometryType.MULTI_SURFACE, Lod.LOD1);
ConcretePolygon polygon = new ConcretePolygon();
geom.getPolygons().add(polygon);
polygon.setParent(geom);
LinearRing lr = new LinearRing(LinearRingType.EXTERIOR);
polygon.setExteriorRing(lr);
Vertex v1 = new Vertex(427583.301, 6003502.571, 9.711);
lr.getVertices().add(v1);
Vertex v2 = new Vertex(427583.304, 6003502.574, 9.713);
lr.getVertices().add(v2);
Vertex v3 = new Vertex(427583.304, 6003502.574, 4.097);
lr.getVertices().add(v3);
Vertex v4 = new Vertex(427583.301, 6003502.571, 4.097);
lr.getVertices().add(v4);
lr.getVertices().add(v1);
geom.updateEdgesAndVertices();
Building b = new Building();
b.addGeometry(geom);
ParserConfiguration config = new ParserConfiguration(8, false);
CityDoctorModel model = new CityDoctorModel(config, new File(""));
model.addBuilding(b);
// model
// Edge [from=Vertex [x=427583.301, y=6003502.571, z=9.711], to=Vertex [x=427583.304, y=6003502.574, z=9.713]],
// Edge [from=Vertex [x=427583.304, y=6003502.574, z=9.713], to=Vertex [x=427583.304, y=6003502.574, z=4.097]],
// Edge [from=Vertex [x=427583.304, y=6003502.574, z=4.097], to=Vertex [x=427583.301, y=6003502.571, z=4.097]],
// Edge [from=Vertex [x=427583.301, y=6003502.571, z=4.097], to=Vertex [x=427583.301, y=6003502.571, z=9.711]]]
// test
// Edge [from=Vertex [x=427583.301, y=6003502.571, z=9.711], to=Vertex [x=427583.304, y=6003502.574, z=9.713]],
// Edge [from=Vertex [x=427583.304, y=6003502.574, z=9.713], to=Vertex [x=427583.304, y=6003502.574, z=4.097]],
// Edge [from=Vertex [x=427583.304, y=6003502.574, z=4.097], to=Vertex [x=427583.301, y=6003502.571, z=4.097]],
// Edge [from=Vertex [x=427583.301, y=6003502.571, z=4.097], to=Vertex [x=427583.301, y=6003502.571, z=9.711]]]
// Segment3d [pointA=Vertex [x=427583.301, y=6003502.571, z=9.711], pointB=Vertex [x=427583.304, y=6003502.574, z=9.713]]
// Vertex [x=427583.301, y=6003502.571, z=9.711]
ValidationConfiguration valConfig = ValidationConfiguration.loadStandardValidationConfig();
Map<String, String> parameters = new HashMap<>();
parameters.put("degeneratedPolygonTolerance", "0.0001");
valConfig.getChecks().get(CheckId.C_GE_P_NON_PLANAR).setParameters(parameters);
Checker c = new Checker(valConfig, model);
c.runChecks();
List<CheckError> errors = new ArrayList<>();
b.collectContainedErrors(errors);
CheckError checkError = errors.get(0);
assertEquals(ErrorId.GE_P_DEGENERATED_POLYGON, checkError.getErrorId());
}
}
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