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
2d2487cc
Commit
2d2487cc
authored
Feb 27, 2026
by
Numanoglu
Browse files
Fix BVH query + update tests for Geometry/Stream API
parent
24f4d6cd
Pipeline
#12353
failed with stage
in 2 minutes and 7 seconds
Changes
19
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/bht/AABB.java
View file @
2d2487cc
...
@@ -17,11 +17,6 @@ public class AABB {
...
@@ -17,11 +17,6 @@ public class AABB {
private
double
minX
,
minY
,
minZ
;
private
double
minX
,
minY
,
minZ
;
private
double
maxX
,
maxY
,
maxZ
;
private
double
maxX
,
maxY
,
maxZ
;
// public static AABB of(Geometry geom) {
// return of(geom.getPolygons());
// }
//
//
public
static
AABB
ofPolygons
(
List
<?
extends
Polygon
>
polygons
)
{
public
static
AABB
ofPolygons
(
List
<?
extends
Polygon
>
polygons
)
{
List
<
Vector3d
>
points
=
new
ArrayList
<>();
List
<
Vector3d
>
points
=
new
ArrayList
<>();
for
(
Polygon
p
:
polygons
)
{
for
(
Polygon
p
:
polygons
)
{
...
@@ -37,8 +32,6 @@ public class AABB {
...
@@ -37,8 +32,6 @@ public class AABB {
return
of
(
ring
);
return
of
(
ring
);
}
}
// NOTE: May replaced later: double[] extractBoundsFromPoints(List<? extends
// Point> points)
public
static
AABB
ofPoints
(
List
<?
extends
Vector3d
>
points
)
{
public
static
AABB
ofPoints
(
List
<?
extends
Vector3d
>
points
)
{
double
minX
=
Double
.
POSITIVE_INFINITY
,
minY
=
Double
.
POSITIVE_INFINITY
,
minZ
=
Double
.
POSITIVE_INFINITY
;
double
minX
=
Double
.
POSITIVE_INFINITY
,
minY
=
Double
.
POSITIVE_INFINITY
,
minZ
=
Double
.
POSITIVE_INFINITY
;
double
maxX
=
Double
.
NEGATIVE_INFINITY
,
maxY
=
Double
.
NEGATIVE_INFINITY
,
maxZ
=
Double
.
NEGATIVE_INFINITY
;
double
maxX
=
Double
.
NEGATIVE_INFINITY
,
maxY
=
Double
.
NEGATIVE_INFINITY
,
maxZ
=
Double
.
NEGATIVE_INFINITY
;
...
@@ -246,7 +239,7 @@ public class AABB {
...
@@ -246,7 +239,7 @@ public class AABB {
/**
/**
* Returns true if two AABBs overlap (
ex
clusive)
.
* Returns true if two AABBs overlap (
in
clusive
: touching counts as overlap
)
*/
*/
public
boolean
overlaps
(
AABB
other
)
{
public
boolean
overlaps
(
AABB
other
)
{
return
!(
getMaxX
()
<
other
.
getMinX
()
||
return
!(
getMaxX
()
<
other
.
getMinX
()
||
...
@@ -270,7 +263,7 @@ public class AABB {
...
@@ -270,7 +263,7 @@ public class AABB {
}
}
/**
/**
* Checks if this and other boxes intersect (
in
clusive)
* Checks if this and other boxes intersect (
ex
clusive
: touching does not count
)
*/
*/
public
boolean
intersects
(
AABB
other
)
{
public
boolean
intersects
(
AABB
other
)
{
return
!(
other
.
maxX
<=
this
.
minX
||
other
.
minX
>=
this
.
maxX
||
other
.
maxY
<=
this
.
minY
||
other
.
minY
>=
this
.
maxY
return
!(
other
.
maxX
<=
this
.
minX
||
other
.
minX
>=
this
.
maxX
||
other
.
maxY
<=
this
.
minY
||
other
.
minY
>=
this
.
maxY
...
@@ -303,6 +296,5 @@ public class AABB {
...
@@ -303,6 +296,5 @@ public class AABB {
public
String
toString
()
{
public
String
toString
()
{
return
"AABB ["
+
String
.
format
(
"min: %.2f, %.2f, %.2f max: %.2f, %.2f, %.2f"
,
minX
,
minY
,
minZ
,
maxX
,
maxY
,
maxZ
)
+
"]"
;
return
"AABB ["
+
String
.
format
(
"min: %.2f, %.2f, %.2f max: %.2f, %.2f, %.2f"
,
minX
,
minY
,
minZ
,
maxX
,
maxY
,
maxZ
)
+
"]"
;
}
}
}
}
CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/bht/AABBUtils.java
View file @
2d2487cc
...
@@ -41,39 +41,5 @@ import de.hft.stuttgart.citydoctor2.datastructure.Vertex;
...
@@ -41,39 +41,5 @@ import de.hft.stuttgart.citydoctor2.datastructure.Vertex;
}
}
return
set
.
size
();
return
set
.
size
();
// if (ring == null || ring.getVertices() == null) return 0;
// // Use a quantization resolution based on tol (avoid div by zero).
// final double q = (tol > 0) ? tol : 1e-9;
//
// // Hash set of quantized integer triplets "ix|iy|iz"
// Set<Long> buckets = new HashSet<>(ring.getVertices().size() * 2);
// for (Vertex v : ring.getVertices()) {
// long ix = Math.round(v.getX() / q);
// long iy = Math.round(v.getY() / q);
// long iz = Math.round(v.getZ() / q);
// // pack into a 64-bit key (simple mixing; safe if ranges are reasonable)
// long key = mix3(ix, iy, iz);
// buckets.add(key);
// }
// return buckets.size();
}
}
// Simple 3D integer mix to a 64-bit key (Xorshift-ish) from JavaDoc
// private static long mix3(long x, long y, long z) {
// long h = x * 73856093L ^ y * 19349663L ^ z * 83492791L;
// // final avalanche
// h ^= (h >>> 33);
// h *= 0xff51afd7ed558ccdL;
// h ^= (h >>> 33);
// h *= 0xc4ceb9fe1a85ec53L;
// h ^= (h >>> 33);
// return h;
// }
}
}
CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/bht/BoundingVolumeHierarchyTree.java
View file @
2d2487cc
...
@@ -84,11 +84,6 @@ public class BoundingVolumeHierarchyTree<E> {
...
@@ -84,11 +84,6 @@ public class BoundingVolumeHierarchyTree<E> {
this
.
root
=
root
;
this
.
root
=
root
;
}
}
public
List
<
E
>
getAllIntersectingElements
(
AABB
box
)
{
// TODO: implement
throw
new
UnsupportedOperationException
();
}
/**
/**
* Recursively builds a balanced AABB tree from the list of elements.
* Recursively builds a balanced AABB tree from the list of elements.
*/
*/
...
@@ -116,36 +111,34 @@ public class BoundingVolumeHierarchyTree<E> {
...
@@ -116,36 +111,34 @@ public class BoundingVolumeHierarchyTree<E> {
return
node
;
return
node
;
}
}
/////////////////////////////////////////////////////////////////
// Works with overlaps()<--includes touching; not with intersects()
/* Sketch: method for rapid intersection dedection */
public
List
<
E
>
getAllIntersectingElements
(
AABB
query
)
{
/*
List
<
E
>
result
=
new
ArrayList
<>();
*
getAllIntersectingElementsRecursive
(
root
,
query
,
result
);
*
return
result
;
*/
}
public
List
<
E
>
findCandidates
(
AABB
query
)
{
List
<
E
>
candidates
=
new
ArrayList
<>();
private
void
getAllIntersectingElementsRecursive
(
Node
<
E
>
node
,
AABB
query
,
List
<
E
>
result
)
{
findCandidatesRecursive
(
root
,
query
,
candidates
);
if
(
node
==
null
)
{
return
candidates
;
return
;
}
}
/*
*
// Broad-phase pruning (includes touching points)
*
if
(!
node
.
getAabb
().
overlaps
(
query
))
{
*
return
;
*/
}
private
void
findCandidatesRecursive
(
Node
<
E
>
node
,
AABB
query
,
List
<
E
>
result
)
{
if
(
node
==
null
||
!
node
.
getAabb
().
intersects
(
query
))
{
if
(
node
.
isLeaf
())
{
return
;
// Leaf-AABB is all ready in heap
}
if
(
node
.
getAabb
().
overlaps
(
query
))
{
result
.
add
(
node
.
getElement
());
if
(
node
.
isLeaf
())
{
}
if
(
aabbFunction
.
apply
(
node
.
getElement
()).
intersects
(
query
))
{
return
;
result
.
add
(
node
.
getElement
());
}
}
}
else
{
for
(
Node
<
E
>
child
:
node
.
getChildren
())
{
for
(
Node
<
E
>
child
:
node
.
getChildren
())
{
getAllIntersectingElementsRecursive
(
child
,
query
,
result
);
findCandidatesRecursive
(
child
,
query
,
result
);
}
}
}
}
}
}
}
CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/bht/Node.java
View file @
2d2487cc
...
@@ -10,11 +10,6 @@ public class Node<E> {
...
@@ -10,11 +10,6 @@ public class Node<E> {
private
E
element
;
private
E
element
;
public
Node
(
E
element
,
AABB
aabb
)
{
public
Node
(
E
element
,
AABB
aabb
)
{
// // Anchor-3DPoint given by means of its coords
// double zeroX = 0;
// double zeroY = 0;
// double zeroZ = 0;
// this.aabb = new AABB(zeroX, zeroY, zeroZ, zeroX, zeroY, zeroZ);
this
.
aabb
=
aabb
;
this
.
aabb
=
aabb
;
this
.
element
=
element
;
this
.
element
=
element
;
}
}
...
...
CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/datastructure/bht/AABBTest.java
View file @
2d2487cc
...
@@ -21,18 +21,6 @@ public class AABBTest {
...
@@ -21,18 +21,6 @@ public class AABBTest {
@Test
@Test
public
void
testContainsAABB
()
{
public
void
testContainsAABB
()
{
// System.out.println("=== AABB TEST ===");
ConcretePolygon
polygon
=
new
ConcretePolygon
();
LinearRing
exterior
=
new
LinearRing
(
LinearRingType
.
EXTERIOR
);
exterior
.
addVertex
(
new
Vertex
(
0
,
0
,
0
));
exterior
.
addVertex
(
new
Vertex
(
1
,
0
,
0
));
exterior
.
addVertex
(
new
Vertex
(
0
,
1
,
0
));
exterior
.
addVertex
(
new
Vertex
(
0
,
0
,
0
));
polygon
.
setExteriorRing
(
exterior
);
// Define points of a tetrahedron
// Define points of a tetrahedron
Point3d
p1
=
new
Point3d
(
0
,
0
,
0
);
Point3d
p1
=
new
Point3d
(
0
,
0
,
0
);
Point3d
p2
=
new
Point3d
(
1
,
0
,
0
);
Point3d
p2
=
new
Point3d
(
1
,
0
,
0
);
...
@@ -75,8 +63,7 @@ public class AABBTest {
...
@@ -75,8 +63,7 @@ public class AABBTest {
List
<
Polygon
>
polys
=
Arrays
.
asList
(
base
,
side1
,
side2
,
side3
);
List
<
Polygon
>
polys
=
Arrays
.
asList
(
base
,
side1
,
side2
,
side3
);
AABB
aabb
=
AABB
.
ofPolygons
(
polys
);
AABB
aabb
=
AABB
.
ofPolygons
(
polys
);
// System.out.println("\nComputed " + aabb);
/*** 3D-Point-coords with Test Properties ***/
/*** 3D-Point-coords with Test Properties ***/
// Inside laying Point
// Inside laying Point
double
testInsideX
=
0.5
;
double
testInsideX
=
0.5
;
...
@@ -94,18 +81,10 @@ public class AABBTest {
...
@@ -94,18 +81,10 @@ public class AABBTest {
// inside point
// inside point
Assert
.
assertTrue
(
aabb
.
contains
(
testInsideX
,
testInsideY
,
testInsideZ
));
Assert
.
assertTrue
(
aabb
.
contains
(
testInsideX
,
testInsideY
,
testInsideZ
));
// System.out.println("\nTest point (inside): " + testInsideX + " " + testInsideY + " " + testInsideZ);
// System.out.println("-> contained?: " + aabb.contains(testInsideX, testInsideY, testInsideZ));
// outside point
// outside point
Assert
.
assertFalse
(
aabb
.
contains
(
testOutsideX
,
testOutsideY
,
testOutsideZ
));
Assert
.
assertFalse
(
aabb
.
contains
(
testOutsideX
,
testOutsideY
,
testOutsideZ
));
// System.out.println("\nTest point (outside): " + testOutsideX + " " + testOutsideY + " " + testOutsideZ);
// System.out.println("-> contained?: " + aabb.contains(testOutsideX, testOutsideY, testOutsideZ));
// edge point
// edge point
Assert
.
assertTrue
(
aabb
.
contains
(
testOnEdgeX
,
testOnEdgeY
,
testOnEdgeZ
));
Assert
.
assertTrue
(
aabb
.
contains
(
testOnEdgeX
,
testOnEdgeY
,
testOnEdgeZ
));
// System.out.println("\nTest point (on edge): " + testOnEdgeX + " " + testOnEdgeY + " " + testOnEdgeZ);
// System.out.println("-> contained?: " + aabb.contains(testOnEdgeX, testOnEdgeY, testOnEdgeZ));
}
}
}
}
CityDoctorParent/CityDoctorModel/src/test/java/de/hft/stuttgart/citydoctor2/datastructure/bht/TestHouseAABB.java
View file @
2d2487cc
package
de.hft.stuttgart.citydoctor2.datastructure.bht
;
package
de.hft.stuttgart.citydoctor2.datastructure.bht
;
//import de.hft.stuttgart.citydoctor2.checks.aabb.*;
import
java.util.ArrayList
;
import
java.io.IOException
;
import
java.util.List
;
import
java.util.*
;
import
org.junit.Assert
;
import
org.junit.Test
;
import
de.hft.stuttgart.citydoctor2.datastructure.ConcretePolygon
;
import
de.hft.stuttgart.citydoctor2.datastructure.ConcretePolygon
;
import
de.hft.stuttgart.citydoctor2.datastructure.LinearRing
;
import
de.hft.stuttgart.citydoctor2.datastructure.LinearRing
;
import
de.hft.stuttgart.citydoctor2.datastructure.Vertex
;
import
de.hft.stuttgart.citydoctor2.datastructure.Vertex
;
import
de.hft.stuttgart.citydoctor2.parser.CityGmlParseException
;
import
de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException
;
public
class
TestHouseAABB
{
public
class
TestHouseAABB
{
public
static
void
main
(
String
[]
args
)
throws
CityGmlParseException
,
IOException
,
InvalidGmlFileException
{
@Test
System
.
out
.
println
(
"===TestHouseAABB==="
);
public
void
testHouseAabbContainsPoints
()
{
/*
// 3D House: base 2x2, height 2, roof +1
* 3D House of St.Niclas
*
* */
// Haus-Basis: Würfelgröße 2x2x2, Dachhöhe +1
double
baseSize
=
2.0
;
double
baseSize
=
2.0
;
double
height
=
2.0
;
double
height
=
2.0
;
double
roofHeight
=
1.0
;
double
roofHeight
=
1.0
;
//
points for Ground floor
//
ground points
Point3d
b1
=
new
Point3d
(
0
,
0
,
0
);
Point3d
b1
=
new
Point3d
(
0
,
0
,
0
);
Point3d
b2
=
new
Point3d
(
baseSize
,
0
,
0
);
Point3d
b2
=
new
Point3d
(
baseSize
,
0
,
0
);
Point3d
b3
=
new
Point3d
(
baseSize
,
baseSize
,
0
);
Point3d
b3
=
new
Point3d
(
baseSize
,
baseSize
,
0
);
Point3d
b4
=
new
Point3d
(
0
,
baseSize
,
0
);
Point3d
b4
=
new
Point3d
(
0
,
baseSize
,
0
);
//
points for Roof
//
top of walls
Point3d
t1
=
new
Point3d
(
0
,
0
,
height
);
Point3d
t1
=
new
Point3d
(
0
,
0
,
height
);
Point3d
t2
=
new
Point3d
(
baseSize
,
0
,
height
);
Point3d
t2
=
new
Point3d
(
baseSize
,
0
,
height
);
Point3d
t3
=
new
Point3d
(
baseSize
,
baseSize
,
height
);
Point3d
t3
=
new
Point3d
(
baseSize
,
baseSize
,
height
);
Point3d
t4
=
new
Point3d
(
0
,
baseSize
,
height
);
Point3d
t4
=
new
Point3d
(
0
,
baseSize
,
height
);
//
R
oofpeaks
//
r
oof
peaks
(slightly beyond footprint in Y to create overhang)
Point3d
roofPeak1
=
new
Point3d
(
baseSize
/
2
,
-
0.2
,
height
+
roofHeight
);
Point3d
roofPeak1
=
new
Point3d
(
baseSize
/
2
,
-
0.2
,
height
+
roofHeight
);
Point3d
roofPeak2
=
new
Point3d
(
baseSize
/
2
,
baseSize
+
0.2
,
height
+
roofHeight
);
Point3d
roofPeak2
=
new
Point3d
(
baseSize
/
2
,
baseSize
+
0.2
,
height
+
roofHeight
);
List
<
ConcretePolygon
>
house
=
new
ArrayList
<>();
List
<
ConcretePolygon
>
house
=
new
ArrayList
<>();
// floor
(b1,b2,b3,b4)
// floor
house
.
add
(
createQuadPolygon
(
b1
,
b2
,
b3
,
b4
));
house
.
add
(
createQuadPolygon
(
b1
,
b2
,
b3
,
b4
));
//
W
alls
//
w
alls
house
.
add
(
createQuadPolygon
(
b1
,
b2
,
t2
,
t1
));
// vorne
house
.
add
(
createQuadPolygon
(
b1
,
b2
,
t2
,
t1
));
house
.
add
(
createQuadPolygon
(
b2
,
b3
,
t3
,
t2
));
// rechts
house
.
add
(
createQuadPolygon
(
b2
,
b3
,
t3
,
t2
));
house
.
add
(
createQuadPolygon
(
b3
,
b4
,
t4
,
t3
));
// hinten
house
.
add
(
createQuadPolygon
(
b3
,
b4
,
t4
,
t3
));
house
.
add
(
createQuadPolygon
(
b4
,
b1
,
t1
,
t4
));
// links
house
.
add
(
createQuadPolygon
(
b4
,
b1
,
t1
,
t4
));
//
sea
ling under roof
//
cei
ling under roof
house
.
add
(
createQuadPolygon
(
t1
,
t2
,
t3
,
t4
));
house
.
add
(
createQuadPolygon
(
t1
,
t2
,
t3
,
t4
));
// triangles
of roof
//
roof
triangles
house
.
add
(
createTrianglePolygon
(
t1
,
t2
,
roofPeak1
));
house
.
add
(
createTrianglePolygon
(
t1
,
t2
,
roofPeak1
));
house
.
add
(
createTrianglePolygon
(
t4
,
t3
,
roofPeak2
));
house
.
add
(
createTrianglePolygon
(
t4
,
t3
,
roofPeak2
));
// faces of roof
// roof faces
house
.
add
(
createQuadPolygon
(
t2
,
t3
,
roofPeak2
,
roofPeak1
));
house
.
add
(
createQuadPolygon
(
t2
,
t3
,
roofPeak2
,
roofPeak1
));
house
.
add
(
createQuadPolygon
(
t1
,
t4
,
roofPeak2
,
roofPeak1
));
house
.
add
(
createQuadPolygon
(
t1
,
t4
,
roofPeak2
,
roofPeak1
));
AABB
houseAABB
=
AABB
.
ofPolygons
(
house
);
AABB
houseAABB
=
AABB
.
ofPolygons
(
house
);
// houseAABB.print();
//
Define test
points
// points
double
[]
insidePoint
=
{
1.0
,
1.0
,
1.0
};
//
clearly inside (center of the base cube)
double
[]
insidePoint
=
{
1.0
,
1.0
,
1.0
};
//
inside base volume
double
[]
roofPoint
=
{
1.0
,
1.0
,
2.8
};
// inside roof area but near the top
double
[]
roofPoint
=
{
1.0
,
1.0
,
2.8
};
// below roof peak (z=3.0), should be inside AABB
double
[]
outsidePoint
=
{
3.0
,
3.0
,
3.0
};
//
clearly
outside
double
[]
outsidePoint
=
{
3.0
,
3.0
,
3.0
};
// outside
double
[]
edgePoint
=
{
2.0
,
2.0
,
2.0
};
// exactly on the upper cube corner
double
[]
edgePoint
=
{
2.0
,
2.0
,
2.0
};
// on top corner of base cube
//
Test
containment
//
AABB
containment
assertions
System
.
out
.
println
(
"\nTest point (inside): "
+
Arrays
.
toString
(
insidePoint
));
Assert
.
assertTrue
(
"insidePoint should be inside AABB"
,
System
.
out
.
println
(
"-> contained? "
+
houseAABB
.
contains
(
insidePoint
[
0
],
insidePoint
[
1
],
insidePoint
[
2
]));
houseAABB
.
contains
(
insidePoint
[
0
],
insidePoint
[
1
],
insidePoint
[
2
]));
System
.
out
.
println
(
"\nTest point (on roof): "
+
Arrays
.
toString
(
roofPoint
));
Assert
.
assertTrue
(
"roofPoint should be inside AABB (AABB includes the roof peak z)"
,
System
.
out
.
println
(
"-> contained? "
+
houseAABB
.
contains
(
roofPoint
[
0
],
roofPoint
[
1
],
roofPoint
[
2
]));
houseAABB
.
contains
(
roofPoint
[
0
],
roofPoint
[
1
],
roofPoint
[
2
]));
System
.
out
.
println
(
"\nTest point (outside): "
+
Arrays
.
toString
(
outsidePoint
));
Assert
.
assertFalse
(
"outsidePoint should be outside AABB"
,
System
.
out
.
println
(
"-> contained? "
+
houseAABB
.
contains
(
outsidePoint
[
0
],
outsidePoint
[
1
],
outsidePoint
[
2
]));
houseAABB
.
contains
(
outsidePoint
[
0
],
outsidePoint
[
1
],
outsidePoint
[
2
]));
System
.
out
.
println
(
"\nTest point (on edge): "
+
Arrays
.
toString
(
edgePoint
));
Assert
.
assertTrue
(
"edgePoint should be inside AABB (contains is inclusive)"
,
System
.
out
.
println
(
"-> contained? "
+
houseAABB
.
contains
(
edgePoint
[
0
],
edgePoint
[
1
],
edgePoint
[
2
]));
houseAABB
.
contains
(
edgePoint
[
0
],
edgePoint
[
1
],
edgePoint
[
2
]));
// optional: check expected bounds explicitly (helps debugging)
Assert
.
assertEquals
(
0.0
,
houseAABB
.
getMinX
(),
0.0
);
Assert
.
assertEquals
(-
0.2
,
houseAABB
.
getMinY
(),
0.0
);
Assert
.
assertEquals
(
0.0
,
houseAABB
.
getMinZ
(),
0.0
);
Assert
.
assertEquals
(
2.0
,
houseAABB
.
getMaxX
(),
0.0
);
Assert
.
assertEquals
(
2.2
,
houseAABB
.
getMaxY
(),
0.0
);
Assert
.
assertEquals
(
3.0
,
houseAABB
.
getMaxZ
(),
0.0
);
}
}
/** Creates a triangular polygon from three points */
private
static
ConcretePolygon
createTrianglePolygon
(
Point3d
p1
,
Point3d
p2
,
Point3d
p3
)
{
private
static
ConcretePolygon
createTrianglePolygon
(
Point3d
p1
,
Point3d
p2
,
Point3d
p3
)
{
// alocate poly
ConcretePolygon
poly
=
new
ConcretePolygon
();
ConcretePolygon
poly
=
new
ConcretePolygon
();
// alocate ring
LinearRing
ring
=
new
LinearRing
(
LinearRing
.
LinearRingType
.
EXTERIOR
);
LinearRing
ring
=
new
LinearRing
(
LinearRing
.
LinearRingType
.
EXTERIOR
);
// vertices of triangle
ring
.
addVertex
(
new
Vertex
(
p1
.
getX
(),
p1
.
getY
(),
p1
.
getZ
()));
ring
.
addVertex
(
new
Vertex
(
p1
.
getX
(),
p1
.
getY
(),
p1
.
getZ
()));
ring
.
addVertex
(
new
Vertex
(
p2
.
getX
(),
p2
.
getY
(),
p2
.
getZ
()));
ring
.
addVertex
(
new
Vertex
(
p2
.
getX
(),
p2
.
getY
(),
p2
.
getZ
()));
ring
.
addVertex
(
new
Vertex
(
p3
.
getX
(),
p3
.
getY
(),
p3
.
getZ
()));
ring
.
addVertex
(
new
Vertex
(
p3
.
getX
(),
p3
.
getY
(),
p3
.
getZ
()));
ring
.
addVertex
(
new
Vertex
(
p1
.
getX
(),
p1
.
getY
(),
p1
.
getZ
()));
//
C
lose ring
ring
.
addVertex
(
new
Vertex
(
p1
.
getX
(),
p1
.
getY
(),
p1
.
getZ
()));
//
c
lose ring
//
poly
.
setExteriorRing
(
ring
);
poly
.
setExteriorRing
(
ring
);
return
poly
;
return
poly
;
}
}
/** Creates a quadrilateral polygon from four points */
private
static
ConcretePolygon
createQuadPolygon
(
Point3d
p1
,
Point3d
p2
,
Point3d
p3
,
Point3d
p4
)
{
private
static
ConcretePolygon
createQuadPolygon
(
Point3d
p1
,
Point3d
p2
,
Point3d
p3
,
Point3d
p4
)
{
ConcretePolygon
poly
=
new
ConcretePolygon
();
ConcretePolygon
poly
=
new
ConcretePolygon
();
LinearRing
ring
=
new
LinearRing
(
LinearRing
.
LinearRingType
.
EXTERIOR
);
LinearRing
ring
=
new
LinearRing
(
LinearRing
.
LinearRingType
.
EXTERIOR
);
ring
.
addVertex
(
new
Vertex
(
p1
.
getX
(),
p1
.
getY
(),
p1
.
getZ
()));
ring
.
addVertex
(
new
Vertex
(
p1
.
getX
(),
p1
.
getY
(),
p1
.
getZ
()));
ring
.
addVertex
(
new
Vertex
(
p2
.
getX
(),
p2
.
getY
(),
p2
.
getZ
()));
ring
.
addVertex
(
new
Vertex
(
p2
.
getX
(),
p2
.
getY
(),
p2
.
getZ
()));
ring
.
addVertex
(
new
Vertex
(
p3
.
getX
(),
p3
.
getY
(),
p3
.
getZ
()));
ring
.
addVertex
(
new
Vertex
(
p3
.
getX
(),
p3
.
getY
(),
p3
.
getZ
()));
ring
.
addVertex
(
new
Vertex
(
p4
.
getX
(),
p4
.
getY
(),
p4
.
getZ
()));
ring
.
addVertex
(
new
Vertex
(
p4
.
getX
(),
p4
.
getY
(),
p4
.
getZ
()));
ring
.
addVertex
(
new
Vertex
(
p1
.
getX
(),
p1
.
getY
(),
p1
.
getZ
()));
//
C
lose ring
ring
.
addVertex
(
new
Vertex
(
p1
.
getX
(),
p1
.
getY
(),
p1
.
getZ
()));
//
c
lose ring
poly
.
setExteriorRing
(
ring
);
poly
.
setExteriorRing
(
ring
);
return
poly
;
return
poly
;
}
}
}
}
\ No newline at end of file
CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/checks/bht/NestedRingsCheckAABB.java
View file @
2d2487cc
...
@@ -48,6 +48,7 @@ import de.hft.stuttgart.citydoctor2.datastructure.bht.AABBUtils;
...
@@ -48,6 +48,7 @@ import de.hft.stuttgart.citydoctor2.datastructure.bht.AABBUtils;
* @author Baris Numanoglu
* @author Baris Numanoglu
*
*
*/
*/
// TODO extend check with tree
public
class
NestedRingsCheckAABB
extends
Check
{
public
class
NestedRingsCheckAABB
extends
Check
{
private
static
final
List
<
CheckId
>
dependencies
;
private
static
final
List
<
CheckId
>
dependencies
;
...
@@ -74,7 +75,7 @@ public class NestedRingsCheckAABB extends Check {
...
@@ -74,7 +75,7 @@ public class NestedRingsCheckAABB extends Check {
// --- NEW: cache AABBs of inner rings for broad-phase ---
// --- NEW: cache AABBs of inner rings for broad-phase ---
Map
<
LinearRing
,
AABB
>
ringBoxes
=
new
HashMap
<>(
inner
.
size
());
Map
<
LinearRing
,
AABB
>
ringBoxes
=
new
HashMap
<>(
inner
.
size
());
for
(
LinearRing
r
:
inner
)
{
for
(
LinearRing
r
:
inner
)
{
ringBoxes
.
put
(
r
,
AABB
Utils
.
computeAABBFromRing
(
r
));
ringBoxes
.
put
(
r
,
AABB
.
of
(
r
));
}
}
for
(
LinearRing
interiorRing
:
inner
)
{
for
(
LinearRing
interiorRing
:
inner
)
{
...
@@ -90,7 +91,7 @@ public class NestedRingsCheckAABB extends Check {
...
@@ -90,7 +91,7 @@ public class NestedRingsCheckAABB extends Check {
AABB
checkBox
=
ringBoxes
.
get
(
checkRing
);
AABB
checkBox
=
ringBoxes
.
get
(
checkRing
);
// If the inner AABB is not fully inside the other ring's AABB,
// If the inner AABB is not fully inside the other ring's AABB,
// "nested" is impossible -> skip narrow phase.
// "nested" is impossible -> skip narrow phase.
if
(!
AABBUtils
.
containsAabb
(
interiorBox
,
checkBox
))
{
if
(!
interiorBox
.
contains
(
checkBox
))
{
continue
;
continue
;
}
}
...
...
CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/checks/bht/RingSelfIntCheckAABB.java
View file @
2d2487cc
...
@@ -61,6 +61,8 @@ import de.hft.stuttgart.citydoctor2.datastructure.bht.AABBUtils;
...
@@ -61,6 +61,8 @@ import de.hft.stuttgart.citydoctor2.datastructure.bht.AABBUtils;
* Axis Aligned Boundin Box Early-Out-Version of Matthias Betz's Check
* Axis Aligned Boundin Box Early-Out-Version of Matthias Betz's Check
* @author Baris Numanoglu
* @author Baris Numanoglu
*/
*/
// TODO extend check with tree
public
class
RingSelfIntCheckAABB
extends
Check
{
public
class
RingSelfIntCheckAABB
extends
Check
{
private
static
final
String
EPSILON_NAME
=
"minVertexDistance"
;
private
static
final
String
EPSILON_NAME
=
"minVertexDistance"
;
...
@@ -111,7 +113,7 @@ public class RingSelfIntCheckAABB extends Check {
...
@@ -111,7 +113,7 @@ public class RingSelfIntCheckAABB extends Check {
// Precompute padded AABBs for all edges (padding = epsilon)
// Precompute padded AABBs for all edges (padding = epsilon)
List
<
EdgeBox
>
edgeBoxes
=
new
ArrayList
<>(
edges
.
size
());
List
<
EdgeBox
>
edgeBoxes
=
new
ArrayList
<>(
edges
.
size
());
for
(
Edge
e
:
edges
)
{
for
(
Edge
e
:
edges
)
{
edgeBoxes
.
add
(
new
EdgeBox
(
e
,
AABB
Utils
.
edgeAabb
(
e
.
getFrom
(),
e
.
getTo
(),
epsilon
)));
edgeBoxes
.
add
(
new
EdgeBox
(
e
,
AABB
.
of
(
e
.
getFrom
(),
e
.
getTo
(),
epsilon
)));
}
}
// Optimized "point touches edge": first filter by padded edge AABB
// Optimized "point touches edge": first filter by padded edge AABB
...
@@ -136,7 +138,7 @@ public class RingSelfIntCheckAABB extends Check {
...
@@ -136,7 +138,7 @@ public class RingSelfIntCheckAABB extends Check {
//skip if AABBs don't overlap
//skip if AABBs don't overlap
EdgeBox
eb2
=
edgeBoxes
.
get
(
j
);
EdgeBox
eb2
=
edgeBoxes
.
get
(
j
);
if
(!
AABBUtils
.
overlaps
(
eb1
.
box
,
eb2
.
box
))
{
if
(!
eb1
.
box
.
overlaps
(
eb2
.
box
))
{
continue
;
continue
;
}
}
...
@@ -204,7 +206,7 @@ public class RingSelfIntCheckAABB extends Check {
...
@@ -204,7 +206,7 @@ public class RingSelfIntCheckAABB extends Check {
continue
;
continue
;
}
}
// Broad-phase: reject if vertex is outside padded edge AABB
// Broad-phase: reject if vertex is outside padded edge AABB
if
(!
eb
.
box
.
enclose
s
(
v
.
getX
(),
v
.
getY
(),
v
.
getZ
()))
{
if
(!
eb
.
box
.
contain
s
(
v
.
getX
(),
v
.
getY
(),
v
.
getZ
()))
{
continue
;
continue
;
}
}
// Narrow-phase: exact segment-point distance
// Narrow-phase: exact segment-point distance
...
...
CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/checks/bht/SolidSelfIntCheckAABB.java
View file @
2d2487cc
...
@@ -28,7 +28,6 @@ import de.hft.stuttgart.citydoctor2.check.Check;
...
@@ -28,7 +28,6 @@ import de.hft.stuttgart.citydoctor2.check.Check;
import
de.hft.stuttgart.citydoctor2.check.CheckError
;
import
de.hft.stuttgart.citydoctor2.check.CheckError
;
import
de.hft.stuttgart.citydoctor2.check.CheckId
;
import
de.hft.stuttgart.citydoctor2.check.CheckId
;
import
de.hft.stuttgart.citydoctor2.check.CheckResult
;
import
de.hft.stuttgart.citydoctor2.check.CheckResult
;
import
de.hft.stuttgart.citydoctor2.check.GeometrySelfIntersection
;
import
de.hft.stuttgart.citydoctor2.check.Requirement
;
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
;
...
@@ -38,11 +37,10 @@ import de.hft.stuttgart.citydoctor2.checks.util.SelfIntersectionUtil;
...
@@ -38,11 +37,10 @@ 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.Polygon
;
import
de.hft.stuttgart.citydoctor2.datastructure.Polygon
;
import
de.hft.stuttgart.citydoctor2.datastructure.ConcretePolygon
;
import
de.hft.stuttgart.citydoctor2.utils.PolygonIntersection
;
import
de.hft.stuttgart.citydoctor2.utils.PolygonIntersection
;
import
de.hft.stuttgart.citydoctor2.datastructure.bht.AABB
;
import
de.hft.stuttgart.citydoctor2.datastructure.bht.AABB
;
import
de.hft.stuttgart.citydoctor2.datastructure.bht.
AABBUtils
;
import
de.hft.stuttgart.citydoctor2.datastructure.bht.
BoundingVolumeHierarchyTree
;
/**
/**
* Check for self intersecting solids
* Check for self intersecting solids
...
@@ -79,37 +77,30 @@ public class SolidSelfIntCheckAABB extends Check {
...
@@ -79,37 +77,30 @@ public class SolidSelfIntCheckAABB extends Check {
if
(
g
.
getType
()
!=
GeometryType
.
SOLID
&&
g
.
getType
()
!=
GeometryType
.
COMPOSITE_SURFACE
)
{
if
(
g
.
getType
()
!=
GeometryType
.
SOLID
&&
g
.
getType
()
!=
GeometryType
.
COMPOSITE_SURFACE
)
{
return
;
return
;
}
}
// ---
cheap
broad-phase
using per-polygon AABBs
---
// --- broad-phase
via BVH (AABB tree)
---
List
<
Polygon
>
polys
=
g
.
getPolygons
();
List
<
Polygon
>
polys
=
g
.
getPolygons
();
if
(
polys
==
null
||
polys
.
size
()
<=
1
)
{
if
(
polys
==
null
||
polys
.
size
()
<=
1
)
{
g
.
addCheckResult
(
new
CheckResult
(
this
,
ResultStatus
.
OK
,
null
));
g
.
addCheckResult
(
new
CheckResult
(
this
,
ResultStatus
.
OK
,
null
));
return
;
return
;
}
// Building BVH Tree
// Build AABBs once
AABB
[]
boxes
=
new
AABB
[
polys
.
size
()];
for
(
int
i
=
0
;
i
<
polys
.
size
();
i
++)
{
ConcretePolygon
cp
=
polys
.
get
(
i
).
getOriginal
();
boxes
[
i
]
=
AABB
.
of
(
cp
);
}
// If no AABB pair overlaps, self-intersection is impossible
if
(!
AABB
.
doAnyBoxesOverlap
(
boxes
))
{
g
.
addCheckResult
(
new
CheckResult
(
this
,
ResultStatus
.
OK
,
null
));
return
;
}
}
// --- ---
CheckResult
cr
;
CheckResult
cr
;
List
<
PolygonIntersection
>
intersections
=
SelfIntersectionUtil
.
calculateSolidSelfIntersection
(
g
,
0.001
,
tree
);
// Build BVH on polygons, but compute AABBs from the *original* polygons
BoundingVolumeHierarchyTree
<
Polygon
>
tree
=
new
BoundingVolumeHierarchyTree
<>(
polys
,
p
->
AABB
.
of
(
p
.
getOriginal
()));
// TODO: comparison with older version without tree
List
<
PolygonIntersection
>
intersections
=
SelfIntersectionUtil
.
calculateSolidSelfIntersection
(
g
,
0.001
,
tree
);
if
(
intersections
.
isEmpty
())
{
if
(
intersections
.
isEmpty
())
{
cr
=
new
CheckResult
(
this
,
ResultStatus
.
OK
,
null
);
cr
=
new
CheckResult
(
this
,
ResultStatus
.
OK
,
null
);
}
else
{
}
else
{
CheckError
e
=
new
SolidSelfIntError
(
g
,
intersections
);
CheckError
e
=
new
SolidSelfIntError
(
g
,
intersections
);
cr
=
new
CheckResult
(
this
,
ResultStatus
.
ERROR
,
e
);
cr
=
new
CheckResult
(
this
,
ResultStatus
.
ERROR
,
e
);
}
}
g
.
addCheckResult
(
cr
);
g
.
addCheckResult
(
cr
);
}
}
...
...
CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/checks/geometry/SolidSelfIntCheck.java
View file @
2d2487cc
...
@@ -85,6 +85,7 @@ public class SolidSelfIntCheck extends Check {
...
@@ -85,6 +85,7 @@ public class SolidSelfIntCheck extends Check {
return
;
return
;
}
}
CheckResult
cr
;
CheckResult
cr
;
// TODO: reproduce older version by Mathias of calculateSolidSefInt to compare
List
<
PolygonIntersection
>
intersections
=
SelfIntersectionUtil
.
calculateSolidSelfIntersection
(
g
,
delta
);
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
);
...
...
CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/checks/util/SelfIntersectionUtil.java
View file @
2d2487cc
...
@@ -91,49 +91,113 @@ public class SelfIntersectionUtil {
...
@@ -91,49 +91,113 @@ public class SelfIntersectionUtil {
}
}
public
static
List
<
PolygonIntersection
>
calculateSolidSelfIntersection
(
Geometry
g
,
double
delta
,
BoundingVolumeHierarchyTree
<
Polygon
>
tree
)
{
// Tesselation and filtering degenerated triangles
List
<
TesselatedPolygon
>
tesselatedPolygons
=
new
ArrayList
<>();
private
static
List
<
TesselatedPolygon
>
tesselateAndFilter
(
Geometry
g
,
double
delta
)
{
for
(
Polygon
p
:
g
.
getPolygons
())
{
List
<
TesselatedPolygon
>
tesselatedPolygons
=
new
ArrayList
<>();
TesselatedPolygon
tessPolygon
=
EarcutTesselator
.
tesselatePolygon
(
p
);
for
(
Iterator
<
Triangle3d
>
iterator
=
tessPolygon
.
getTriangles
().
iterator
();
iterator
.
hasNext
();)
{
Triangle3d
t
=
iterator
.
next
();
List
<
Vector3d
>
vertices
=
new
ArrayList
<>(
3
);
vertices
.
add
(
t
.
getP1
());
vertices
.
add
(
t
.
getP2
());
vertices
.
add
(
t
.
getP3
());
Vector3d
centroid
=
CovarianceMatrix
.
getCentroid
(
vertices
);
EigenvalueDecomposition
ed
=
OrthogonalRegressionPlane
.
decompose
(
vertices
,
centroid
);
Matrix
eigenValues
=
ed
.
getD
();
double
[]
eigenValuesArray
=
new
double
[
3
];
eigenValuesArray
[
0
]
=
eigenValues
.
get
(
0
,
0
);
eigenValuesArray
[
1
]
=
eigenValues
.
get
(
1
,
1
);
eigenValuesArray
[
2
]
=
eigenValues
.
get
(
2
,
2
);
if
(
eigenValuesArray
[
1
]
<
delta
)
{
iterator
.
remove
();
}
}
tesselatedPolygons
.
add
(
tessPolygon
);
}
List
<
PolygonIntersection
>
intersections
=
new
ArrayList
<>();
for
(
Polygon
p
:
g
.
getPolygons
())
{
for
(
int
i
=
0
;
i
<
tesselatedPolygons
.
size
()
-
1
;
i
++)
{
TesselatedPolygon
tessPolygon
=
EarcutTesselator
.
tesselatePolygon
(
p
);
TesselatedPolygon
p1
=
tesselatedPolygons
.
get
(
i
);
List
<
Polygon
>
candidates
=
tree
.
findCandidates
(
AABB
.
of
(
p1
.
getOriginal
()));
for
(
Iterator
<
Triangle3d
>
it
=
tessPolygon
.
getTriangles
().
iterator
();
it
.
hasNext
();)
{
if
(
candidates
.
isEmpty
())
{
Triangle3d
t
=
it
.
next
();
// TODO:
}
for
(
int
j
=
i
+
1
;
j
<
tesselatedPolygons
.
size
();
j
++)
{
TesselatedPolygon
p2
=
tesselatedPolygons
.
get
(
j
);
GeometrySelfIntersection
intersection
=
doPolygonsIntersect
(
p1
,
p2
,
delta
);
if
(
intersection
!=
null
)
{
intersections
.
add
(
PolygonIntersection
.
triangles
(
intersection
.
t1
(),
intersection
.
t2
()));
}
}
}
return
intersections
;
}
List
<
Vector3d
>
vertices
=
new
ArrayList
<>(
3
);
vertices
.
add
(
t
.
getP1
());
vertices
.
add
(
t
.
getP2
());
vertices
.
add
(
t
.
getP3
());
Vector3d
centroid
=
CovarianceMatrix
.
getCentroid
(
vertices
);
EigenvalueDecomposition
ed
=
OrthogonalRegressionPlane
.
decompose
(
vertices
,
centroid
);
Matrix
eigenValues
=
ed
.
getD
();
double
ev1
=
eigenValues
.
get
(
1
,
1
);
if
(
ev1
<
delta
)
{
it
.
remove
();
}
}
tesselatedPolygons
.
add
(
tessPolygon
);
}
return
tesselatedPolygons
;
}
/*
* @ Baris Numanoglu
*
* New Version with tree query
* */
public
static
List
<
PolygonIntersection
>
calculateSolidSelfIntersection
(
Geometry
g
,
double
delta
,
BoundingVolumeHierarchyTree
<
Polygon
>
tree
)
{
List
<
TesselatedPolygon
>
tesselatedPolygons
=
tesselateAndFilter
(
g
,
delta
);
// Map: original ConcretePolygon (identity) -> index in tesselatedPolygons
IdentityHashMap
<
ConcretePolygon
,
Integer
>
indexByOriginal
=
new
IdentityHashMap
<>();
for
(
int
i
=
0
;
i
<
tesselatedPolygons
.
size
();
i
++)
{
Polygon
p
=
tesselatedPolygons
.
get
(
i
).
getOriginal
();
// returns Polygon
ConcretePolygon
orig
=
p
.
getOriginal
();
// returns ConcretePolygon
indexByOriginal
.
put
(
orig
,
i
);
}
List
<
PolygonIntersection
>
intersections
=
new
ArrayList
<>();
for
(
int
i
=
0
;
i
<
tesselatedPolygons
.
size
()
-
1
;
i
++)
{
TesselatedPolygon
p1
=
tesselatedPolygons
.
get
(
i
);
// Query AABB based on original polygon (consistent with tree construction)
ConcretePolygon
p1Orig
=
p1
.
getOriginal
().
getOriginal
();
// p1:teselatedPoly->Polygon->Concrete Polygon
AABB
q
=
AABB
.
of
(
p1Orig
);
List
<
Polygon
>
candidates
=
tree
.
getAllIntersectingElements
(
q
);
if
(
candidates
.
isEmpty
())
{
continue
;
// no candidate ergo no overlap
}
for
(
Polygon
cand
:
candidates
)
{
ConcretePolygon
candOrig
=
cand
.
getOriginal
();
Integer
jObj
=
indexByOriginal
.
get
(
candOrig
);
if
(
jObj
==
null
)
{
continue
;
// candidate not in tesselated-Liste (RE: edge case)
}
int
j
=
jObj
.
intValue
();
if
(
j
<=
i
)
{
continue
;
// avoids double pairwise checks and self-pair
}
TesselatedPolygon
p2
=
tesselatedPolygons
.
get
(
j
);
// TODO may be later a further tree in here
GeometrySelfIntersection
inter
=
doPolygonsIntersect
(
p1
,
p2
,
delta
);
if
(
inter
!=
null
)
{
intersections
.
add
(
PolygonIntersection
.
triangles
(
inter
.
t1
(),
inter
.
t2
()));
}
}
}
return
intersections
;
}
// Older Version without Tree: going to be used for comparison
public
static
List
<
PolygonIntersection
>
calculateSolidSelfIntersection
(
Geometry
g
,
double
delta
)
{
List
<
TesselatedPolygon
>
tesselatedPolygons
=
tesselateAndFilter
(
g
,
delta
);
List
<
PolygonIntersection
>
intersections
=
new
ArrayList
<>();
for
(
int
i
=
0
;
i
<
tesselatedPolygons
.
size
()
-
1
;
i
++)
{
TesselatedPolygon
p1
=
tesselatedPolygons
.
get
(
i
);
for
(
int
j
=
i
+
1
;
j
<
tesselatedPolygons
.
size
();
j
++)
{
TesselatedPolygon
p2
=
tesselatedPolygons
.
get
(
j
);
GeometrySelfIntersection
inter
=
doPolygonsIntersect
(
p1
,
p2
,
delta
);
if
(
inter
!=
null
)
{
intersections
.
add
(
PolygonIntersection
.
triangles
(
inter
.
t1
(),
inter
.
t2
()));
}
}
}
return
intersections
;
}
public
static
GeometrySelfIntersection
doesSolidSelfIntersect
(
Geometry
g
,
double
epsilon
)
{
public
static
GeometrySelfIntersection
doesSolidSelfIntersect
(
Geometry
g
,
double
epsilon
)
{
return
selfIntersectionJava
(
g
,
epsilon
);
return
selfIntersectionJava
(
g
,
epsilon
);
}
}
...
...
CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/checks/bht/GeometryChecksWithAABBTest.java
View file @
2d2487cc
...
@@ -4,6 +4,7 @@ package de.hft.stuttgart.citydoctor2.checks.bht;
...
@@ -4,6 +4,7 @@ package de.hft.stuttgart.citydoctor2.checks.bht;
import
de.hft.stuttgart.citydoctor2.datastructure.ConcretePolygon
;
import
de.hft.stuttgart.citydoctor2.datastructure.ConcretePolygon
;
import
de.hft.stuttgart.citydoctor2.datastructure.LinearRing
;
import
de.hft.stuttgart.citydoctor2.datastructure.LinearRing
;
import
de.hft.stuttgart.citydoctor2.datastructure.Vertex
;
import
de.hft.stuttgart.citydoctor2.datastructure.Vertex
;
import
de.hft.stuttgart.citydoctor2.datastructure.Geometry
;
import
java.util.Arrays
;
import
java.util.Arrays
;
import
java.util.List
;
import
java.util.List
;
...
@@ -94,7 +95,8 @@ public class GeometryChecksWithAABBTest {
...
@@ -94,7 +95,8 @@ public class GeometryChecksWithAABBTest {
ConcretePolygon
p
=
new
ConcretePolygon
();
ConcretePolygon
p
=
new
ConcretePolygon
();
p
.
setExteriorRing
(
ring
);
p
.
setExteriorRing
(
ring
);
Geometry
g
=
new
Geometry
(
GeometryType
.
SOLID
,
Lod
.
LOD2
);
// TODO Check semantics of Orientation
Geometry
g
=
new
Geometry
(
GeometryType
.
SOLID
,
Lod
.
LOD2
,
Geometry
.
Orientation
.
OUTWARD
);
g
.
addPolygon
(
p
);
// ensures parent links exist
g
.
addPolygon
(
p
);
// ensures parent links exist
g
.
updateEdgesAndVertices
();
g
.
updateEdgesAndVertices
();
...
@@ -133,7 +135,8 @@ public class GeometryChecksWithAABBTest {
...
@@ -133,7 +135,8 @@ public class GeometryChecksWithAABBTest {
));
));
p2
.
setExteriorRing
(
r2
);
p2
.
setExteriorRing
(
r2
);
Geometry
solid
=
new
Geometry
(
GeometryType
.
SOLID
,
Lod
.
LOD2
);
// TODO Check Orientation<-OUTWARD again
Geometry
solid
=
new
Geometry
(
GeometryType
.
SOLID
,
Lod
.
LOD2
,
Geometry
.
Orientation
.
OUTWARD
);
solid
.
getPolygons
().
addAll
(
List
.
of
(
p1
,
p2
));
solid
.
getPolygons
().
addAll
(
List
.
of
(
p1
,
p2
));
SolidSelfIntCheckAABB
check
=
new
SolidSelfIntCheckAABB
();
SolidSelfIntCheckAABB
check
=
new
SolidSelfIntCheckAABB
();
...
...
CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/checks/util/SolidSelfIntersectionBVHUtilTest.java
0 → 100644
View file @
2d2487cc
package
de.hft.stuttgart.citydoctor2.checks.util
;
import
static
org
.
junit
.
Assert
.*;
import
java.util.List
;
import
org.junit.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.datastructure.bht.AABB
;
import
de.hft.stuttgart.citydoctor2.datastructure.bht.BoundingVolumeHierarchyTree
;
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.utils.PolygonIntersection
;
public
class
SolidSelfIntersectionBVHUtilTest
{
@Test
public
void
testBVHCalculateOnKnownGoodModel
()
throws
CityGmlParseException
,
InvalidGmlFileException
{
ValidationConfiguration
config
=
ValidationConfiguration
.
loadStandardValidationConfig
();
config
.
setSchematronFilePathInGlobalParameters
(
null
);
CityDoctorModel
m
=
CityGmlParser
.
parseCityGmlFile
(
"src/test/resources/SolidSelfIntTest1.gml"
,
config
.
getParserConfiguration
()
);
Building
building
=
m
.
getBuildings
().
findFirst
().
orElseThrow
();
Geometry
g
=
building
.
getGeometry
(
GeometryType
.
SOLID
,
Lod
.
LOD2
);
assertNotNull
(
"Expected SOLID LOD2 geometry in test model"
,
g
);
List
<
Polygon
>
polys
=
g
.
getPolygons
();
assertNotNull
(
polys
);
assertTrue
(
"Expected at least 2 polygons"
,
polys
.
size
()
>
1
);
BoundingVolumeHierarchyTree
<
Polygon
>
tree
=
new
BoundingVolumeHierarchyTree
<>(
polys
,
p
->
AABB
.
of
(
p
.
getOriginal
()));
double
delta
=
0.001
;
// calls new method with trees
List
<
PolygonIntersection
>
intersections
=
SelfIntersectionUtil
.
calculateSolidSelfIntersection
(
g
,
delta
,
tree
);
// This file is a good example (no self intersection)
assertTrue
(
"No self-intersections expected for SolidSelfIntTest1.gml"
,
intersections
.
isEmpty
());
}
}
\ No newline at end of file
CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/checks/util/SolidSelfIntersectionOldVsNewTest.java
0 → 100644
View file @
2d2487cc
package
de.hft.stuttgart.citydoctor2.checks.util
;
import
static
org
.
junit
.
Assert
.*;
import
java.util.List
;
import
org.junit.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.datastructure.bht.AABB
;
import
de.hft.stuttgart.citydoctor2.datastructure.bht.BoundingVolumeHierarchyTree
;
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.utils.PolygonIntersection
;
/*
* 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/SolidSelfIntTest1.gml"
,
0.001
);
}
@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
);
BoundingVolumeHierarchyTree
<
Polygon
>
tree
=
new
BoundingVolumeHierarchyTree
<>(
polys
,
p
->
AABB
.
of
(
p
.
getOriginal
()));
List
<
PolygonIntersection
>
oldRes
=
SelfIntersectionUtil
.
calculateSolidSelfIntersection
(
g
,
delta
);
List
<
PolygonIntersection
>
newRes
=
SelfIntersectionUtil
.
calculateSolidSelfIntersection
(
g
,
delta
,
tree
);
assertEquals
(
"Old vs new self-intersection result count differs for: "
+
gmlPath
,
oldRes
.
size
(),
newRes
.
size
());
}
}
\ No newline at end of file
CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealMissingSolidTest.java
View file @
2d2487cc
...
@@ -61,6 +61,8 @@ import de.hft.stuttgart.citydoctor2.healer.Healer;
...
@@ -61,6 +61,8 @@ import de.hft.stuttgart.citydoctor2.healer.Healer;
import
de.hft.stuttgart.citydoctor2.parser.CityGmlParseException
;
import
de.hft.stuttgart.citydoctor2.parser.CityGmlParseException
;
import
de.hft.stuttgart.citydoctor2.parser.CityGmlParser
;
import
de.hft.stuttgart.citydoctor2.parser.CityGmlParser
;
import
de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException
;
import
de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException
;
import
de.hft.stuttgart.citydoctor2.database.CityObjectCache
;
import
de.hft.stuttgart.citydoctor2.database.UnconnectedCache
;
public
class
HealMissingSolidTest
{
public
class
HealMissingSolidTest
{
...
@@ -70,7 +72,13 @@ public class HealMissingSolidTest {
...
@@ -70,7 +72,13 @@ public class HealMissingSolidTest {
@Test
@Test
public
void
testCreateSolid
()
throws
CityDoctorWriteException
,
IOException
,
CityGmlParseException
,
InvalidGmlFileException
{
public
void
testCreateSolid
()
throws
CityDoctorWriteException
,
IOException
,
CityGmlParseException
,
InvalidGmlFileException
{
ValidationConfiguration
config
=
ValidationConfiguration
.
loadStandardValidationConfig
();
ValidationConfiguration
config
=
ValidationConfiguration
.
loadStandardValidationConfig
();
CityDoctorModel
model
=
new
CityDoctorModel
(
config
.
getParserConfiguration
(),
new
File
(
"test"
));
// edit @Numanoglu
CityDoctorModel
model
=
new
CityDoctorModel
(
config
.
getParserConfiguration
(),
new
File
(
"test"
),
new
UnconnectedCache
()
);
model
.
setCityModel
(
new
CityModel
());
model
.
setCityModel
(
new
CityModel
());
Building
b
=
new
Building
();
Building
b
=
new
Building
();
model
.
addBuilding
(
b
);
model
.
addBuilding
(
b
);
...
...
CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/bht/TestCityGmlAABB.java
View file @
2d2487cc
...
@@ -49,8 +49,10 @@ public class TestCityGmlAABB {
...
@@ -49,8 +49,10 @@ public class TestCityGmlAABB {
ValidationConfiguration
config
=
ValidationConfiguration
.
loadStandardValidationConfig
();
ValidationConfiguration
config
=
ValidationConfiguration
.
loadStandardValidationConfig
();
CityDoctorModel
model
=
de
.
hft
.
stuttgart
.
citydoctor2
.
healing
.
TestUtil
.
loadCityModel
(
filePathForParser
,
config
);
CityDoctorModel
model
=
de
.
hft
.
stuttgart
.
citydoctor2
.
healing
.
TestUtil
.
loadCityModel
(
filePathForParser
,
config
);
System
.
out
.
println
(
"Model loaded successfully.\n"
);
System
.
out
.
println
(
"Model loaded successfully.\n"
);
List
<
Building
>
buildings
=
model
.
getBuildings
();
// TODO : use stream Building
List
<
Building
>
buildings
=
model
.
getBuildings
().
toList
()
;
// --- 3) Menu: choose granularity ---
// --- 3) Menu: choose granularity ---
System
.
out
.
println
(
"\nChoose granularity:"
);
System
.
out
.
println
(
"\nChoose granularity:"
);
...
@@ -83,14 +85,13 @@ public class TestCityGmlAABB {
...
@@ -83,14 +85,13 @@ public class TestCityGmlAABB {
Set
<
ConcretePolygon
>
polys
=
collectAllPolygons
(
buildings
);
Set
<
ConcretePolygon
>
polys
=
collectAllPolygons
(
buildings
);
BoundingVolumeHierarchyTree
<
ConcretePolygon
>
bvh
=
new
BoundingVolumeHierarchyTree
<>(
BoundingVolumeHierarchyTree
<
ConcretePolygon
>
bvh
=
new
BoundingVolumeHierarchyTree
<>(
new
ArrayList
<>(
polys
),
new
ArrayList
<>(
polys
),
AABBUtils:
:
getAABB
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: "
);
bvh
.
getRoot
().
aabb
.
print
();
//
bvh.getRoot().aabb.print();
}
}
}
}
...
@@ -104,13 +105,13 @@ public class TestCityGmlAABB {
...
@@ -104,13 +105,13 @@ public class TestCityGmlAABB {
BoundingVolumeHierarchyTree
<
LinearRing
>
bvh
=
new
BoundingVolumeHierarchyTree
<>(
BoundingVolumeHierarchyTree
<
LinearRing
>
bvh
=
new
BoundingVolumeHierarchyTree
<>(
new
ArrayList
<>(
rings
),
new
ArrayList
<>(
rings
),
AABB
Utils:
:
computeAABBFromRing
AABB
:
:
of
);
);
System
.
out
.
println
(
label
+
" rings: "
+
rings
.
size
());
System
.
out
.
println
(
label
+
" rings: "
+
rings
.
size
());
if
(
bvh
.
getRoot
()
!=
null
)
{
if
(
bvh
.
getRoot
()
!=
null
)
{
System
.
out
.
print
(
"Root AABB: "
);
// TODO Assertion BLOCK
bvh
.
getRoot
().
aabb
.
print
(
);
System
.
out
.
println
(
"Root AABB: "
+
bvh
.
getRoot
().
getAabb
()
);
}
}
}
}
...
@@ -120,13 +121,13 @@ public class TestCityGmlAABB {
...
@@ -120,13 +121,13 @@ public class TestCityGmlAABB {
BoundingVolumeHierarchyTree
<
Vertex
>
bvh
=
new
BoundingVolumeHierarchyTree
<>(
BoundingVolumeHierarchyTree
<
Vertex
>
bvh
=
new
BoundingVolumeHierarchyTree
<>(
new
ArrayList
<>(
verts
),
new
ArrayList
<>(
verts
),
AABB
Utils:
:
computeAABBFromVertex
AABB
:
:
of
);
);
System
.
out
.
println
(
"Vertices: "
+
verts
.
size
());
System
.
out
.
println
(
"Vertices: "
+
verts
.
size
());
if
(
bvh
.
getRoot
()
!=
null
)
{
if
(
bvh
.
getRoot
()
!=
null
)
{
System
.
out
.
print
(
"Root AABB: "
);
System
.
out
.
print
(
"Root AABB: "
);
bvh
.
getRoot
().
aabb
.
print
();
//
bvh.getRoot().aabb.print();
}
}
}
}
...
@@ -252,7 +253,7 @@ public class TestCityGmlAABB {
...
@@ -252,7 +253,7 @@ public class TestCityGmlAABB {
"Resource nicht im Klassenpfad gefunden: "
+
resourcePath
+
" (versucht als: "
+
rp
+
")"
"Resource nicht im Klassenpfad gefunden: "
+
resourcePath
+
" (versucht als: "
+
rp
+
")"
);
);
}
}
// TODO Remove if redund.
private
static
String
normalizeResourcePath
(
String
path
)
{
private
static
String
normalizeResourcePath
(
String
path
)
{
String
p
=
path
.
replace
(
'\\'
,
'/'
);
String
p
=
path
.
replace
(
'\\'
,
'/'
);
// Quellordner-Präfixe entfernen, falls mit übergeben
// Quellordner-Präfixe entfernen, falls mit übergeben
...
...
CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/bht/TestExample.java
View file @
2d2487cc
...
@@ -58,7 +58,7 @@ public class TestExample {
...
@@ -58,7 +58,7 @@ public class TestExample {
// visitor
// visitor
// filter duplicate polygons out
// filter duplicate polygons out
Set
<
ConcretePolygon
>
allBuildingPolygons
=
new
HashSet
<>();
Set
<
ConcretePolygon
>
allBuildingPolygons
=
new
HashSet
<>();
for
(
Building
b
:
model
.
getBuildings
())
{
for
(
Building
b
:
model
.
getBuildings
()
.
toList
()
)
{
b
.
accept
(
new
CheckableUtilsVisitor
()
{
b
.
accept
(
new
CheckableUtilsVisitor
()
{
public
void
check
(
Polygon
poly
)
{
public
void
check
(
Polygon
poly
)
{
allBuildingPolygons
.
add
(
poly
.
getOriginal
());
allBuildingPolygons
.
add
(
poly
.
getOriginal
());
...
@@ -70,7 +70,7 @@ public class TestExample {
...
@@ -70,7 +70,7 @@ public class TestExample {
// // for loop
// // for loop
List
<
Polygon
>
allBuildingPolygons2
=
new
ArrayList
<>();
List
<
Polygon
>
allBuildingPolygons2
=
new
ArrayList
<>();
for
(
Building
b
:
model
.
getBuildings
())
{
for
(
Building
b
:
model
.
getBuildings
()
.
toList
()
)
{
for
(
Geometry
geom
:
b
.
getGeometries
())
{
for
(
Geometry
geom
:
b
.
getGeometries
())
{
for
(
Polygon
p
:
geom
.
getPolygons
())
{
for
(
Polygon
p
:
geom
.
getPolygons
())
{
allBuildingPolygons2
.
add
(
p
);
allBuildingPolygons2
.
add
(
p
);
...
@@ -85,7 +85,7 @@ public class TestExample {
...
@@ -85,7 +85,7 @@ public class TestExample {
// visitor
// visitor
// filter duplicate linear rings out
// filter duplicate linear rings out
Set
<
LinearRing
>
allBuildingLinearRings
=
new
HashSet
<>();
Set
<
LinearRing
>
allBuildingLinearRings
=
new
HashSet
<>();
for
(
Building
b
:
model
.
getBuildings
())
{
for
(
Building
b
:
model
.
getBuildings
()
.
toList
()
)
{
b
.
accept
(
new
CheckableUtilsVisitor
()
{
b
.
accept
(
new
CheckableUtilsVisitor
()
{
public
void
check
(
LinearRing
ring
)
{
public
void
check
(
LinearRing
ring
)
{
allBuildingLinearRings
.
add
(
ring
);
allBuildingLinearRings
.
add
(
ring
);
...
@@ -100,7 +100,7 @@ public class TestExample {
...
@@ -100,7 +100,7 @@ public class TestExample {
// visitor
// visitor
// filter duplicate exterior rings out
// filter duplicate exterior rings out
Set
<
LinearRing
>
allBuildingExteriorRings
=
new
HashSet
<>();
Set
<
LinearRing
>
allBuildingExteriorRings
=
new
HashSet
<>();
for
(
Building
b
:
model
.
getBuildings
())
{
for
(
Building
b
:
model
.
getBuildings
()
.
toList
()
)
{
b
.
accept
(
new
CheckableUtilsVisitor
()
{
b
.
accept
(
new
CheckableUtilsVisitor
()
{
public
void
check
(
LinearRing
ring
)
{
public
void
check
(
LinearRing
ring
)
{
allBuildingExteriorRings
.
add
(
ring
.
getParent
().
getExteriorRing
());
// ACHTUNG getParent
allBuildingExteriorRings
.
add
(
ring
.
getParent
().
getExteriorRing
());
// ACHTUNG getParent
...
@@ -110,24 +110,8 @@ public class TestExample {
...
@@ -110,24 +110,8 @@ public class TestExample {
System
.
out
.
println
(
"\nExteriorRings via visitor:"
+
allBuildingExteriorRings
);
//new
System
.
out
.
println
(
"\nExteriorRings via visitor:"
+
allBuildingExteriorRings
);
//new
// // new: ExteriorRings (List)
// // for loop
// List<LinearRing> allBuildingExteriorRings2 = new ArrayList<>();
// for (Building b : model.getBuildings()) {
// for (Geometry geom : b.getGeometries()) {
// for (Polygon p : geom.getPolygons()) {
// allBuildingExteriorRings2.add(p.getOriginal().getExteriorRing());
// }
// }
// }
// System.out.println("\nExteriorRing List:" + allBuildingExteriorRings2); //new
// new: InnerRings
// visitor
// filter duplicate inner rings out
Set
<
LinearRing
>
allBuildingInnerRings
=
new
HashSet
<>();
Set
<
LinearRing
>
allBuildingInnerRings
=
new
HashSet
<>();
for
(
Building
b
:
model
.
getBuildings
())
{
for
(
Building
b
:
model
.
getBuildings
()
.
toList
()
)
{
b
.
accept
(
new
CheckableUtilsVisitor
()
{
b
.
accept
(
new
CheckableUtilsVisitor
()
{
public
void
check
(
Polygon
poly
)
{
public
void
check
(
Polygon
poly
)
{
allBuildingInnerRings
.
addAll
(
poly
.
getOriginal
().
getInnerRings
());
// ACHTUNG getOriginal
allBuildingInnerRings
.
addAll
(
poly
.
getOriginal
().
getInnerRings
());
// ACHTUNG getOriginal
...
...
CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/bht/TestExampleAABB.java
View file @
2d2487cc
...
@@ -87,8 +87,9 @@ public class TestExampleAABB {
...
@@ -87,8 +87,9 @@ public class TestExampleAABB {
Checker
c
=
new
Checker
(
config
,
model
);
Checker
c
=
new
Checker
(
config
,
model
);
c
.
runChecks
();
c
.
runChecks
();
Building
building
=
model
.
getBuildings
().
get
(
0
);
Building
building
=
model
.
getBuildings
()
.
findFirst
()
.
orElseThrow
(()
->
new
IllegalStateException
(
"No buildings found"
));
// assertFalse(building.containsError(CheckId.C_GE_S_SELF_INTERSECTION));
// assertFalse(building.containsError(CheckId.C_GE_S_SELF_INTERSECTION));
// assertEquals(building.containsError(CheckId.C_GE_S_SELF_INTERSECTION));
// assertEquals(building.containsError(CheckId.C_GE_S_SELF_INTERSECTION));
// assertNotNull(building.containsError(CheckId.C_GE_S_SELF_INTERSECTION));
// assertNotNull(building.containsError(CheckId.C_GE_S_SELF_INTERSECTION));
...
...
CityDoctorParent/Extensions/CityDoctorHealerGUI/src/main/java/de/hft/stuttgart/citydoctor2/healer/gui/HealerController.java
View file @
2d2487cc
...
@@ -535,43 +535,35 @@ public class HealerController {
...
@@ -535,43 +535,35 @@ public class HealerController {
}
}
public
void
injectSolid
(
boolean
useBs
,
boolean
useBi
,
boolean
useLod2
,
boolean
useLod3
,
boolean
useLod4
)
{
public
void
injectSolid
(
boolean
useBs
,
boolean
useBi
,
boolean
useLod2
,
boolean
useLod3
,
boolean
useLod4
)
{
// if (model == null || currentFeature == null) {
if
(
model
==
null
)
{
// return;
return
;
// }
}
for
(
Building
b
:
model
.
getBuildings
())
{
// collect polygons
Map
<
Lod
,
List
<
Polygon
>>
availablePolygons
=
new
EnumMap
<>(
Lod
.
class
);
Map
<
Lod
,
Set
<
Polygon
>>
existingPolygons
=
new
EnumMap
<>(
Lod
.
class
);
collectPolygons
(
useBs
,
useBi
,
availablePolygons
,
existingPolygons
,
b
);
if
(
useLod2
)
{
insertSolidGeometry
(
availablePolygons
,
b
,
existingPolygons
,
Lod
.
LOD2
);
}
if
(
useLod3
)
{
insertSolidGeometry
(
availablePolygons
,
b
,
existingPolygons
,
Lod
.
LOD3
);
}
if
(
useLod4
)
{
insertSolidGeometry
(
availablePolygons
,
b
,
existingPolygons
,
Lod
.
LOD4
);
}
for
(
BuildingPart
part
:
b
.
getBuildingParts
())
{
// collect polygons
availablePolygons
=
new
EnumMap
<>(
Lod
.
class
);
existingPolygons
=
new
EnumMap
<>(
Lod
.
class
);
collectPolygons
(
useBs
,
useBi
,
availablePolygons
,
existingPolygons
,
part
);
if
(
useLod2
)
{
insertSolidGeometry
(
availablePolygons
,
part
,
existingPolygons
,
Lod
.
LOD2
);
}
if
(
useLod3
)
{
insertSolidGeometry
(
availablePolygons
,
part
,
existingPolygons
,
Lod
.
LOD3
);
}
if
(
useLod4
)
{
insertSolidGeometry
(
availablePolygons
,
part
,
existingPolygons
,
Lod
.
LOD4
);
}
}
}
}
model
.
getBuildings
().
forEach
(
b
->
{
// --- Building ---
Map
<
Lod
,
List
<
Polygon
>>
availablePolygonsB
=
new
EnumMap
<>(
Lod
.
class
);
Map
<
Lod
,
Set
<
Polygon
>>
existingPolygonsB
=
new
EnumMap
<>(
Lod
.
class
);
collectPolygons
(
useBs
,
useBi
,
availablePolygonsB
,
existingPolygonsB
,
b
);
if
(
useLod2
)
insertSolidGeometry
(
availablePolygonsB
,
b
,
existingPolygonsB
,
Lod
.
LOD2
);
if
(
useLod3
)
insertSolidGeometry
(
availablePolygonsB
,
b
,
existingPolygonsB
,
Lod
.
LOD3
);
if
(
useLod4
)
insertSolidGeometry
(
availablePolygonsB
,
b
,
existingPolygonsB
,
Lod
.
LOD4
);
// --- BuildingParts ---
// Falls getBuildingParts() jetzt auch Stream liefert, ist das so korrekt:
b
.
getBuildingParts
().
forEach
(
part
->
{
Map
<
Lod
,
List
<
Polygon
>>
availablePolygonsP
=
new
EnumMap
<>(
Lod
.
class
);
Map
<
Lod
,
Set
<
Polygon
>>
existingPolygonsP
=
new
EnumMap
<>(
Lod
.
class
);
collectPolygons
(
useBs
,
useBi
,
availablePolygonsP
,
existingPolygonsP
,
part
);
if
(
useLod2
)
insertSolidGeometry
(
availablePolygonsP
,
part
,
existingPolygonsP
,
Lod
.
LOD2
);
if
(
useLod3
)
insertSolidGeometry
(
availablePolygonsP
,
part
,
existingPolygonsP
,
Lod
.
LOD3
);
if
(
useLod4
)
insertSolidGeometry
(
availablePolygonsP
,
part
,
existingPolygonsP
,
Lod
.
LOD4
);
});
});
}
private
void
collectPolygons
(
boolean
useBs
,
boolean
useBi
,
Map
<
Lod
,
List
<
Polygon
>>
availablePolygons
,
private
void
collectPolygons
(
boolean
useBs
,
boolean
useBi
,
Map
<
Lod
,
List
<
Polygon
>>
availablePolygons
,
Map
<
Lod
,
Set
<
Polygon
>>
existingPolygons
,
AbstractBuilding
b
)
{
Map
<
Lod
,
Set
<
Polygon
>>
existingPolygons
,
AbstractBuilding
b
)
{
if
(
useBs
)
{
if
(
useBs
)
{
...
...
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