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
a4c9094e
Commit
a4c9094e
authored
Mar 06, 2026
by
Matthias Betz
Browse files
fixes
parent
2d2487cc
Pipeline
#12355
failed with stage
in 1 minute and 54 seconds
Changes
4
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/datastructure/bht/BoundingVolumeHierarchyTree.java
View file @
a4c9094e
...
...
@@ -112,13 +112,13 @@ public class BoundingVolumeHierarchyTree<E> {
}
// Works with overlaps()<--includes touching; not with intersects()
public
List
<
E
>
getAll
Intersect
ingElements
(
AABB
query
)
{
public
List
<
E
>
getAll
Overlapp
ingElements
(
AABB
query
)
{
List
<
E
>
result
=
new
ArrayList
<>();
getAll
Intersect
ingElementsRecursive
(
root
,
query
,
result
);
getAll
Overlapp
ingElementsRecursive
(
root
,
query
,
result
);
return
result
;
}
private
void
getAll
Intersect
ingElementsRecursive
(
Node
<
E
>
node
,
AABB
query
,
List
<
E
>
result
)
{
private
void
getAll
Overlapp
ingElementsRecursive
(
Node
<
E
>
node
,
AABB
query
,
List
<
E
>
result
)
{
if
(
node
==
null
)
{
return
;
}
...
...
@@ -137,7 +137,7 @@ public class BoundingVolumeHierarchyTree<E> {
}
for
(
Node
<
E
>
child
:
node
.
getChildren
())
{
getAll
Intersect
ingElementsRecursive
(
child
,
query
,
result
);
getAll
Overlapp
ingElementsRecursive
(
child
,
query
,
result
);
}
}
...
...
CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/checks/bht/RingSelfIntCheckAABB.java
View file @
a4c9094e
...
...
@@ -122,7 +122,7 @@ public class RingSelfIntCheckAABB extends Check {
return
;
}
}
// --- Original pairwise edge test, now with AABB early-out ---
for
(
int
i
=
0
;
i
<
edges
.
size
()
-
1
;
i
++)
{
Edge
e1
=
edges
.
get
(
i
);
...
...
CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/checks/util/SelfIntersectionUtil.java
View file @
a4c9094e
...
...
@@ -123,6 +123,66 @@ public class SelfIntersectionUtil {
return
tesselatedPolygons
;
}
/*
* @ Baris Numanoglu
*
* New Version with tree query
* */
public
static
List
<
PolygonIntersection
>
calculateSolidSelfIntersectionWithTree
(
Geometry
g
,
double
delta
)
{
List
<
TesselatedPolygon
>
tesselatedPolygons
=
tesselateAndFilter
(
g
,
delta
);
List
<
Integer
>
indices
=
new
ArrayList
<>(
tesselatedPolygons
.
size
());
for
(
int
i
=
0
;
i
<
tesselatedPolygons
.
size
();
i
++)
{
indices
.
add
(
i
);
}
// Build BVH on polygons, but compute AABBs from the *original* polygons
BoundingVolumeHierarchyTree
<
Integer
>
tree
=
new
BoundingVolumeHierarchyTree
<>(
indices
,
index
->
AABB
.
of
(
tesselatedPolygons
.
get
(
index
).
getOriginal
()));
// 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)
AABB
q
=
AABB
.
of
(
p1
.
getOriginal
());
List
<
Integer
>
candidates
=
tree
.
getAllOverlappingElements
(
q
);
if
(
candidates
.
isEmpty
())
{
continue
;
// no candidate ergo no overlap
}
for
(
Integer
j
:
candidates
)
{
if
(
j
<=
i
)
{
// avoids double pairwise checks and self-pair
continue
;
}
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
;
}
/*
* @ Baris Numanoglu
*
...
...
@@ -150,7 +210,7 @@ public class SelfIntersectionUtil {
ConcretePolygon
p1Orig
=
p1
.
getOriginal
().
getOriginal
();
// p1:teselatedPoly->Polygon->Concrete Polygon
AABB
q
=
AABB
.
of
(
p1Orig
);
List
<
Polygon
>
candidates
=
tree
.
getAll
Intersect
ingElements
(
q
);
List
<
Polygon
>
candidates
=
tree
.
getAll
Overlapp
ingElements
(
q
);
if
(
candidates
.
isEmpty
())
{
continue
;
// no candidate ergo no overlap
}
...
...
CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/checks/util/SolidSelfIntersectionOldVsNewTest.java
View file @
a4c9094e
...
...
@@ -4,7 +4,7 @@ import static org.junit.Assert.*;
import
java.util.List
;
import
org.junit.Test
;
import
org.junit.
jupiter.api.
Test
;
import
de.hft.stuttgart.citydoctor2.check.ValidationConfiguration
;
import
de.hft.stuttgart.citydoctor2.datastructure.Building
;
...
...
@@ -27,42 +27,48 @@ import de.hft.stuttgart.citydoctor2.utils.PolygonIntersection;
* */
public
class
SolidSelfIntersectionOldVsNewTest
{
@Test
public
void
testOldVsNewSameResultCount
()
throws
CityGmlParseException
,
InvalidGmlFileException
{
compareOnFile
(
"src/test/resources/SolidSelfIntTest
1
.gml"
,
0.001
);
}
@Test
public
void
testOldVsNewSameResultCount
()
throws
CityGmlParseException
,
InvalidGmlFileException
{
compareOnFile
(
"src/test/resources/SolidSelfIntTest
-known_false_positive_Big_Mesh2
.gml"
,
0.001
);
}
@Test
public
void
testOldVsNewSameResultCountFalsePositiveExample1
()
throws
CityGmlParseException
,
InvalidGmlFileException
{
compareOnFile
(
"src/test/resources/SolidSelfIntTest-known_false_positive1.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);
// }
@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
);
private
void
compareOnFile
(
String
gmlPath
,
double
delta
)
throws
CityGmlParseException
,
InvalidGmlFileException
{
ValidationConfiguration
config
=
ValidationConfiguration
.
loadStandardValidationConfig
();
config
.
setSchematronFilePathInGlobalParameters
(
null
);
CityDoctorModel
m
=
CityGmlParser
.
parseCityGmlFile
(
gmlPath
,
config
.
getParserConfiguration
());
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
);
Building
building
=
m
.
get
Buildings
().
findFirst
().
orElseThrow
();
Geometry
g
=
building
.
getGeometry
(
GeometryType
.
SOLID
,
Lod
.
LOD2
);
assertNotNull
(
"Expected SOLID LOD2 geometry in test model: "
+
gmlPath
,
g
);
List
<
Polygon
>
polys
=
g
.
get
Polygons
();
assertNotNull
(
polys
);
assertTrue
(
"Expected at least 2 polygons in: "
+
gmlPath
,
polys
.
size
()
>
1
);
List
<
Polygon
>
polys
=
g
.
getPolygons
();
assertNotNull
(
polys
);
assertTrue
(
"Expected at least 2 polygons in: "
+
gmlPath
,
polys
.
size
()
>
1
);
long
start
=
System
.
nanoTime
();
List
<
PolygonIntersection
>
oldRes
=
SelfIntersectionUtil
.
calculateSolidSelfIntersection
(
g
,
delta
);
long
dif
=
System
.
nanoTime
()
-
start
;
System
.
out
.
println
(
"Alt: "
+
dif
);
BoundingVolumeHierarchyTree
<
Polygon
>
tree
=
new
BoundingVolumeHierarchyTree
<>(
polys
,
p
->
AABB
.
of
(
p
.
getOriginal
()));
start
=
System
.
nanoTime
();
List
<
PolygonIntersection
>
newRes
=
SelfIntersectionUtil
.
calculateSolidSelfIntersectionWithTree
(
g
,
delta
);
dif
=
System
.
nanoTime
()
-
start
;
System
.
out
.
println
(
"Neu: "
+
dif
);
List
<
PolygonIntersection
>
oldRes
=
SelfIntersectionUtil
.
calculateSolidSelfIntersection
(
g
,
delta
);
List
<
PolygonIntersection
>
newRes
=
SelfIntersectionUtil
.
calculateSolidSelfIntersection
(
g
,
delta
,
tree
);
assertFalse
(
oldRes
.
isEmpty
()
);
assertFalse
(
newRes
.
isEmpty
()
);
assertEquals
(
"Old vs new self-intersection result count differs for: "
+
gmlPath
,
oldRes
.
size
(),
newRes
.
size
());
}
assertEquals
(
"Old vs new self-intersection result count differs for: "
+
gmlPath
,
oldRes
.
size
(),
newRes
.
size
());
}
}
\ No newline at end of file
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