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
This commit is part of merge request !4. Comments created here will be created in the context of that merge request.
Showing with 338 additions and 162 deletions
+338 -162
...@@ -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())) {
......
...@@ -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);
...@@ -729,88 +716,9 @@ public class Checker { ...@@ -729,88 +716,9 @@ public class Checker {
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);
...@@ -823,33 +731,6 @@ public class Checker { ...@@ -823,33 +731,6 @@ public class Checker {
} }
} }
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) {
XmlStreamReporter xmlReporter; XmlStreamReporter xmlReporter;
......
/*-
* 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);
}
}
}
...@@ -63,6 +63,8 @@ import de.hft.stuttgart.citydoctor2.utils.Localization; ...@@ -63,6 +63,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);
private static List<CheckPrototype> checkPrototypes; private static List<CheckPrototype> checkPrototypes;
...@@ -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++) {
for (int j = i + 2; j < pointList.size() - 1; j++) {
Vertex point1 = pointList.get(i); Vertex point1 = pointList.get(i);
for (int j = i + 2; j < pointList.size() - 1; j++) {
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;
...@@ -43,10 +44,8 @@ public class RingSelfIntCheck extends Check { ...@@ -43,10 +44,8 @@ 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);
} }
} }
......
/*-
* 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());
}
}
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