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 { ...@@ -59,6 +59,7 @@ public class SchematronError implements CheckError {
@Override @Override
public void report(ErrorReport report) { public void report(ErrorReport report) {
report.add("errorId", errorId); report.add("errorId", errorId);
report.add("message", nameOfAttribute);
} }
@Override @Override
......
...@@ -61,15 +61,11 @@ public class BridgeObject extends CityObject { ...@@ -61,15 +61,11 @@ public class BridgeObject extends CityObject {
private BridgeObject parent; private BridgeObject parent;
public BridgeObject(AbstractBridge ab) { public BridgeObject(AbstractBridge ab) {
this.ab = ab; this(BridgeType.BRIDGE, ab, null);
this.type = BridgeType.BRIDGE;
this.parent = null;
} }
public BridgeObject(AbstractBridge ab, BridgeObject parent) { public BridgeObject(AbstractBridge ab, BridgeObject parent) {
this.ab = ab; this(BridgeType.BRIDGE_PART, ab, parent);
this.type = BridgeType.BRIDGE_PART;
this.parent = parent;
} }
private BridgeObject(BridgeType type, AbstractBridge ab, BridgeObject parent) { private BridgeObject(BridgeType type, AbstractBridge ab, BridgeObject parent) {
......
package de.hft.stuttgart.citydoctor2.datastructure; package de.hft.stuttgart.citydoctor2.datastructure;
import de.hft.stuttgart.citydoctor2.check.CheckableVisitor; import java.io.Serial;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; import java.util.ArrayList;
import de.hft.stuttgart.citydoctor2.utils.CityGmlUtils; import java.util.List;
import javafx.scene.paint.Color;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.citygml4j.core.model.core.AbstractSpaceBoundaryProperty; import org.citygml4j.core.model.core.AbstractSpaceBoundaryProperty;
import org.citygml4j.core.model.deprecated.bridge.DeprecatedPropertiesOfBridgeConstructiveElement;
import org.citygml4j.core.util.geometry.GeometryFactory; 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.MultiSurface;
import org.xmlobjects.gml.model.geometry.aggregates.MultiSurfaceProperty; 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.Solid;
import org.xmlobjects.gml.model.geometry.primitives.SolidProperty; import org.xmlobjects.gml.model.geometry.primitives.SolidProperty;
import org.xmlobjects.gml.model.geometry.primitives.SurfaceProperty;
import java.io.Serial; import de.hft.stuttgart.citydoctor2.check.CheckableVisitor;
import java.util.ArrayList; import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import java.util.List; import de.hft.stuttgart.citydoctor2.utils.CityGmlUtils;
import javafx.scene.paint.Color;
public class BuildingConstructiveElement extends CityObject { public class BuildingConstructiveElement extends CityObject {
......
...@@ -47,10 +47,6 @@ public class Opening extends CityObject { ...@@ -47,10 +47,6 @@ public class Opening extends CityObject {
private AbstractFillingSurface ao; private AbstractFillingSurface ao;
private Opening(OpeningType type) {
this.type = type;
}
public Opening(OpeningType type, BoundarySurface partOf, public Opening(OpeningType type, BoundarySurface partOf,
AbstractFillingSurface ao) { AbstractFillingSurface ao) {
this.partOf = partOf; this.partOf = partOf;
......
...@@ -9,6 +9,8 @@ public class TunnelPart extends AbstractTunnel { ...@@ -9,6 +9,8 @@ public class TunnelPart extends AbstractTunnel {
private Tunnel parent; private Tunnel parent;
private TunnelPart() {
}
public TunnelPart(Tunnel parent) { public TunnelPart(Tunnel parent) {
this.parent = parent; this.parent = parent;
...@@ -34,6 +36,4 @@ public class TunnelPart extends AbstractTunnel { ...@@ -34,6 +36,4 @@ public class TunnelPart extends AbstractTunnel {
return "TunnelPart [id=" + getGmlId() + "]"; return "TunnelPart [id=" + getGmlId() + "]";
} }
private TunnelPart() {
}
} }
...@@ -89,6 +89,11 @@ public class Triangle3d implements Serializable { ...@@ -89,6 +89,11 @@ public class Triangle3d implements Serializable {
} }
public boolean doesIntersect(Triangle3d other) { public boolean doesIntersect(Triangle3d other) {
return doesIntersect(other, EPSILON);
}
public boolean doesIntersect(Triangle3d other, double epsilon) {
// plane of other triangle // plane of other triangle
Plane planeT2 = other.getPlane(); Plane planeT2 = other.getPlane();
// check if all points are on one side of the plane // check if all points are on one side of the plane
...@@ -96,13 +101,13 @@ public class Triangle3d implements Serializable { ...@@ -96,13 +101,13 @@ public class Triangle3d implements Serializable {
double distanceP2T2 = planeT2.getSignedDistance(p2); double distanceP2T2 = planeT2.getSignedDistance(p2);
double distanceP3T2 = planeT2.getSignedDistance(p3); double distanceP3T2 = planeT2.getSignedDistance(p3);
if (Math.abs(distanceP1T2) < EPSILON) { if (Math.abs(distanceP1T2) < epsilon) {
distanceP1T2 = 0.0; distanceP1T2 = 0.0;
} }
if (Math.abs(distanceP2T2) < EPSILON) { if (Math.abs(distanceP2T2) < epsilon) {
distanceP2T2 = 0.0; distanceP2T2 = 0.0;
} }
if (Math.abs(distanceP3T2) < EPSILON) { if (Math.abs(distanceP3T2) < epsilon) {
distanceP3T2 = 0.0; distanceP3T2 = 0.0;
} }
...@@ -123,13 +128,13 @@ public class Triangle3d implements Serializable { ...@@ -123,13 +128,13 @@ public class Triangle3d implements Serializable {
double distanceP2T1 = planeT1.getSignedDistance(other.getP2()); double distanceP2T1 = planeT1.getSignedDistance(other.getP2());
double distanceP3T1 = planeT1.getSignedDistance(other.getP3()); double distanceP3T1 = planeT1.getSignedDistance(other.getP3());
if (Math.abs(distanceP1T1) < EPSILON) { if (Math.abs(distanceP1T1) < epsilon) {
distanceP1T1 = 0.0; distanceP1T1 = 0.0;
} }
if (Math.abs(distanceP2T1) < EPSILON) { if (Math.abs(distanceP2T1) < epsilon) {
distanceP2T1 = 0.0; distanceP2T1 = 0.0;
} }
if (Math.abs(distanceP3T1) < EPSILON) { if (Math.abs(distanceP3T1) < epsilon) {
distanceP3T1 = 0.0; distanceP3T1 = 0.0;
} }
...@@ -139,11 +144,15 @@ public class Triangle3d implements Serializable { ...@@ -139,11 +144,15 @@ public class Triangle3d implements Serializable {
return false; 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(other, p2, p3)
|| checkTriangleLineIntersection(this, other.p1, other.p2) || checkTriangleLineIntersection(this, other.p1, other.p2)
|| checkTriangleLineIntersection(this, other.p1, other.p3) || checkTriangleLineIntersection(this, other.p1, other.p3)
|| checkTriangleLineIntersection(this, other.p2, other.p3); || checkTriangleLineIntersection(this, other.p2, other.p3);
if (intersects) {
System.out.println();
}
return intersects;
} }
private boolean checkTriangleLineIntersection(Triangle3d other, Vector3d a, Vector3d b) { private boolean checkTriangleLineIntersection(Triangle3d other, Vector3d a, Vector3d b) {
...@@ -171,7 +180,11 @@ public class Triangle3d implements Serializable { ...@@ -171,7 +180,11 @@ public class Triangle3d implements Serializable {
private boolean doesIntersectCoplanarTriangle(Triangle3d other) { private boolean doesIntersectCoplanarTriangle(Triangle3d other) {
Triangle2d t1 = projectTo2d(); Triangle2d t1 = projectTo2d();
Triangle2d t2 = other.projectTo2d(); Triangle2d t2 = other.projectTo2d();
return t1.intersects(t2); boolean intersects = t1.intersects(t2);
if (intersects) {
System.out.println();
}
return intersects;
} }
public Triangle2d projectTo2d() { public Triangle2d projectTo2d() {
......
...@@ -49,6 +49,15 @@ public class EarcutTesselator { ...@@ -49,6 +49,15 @@ public class EarcutTesselator {
start = addRingToArray(innerRing, vertices, start, axis); 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 // triangulation
List<Integer> indices = Earcut.earcut(vertices, holeStart, 2); List<Integer> indices = Earcut.earcut(vertices, holeStart, 2);
List<Triangle3d> triangles = new ArrayList<>(); List<Triangle3d> triangles = new ArrayList<>();
...@@ -56,9 +65,10 @@ public class EarcutTesselator { ...@@ -56,9 +65,10 @@ public class EarcutTesselator {
throw new IllegalStateException(); throw new IllegalStateException();
} }
for (int i = 0; i < indices.size(); i = i + 3) { for (int i = 0; i < indices.size(); i = i + 3) {
Triangle3d t = new Triangle3d(vertexObjects.get(indices.get(i + 0)), Vertex v1 = vertexObjects.get(indices.get(i + 0));
vertexObjects.get(indices.get(i + 1)), Vertex v2 = vertexObjects.get(indices.get(i + 1));
vertexObjects.get(indices.get(i + 2))); Vertex v3 = vertexObjects.get(indices.get(i + 2));
Triangle3d t = new Triangle3d(v1, v2, v3);
triangles.add(t); triangles.add(t);
} }
return new TesselatedPolygon(triangles, p); return new TesselatedPolygon(triangles, p);
......
...@@ -29,11 +29,13 @@ import de.hft.stuttgart.citydoctor2.checks.Checks; ...@@ -29,11 +29,13 @@ import de.hft.stuttgart.citydoctor2.checks.Checks;
import de.hft.stuttgart.citydoctor2.checks.SvrlContentHandler; import de.hft.stuttgart.citydoctor2.checks.SvrlContentHandler;
import de.hft.stuttgart.citydoctor2.checks.util.FeatureCheckedListener; import de.hft.stuttgart.citydoctor2.checks.util.FeatureCheckedListener;
import de.hft.stuttgart.citydoctor2.database.CityObjectCache; 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.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject; import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.datastructure.FeatureType; import de.hft.stuttgart.citydoctor2.datastructure.FeatureType;
import de.hft.stuttgart.citydoctor2.datastructure.GmlId; import de.hft.stuttgart.citydoctor2.datastructure.GmlId;
import de.hft.stuttgart.citydoctor2.datastructure.ImplicitGeometryHolder; 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.CityGmlConsumer;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException; import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParser; import de.hft.stuttgart.citydoctor2.parser.CityGmlParser;
...@@ -231,25 +233,54 @@ public class Checker { ...@@ -231,25 +233,54 @@ public class Checker {
} }
private void handleSchematronResults(SvrlContentHandler handler) { private void handleSchematronResults(SvrlContentHandler handler) {
model.addGlobalErrors(handler.getGeneralErrors());
CityObjectCache cache = model.getCache(); CityObjectCache cache = model.getCache();
handler.getFeatureErrors().forEach((k, v) -> { handleSchematronErrorsGlobal(handler.getGeneralErrors());
if (k.trim().isEmpty()) { Map<String, CityObject> featureMap = new HashMap<>();
// missing gml id, ignore? boolean onlySchematron = execLayers.isEmpty();
return; 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) -> {
String trimmedId = k.trim();
CityObject co = cache.get(new GmlId(k)); CityObject co = cache.get(new GmlId(k));
if (co == null) { if (co == null) {
// gml id reported by schematron was not found, add to general errors // gml id reported by schematron was not found, add to general errors
for (SchematronError se : v) { handleSchematronErrorsGlobal(v);
model.addGlobalError(se);
}
} else { } else {
handleSchematronErrorsForCityObject(v, co); 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) { public static void handleSchematronErrorsForCityObject(List<SchematronError> v, CityObject co) {
int count = 0; int count = 0;
for (SchematronError se : v) { for (SchematronError se : v) {
...@@ -462,7 +493,6 @@ public class Checker { ...@@ -462,7 +493,6 @@ public class Checker {
} }
} }
@SuppressWarnings("resource")
public static SvrlContentHandler executeSchematronValidationIfAvailable(ValidationConfiguration config, public static SvrlContentHandler executeSchematronValidationIfAvailable(ValidationConfiguration config,
InputStream in) { InputStream in) {
if (config.getSchematronFilePath() != null && !config.getSchematronFilePath().isEmpty()) { if (config.getSchematronFilePath() != null && !config.getSchematronFilePath().isEmpty()) {
......
...@@ -106,12 +106,12 @@ public class SvrlContentHandler implements ContentHandler { ...@@ -106,12 +106,12 @@ public class SvrlContentHandler implements ContentHandler {
throw new IllegalStateException( throw new IllegalStateException(
"Schematron File is not formed according to specification for CityDoctor."); "Schematron File is not formed according to specification for CityDoctor.");
} }
String gmlId = split[0]; String gmlId = split[0].strip();
String childId = split[1]; String childId = split[1];
String errorId = split[2]; String errorId = split[2];
String nameOfAttribute = split[3]; String nameOfAttribute = split[3];
SchematronError err = new SchematronError(errorId, gmlId, childId, nameOfAttribute); SchematronError err = new SchematronError(errorId, gmlId, childId, nameOfAttribute);
if (gmlId == null || gmlId.isEmpty()) { if (gmlId == null || gmlId.isBlank()) {
// general error // general error
generalErrors.add(err); generalErrors.add(err);
} else { } else {
......
...@@ -57,10 +57,12 @@ import de.hft.stuttgart.citydoctor2.tesselation.TesselatedPolygon; ...@@ -57,10 +57,12 @@ import de.hft.stuttgart.citydoctor2.tesselation.TesselatedPolygon;
*/ */
public class PlanarCheck extends Check { public class PlanarCheck extends Check {
private static final String DISTANCE = "distance"; public static final String ANGLE = "angle";
private static final String DISTANCE_TOLERANCE = "distanceTolerance"; 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 ANGLE_TOLERANCE = "angleTolerance";
private static final String TYPE = "type"; public static final String TYPE = "type";
private static final List<CheckId> dependencies; private static final List<CheckId> dependencies;
...@@ -97,7 +99,7 @@ public class PlanarCheck extends Check { ...@@ -97,7 +99,7 @@ public class PlanarCheck extends Check {
public void check(Polygon p) { public void check(Polygon p) {
if (DISTANCE.equals(planarCheckType)) { if (DISTANCE.equals(planarCheckType)) {
planarDistance(p); planarDistance(p);
} else if ("angle".equals(planarCheckType)) { } else if (ANGLE.equals(planarCheckType)) {
planarNormalDeviation(p); planarNormalDeviation(p);
} else if ("both".equals(planarCheckType)) { } else if ("both".equals(planarCheckType)) {
planarDistance(p); planarDistance(p);
......
...@@ -21,13 +21,13 @@ package de.hft.stuttgart.citydoctor2.checks.geometry; ...@@ -21,13 +21,13 @@ package de.hft.stuttgart.citydoctor2.checks.geometry;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import de.hft.stuttgart.citydoctor2.check.Check; import de.hft.stuttgart.citydoctor2.check.Check;
import de.hft.stuttgart.citydoctor2.check.CheckError; import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.CheckId; import de.hft.stuttgart.citydoctor2.check.CheckId;
import de.hft.stuttgart.citydoctor2.check.CheckResult; 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.Requirement;
import de.hft.stuttgart.citydoctor2.check.RequirementType; import de.hft.stuttgart.citydoctor2.check.RequirementType;
import de.hft.stuttgart.citydoctor2.check.ResultStatus; import de.hft.stuttgart.citydoctor2.check.ResultStatus;
...@@ -36,6 +36,7 @@ import de.hft.stuttgart.citydoctor2.checks.util.CollectionUtils; ...@@ -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.checks.util.SelfIntersectionUtil;
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;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.utils.PolygonIntersection; import de.hft.stuttgart.citydoctor2.utils.PolygonIntersection;
/** /**
...@@ -48,6 +49,8 @@ public class SolidSelfIntCheck extends Check { ...@@ -48,6 +49,8 @@ public class SolidSelfIntCheck extends Check {
private static final List<CheckId> dependencies; private static final List<CheckId> dependencies;
private double delta = 0.01;
static { static {
ArrayList<CheckId> deps = new ArrayList<>(); ArrayList<CheckId> deps = new ArrayList<>();
dependencies = Collections.unmodifiableList(deps); dependencies = Collections.unmodifiableList(deps);
...@@ -69,13 +72,20 @@ public class SolidSelfIntCheck extends Check { ...@@ -69,13 +72,20 @@ public class SolidSelfIntCheck extends Check {
deps.add(CheckId.C_GE_S_POLYGON_WRONG_ORIENTATION); 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 @Override
public void check(Geometry g) { public void check(Geometry g) {
if (g.getType() != GeometryType.SOLID && g.getType() != GeometryType.COMPOSITE_SURFACE) { if (g.getType() != GeometryType.SOLID && g.getType() != GeometryType.COMPOSITE_SURFACE) {
return; return;
} }
CheckResult cr; CheckResult cr;
List<PolygonIntersection> intersections = SelfIntersectionUtil.calculateSolidSelfIntersection(g); List<PolygonIntersection> intersections = SelfIntersectionUtil.calculateSolidSelfIntersection(g, delta);
if (intersections.isEmpty()) { if (intersections.isEmpty()) {
cr = new CheckResult(this, ResultStatus.OK, null); cr = new CheckResult(this, ResultStatus.OK, null);
} else { } else {
...@@ -85,18 +95,6 @@ public class SolidSelfIntCheck extends Check { ...@@ -85,18 +95,6 @@ public class SolidSelfIntCheck extends Check {
g.addCheckResult(cr); 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 @Override
public List<CheckId> getDependencies() { public List<CheckId> getDependencies() {
return dependencies; return dependencies;
......
...@@ -21,6 +21,7 @@ package de.hft.stuttgart.citydoctor2.checks.util; ...@@ -21,6 +21,7 @@ package de.hft.stuttgart.citydoctor2.checks.util;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.IdentityHashMap; import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
...@@ -39,6 +40,8 @@ import org.locationtech.jts.geom.impl.CoordinateArraySequence; ...@@ -39,6 +40,8 @@ import org.locationtech.jts.geom.impl.CoordinateArraySequence;
import org.locationtech.jts.operation.overlay.OverlayOp; import org.locationtech.jts.operation.overlay.OverlayOp;
import org.locationtech.jts.operation.overlay.snap.SnapIfNeededOverlayOp; 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.check.GeometrySelfIntersection;
import de.hft.stuttgart.citydoctor2.datastructure.ConcretePolygon; import de.hft.stuttgart.citydoctor2.datastructure.ConcretePolygon;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry; import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
...@@ -50,8 +53,10 @@ import de.hft.stuttgart.citydoctor2.edge.EdgePolygon; ...@@ -50,8 +53,10 @@ import de.hft.stuttgart.citydoctor2.edge.EdgePolygon;
import de.hft.stuttgart.citydoctor2.edge.IntersectPlanarPolygons; import de.hft.stuttgart.citydoctor2.edge.IntersectPlanarPolygons;
import de.hft.stuttgart.citydoctor2.edge.MeshSurface; import de.hft.stuttgart.citydoctor2.edge.MeshSurface;
import de.hft.stuttgart.citydoctor2.edge.PolygonPolygonIntersection; 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.MovedPolygon;
import de.hft.stuttgart.citydoctor2.math.MovedRing; 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.Plane;
import de.hft.stuttgart.citydoctor2.math.PlaneSegmentIntersection; import de.hft.stuttgart.citydoctor2.math.PlaneSegmentIntersection;
import de.hft.stuttgart.citydoctor2.math.PlaneSegmentIntersection.Type; import de.hft.stuttgart.citydoctor2.math.PlaneSegmentIntersection.Type;
...@@ -84,17 +89,36 @@ public class SelfIntersectionUtil { ...@@ -84,17 +89,36 @@ public class SelfIntersectionUtil {
} }
public static List<PolygonIntersection> calculateSolidSelfIntersection(Geometry g) { public static List<PolygonIntersection> calculateSolidSelfIntersection(Geometry g, double delta) {
List<TesselatedPolygon> tesselatedPolygons = new ArrayList<>(); List<TesselatedPolygon> tesselatedPolygons = new ArrayList<>();
for (Polygon p : g.getPolygons()) { 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<>(); List<PolygonIntersection> intersections = new ArrayList<>();
for (int i = 0; i < tesselatedPolygons.size() - 1; i++) { for (int i = 0; i < tesselatedPolygons.size() - 1; i++) {
TesselatedPolygon p1 = tesselatedPolygons.get(i); TesselatedPolygon p1 = tesselatedPolygons.get(i);
for (int j = i + 1; j < tesselatedPolygons.size(); j++) { for (int j = i + 1; j < tesselatedPolygons.size(); j++) {
TesselatedPolygon p2 = tesselatedPolygons.get(j); TesselatedPolygon p2 = tesselatedPolygons.get(j);
GeometrySelfIntersection intersection = doPolygonsIntersect(p1, p2); GeometrySelfIntersection intersection = doPolygonsIntersect(p1, p2, delta);
if (intersection != null) { if (intersection != null) {
intersections.add(PolygonIntersection.triangles(intersection.t1(), intersection.t2())); intersections.add(PolygonIntersection.triangles(intersection.t1(), intersection.t2()));
} }
...@@ -103,8 +127,8 @@ public class SelfIntersectionUtil { ...@@ -103,8 +127,8 @@ public class SelfIntersectionUtil {
return intersections; return intersections;
} }
public static GeometrySelfIntersection doesSolidSelfIntersect(Geometry g) { public static GeometrySelfIntersection doesSolidSelfIntersect(Geometry g, double epsilon) {
return selfIntersectionJava(g); return selfIntersectionJava(g, epsilon);
} }
public static List<PolygonIntersection> doesSolidSelfIntersect2(Geometry g) { public static List<PolygonIntersection> doesSolidSelfIntersect2(Geometry g) {
...@@ -404,7 +428,7 @@ public class SelfIntersectionUtil { ...@@ -404,7 +428,7 @@ public class SelfIntersectionUtil {
return sign != 0; return sign != 0;
} }
private static GeometrySelfIntersection selfIntersectionJava(Geometry g) { private static GeometrySelfIntersection selfIntersectionJava(Geometry g, double epsilon) {
List<TesselatedPolygon> tessPolys = new ArrayList<>(); List<TesselatedPolygon> tessPolys = new ArrayList<>();
for (Polygon p : g.getPolygons()) { for (Polygon p : g.getPolygons()) {
tessPolys.add(JoglTesselator.tesselatePolygon(p)); tessPolys.add(JoglTesselator.tesselatePolygon(p));
...@@ -413,7 +437,7 @@ public class SelfIntersectionUtil { ...@@ -413,7 +437,7 @@ public class SelfIntersectionUtil {
TesselatedPolygon p1 = tessPolys.get(i); TesselatedPolygon p1 = tessPolys.get(i);
for (int j = i + 1; j < tessPolys.size(); j++) { for (int j = i + 1; j < tessPolys.size(); j++) {
TesselatedPolygon p2 = tessPolys.get(j); TesselatedPolygon p2 = tessPolys.get(j);
GeometrySelfIntersection intersection = doPolygonsIntersect(p1, p2); GeometrySelfIntersection intersection = doPolygonsIntersect(p1, p2, epsilon);
if (intersection != null) { if (intersection != null) {
return intersection; return intersection;
} }
...@@ -422,12 +446,12 @@ public class SelfIntersectionUtil { ...@@ -422,12 +446,12 @@ public class SelfIntersectionUtil {
return null; 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 p1Index = 0; p1Index < p1.getTriangles().size(); p1Index++) {
for (int p2Index = 0; p2Index < p2.getTriangles().size(); p2Index++) { for (int p2Index = 0; p2Index < p2.getTriangles().size(); p2Index++) {
Triangle3d t1 = p1.getTriangles().get(p1Index); Triangle3d t1 = p1.getTriangles().get(p1Index);
Triangle3d t2 = p2.getTriangles().get(p2Index); Triangle3d t2 = p2.getTriangles().get(p2Index);
if (t1.doesIntersect(t2)) { if (t1.doesIntersect(t2, epsilon)) {
logger.trace("{} intersects {}", t1, t2); logger.trace("{} intersects {}", t1, t2);
logger.trace("GML-ID: {} intersects {}", t1.getPartOf().getOriginal().getGmlId(), logger.trace("GML-ID: {} intersects {}", t1.getPartOf().getOriginal().getGmlId(),
t2.getPartOf().getOriginal().getGmlId()); t2.getPartOf().getOriginal().getGmlId());
......
...@@ -25,14 +25,18 @@ import static org.junit.Assert.assertNotNull; ...@@ -25,14 +25,18 @@ import static org.junit.Assert.assertNotNull;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import de.hft.stuttgart.citydoctor2.check.CheckId;
import de.hft.stuttgart.citydoctor2.check.CheckResult; import de.hft.stuttgart.citydoctor2.check.CheckResult;
import de.hft.stuttgart.citydoctor2.check.Checker; import de.hft.stuttgart.citydoctor2.check.Checker;
import de.hft.stuttgart.citydoctor2.check.ResultStatus; import de.hft.stuttgart.citydoctor2.check.ResultStatus;
import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration; 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.checks.util.GeometryTestUtils;
import de.hft.stuttgart.citydoctor2.datastructure.Building; import de.hft.stuttgart.citydoctor2.datastructure.Building;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel; import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.datastructure.ConcretePolygon;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry; 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.GeometryType;
import de.hft.stuttgart.citydoctor2.datastructure.Lod; import de.hft.stuttgart.citydoctor2.datastructure.Lod;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException; import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
...@@ -46,6 +50,22 @@ import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException; ...@@ -46,6 +50,22 @@ import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException;
*/ */
public class SolidSelfIntCheckTest { 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 @Test
public void testGoodGeometry() { public void testGoodGeometry() {
SolidSelfIntCheck check = new SolidSelfIntCheck(); SolidSelfIntCheck check = new SolidSelfIntCheck();
......
...@@ -31,6 +31,7 @@ import de.hft.stuttgart.citydoctor2.check.CheckResult; ...@@ -31,6 +31,7 @@ import de.hft.stuttgart.citydoctor2.check.CheckResult;
import de.hft.stuttgart.citydoctor2.check.Checker; import de.hft.stuttgart.citydoctor2.check.Checker;
import de.hft.stuttgart.citydoctor2.check.ErrorId; import de.hft.stuttgart.citydoctor2.check.ErrorId;
import de.hft.stuttgart.citydoctor2.check.ResultStatus; 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.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon; import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException; import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
...@@ -142,7 +143,7 @@ public class PlanarTest { ...@@ -142,7 +143,7 @@ public class PlanarTest {
public void testPlanarPolygon6() throws CityGmlParseException, IOException, InvalidGmlFileException { public void testPlanarPolygon6() throws CityGmlParseException, IOException, InvalidGmlFileException {
Map<String, Map<String, String>> paramMap = new HashMap<>(); Map<String, Map<String, String>> paramMap = new HashMap<>();
Map<String, String> parameter = new HashMap<>(); Map<String, String> parameter = new HashMap<>();
parameter.put("type", "both"); parameter.put(PlanarCheck.TYPE, PlanarCheck.BOTH);
parameter.put("distanceTolerance", "0.5"); parameter.put("distanceTolerance", "0.5");
paramMap.put(RequirementId.R_GE_P_NON_PLANAR.toString(), parameter); 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); CityDoctorModel c = TestUtil.loadAndCheckCityModel("src/test/resources/SimpleSolid_SrefBS-GE-gml-PO-0002-T0002.gml", paramMap);
......
#!/bin/sh #! /usr/bin/env sh
./runtime/bin/java -classpath app/*:plugin/* de.hft.stuttgart.citydoctor2.gui.CityDoctorGUIStarter java -classpath "app/*:plugin/*" de.hft.stuttgart.citydoctor2.gui.CityDoctorGUIStarter
\ No newline at end of file
...@@ -18,6 +18,7 @@ import de.hft.stuttgart.citydoctor2.gui.tree.node.TopLevelCityObjectNode; ...@@ -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.mapper.citygml3.GMLValidationHandler;
import de.hft.stuttgart.citydoctor2.parser.*; import de.hft.stuttgart.citydoctor2.parser.*;
import de.hft.stuttgart.citydoctor2.utils.Localization; import de.hft.stuttgart.citydoctor2.utils.Localization;
import de.hft.stuttgart.quality.adapter.types.ErrorAdapter;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.scene.chart.XYChart.Data; import javafx.scene.chart.XYChart.Data;
import javafx.scene.chart.XYChart.Series; import javafx.scene.chart.XYChart.Series;
...@@ -1084,11 +1085,7 @@ public class CityDoctorController { ...@@ -1084,11 +1085,7 @@ public class CityDoctorController {
buildTrees(); buildTrees();
updateFeatureTrees(); updateFeatureTrees();
updateTree(mainWindow.getPolygonsView().getRoot()); updateTree(mainWindow.getPolygonsView().getRoot());
for (CheckError e : model.getGlobalErrors()) { updateGlobalErrors();
if (e instanceof SchematronError se) {
mainWindow.getGlobalErrorsView().getItems().add(se.getErrorIdString() + " - " + se.getNameOfAttribute());
}
}
renderer.refresh(); renderer.refresh();
mainWindow.getWriteReportButton().setDisable(false); mainWindow.getWriteReportButton().setDisable(false);
}); });
...@@ -1097,6 +1094,13 @@ public class CityDoctorController { ...@@ -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() { void updateFeatureTrees() {
updateTree(mainWindow.getBuildingsView().getRoot()); updateTree(mainWindow.getBuildingsView().getRoot());
updateTree(mainWindow.getVegetationView().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,22 +538,14 @@ public class HealerController { ...@@ -538,22 +538,14 @@ public class HealerController {
} }
public void injectSolid(boolean useBs, boolean useBi, boolean useLod2, boolean useLod3, boolean useLod4) { public void injectSolid(boolean useBs, boolean useBi, boolean useLod2, boolean useLod3, boolean useLod4) {
if (model == null || currentFeature == null) { // if (model == null || currentFeature == null) {
return; // return;
} // }
CityObject oldFeature = currentFeature;
currentFeature.prepareForChecking(); for (Building b : model.getBuildings()) {
if (currentFeature instanceof BoundarySurface) {
BoundarySurface surface = (BoundarySurface) currentFeature;
currentFeature = surface.getParent();
}
if (!(currentFeature instanceof Building)) {
return;
}
// collect polygons // collect polygons
Map<Lod, List<Polygon>> availablePolygons = new EnumMap<>(Lod.class); Map<Lod, List<Polygon>> availablePolygons = new EnumMap<>(Lod.class);
Map<Lod, Set<Polygon>> existingPolygons = new EnumMap<>(Lod.class); Map<Lod, Set<Polygon>> existingPolygons = new EnumMap<>(Lod.class);
Building b = (Building) currentFeature;
collectPolygons(useBs, useBi, availablePolygons, existingPolygons, b); collectPolygons(useBs, useBi, availablePolygons, existingPolygons, b);
if (useLod2) { if (useLod2) {
insertSolidGeometry(availablePolygons, b, existingPolygons, Lod.LOD2); insertSolidGeometry(availablePolygons, b, existingPolygons, Lod.LOD2);
...@@ -564,34 +556,27 @@ public class HealerController { ...@@ -564,34 +556,27 @@ public class HealerController {
if (useLod4) { if (useLod4) {
insertSolidGeometry(availablePolygons, b, existingPolygons, Lod.LOD4); insertSolidGeometry(availablePolygons, b, existingPolygons, Lod.LOD4);
} }
nextFeature = null; for (BuildingPart part : b.getBuildingParts()) {
nextGeometry = null; // collect polygons
Lod lod = currentGeometry.getLod(); availablePolygons = new EnumMap<>(Lod.class);
GeometryType type = GeometryType.SOLID; existingPolygons = new EnumMap<>(Lod.class);
currentGeometry = Objects.requireNonNull(currentFeature.getGeometry(type, lod)); collectPolygons(useBs, useBi, availablePolygons, existingPolygons, part);
checker.executeChecksForCheckable(currentFeature); if (useLod2) {
healerView.getNextErrorList().getItems().clear(); insertSolidGeometry(availablePolygons, part, existingPolygons, Lod.LOD2);
healerView.getNextMeshGroup().getChildren().clear(); }
updateCurrentErrors(); if (useLod3) {
currentTriangulatedGeometry = TriangulatedGeometry.of(currentGeometry); insertSolidGeometry(availablePolygons, part, existingPolygons, Lod.LOD3);
currentErrorVisitor.setGeometry(currentTriangulatedGeometry); }
currentTriangulatedGeometry.setCullFace(culling); if (useLod4) {
currentTriangulatedGeometry.setDrawMode(drawMode); insertSolidGeometry(availablePolygons, part, existingPolygons, Lod.LOD4);
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, 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) { if (useBs) {
collectPolygons(availablePolygons, b.getBoundarySurfaces()); collectPolygons(availablePolygons, b.getBoundarySurfaces());
} }
...@@ -604,13 +589,13 @@ public class HealerController { ...@@ -604,13 +589,13 @@ public class HealerController {
collectPolygons(availablePolygons, bi.getBoundarySurfaces()); collectPolygons(availablePolygons, bi.getBoundarySurfaces());
} }
} }
for (Geometry geom : b.getGeometries()) { // for (Geometry geom : b.getGeometries()) {
Set<Polygon> polygons = existingPolygons.computeIfAbsent(geom.getLod(), l -> new HashSet<>()); // Set<Polygon> polygons = existingPolygons.computeIfAbsent(geom.getLod(), l -> new HashSet<>());
polygons.addAll(geom.getPolygons()); // 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) { Map<Lod, Set<Polygon>> existingPolygons, Lod lod) {
List<Polygon> newPolygons = availablePolygons.get(lod); List<Polygon> newPolygons = availablePolygons.get(lod);
if (newPolygons != null) { 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