Commit fb72860f authored by Numanoglu's avatar Numanoglu
Browse files

Add BVH auto usage policy

parent e7bb119d
......@@ -34,6 +34,8 @@ import de.hft.stuttgart.citydoctor2.check.RequirementType;
import de.hft.stuttgart.citydoctor2.check.Requirement;
import de.hft.stuttgart.citydoctor2.check.ResultStatus;
import de.hft.stuttgart.citydoctor2.check.error.NestedRingError;
import de.hft.stuttgart.citydoctor2.checks.util.BvhUsagePolicy;
import de.hft.stuttgart.citydoctor2.checks.util.BvhUsagePolicy.BvhCheckType;
import de.hft.stuttgart.citydoctor2.checks.util.CollectionUtils;
import de.hft.stuttgart.citydoctor2.datastructure.LinearRing;
import de.hft.stuttgart.citydoctor2.datastructure.Polygon;
......@@ -134,6 +136,10 @@ public class NestedRingsCheck extends Check {
checkWithBoundingBoxFilter(p);
} else if (variant.isBvh()) {
checkWithBvhFilter(p, variant.getSplitStrategy());
} else if (BvhUsagePolicy.shouldUseTree(BvhCheckType.NESTED_RINGS, p.getInnerRings().size())) {
SplitStrategy splitStrategy = BvhUsagePolicy.chooseSplitStrategy(
BvhCheckType.NESTED_RINGS, p.getInnerRings().size());
checkWithBvhFilter(p, splitStrategy);
} else if (p.getInnerRings().size() > 3) {
checkWithBoundingBoxFilter(p);
} else {
......
......@@ -36,6 +36,8 @@ import de.hft.stuttgart.citydoctor2.check.error.DegeneratedRingError;
import de.hft.stuttgart.citydoctor2.check.error.PointTouchesEdgeError;
import de.hft.stuttgart.citydoctor2.check.error.RingEdgeIntersectionError;
import de.hft.stuttgart.citydoctor2.checks.Checks;
import de.hft.stuttgart.citydoctor2.checks.util.BvhUsagePolicy;
import de.hft.stuttgart.citydoctor2.checks.util.BvhUsagePolicy.BvhCheckType;
import de.hft.stuttgart.citydoctor2.checks.util.CollectionUtils;
import de.hft.stuttgart.citydoctor2.datastructure.Edge;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
......@@ -89,6 +91,7 @@ public class RingSelfIntCheck extends Check {
}
public enum Variant {
AUTO,
OLD,
BVH_BINARY_OBJECT_MEDIAN(SplitStrategy.BINARY_OBJECT_MEDIAN),
BVH_BINARY_OBJECT_MEAN(SplitStrategy.BINARY_OBJECT_MEAN),
......@@ -153,6 +156,17 @@ public class RingSelfIntCheck extends Check {
checkRingOld(lr);
return;
}
if (variant == Variant.AUTO) {
int edgeCount = Math.max(0, lr.getVertices().size() - 1);
if (BvhUsagePolicy.shouldUseTree(BvhCheckType.RING_SELF_INTERSECTION, edgeCount)) {
SplitStrategy splitStrategy = BvhUsagePolicy.chooseSplitStrategy(
BvhCheckType.RING_SELF_INTERSECTION, edgeCount);
checkRingBvh(lr, splitStrategy);
} else {
checkRingOld(lr);
}
return;
}
checkRingBvh(lr, variant.getSplitStrategy());
}
......
......@@ -32,10 +32,14 @@ import de.hft.stuttgart.citydoctor2.check.Requirement;
import de.hft.stuttgart.citydoctor2.check.RequirementType;
import de.hft.stuttgart.citydoctor2.check.ResultStatus;
import de.hft.stuttgart.citydoctor2.check.error.SolidSelfIntError;
import de.hft.stuttgart.citydoctor2.checks.util.BvhUsagePolicy;
import de.hft.stuttgart.citydoctor2.checks.util.BvhUsagePolicy.BvhCheckType;
import de.hft.stuttgart.citydoctor2.checks.util.CollectionUtils;
import de.hft.stuttgart.citydoctor2.checks.util.SelfIntersectionUtil;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
import de.hft.stuttgart.citydoctor2.datastructure.GeometryType;
import de.hft.stuttgart.citydoctor2.datastructure.bht.BoundingVolumeHierarchyTree;
import de.hft.stuttgart.citydoctor2.datastructure.bht.SplitStrategy;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.utils.PolygonIntersection;
......@@ -50,6 +54,39 @@ public class SolidSelfIntCheck extends Check {
private static final List<CheckId> dependencies;
private double delta = 0.01;
private Variant variant = Variant.OLD;
public enum Variant {
AUTO,
OLD,
BVH_BINARY_OBJECT_MEDIAN(SplitStrategy.BINARY_OBJECT_MEDIAN),
BVH_BINARY_OBJECT_MEAN(SplitStrategy.BINARY_OBJECT_MEAN),
BVH_BINARY_SPATIAL_MEDIAN(SplitStrategy.BINARY_SPATIAL_MEDIAN),
BVH_OCTONARY_OBJECT_MEDIAN(SplitStrategy.OCTONARY_OBJECT_MEDIAN),
BVH_OCTONARY_OBJECT_MEAN(SplitStrategy.OCTONARY_OBJECT_MEAN),
BVH_OCTONARY_SPATIAL_MEDIAN(SplitStrategy.OCTONARY_SPATIAL_MEDIAN);
private final SplitStrategy splitStrategy;
Variant() {
this.splitStrategy = null;
}
Variant(SplitStrategy splitStrategy) {
this.splitStrategy = splitStrategy;
}
public boolean isBvh() {
return splitStrategy != null;
}
public SplitStrategy getSplitStrategy() {
if (splitStrategy == null) {
throw new IllegalStateException("Variant " + this + " has no BVH split strategy.");
}
return splitStrategy;
}
}
static {
ArrayList<CheckId> deps = new ArrayList<>();
......@@ -79,14 +116,28 @@ public class SolidSelfIntCheck extends Check {
}
}
public SolidSelfIntCheck() {
}
public SolidSelfIntCheck(Variant variant) {
this.variant = variant;
}
public void setVariant(Variant variant) {
this.variant = variant;
}
public Variant getVariant() {
return variant;
}
@Override
public void check(Geometry g) {
if (g.getType() != GeometryType.SOLID && g.getType() != GeometryType.COMPOSITE_SURFACE) {
return;
}
CheckResult cr;
// TODO: reproduce older version by Mathias of calculateSolidSefInt to compare
List<PolygonIntersection> intersections = SelfIntersectionUtil.calculateSolidSelfIntersection(g, delta);
List<PolygonIntersection> intersections = calculateIntersections(g);
if (intersections.isEmpty()) {
cr = new CheckResult(this, ResultStatus.OK, null);
} else {
......@@ -96,6 +147,36 @@ public class SolidSelfIntCheck extends Check {
g.addCheckResult(cr);
}
private List<PolygonIntersection> calculateIntersections(Geometry g) {
if (variant == Variant.OLD) {
return SelfIntersectionUtil.calculateSolidSelfIntersection(g, delta);
}
if (variant.isBvh()) {
return calculateIntersectionsWithTree(g, variant.getSplitStrategy());
}
int polygonCount = g.getPolygons().size();
if (!BvhUsagePolicy.shouldUseTree(BvhCheckType.SOLID_SELF_INTERSECTION, polygonCount)) {
return SelfIntersectionUtil.calculateSolidSelfIntersection(g, delta);
}
SplitStrategy splitStrategy = BvhUsagePolicy.chooseSplitStrategy(
BvhCheckType.SOLID_SELF_INTERSECTION, polygonCount);
return calculateIntersectionsWithTree(g, splitStrategy);
}
private List<PolygonIntersection> calculateIntersectionsWithTree(Geometry g, SplitStrategy splitStrategy) {
BoundingVolumeHierarchyTree.Builder<Integer> treeConfig = BoundingVolumeHierarchyTree.<Integer>builder()
.degree(isBinary(splitStrategy) ? 2 : 8)
.splitStrategy(splitStrategy);
return SelfIntersectionUtil.calculateSolidSelfIntersectionWithTree(g, delta, treeConfig);
}
private static boolean isBinary(SplitStrategy splitStrategy) {
return splitStrategy == SplitStrategy.BINARY_OBJECT_MEDIAN
|| splitStrategy == SplitStrategy.BINARY_OBJECT_MEAN
|| splitStrategy == SplitStrategy.BINARY_SPATIAL_MEDIAN;
}
@Override
public List<CheckId> getDependencies() {
return dependencies;
......@@ -113,7 +194,7 @@ public class SolidSelfIntCheck extends Check {
@Override
public Check createNewInstance() {
return new SolidSelfIntCheck();
return new SolidSelfIntCheck(variant);
}
@Override
......
package de.hft.stuttgart.citydoctor2.checks.util;
import de.hft.stuttgart.citydoctor2.datastructure.bht.SplitStrategy;
/**
* Central policy for cheap BVH decisions in geometry checks.
*/
public final class BvhUsagePolicy {
private static final int SOLID_SELF_INTERSECTION_TREE_THRESHOLD = 16;
private static final int NESTED_RINGS_TREE_THRESHOLD = 8;
private static final int RING_SELF_INTERSECTION_TREE_THRESHOLD = 32;
private BvhUsagePolicy() {
}
public enum BvhCheckType {
SOLID_SELF_INTERSECTION,
NESTED_RINGS,
RING_SELF_INTERSECTION
}
public static boolean shouldUseTree(BvhCheckType checkType, int elementCount) {
if (elementCount < 2) {
return false;
}
return elementCount >= thresholdFor(checkType);
}
public static SplitStrategy chooseSplitStrategy(BvhCheckType checkType, int elementCount) {
if (checkType == BvhCheckType.RING_SELF_INTERSECTION) {
return SplitStrategy.BINARY_SPATIAL_MEDIAN;
}
if (elementCount >= 128) {
return SplitStrategy.OCTONARY_OBJECT_MEAN;
}
return SplitStrategy.BINARY_SPATIAL_MEDIAN;
}
private static int thresholdFor(BvhCheckType checkType) {
switch (checkType) {
case SOLID_SELF_INTERSECTION:
return SOLID_SELF_INTERSECTION_TREE_THRESHOLD;
case NESTED_RINGS:
return NESTED_RINGS_TREE_THRESHOLD;
case RING_SELF_INTERSECTION:
return RING_SELF_INTERSECTION_TREE_THRESHOLD;
default:
throw new IllegalArgumentException("Unsupported BVH check type: " + checkType);
}
}
}
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