Commit 43660f7f authored by Matthias Betz's avatar Matthias Betz
Browse files

Adding default check for solids

switching proj4j to newer version not on maven
fixing an issue of polygon association when replacing a polygon in a geometry
parent 5cab90a1
Pipeline #4347 passed with stage
in 2 minutes and 33 seconds
......@@ -24,7 +24,9 @@ import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.ServiceLoader;
import java.util.regex.Matcher;
......@@ -50,9 +52,14 @@ 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.bridge.Bridge;
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.citygml.landuse.LandUse;
import org.citygml4j.model.citygml.transportation.AbstractTransportationObject;
import org.citygml4j.model.citygml.vegetation.AbstractVegetationObject;
import org.citygml4j.model.citygml.waterbody.WaterBody;
import org.citygml4j.model.gml.feature.AbstractFeature;
import org.citygml4j.model.module.citygml.CityGMLVersion;
import org.citygml4j.xml.io.CityGMLInputFactory;
......@@ -64,12 +71,12 @@ 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;
import org.osgeo.proj4j.ProjCoordinate;
import org.osgeo.proj4j.proj.Projection;
import org.osgeo.proj4j.units.Units;
import org.locationtech.proj4j.BasicCoordinateTransform;
import org.locationtech.proj4j.CRSFactory;
import org.locationtech.proj4j.CoordinateReferenceSystem;
import org.locationtech.proj4j.ProjCoordinate;
import org.locationtech.proj4j.proj.Projection;
import org.locationtech.proj4j.units.Units;
import org.w3c.dom.DOMException;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
......@@ -92,6 +99,8 @@ import de.hft.stuttgart.quality.QualityADEModule;
*/
public class CityGmlParser {
private static final String WGS_84 = "EPSG:4326";
private static final Logger logger = LogManager.getLogger(CityGmlParser.class);
private static final CRSFactory CRS_FACTORY = new CRSFactory();
......@@ -178,15 +187,32 @@ public class CityGmlParser {
CityGMLInputFactory inputFactory, ObservedInputStream ois) throws CityGMLReadException {
try (CityGMLReader reader = inputFactory.createCityGMLReader(file.getAbsolutePath(), ois)) {
FeatureMapper mapper = new FeatureMapper(config, file);
// model is read in chunked mode
// object members are replaced by href in model
// need to remove the refs and re-add unparsed objects
List<AbstractCityObject> acos = new ArrayList<>();
List<ADEGenericElement> genericElements = new ArrayList<>();
while (reader.hasNext()) {
CityGML chunk = reader.nextFeature();
if (chunk instanceof AbstractCityObject) {
AbstractCityObject ag = (AbstractCityObject) chunk;
ag.accept(mapper);
AbstractCityObject aco = (AbstractCityObject) chunk;
aco.accept(mapper);
acos.add(aco);
} else if (chunk instanceof CityModel) {
CityModel cModel = (CityModel) chunk;
cModel.unsetCityObjectMember();
((CityModel) chunk).unsetCityObjectMember();
// re-add all objects
for (AbstractCityObject aco : acos) {
cModel.addCityObjectMember(new CityObjectMember(aco));
}
// remove those that should have been parsed
unsetParsedCityObjectMembers(cModel);
for (ADEGenericElement ele : genericElements) {
cModel.addGenericADEElement(ele);
}
mapper.setCityModel(cModel);
} else if (chunk instanceof ADEGenericElement) {
genericElements.add((ADEGenericElement) chunk);
}
}
if (logger.isInfoEnabled()) {
......@@ -233,7 +259,7 @@ public class CityGmlParser {
}
private static CityGMLInputFactory setupGmlReader(CityGMLBuilder builder, ParserConfiguration config)
throws CityGMLBuilderException, ADEException {
throws CityGMLBuilderException {
CityGMLInputFactory inputFactory = builder.createCityGMLInputFactory();
inputFactory.setProperty(CityGMLInputFactory.FEATURE_READ_MODE, FeatureReadMode.SPLIT_PER_FEATURE);
if (config != null) {
......@@ -258,8 +284,7 @@ public class CityGmlParser {
context.registerADEContext(adeContext);
}
}
CityGMLBuilder builder = context.createCityGMLBuilder(CityGmlParser.class.getClassLoader());
return builder;
return context.createCityGMLBuilder(CityGmlParser.class.getClassLoader());
}
public static void streamCityGml(String file, ParserConfiguration config, CityGmlConsumer cityObjectConsumer,
......@@ -284,7 +309,7 @@ public class CityGmlParser {
private static void startReadingCityGml(File file, ParserConfiguration config, ProgressListener l,
CityGmlConsumer cityObjectConsumer, CityGMLBuilder builder, String outputFile)
throws CityGMLBuilderException, ADEException {
throws CityGMLBuilderException {
try (ObservedInputStream ois = new ObservedInputStream(file)) {
if (l != null) {
ois.addListener(l::updateProgress);
......@@ -389,7 +414,7 @@ public class CityGmlParser {
}
}
if (srsName.equals("http://www.opengis.net/def/crs/EPSG/0/6697")) {
return CRS_FACTORY.createFromParameters("EPSG:6697", "+proj=longlat +ellps=GRS80 +no_defs ");
return CRS_FACTORY.createFromParameters("EPSG:6697", "+proj=longlat +ellps=GRS80 +no_defs +axis=neu");
}
return null;
}
......@@ -403,7 +428,7 @@ public class CityGmlParser {
CityGML chunk = reader.nextFeature();
if (chunk instanceof CityModel) {
CityModel cModel = (CityModel) chunk;
cModel.unsetCityObjectMember();
unsetParsedCityObjectMembers(cModel);
return cModel;
}
}
......@@ -414,9 +439,22 @@ public class CityGmlParser {
throw new CityGmlParseException("Did not find any CityModel in CityGML file");
}
private static void unsetParsedCityObjectMembers(CityModel cModel) {
Iterator<CityObjectMember> iterator = cModel.getCityObjectMember().iterator();
while (iterator.hasNext()) {
CityObjectMember m = iterator.next();
AbstractCityObject aco = m.getCityObject();
if (aco instanceof Bridge || aco instanceof org.citygml4j.model.citygml.building.Building
|| aco instanceof AbstractTransportationObject || aco instanceof AbstractVegetationObject
|| aco instanceof WaterBody || aco instanceof LandUse) {
iterator.remove();
}
}
}
private static void readAndDiscardFeatures(File file, ParserConfiguration config, CityGMLBuilder builder,
ObservedInputStream ois, CityGmlConsumer cityObjectConsumer, String outputFile)
throws CityGMLBuilderException, ADEException {
throws CityGMLBuilderException {
CityGMLInputFactory inputFactory = setupGmlReader(builder, config);
try (CityGMLReader reader = inputFactory.createCityGMLReader(file.getAbsolutePath(), ois);
CityModelWriter writer = createCityModelWriter(builder, outputFile)) {
......@@ -478,7 +516,8 @@ public class CityGmlParser {
}
}
private static CityModelWriter createCityModelWriter(CityGMLBuilder builder, String outputFile) throws CityGMLWriteException {
private static CityModelWriter createCityModelWriter(CityGMLBuilder builder, String outputFile)
throws CityGMLWriteException {
if (outputFile == null) {
return null;
}
......@@ -486,7 +525,7 @@ public class CityGmlParser {
CityModelWriter writer = factory.createCityModelWriter(new File(outputFile), "UTF-8");
writer.setPrefix("qual", QualityADEModule.NAMESPACE_URI);
writer.setSchemaLocation(QualityADEModule.NAMESPACE_URI,
"https://transfer.hft-stuttgart.de/pages/qualityade/0.1/qualityAde.xsd");
QualityADEModule.NAMESPACE_URI + "qualityAde.xsd");
writer.setIndentString(" ");
writer.setPrefixes(CityGMLVersion.DEFAULT);
writer.setSchemaLocations(CityGMLVersion.DEFAULT);
......@@ -533,8 +572,7 @@ public class CityGmlParser {
// assuming metric system
return;
}
ProjectionUnitExtractor extractor = new ProjectionUnitExtractor(crs.getProjection());
if (extractor.getUnit() == Units.METRES) {
if (crs.getProjection().getUnits() == Units.METRES) {
// coordinate system is in meters, do not convert
if (logger.isInfoEnabled()) {
logger.info(Localization.getText("CityGmlParser.noConversionNeeded"));
......@@ -546,16 +584,16 @@ public class CityGmlParser {
Vector3d up = handler.getUpperCorner();
double centerLong = low.getX() + ((up.getX() - low.getX()) / 2);
double centerLat = low.getY() + ((up.getY() - low.getY()) / 2);
if (!crs.getName().equals("EPSG:4326")) {
if (!crs.getName().equals(WGS_84)) {
// need to convert coordinates first to WGS84, then find UTM Zone
CoordinateReferenceSystem wgs84 = crsFromSrsName("EPSG:4326");
CoordinateReferenceSystem wgs84 = crsFromSrsName(WGS_84);
ProjCoordinate p1 = new ProjCoordinate();
p1.setValue(centerLong, centerLat);
ProjCoordinate p2 = new ProjCoordinate();
BasicCoordinateTransform bct = new BasicCoordinateTransform(crs, wgs84);
bct.transform(p1, p2);
centerLong = p2.y;
centerLat = p2.x;
centerLong = p2.x;
centerLat = p2.y;
}
int zone = (int) (31 + Math.round(centerLong / 6));
CoordinateReferenceSystem utm;
......@@ -566,7 +604,7 @@ public class CityGmlParser {
} else {
// north
logger.info("Converting coordiante system to UTM zone {}N", zone);
utm = CRS_FACTORY.createFromParameters("UTM", "+proj=utm +ellps=WGS84 +units=m +zone=" + zone);
utm = CRS_FACTORY.createFromParameters("UTM", "+proj=utm +ellps=WGS84 +units=m +zone=" + zone);
}
config.setCoordinateSystem(crs, utm);
}
......
......@@ -20,9 +20,9 @@ package de.hft.stuttgart.citydoctor2.parser;
import java.io.Serializable;
import org.osgeo.proj4j.BasicCoordinateTransform;
import org.osgeo.proj4j.CRSFactory;
import org.osgeo.proj4j.CoordinateReferenceSystem;
import org.locationtech.proj4j.BasicCoordinateTransform;
import org.locationtech.proj4j.CRSFactory;
import org.locationtech.proj4j.CoordinateReferenceSystem;
/**
* Container class to store the configuration needed to parse a file. Also
......
/*-
* 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.lang.reflect.Field;
import org.osgeo.proj4j.proj.Projection;
import org.osgeo.proj4j.units.Unit;
/**
* To extract the unit of the coordinate system. Workaround as the library
* proj4j has no getter to access the unit value
*
* @author Matthias Betz
*
*/
public class ProjectionUnitExtractor {
private Unit unit;
public ProjectionUnitExtractor(Projection proj) {
try {
Field f = Projection.class.getDeclaredField("unit");
f.setAccessible(true);
unit = (Unit) f.get(proj);
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
throw new IllegalArgumentException(e);
}
}
public Unit getUnit() {
return unit;
}
}
......@@ -103,7 +103,7 @@ public class JoglTesselator {
public static TesselatedPolygon tesselatePolygon(Polygon p) {
ArrayList<Vector3d> vertices = new ArrayList<>();
Vector3d normal = p.calculateNormal();
Vector3d normal = p.calculateNormalNormalized();
synchronized (tess) {
GLU.gluTessProperty(tess, GLU.GLU_TESS_BOUNDARY_ONLY, GL.GL_FALSE);
GLU.gluTessBeginPolygon(tess, vertices);
......@@ -139,7 +139,7 @@ public class JoglTesselator {
public static TesselatedRing tesselateRing(LinearRing r) {
ArrayList<Vector3d> vertices = new ArrayList<>();
Vector3d normal = r.calculateNormal();
Vector3d normal = r.calculateNormalNormalized();
synchronized (tess) {
GLU.gluTessBeginPolygon(tess, vertices);
GLU.gluTessNormal(tess, normal.getX(), normal.getY(), normal.getZ());
......
......@@ -30,8 +30,8 @@ import org.citygml4j.model.gml.geometry.primitives.Exterior;
import org.citygml4j.model.gml.geometry.primitives.Interior;
import org.citygml4j.model.gml.geometry.primitives.Solid;
import org.citygml4j.model.gml.geometry.primitives.SurfaceProperty;
import org.osgeo.proj4j.BasicCoordinateTransform;
import org.osgeo.proj4j.ProjCoordinate;
import org.locationtech.proj4j.BasicCoordinateTransform;
import org.locationtech.proj4j.ProjCoordinate;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.datastructure.GeometryType;
......
......@@ -72,7 +72,7 @@ public class LinearRingTest {
lr.addVertex(v1);
lr.addVertex(v2);
lr.addVertex(v0);
Vector3d normal = lr.calculateNormal();
Vector3d normal = lr.calculateNormalNormalized();
assertEquals(0.0, normal.getX(), 0.0000001);
assertEquals(0.0, normal.getY(), 0.0000001);
assertEquals(1.0, normal.getZ(), 0.0000001);
......@@ -88,7 +88,7 @@ public class LinearRingTest {
lr.addVertex(v1);
lr.addVertex(v2);
lr.addVertex(v0);
Vector3d normal = lr.calculateNormal();
Vector3d normal = lr.calculateNormalNormalized();
assertEquals(0.0, normal.getX(), 0.0000001);
assertEquals(-1.0, normal.getY(), 0.0000001);
assertEquals(0.0, normal.getZ(), 0.0000001);
......@@ -104,7 +104,7 @@ public class LinearRingTest {
lr.addVertex(v1);
lr.addVertex(v2);
lr.addVertex(v0);
Vector3d normal = lr.calculateNormal();
Vector3d normal = lr.calculateNormalNormalized();
assertEquals(1.0, normal.getX(), 0.0000001);
assertEquals(0.0, normal.getY(), 0.0000001);
assertEquals(0.0, normal.getZ(), 0.0000001);
......
......@@ -18,11 +18,11 @@
*/
package de.hft.stuttgart.citydoctor2.parser;
import static org.junit.Assert.*;
import static org.junit.Assert.assertSame;
import org.junit.Test;
import org.osgeo.proj4j.CRSFactory;
import org.osgeo.proj4j.CoordinateReferenceSystem;
import org.locationtech.proj4j.CRSFactory;
import org.locationtech.proj4j.CoordinateReferenceSystem;
/**
*
......
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://purl.oclc.org/dsdl/schematron" queryBinding="xslt2">
<ns prefix="gml" uri="http://www.opengis.net/gml"/>
<ns prefix="bldg" uri="http://www.opengis.net/citygml/building/2.0"/>
<pattern>
<rule context="//*:Building">
<assert test="count(*:lod1Solid) = 1 or count(*:lod2Solid) = 1 or count(*:lod3Solid) = 1 or count(*:lod4Solid) = 1"><value-of select="@gml:id | @id"/>||||SE_ATTRIBUTE_MISSING||any solid||false</assert>
</rule>
<rule context="//*:BuildingPart">
<assert test="count(*:lod1Solid) = 1 or count(*:lod2Solid) = 1 or count(*:lod3Solid) = 1 or count(*:lod4Solid) = 1"><value-of select="ancestor::*:Building/@*:id"/>||<value-of select="@gml:id | @id"/>||SE_ATTRIBUTE_MISSING||any solid||false</assert>
</rule>
</pattern>
</schema>
......@@ -35,6 +35,7 @@
<include>start.bat</include>
<include>testConfigWithStreaming.yml</include>
<include>REKaiserwall.gml</include>
<include>checkForSolid.xml</include>
</includes>
<filtered>true</filtered>
</fileSet>
......
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://purl.oclc.org/dsdl/schematron" queryBinding="xslt2">
<ns prefix="gml" uri="http://www.opengis.net/gml"/>
<ns prefix="bldg" uri="http://www.opengis.net/citygml/building/2.0"/>
<pattern>
<rule context="//*:Building">
<assert test="count(*:lod1Solid) = 1 or count(*:lod2Solid) = 1 or count(*:lod3Solid) = 1 or count(*:lod4Solid) = 1"><value-of select="@gml:id | @id"/>||||SE_ATTRIBUTE_MISSING||any solid||false</assert>
</rule>
<rule context="//*:BuildingPart">
<assert test="count(*:lod1Solid) = 1 or count(*:lod2Solid) = 1 or count(*:lod3Solid) = 1 or count(*:lod4Solid) = 1"><value-of select="ancestor::*:Building/@*:id"/>||<value-of select="@gml:id | @id"/>||SE_ATTRIBUTE_MISSING||any solid||false</assert>
</rule>
</pattern>
</schema>
......@@ -2,7 +2,7 @@ globalParameters:
numberOfRoundingPlaces: 8
# in m
minVertexDistance: 0.0001
schematronFilePath: ''
schematronPath: 'checkForSolid.xml'
useStreaming: true
requirements:
R_GE_R_TOO_FEW_POINTS:
......
......@@ -20,9 +20,12 @@ package de.hft.stuttgart.citydoctor2.check;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
......@@ -136,7 +139,7 @@ public class Checker {
return;
}
File xmlFile = new File(xmlOutput);
if (xmlFile.getParentFile() == null) {
if (xmlFile.getParentFile() != null) {
xmlFile.getParentFile().mkdirs();
}
Reporter reporter = new XmlValidationReporter();
......@@ -152,7 +155,7 @@ public class Checker {
return;
}
File pdfFile = new File(pdfOutput);
if (pdfFile.getParentFile() == null) {
if (pdfFile.getParentFile() != null) {
pdfFile.getParentFile().mkdirs();
}
Reporter reporter = new PdfReporter("assets/Logo.png");
......@@ -220,7 +223,7 @@ public class Checker {
});
}
static void handleSchematronErrorsForCityObject(List<SchematronError> v, CityObject co) {
public static void handleSchematronErrorsForCityObject(List<SchematronError> v, CityObject co) {
int count = 0;
for (SchematronError se : v) {
CheckError err;
......@@ -232,7 +235,7 @@ public class Checker {
throw new IllegalStateException(
"Unknown error ID was given in schematron file: " + se.getErrorIdString());
}
co.addCheckResult(new CheckResult(new CheckId("" + count), ResultStatus.ERROR, err));
co.addCheckResult(new CheckResult(new CheckId("SchematronCheck " + count), ResultStatus.ERROR, err));
count++;
}
}
......@@ -399,6 +402,18 @@ public class Checker {
}
public static SvrlContentHandler executeSchematronValidationIfAvailable(ValidationConfiguration config, File file) {
if (file == null || !file.exists()) {
return null;
}
try {
return executeSchematronValidationIfAvailable(config, new FileInputStream(file));
} catch (FileNotFoundException e) {
throw new UncheckedIOException(e);
}
}
public static SvrlContentHandler executeSchematronValidationIfAvailable(ValidationConfiguration config,
InputStream in) {
if (config.getSchematronFilePath() != null && !config.getSchematronFilePath().isEmpty()) {
if (logger.isInfoEnabled()) {
logger.info(Localization.getText("Checker.schematronValidation"));
......@@ -441,7 +456,7 @@ public class Checker {
XsltExecutable schematronExecutable = xsltCompiler.compile(new DOMSource(doc));
XsltTransformer schematronTransformer = schematronExecutable.load();
schematronTransformer.setSource(new StreamSource(file));
schematronTransformer.setSource(new StreamSource(in));
SvrlContentHandler handler = new SvrlContentHandler();
Destination dest = new SAXDestination(handler);
schematronTransformer.setDestination(dest);
......@@ -538,24 +553,7 @@ public class Checker {
} else {
if (e.getValue().isEnabled()) {
// this requirement is enabled
for (CheckPrototype proto : Checks.getCheckPrototypes()) {
if (proto.checksRequirements().contains(req)) {
// this requirement is checked by this check
// put all requirement parameter in the map
parameterMap.compute(proto.getCheckId(), (k, v) -> {
if (v == null) {
v = new HashMap<>();
v.put(GlobalParameters.NUMBER_OF_ROUNDING_PLACES,
config.getNumberOfRoundingPlacesAsString());
v.put(GlobalParameters.MIN_VERTEX_DISTANCE, config.getMinVertexDistanceAsString());
}
v.putAll(e.getValue().getParameters());
return v;
});
enabledCheck.add(proto.getCheckId());
collectDependencyChecks(proto, enabledCheck);
}
}
insertGlobalParameters(config, enabledCheck, parameterMap, e, req);
}
}
}
......@@ -569,6 +567,29 @@ public class Checker {
return checkList;
}
private void insertGlobalParameters(ValidationConfiguration config, Set<CheckId> enabledCheck,
Map<CheckId, Map<String, String>> parameterMap, Entry<String, RequirementConfiguration> e,
de.hft.stuttgart.citydoctor2.check.Requirement req) {
for (CheckPrototype proto : Checks.getCheckPrototypes()) {
if (proto.checksRequirements().contains(req)) {
// this requirement is checked by this check
// put all requirement parameter in the map
parameterMap.compute(proto.getCheckId(), (k, v) -> {
if (v == null) {
v = new HashMap<>();
v.put(GlobalParameters.NUMBER_OF_ROUNDING_PLACES,
config.getNumberOfRoundingPlacesAsString());
v.put(GlobalParameters.MIN_VERTEX_DISTANCE, config.getMinVertexDistanceAsString());
}
v.putAll(e.getValue().getParameters());
return v;
});
enabledCheck.add(proto.getCheckId());
collectDependencyChecks(proto, enabledCheck);
}
}
}
private void fillParameterMapsWithDefaultParameter(Set<CheckId> enabledCheck,
Map<CheckId, Map<String, String>> parameterMap) {
for (CheckId id : enabledCheck) {
......@@ -745,8 +766,8 @@ public class Checker {
CityGmlParser.streamCityGml(inputFile, config.getParserConfiguration(), con, outputFile);
// write reports if available
writeReport(xmlReporter, handler);
writeReport(pdfReporter, handler);
writeReport(xmlReporter);
writeReport(pdfReporter);
} catch (CheckReportWriteException e) {
logger.error(Localization.getText("Checker.failReports"), e);
}
......@@ -774,19 +795,9 @@ public class Checker {
return pdfReporter;
}
public static void writeReport(StreamReporter reporter, SvrlContentHandler handler)
public static void writeReport(StreamReporter reporter)
throws CheckReportWriteException {
if (reporter != null) {
if (handler != null) {
for (SchematronError err : handler.getGeneralErrors()) {
reporter.reportGlobalError(err);
}
for (Entry<String, List<SchematronError>> e : handler.getFeatureErrors().entrySet()) {
for (SchematronError se : e.getValue()) {
reporter.addError(e.getKey(), se);
}
}
}
reporter.finishReport();
}
}
......
......@@ -28,6 +28,8 @@ import java.util.Set;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.citygml4j.factory.GMLGeometryFactory;
import org.citygml4j.model.citygml.core.CityModel;
......@@ -53,6 +55,8 @@ import de.hft.stuttgart.quality.model.jaxb.Statistics;
public class StreamCityGmlConsumer implements CityGmlConsumer {
private static final Logger logger = LogManager.getLogger(StreamCityGmlConsumer.class);
private Checker c;
private XmlStreamReporter xmlReporter;
private PdfStreamReporter pdfReporter;
......@@ -102,8 +106,16 @@ public class StreamCityGmlConsumer implements CityGmlConsumer {
@Override
public void accept(CityObject co) {
c.checkFeature(xmlReporter, pdfReporter, co);
if (logger.isDebugEnabled()) {
logger.debug(Localization.getText("Checker.checkFeature"), co);
}
// check without reporters, nothing will be put into the reports like that
// this will also clear old check results if any (though in stream mode there
// won't be any)
c.checkFeature(null, null, co);
// now add the schematron errors
if (handler != null) {
List<SchematronError> errors = handler.getFeatureErrors().get(co.getGmlId().getGmlString());
if (errors != null) {
......@@ -111,6 +123,15 @@ public class StreamCityGmlConsumer implements CityGmlConsumer {
}
}
// now add the city object to the reports so it includes the schematron errors
// as well
if (xmlReporter != null) {
xmlReporter.report(co);
}
if (pdfReporter != null) {
pdfReporter.report(co);
}
// remove existing quality ade datastructure if existing
QualityADEUtils.removeValidationResult(co);
// store quality ade datastructures in cityobject
......
......@@ -52,6 +52,7 @@ import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
*/
public class ValidationConfiguration implements Serializable {
public static final String CHECK_FOR_SOLID_XML = "checkForSolid.xml";
private static final String NUMBER_OF_ROUNDING_PLACES_DEFAULT = "8";
private static final String MIN_VERTEX_DISTANCE_DEFAULT = "0.0001";
private static final long serialVersionUID = -8020055032177740646L;
......@@ -93,6 +94,7 @@ public class ValidationConfiguration implements Serializable {
config.globalParameters = new HashMap<>();
config.globalParameters.put(GlobalParameters.NUMBER_OF_ROUNDING_PLACES, NUMBER_OF_ROUNDING_PLACES_DEFAULT);
config.globalParameters.put(GlobalParameters.MIN_VERTEX_DISTANCE, MIN_VERTEX_DISTANCE_DEFAULT);
config.setSchematronFilePathInGlobalParameters(CHECK_FOR_SOLID_XML);
return config;
}
......
......@@ -150,7 +150,7 @@ public class AllPolygonsWrongOrientationCheck extends Check {
throw new IllegalStateException("Constructed a ray that does not intersect any polygon");
}
// calculate normal of the closest polygon
Vector3d normal = tessPoly.getOriginal().calculateNormal();
Vector3d normal = tessPoly.getOriginal().calculateNormalNormalized();
// calculate cos(gamma) of normal and ray direction, the normal is normalized,
// don't need to get the length
double cosAngle = outsidePointDirection.dot(normal) / outsidePointDirection.getLength();
......
......@@ -66,7 +66,7 @@ public class IsCeilingCheck extends Check {
}
for (Geometry geom : bs.getGeometries()) {
for (Polygon p : geom.getPolygons()) {
Vector3d normal = p.calculateNormal();
Vector3d normal = p.calculateNormalNormalized();
if (normal.getZ() >= 0) {
NotCeilingError err = new NotCeilingError(bs, p);
CheckResult cr = new CheckResult(this, ResultStatus.ERROR, err);
......
......@@ -67,7 +67,7 @@ public class IsFloorCheck extends Check {
}
for (Geometry geom : bs.getGeometries()) {
for (Polygon p : geom.getPolygons()) {
Vector3d normal = p.calculateNormal();
Vector3d normal = p.calculateNormalNormalized();
if (normal.getZ() <= 0) {
NotFloorError err = new NotFloorError(bs, p);
CheckResult cr = new CheckResult(this, ResultStatus.ERROR, err);
......
......@@ -66,7 +66,7 @@ public class IsGroundCheck extends Check {
}
for (Geometry geom : bs.getGeometries()) {
for (Polygon p : geom.getPolygons()) {
Vector3d normal = p.calculateNormal();
Vector3d normal = p.calculateNormalNormalized();
if (normal.getZ() >= 0) {
NotGroundError err = new NotGroundError(bs, p);
CheckResult cr = new CheckResult(this, ResultStatus.ERROR, err);
......
......@@ -98,7 +98,7 @@ public class IsWallCheck extends Check {
for (Geometry geom : bs.getGeometries()) {
for (Polygon p : geom.getPolygons()) {
Vector3d normal = p.calculateNormal();
Vector3d normal = p.calculateNormalNormalized();
double dot = normal.dot(Z_AXIS);
// The angle should be between 45 and 135 degree, measured
......
......@@ -20,6 +20,7 @@ package de.hft.stuttgart.citydoctor2.checks.util;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.apache.logging.log4j.LogManager;
......@@ -44,6 +45,9 @@ import de.hft.stuttgart.citydoctor2.datastructure.LinearRing;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing.LinearRingType;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
import de.hft.stuttgart.citydoctor2.datastructure.Vertex;
import de.hft.stuttgart.citydoctor2.edge.MeshSurface;
import de.hft.stuttgart.citydoctor2.edge.MeshSurfaceUtils;
import de.hft.stuttgart.citydoctor2.edge.PolygonPolygonIntersection;
import de.hft.stuttgart.citydoctor2.math.MovedPolygon;
import de.hft.stuttgart.citydoctor2.math.MovedRing;
import de.hft.stuttgart.citydoctor2.math.Plane;
......@@ -71,6 +75,8 @@ public class SelfIntersectionUtil {
private static final String DIVISOR_IS_0 = "Divisor is 0";
private static final Logger logger = LogManager.getLogger(SelfIntersectionUtil.class);
private static boolean useEdge = false;
private static GeometryFactory factory = new GeometryFactory(new PrecisionModel(PrecisionModel.FLOATING));
......@@ -85,13 +91,37 @@ public class SelfIntersectionUtil {
public static List<PolygonIntersection> doesSolidSelfIntersect2(Geometry g) {
List<Polygon> polygons = g.getPolygons();
List<PolygonIntersection> intersections = new ArrayList<>();
if (useEdge) {
MeshSurface meshSurface = MeshSurface.of(g);
List<PolygonPolygonIntersection> selfIntersects = MeshSurfaceUtils.selfIntersects(meshSurface, 0.000001, 0.001);
if (!selfIntersects.isEmpty()) {
PolygonPolygonIntersection polygonPolygonIntersection = selfIntersects.get(0);
Polygon p1 = polygonPolygonIntersection.getPolygon1().getOriginal();
Polygon p2 = polygonPolygonIntersection.getPolygon2().getOriginal();
System.out.println();
for (Vertex v : p1.getExteriorRing().getVertices()) {
System.out.println(v);
}
System.out.println();
for (Vertex v : p2.getExteriorRing().getVertices()) {
System.out.println(v);
}
// DebugUtils.printPolygon3d(polygonPolygonIntersection.getPolygon1());
// System.out.println();
// DebugUtils.printPolygon3d(polygonPolygonIntersection.getPolygon2());
intersections.add(PolygonIntersection.lines(Collections.emptyList(), p1, p2));
}
}
for (int i = 0; i < polygons.size() - 1; i++) {
Polygon p1 = polygons.get(i);
for (int j = i + 1; j < polygons.size(); j++) {
Polygon p2 = polygons.get(j);
PolygonIntersection intersect = polygonIntersection(p1, p2, 0.1, 0.01);
if (intersect.getType() != IntersectionType.NONE) {
intersections.add(intersect);
if (useEdge && p1.getInnerRings().isEmpty() && p2.getInnerRings().isEmpty()) {
} else {
PolygonIntersection intersect = polygonIntersection(p1, p2, 0.1, 0.01);
if (intersect.getType() != IntersectionType.NONE) {
intersections.add(intersect);
}
}
}
}
......
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