Commit 85cf93b6 authored by Matthias Betz's avatar Matthias Betz
Browse files

reworked check engine now working on requirements

parent 35577785
Pipeline #2108 passed with stage
in 3 minutes and 6 seconds
......@@ -23,6 +23,7 @@ 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.error.DependenciesNotMetError;
import de.hft.stuttgart.citydoctor2.datastructure.AbstractBuilding;
......@@ -98,6 +99,8 @@ public abstract class Check {
public List<CheckId> getDependencies() {
return Collections.emptyList();
}
public abstract Set<Requirement> appliesToRequirements();
/**
* Getter for the check id.
......@@ -111,7 +114,7 @@ public abstract class Check {
*
* @return the check type
*/
public abstract CheckType getType();
public abstract RequirementType getType();
/**
* Checks whether the check can be executed on this checkable, meaning the
......
......@@ -44,14 +44,13 @@ public class CheckId implements Serializable {
public static final CheckId C_GE_P_HOLE_OUTSIDE = new CheckId("C_GE_P_HOLE_OUTSIDE");
public static final CheckId IS_CEILING = new CheckId("IS_CEILING");
public static final CheckId C_GE_P_INNER_RINGS_NESTED = new CheckId("C_GE_P_INNER_RINGS_NESTED");
public static final CheckId C_SEM_BS_NOT_CEILING = new CheckId("C_SEM_BS_NOT_CEILING");
public static final CheckId C_SEM_BS_NOT_FLOOR = new CheckId("C_SEM_BS_NOT_FLOOR");
public static final CheckId C_SEM_BS_NOT_GROUND = new CheckId("C_SEM_BS_NOT_GROUND");
public static final CheckId C_SEM_F_MISSING_ID = new CheckId("C_SEM_F_MISSING_ID");
public static final CheckId C_SEM_BS_GROUND_NOT_FRAGMENTED = new CheckId("C_SEM_BS_GROUND_NOT_FRAGMENTED");
public static final CheckId C_SEM_BS_IS_WALL = new CheckId("C_SEM_BS_IS_WALL");
public static final CheckId C_SEM_SCHEMATRON = new CheckId("C_SEM_SCHEMATRON");
public static final CheckId C_SEM_BS_ROOF_NOT_FRAGMENTED = new CheckId("C_SEM_BS_ROOF_NOT_FRAGMENTED");
public static final CheckId C_SE_BS_IS_CEILING = new CheckId("C_SE_BS_IS_CEILING");
public static final CheckId C_SE_BS_IS_FLOOR = new CheckId("C_SE_BS_IS_FLOOR");
public static final CheckId C_SE_BS_IS_GROUND = new CheckId("C_SE_BS_IS_GROUND");
public static final CheckId C_SE_BS_GROUND_NOT_FRAGMENTED = new CheckId("C_SE_BS_GROUND_NOT_FRAGMENTED");
public static final CheckId C_SE_BS_IS_WALL = new CheckId("C_SE_BS_IS_WALL");
public static final CheckId C_SE_SCHEMATRON = new CheckId("C_SE_SCHEMATRON");
public static final CheckId C_SE_BS_ROOF_UNFRAGMENTED = new CheckId("C_SE_BS_ROOF_UNFRAGMENTED");
public static final CheckId C_GE_S_NOT_CLOSED = new CheckId("C_GE_S_NOT_CLOSED");
public static final CheckId C_GE_P_ORIENTATION_RINGS_SAME = new CheckId("C_GE_P_ORIENTATION_RINGS_SAME");
......
......@@ -31,7 +31,7 @@ import de.hft.stuttgart.citydoctor2.datastructure.GmlId;
/**
* Interface to indicate that this object can be checked by Checks.
*
* @author Matthias Betz - 12bema1bif@hft-stuttgart.de
* @author Matthias Betz
*
*/
public abstract class Checkable implements Serializable {
......
......@@ -18,6 +18,8 @@
*/
package de.hft.stuttgart.citydoctor2.check;
import java.io.Serializable;
/**
* Describes a parameter for a check including the default value as a String.
* All values are a String as they are passed to the check as a Map<String,
......@@ -26,15 +28,17 @@ package de.hft.stuttgart.citydoctor2.check;
* @author Matthias Betz
*
*/
public class DefaultParameter {
public class DefaultParameter implements Serializable {
private static final long serialVersionUID = -4587211298078974066L;
private String name;
private String defaultValue;
private String value;
private Unit unitType;
public DefaultParameter(String name, String defaultValue, Unit unitType) {
this.name = name;
this.defaultValue = defaultValue;
this.value = defaultValue;
this.unitType = unitType;
}
......@@ -56,8 +60,8 @@ public class DefaultParameter {
*
* @return the defaultValue
*/
public String getDefaultValue() {
return defaultValue;
public String getValue() {
return value;
}
/*
......@@ -68,10 +72,10 @@ public class DefaultParameter {
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("CheckParameter [name=");
builder.append("DefaultParameter [name=");
builder.append(name);
builder.append(", defaultValue=");
builder.append(defaultValue);
builder.append(", value=");
builder.append(value);
builder.append("]");
return builder.toString();
}
......
......@@ -56,13 +56,12 @@ public class ErrorId implements Serializable {
public static final ErrorId GE_P_ORIENTATION_RINGS_SAME = new ErrorId("GE_P_ORIENTATION_RINGS_SAME");
public static final ErrorId GE_S_NOT_CLOSED = new ErrorId("GE_S_NOT_CLOSED");
public static final ErrorId GE_S_TOO_FEW_POLYGONS = new ErrorId("GE_S_TOO_FEW_POLYGONS");
public static final ErrorId SEM_F_MISSING_ID = new ErrorId("SEM_F_MISSING_ID");
public static final ErrorId SEM_BS_NOT_CEILING = new ErrorId("SEM_BS_NOT_CEILING");
public static final ErrorId SEM_BS_NOT_WALL = new ErrorId("SEM_BS_NOT_WALL");
public static final ErrorId SEM_BS_NOT_FLOOR = new ErrorId("SEM_BS_NOT_FLOOR");
public static final ErrorId SEM_BS_NOT_GROUND = new ErrorId("SEM_BS_NOT_GROUND");
public static final ErrorId SEM_SCHEMATRON_ERROR = new ErrorId("SEM_SCHEMATRON_ERROR");
public static final ErrorId SEM_BS_UNFRAGMENTED = new ErrorId("SEM_BS_UNFRAGMENTED");
public static final ErrorId SE_BS_NOT_CEILING = new ErrorId("SE_BS_NOT_CEILING");
public static final ErrorId SE_BS_NOT_WALL = new ErrorId("SE_BS_NOT_WALL");
public static final ErrorId SE_BS_NOT_FLOOR = new ErrorId("SE_BS_NOT_FLOOR");
public static final ErrorId SE_BS_NOT_GROUND = new ErrorId("SE_BS_NOT_GROUND");
public static final ErrorId SE_SCHEMATRON_ERROR = new ErrorId("SE_SCHEMATRON_ERROR");
public static final ErrorId SE_BS_UNFRAGMENTED = new ErrorId("SE_BS_UNFRAGMENTED");
public static final ErrorId GE_P_DEGENERATED_POLYGON = new ErrorId("GE_P_DEGENERATED_POLYGON");
private String name;
......
/*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
*
* This file is part of CityDoctor2.
*
* CityDoctor2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CityDoctor2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with CityDoctor2. If not, see <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.check;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Requirement implements Serializable {
private static final long serialVersionUID = -590639811553512803L;
private static final String DISTANCE_TOLERANCE = "distanceTolerance";
private static final String ANGLE_TOLERANCE = "angleTolerance";
private static final String TYPE_STRING = "type";
private static final String DEGENERATED_POLYGON_TOLERANCE = "degeneratedPolygonTolerance";
private static final String LOWER_ANGLE_NAME = "lowerAngle";
private static final String UPPER_ANGLE_NAME = "upperAngle";
public static final Requirement R_GE_R_TOO_FEW_POINTS = new Requirement("R_GE_R_TOO_FEW_POINTS", RequirementType.GEOMETRY);
public static final Requirement R_GE_R_NOT_CLOSED = new Requirement("R_GE_R_NOT_CLOSED", RequirementType.GEOMETRY);
public static final Requirement R_GE_R_CONSECUTIVE_POINTS_SAME = new Requirement("R_GE_R_CONSECUTIVE_POINTS_SAME", RequirementType.GEOMETRY);
public static final Requirement R_GE_R_SELF_INTERSECTION = new Requirement("R_GE_R_SELF_INTERSECTION", RequirementType.GEOMETRY);
public static final Requirement R_GE_P_NON_PLANAR = new Requirement("R_GE_P_NON_PLANAR", RequirementType.GEOMETRY);
public static final Requirement R_GE_P_INTERIOR_DISCONNECTED = new Requirement("R_GE_P_INTERIOR_DISCONNECTED", RequirementType.GEOMETRY);
public static final Requirement R_GE_P_INTERSECTING_RINGS = new Requirement("R_GE_P_INTERSECTING_RINGS", RequirementType.GEOMETRY);
public static final Requirement R_GE_P_HOLE_OUTSIDE = new Requirement("R_GE_P_HOLE_OUTSIDE", RequirementType.GEOMETRY);
public static final Requirement R_GE_P_ORIENTATION_RINGS_SAME = new Requirement("R_GE_P_ORIENTATION_RINGS_SAME", RequirementType.GEOMETRY);
public static final Requirement R_GE_P_INNER_RINGS_NESTED = new Requirement("R_GE_P_INNER_RINGS_NESTED", RequirementType.GEOMETRY);
public static final Requirement R_GE_S_TOO_FEW_POLYGONS = new Requirement("R_GE_S_TOO_FEW_POLYGONS", RequirementType.GEOMETRY);
public static final Requirement R_GE_S_NOT_CLOSED = new Requirement("R_GE_S_NOT_CLOSED", RequirementType.GEOMETRY);
public static final Requirement R_GE_S_NON_MANIFOLD_EDGE = new Requirement("R_GE_S_NON_MANIFOLD_EDGE", RequirementType.GEOMETRY);
public static final Requirement R_GE_S_POLYGON_WRONG_ORIENTATION = new Requirement(
"R_GE_S_POLYGON_WRONG_ORIENTATION", RequirementType.GEOMETRY);
public static final Requirement R_GE_S_ALL_POLYGONS_WRONG_ORIENTATION = new Requirement(
"R_GE_S_ALL_POLYGONS_WRONG_ORIENTATION", RequirementType.GEOMETRY);
public static final Requirement R_GE_S_NON_MANIFOLD_VERTEX = new Requirement("R_GE_S_NON_MANIFOLD_VERTEX", RequirementType.GEOMETRY);
public static final Requirement R_GE_S_SELF_INTERSECTION = new Requirement("R_GE_S_SELF_INTERSECTION", RequirementType.GEOMETRY);
public static final Requirement R_GE_S_MULTIPLE_CONNECTED_COMPONENTS = new Requirement(
"R_GE_S_MULTIPLE_CONNECTED_COMPONENTS", RequirementType.GEOMETRY);
public static final Requirement R_SE_ATTRIBUTES_EXISTING = new Requirement("R_SE_ATTRIBUTES_EXISTING", RequirementType.SEMANTIC);
public static final Requirement R_SE_ATTRIBUTES_CORRECT = new Requirement("R_SE_ATTRIBUTES_CORRECT", RequirementType.SEMANTIC);
public static final Requirement R_GE_R_NULL_AREA = new Requirement("R_GE_R_NULL_AREA", RequirementType.GEOMETRY);
public static final Requirement R_SE_BS_GROUND_UNFRAGMENTED = new Requirement("R_SE_BS_GROUND_UNFRAGMENTED", RequirementType.SEMANTIC);
public static final Requirement R_SE_BS_ROOF_UNFRAGMENTED = new Requirement("R_SE_BS_GROUND_UNFRAGMENTED", RequirementType.SEMANTIC);
public static final Requirement R_SE_BS_IS_CEILING = new Requirement("R_SE_BS_IS_CEILING", RequirementType.SEMANTIC);
public static final Requirement R_SE_BS_IS_FLOOR = new Requirement("R_SE_BS_IS_FLOOR", RequirementType.SEMANTIC);
public static final Requirement R_SE_BS_IS_WALL = new Requirement("R_SE_BS_IS_WALL", RequirementType.SEMANTIC);
public static final Requirement R_SE_BS_IS_GROUND = new Requirement("R_SE_BS_IS_GROUND", RequirementType.SEMANTIC);
static {
// fill requirements with default parameters
ArrayList<DefaultParameter> defaultParameters = new ArrayList<>();
defaultParameters.add(new DefaultParameter(TYPE_STRING, "distance", Unit.NONE));
defaultParameters.add(new DefaultParameter(DISTANCE_TOLERANCE, "0.01", Unit.METER));
defaultParameters.add(new DefaultParameter(ANGLE_TOLERANCE, "1", Unit.DEGREE));
defaultParameters.add(new DefaultParameter(DEGENERATED_POLYGON_TOLERANCE, "0.00000", Unit.METER));
R_GE_P_NON_PLANAR.parameters = Collections.unmodifiableList(defaultParameters);
defaultParameters = new ArrayList<>();
defaultParameters.add(new DefaultParameter(LOWER_ANGLE_NAME, "45", Unit.DEGREE));
defaultParameters.add(new DefaultParameter(UPPER_ANGLE_NAME, "135", Unit.DEGREE));
R_SE_BS_IS_WALL.parameters = Collections.unmodifiableList(defaultParameters);
}
private String id;
private RequirementType type;
private List<DefaultParameter> parameters;
public Requirement(String id, RequirementType type) {
this.id = id;
this.type = type;
parameters = Collections.emptyList();
}
public String getId() {
return id;
}
public List<DefaultParameter> getDefaultParameter() {
return parameters;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Requirement other = (Requirement) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
@Override
public String toString() {
return id;
}
public RequirementType getType() {
return type;
}
}
......@@ -26,7 +26,7 @@ package de.hft.stuttgart.citydoctor2.check;
* @author Matthias Betz
*
*/
public enum CheckType {
public enum RequirementType {
GEOMETRY, SEMANTIC
......
......@@ -79,7 +79,7 @@ public class NotCeilingError implements CheckError {
@Override
public ErrorId getErrorId() {
return ErrorId.SEM_BS_NOT_CEILING;
return ErrorId.SE_BS_NOT_CEILING;
}
@Override
......
......@@ -77,7 +77,7 @@ public class NotFloorError implements CheckError {
@Override
public ErrorId getErrorId() {
return ErrorId.SEM_BS_NOT_FLOOR;
return ErrorId.SE_BS_NOT_FLOOR;
}
@Override
......
......@@ -79,7 +79,7 @@ public class NotGroundError implements CheckError {
@Override
public ErrorId getErrorId() {
return ErrorId.SEM_BS_NOT_GROUND;
return ErrorId.SE_BS_NOT_GROUND;
}
@Override
......
......@@ -82,7 +82,7 @@ public class NotWallError implements CheckError {
@Override
public ErrorId getErrorId() {
return ErrorId.SEM_BS_NOT_WALL;
return ErrorId.SE_BS_NOT_WALL;
}
@Override
......
......@@ -94,7 +94,7 @@ public class SchematronError implements CheckError {
@Override
public ErrorId getErrorId() {
return ErrorId.SEM_SCHEMATRON_ERROR;
return ErrorId.SE_SCHEMATRON_ERROR;
}
@Override
......
......@@ -77,7 +77,7 @@ public class SurfaceUnfragmentedError implements CheckError {
@Override
public ErrorId getErrorId() {
return ErrorId.SEM_BS_UNFRAGMENTED;
return ErrorId.SE_BS_UNFRAGMENTED;
}
@Override
......
......@@ -42,6 +42,10 @@ public class BoundingBox {
public static BoundingBox of(List<Polygon> polygons) {
return BoundingBoxCalculator.calculateBoundingBox(polygons);
}
public static BoundingBox ofPoints(List<? extends Vector3d> points) {
return BoundingBoxCalculator.calculateBoundingBoxFromPoints(points);
}
/**
* Creates an axis aligned bounding box of the whole model.
......
......@@ -56,6 +56,12 @@ public class CovarianceMatrix {
covValues[1][2] += ydiff * zdiff;
covValues[2][2] += zdiff * zdiff;
}
covValues[0][0] /= vertices.size();
covValues[0][1] /= vertices.size();
covValues[0][2] /= vertices.size();
covValues[1][1] /= vertices.size();
covValues[1][2] /= vertices.size();
covValues[2][2] /= vertices.size();
// the covariance matrix is symmetric, so we can fill in the remaining values
covValues[1][0] = covValues[0][1];
covValues[2][0] = covValues[0][2];
......
......@@ -135,7 +135,7 @@ public class Matrix3x3d {
/**
* Multiplies this matrix with a 3-dim vector.
*
* @param other the vector
* @param the multiplied vector
* @return the result stored in a new vector
*/
public Vector3d mult(Vector3d other) {
......
......@@ -63,17 +63,20 @@ public class BoundingBoxCalculator {
for (Vertex v : p.getExteriorRing().getVertices()) {
if (v.getX() < lowX) {
lowX = v.getX();
} else if (v.getX() > highX) {
}
if (v.getX() > highX) {
highX = v.getX();
}
if (v.getY() < lowY) {
lowY = v.getY();
} else if (v.getY() > highY) {
}
if (v.getY() > highY) {
highY = v.getY();
}
if (v.getZ() < lowZ) {
lowZ = v.getZ();
} else if (v.getZ() > highZ) {
}
if (v.getZ() > highZ) {
highZ = v.getZ();
}
}
......@@ -92,7 +95,7 @@ public class BoundingBoxCalculator {
*/
public static BoundingBox calculateBoundingBox(CityDoctorModel model) {
Vector3d low = new Vector3d(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE);
Vector3d high = new Vector3d(Double.MIN_VALUE, Double.MIN_VALUE, Double.MIN_VALUE);
Vector3d high = new Vector3d(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
findMinMax(low, high, model.getBuildings());
findMinMax(low, high, model.getBridges());
......@@ -107,6 +110,40 @@ public class BoundingBoxCalculator {
return BoundingBox.of(result);
}
public static BoundingBox calculateBoundingBoxFromPoints(List<? extends Vector3d> points) {
double lowX = Double.MAX_VALUE;
double highX = Double.NEGATIVE_INFINITY;
double lowY = Double.MAX_VALUE;
double highY = Double.NEGATIVE_INFINITY;
double lowZ = Double.MAX_VALUE;
double highZ = Double.NEGATIVE_INFINITY;
// only need to check exterior rings
for (Vector3d v : points) {
if (v.getX() < lowX) {
lowX = v.getX();
}
if (v.getX() > highX) {
highX = v.getX();
}
if (v.getY() < lowY) {
lowY = v.getY();
}
if (v.getY() > highY) {
highY = v.getY();
}
if (v.getZ() < lowZ) {
lowZ = v.getZ();
}
if (v.getZ() > highZ) {
highZ = v.getZ();
}
}
Vector3d[] result = new Vector3d[2];
result[0] = new Vector3d(lowX, lowY, lowZ);
result[1] = new Vector3d(highX, highY, highZ);
return BoundingBox.of(result);
}
private static void findMinMax(Vector3d low, Vector3d high, List<? extends CityObject> features) {
for (CityObject co : features) {
findMinMax(low, high, co);
......@@ -121,17 +158,20 @@ public class BoundingBoxCalculator {
for (Vertex v : geom.getVertices()) {
if (v.getX() < low.getX()) {
low.setX(v.getX());
} else if (v.getX() > high.getX()) {
}
if (v.getX() > high.getX()) {
high.setX(v.getX());
}
if (v.getY() < low.getY()) {
low.setY(v.getY());
} else if (v.getY() > high.getY()) {
}
if (v.getY() > high.getY()) {
high.setY(v.getY());
}
if (v.getZ() < low.getZ()) {
low.setZ(v.getZ());
} else if (v.getZ() > high.getZ()) {
}
if (v.getZ() > high.getZ()) {
high.setZ(v.getZ());
}
}
......
......@@ -241,7 +241,7 @@ public class Checker {
ValidationPlan plan = new ValidationPlan();
List<Checking> filter = createFilter();
for (Entry<CheckId, CheckConfiguration> e : config.getChecks().entrySet()) {
for (Entry<String, RequirementConfiguration> e : config.getRequirements().entrySet()) {
RequirementId reqId = mapToRequirement(e.getKey());
if (reqId == null) {
continue;
......@@ -250,12 +250,12 @@ public class Checker {
req.setName(reqId);
req.setEnabled(e.getValue().isEnabled());
plan.getRequirements().add(req);
CheckPrototype proto = Checks.getCheckPrototypeForId(e.getKey());
Map<String, String> parameters = e.getValue().getParameters();
Map<String, de.hft.stuttgart.citydoctor2.check.Requirement> reqs = Checks.getAvailableRequirements();
if (parameters != null) {
for (Entry<String, String> param : parameters.entrySet()) {
Parameter p = new Parameter();
DefaultParameter defaultP = getDefaultParameter(param.getKey(), proto);
DefaultParameter defaultP = getDefaultParameter(param.getKey(), reqs);
if (defaultP != null) {
p.setUom(defaultP.getUnitType().getGmlRepresentation());
}
......@@ -292,10 +292,14 @@ public class Checker {
return plan;
}
private DefaultParameter getDefaultParameter(String key, CheckPrototype proto) {
for (DefaultParameter param : proto.getDefaultParameter()) {
if (param.getName().equals(key)) {
return param;
private DefaultParameter getDefaultParameter(String key,
Map<String, de.hft.stuttgart.citydoctor2.check.Requirement> reqs) {
de.hft.stuttgart.citydoctor2.check.Requirement requirement = reqs.get(key);
if (requirement != null) {
for (DefaultParameter param : requirement.getDefaultParameter()) {
if (param.getName().equals(key)) {
return param;
}
}
}
return null;
......@@ -382,43 +386,10 @@ public class Checker {
}
}
private RequirementId mapToRequirement(CheckId key) {
switch (key.getName()) {
case "C_GE_R_TOO_FEW_POINTS":
return RequirementId.R_GE_R_TOO_FEW_POINTS;
case "C_GE_R_NOT_CLOSED":
return RequirementId.R_GE_R_NOT_CLOSED;
case "C_GE_R_DUPLICATE_POINT":
return RequirementId.R_GE_R_CONSECUTIVE_POINTS_SAME;
case "C_GE_R_SELF_INTERSECTION":
return RequirementId.R_GE_R_SELF_INTERSECTION;
case "C_GE_P_INTERIOR_DISCONNECTED":
return RequirementId.R_GE_P_INTERIOR_DISCONNECTED;
case "C_GE_P_INTERSECTING_RINGS":
return RequirementId.R_GE_P_INTERSECTING_RINGS;
case "C_GE_P_NON_PLANAR":
return RequirementId.R_GE_P_NON_PLANAR;
case "C_GE_S_TOO_FEW_POLYGONS":
return RequirementId.R_GE_S_TOO_FEW_POLYGONS;
case "C_GE_S_NON_MANIFOLD_EDGE":