Commit d3ca6500 authored by Matthias Betz's avatar Matthias Betz
Browse files

fix solid self intersection incorrectly ignoring degenerated triangles...

fix solid self intersection incorrectly ignoring degenerated triangles depending on planarity settings
parent 8536ec35
Pipeline #12318 passed with stage
in 2 minutes and 3 seconds
...@@ -345,7 +345,7 @@ public abstract non-sealed class Check implements CheckableVisitor { ...@@ -345,7 +345,7 @@ public abstract non-sealed class Check implements CheckableVisitor {
* @param config sometimes there are global parameters which can be used by * @param config sometimes there are global parameters which can be used by
* checks. Those are be stored in this container * checks. Those are be stored in this container
*/ */
public void init(Map<String, String> params, ParserConfiguration config) { public void init(Map<CheckId, Map<String, String>> params, ParserConfiguration config) {
} }
......
...@@ -34,8 +34,6 @@ public class Segment3d implements Serializable { ...@@ -34,8 +34,6 @@ public class Segment3d implements Serializable {
private static final double PRECISION = 0.00000001; private static final double PRECISION = 0.00000001;
private static final double EPSILON = 0.01;
private final Vector3d pointA; private final Vector3d pointA;
private final Vector3d pointB; private final Vector3d pointB;
...@@ -178,7 +176,7 @@ public class Segment3d implements Serializable { ...@@ -178,7 +176,7 @@ public class Segment3d implements Serializable {
return "Segment3d [pointA=" + pointA + ", pointB=" + pointB + "]"; return "Segment3d [pointA=" + pointA + ", pointB=" + pointB + "]";
} }
public Vector3d intersection(Triangle3d triangle) { public Vector3d intersection(Triangle3d triangle, double eps) {
Vector3d v0 = triangle.getP1(); Vector3d v0 = triangle.getP1();
Vector3d v1 = triangle.getP2(); Vector3d v1 = triangle.getP2();
Vector3d v2 = triangle.getP3(); Vector3d v2 = triangle.getP3();
...@@ -188,7 +186,7 @@ public class Segment3d implements Serializable { ...@@ -188,7 +186,7 @@ public class Segment3d implements Serializable {
Vector3d p = direction.cross(edge2); Vector3d p = direction.cross(edge2);
double det = edge1.dot(p); double det = edge1.dot(p);
if (det > -EPSILON && det < EPSILON) { if (det > -eps && det < eps) {
return null; return null;
} }
...@@ -197,7 +195,7 @@ public class Segment3d implements Serializable { ...@@ -197,7 +195,7 @@ public class Segment3d implements Serializable {
Vector3d s = pointA.minus(v0); Vector3d s = pointA.minus(v0);
double u = invDet * s.dot(p); double u = invDet * s.dot(p);
if (u < EPSILON || u > (1.0 - EPSILON)) { if (u < eps || u > (1.0 - eps)) {
return null; return null;
} }
...@@ -210,7 +208,7 @@ public class Segment3d implements Serializable { ...@@ -210,7 +208,7 @@ public class Segment3d implements Serializable {
} }
double t = edge2.dot(q) * invDet; double t = edge2.dot(q) * invDet;
if (t > EPSILON && t < 1 - EPSILON) { if (t > eps && t < 1 - eps) {
// t is in segment // t is in segment
return pointA.plus(direction.mult(t)); return pointA.plus(direction.mult(t));
} }
......
...@@ -35,6 +35,8 @@ public class Triangle3d implements Serializable { ...@@ -35,6 +35,8 @@ public class Triangle3d implements Serializable {
private static final long serialVersionUID = -6907333357794272435L; private static final long serialVersionUID = -6907333357794272435L;
private static final double EPSILON = 0.0001; private static final double EPSILON = 0.0001;
private static final double PLANAR_EPSILON = 0.0000001;
private final Vector3d p1; private final Vector3d p1;
private final Vector3d p2; private final Vector3d p2;
private final Vector3d p3; private final Vector3d p3;
...@@ -51,7 +53,54 @@ public class Triangle3d implements Serializable { ...@@ -51,7 +53,54 @@ public class Triangle3d implements Serializable {
this.p3 = p3; this.p3 = p3;
this.partOf = partOf; this.partOf = partOf;
} }
public boolean hasMinExtent(double minExtent) {
Vector3d ab = p2.minus(p1);
Vector3d ac = p3.minus(p1);
Vector3d bc = p3.minus(p2);
// Find the longest edge to use as primary axis
double lenAB2 = ab.getSquaredLength();
double lenAC2 = ac.getSquaredLength();
double lenBC2 = bc.getSquaredLength();
Vector3d axisX;
if (lenAB2 >= lenAC2 && lenAB2 >= lenBC2) {
axisX = ab;
} else if (lenAC2 >= lenBC2) {
axisX = ac;
} else {
axisX = bc;
}
axisX = axisX.normalize();
// Pick any vector not parallel to axisX for in-plane Y axis
Vector3d axisY = pickPerpendicular(axisX);
// Project vertices onto axes
double minX = Math.min(p1.dot(axisX), Math.min(p2.dot(axisX), p3.dot(axisX)));
double maxX = Math.max(p1.dot(axisX), Math.max(p2.dot(axisX), p3.dot(axisX)));
double minY = Math.min(p1.dot(axisY), Math.min(p2.dot(axisY), p3.dot(axisY)));
double maxY = Math.max(p1.dot(axisY), Math.max(p2.dot(axisY), p3.dot(axisY)));
double extentX = maxX - minX;
double extentY = maxY - minY;
return extentX > minExtent && extentY > minExtent;
}
private Vector3d pickPerpendicular(Vector3d v) {
// choose smallest component to avoid near-zero cross
if (Math.abs(v.getX()) < Math.abs(v.getY()) && Math.abs(v.getX()) < Math.abs(v.getZ())) {
return new Vector3d(0, -v.getZ(), v.getY()).normalize();
}
if (Math.abs(v.getY()) < Math.abs(v.getZ())) {
return new Vector3d(-v.getZ(), 0, v.getX()).normalize();
}
return new Vector3d(-v.getY(), v.getX(), 0).normalize();
}
public TesselatedPolygon getPartOf() { public TesselatedPolygon getPartOf() {
return partOf; return partOf;
} }
...@@ -101,13 +150,13 @@ public class Triangle3d implements Serializable { ...@@ -101,13 +150,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) < PLANAR_EPSILON) {
distanceP1T2 = 0.0; distanceP1T2 = 0.0;
} }
if (Math.abs(distanceP2T2) < epsilon) { if (Math.abs(distanceP2T2) < PLANAR_EPSILON) {
distanceP2T2 = 0.0; distanceP2T2 = 0.0;
} }
if (Math.abs(distanceP3T2) < epsilon) { if (Math.abs(distanceP3T2) < PLANAR_EPSILON) {
distanceP3T2 = 0.0; distanceP3T2 = 0.0;
} }
...@@ -144,20 +193,18 @@ public class Triangle3d implements Serializable { ...@@ -144,20 +193,18 @@ public class Triangle3d implements Serializable {
return false; return false;
} }
boolean intersects = checkTriangleLineIntersection(other, p1, p2) || checkTriangleLineIntersection(other, p1, p3) boolean intersects = checkTriangleLineIntersection(other, p1, p2, epsilon)
|| checkTriangleLineIntersection(other, p2, p3) || checkTriangleLineIntersection(other, p1, p3, epsilon)
|| checkTriangleLineIntersection(this, other.p1, other.p2) || checkTriangleLineIntersection(other, p2, p3, epsilon)
|| checkTriangleLineIntersection(this, other.p1, other.p3) || checkTriangleLineIntersection(this, other.p1, other.p2, epsilon)
|| checkTriangleLineIntersection(this, other.p2, other.p3); || checkTriangleLineIntersection(this, other.p1, other.p3, epsilon)
if (intersects) { || checkTriangleLineIntersection(this, other.p2, other.p3, epsilon);
System.out.println();
}
return intersects; return intersects;
} }
private boolean checkTriangleLineIntersection(Triangle3d other, Vector3d a, Vector3d b) { private boolean checkTriangleLineIntersection(Triangle3d other, Vector3d a, Vector3d b, double eps) {
Segment3d seg = new Segment3d(a, b); Segment3d seg = new Segment3d(a, b);
Vector3d intersection1 = seg.intersection(other); Vector3d intersection1 = seg.intersection(other, eps);
return intersection1 != null; return intersection1 != null;
} }
...@@ -274,5 +321,4 @@ public class Triangle3d implements Serializable { ...@@ -274,5 +321,4 @@ public class Triangle3d implements Serializable {
public void setPartOf(TesselatedPolygon p) { public void setPartOf(TesselatedPolygon p) {
partOf = p; partOf = p;
} }
} }
...@@ -46,9 +46,10 @@ public class Vector3d implements Serializable { ...@@ -46,9 +46,10 @@ public class Vector3d implements Serializable {
public Vector3d() { public Vector3d() {
this(0d, 0d, 0d); this(0d, 0d, 0d);
} }
/** /**
* Convert JTS Coordinate class to Vector3d. * Convert JTS Coordinate class to Vector3d.
*
* @param coord JTS Coordinate * @param coord JTS Coordinate
*/ */
public Vector3d(Coordinate coord) { public Vector3d(Coordinate coord) {
...@@ -210,7 +211,8 @@ public class Vector3d implements Serializable { ...@@ -210,7 +211,8 @@ public class Vector3d implements Serializable {
} }
/** /**
* normalizes this vector. This method changes the coordinates of this instance. * returns a normalized vector in the same direction as this one. This method
* does not change the coordinates of this instance.
*/ */
public UnitVector3d normalize() { public UnitVector3d normalize() {
return UnitVector3d.of(this); return UnitVector3d.of(this);
...@@ -253,9 +255,9 @@ public class Vector3d implements Serializable { ...@@ -253,9 +255,9 @@ public class Vector3d implements Serializable {
@Override @Override
public String toString() { public String toString() {
final int maxLen = 5; final int maxLen = 5;
return "Vector3d [coords=" + return "Vector3d [coords="
(coords != null ? Arrays.toString(Arrays.copyOf(coords, Math.min(coords.length, maxLen))) : null) + + (coords != null ? Arrays.toString(Arrays.copyOf(coords, Math.min(coords.length, maxLen))) : null)
"]"; + "]";
} }
@Override @Override
......
...@@ -641,7 +641,7 @@ public class Checker { ...@@ -641,7 +641,7 @@ public class Checker {
ArrayList<Check> checkList = new ArrayList<>(); ArrayList<Check> checkList = new ArrayList<>();
for (CheckId id : enabledCheck) { for (CheckId id : enabledCheck) {
Check c = checkConfig.getCheckForId(id); Check c = checkConfig.getCheckForId(id);
c.init(parameterMap.get(id), parserConfig); c.init(parameterMap, parserConfig);
checkList.add(c); checkList.add(c);
} }
return checkList; return checkList;
...@@ -657,7 +657,6 @@ public class Checker { ...@@ -657,7 +657,6 @@ public class Checker {
parameterMap.compute(proto.getCheckId(), (k, v) -> { parameterMap.compute(proto.getCheckId(), (k, v) -> {
if (v == null) { if (v == null) {
v = new HashMap<>(); v = new HashMap<>();
v.put(GlobalParameters.NUMBER_OF_ROUNDING_PLACES, config.getNumberOfRoundingPlacesAsString());
v.put(GlobalParameters.MIN_VERTEX_DISTANCE, config.getMinVertexDistanceAsString()); v.put(GlobalParameters.MIN_VERTEX_DISTANCE, config.getMinVertexDistanceAsString());
} }
v.putAll(e.getValue().getParameters()); v.putAll(e.getValue().getParameters());
......
...@@ -62,7 +62,7 @@ public class CheckContainer extends Check { ...@@ -62,7 +62,7 @@ public class CheckContainer extends Check {
} }
@Override @Override
public void init(Map<String, String> parameters, ParserConfiguration config) { public void init(Map<CheckId, Map<String, String>> parameters, ParserConfiguration config) {
check.init(parameters, config); check.init(parameters, config);
} }
......
...@@ -30,10 +30,12 @@ import de.hft.stuttgart.citydoctor2.check.CheckId; ...@@ -30,10 +30,12 @@ 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.RequirementType; import de.hft.stuttgart.citydoctor2.check.RequirementType;
import de.hft.stuttgart.citydoctor2.check.Checkable; import de.hft.stuttgart.citydoctor2.check.Checkable;
import de.hft.stuttgart.citydoctor2.check.GlobalParameters;
import de.hft.stuttgart.citydoctor2.check.Requirement; import de.hft.stuttgart.citydoctor2.check.Requirement;
import de.hft.stuttgart.citydoctor2.check.ResultStatus; import de.hft.stuttgart.citydoctor2.check.ResultStatus;
import de.hft.stuttgart.citydoctor2.check.error.ConsecutivePointSameError; import de.hft.stuttgart.citydoctor2.check.error.ConsecutivePointSameError;
import de.hft.stuttgart.citydoctor2.check.error.RingDuplicatePointError; import de.hft.stuttgart.citydoctor2.check.error.RingDuplicatePointError;
import de.hft.stuttgart.citydoctor2.checks.Checks;
import de.hft.stuttgart.citydoctor2.checks.util.CollectionUtils; import de.hft.stuttgart.citydoctor2.checks.util.CollectionUtils;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing; import de.hft.stuttgart.citydoctor2.datastructure.LinearRing;
import de.hft.stuttgart.citydoctor2.datastructure.Vertex; import de.hft.stuttgart.citydoctor2.datastructure.Vertex;
...@@ -52,8 +54,6 @@ import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; ...@@ -52,8 +54,6 @@ import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
*/ */
public class DuplicatePointsCheck extends Check { public class DuplicatePointsCheck extends Check {
private static final String EPSILON_NAME = "minVertexDistance";
private static final List<CheckId> dependencies; private static final List<CheckId> dependencies;
static { static {
...@@ -66,11 +66,16 @@ public class DuplicatePointsCheck extends Check { ...@@ -66,11 +66,16 @@ public class DuplicatePointsCheck extends Check {
classes.add(LinearRing.class); classes.add(LinearRing.class);
} }
private double epsilon = 0.0001; private double epsilon = Checks.MIN_VERTEX_DISTANCE_DEFAULT;
@Override @Override
public void init(Map<String, String> params, ParserConfiguration config) { public void init(Map<CheckId, Map<String, String>> params, ParserConfiguration config) {
String epsilonString = params.get(EPSILON_NAME); Map<String, String> localParameters = params.get(getCheckId());
if (localParameters == null) {
// no parameters
return;
}
String epsilonString = localParameters.get(GlobalParameters.MIN_VERTEX_DISTANCE);
if (epsilonString != null) { if (epsilonString != null) {
epsilon = Double.parseDouble(epsilonString); epsilon = Double.parseDouble(epsilonString);
} }
......
...@@ -29,10 +29,12 @@ import de.hft.stuttgart.citydoctor2.check.Check; ...@@ -29,10 +29,12 @@ 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.GlobalParameters;
import de.hft.stuttgart.citydoctor2.check.RequirementType; import de.hft.stuttgart.citydoctor2.check.RequirementType;
import de.hft.stuttgart.citydoctor2.check.Requirement; import de.hft.stuttgart.citydoctor2.check.Requirement;
import de.hft.stuttgart.citydoctor2.check.ResultStatus; import de.hft.stuttgart.citydoctor2.check.ResultStatus;
import de.hft.stuttgart.citydoctor2.check.error.PolygonInteriorDisconnectedError; import de.hft.stuttgart.citydoctor2.check.error.PolygonInteriorDisconnectedError;
import de.hft.stuttgart.citydoctor2.checks.Checks;
import de.hft.stuttgart.citydoctor2.checks.util.CollectionUtils; import de.hft.stuttgart.citydoctor2.checks.util.CollectionUtils;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing; import de.hft.stuttgart.citydoctor2.datastructure.LinearRing;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon; import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
...@@ -49,8 +51,6 @@ import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; ...@@ -49,8 +51,6 @@ import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
*/ */
public class InteriorDisconnectedCheck extends Check { public class InteriorDisconnectedCheck extends Check {
private static final String EPSILON_NAME = "minVertexDistance";
private static final List<CheckId> dependencies; private static final List<CheckId> dependencies;
static { static {
...@@ -63,11 +63,16 @@ public class InteriorDisconnectedCheck extends Check { ...@@ -63,11 +63,16 @@ public class InteriorDisconnectedCheck extends Check {
dependencies = Collections.unmodifiableList(deps); dependencies = Collections.unmodifiableList(deps);
} }
private double epsilon = 0.0001; private double epsilon = Checks.MIN_VERTEX_DISTANCE_DEFAULT;
@Override @Override
public void init(Map<String, String> params, ParserConfiguration config) { public void init(Map<CheckId, Map<String, String>> params, ParserConfiguration config) {
String epsilonString = params.get(EPSILON_NAME); Map<String, String> localParameters = params.get(getCheckId());
if (localParameters == null) {
// no parameters
return;
}
String epsilonString = localParameters.get(GlobalParameters.MIN_VERTEX_DISTANCE);
if (epsilonString != null) { if (epsilonString != null) {
epsilon = Double.parseDouble(epsilonString); epsilon = Double.parseDouble(epsilonString);
} }
......
...@@ -44,9 +44,10 @@ import de.hft.stuttgart.citydoctor2.tesselation.TesselatedRing; ...@@ -44,9 +44,10 @@ import de.hft.stuttgart.citydoctor2.tesselation.TesselatedRing;
public class NullAreaCheck extends Check { public class NullAreaCheck extends Check {
private static final String DELTA_NAME = "delta"; private static final String DELTA_NAME = "delta";
private static final List<CheckId> dependencies; private static final List<CheckId> dependencies;
private double delta = 0.0001;
static { static {
ArrayList<CheckId> deps = new ArrayList<>(); ArrayList<CheckId> deps = new ArrayList<>();
deps.add(CheckId.C_GE_R_TOO_FEW_POINTS); deps.add(CheckId.C_GE_R_TOO_FEW_POINTS);
...@@ -55,12 +56,16 @@ public class NullAreaCheck extends Check { ...@@ -55,12 +56,16 @@ public class NullAreaCheck extends Check {
dependencies = Collections.unmodifiableList(deps); dependencies = Collections.unmodifiableList(deps);
} }
private double delta = 0.0001;
@Override @Override
public void init(Map<String, String> parameters, ParserConfiguration config) { public void init(Map<CheckId, Map<String, String>> params, ParserConfiguration config) {
if (parameters.containsKey(DELTA_NAME)) { Map<String, String> localParameters = params.get(getCheckId());
delta = Double.parseDouble(parameters.get(DELTA_NAME)); if (localParameters == null) {
// no parameters
return;
}
String epsilonString = localParameters.get(DELTA_NAME);
if (epsilonString != null) {
delta = Double.parseDouble(epsilonString);
} }
} }
......
...@@ -81,17 +81,22 @@ public class PlanarCheck extends Check { ...@@ -81,17 +81,22 @@ public class PlanarCheck extends Check {
private double delta = 0.01; private double delta = 0.01;
@Override @Override
public void init(Map<String, String> parameters, ParserConfiguration config) { public void init(Map<CheckId, Map<String, String>> parameters, ParserConfiguration config) {
if (parameters.containsKey(TYPE)) { Map<String, String> localParameters = parameters.get(getCheckId());
planarCheckType = parameters.get(TYPE).toLowerCase(); if (localParameters == null) {
// no parameters
return;
}
if (localParameters.containsKey(TYPE)) {
planarCheckType = localParameters.get(TYPE).toLowerCase();
} else { } else {
throw new IllegalStateException("Parameter " + TYPE + " is missing from parameters"); throw new IllegalStateException("Parameter " + TYPE + " is missing from parameters");
} }
if (parameters.containsKey(ANGLE_TOLERANCE)) { if (localParameters.containsKey(ANGLE_TOLERANCE)) {
rad = Math.toRadians(Double.parseDouble(parameters.get(ANGLE_TOLERANCE))); rad = Math.toRadians(Double.parseDouble(localParameters.get(ANGLE_TOLERANCE)));
} }
if (parameters.containsKey(DISTANCE_TOLERANCE)) { if (localParameters.containsKey(DISTANCE_TOLERANCE)) {
delta = Double.parseDouble(parameters.get(DISTANCE_TOLERANCE)); delta = Double.parseDouble(localParameters.get(DISTANCE_TOLERANCE));
} }
} }
......
...@@ -29,6 +29,7 @@ import de.hft.stuttgart.citydoctor2.check.Check; ...@@ -29,6 +29,7 @@ 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.GlobalParameters;
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;
...@@ -59,15 +60,12 @@ import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; ...@@ -59,15 +60,12 @@ import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
*/ */
public class RingSelfIntCheck extends Check { public class RingSelfIntCheck extends Check {
private static final String EPSILON_NAME = "minVertexDistance"; private static final List<CheckId> dependencies;
// check requirement class for default parameters // check requirement class for default parameters
private double degeneratedRingTolerance = 0.01; private double degeneratedRingTolerance = 0.01;
private double epsilon = Checks.MIN_VERTEX_DISTANCE_DEFAULT; private double epsilon = Checks.MIN_VERTEX_DISTANCE_DEFAULT;
private static final List<CheckId> dependencies;
static { static {
ArrayList<CheckId> deps = new ArrayList<>(); ArrayList<CheckId> deps = new ArrayList<>();
deps.add(CheckId.C_GE_R_TOO_FEW_POINTS); deps.add(CheckId.C_GE_R_TOO_FEW_POINTS);
...@@ -78,13 +76,18 @@ public class RingSelfIntCheck extends Check { ...@@ -78,13 +76,18 @@ public class RingSelfIntCheck extends Check {
@Override @Override
public void init(Map<String, String> parameters, ParserConfiguration config) { public void init(Map<CheckId, Map<String, String>> parameters, ParserConfiguration config) {
String epsilonString = parameters.get(EPSILON_NAME); Map<String, String> localParameters = parameters.get(getCheckId());
if (localParameters == null) {
// no parameters
return;
}
String epsilonString = localParameters.get(GlobalParameters.MIN_VERTEX_DISTANCE);
if (epsilonString != null) { if (epsilonString != null) {
epsilon = Double.parseDouble(epsilonString); epsilon = Double.parseDouble(epsilonString);
} }
if (parameters.containsKey(Requirement.DEGENERATED_RING_TOLERANCE)) { if (localParameters.containsKey(Requirement.DEGENERATED_RING_TOLERANCE)) {
degeneratedRingTolerance = Double.parseDouble(parameters.get(Requirement.DEGENERATED_RING_TOLERANCE)); degeneratedRingTolerance = Double.parseDouble(localParameters.get(Requirement.DEGENERATED_RING_TOLERANCE));
} }
} }
......
...@@ -73,10 +73,16 @@ public class SolidSelfIntCheck extends Check { ...@@ -73,10 +73,16 @@ public class SolidSelfIntCheck extends Check {
} }
@Override @Override
public void init(Map<String, String> parameters, ParserConfiguration config) { public void init(Map<CheckId, Map<String, String>> parameters, ParserConfiguration config) {
if (parameters.containsKey(PlanarCheck.DISTANCE_TOLERANCE)) { Map<String, String> planarParameters = parameters.get(CheckId.C_GE_P_NON_PLANAR);
delta = Double.parseDouble(parameters.get(PlanarCheck.DISTANCE_TOLERANCE)); if (planarParameters == null) {
// no parameters
return;
} }
planarParameters.computeIfPresent(PlanarCheck.DISTANCE_TOLERANCE, (k, v) -> {
delta = Double.parseDouble(v);
return v;
});
} }
@Override @Override
......
...@@ -75,13 +75,18 @@ public class IsWallCheck extends Check { ...@@ -75,13 +75,18 @@ public class IsWallCheck extends Check {
private double upperAngleCos = Math.cos(135 * Math.PI / 180); private double upperAngleCos = Math.cos(135 * Math.PI / 180);
@Override @Override
public void init(Map<String, String> params, ParserConfiguration config) { public void init(Map<CheckId, Map<String, String>> params, ParserConfiguration config) {
String lowerAngleString = params.get(LOWER_ANGLE_NAME); Map<String, String> localParameters = params.get(getCheckId());
if (localParameters == null) {
// no parameters
return;
}
String lowerAngleString = localParameters.get(LOWER_ANGLE_NAME);
if (lowerAngleString != null) { if (lowerAngleString != null) {
lowerAngleCos = Double.parseDouble(lowerAngleString); lowerAngleCos = Double.parseDouble(lowerAngleString);
lowerAngleCos = Math.cos(lowerAngleCos * Math.PI / 180); lowerAngleCos = Math.cos(lowerAngleCos * Math.PI / 180);
} }
String upperAngleString = params.get(UPPER_ANGLE_NAME); String upperAngleString = localParameters.get(UPPER_ANGLE_NAME);
if (upperAngleString != null) { if (upperAngleString != null) {
upperAngleCos = Double.parseDouble(upperAngleString); upperAngleCos = Double.parseDouble(upperAngleString);
upperAngleCos = Math.cos(upperAngleCos * Math.PI / 180); upperAngleCos = Math.cos(upperAngleCos * Math.PI / 180);
......
...@@ -60,8 +60,13 @@ public class RoofSurfaceUnfragmentedCheck extends Check { ...@@ -60,8 +60,13 @@ public class RoofSurfaceUnfragmentedCheck extends Check {
} }
@Override @Override
public void init(Map<String, String> params, ParserConfiguration config) { public void init(Map<CheckId, Map<String, String>> params, ParserConfiguration config) {
String maxAngleString = params.get(MAX_ANGLE_DEVIATION); Map<String, String> localParameters = params.get(getCheckId());
if (localParameters == null) {
// no parameters
return;
}
String maxAngleString = localParameters.get(MAX_ANGLE_DEVIATION);
if (maxAngleString != null) { if (maxAngleString != null) {
maxAngleDeviation = Math.toRadians(Double.parseDouble(maxAngleString)); maxAngleDeviation = Math.toRadians(Double.parseDouble(maxAngleString));
} }
......
...@@ -40,8 +40,6 @@ import org.locationtech.jts.geom.impl.CoordinateArraySequence; ...@@ -40,8 +40,6 @@ 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;
...@@ -53,10 +51,8 @@ import de.hft.stuttgart.citydoctor2.edge.EdgePolygon; ...@@ -53,10 +51,8 @@ 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;
...@@ -95,18 +91,7 @@ public class SelfIntersectionUtil { ...@@ -95,18 +91,7 @@ public class SelfIntersectionUtil {
TesselatedPolygon tessPolygon = EarcutTesselator.tesselatePolygon(p); TesselatedPolygon tessPolygon = EarcutTesselator.tesselatePolygon(p);
for (Iterator<Triangle3d> iterator = tessPolygon.getTriangles().iterator(); iterator.hasNext();) { for (Iterator<Triangle3d> iterator = tessPolygon.getTriangles().iterator(); iterator.hasNext();) {
Triangle3d t = iterator.next(); Triangle3d t = iterator.next();
List<Vector3d> vertices = new ArrayList<>(3); if (!t.hasMinExtent(delta)) {
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(); iterator.remove();
} }
} }
...@@ -126,7 +111,7 @@ public class SelfIntersectionUtil { ...@@ -126,7 +111,7 @@ public class SelfIntersectionUtil {
} }
return intersections; return intersections;
} }
public static GeometrySelfIntersection doesSolidSelfIntersect(Geometry g, double epsilon) { public static GeometrySelfIntersection doesSolidSelfIntersect(Geometry g, double epsilon) {
return selfIntersectionJava(g, epsilon); return selfIntersectionJava(g, epsilon);
} }
...@@ -448,8 +433,8 @@ public class SelfIntersectionUtil { ...@@ -448,8 +433,8 @@ public class SelfIntersectionUtil {
private static GeometrySelfIntersection doPolygonsIntersect(TesselatedPolygon p1, TesselatedPolygon p2, double epsilon) { 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++) {
Triangle3d t1 = p1.getTriangles().get(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 t2 = p2.getTriangles().get(p2Index); Triangle3d t2 = p2.getTriangles().get(p2Index);
if (t1.doesIntersect(t2, epsilon)) { if (t1.doesIntersect(t2, epsilon)) {
logger.trace("{} intersects {}", t1, t2); logger.trace("{} intersects {}", t1, t2);
......
...@@ -24,16 +24,7 @@ import de.hft.stuttgart.citydoctor2.check.CheckError; ...@@ -24,16 +24,7 @@ import de.hft.stuttgart.citydoctor2.check.CheckError;
import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration; import de.hft.stuttgart.citydoctor2.check.ValidationConfiguration;
import de.hft.stuttgart.citydoctor2.checkresult.utility.CheckReportWriteException; import de.hft.stuttgart.citydoctor2.checkresult.utility.CheckReportWriteException;
import de.hft.stuttgart.citydoctor2.checks.Checks; import de.hft.stuttgart.citydoctor2.checks.Checks;
import de.hft.stuttgart.citydoctor2.datastructure.BridgeObject;
import de.hft.stuttgart.citydoctor2.datastructure.Building;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel; import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.datastructure.CityFurniture;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.datastructure.GenericCityObject;
import de.hft.stuttgart.citydoctor2.datastructure.TransportationObject;
import de.hft.stuttgart.citydoctor2.datastructure.Tunnel;
import de.hft.stuttgart.citydoctor2.datastructure.Vegetation;
import de.hft.stuttgart.citydoctor2.datastructure.WaterObject;
/** /**
* *
......
...@@ -285,7 +285,6 @@ public class PdfStreamReporter implements StreamReporter { ...@@ -285,7 +285,6 @@ public class PdfStreamReporter implements StreamReporter {
tSection.setHeadlineColor(OK_COLOR); tSection.setHeadlineColor(OK_COLOR);
} }
writeErrorForCityObject(co, tSection); writeErrorForCityObject(co, tSection);
TransportationObject to = (TransportationObject) co;
} }
private void reportVegetation(CityObject co, boolean hasError) { private void reportVegetation(CityObject co, boolean hasError) {
...@@ -389,25 +388,6 @@ public class PdfStreamReporter implements StreamReporter { ...@@ -389,25 +388,6 @@ public class PdfStreamReporter implements StreamReporter {
} }
} }
private void writeCheckResultForTransportationObject(TransportationObject to, Section root) {
Map<CheckId, CheckResult> results = to.getAllCheckResults();
writeCheckResults(results.values(), root);
for (Geometry geom : to.getGeometries()) {
writeCheckResultForGeometry(geom, root);
}
}
private void writeCheckResultForBuildingPart(BuildingPart bp, Section root) {
Map<CheckId, CheckResult> results = bp.getAllCheckResults();
writeCheckResults(results.values(), root);
for (Geometry geom : bp.getGeometries()) {
writeCheckResultForGeometry(geom, root);
}
for (BoundarySurface bs : bp.getBoundarySurfaces()) {
writeCheckResultForBoundarySurface(bs, root);
}
}
private void writeCheckResultForAbstractBuilding(AbstractBuilding ab, Section root) { private void writeCheckResultForAbstractBuilding(AbstractBuilding ab, Section root) {
Map<CheckId, CheckResult> results = ab.getAllCheckResults(); Map<CheckId, CheckResult> results = ab.getAllCheckResults();
writeCheckResults(results.values(), root); writeCheckResults(results.values(), root);
...@@ -714,24 +694,6 @@ public class PdfStreamReporter implements StreamReporter { ...@@ -714,24 +694,6 @@ public class PdfStreamReporter implements StreamReporter {
report.save(outFile); report.save(outFile);
} }
private void countFinishedReportBuildings() {
for (Section s : buildings.getSubSections()) {
if (!s.hasErrors()) {
numOkBuildings++;
// building has no errors, no table
continue;
}
numErrorBuildings++;
Table t = new Table(2);
t.setTableColumnWidth(75, 25);
t.setTitle("Error", "Count");
for (Entry<String, AtomicInteger> e : s.getStats().getErrorCounts().entrySet()) {
t.addRow(e.getKey(), e.getValue().toString());
}
s.addTable(1, t);
}
}
@Override @Override
public void reportGlobalError(CheckError err) { public void reportGlobalError(CheckError err) {
AtomicInteger errorCount = errorStatistics.computeIfAbsent(err.getErrorId(), k -> new AtomicInteger(0)); AtomicInteger errorCount = errorStatistics.computeIfAbsent(err.getErrorId(), k -> new AtomicInteger(0));
......
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