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; ...@@ -24,7 +24,9 @@ import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.UncheckedIOException; import java.io.UncheckedIOException;
import java.util.ArrayList;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.ServiceLoader; import java.util.ServiceLoader;
import java.util.regex.Matcher; import java.util.regex.Matcher;
...@@ -50,9 +52,14 @@ import org.citygml4j.model.citygml.ade.ADEComponent; ...@@ -50,9 +52,14 @@ import org.citygml4j.model.citygml.ade.ADEComponent;
import org.citygml4j.model.citygml.ade.ADEException; import org.citygml4j.model.citygml.ade.ADEException;
import org.citygml4j.model.citygml.ade.binding.ADEContext; import org.citygml4j.model.citygml.ade.binding.ADEContext;
import org.citygml4j.model.citygml.ade.generic.ADEGenericElement; 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.AbstractCityObject;
import org.citygml4j.model.citygml.core.CityModel; import org.citygml4j.model.citygml.core.CityModel;
import org.citygml4j.model.citygml.core.CityObjectMember; 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.gml.feature.AbstractFeature;
import org.citygml4j.model.module.citygml.CityGMLVersion; import org.citygml4j.model.module.citygml.CityGMLVersion;
import org.citygml4j.xml.io.CityGMLInputFactory; import org.citygml4j.xml.io.CityGMLInputFactory;
...@@ -64,12 +71,12 @@ import org.citygml4j.xml.io.reader.ParentInfo; ...@@ -64,12 +71,12 @@ import org.citygml4j.xml.io.reader.ParentInfo;
import org.citygml4j.xml.io.writer.CityGMLWriteException; import org.citygml4j.xml.io.writer.CityGMLWriteException;
import org.citygml4j.xml.io.writer.CityModelInfo; import org.citygml4j.xml.io.writer.CityModelInfo;
import org.citygml4j.xml.io.writer.CityModelWriter; import org.citygml4j.xml.io.writer.CityModelWriter;
import org.osgeo.proj4j.BasicCoordinateTransform; import org.locationtech.proj4j.BasicCoordinateTransform;
import org.osgeo.proj4j.CRSFactory; import org.locationtech.proj4j.CRSFactory;
import org.osgeo.proj4j.CoordinateReferenceSystem; import org.locationtech.proj4j.CoordinateReferenceSystem;
import org.osgeo.proj4j.ProjCoordinate; import org.locationtech.proj4j.ProjCoordinate;
import org.osgeo.proj4j.proj.Projection; import org.locationtech.proj4j.proj.Projection;
import org.osgeo.proj4j.units.Units; import org.locationtech.proj4j.units.Units;
import org.w3c.dom.DOMException; import org.w3c.dom.DOMException;
import org.xml.sax.InputSource; import org.xml.sax.InputSource;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
...@@ -92,6 +99,8 @@ import de.hft.stuttgart.quality.QualityADEModule; ...@@ -92,6 +99,8 @@ import de.hft.stuttgart.quality.QualityADEModule;
*/ */
public class CityGmlParser { public class CityGmlParser {
private static final String WGS_84 = "EPSG:4326";
private static final Logger logger = LogManager.getLogger(CityGmlParser.class); private static final Logger logger = LogManager.getLogger(CityGmlParser.class);
private static final CRSFactory CRS_FACTORY = new CRSFactory(); private static final CRSFactory CRS_FACTORY = new CRSFactory();
...@@ -178,15 +187,32 @@ public class CityGmlParser { ...@@ -178,15 +187,32 @@ public class CityGmlParser {
CityGMLInputFactory inputFactory, ObservedInputStream ois) throws CityGMLReadException { CityGMLInputFactory inputFactory, ObservedInputStream ois) throws CityGMLReadException {
try (CityGMLReader reader = inputFactory.createCityGMLReader(file.getAbsolutePath(), ois)) { try (CityGMLReader reader = inputFactory.createCityGMLReader(file.getAbsolutePath(), ois)) {
FeatureMapper mapper = new FeatureMapper(config, file); 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()) { while (reader.hasNext()) {
CityGML chunk = reader.nextFeature(); CityGML chunk = reader.nextFeature();
if (chunk instanceof AbstractCityObject) { if (chunk instanceof AbstractCityObject) {
AbstractCityObject ag = (AbstractCityObject) chunk; AbstractCityObject aco = (AbstractCityObject) chunk;
ag.accept(mapper); aco.accept(mapper);
acos.add(aco);
} else if (chunk instanceof CityModel) { } else if (chunk instanceof CityModel) {
CityModel cModel = (CityModel) chunk; 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); mapper.setCityModel(cModel);
} else if (chunk instanceof ADEGenericElement) {
genericElements.add((ADEGenericElement) chunk);
} }
} }
if (logger.isInfoEnabled()) { if (logger.isInfoEnabled()) {
...@@ -233,7 +259,7 @@ public class CityGmlParser { ...@@ -233,7 +259,7 @@ public class CityGmlParser {
} }
private static CityGMLInputFactory setupGmlReader(CityGMLBuilder builder, ParserConfiguration config) private static CityGMLInputFactory setupGmlReader(CityGMLBuilder builder, ParserConfiguration config)
throws CityGMLBuilderException, ADEException { throws CityGMLBuilderException {
CityGMLInputFactory inputFactory = builder.createCityGMLInputFactory(); CityGMLInputFactory inputFactory = builder.createCityGMLInputFactory();
inputFactory.setProperty(CityGMLInputFactory.FEATURE_READ_MODE, FeatureReadMode.SPLIT_PER_FEATURE); inputFactory.setProperty(CityGMLInputFactory.FEATURE_READ_MODE, FeatureReadMode.SPLIT_PER_FEATURE);
if (config != null) { if (config != null) {
...@@ -258,8 +284,7 @@ public class CityGmlParser { ...@@ -258,8 +284,7 @@ public class CityGmlParser {
context.registerADEContext(adeContext); context.registerADEContext(adeContext);
} }
} }
CityGMLBuilder builder = context.createCityGMLBuilder(CityGmlParser.class.getClassLoader()); return context.createCityGMLBuilder(CityGmlParser.class.getClassLoader());
return builder;
} }
public static void streamCityGml(String file, ParserConfiguration config, CityGmlConsumer cityObjectConsumer, public static void streamCityGml(String file, ParserConfiguration config, CityGmlConsumer cityObjectConsumer,
...@@ -284,7 +309,7 @@ public class CityGmlParser { ...@@ -284,7 +309,7 @@ public class CityGmlParser {
private static void startReadingCityGml(File file, ParserConfiguration config, ProgressListener l, private static void startReadingCityGml(File file, ParserConfiguration config, ProgressListener l,
CityGmlConsumer cityObjectConsumer, CityGMLBuilder builder, String outputFile) CityGmlConsumer cityObjectConsumer, CityGMLBuilder builder, String outputFile)
throws CityGMLBuilderException, ADEException { throws CityGMLBuilderException {
try (ObservedInputStream ois = new ObservedInputStream(file)) { try (ObservedInputStream ois = new ObservedInputStream(file)) {
if (l != null) { if (l != null) {
ois.addListener(l::updateProgress); ois.addListener(l::updateProgress);
...@@ -389,7 +414,7 @@ public class CityGmlParser { ...@@ -389,7 +414,7 @@ public class CityGmlParser {
} }
} }
if (srsName.equals("http://www.opengis.net/def/crs/EPSG/0/6697")) { 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; return null;
} }
...@@ -403,7 +428,7 @@ public class CityGmlParser { ...@@ -403,7 +428,7 @@ public class CityGmlParser {
CityGML chunk = reader.nextFeature(); CityGML chunk = reader.nextFeature();
if (chunk instanceof CityModel) { if (chunk instanceof CityModel) {
CityModel cModel = (CityModel) chunk; CityModel cModel = (CityModel) chunk;
cModel.unsetCityObjectMember(); unsetParsedCityObjectMembers(cModel);
return cModel; return cModel;
} }
} }
...@@ -414,9 +439,22 @@ public class CityGmlParser { ...@@ -414,9 +439,22 @@ public class CityGmlParser {
throw new CityGmlParseException("Did not find any CityModel in CityGML file"); 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, private static void readAndDiscardFeatures(File file, ParserConfiguration config, CityGMLBuilder builder,
ObservedInputStream ois, CityGmlConsumer cityObjectConsumer, String outputFile) ObservedInputStream ois, CityGmlConsumer cityObjectConsumer, String outputFile)
throws CityGMLBuilderException, ADEException { throws CityGMLBuilderException {
CityGMLInputFactory inputFactory = setupGmlReader(builder, config); CityGMLInputFactory inputFactory = setupGmlReader(builder, config);
try (CityGMLReader reader = inputFactory.createCityGMLReader(file.getAbsolutePath(), ois); try (CityGMLReader reader = inputFactory.createCityGMLReader(file.getAbsolutePath(), ois);
CityModelWriter writer = createCityModelWriter(builder, outputFile)) { CityModelWriter writer = createCityModelWriter(builder, outputFile)) {
...@@ -478,7 +516,8 @@ public class CityGmlParser { ...@@ -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) { if (outputFile == null) {
return null; return null;
} }
...@@ -486,7 +525,7 @@ public class CityGmlParser { ...@@ -486,7 +525,7 @@ public class CityGmlParser {
CityModelWriter writer = factory.createCityModelWriter(new File(outputFile), "UTF-8"); CityModelWriter writer = factory.createCityModelWriter(new File(outputFile), "UTF-8");
writer.setPrefix("qual", QualityADEModule.NAMESPACE_URI); writer.setPrefix("qual", QualityADEModule.NAMESPACE_URI);
writer.setSchemaLocation(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.setIndentString(" ");
writer.setPrefixes(CityGMLVersion.DEFAULT); writer.setPrefixes(CityGMLVersion.DEFAULT);
writer.setSchemaLocations(CityGMLVersion.DEFAULT); writer.setSchemaLocations(CityGMLVersion.DEFAULT);
...@@ -533,8 +572,7 @@ public class CityGmlParser { ...@@ -533,8 +572,7 @@ public class CityGmlParser {
// assuming metric system // assuming metric system
return; return;
} }
ProjectionUnitExtractor extractor = new ProjectionUnitExtractor(crs.getProjection()); if (crs.getProjection().getUnits() == Units.METRES) {
if (extractor.getUnit() == Units.METRES) {
// coordinate system is in meters, do not convert // coordinate system is in meters, do not convert
if (logger.isInfoEnabled()) { if (logger.isInfoEnabled()) {
logger.info(Localization.getText("CityGmlParser.noConversionNeeded")); logger.info(Localization.getText("CityGmlParser.noConversionNeeded"));
...@@ -546,16 +584,16 @@ public class CityGmlParser { ...@@ -546,16 +584,16 @@ public class CityGmlParser {
Vector3d up = handler.getUpperCorner(); Vector3d up = handler.getUpperCorner();
double centerLong = low.getX() + ((up.getX() - low.getX()) / 2); double centerLong = low.getX() + ((up.getX() - low.getX()) / 2);
double centerLat = low.getY() + ((up.getY() - low.getY()) / 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 // 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(); ProjCoordinate p1 = new ProjCoordinate();
p1.setValue(centerLong, centerLat); p1.setValue(centerLong, centerLat);
ProjCoordinate p2 = new ProjCoordinate(); ProjCoordinate p2 = new ProjCoordinate();
BasicCoordinateTransform bct = new BasicCoordinateTransform(crs, wgs84); BasicCoordinateTransform bct = new BasicCoordinateTransform(crs, wgs84);
bct.transform(p1, p2); bct.transform(p1, p2);
centerLong = p2.y; centerLong = p2.x;
centerLat = p2.x; centerLat = p2.y;
} }
int zone = (int) (31 + Math.round(centerLong / 6)); int zone = (int) (31 + Math.round(centerLong / 6));
CoordinateReferenceSystem utm; CoordinateReferenceSystem utm;
...@@ -566,7 +604,7 @@ public class CityGmlParser { ...@@ -566,7 +604,7 @@ public class CityGmlParser {
} else { } else {
// north // north
logger.info("Converting coordiante system to UTM zone {}N", zone); 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); config.setCoordinateSystem(crs, utm);
} }
......
...@@ -20,9 +20,9 @@ package de.hft.stuttgart.citydoctor2.parser; ...@@ -20,9 +20,9 @@ package de.hft.stuttgart.citydoctor2.parser;
import java.io.Serializable; import java.io.Serializable;
import org.osgeo.proj4j.BasicCoordinateTransform; import org.locationtech.proj4j.BasicCoordinateTransform;
import org.osgeo.proj4j.CRSFactory; import org.locationtech.proj4j.CRSFactory;
import org.osgeo.proj4j.CoordinateReferenceSystem; import org.locationtech.proj4j.CoordinateReferenceSystem;
/** /**
* Container class to store the configuration needed to parse a file. Also * 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 { ...@@ -103,7 +103,7 @@ public class JoglTesselator {
public static TesselatedPolygon tesselatePolygon(Polygon p) { public static TesselatedPolygon tesselatePolygon(Polygon p) {
ArrayList<Vector3d> vertices = new ArrayList<>(); ArrayList<Vector3d> vertices = new ArrayList<>();
Vector3d normal = p.calculateNormal(); Vector3d normal = p.calculateNormalNormalized();
synchronized (tess) { synchronized (tess) {
GLU.gluTessProperty(tess, GLU.GLU_TESS_BOUNDARY_ONLY, GL.GL_FALSE); GLU.gluTessProperty(tess, GLU.GLU_TESS_BOUNDARY_ONLY, GL.GL_FALSE);
GLU.gluTessBeginPolygon(tess, vertices); GLU.gluTessBeginPolygon(tess, vertices);
...@@ -139,7 +139,7 @@ public class JoglTesselator { ...@@ -139,7 +139,7 @@ public class JoglTesselator {
public static TesselatedRing tesselateRing(LinearRing r) { public static TesselatedRing tesselateRing(LinearRing r) {
ArrayList<Vector3d> vertices = new ArrayList<>(); ArrayList<Vector3d> vertices = new ArrayList<>();
Vector3d normal = r.calculateNormal(); Vector3d normal = r.calculateNormalNormalized();
synchronized (tess) { synchronized (tess) {
GLU.gluTessBeginPolygon(tess, vertices); GLU.gluTessBeginPolygon(tess, vertices);
GLU.gluTessNormal(tess, normal.getX(), normal.getY(), normal.getZ()); GLU.gluTessNormal(tess, normal.getX(), normal.getY(), normal.getZ());
......
...@@ -30,8 +30,8 @@ import org.citygml4j.model.gml.geometry.primitives.Exterior; ...@@ -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.Interior;
import org.citygml4j.model.gml.geometry.primitives.Solid; import org.citygml4j.model.gml.geometry.primitives.Solid;
import org.citygml4j.model.gml.geometry.primitives.SurfaceProperty; import org.citygml4j.model.gml.geometry.primitives.SurfaceProperty;
import org.osgeo.proj4j.BasicCoordinateTransform; import org.locationtech.proj4j.BasicCoordinateTransform;
import org.osgeo.proj4j.ProjCoordinate; import org.locationtech.proj4j.ProjCoordinate;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry; import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.datastructure.GeometryType; import de.hft.stuttgart.citydoctor2.datastructure.GeometryType;
......
...@@ -72,7 +72,7 @@ public class LinearRingTest { ...@@ -72,7 +72,7 @@ public class LinearRingTest {
lr.addVertex(v1); lr.addVertex(v1);
lr.addVertex(v2); lr.addVertex(v2);
lr.addVertex(v0); lr.addVertex(v0);
Vector3d normal = lr.calculateNormal(); Vector3d normal = lr.calculateNormalNormalized();
assertEquals(0.0, normal.getX(), 0.0000001); assertEquals(0.0, normal.getX(), 0.0000001);
assertEquals(0.0, normal.getY(), 0.0000001); assertEquals(0.0, normal.getY(), 0.0000001);
assertEquals(1.0, normal.getZ(), 0.0000001); assertEquals(1.0, normal.getZ(), 0.0000001);
...@@ -88,7 +88,7 @@ public class LinearRingTest { ...@@ -88,7 +88,7 @@ public class LinearRingTest {
lr.addVertex(v1); lr.addVertex(v1);
lr.addVertex(v2); lr.addVertex(v2);
lr.addVertex(v0); lr.addVertex(v0);
Vector3d normal = lr.calculateNormal(); Vector3d normal = lr.calculateNormalNormalized();
assertEquals(0.0, normal.getX(), 0.0000001); assertEquals(0.0, normal.getX(), 0.0000001);
assertEquals(-1.0, normal.getY(), 0.0000001); assertEquals(-1.0, normal.getY(), 0.0000001);
assertEquals(0.0, normal.getZ(), 0.0000001); assertEquals(0.0, normal.getZ(), 0.0000001);
...@@ -104,7 +104,7 @@ public class LinearRingTest { ...@@ -104,7 +104,7 @@ public class LinearRingTest {
lr.addVertex(v1); lr.addVertex(v1);
lr.addVertex(v2); lr.addVertex(v2);
lr.addVertex(v0); lr.addVertex(v0);
Vector3d normal = lr.calculateNormal(); Vector3d normal = lr.calculateNormalNormalized();
assertEquals(1.0, normal.getX(), 0.0000001); assertEquals(1.0, normal.getX(), 0.0000001);
assertEquals(0.0, normal.getY(), 0.0000001); assertEquals(0.0, normal.getY(), 0.0000001);
assertEquals(0.0, normal.getZ(), 0.0000001); assertEquals(0.0, normal.getZ(), 0.0000001);
......
...@@ -18,11 +18,11 @@ ...@@ -18,11 +18,11 @@
*/ */
package de.hft.stuttgart.citydoctor2.parser; package de.hft.stuttgart.citydoctor2.parser;
import static org.junit.Assert.*; import static org.junit.Assert.assertSame;
import org.junit.Test; import org.junit.Test;
import org.osgeo.proj4j.CRSFactory; import org.locationtech.proj4j.CRSFactory;
import org.osgeo.proj4j.CoordinateReferenceSystem; 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 @@ ...@@ -35,6 +35,7 @@
<include>start.bat</include> <include>start.bat</include>
<include>testConfigWithStreaming.yml</include> <include>testConfigWithStreaming.yml</include>
<include>REKaiserwall.gml</include> <include>REKaiserwall.gml</include>
<include>checkForSolid.xml</include>
</includes> </includes>
<filtered>true</filtered> <filtered>true</filtered>
</fileSet> </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: ...@@ -2,7 +2,7 @@ globalParameters:
numberOfRoundingPlaces: 8 numberOfRoundingPlaces: 8
# in m # in m
minVertexDistance: 0.0001 minVertexDistance: 0.0001
schematronFilePath: '' schematronPath: 'checkForSolid.xml'
useStreaming: true useStreaming: true
requirements: requirements:
R_GE_R_TOO_FEW_POINTS: R_GE_R_TOO_FEW_POINTS:
......
...@@ -20,9 +20,12 @@ package de.hft.stuttgart.citydoctor2.check; ...@@ -20,9 +20,12 @@ package de.hft.stuttgart.citydoctor2.check;
import java.io.BufferedOutputStream; import java.io.BufferedOutputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
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.io.InputStream;
import java.io.UncheckedIOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
...@@ -136,7 +139,7 @@ public class Checker { ...@@ -136,7 +139,7 @@ public class Checker {
return; return;
} }
File xmlFile = new File(xmlOutput); File xmlFile = new File(xmlOutput);
if (xmlFile.getParentFile() == null) { if (xmlFile.getParentFile() != null) {
xmlFile.getParentFile().mkdirs(); xmlFile.getParentFile().mkdirs();
} }
Reporter reporter = new XmlValidationReporter(); Reporter reporter = new XmlValidationReporter();
...@@ -152,7 +155,7 @@ public class Checker { ...@@ -152,7 +155,7 @@ public class Checker {
return; return;
} }
File pdfFile = new File(pdfOutput); File pdfFile = new File(pdfOutput);
if (pdfFile.getParentFile() == null) { if (pdfFile.getParentFile() != null) {
pdfFile.getParentFile().mkdirs(); pdfFile.getParentFile().mkdirs();
} }
Reporter reporter = new PdfReporter("assets/Logo.png"); Reporter reporter = new PdfReporter("assets/Logo.png");
...@@ -220,7 +223,7 @@ public class Checker { ...@@ -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; int count = 0;
for (SchematronError se : v) { for (SchematronError se : v) {
CheckError err; CheckError err;
...@@ -232,7 +235,7 @@ public class Checker { ...@@ -232,7 +235,7 @@ public class Checker {
throw new IllegalStateException( throw new IllegalStateException(
"Unknown error ID was given in schematron file: " + se.getErrorIdString()); "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++; count++;
} }
} }
...@@ -399,6 +402,18 @@ public class Checker { ...@@ -399,6 +402,18 @@ public class Checker {
} }
public static SvrlContentHandler executeSchematronValidationIfAvailable(ValidationConfiguration config, File file) { 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 (config.getSchematronFilePath() != null && !config.getSchematronFilePath().isEmpty()) {
if (logger.isInfoEnabled()) { if (logger.isInfoEnabled()) {
logger.info(Localization.getText("Checker.schematronValidation")); logger.info(Localization.getText("Checker.schematronValidation"));
...@@ -441,7 +456,7 @@ public class Checker { ...@@ -441,7 +456,7 @@ public class Checker {
XsltExecutable schematronExecutable = xsltCompiler.compile(new DOMSource(doc)); XsltExecutable schematronExecutable = xsltCompiler.compile(new DOMSource(doc));
XsltTransformer schematronTransformer = schematronExecutable.load(); XsltTransformer schematronTransformer = schematronExecutable.load();
schematronTransformer.setSource(new StreamSource(file)); schematronTransformer.setSource(new StreamSource(in));
SvrlContentHandler handler = new SvrlContentHandler(); SvrlContentHandler handler = new SvrlContentHandler();
Destination dest = new SAXDestination(handler); Destination dest = new SAXDestination(handler);
schematronTransformer.setDestination(dest); schematronTransformer.setDestination(dest);
...@@ -538,24 +553,7 @@ public class Checker { ...@@ -538,24 +553,7 @@ public class Checker {
} else { } else {
if (e.getValue().isEnabled()) { if (e.getValue().isEnabled()) {
// this requirement is enabled // this requirement is enabled
for (CheckPrototype proto : Checks.getCheckPrototypes()) { insertGlobalParameters(config, enabledCheck, parameterMap, e, req);
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);
}
}
} }
} }
} }
...@@ -569,6 +567,29 @@ public class Checker { ...@@ -569,6 +567,29 @@ public class Checker {
return checkList; 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, private void fillParameterMapsWithDefaultParameter(Set<CheckId> enabledCheck,
Map<CheckId, Map<String, String>> parameterMap) { Map<CheckId, Map<String, String>> parameterMap) {
for (CheckId id : enabledCheck) { for (CheckId id : enabledCheck) {
...@@ -745,8 +766,8 @@ public class Checker { ...@@ -745,8 +766,8 @@ public class Checker {
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);
writeReport(pdfReporter, handler); writeReport(pdfReporter);
} catch (CheckReportWriteException e) { } catch (CheckReportWriteException e) {
logger.error(Localization.getText("Checker.failReports"), e); logger.error(Localization.getText("Checker.failReports"), e);
} }
...@@ -774,19 +795,9 @@ public class Checker { ...@@ -774,19 +795,9 @@ public class Checker {
return pdfReporter; return pdfReporter;
} }
public static void writeReport(StreamReporter reporter, SvrlContentHandler handler) public static void writeReport(StreamReporter reporter)
throws CheckReportWriteException { throws CheckReportWriteException {
if (reporter != null) { 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(); reporter.finishReport();
} }
} }
......
...@@ -28,6 +28,8 @@ import java.util.Set; ...@@ -28,6 +28,8 @@ import java.util.Set;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicInteger; 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.factory.GMLGeometryFactory;
import org.citygml4j.model.citygml.core.CityModel; import org.citygml4j.model.citygml.core.CityModel;
...@@ -53,6 +55,8 @@ import de.hft.stuttgart.quality.model.jaxb.Statistics; ...@@ -53,6 +55,8 @@ import de.hft.stuttgart.quality.model.jaxb.Statistics;
public class StreamCityGmlConsumer implements CityGmlConsumer { public class StreamCityGmlConsumer implements CityGmlConsumer {
private static final Logger logger = LogManager.getLogger(StreamCityGmlConsumer.class);
private Checker c; private Checker c;
private XmlStreamReporter xmlReporter; private XmlStreamReporter xmlReporter;
private PdfStreamReporter pdfReporter; private PdfStreamReporter pdfReporter;
...@@ -102,8 +106,16 @@ public class StreamCityGmlConsumer implements CityGmlConsumer { ...@@ -102,8 +106,16 @@ public class StreamCityGmlConsumer implements CityGmlConsumer {
@Override @Override
public void accept(CityObject co) { 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) { if (handler != null) {
List<SchematronError> errors = handler.getFeatureErrors().get(co.getGmlId().getGmlString()); List<SchematronError> errors = handler.getFeatureErrors().get(co.getGmlId().getGmlString());
if (errors != null) { if (errors != null) {
...@@ -111,6 +123,15 @@ public class StreamCityGmlConsumer implements CityGmlConsumer { ...@@ -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 // remove existing quality ade datastructure if existing
QualityADEUtils.removeValidationResult(co); QualityADEUtils.removeValidationResult(co);
// store quality ade datastructures in cityobject // store quality ade datastructures in cityobject
......
...@@ -52,6 +52,7 @@ import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; ...@@ -52,6 +52,7 @@ import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
*/ */
public class ValidationConfiguration implements Serializable { 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 NUMBER_OF_ROUNDING_PLACES_DEFAULT = "8";
private static final String MIN_VERTEX_DISTANCE_DEFAULT = "0.0001"; private static final String MIN_VERTEX_DISTANCE_DEFAULT = "0.0001";
private static final long serialVersionUID = -8020055032177740646L; private static final long serialVersionUID = -8020055032177740646L;
...@@ -93,6 +94,7 @@ public class ValidationConfiguration implements Serializable { ...@@ -93,6 +94,7 @@ public class ValidationConfiguration implements Serializable {
config.globalParameters = new HashMap<>(); config.globalParameters = new HashMap<>();
config.globalParameters.put(GlobalParameters.NUMBER_OF_ROUNDING_PLACES, NUMBER_OF_ROUNDING_PLACES_DEFAULT); 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.globalParameters.put(GlobalParameters.MIN_VERTEX_DISTANCE, MIN_VERTEX_DISTANCE_DEFAULT);
config.setSchematronFilePathInGlobalParameters(CHECK_FOR_SOLID_XML);
return config; return config;
} }
......
...@@ -150,7 +150,7 @@ public class AllPolygonsWrongOrientationCheck extends Check { ...@@ -150,7 +150,7 @@ public class AllPolygonsWrongOrientationCheck extends Check {
throw new IllegalStateException("Constructed a ray that does not intersect any polygon"); throw new IllegalStateException("Constructed a ray that does not intersect any polygon");
} }
// calculate normal of the closest 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, // calculate cos(gamma) of normal and ray direction, the normal is normalized,
// don't need to get the length // don't need to get the length
double cosAngle = outsidePointDirection.dot(normal) / outsidePointDirection.getLength(); double cosAngle = outsidePointDirection.dot(normal) / outsidePointDirection.getLength();
......
...@@ -66,7 +66,7 @@ public class IsCeilingCheck extends Check { ...@@ -66,7 +66,7 @@ public class IsCeilingCheck extends Check {
} }
for (Geometry geom : bs.getGeometries()) { for (Geometry geom : bs.getGeometries()) {
for (Polygon p : geom.getPolygons()) { for (Polygon p : geom.getPolygons()) {
Vector3d normal = p.calculateNormal(); Vector3d normal = p.calculateNormalNormalized();
if (normal.getZ() >= 0) { if (normal.getZ() >= 0) {
NotCeilingError err = new NotCeilingError(bs, p); NotCeilingError err = new NotCeilingError(bs, p);
CheckResult cr = new CheckResult(this, ResultStatus.ERROR, err); CheckResult cr = new CheckResult(this, ResultStatus.ERROR, err);
......
...@@ -67,7 +67,7 @@ public class IsFloorCheck extends Check { ...@@ -67,7 +67,7 @@ public class IsFloorCheck extends Check {
} }
for (Geometry geom : bs.getGeometries()) { for (Geometry geom : bs.getGeometries()) {
for (Polygon p : geom.getPolygons()) { for (Polygon p : geom.getPolygons()) {
Vector3d normal = p.calculateNormal(); Vector3d normal = p.calculateNormalNormalized();
if (normal.getZ() <= 0) { if (normal.getZ() <= 0) {
NotFloorError err = new NotFloorError(bs, p); NotFloorError err = new NotFloorError(bs, p);
CheckResult cr = new CheckResult(this, ResultStatus.ERROR, err); CheckResult cr = new CheckResult(this, ResultStatus.ERROR, err);
......
...@@ -66,7 +66,7 @@ public class IsGroundCheck extends Check { ...@@ -66,7 +66,7 @@ public class IsGroundCheck extends Check {
} }
for (Geometry geom : bs.getGeometries()) { for (Geometry geom : bs.getGeometries()) {
for (Polygon p : geom.getPolygons()) { for (Polygon p : geom.getPolygons()) {
Vector3d normal = p.calculateNormal(); Vector3d normal = p.calculateNormalNormalized();
if (normal.getZ() >= 0) { if (normal.getZ() >= 0) {
NotGroundError err = new NotGroundError(bs, p); NotGroundError err = new NotGroundError(bs, p);
CheckResult cr = new CheckResult(this, ResultStatus.ERROR, err); CheckResult cr = new CheckResult(this, ResultStatus.ERROR, err);
......
...@@ -98,7 +98,7 @@ public class IsWallCheck extends Check { ...@@ -98,7 +98,7 @@ public class IsWallCheck extends Check {
for (Geometry geom : bs.getGeometries()) { for (Geometry geom : bs.getGeometries()) {
for (Polygon p : geom.getPolygons()) { for (Polygon p : geom.getPolygons()) {
Vector3d normal = p.calculateNormal(); Vector3d normal = p.calculateNormalNormalized();
double dot = normal.dot(Z_AXIS); double dot = normal.dot(Z_AXIS);
// The angle should be between 45 and 135 degree, measured // The angle should be between 45 and 135 degree, measured
......
...@@ -20,6 +20,7 @@ package de.hft.stuttgart.citydoctor2.checks.util; ...@@ -20,6 +20,7 @@ package de.hft.stuttgart.citydoctor2.checks.util;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.List; import java.util.List;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
...@@ -44,6 +45,9 @@ import de.hft.stuttgart.citydoctor2.datastructure.LinearRing; ...@@ -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.LinearRing.LinearRingType;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon; import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
import de.hft.stuttgart.citydoctor2.datastructure.Vertex; 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.MovedPolygon;
import de.hft.stuttgart.citydoctor2.math.MovedRing; import de.hft.stuttgart.citydoctor2.math.MovedRing;
import de.hft.stuttgart.citydoctor2.math.Plane; import de.hft.stuttgart.citydoctor2.math.Plane;
...@@ -71,6 +75,8 @@ public class SelfIntersectionUtil { ...@@ -71,6 +75,8 @@ public class SelfIntersectionUtil {
private static final String DIVISOR_IS_0 = "Divisor is 0"; private static final String DIVISOR_IS_0 = "Divisor is 0";
private static final Logger logger = LogManager.getLogger(SelfIntersectionUtil.class); private static final Logger logger = LogManager.getLogger(SelfIntersectionUtil.class);
private static boolean useEdge = false;
private static GeometryFactory factory = new GeometryFactory(new PrecisionModel(PrecisionModel.FLOATING)); private static GeometryFactory factory = new GeometryFactory(new PrecisionModel(PrecisionModel.FLOATING));
...@@ -85,13 +91,37 @@ public class SelfIntersectionUtil { ...@@ -85,13 +91,37 @@ public class SelfIntersectionUtil {
public static List<PolygonIntersection> doesSolidSelfIntersect2(Geometry g) { public static List<PolygonIntersection> doesSolidSelfIntersect2(Geometry g) {
List<Polygon> polygons = g.getPolygons(); List<Polygon> polygons = g.getPolygons();
List<PolygonIntersection> intersections = new ArrayList<>(); 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++) { for (int i = 0; i < polygons.size() - 1; i++) {
Polygon p1 = polygons.get(i); Polygon p1 = polygons.get(i);
for (int j = i + 1; j < polygons.size(); j++) { for (int j = i + 1; j < polygons.size(); j++) {
Polygon p2 = polygons.get(j); Polygon p2 = polygons.get(j);
PolygonIntersection intersect = polygonIntersection(p1, p2, 0.1, 0.01); if (useEdge && p1.getInnerRings().isEmpty() && p2.getInnerRings().isEmpty()) {
if (intersect.getType() != IntersectionType.NONE) { } else {
intersections.add(intersect); 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