Commit a2e3d7f7 authored by Luna Riegel's avatar Luna Riegel
Browse files

Merge branch 'refs/heads/dev' into dev_embedded_geodb

# Conflicts:
#	CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/Opening.java
#	CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/check/Checker.java
#	CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/CityDoctorController.java
parents c748a058 2fe401b3
......@@ -59,6 +59,7 @@ public class SchematronError implements CheckError {
@Override
public void report(ErrorReport report) {
report.add("errorId", errorId);
report.add("message", nameOfAttribute);
}
@Override
......
......@@ -61,15 +61,11 @@ public class BridgeObject extends CityObject {
private BridgeObject parent;
public BridgeObject(AbstractBridge ab) {
this.ab = ab;
this.type = BridgeType.BRIDGE;
this.parent = null;
this(BridgeType.BRIDGE, ab, null);
}
public BridgeObject(AbstractBridge ab, BridgeObject parent) {
this.ab = ab;
this.type = BridgeType.BRIDGE_PART;
this.parent = parent;
this(BridgeType.BRIDGE_PART, ab, parent);
}
private BridgeObject(BridgeType type, AbstractBridge ab, BridgeObject parent) {
......
package de.hft.stuttgart.citydoctor2.datastructure;
import de.hft.stuttgart.citydoctor2.check.CheckableVisitor;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.utils.CityGmlUtils;
import javafx.scene.paint.Color;
import java.io.Serial;
import java.util.ArrayList;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.citygml4j.core.model.core.AbstractSpaceBoundaryProperty;
import org.citygml4j.core.model.deprecated.bridge.DeprecatedPropertiesOfBridgeConstructiveElement;
import org.citygml4j.core.util.geometry.GeometryFactory;
import org.xmlobjects.gml.model.geometry.GeometryProperty;
import org.xmlobjects.gml.model.geometry.aggregates.MultiSurface;
import org.xmlobjects.gml.model.geometry.aggregates.MultiSurfaceProperty;
import org.xmlobjects.gml.model.geometry.complexes.CompositeSurface;
import org.xmlobjects.gml.model.geometry.primitives.Solid;
import org.xmlobjects.gml.model.geometry.primitives.SolidProperty;
import org.xmlobjects.gml.model.geometry.primitives.SurfaceProperty;
import java.io.Serial;
import java.util.ArrayList;
import java.util.List;
import de.hft.stuttgart.citydoctor2.check.CheckableVisitor;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.utils.CityGmlUtils;
import javafx.scene.paint.Color;
public class BuildingConstructiveElement extends CityObject {
......
......@@ -47,10 +47,6 @@ public class Opening extends CityObject {
private AbstractFillingSurface ao;
private Opening(OpeningType type) {
this.type = type;
}
public Opening(OpeningType type, BoundarySurface partOf,
AbstractFillingSurface ao) {
this.partOf = partOf;
......
......@@ -9,6 +9,8 @@ public class TunnelPart extends AbstractTunnel {
private Tunnel parent;
private TunnelPart() {
}
public TunnelPart(Tunnel parent) {
this.parent = parent;
......@@ -34,6 +36,4 @@ public class TunnelPart extends AbstractTunnel {
return "TunnelPart [id=" + getGmlId() + "]";
}
private TunnelPart() {
}
}
......@@ -87,8 +87,13 @@ public class Triangle3d implements Serializable {
Vector3d n2 = v1.cross(v2);
return new Plane(n2, p1);
}
public boolean doesIntersect(Triangle3d other) {
return doesIntersect(other, EPSILON);
}
public boolean doesIntersect(Triangle3d other, double epsilon) {
// plane of other triangle
Plane planeT2 = other.getPlane();
// check if all points are on one side of the plane
......@@ -96,13 +101,13 @@ public class Triangle3d implements Serializable {
double distanceP2T2 = planeT2.getSignedDistance(p2);
double distanceP3T2 = planeT2.getSignedDistance(p3);
if (Math.abs(distanceP1T2) < EPSILON) {
if (Math.abs(distanceP1T2) < epsilon) {
distanceP1T2 = 0.0;
}
if (Math.abs(distanceP2T2) < EPSILON) {
if (Math.abs(distanceP2T2) < epsilon) {
distanceP2T2 = 0.0;
}
if (Math.abs(distanceP3T2) < EPSILON) {
if (Math.abs(distanceP3T2) < epsilon) {
distanceP3T2 = 0.0;
}
......@@ -123,13 +128,13 @@ public class Triangle3d implements Serializable {
double distanceP2T1 = planeT1.getSignedDistance(other.getP2());
double distanceP3T1 = planeT1.getSignedDistance(other.getP3());
if (Math.abs(distanceP1T1) < EPSILON) {
if (Math.abs(distanceP1T1) < epsilon) {
distanceP1T1 = 0.0;
}
if (Math.abs(distanceP2T1) < EPSILON) {
if (Math.abs(distanceP2T1) < epsilon) {
distanceP2T1 = 0.0;
}
if (Math.abs(distanceP3T1) < EPSILON) {
if (Math.abs(distanceP3T1) < epsilon) {
distanceP3T1 = 0.0;
}
......@@ -139,11 +144,15 @@ public class Triangle3d implements Serializable {
return false;
}
return checkTriangleLineIntersection(other, p1, p2) || checkTriangleLineIntersection(other, p1, p3)
boolean intersects = checkTriangleLineIntersection(other, p1, p2) || checkTriangleLineIntersection(other, p1, p3)
|| checkTriangleLineIntersection(other, p2, p3)
|| checkTriangleLineIntersection(this, other.p1, other.p2)
|| checkTriangleLineIntersection(this, other.p1, other.p3)
|| checkTriangleLineIntersection(this, other.p2, other.p3);
if (intersects) {
System.out.println();
}
return intersects;
}
private boolean checkTriangleLineIntersection(Triangle3d other, Vector3d a, Vector3d b) {
......@@ -171,7 +180,11 @@ public class Triangle3d implements Serializable {
private boolean doesIntersectCoplanarTriangle(Triangle3d other) {
Triangle2d t1 = projectTo2d();
Triangle2d t2 = other.projectTo2d();
return t1.intersects(t2);
boolean intersects = t1.intersects(t2);
if (intersects) {
System.out.println();
}
return intersects;
}
public Triangle2d projectTo2d() {
......
......@@ -49,6 +49,15 @@ public class EarcutTesselator {
start = addRingToArray(innerRing, vertices, start, axis);
}
// center vertices?
// double[] projectedCenter = new double[2];
// Geometry geometry = p.getParent();
// Vector3d center = geometry.getCenter();
// axis.writeCoordinatesOfVectorInArray(center, projectedCenter, 0);
// for (int i = 0; i < vertices.length; i++) {
// vertices[i] = vertices[i] - projectedCenter[i % 2];
// }
// triangulation
List<Integer> indices = Earcut.earcut(vertices, holeStart, 2);
List<Triangle3d> triangles = new ArrayList<>();
......@@ -56,14 +65,15 @@ public class EarcutTesselator {
throw new IllegalStateException();
}
for (int i = 0; i < indices.size(); i = i + 3) {
Triangle3d t = new Triangle3d(vertexObjects.get(indices.get(i + 0)),
vertexObjects.get(indices.get(i + 1)),
vertexObjects.get(indices.get(i + 2)));
Vertex v1 = vertexObjects.get(indices.get(i + 0));
Vertex v2 = vertexObjects.get(indices.get(i + 1));
Vertex v3 = vertexObjects.get(indices.get(i + 2));
Triangle3d t = new Triangle3d(v1, v2, v3);
triangles.add(t);
}
return new TesselatedPolygon(triangles, p);
}
private static void addVerticesToList(LinearRing ring, List<Vertex> vertexObjects) {
List<Vertex> vertices = ring.getVertices();
for (int i = 0; i < vertices.size() - 1; i++) {
......
......@@ -29,11 +29,13 @@ import de.hft.stuttgart.citydoctor2.checks.Checks;
import de.hft.stuttgart.citydoctor2.checks.SvrlContentHandler;
import de.hft.stuttgart.citydoctor2.checks.util.FeatureCheckedListener;
import de.hft.stuttgart.citydoctor2.database.CityObjectCache;
import de.hft.stuttgart.citydoctor2.database.CityObjectCache;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.datastructure.FeatureType;
import de.hft.stuttgart.citydoctor2.datastructure.GmlId;
import de.hft.stuttgart.citydoctor2.datastructure.ImplicitGeometryHolder;
import de.hft.stuttgart.citydoctor2.datastructure.GmlId;
import de.hft.stuttgart.citydoctor2.parser.CityGmlConsumer;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParser;
......@@ -231,25 +233,54 @@ public class Checker {
}
private void handleSchematronResults(SvrlContentHandler handler) {
model.addGlobalErrors(handler.getGeneralErrors());
CityObjectCache cache = model.getCache();
handleSchematronErrorsGlobal(handler.getGeneralErrors());
Map<String, CityObject> featureMap = new HashMap<>();
boolean onlySchematron = execLayers.isEmpty();
if (onlySchematron) {
CheckableUtilsVisitor visitor = new CheckableUtilsVisitor() {
@Override
public void check(Checkable checkable) {
checkable.setValidated(true);
}
};
model.createFeatureStream().forEach(f -> {
featureMap.put(f.getGmlId().getGmlString(), f);
f.accept(visitor);
});
} else {
model.createFeatureStream().forEach(f -> featureMap.put(f.getGmlId().getGmlString(), f));
}
handler.getFeatureErrors().forEach((k, v) -> {
if (k.trim().isEmpty()) {
// missing gml id, ignore?
return;
}
String trimmedId = k.trim();
CityObject co = cache.get(new GmlId(k));
if (co == null) {
// gml id reported by schematron was not found, add to general errors
for (SchematronError se : v) {
model.addGlobalError(se);
}
handleSchematronErrorsGlobal(v);
} else {
handleSchematronErrorsForCityObject(v, co);
co.setValidated(true);
}
});
}
private void handleSchematronErrorsGlobal(List<SchematronError> v) {
for (SchematronError se : v) {
CheckError err;
if (AttributeMissingError.ID.getIdString().equals(se.getErrorIdString())) {
err = new AttributeMissingError(null, se.getChildId(), se.getNameOfAttribute());
} else if (AttributeValueWrongError.ID.getIdString().equals(se.getErrorIdString())) {
err = new AttributeValueWrongError(null, se.getChildId(), se.getNameOfAttribute());
} else if (AttributeInvalidError.ID.getIdString().equals(se.getErrorIdString())) {
err = new AttributeInvalidError(null, se.getChildId(), se.getNameOfAttribute());
} else {
throw new IllegalStateException(
"Unknown error ID was given in schematron file: " + se.getErrorIdString());
}
model.addGlobalError(err);
}
}
public static void handleSchematronErrorsForCityObject(List<SchematronError> v, CityObject co) {
int count = 0;
for (SchematronError se : v) {
......@@ -462,7 +493,6 @@ public class Checker {
}
}
@SuppressWarnings("resource")
public static SvrlContentHandler executeSchematronValidationIfAvailable(ValidationConfiguration config,
InputStream in) {
if (config.getSchematronFilePath() != null && !config.getSchematronFilePath().isEmpty()) {
......
......@@ -106,12 +106,12 @@ public class SvrlContentHandler implements ContentHandler {
throw new IllegalStateException(
"Schematron File is not formed according to specification for CityDoctor.");
}
String gmlId = split[0];
String gmlId = split[0].strip();
String childId = split[1];
String errorId = split[2];
String nameOfAttribute = split[3];
SchematronError err = new SchematronError(errorId, gmlId, childId, nameOfAttribute);
if (gmlId == null || gmlId.isEmpty()) {
if (gmlId == null || gmlId.isBlank()) {
// general error
generalErrors.add(err);
} else {
......
......@@ -57,10 +57,12 @@ import de.hft.stuttgart.citydoctor2.tesselation.TesselatedPolygon;
*/
public class PlanarCheck extends Check {
private static final String DISTANCE = "distance";
private static final String DISTANCE_TOLERANCE = "distanceTolerance";
public static final String ANGLE = "angle";
public static final String DISTANCE = "distance";
public static final String BOTH = "both";
public static final String DISTANCE_TOLERANCE = "distanceTolerance";
private static final String ANGLE_TOLERANCE = "angleTolerance";
private static final String TYPE = "type";
public static final String TYPE = "type";
private static final List<CheckId> dependencies;
......@@ -97,7 +99,7 @@ public class PlanarCheck extends Check {
public void check(Polygon p) {
if (DISTANCE.equals(planarCheckType)) {
planarDistance(p);
} else if ("angle".equals(planarCheckType)) {
} else if (ANGLE.equals(planarCheckType)) {
planarNormalDeviation(p);
} else if ("both".equals(planarCheckType)) {
planarDistance(p);
......
......@@ -21,13 +21,13 @@ package de.hft.stuttgart.citydoctor2.checks.geometry;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import de.hft.stuttgart.citydoctor2.check.Check;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.CheckId;
import de.hft.stuttgart.citydoctor2.check.CheckResult;
import de.hft.stuttgart.citydoctor2.check.GeometrySelfIntersection;
import de.hft.stuttgart.citydoctor2.check.Requirement;
import de.hft.stuttgart.citydoctor2.check.RequirementType;
import de.hft.stuttgart.citydoctor2.check.ResultStatus;
......@@ -36,6 +36,7 @@ import de.hft.stuttgart.citydoctor2.checks.util.CollectionUtils;
import de.hft.stuttgart.citydoctor2.checks.util.SelfIntersectionUtil;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.datastructure.GeometryType;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.utils.PolygonIntersection;
/**
......@@ -47,7 +48,9 @@ import de.hft.stuttgart.citydoctor2.utils.PolygonIntersection;
public class SolidSelfIntCheck extends Check {
private static final List<CheckId> dependencies;
private double delta = 0.01;
static {
ArrayList<CheckId> deps = new ArrayList<>();
dependencies = Collections.unmodifiableList(deps);
......@@ -68,6 +71,13 @@ public class SolidSelfIntCheck extends Check {
deps.add(CheckId.C_GE_S_NON_MANIFOLD_VERTEX);
deps.add(CheckId.C_GE_S_POLYGON_WRONG_ORIENTATION);
}
@Override
public void init(Map<String, String> parameters, ParserConfiguration config) {
if (parameters.containsKey(PlanarCheck.DISTANCE_TOLERANCE)) {
delta = Double.parseDouble(parameters.get(PlanarCheck.DISTANCE_TOLERANCE));
}
}
@Override
public void check(Geometry g) {
......@@ -75,7 +85,7 @@ public class SolidSelfIntCheck extends Check {
return;
}
CheckResult cr;
List<PolygonIntersection> intersections = SelfIntersectionUtil.calculateSolidSelfIntersection(g);
List<PolygonIntersection> intersections = SelfIntersectionUtil.calculateSolidSelfIntersection(g, delta);
if (intersections.isEmpty()) {
cr = new CheckResult(this, ResultStatus.OK, null);
} else {
......@@ -85,18 +95,6 @@ public class SolidSelfIntCheck extends Check {
g.addCheckResult(cr);
}
@SuppressWarnings("unused")
private CheckResult oldIntersectionAlgorithm(Geometry g) {
CheckResult cr;
GeometrySelfIntersection intersect = SelfIntersectionUtil.doesSolidSelfIntersect(g);
if (intersect != null) {
cr = new CheckResult(this, ResultStatus.ERROR, null);
} else {
cr = new CheckResult(this, ResultStatus.OK, null);
}
return cr;
}
@Override
public List<CheckId> getDependencies() {
return dependencies;
......
......@@ -21,6 +21,7 @@ package de.hft.stuttgart.citydoctor2.checks.util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
......@@ -39,6 +40,8 @@ import org.locationtech.jts.geom.impl.CoordinateArraySequence;
import org.locationtech.jts.operation.overlay.OverlayOp;
import org.locationtech.jts.operation.overlay.snap.SnapIfNeededOverlayOp;
import Jama.EigenvalueDecomposition;
import Jama.Matrix;
import de.hft.stuttgart.citydoctor2.check.GeometrySelfIntersection;
import de.hft.stuttgart.citydoctor2.datastructure.ConcretePolygon;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
......@@ -50,8 +53,10 @@ import de.hft.stuttgart.citydoctor2.edge.EdgePolygon;
import de.hft.stuttgart.citydoctor2.edge.IntersectPlanarPolygons;
import de.hft.stuttgart.citydoctor2.edge.MeshSurface;
import de.hft.stuttgart.citydoctor2.edge.PolygonPolygonIntersection;
import de.hft.stuttgart.citydoctor2.math.CovarianceMatrix;
import de.hft.stuttgart.citydoctor2.math.MovedPolygon;
import de.hft.stuttgart.citydoctor2.math.MovedRing;
import de.hft.stuttgart.citydoctor2.math.OrthogonalRegressionPlane;
import de.hft.stuttgart.citydoctor2.math.Plane;
import de.hft.stuttgart.citydoctor2.math.PlaneSegmentIntersection;
import de.hft.stuttgart.citydoctor2.math.PlaneSegmentIntersection.Type;
......@@ -83,18 +88,37 @@ public class SelfIntersectionUtil {
private SelfIntersectionUtil() {
}
public static List<PolygonIntersection> calculateSolidSelfIntersection(Geometry g) {
public static List<PolygonIntersection> calculateSolidSelfIntersection(Geometry g, double delta) {
List<TesselatedPolygon> tesselatedPolygons = new ArrayList<>();
for (Polygon p : g.getPolygons()) {
tesselatedPolygons.add(EarcutTesselator.tesselatePolygon(p));
TesselatedPolygon tessPolygon = EarcutTesselator.tesselatePolygon(p);
for (Iterator<Triangle3d> iterator = tessPolygon.getTriangles().iterator(); iterator.hasNext();) {
Triangle3d t = iterator.next();
List<Vector3d> vertices = new ArrayList<>(3);
vertices.add(t.getP1());
vertices.add(t.getP2());
vertices.add(t.getP3());
Vector3d centroid = CovarianceMatrix.getCentroid(vertices);
EigenvalueDecomposition ed = OrthogonalRegressionPlane.decompose(vertices, centroid);
Matrix eigenValues = ed.getD();
double[] eigenValuesArray = new double[3];
eigenValuesArray[0] = eigenValues.get(0, 0);
eigenValuesArray[1] = eigenValues.get(1, 1);
eigenValuesArray[2] = eigenValues.get(2, 2);
if (eigenValuesArray[1] < delta) {
iterator.remove();
}
}
tesselatedPolygons.add(tessPolygon);
}
List<PolygonIntersection> intersections = new ArrayList<>();
for (int i = 0; i < tesselatedPolygons.size() - 1; i++) {
TesselatedPolygon p1 = tesselatedPolygons.get(i);
for (int j = i + 1; j < tesselatedPolygons.size(); j++) {
TesselatedPolygon p2 = tesselatedPolygons.get(j);
GeometrySelfIntersection intersection = doPolygonsIntersect(p1, p2);
GeometrySelfIntersection intersection = doPolygonsIntersect(p1, p2, delta);
if (intersection != null) {
intersections.add(PolygonIntersection.triangles(intersection.t1(), intersection.t2()));
}
......@@ -103,8 +127,8 @@ public class SelfIntersectionUtil {
return intersections;
}
public static GeometrySelfIntersection doesSolidSelfIntersect(Geometry g) {
return selfIntersectionJava(g);
public static GeometrySelfIntersection doesSolidSelfIntersect(Geometry g, double epsilon) {
return selfIntersectionJava(g, epsilon);
}
public static List<PolygonIntersection> doesSolidSelfIntersect2(Geometry g) {
......@@ -404,7 +428,7 @@ public class SelfIntersectionUtil {
return sign != 0;
}
private static GeometrySelfIntersection selfIntersectionJava(Geometry g) {
private static GeometrySelfIntersection selfIntersectionJava(Geometry g, double epsilon) {
List<TesselatedPolygon> tessPolys = new ArrayList<>();
for (Polygon p : g.getPolygons()) {
tessPolys.add(JoglTesselator.tesselatePolygon(p));
......@@ -413,7 +437,7 @@ public class SelfIntersectionUtil {
TesselatedPolygon p1 = tessPolys.get(i);
for (int j = i + 1; j < tessPolys.size(); j++) {
TesselatedPolygon p2 = tessPolys.get(j);
GeometrySelfIntersection intersection = doPolygonsIntersect(p1, p2);
GeometrySelfIntersection intersection = doPolygonsIntersect(p1, p2, epsilon);
if (intersection != null) {
return intersection;
}
......@@ -422,12 +446,12 @@ public class SelfIntersectionUtil {
return null;
}
private static GeometrySelfIntersection doPolygonsIntersect(TesselatedPolygon p1, TesselatedPolygon p2) {
private static GeometrySelfIntersection doPolygonsIntersect(TesselatedPolygon p1, TesselatedPolygon p2, double epsilon) {
for (int p1Index = 0; p1Index < p1.getTriangles().size(); p1Index++) {
for (int p2Index = 0; p2Index < p2.getTriangles().size(); p2Index++) {
Triangle3d t1 = p1.getTriangles().get(p1Index);
Triangle3d t2 = p2.getTriangles().get(p2Index);
if (t1.doesIntersect(t2)) {
if (t1.doesIntersect(t2, epsilon)) {
logger.trace("{} intersects {}", t1, t2);
logger.trace("GML-ID: {} intersects {}", t1.getPartOf().getOriginal().getGmlId(),
t2.getPartOf().getOriginal().getGmlId());
......
......@@ -25,14 +25,18 @@ import static org.junit.Assert.assertNotNull;
import org.junit.Assert;
import org.junit.Test;
import de.hft.stuttgart.citydoctor2.check.CheckId;
import de.hft.stuttgart.citydoctor2.check.CheckResult;
import de.hft.stuttgart.citydoctor2.check.Checker;
import de.hft.stuttgart.citydoctor2.check.ResultStatus;
import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration;
import de.hft.stuttgart.citydoctor2.check.error.NonPlanarPolygonDistancePlaneError;
import de.hft.stuttgart.citydoctor2.checks.util.GeometryTestUtils;
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.Geometry.Orientation;
import de.hft.stuttgart.citydoctor2.datastructure.GeometryType;
import de.hft.stuttgart.citydoctor2.datastructure.Lod;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
......@@ -45,6 +49,22 @@ import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException;
*
*/
public class SolidSelfIntCheckTest {
@Test
public void testDependencyChecking() {
Geometry geom = new Geometry(GeometryType.SOLID, Lod.LOD2, Orientation.OUTWARD);
ConcretePolygon p = new ConcretePolygon();
geom.addPolygon(p);
NonPlanarPolygonDistancePlaneError err = new NonPlanarPolygonDistancePlaneError(p, 2, null, null);
CheckResult cr = new CheckResult(CheckId.C_GE_P_NON_PLANAR, ResultStatus.ERROR, err);
p.addCheckResult(cr);
SolidSelfIntCheck selfIntCheck = new SolidSelfIntCheck();
boolean canExecute = selfIntCheck.canExecute(geom);
assertFalse(canExecute);
}
@Test
public void testGoodGeometry() {
......
......@@ -31,6 +31,7 @@ import de.hft.stuttgart.citydoctor2.check.CheckResult;
import de.hft.stuttgart.citydoctor2.check.Checker;
import de.hft.stuttgart.citydoctor2.check.ErrorId;
import de.hft.stuttgart.citydoctor2.check.ResultStatus;
import de.hft.stuttgart.citydoctor2.checks.geometry.PlanarCheck;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
......@@ -142,7 +143,7 @@ public class PlanarTest {
public void testPlanarPolygon6() throws CityGmlParseException, IOException, InvalidGmlFileException {
Map<String, Map<String, String>> paramMap = new HashMap<>();
Map<String, String> parameter = new HashMap<>();
parameter.put("type", "both");
parameter.put(PlanarCheck.TYPE, PlanarCheck.BOTH);
parameter.put("distanceTolerance", "0.5");
paramMap.put(RequirementId.R_GE_P_NON_PLANAR.toString(), parameter);
CityDoctorModel c = TestUtil.loadAndCheckCityModel("src/test/resources/SimpleSolid_SrefBS-GE-gml-PO-0002-T0002.gml", paramMap);
......
#!/bin/sh
./runtime/bin/java -classpath app/*:plugin/* de.hft.stuttgart.citydoctor2.gui.CityDoctorGUIStarter
\ No newline at end of file
#! /usr/bin/env sh
java -classpath "app/*:plugin/*" de.hft.stuttgart.citydoctor2.gui.CityDoctorGUIStarter
......@@ -18,6 +18,7 @@ import de.hft.stuttgart.citydoctor2.gui.tree.node.TopLevelCityObjectNode;
import de.hft.stuttgart.citydoctor2.mapper.citygml3.GMLValidationHandler;
import de.hft.stuttgart.citydoctor2.parser.*;
import de.hft.stuttgart.citydoctor2.utils.Localization;
import de.hft.stuttgart.quality.adapter.types.ErrorAdapter;
import javafx.application.Platform;
import javafx.scene.chart.XYChart.Data;
import javafx.scene.chart.XYChart.Series;
......@@ -1084,11 +1085,7 @@ public class CityDoctorController {
buildTrees();
updateFeatureTrees();
updateTree(mainWindow.getPolygonsView().getRoot());
for (CheckError e : model.getGlobalErrors()) {
if (e instanceof SchematronError se) {
mainWindow.getGlobalErrorsView().getItems().add(se.getErrorIdString() + " - " + se.getNameOfAttribute());
}
}
updateGlobalErrors();
renderer.refresh();
mainWindow.getWriteReportButton().setDisable(false);
});
......@@ -1097,6 +1094,13 @@ public class CityDoctorController {
}
}
private void updateGlobalErrors() {
GlobalErrorVisitor globErrVisitor = new GlobalErrorVisitor(mainWindow);
for (CheckError e : model.getGlobalErrors()) {
e.accept(globErrVisitor);
}
}
void updateFeatureTrees() {
updateTree(mainWindow.getBuildingsView().getRoot());
updateTree(mainWindow.getVegetationView().getRoot());
......
package de.hft.stuttgart.citydoctor2.gui;
import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.ErrorVisitor;
import de.hft.stuttgart.citydoctor2.check.error.AllPolygonsWrongOrientationError;
import de.hft.stuttgart.citydoctor2.check.error.AttributeInvalidError;
import de.hft.stuttgart.citydoctor2.check.error.AttributeMissingError;
import de.hft.stuttgart.citydoctor2.check.error.AttributeValueWrongError;
import de.hft.stuttgart.citydoctor2.check.error.ConsecutivePointSameError;
import de.hft.stuttgart.citydoctor2.check.error.DegeneratedRingError;
import de.hft.stuttgart.citydoctor2.check.error.DependenciesNotMetError;
import de.hft.stuttgart.citydoctor2.check.error.MultipleConnectedComponentsError;
import de.hft.stuttgart.citydoctor2.check.error.NestedRingError;
import de.hft.stuttgart.citydoctor2.check.error.NonManifoldEdgeError;
import de.hft.stuttgart.citydoctor2.check.error.NonManifoldVertexError;
import de.hft.stuttgart.citydoctor2.check.error.NonPlanarPolygonDistancePlaneError;
import de.hft.stuttgart.citydoctor2.check.error.NonPlanarPolygonNormalsDeviation;
import de.hft.stuttgart.citydoctor2.check.error.NotCeilingError;
import de.hft.stuttgart.citydoctor2.check.error.NotFloorError;
import de.hft.stuttgart.citydoctor2.check.error.NotGroundError;
import de.hft.stuttgart.citydoctor2.check.error.NotWallError;
import de.hft.stuttgart.citydoctor2.check.error.NullAreaError;
import de.hft.stuttgart.citydoctor2.check.error.PlanarityError;
import de.hft.stuttgart.citydoctor2.check.error.PointTouchesEdgeError;
import de.hft.stuttgart.citydoctor2.check.error.PolygonError;
import de.hft.stuttgart.citydoctor2.check.error.PolygonHoleOutsideError;
import de.hft.stuttgart.citydoctor2.check.error.PolygonInteriorDisconnectedError;
import de.hft.stuttgart.citydoctor2.check.error.PolygonIntersectingRingsError;
import de.hft.stuttgart.citydoctor2.check.error.PolygonSameOrientationError;
import de.hft.stuttgart.citydoctor2.check.error.PolygonWithoutSurfaceError;
import de.hft.stuttgart.citydoctor2.check.error.PolygonWrongOrientationError;
import de.hft.stuttgart.citydoctor2.check.error.RingDuplicatePointError;
import de.hft.stuttgart.citydoctor2.check.error.RingEdgeIntersectionError;
import de.hft.stuttgart.citydoctor2.check.error.RingError;
import de.hft.stuttgart.citydoctor2.check.error.RingNotClosedError;
import de.hft.stuttgart.citydoctor2.check.error.RingSelfIntersectionError;
import de.hft.stuttgart.citydoctor2.check.error.RingTooFewPointsError;
import de.hft.stuttgart.citydoctor2.check.error.SchematronError;
import de.hft.stuttgart.citydoctor2.check.error.SolidError;
import de.hft.stuttgart.citydoctor2.check.error.SolidNotClosedError;
import de.hft.stuttgart.citydoctor2.check.error.SolidSelfIntError;
import de.hft.stuttgart.citydoctor2.check.error.SurfaceUnfragmentedError;
import de.hft.stuttgart.citydoctor2.check.error.TooFewPolygonsError;
import de.hft.stuttgart.citydoctor2.check.error.UnknownCheckError;
public class GlobalErrorVisitor implements ErrorVisitor {
private MainWindow mainWindow;
public GlobalErrorVisitor(MainWindow mainWindow) {
this.mainWindow = mainWindow;
}
@Override
public void visit(RingError err) {
}
@Override
public void visit(PolygonError err) {
}
@Override
public void visit(RingSelfIntersectionError err) {
}
@Override
public void visit(PlanarityError err) {
}
@Override
public void visit(PolygonHoleOutsideError err) {
}
@Override
public void visit(NonManifoldEdgeError err) {
}
@Override
public void visit(MultipleConnectedComponentsError err) {
}
@Override
public void visit(NestedRingError err) {
}
@Override
public void visit(NonManifoldVertexError err) {
}
@Override
public void visit(PolygonWrongOrientationError err) {
}
@Override
public void visit(PolygonSameOrientationError err) {
}
@Override
public void visit(SolidNotClosedError err) {
}
@Override
public void visit(DependenciesNotMetError err) {
}
@Override
public void visit(UnknownCheckError err) {
}
@Override
public void visit(RingNotClosedError err) {
}
@Override
public void visit(ConsecutivePointSameError err) {
}
@Override
public void visit(AllPolygonsWrongOrientationError err) {
}
@Override
public void visit(PolygonInteriorDisconnectedError err) {
}
@Override
public void visit(NullAreaError err) {
}
@Override
public void visit(RingTooFewPointsError err) {
}
@Override
public void visit(NonPlanarPolygonNormalsDeviation err) {
}
@Override
public void visit(NonPlanarPolygonDistancePlaneError err) {
}
@Override
public void visit(PolygonIntersectingRingsError err) {
}
@Override
public void visit(SolidSelfIntError err) {
}
@Override
public void visit(TooFewPolygonsError err) {
}
@Override
public void visit(RingDuplicatePointError err) {
}
@Override
public void visit(RingEdgeIntersectionError err) {
}
@Override
public void visit(PointTouchesEdgeError err) {
}
@Override
public void visit(NotCeilingError err) {
}
@Override
public void visit(NotFloorError err) {
}
@Override
public void visit(NotWallError err) {
}
@Override
public void visit(NotGroundError err) {
}
@Override
public void visit(SchematronError se) {
mainWindow.getGlobalErrorsView().getItems().add(se.getErrorIdString() + " - " + se.getNameOfAttribute());
}
@Override
public void visit(SurfaceUnfragmentedError err) {
}
@Override
public void visit(DegeneratedRingError err) {
}
@Override
public void visit(AttributeMissingError err) {
mainWindow.getGlobalErrorsView().getItems().add(err.getErrorId().getIdString()
+ " - " + err.getNameOfAttribute());
}
@Override
public void visit(AttributeValueWrongError err) {
mainWindow.getGlobalErrorsView().getItems().add(err.getErrorId().getIdString()
+ " - " + err.getNameOfAttribute());
}
@Override
public void visit(AttributeInvalidError err) {
mainWindow.getGlobalErrorsView().getItems().add(err.getErrorId().getIdString()
+ " - " + err.getNameOfAttribute());
}
@Override
public void visit(PolygonWithoutSurfaceError err) {
}
@Override
public void visit(CheckError err) {
}
@Override
public void visit(SolidError err) {
}
}
......@@ -538,60 +538,45 @@ public class HealerController {
}
public void injectSolid(boolean useBs, boolean useBi, boolean useLod2, boolean useLod3, boolean useLod4) {
if (model == null || currentFeature == null) {
return;
}
CityObject oldFeature = currentFeature;
currentFeature.prepareForChecking();
if (currentFeature instanceof BoundarySurface) {
BoundarySurface surface = (BoundarySurface) currentFeature;
currentFeature = surface.getParent();
}
if (!(currentFeature instanceof Building)) {
return;
}
// collect polygons
Map<Lod, List<Polygon>> availablePolygons = new EnumMap<>(Lod.class);
Map<Lod, Set<Polygon>> existingPolygons = new EnumMap<>(Lod.class);
Building b = (Building) currentFeature;
collectPolygons(useBs, useBi, availablePolygons, existingPolygons, b);
if (useLod2) {
insertSolidGeometry(availablePolygons, b, existingPolygons, Lod.LOD2);
}
if (useLod3) {
insertSolidGeometry(availablePolygons, b, existingPolygons, Lod.LOD3);
}
if (useLod4) {
insertSolidGeometry(availablePolygons, b, existingPolygons, Lod.LOD4);
// if (model == null || currentFeature == null) {
// return;
// }
for (Building b : model.getBuildings()) {
// collect polygons
Map<Lod, List<Polygon>> availablePolygons = new EnumMap<>(Lod.class);
Map<Lod, Set<Polygon>> existingPolygons = new EnumMap<>(Lod.class);
collectPolygons(useBs, useBi, availablePolygons, existingPolygons, b);
if (useLod2) {
insertSolidGeometry(availablePolygons, b, existingPolygons, Lod.LOD2);
}
if (useLod3) {
insertSolidGeometry(availablePolygons, b, existingPolygons, Lod.LOD3);
}
if (useLod4) {
insertSolidGeometry(availablePolygons, b, existingPolygons, Lod.LOD4);
}
for (BuildingPart part : b.getBuildingParts()) {
// collect polygons
availablePolygons = new EnumMap<>(Lod.class);
existingPolygons = new EnumMap<>(Lod.class);
collectPolygons(useBs, useBi, availablePolygons, existingPolygons, part);
if (useLod2) {
insertSolidGeometry(availablePolygons, part, existingPolygons, Lod.LOD2);
}
if (useLod3) {
insertSolidGeometry(availablePolygons, part, existingPolygons, Lod.LOD3);
}
if (useLod4) {
insertSolidGeometry(availablePolygons, part, existingPolygons, Lod.LOD4);
}
}
}
nextFeature = null;
nextGeometry = null;
Lod lod = currentGeometry.getLod();
GeometryType type = GeometryType.SOLID;
currentGeometry = Objects.requireNonNull(currentFeature.getGeometry(type, lod));
checker.executeChecksForCheckable(currentFeature);
healerView.getNextErrorList().getItems().clear();
healerView.getNextMeshGroup().getChildren().clear();
updateCurrentErrors();
currentTriangulatedGeometry = TriangulatedGeometry.of(currentGeometry);
currentErrorVisitor.setGeometry(currentTriangulatedGeometry);
currentTriangulatedGeometry.setCullFace(culling);
currentTriangulatedGeometry.setDrawMode(drawMode);
healerView.zoomOutForBoundingBox(currentGeometry.calculateBoundingBox());
healerView.getCurrentMeshGroup().getChildren().clear();
healerView.getCurrentMeshGroup().getChildren().addAll(currentTriangulatedGeometry.getMeshes());
healerView.getNextStepBtn().setDisable(false);
healerView.getHealCompleteBtn().setDisable(false);
healerView.getAcceptBtn().setDisable(true);
healerView.getCancelBtn().setDisable(true);
healerView.getSolidInjectorBtn().setDisable(true);
currentFeature = oldFeature;
}
private void collectPolygons(boolean useBs, boolean useBi, Map<Lod, List<Polygon>> availablePolygons,
Map<Lod, Set<Polygon>> existingPolygons, Building b) {
Map<Lod, Set<Polygon>> existingPolygons, AbstractBuilding b) {
if (useBs) {
collectPolygons(availablePolygons, b.getBoundarySurfaces());
}
......@@ -604,13 +589,13 @@ public class HealerController {
collectPolygons(availablePolygons, bi.getBoundarySurfaces());
}
}
for (Geometry geom : b.getGeometries()) {
Set<Polygon> polygons = existingPolygons.computeIfAbsent(geom.getLod(), l -> new HashSet<>());
polygons.addAll(geom.getPolygons());
}
// for (Geometry geom : b.getGeometries()) {
// Set<Polygon> polygons = existingPolygons.computeIfAbsent(geom.getLod(), l -> new HashSet<>());
// polygons.addAll(geom.getPolygons());
// }
}
private void insertSolidGeometry(Map<Lod, List<Polygon>> availablePolygons, Building b,
private void insertSolidGeometry(Map<Lod, List<Polygon>> availablePolygons, AbstractBuilding b,
Map<Lod, Set<Polygon>> existingPolygons, Lod lod) {
List<Polygon> newPolygons = availablePolygons.get(lod);
if (newPolygons != null) {
......
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