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; ...@@ -23,6 +23,7 @@ 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.Map;
import java.util.Set;
import de.hft.stuttgart.citydoctor2.check.error.DependenciesNotMetError; import de.hft.stuttgart.citydoctor2.check.error.DependenciesNotMetError;
import de.hft.stuttgart.citydoctor2.datastructure.AbstractBuilding; import de.hft.stuttgart.citydoctor2.datastructure.AbstractBuilding;
...@@ -98,6 +99,8 @@ public abstract class Check { ...@@ -98,6 +99,8 @@ public abstract class Check {
public List<CheckId> getDependencies() { public List<CheckId> getDependencies() {
return Collections.emptyList(); return Collections.emptyList();
} }
public abstract Set<Requirement> appliesToRequirements();
/** /**
* Getter for the check id. * Getter for the check id.
...@@ -111,7 +114,7 @@ public abstract class Check { ...@@ -111,7 +114,7 @@ public abstract class Check {
* *
* @return the check type * @return the check type
*/ */
public abstract CheckType getType(); public abstract RequirementType getType();
/** /**
* Checks whether the check can be executed on this checkable, meaning the * Checks whether the check can be executed on this checkable, meaning the
......
...@@ -44,14 +44,13 @@ public class CheckId implements Serializable { ...@@ -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 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 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_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_SE_BS_IS_CEILING = new CheckId("C_SE_BS_IS_CEILING");
public static final CheckId C_SEM_BS_NOT_FLOOR = new CheckId("C_SEM_BS_NOT_FLOOR"); public static final CheckId C_SE_BS_IS_FLOOR = new CheckId("C_SE_BS_IS_FLOOR");
public static final CheckId C_SEM_BS_NOT_GROUND = new CheckId("C_SEM_BS_NOT_GROUND"); public static final CheckId C_SE_BS_IS_GROUND = new CheckId("C_SE_BS_IS_GROUND");
public static final CheckId C_SEM_F_MISSING_ID = new CheckId("C_SEM_F_MISSING_ID"); public static final CheckId C_SE_BS_GROUND_NOT_FRAGMENTED = new CheckId("C_SE_BS_GROUND_NOT_FRAGMENTED");
public static final CheckId C_SEM_BS_GROUND_NOT_FRAGMENTED = new CheckId("C_SEM_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_SEM_BS_IS_WALL = new CheckId("C_SEM_BS_IS_WALL"); public static final CheckId C_SE_SCHEMATRON = new CheckId("C_SE_SCHEMATRON");
public static final CheckId C_SEM_SCHEMATRON = new CheckId("C_SEM_SCHEMATRON"); public static final CheckId C_SE_BS_ROOF_UNFRAGMENTED = new CheckId("C_SE_BS_ROOF_UNFRAGMENTED");
public static final CheckId C_SEM_BS_ROOF_NOT_FRAGMENTED = new CheckId("C_SEM_BS_ROOF_NOT_FRAGMENTED");
public static final CheckId C_GE_S_NOT_CLOSED = new CheckId("C_GE_S_NOT_CLOSED"); 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"); 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; ...@@ -31,7 +31,7 @@ import de.hft.stuttgart.citydoctor2.datastructure.GmlId;
/** /**
* Interface to indicate that this object can be checked by Checks. * 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 { public abstract class Checkable implements Serializable {
......
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
*/ */
package de.hft.stuttgart.citydoctor2.check; package de.hft.stuttgart.citydoctor2.check;
import java.io.Serializable;
/** /**
* Describes a parameter for a check including the default value as a String. * 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, * 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; ...@@ -26,15 +28,17 @@ package de.hft.stuttgart.citydoctor2.check;
* @author Matthias Betz * @author Matthias Betz
* *
*/ */
public class DefaultParameter { public class DefaultParameter implements Serializable {
private static final long serialVersionUID = -4587211298078974066L;
private String name; private String name;
private String defaultValue; private String value;
private Unit unitType; private Unit unitType;
public DefaultParameter(String name, String defaultValue, Unit unitType) { public DefaultParameter(String name, String defaultValue, Unit unitType) {
this.name = name; this.name = name;
this.defaultValue = defaultValue; this.value = defaultValue;
this.unitType = unitType; this.unitType = unitType;
} }
...@@ -56,8 +60,8 @@ public class DefaultParameter { ...@@ -56,8 +60,8 @@ public class DefaultParameter {
* *
* @return the defaultValue * @return the defaultValue
*/ */
public String getDefaultValue() { public String getValue() {
return defaultValue; return value;
} }
/* /*
...@@ -68,10 +72,10 @@ public class DefaultParameter { ...@@ -68,10 +72,10 @@ public class DefaultParameter {
@Override @Override
public String toString() { public String toString() {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
builder.append("CheckParameter [name="); builder.append("DefaultParameter [name=");
builder.append(name); builder.append(name);
builder.append(", defaultValue="); builder.append(", value=");
builder.append(defaultValue); builder.append(value);
builder.append("]"); builder.append("]");
return builder.toString(); return builder.toString();
} }
......
...@@ -56,13 +56,12 @@ public class ErrorId implements Serializable { ...@@ -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_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_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 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 SE_BS_NOT_CEILING = new ErrorId("SE_BS_NOT_CEILING");
public static final ErrorId SEM_BS_NOT_CEILING = new ErrorId("SEM_BS_NOT_CEILING"); public static final ErrorId SE_BS_NOT_WALL = new ErrorId("SE_BS_NOT_WALL");
public static final ErrorId SEM_BS_NOT_WALL = new ErrorId("SEM_BS_NOT_WALL"); public static final ErrorId SE_BS_NOT_FLOOR = new ErrorId("SE_BS_NOT_FLOOR");
public static final ErrorId SEM_BS_NOT_FLOOR = new ErrorId("SEM_BS_NOT_FLOOR"); public static final ErrorId SE_BS_NOT_GROUND = new ErrorId("SE_BS_NOT_GROUND");
public static final ErrorId SEM_BS_NOT_GROUND = new ErrorId("SEM_BS_NOT_GROUND"); public static final ErrorId SE_SCHEMATRON_ERROR = new ErrorId("SE_SCHEMATRON_ERROR");
public static final ErrorId SEM_SCHEMATRON_ERROR = new ErrorId("SEM_SCHEMATRON_ERROR"); public static final ErrorId SE_BS_UNFRAGMENTED = new ErrorId("SE_BS_UNFRAGMENTED");
public static final ErrorId SEM_BS_UNFRAGMENTED = new ErrorId("SEM_BS_UNFRAGMENTED");
public static final ErrorId GE_P_DEGENERATED_POLYGON = new ErrorId("GE_P_DEGENERATED_POLYGON"); public static final ErrorId GE_P_DEGENERATED_POLYGON = new ErrorId("GE_P_DEGENERATED_POLYGON");
private String name; 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; ...@@ -26,7 +26,7 @@ package de.hft.stuttgart.citydoctor2.check;
* @author Matthias Betz * @author Matthias Betz
* *
*/ */
public enum CheckType { public enum RequirementType {
GEOMETRY, SEMANTIC GEOMETRY, SEMANTIC
......
...@@ -79,7 +79,7 @@ public class NotCeilingError implements CheckError { ...@@ -79,7 +79,7 @@ public class NotCeilingError implements CheckError {
@Override @Override
public ErrorId getErrorId() { public ErrorId getErrorId() {
return ErrorId.SEM_BS_NOT_CEILING; return ErrorId.SE_BS_NOT_CEILING;
} }
@Override @Override
......
...@@ -77,7 +77,7 @@ public class NotFloorError implements CheckError { ...@@ -77,7 +77,7 @@ public class NotFloorError implements CheckError {
@Override @Override
public ErrorId getErrorId() { public ErrorId getErrorId() {
return ErrorId.SEM_BS_NOT_FLOOR; return ErrorId.SE_BS_NOT_FLOOR;
} }
@Override @Override
......
...@@ -79,7 +79,7 @@ public class NotGroundError implements CheckError { ...@@ -79,7 +79,7 @@ public class NotGroundError implements CheckError {
@Override @Override
public ErrorId getErrorId() { public ErrorId getErrorId() {
return ErrorId.SEM_BS_NOT_GROUND; return ErrorId.SE_BS_NOT_GROUND;
} }
@Override @Override
......
...@@ -82,7 +82,7 @@ public class NotWallError implements CheckError { ...@@ -82,7 +82,7 @@ public class NotWallError implements CheckError {
@Override @Override
public ErrorId getErrorId() { public ErrorId getErrorId() {
return ErrorId.SEM_BS_NOT_WALL; return ErrorId.SE_BS_NOT_WALL;
} }
@Override @Override
......
...@@ -94,7 +94,7 @@ public class SchematronError implements CheckError { ...@@ -94,7 +94,7 @@ public class SchematronError implements CheckError {
@Override @Override
public ErrorId getErrorId() { public ErrorId getErrorId() {
return ErrorId.SEM_SCHEMATRON_ERROR; return ErrorId.SE_SCHEMATRON_ERROR;
} }
@Override @Override
......
...@@ -77,7 +77,7 @@ public class SurfaceUnfragmentedError implements CheckError { ...@@ -77,7 +77,7 @@ public class SurfaceUnfragmentedError implements CheckError {
@Override @Override
public ErrorId getErrorId() { public ErrorId getErrorId() {
return ErrorId.SEM_BS_UNFRAGMENTED; return ErrorId.SE_BS_UNFRAGMENTED;
} }
@Override @Override
......
...@@ -42,6 +42,10 @@ public class BoundingBox { ...@@ -42,6 +42,10 @@ public class BoundingBox {
public static BoundingBox of(List<Polygon> polygons) { public static BoundingBox of(List<Polygon> polygons) {
return BoundingBoxCalculator.calculateBoundingBox(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. * Creates an axis aligned bounding box of the whole model.
......
...@@ -56,6 +56,12 @@ public class CovarianceMatrix { ...@@ -56,6 +56,12 @@ public class CovarianceMatrix {
covValues[1][2] += ydiff * zdiff; covValues[1][2] += ydiff * zdiff;
covValues[2][2] += zdiff * 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 // the covariance matrix is symmetric, so we can fill in the remaining values
covValues[1][0] = covValues[0][1]; covValues[1][0] = covValues[0][1];
covValues[2][0] = covValues[0][2]; covValues[2][0] = covValues[0][2];
......
...@@ -135,7 +135,7 @@ public class Matrix3x3d { ...@@ -135,7 +135,7 @@ public class Matrix3x3d {
/** /**
* Multiplies this matrix with a 3-dim vector. * Multiplies this matrix with a 3-dim vector.
* *
* @param other the vector * @param the multiplied vector
* @return the result stored in a new vector * @return the result stored in a new vector
*/ */
public Vector3d mult(Vector3d other) { public Vector3d mult(Vector3d other) {
......
...@@ -63,17 +63,20 @@ public class BoundingBoxCalculator { ...@@ -63,17 +63,20 @@ public class BoundingBoxCalculator {
for (Vertex v : p.getExteriorRing().getVertices()) { for (Vertex v : p.getExteriorRing().getVertices()) {
if (v.getX() < lowX) { if (v.getX() < lowX) {
lowX = v.getX(); lowX = v.getX();
} else if (v.getX() > highX) { }
if (v.getX() > highX) {
highX = v.getX(); highX = v.getX();
} }
if (v.getY() < lowY) { if (v.getY() < lowY) {
lowY = v.getY(); lowY = v.getY();
} else if (v.getY() > highY) { }
if (v.getY() > highY) {
highY = v.getY(); highY = v.getY();
} }
if (v.getZ() < lowZ) { if (v.getZ() < lowZ) {
lowZ = v.getZ(); lowZ = v.getZ();
} else if (v.getZ() > highZ) { }
if (v.getZ() > highZ) {
highZ = v.getZ(); highZ = v.getZ();
} }
} }
...@@ -92,7 +95,7 @@ public class BoundingBoxCalculator { ...@@ -92,7 +95,7 @@ public class BoundingBoxCalculator {
*/ */
public static BoundingBox calculateBoundingBox(CityDoctorModel model) { public static BoundingBox calculateBoundingBox(CityDoctorModel model) {
Vector3d low = new Vector3d(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE); 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.getBuildings());
findMinMax(low, high, model.getBridges()); findMinMax(low, high, model.getBridges());
...@@ -107,6 +110,40 @@ public class BoundingBoxCalculator { ...@@ -107,6 +110,40 @@ public class BoundingBoxCalculator {
return BoundingBox.of(result); 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) {