Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
CityDoctor
CityDoctor2
Commits
e6f4979d
Commit
e6f4979d
authored
Apr 28, 2026
by
Numanoglu
Browse files
Add BVH variants and validation tests
parent
54c56f2d
Changes
25
Hide whitespace changes
Inline
Side-by-side
CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/checks/bht/SolidSelfIntersectionBvhVariantsSyntheticTest.java
0 → 100644
View file @
e6f4979d
package
de.hft.stuttgart.citydoctor2.checks.bht
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertNotNull
;
import
java.util.HashMap
;
import
java.util.HashSet
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Set
;
import
org.junit.jupiter.api.Test
;
import
de.hft.stuttgart.citydoctor2.datastructure.Geometry
;
import
de.hft.stuttgart.citydoctor2.datastructure.Lod
;
import
de.hft.stuttgart.citydoctor2.datastructure.Polygon
;
import
de.hft.stuttgart.citydoctor2.datastructure.bht.AABB
;
import
de.hft.stuttgart.citydoctor2.datastructure.bht.BoundingVolumeHierarchyTree
;
import
de.hft.stuttgart.citydoctor2.datastructure.bht.SplitStrategy
;
import
de.hft.stuttgart.citydoctor2.checks.util.SelfIntersectionUtil
;
import
de.hft.stuttgart.citydoctor2.utils.PolygonIntersection
;
public
class
SolidSelfIntersectionBvhVariantsSyntheticTest
{
private
static
final
double
DELTA
=
0.001
;
@Test
public
void
allBvhVariantsMatchBruteForceOnSeparatedGrid
()
{
Geometry
geometry
=
SyntheticSolidGeometryFactory
.
separatedBoxGrid
(
Lod
.
LOD2
,
6
,
6
);
assertAllVariantsMatchBruteForce
(
geometry
,
"separated grid"
);
}
@Test
public
void
allBvhVariantsMatchBruteForceOnOverlappingGrid
()
{
Geometry
geometry
=
SyntheticSolidGeometryFactory
.
overlappingBoxGrid
(
Lod
.
LOD2
,
6
,
6
);
assertAllVariantsMatchBruteForce
(
geometry
,
"overlapping grid"
);
}
@Test
public
void
allBvhVariantsMatchBruteForceOnDenseClusters
()
{
Geometry
geometry
=
SyntheticSolidGeometryFactory
.
denseBoxClusters
(
Lod
.
LOD2
,
4
,
12
);
assertAllVariantsMatchBruteForce
(
geometry
,
"dense clusters"
);
}
@Test
public
void
allBvhVariantsMatchBruteForceOnLongThinSlabs
()
{
Geometry
geometry
=
SyntheticSolidGeometryFactory
.
longThinSlabs
(
Lod
.
LOD2
,
40
);
assertAllVariantsMatchBruteForce
(
geometry
,
"long thin slabs"
);
}
@Test
public
void
allBvhVariantsMatchBruteForceOnFlatBoxGrid
()
{
Geometry
geometry
=
SyntheticSolidGeometryFactory
.
flatBoxGrid
(
Lod
.
LOD2
,
50
);
assertAllVariantsMatchBruteForce
(
geometry
,
"flat box grid"
);
}
private
static
void
assertAllVariantsMatchBruteForce
(
Geometry
geometry
,
String
scenario
)
{
assertNotNull
(
"Expected geometry for "
+
scenario
,
geometry
);
List
<
Polygon
>
polygons
=
geometry
.
getPolygons
();
assertNotNull
(
"Expected polygons for "
+
scenario
,
polygons
);
List
<
PolygonIntersection
>
bruteForce
=
SelfIntersectionUtil
.
calculateSolidSelfIntersection0
(
geometry
,
DELTA
);
assertNotNull
(
"Expected brute-force result for "
+
scenario
,
bruteForce
);
Set
<
String
>
bruteForcePolygonPairs
=
polygonPairKeys
(
polygons
,
bruteForce
);
for
(
SplitStrategy
strategy
:
concreteStrategies
())
{
BoundingVolumeHierarchyTree
<
Polygon
>
tree
=
BoundingVolumeHierarchyTree
.
newWithStrategy
(
polygons
,
p
->
AABB
.
of
(
p
.
getOriginal
()),
strategy
);
List
<
PolygonIntersection
>
withTree
=
SelfIntersectionUtil
.
calculateSolidSelfIntersection
(
geometry
,
DELTA
,
tree
);
assertNotNull
(
"Expected BVH result for "
+
scenario
+
" / "
+
strategy
,
withTree
);
assertEquals
(
"BVH result count differs from brute force for "
+
scenario
+
" / "
+
strategy
,
bruteForce
.
size
(),
withTree
.
size
());
assertEquals
(
"BVH polygon pairs differ from brute force for "
+
scenario
+
" / "
+
strategy
,
bruteForcePolygonPairs
,
polygonPairKeys
(
polygons
,
withTree
));
}
}
private
static
Set
<
String
>
polygonPairKeys
(
List
<
Polygon
>
polygons
,
List
<
PolygonIntersection
>
intersections
)
{
Map
<
Polygon
,
Integer
>
polygonIds
=
new
HashMap
<>();
for
(
int
i
=
0
;
i
<
polygons
.
size
();
i
++)
{
polygonIds
.
put
(
polygons
.
get
(
i
),
i
);
polygonIds
.
put
(
polygons
.
get
(
i
).
getOriginal
(),
i
);
}
Set
<
String
>
polygonPairs
=
new
HashSet
<>();
for
(
PolygonIntersection
intersection
:
intersections
)
{
polygonPairs
.
add
(
polygonPairKey
(
polygonIds
,
intersection
));
}
return
polygonPairs
;
}
private
static
String
polygonPairKey
(
Map
<
Polygon
,
Integer
>
polygonIds
,
PolygonIntersection
intersection
)
{
int
p1
=
polygonIndex
(
polygonIds
,
intersection
.
getP1
());
int
p2
=
polygonIndex
(
polygonIds
,
intersection
.
getP2
());
if
(
p1
<=
p2
)
{
return
p1
+
"|"
+
p2
;
}
return
p2
+
"|"
+
p1
;
}
private
static
int
polygonIndex
(
Map
<
Polygon
,
Integer
>
polygonIds
,
Polygon
polygon
)
{
Integer
id
=
polygonIds
.
get
(
polygon
);
if
(
id
==
null
)
{
throw
new
AssertionError
(
"Intersection references a polygon outside the tested geometry: "
+
polygon
);
}
return
id
;
}
private
static
SplitStrategy
[]
concreteStrategies
()
{
return
new
SplitStrategy
[]
{
SplitStrategy
.
BINARY_OBJECT_MEDIAN
,
SplitStrategy
.
BINARY_OBJECT_MEAN
,
SplitStrategy
.
BINARY_SPATIAL_MEDIAN
,
SplitStrategy
.
OCTONARY_OBJECT_MEDIAN
,
SplitStrategy
.
OCTONARY_OBJECT_MEAN
,
SplitStrategy
.
OCTONARY_SPATIAL_MEDIAN
};
}
}
CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/checks/bht/SolidSelfIntersectionOldVsNewTest.java
0 → 100644
View file @
e6f4979d
package
de.hft.stuttgart.citydoctor2.checks.bht
;
import
static
org
.
junit
.
Assert
.*;
import
java.util.List
;
import
org.junit.jupiter.api.Test
;
import
de.hft.stuttgart.citydoctor2.check.ValidationConfiguration
;
import
de.hft.stuttgart.citydoctor2.datastructure.Building
;
import
de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel
;
import
de.hft.stuttgart.citydoctor2.datastructure.Geometry
;
import
de.hft.stuttgart.citydoctor2.datastructure.GeometryType
;
import
de.hft.stuttgart.citydoctor2.datastructure.Lod
;
import
de.hft.stuttgart.citydoctor2.datastructure.Polygon
;
import
de.hft.stuttgart.citydoctor2.parser.CityGmlParseException
;
import
de.hft.stuttgart.citydoctor2.parser.CityGmlParser
;
import
de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException
;
import
de.hft.stuttgart.citydoctor2.checks.util.SelfIntersectionUtil
;
import
de.hft.stuttgart.citydoctor2.utils.PolygonIntersection
;
import
de.hft.stuttgart.citydoctor2.datastructure.bht.AABB
;
import
de.hft.stuttgart.citydoctor2.datastructure.bht.BoundingVolumeHierarchyTree
;
/*
* First comparison SolidSelfIntersection version with Bounding Volume Tree vs old version
*
* @ Baris Numanoglu
* */
public
class
SolidSelfIntersectionOldVsNewTest
{
// @Test
// public void testOldVsNewSameResultCount() throws CityGmlParseException, InvalidGmlFileException {
// compareOnFile("src/test/resources/SolidSelfIntTest-known_false_positive_Big_Mesh2.gml", 0.001);
// }// dubious Test data: may be TP and not FP?
//
// @Test
// public void testOldVsNewSameResultCountFalsePositiveExample1() throws CityGmlParseException, InvalidGmlFileException {
// compareOnFile("src/test/resources/SolidSelfIntTest-known_false_positive1.gml", 0.001);
// }
@Test
public
void
testOldVsNewSameResultCountFalsePositiveExample2
()
throws
CityGmlParseException
,
InvalidGmlFileException
{
compareOnFile
(
"src/test/resources/SolidSelfIntTest-known_false_positive2.gml"
,
0.001
);
}
private
void
compareOnFile
(
String
gmlPath
,
double
delta
)
throws
CityGmlParseException
,
InvalidGmlFileException
{
ValidationConfiguration
config
=
ValidationConfiguration
.
loadStandardValidationConfig
();
config
.
setSchematronFilePathInGlobalParameters
(
null
);
CityDoctorModel
m
=
CityGmlParser
.
parseCityGmlFile
(
gmlPath
,
config
.
getParserConfiguration
());
Building
building
=
m
.
getBuildings
().
findFirst
().
orElseThrow
();
Geometry
g
=
building
.
getGeometry
(
GeometryType
.
SOLID
,
Lod
.
LOD2
);
assertNotNull
(
"Expected SOLID LOD2 geometry in test model: "
+
gmlPath
,
g
);
List
<
Polygon
>
polys
=
g
.
getPolygons
();
assertNotNull
(
polys
);
assertTrue
(
"Expected at least 2 polygons in: "
+
gmlPath
,
polys
.
size
()
>
1
);
/// Without Tree
long
start
=
System
.
nanoTime
();
List
<
PolygonIntersection
>
oldRes
=
SelfIntersectionUtil
.
calculateSolidSelfIntersection0
(
g
,
delta
);
long
dif
=
System
.
nanoTime
()
-
start
;
System
.
out
.
println
(
"Alt: "
+
dif
);
/// With IdentityHashMap
start
=
System
.
nanoTime
();
BoundingVolumeHierarchyTree
<
Polygon
>
polygonTree
=
BoundingVolumeHierarchyTree
.
newBinary
(
g
.
getPolygons
(),
p
->
AABB
.
of
(
p
.
getOriginal
())
);
List
<
PolygonIntersection
>
oldTreeRes
=
SelfIntersectionUtil
.
calculateSolidSelfIntersection
(
g
,
delta
,
polygonTree
);
dif
=
System
.
nanoTime
()
-
start
;
System
.
out
.
println
(
"Alt + external polygon tree: "
+
dif
);
/// With Polygon Indices
start
=
System
.
nanoTime
();
List
<
PolygonIntersection
>
newRes
=
SelfIntersectionUtil
.
calculateSolidSelfIntersectionWithTree
(
g
,
delta
);
dif
=
System
.
nanoTime
()
-
start
;
System
.
out
.
println
(
"Neu: "
+
dif
);
///
System
.
out
.
println
(
"oldRes.size() = "
+
oldRes
.
size
());
System
.
out
.
println
(
"oldTreeRes.size() = "
+
oldTreeRes
.
size
());
System
.
out
.
println
(
"newRes.size() = "
+
newRes
.
size
());
assertFalse
(
"oldRes is empty for: "
+
gmlPath
,
oldRes
.
isEmpty
());
assertFalse
(
"oldTreeRes is empty for: "
+
gmlPath
,
oldTreeRes
.
isEmpty
());
assertFalse
(
"newRes is empty for: "
+
gmlPath
,
newRes
.
isEmpty
());
assertEquals
(
"Old vs oldTree differs for: "
+
gmlPath
,
oldRes
.
size
(),
oldTreeRes
.
size
());
assertEquals
(
"Old vs new self-intersection result count differs for: "
+
gmlPath
,
oldRes
.
size
(),
newRes
.
size
());
}
}
CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/checks/bht/SyntheticNestedRingGeometryFactory.java
0 → 100644
View file @
e6f4979d
package
de.hft.stuttgart.citydoctor2.checks.bht
;
import
java.util.ArrayList
;
import
java.util.List
;
import
de.hft.stuttgart.citydoctor2.datastructure.ConcretePolygon
;
import
de.hft.stuttgart.citydoctor2.datastructure.Geometry
;
import
de.hft.stuttgart.citydoctor2.datastructure.Geometry.Orientation
;
import
de.hft.stuttgart.citydoctor2.datastructure.GeometryType
;
import
de.hft.stuttgart.citydoctor2.datastructure.LinearRing
;
import
de.hft.stuttgart.citydoctor2.datastructure.LinearRing.LinearRingType
;
import
de.hft.stuttgart.citydoctor2.datastructure.Lod
;
import
de.hft.stuttgart.citydoctor2.datastructure.Vertex
;
/**
* Test-fixture factory
* for polygons with many interior rings used by nested-ring BVH comparison tests.
*
*
* Scenarios:
* - manyDisjointInnerRings:
* many spatially separated holes;
* expected to be the best case for BVH candidate pruning.
*
* - oneNestedPairAmongMany:
* one true nested pair hidden among many unrelated rings;
* useful for correctness and selectivity checks.
*
* - concentricNestedRings:
* many rings around the same center;
* expected worst case because most AABBs overlap or contain each other.
*
* - overlappingAabbsButNotNested:
* rings whose boxes overlap while the rings are not contained;
* stresses the broad phase without creating true errors.
*
* - clusteredInnerRings:
* several local groups of rings;
* useful as a realistic middle ground between disjoint and fully overlapping data.
*
* - complexNestedRingGeometry:
* combines all scenarios in one Geometry so correctness tests can compare
* BVH variants across easy, selective, noisy, clustered, and worst-case inputs.
*
* @author Numanoglu
*/
final
class
SyntheticNestedRingGeometryFactory
{
private
SyntheticNestedRingGeometryFactory
()
{
}
static
Geometry
complexNestedRingGeometry
()
{
Geometry
geometry
=
new
Geometry
(
GeometryType
.
SOLID
,
Lod
.
LOD2
,
Orientation
.
OUTWARD
);
for
(
ConcretePolygon
polygon
:
complexNestedRingPolygons
())
{
geometry
.
addPolygon
(
polygon
);
}
geometry
.
updateEdgesAndVertices
();
return
geometry
;
}
static
List
<
ConcretePolygon
>
complexNestedRingPolygons
()
{
List
<
ConcretePolygon
>
polygons
=
new
ArrayList
<>();
polygons
.
add
(
manyDisjointInnerRings
(
100
));
polygons
.
add
(
oneNestedPairAmongMany
(
96
));
polygons
.
add
(
concentricNestedRings
(
32
));
polygons
.
add
(
overlappingAabbsButNotNested
(
96
));
polygons
.
add
(
clusteredInnerRings
(
9
,
12
));
polygons
.
add
(
clusteredInnerRingsWithNestedPair
(
9
,
12
));
return
polygons
;
}
static
ConcretePolygon
manyDisjointInnerRings
(
int
count
)
{
ConcretePolygon
polygon
=
basePolygon
(
count
);
for
(
int
i
=
0
;
i
<
count
;
i
++)
{
double
x
=
gridX
(
i
,
10
)
*
8.0
+
4.0
;
double
y
=
gridY
(
i
,
10
)
*
8.0
+
4.0
;
polygon
.
addInteriorRing
(
squareRing
(
x
,
y
,
1.0
));
}
return
polygon
;
}
static
ConcretePolygon
oneNestedPairAmongMany
(
int
count
)
{
ConcretePolygon
polygon
=
manyDisjointInnerRings
(
Math
.
max
(
0
,
count
-
2
));
polygon
.
addInteriorRing
(
squareRing
(
5.0
,
85.0
,
5.0
));
polygon
.
addInteriorRing
(
squareRing
(
5.0
,
85.0
,
1.0
));
return
polygon
;
}
static
ConcretePolygon
concentricNestedRings
(
int
count
)
{
ConcretePolygon
polygon
=
basePolygon
(
count
);
for
(
int
i
=
0
;
i
<
count
;
i
++)
{
double
halfSize
=
Math
.
max
(
1.0
,
count
-
i
);
polygon
.
addInteriorRing
(
squareRing
(
50.0
,
50.0
,
halfSize
));
}
return
polygon
;
}
static
ConcretePolygon
overlappingAabbsButNotNested
(
int
count
)
{
ConcretePolygon
polygon
=
basePolygon
(
count
);
for
(
int
i
=
0
;
i
<
count
;
i
++)
{
double
x
=
6.0
+
(
i
%
12
)
*
6.0
;
double
y
=
6.0
+
(
i
/
12
)
*
6.0
;
double
skew
=
i
%
2
==
0
?
1.5
:
-
1.5
;
polygon
.
addInteriorRing
(
diamondRing
(
x
+
skew
,
y
,
2.4
,
1.0
));
}
return
polygon
;
}
static
ConcretePolygon
clusteredInnerRings
(
int
clusterCount
,
int
ringsPerCluster
)
{
ConcretePolygon
polygon
=
basePolygon
(
clusterCount
*
ringsPerCluster
);
for
(
int
cluster
=
0
;
cluster
<
clusterCount
;
cluster
++)
{
double
clusterX
=
8.0
+
(
cluster
%
4
)
*
22.0
;
double
clusterY
=
8.0
+
(
cluster
/
4
)
*
22.0
;
for
(
int
i
=
0
;
i
<
ringsPerCluster
;
i
++)
{
double
offsetX
=
(
i
%
5
)
*
2.5
;
double
offsetY
=
(
i
/
5
)
*
2.5
;
polygon
.
addInteriorRing
(
squareRing
(
clusterX
+
offsetX
,
clusterY
+
offsetY
,
0.8
));
}
}
return
polygon
;
}
static
ConcretePolygon
clusteredInnerRingsWithNestedPair
(
int
clusterCount
,
int
ringsPerCluster
)
{
ConcretePolygon
polygon
=
clusteredInnerRings
(
clusterCount
,
ringsPerCluster
);
polygon
.
addInteriorRing
(
squareRing
(
88.0
,
88.0
,
5.0
));
polygon
.
addInteriorRing
(
squareRing
(
88.0
,
88.0
,
1.0
));
return
polygon
;
}
private
static
ConcretePolygon
basePolygon
(
int
expectedInnerRingCount
)
{
double
extent
=
Math
.
max
(
120.0
,
Math
.
ceil
(
Math
.
sqrt
(
Math
.
max
(
1
,
expectedInnerRingCount
)))
*
10.0
+
20.0
);
ConcretePolygon
polygon
=
new
ConcretePolygon
();
polygon
.
setExteriorRing
(
rectangleRing
(
0.0
,
0.0
,
extent
,
extent
,
LinearRingType
.
EXTERIOR
));
return
polygon
;
}
private
static
double
gridX
(
int
index
,
int
columns
)
{
return
index
%
columns
;
}
private
static
double
gridY
(
int
index
,
int
columns
)
{
return
index
/
columns
;
}
private
static
LinearRing
squareRing
(
double
centerX
,
double
centerY
,
double
halfSize
)
{
return
rectangleRing
(
centerX
-
halfSize
,
centerY
-
halfSize
,
centerX
+
halfSize
,
centerY
+
halfSize
,
LinearRingType
.
INTERIOR
);
}
private
static
LinearRing
rectangleRing
(
double
minX
,
double
minY
,
double
maxX
,
double
maxY
,
LinearRingType
type
)
{
LinearRing
ring
=
new
LinearRing
(
type
);
Vertex
v0
=
new
Vertex
(
minX
,
minY
,
0.0
);
Vertex
v1
=
new
Vertex
(
maxX
,
minY
,
0.0
);
Vertex
v2
=
new
Vertex
(
maxX
,
maxY
,
0.0
);
Vertex
v3
=
new
Vertex
(
minX
,
maxY
,
0.0
);
ring
.
addVertex
(
v0
);
ring
.
addVertex
(
v1
);
ring
.
addVertex
(
v2
);
ring
.
addVertex
(
v3
);
ring
.
addVertex
(
v0
);
return
ring
;
}
private
static
LinearRing
diamondRing
(
double
centerX
,
double
centerY
,
double
radiusX
,
double
radiusY
)
{
LinearRing
ring
=
new
LinearRing
(
LinearRingType
.
INTERIOR
);
Vertex
v0
=
new
Vertex
(
centerX
,
centerY
-
radiusY
,
0.0
);
Vertex
v1
=
new
Vertex
(
centerX
+
radiusX
,
centerY
,
0.0
);
Vertex
v2
=
new
Vertex
(
centerX
,
centerY
+
radiusY
,
0.0
);
Vertex
v3
=
new
Vertex
(
centerX
-
radiusX
,
centerY
,
0.0
);
ring
.
addVertex
(
v0
);
ring
.
addVertex
(
v1
);
ring
.
addVertex
(
v2
);
ring
.
addVertex
(
v3
);
ring
.
addVertex
(
v0
);
return
ring
;
}
}
CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/checks/bht/SyntheticSolidGeometryFactory.java
0 → 100644
View file @
e6f4979d
package
de.hft.stuttgart.citydoctor2.checks.bht
;
import
de.hft.stuttgart.citydoctor2.datastructure.ConcretePolygon
;
import
de.hft.stuttgart.citydoctor2.datastructure.Geometry
;
import
de.hft.stuttgart.citydoctor2.datastructure.Geometry.Orientation
;
import
de.hft.stuttgart.citydoctor2.datastructure.GeometryType
;
import
de.hft.stuttgart.citydoctor2.datastructure.LinearRing
;
import
de.hft.stuttgart.citydoctor2.datastructure.LinearRing.LinearRingType
;
import
de.hft.stuttgart.citydoctor2.datastructure.Lod
;
import
de.hft.stuttgart.citydoctor2.datastructure.Vertex
;
/**
* Test-fixture-factory for Synthetic Solid Geometries used by BVH comparisons.
*
* Provides separated grids, intentionally overlapping grids,
* dense local clusters, long thin slabs and almost-flat boxes
* to cover different broad-phase selectivity and split-strategy stress cases.
*
* @author Numanoglu
*/
final
class
SyntheticSolidGeometryFactory
{
private
SyntheticSolidGeometryFactory
()
{
}
static
Geometry
separatedBoxGrid
(
Lod
lod
,
int
xCount
,
int
yCount
)
{
Geometry
geometry
=
newSolid
(
lod
);
double
spacing
=
6.0
;
for
(
int
ix
=
0
;
ix
<
xCount
;
ix
++)
{
for
(
int
iy
=
0
;
iy
<
yCount
;
iy
++)
{
addBox
(
geometry
,
ix
*
spacing
,
iy
*
spacing
,
0.0
,
4.0
,
4.0
,
4.0
);
}
}
geometry
.
updateEdgesAndVertices
();
return
geometry
;
}
static
Geometry
overlappingBoxGrid
(
Lod
lod
,
int
xCount
,
int
yCount
)
{
Geometry
geometry
=
separatedBoxGrid
(
lod
,
xCount
,
yCount
);
addBox
(
geometry
,
6.0
,
6.0
,
0.5
,
6.0
,
2.8
,
3.5
);
addBox
(
geometry
,
8.0
,
5.5
,
0.0
,
2.8
,
6.0
,
4.2
);
geometry
.
updateEdgesAndVertices
();
return
geometry
;
}
static
Geometry
denseBoxClusters
(
Lod
lod
,
int
clusterCount
,
int
boxesPerCluster
)
{
Geometry
geometry
=
newSolid
(
lod
);
double
clusterSpacing
=
30.0
;
for
(
int
cluster
=
0
;
cluster
<
clusterCount
;
cluster
++)
{
double
baseX
=
cluster
*
clusterSpacing
;
double
baseY
=
(
cluster
%
2
)
*
clusterSpacing
;
for
(
int
i
=
0
;
i
<
boxesPerCluster
;
i
++)
{
double
offset
=
i
*
1.15
;
addBox
(
geometry
,
baseX
+
offset
,
baseY
+
offset
*
0.5
,
0.0
,
3.0
,
3.0
,
3.0
);
}
}
geometry
.
updateEdgesAndVertices
();
return
geometry
;
}
static
Geometry
longThinSlabs
(
Lod
lod
,
int
count
)
{
Geometry
geometry
=
newSolid
(
lod
);
for
(
int
i
=
0
;
i
<
count
;
i
++)
{
double
y
=
i
*
0.75
;
addBox
(
geometry
,
0.0
,
y
,
0.0
,
40.0
,
0.25
,
1.0
);
}
geometry
.
updateEdgesAndVertices
();
return
geometry
;
}
static
Geometry
flatBoxGrid
(
Lod
lod
,
int
count
)
{
Geometry
geometry
=
newSolid
(
lod
);
for
(
int
i
=
0
;
i
<
count
;
i
++)
{
double
x
=
(
i
%
10
)
*
5.0
;
double
y
=
(
i
/
10
)
*
5.0
;
addBox
(
geometry
,
x
,
y
,
0.0
,
4.0
,
4.0
,
0.02
);
}
geometry
.
updateEdgesAndVertices
();
return
geometry
;
}
private
static
Geometry
newSolid
(
Lod
lod
)
{
return
new
Geometry
(
GeometryType
.
SOLID
,
lod
,
Orientation
.
OUTWARD
);
}
private
static
void
addBox
(
Geometry
geometry
,
double
x
,
double
y
,
double
z
,
double
width
,
double
depth
,
double
height
)
{
Vertex
v000
=
new
Vertex
(
x
,
y
,
z
);
Vertex
v100
=
new
Vertex
(
x
+
width
,
y
,
z
);
Vertex
v110
=
new
Vertex
(
x
+
width
,
y
+
depth
,
z
);
Vertex
v010
=
new
Vertex
(
x
,
y
+
depth
,
z
);
Vertex
v001
=
new
Vertex
(
x
,
y
,
z
+
height
);
Vertex
v101
=
new
Vertex
(
x
+
width
,
y
,
z
+
height
);
Vertex
v111
=
new
Vertex
(
x
+
width
,
y
+
depth
,
z
+
height
);
Vertex
v011
=
new
Vertex
(
x
,
y
+
depth
,
z
+
height
);
addQuad
(
geometry
,
v000
,
v100
,
v110
,
v010
);
addQuad
(
geometry
,
v001
,
v011
,
v111
,
v101
);
addQuad
(
geometry
,
v000
,
v001
,
v101
,
v100
);
addQuad
(
geometry
,
v100
,
v101
,
v111
,
v110
);
addQuad
(
geometry
,
v110
,
v111
,
v011
,
v010
);
addQuad
(
geometry
,
v010
,
v011
,
v001
,
v000
);
}
private
static
void
addQuad
(
Geometry
geometry
,
Vertex
a
,
Vertex
b
,
Vertex
c
,
Vertex
d
)
{
ConcretePolygon
polygon
=
new
ConcretePolygon
();
LinearRing
ring
=
new
LinearRing
(
LinearRingType
.
EXTERIOR
);
polygon
.
setExteriorRing
(
ring
);
geometry
.
addPolygon
(
polygon
);
ring
.
addVertex
(
a
);
ring
.
addVertex
(
b
);
ring
.
addVertex
(
c
);
ring
.
addVertex
(
d
);
ring
.
addVertex
(
a
);
}
}
CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/bht/TestCityGmlAABB.java
View file @
e6f4979d
...
@@ -84,10 +84,8 @@ public class TestCityGmlAABB {
...
@@ -84,10 +84,8 @@ public class TestCityGmlAABB {
System
.
out
.
println
(
"\n> Polygon-level AABB (broad-phase)"
);
System
.
out
.
println
(
"\n> Polygon-level AABB (broad-phase)"
);
Set
<
ConcretePolygon
>
polys
=
collectAllPolygons
(
buildings
);
Set
<
ConcretePolygon
>
polys
=
collectAllPolygons
(
buildings
);
BoundingVolumeHierarchyTree
<
ConcretePolygon
>
bvh
=
new
BoundingVolumeHierarchyTree
<>(
BoundingVolumeHierarchyTree
<
ConcretePolygon
>
bvh
=
new
ArrayList
<>(
polys
),
BoundingVolumeHierarchyTree
.
newBinary
(
new
ArrayList
<>(
polys
),
AABB:
:
of
);
AABB:
:
of
);
System
.
out
.
println
(
"Polygons: "
+
polys
.
size
());
System
.
out
.
println
(
"Polygons: "
+
polys
.
size
());
if
(
bvh
.
getRoot
()
!=
null
)
{
if
(
bvh
.
getRoot
()
!=
null
)
{
System
.
out
.
print
(
"Root AABB: "
);
System
.
out
.
print
(
"Root AABB: "
);
...
@@ -103,10 +101,8 @@ public class TestCityGmlAABB {
...
@@ -103,10 +101,8 @@ public class TestCityGmlAABB {
?
collectExteriorRings
(
buildings
)
?
collectExteriorRings
(
buildings
)
:
collectInteriorRings
(
buildings
);
:
collectInteriorRings
(
buildings
);
BoundingVolumeHierarchyTree
<
LinearRing
>
bvh
=
new
BoundingVolumeHierarchyTree
<>(
BoundingVolumeHierarchyTree
<
LinearRing
>
bvh
=
new
ArrayList
<>(
rings
),
BoundingVolumeHierarchyTree
.
newBinary
(
new
ArrayList
<>(
rings
),
AABB:
:
of
);
AABB:
:
of
);
System
.
out
.
println
(
label
+
" rings: "
+
rings
.
size
());
System
.
out
.
println
(
label
+
" rings: "
+
rings
.
size
());
if
(
bvh
.
getRoot
()
!=
null
)
{
if
(
bvh
.
getRoot
()
!=
null
)
{
...
@@ -119,10 +115,8 @@ public class TestCityGmlAABB {
...
@@ -119,10 +115,8 @@ public class TestCityGmlAABB {
System
.
out
.
println
(
"\n> Vertex-level AABB (fine-phase)"
);
System
.
out
.
println
(
"\n> Vertex-level AABB (fine-phase)"
);
Set
<
Vertex
>
verts
=
collectAllVertices
(
buildings
);
Set
<
Vertex
>
verts
=
collectAllVertices
(
buildings
);
BoundingVolumeHierarchyTree
<
Vertex
>
bvh
=
new
BoundingVolumeHierarchyTree
<>(
BoundingVolumeHierarchyTree
<
Vertex
>
bvh
=
new
ArrayList
<>(
verts
),
BoundingVolumeHierarchyTree
.
newBinary
(
new
ArrayList
<>(
verts
),
AABB:
:
of
);
AABB:
:
of
);
System
.
out
.
println
(
"Vertices: "
+
verts
.
size
());
System
.
out
.
println
(
"Vertices: "
+
verts
.
size
());
if
(
bvh
.
getRoot
()
!=
null
)
{
if
(
bvh
.
getRoot
()
!=
null
)
{
...
...
Prev
1
2
Next
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment