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; ...@@ -34,6 +34,8 @@ 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.NestedRingError; 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.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;
...@@ -134,6 +136,10 @@ public class NestedRingsCheck extends Check { ...@@ -134,6 +136,10 @@ public class NestedRingsCheck extends Check {
checkWithBoundingBoxFilter(p); checkWithBoundingBoxFilter(p);
} else if (variant.isBvh()) { } else if (variant.isBvh()) {
checkWithBvhFilter(p, variant.getSplitStrategy()); 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) { } else if (p.getInnerRings().size() > 3) {
checkWithBoundingBoxFilter(p); checkWithBoundingBoxFilter(p);
} else { } else {
......
...@@ -36,6 +36,8 @@ import de.hft.stuttgart.citydoctor2.check.error.DegeneratedRingError; ...@@ -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.PointTouchesEdgeError;
import de.hft.stuttgart.citydoctor2.check.error.RingEdgeIntersectionError; import de.hft.stuttgart.citydoctor2.check.error.RingEdgeIntersectionError;
import de.hft.stuttgart.citydoctor2.checks.Checks; 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.checks.util.CollectionUtils;
import de.hft.stuttgart.citydoctor2.datastructure.Edge; import de.hft.stuttgart.citydoctor2.datastructure.Edge;
import de.hft.stuttgart.citydoctor2.datastructure.Geometry; import de.hft.stuttgart.citydoctor2.datastructure.Geometry;
...@@ -89,6 +91,7 @@ public class RingSelfIntCheck extends Check { ...@@ -89,6 +91,7 @@ public class RingSelfIntCheck extends Check {
} }
public enum Variant { public enum Variant {
AUTO,
OLD, OLD,
BVH_BINARY_OBJECT_MEDIAN(SplitStrategy.BINARY_OBJECT_MEDIAN), BVH_BINARY_OBJECT_MEDIAN(SplitStrategy.BINARY_OBJECT_MEDIAN),
BVH_BINARY_OBJECT_MEAN(SplitStrategy.BINARY_OBJECT_MEAN), BVH_BINARY_OBJECT_MEAN(SplitStrategy.BINARY_OBJECT_MEAN),
...@@ -153,6 +156,17 @@ public class RingSelfIntCheck extends Check { ...@@ -153,6 +156,17 @@ public class RingSelfIntCheck extends Check {
checkRingOld(lr); checkRingOld(lr);
return; 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()); checkRingBvh(lr, variant.getSplitStrategy());
} }
......
...@@ -32,10 +32,14 @@ import de.hft.stuttgart.citydoctor2.check.Requirement; ...@@ -32,10 +32,14 @@ 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;
import de.hft.stuttgart.citydoctor2.check.error.SolidSelfIntError; 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.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.datastructure.bht.BoundingVolumeHierarchyTree;
import de.hft.stuttgart.citydoctor2.datastructure.bht.SplitStrategy;
import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration;
import de.hft.stuttgart.citydoctor2.utils.PolygonIntersection; import de.hft.stuttgart.citydoctor2.utils.PolygonIntersection;
...@@ -50,6 +54,39 @@ public class SolidSelfIntCheck extends Check { ...@@ -50,6 +54,39 @@ public class SolidSelfIntCheck extends Check {
private static final List<CheckId> dependencies; private static final List<CheckId> dependencies;
private double delta = 0.01; 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 { static {
ArrayList<CheckId> deps = new ArrayList<>(); ArrayList<CheckId> deps = new ArrayList<>();
...@@ -79,14 +116,28 @@ public class SolidSelfIntCheck extends Check { ...@@ -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 @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;
// TODO: reproduce older version by Mathias of calculateSolidSefInt to compare List<PolygonIntersection> intersections = calculateIntersections(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 {
...@@ -96,6 +147,36 @@ public class SolidSelfIntCheck extends Check { ...@@ -96,6 +147,36 @@ public class SolidSelfIntCheck extends Check {
g.addCheckResult(cr); 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 @Override
public List<CheckId> getDependencies() { public List<CheckId> getDependencies() {
return dependencies; return dependencies;
...@@ -113,7 +194,7 @@ public class SolidSelfIntCheck extends Check { ...@@ -113,7 +194,7 @@ public class SolidSelfIntCheck extends Check {
@Override @Override
public Check createNewInstance() { public Check createNewInstance() {
return new SolidSelfIntCheck(); return new SolidSelfIntCheck(variant);
} }
@Override @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