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
c67a5961
Commit
c67a5961
authored
Jan 09, 2026
by
Numanoglu
Browse files
Bring over AABB bht work (model + validation + healer tests) from cf200f0
parent
8536ec35
Pipeline
#12312
failed with stage
in 1 minute and 41 seconds
Changes
423
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
.metadata/.plugins/org.eclipse.core.resources/.history/9a/30233d5b506d0010133f8119b8e960f2
0 → 100644
View file @
c67a5961
package
de
.
hft
.
stuttgart
.
citydoctor2
.
healer
.
aabb
.
bht
;
import
java
.
util
.*;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
ConcretePolygon
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
LinearRing
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
Vertex
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
LinearRing
.
LinearRingType
;
public
class
TestHouseAABB
{
private
static
ConcretePolygon
createTrianglePolygon
(
Point
p1
,
Point
p2
,
Point
p3
)
{
ConcretePolygon
poly
=
new
ConcretePolygon
();
LinearRing
ring
=
new
LinearRing
(
LinearRingType
.
EXTERIOR
);
ring
.
addVertex
(
new
Vertex
(
p1
.
getX
(),
p1
.
getY
(),
p1
.
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
(
p1
.
getX
(),
p1
.
getY
(),
p1
.
getZ
()));
//
Ring
schlie
ß
en
poly
.
setExteriorRing
(
ring
);
return
poly
;
}
private
static
ConcretePolygon
createQuadPolygon
(
Point
p1
,
Point
p2
,
Point
p3
,
Point
p4
)
{
ConcretePolygon
poly
=
new
ConcretePolygon
();
LinearRing
ring
=
new
LinearRing
(
LinearRingType
.
EXTERIOR
);
ring
.
addVertex
(
new
Vertex
(
p1
.
getX
(),
p1
.
getY
(),
p1
.
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
(
p4
.
getX
(),
p4
.
getY
(),
p4
.
getZ
()));
ring
.
addVertex
(
new
Vertex
(
p1
.
getX
(),
p1
.
getY
(),
p1
.
getZ
()));
//
Ring
schlie
ß
en
poly
.
setExteriorRing
(
ring
);
return
poly
;
}
}
.metadata/.plugins/org.eclipse.core.resources/.history/9a/70c98d9652e900101245d5e14ea95888
0 → 100644
View file @
c67a5961
package
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
bht
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
bht
.*;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.*;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
parser
.*;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
systemtest
.
TestUtil
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
check
.*;
//
import
de
.
hft
.
stuttgart
.
citydoctor2
.
healing
.*;
import
java
.
io
.
IOException
;
import
java
.
util
.*;
//
src
/
test
/
java
/.../
TestCityGmlAABB
.
java
import
java
.
net
.
URL
;
import
java
.
nio
.
file
.
Paths
;
public
class
TestCityGmlAABB
{
public
static
void
main
(
String
[]
args
)
throws
CityGmlParseException
,
IOException
,
InvalidGmlFileException
{
System
.
out
.
println
(
"=== CityGML AABB Test ==="
);
//
---
1
)
Ask
user
which
test
case
to
run
---
Scanner
sc
=
new
Scanner
(
System
.
in
);
System
.
out
.
print
(
"Enter TestCase ID (e.g. PO_TWO_INNERS, SO_WRONG_POLY_ORIENTATION_SINGLE) "
+
"or press Enter for default: "
);
String
id
=
sc
.
nextLine
().
trim
();
//
Default
w
ä
hlen
String
resourcePath
=
TestPaths
.
PO_TWO_INNERS
;
if
(
!id.isEmpty()) {
try
{
//
Holt
TestPaths
per
Reflection
resourcePath
=
(
String
)
TestPaths
.
class
.
getField
(
id
).
get
(
null
);
}
catch
(
ReflectiveOperationException
ex
)
{
System
.
out
.
println
(
"Unknown testcase: "
+
id
+
" (using default)"
);
}
}
String
filePathForParser
=
resolveResourceOnClasspath
(
resourcePath
);
System
.
out
.
println
(
"Using file: "
+
filePathForParser
);
//
---
2
)
Load
CityGML
model
---
ValidationConfiguration
config
=
ValidationConfiguration
.
loadStandardValidationConfig
();
//
TODO
:
Study
class
model
CityDoctorModel
model
=
TestUtil
.
loadCityModel
(
filePathForParser
,
config
);
System
.
out
.
println
(
"Model loaded successfully.
\n
"
);
List
<
Building
>
buildings
=
model
.
getBuildings
();
//
---
3
)
Menu
:
choose
granularity
---
System
.
out
.
println
(
"
\n
Choose granularity:"
);
System
.
out
.
println
(
" 1) Polygon-level (broad-phase)"
);
System
.
out
.
println
(
" 2) Ring-level (EXTERIOR)"
);
System
.
out
.
println
(
" 3) Ring-level (INTERIOR)"
);
System
.
out
.
println
(
" 4) Vertex-level (fine-phase)"
);
System
.
out
.
println
(
" 5) All of the above"
);
System
.
out
.
print
(
"Your choice [1-5]: "
);
int
choice
=
readChoice
(
sc
,
1
,
5
);
boolean
doPolygon
=
(
choice
==
1
||
choice
==
5
);
boolean
doExtRing
=
(
choice
==
2
||
choice
==
5
);
boolean
doIntRing
=
(
choice
==
3
||
choice
==
5
);
boolean
doVertex
=
(
choice
==
4
||
choice
==
5
);
//
---
4
)
Run
the
selected
modes
---
if
(
doPolygon
)
runPolygonMode
(
buildings
);
if
(
doExtRing
)
runRingMode
(
buildings
,
true
);
if
(
doIntRing
)
runRingMode
(
buildings
,
false
);
if
(
doVertex
)
runVertexMode
(
buildings
);
System
.
out
.
println
(
"
\n
=== Done ==="
);
}
//
----------
Modes
----------
private
static
void
runPolygonMode
(
List
<
Building
>
buildings
)
{
System
.
out
.
println
(
"
\n
> Polygon-level AABB (broad-phase)"
);
Set
<
ConcretePolygon
>
polys
=
collectAllPolygons
(
buildings
);
AABBTree
<
ConcretePolygon
>
bvh
=
new
AABBTree
<>(
new
ArrayList
<>(
polys
),
AABBUtils
::
getAABB
);
System
.
out
.
println
(
"Polygons: "
+
polys
.
size
());
if
(
bvh
.
getRoot
()
!= null) {
System
.
out
.
print
(
"Root AABB: "
);
bvh
.
getRoot
().
aabb
.
print
();
}
}
private
static
void
runRingMode
(
List
<
Building
>
buildings
,
boolean
exterior
)
{
String
label
=
exterior
?
"EXTERIOR"
:
"INTERIOR"
;
System
.
out
.
println
(
"
\n
> Ring-level AABB ("
+
label
+
")"
);
Set
<
LinearRing
>
rings
=
exterior
?
collectExteriorRings
(
buildings
)
:
collectInteriorRings
(
buildings
);
AABBTree
<
LinearRing
>
bvh
=
new
AABBTree
<>(
new
ArrayList
<>(
rings
),
AABBUtils
::
computeAABBFromRing
);
System
.
out
.
println
(
label
+
" rings: "
+
rings
.
size
());
if
(
bvh
.
getRoot
()
!= null) {
System
.
out
.
print
(
"Root AABB: "
);
bvh
.
getRoot
().
aabb
.
print
();
}
}
private
static
void
runVertexMode
(
List
<
Building
>
buildings
)
{
System
.
out
.
println
(
"
\n
> Vertex-level AABB (fine-phase)"
);
Set
<
Vertex
>
verts
=
collectAllVertices
(
buildings
);
AABBTree
<
Vertex
>
bvh
=
new
AABBTree
<>(
new
ArrayList
<>(
verts
),
AABBUtils
::
computeAABBFromVertex
);
System
.
out
.
println
(
"Vertices: "
+
verts
.
size
());
if
(
bvh
.
getRoot
()
!= null) {
System
.
out
.
print
(
"Root AABB: "
);
bvh
.
getRoot
().
aabb
.
print
();
}
}
//
----------
Collectors
----------
/**
Collects
all
ConcretePolygons
(
unique
)
via
visitor
.
*/
private
static
Set
<
ConcretePolygon
>
collectAllPolygons
(
List
<
Building
>
buildings
)
{
Set
<
ConcretePolygon
>
set
=
new
HashSet
<>();
for
(
Building
b
:
buildings
)
{
b
.
accept
(
new
CheckableUtilsVisitor
()
{
@
Override
public
void
check
(
Polygon
poly
)
{
set
.
add
(
poly
.
getOriginal
());
}
});
}
return
set
;
}
/**
Collects
all
EXTERIOR
rings
(
unique
).
*/
private
static
Set
<
LinearRing
>
collectExteriorRings
(
List
<
Building
>
buildings
)
{
Set
<
LinearRing
>
set
=
new
HashSet
<>();
for
(
Building
b
:
buildings
)
{
b
.
accept
(
new
CheckableUtilsVisitor
()
{
@
Override
public
void
check
(
Polygon
poly
)
{
LinearRing
ext
=
poly
.
getOriginal
().
getExteriorRing
();
if
(
ext
!= null) set.add(ext);
}
});
}
return
set
;
}
/**
Collects
all
INTERIOR
rings
(
unique
).
*/
private
static
Set
<
LinearRing
>
collectInteriorRings
(
List
<
Building
>
buildings
)
{
Set
<
LinearRing
>
set
=
new
HashSet
<>();
for
(
Building
b
:
buildings
)
{
b
.
accept
(
new
CheckableUtilsVisitor
()
{
@
Override
public
void
check
(
Polygon
poly
)
{
List
<
LinearRing
>
inner
=
poly
.
getOriginal
().
getInnerRings
();
if
(
inner
!= null && !inner.isEmpty()) {
set
.
addAll
(
inner
);
}
}
});
}
return
set
;
}
/**
Collects
all
vertices
(
unique
)
from
both
exterior
and
interior
rings
.
*/
private
static
Set
<
Vertex
>
collectAllVertices
(
List
<
Building
>
buildings
)
{
Set
<
Vertex
>
set
=
new
HashSet
<>();
for
(
Building
b
:
buildings
)
{
b
.
accept
(
new
CheckableUtilsVisitor
()
{
@
Override
public
void
check
(
Polygon
poly
)
{
ConcretePolygon
cp
=
poly
.
getOriginal
();
LinearRing
ext
=
cp
.
getExteriorRing
();
if
(
ext
!= null) set.addAll(ext.getVertices());
List
<
LinearRing
>
inner
=
cp
.
getInnerRings
();
if
(
inner
!= null) {
for
(
LinearRing
lr
:
inner
)
set
.
addAll
(
lr
.
getVertices
());
}
}
});
}
return
set
;
}
//
----------
Utils
----------
/*
Helper
method
reads
choice
of
the
user
*/
private
static
int
readChoice
(
Scanner
sc
,
int
min
,
int
max
)
{
while
(
true
)
{
String
s
=
sc
.
nextLine
().
trim
();
try
{
int
v
=
Integer
.
parseInt
(
s
);
if
(
v
>=
min
&&
v
<=
max
)
return
v
;
}
catch
(
NumberFormatException
ignored
)
{}
System
.
out
.
print
(
"Please enter a number between "
+
min
+
" and "
+
max
+
": "
);
}
}
/*
Helper
method
Pathfinder
*/
private
static
String
resolveResourceOnClasspath
(
String
resourcePath
)
{
String
rp
=
normalizeResourcePath
(
resourcePath
);
//
1
)
Klassenpfad
via
Class
.
getResource
URL
url
=
TestCityGmlAABB
.
class
.
getResource
(
rp
);
//
2
)
Klassenpfad
via
Context
-
ClassLoader
:
if
(
url
==
null
)
{
ClassLoader
cl
=
Thread
.
currentThread
().
getContextClassLoader
();
String
noSlash
=
rp
.
startsWith
(
"/"
)
?
rp
.
substring
(
1
)
:
rp
;
url
=
cl
.
getResource
(
noSlash
);
}
//
3
)
Wenn
gefunden
:
in
Pfad
umwandeln
if
(
url
!= null) {
try
{
return
Paths
.
get
(
url
.
toURI
()).
toString
();
}
catch
(
Exception
e
)
{
throw
new
RuntimeException
(
"Konnte Resource-URI nicht auflösen: "
+
url
,
e
);
}
}
//
4
)
Fallbacks
:
Projekt
-
relative
Kandidaten
pr
ü
fen
String
noSlash
=
rp
.
startsWith
(
"/"
)
?
rp
.
substring
(
1
)
:
rp
;
String
[]
candidates
=
{
"src/test/resources/"
+
noSlash
,
"src/main/resources/"
+
noSlash
,
resourcePath
//
falls
bereits
ein
echter
Dateipfad
ü
bergeben
wurde
};
for
(
String
cand
:
candidates
)
{
java
.
nio
.
file
.
Path
p
=
java
.
nio
.
file
.
Paths
.
get
(
cand
);
if
(
java
.
nio
.
file
.
Files
.
exists
(
p
))
{
return
p
.
toAbsolutePath
().
toString
();
}
}
throw
new
IllegalArgumentException
(
"Resource nicht im Klassenpfad gefunden: "
+
resourcePath
+
" (versucht als: "
+
rp
+
")"
);
}
//
F
Ü
R
ALLE
F
Ä
LLE
zur
Zeit
REDUNDAD
private
static
String
normalizeResourcePath
(
String
path
)
{
String
p
=
path
.
replace
(
'\\'
,
'/'
);
//
Quellordner
-
Pr
ä
fixe
entfernen
,
falls
mit
ü
bergeben
if
(
p
.
startsWith
(
"src/test/resources/"
))
{
p
=
p
.
substring
(
"src/test/resources/"
.
length
());
}
else
if
(
p
.
startsWith
(
"src/main/resources/"
))
{
p
=
p
.
substring
(
"src/main/resources/"
.
length
());
}
//
F
ü
r
Class
.
getResource
:
f
ü
hrenden
Slash
setzen
if
(
!p.startsWith("/")) p = "/" + p;
return
p
;
}
}
.metadata/.plugins/org.eclipse.core.resources/.history/a/507e361753e900101245d5e14ea95888
0 → 100644
View file @
c67a5961
package
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
bht
;
/**
*
Central
collection
of
CityGML
test
file
paths
used
for
AABB
/
healing
experiments
.
*
Files
are
located
under
{@
code
src
/
test
/
resources
}
or
{@
code
src
/
test
/
resources
/
bht
/}
*
ACHTUNG
:
mit
'!!!'
markierte
Objekte
haben
einen
falschen
Pfad
*/
public
final
class
TestPaths
{
private
TestPaths
()
{
//
utility
class
}
//
==================================================
//
Schematron
/
Validation
tests
//
==================================================
/**
!!! Not XSD valid, namespaces removed, for schematron experiments. */
public
static
final
String
SCHEMATRON
=
"CityDoctorParent/CityDoctorValidation/target/test-classes/SimpleSolid_SrefBS-Schematron-Test.gml"
;
//
CityDoctorParent
//
"src/test/resources/bht/SimpleSolid_SrefBS-Schematron-Test.gml"
;
//
==================================================
//
LinearRing
(
LR
)
test
cases
//
==================================================
/**
1
LinearRing
has
only
2
points
.
*/
public
static
final
String
LR_2POINTS
=
"src/test/resources/SimpleSolid_SrefBS-GE-gml-LR-0001-T0001.gml"
;
/**
2
LinearRing
has
3
points
but
is
not
closed
.
*/
public
static
final
String
LR_NOTCLOSED
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-LR-0001-T0002.gml"
;
/**
3
LinearRing
has
consecutive
duplicate
vertices
.
*/
public
static
final
String
LR_DUPLICATE_CONSEC
=
"src/test/resources/SimpleSolid_SrefBS-GE-gml-LR-0002-T0001.gml"
;
/**
4
LinearRing
has
non
-
consecutive
duplicate
vertices
.
*/
public
static
final
String
LR_DUPLICATE_NONCONSEC
=
"src/test/resources/SimpleSolid_SrefBS-GE-gml-LR-0002-T0002.gml"
;
/**
added
5
LinearRing
points
form
a
straight
line
.
*/
public
static
final
String
LR_LINE
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-LR-0002-T0003.gml"
;
/**
added
6
LinearRing
has
consecutive
points
closer
than
0.1
.
*/
public
static
final
String
LR_TOO_CLOSE
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-LR-0002-T0004.gml"
;
/**
added
7
LinearRing
has
too
few
points
and
duplicate
points
.
*/
public
static
final
String
LR_TOO_FEW_DUP
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-LR-0002-T0005.gml"
;
/**
8
LinearRing
is
not
closed
.
*/
public
static
final
String
LR_NOTCLOSED_2
=
"src/test/resources/SimpleSolid_SrefBS-GE-gml-LR-0003-T0001.gml"
;
/**
added
9
LinearRing
is
closed
but
with
point
distance
<
0.1
.
*/
public
static
final
String
LR_CLOSED_SMALLDIST
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-LR-0003-T0002.gml"
;
/**
10
LinearRing
has
a
loop
.
*/
public
static
final
String
LR_LOOP
=
"src/test/resources/SimpleSolid_SrefBS-GE-gml-LR-0004-T0004.gml"
;
/**
11
LinearRing
point
touches
edge
with
distance
<
0.1
.
*/
public
static
final
String
LR_TOUCH_EDGE
=
"src/test/resources/SimpleSolid_SrefBS-GE-gml-LR-0004-T0005.gml"
;
//
==================================================
//
Polygon
(
PO
)
test
cases
//
==================================================
/**
12
Inner
ring
intersects
outer
ring
.
*/
public
static
final
String
PO_INTERSECT_OUTER
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-PO-0001-T0001.gml"
;
/**
13
Polygon
has
2
inner
rings
.
*/
public
static
final
String
PO_TWO_INNERS
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-PO-0001-T0002.gml"
;
/**
14
Polygon
has
2
intersecting
inner
rings
.
*/
public
static
final
String
PO_INNER_INTERSECT
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-PO-0001-T0003.gml"
;
/**
15
Polygon
has
2
inner
rings
;
one
vertex
too
far
from
the
plane
.
*/
public
static
final
String
PO_INNER_OFF_PLANE
=
"src/test/resources/SimpleSolid_SrefBS-GE-gml-PO-0002-T0001.gml"
;
/**
added
16
Polygon
has
normal
deviation
error
.
*/
public
static
final
String
PO_NORMAL_ERROR
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-PO-0002-T0002.gml"
;
/**
17
Polygon
has
disconnected
interior
surface
.
*/
public
static
final
String
PO_DISCONNECTED_INTERIOR_1
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-PO-0003-T0001.gml"
;
/**
added
18
Polygon
has
disconnected
interior
surface
due
to
two
inner
rings
.
*/
public
static
final
String
PO_DISCONNECTED_INTERIOR_2
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-PO-0003-T0002.gml"
;
/**
added
19
Inner
ring
completely
outside
the
outer
ring
.
*/
public
static
final
String
PO_INNER_OUTSIDE
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-PO-0004-T0001.gml"
;
/**
added
20
Inner
ring
completely
inside
another
inner
ring
.
*/
public
static
final
String
PO_INNER_INSIDE_ANOTHER
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-PO-0005-T0001.gml"
;
/**
21
Two
inner
rings
with
wrong
orientation
.
*/
public
static
final
String
PO_TWO_INNERS_WRONG_ORIENT
=
"src/test/resources/SimpleSolid_SrefBS-GE-gml-PO-0006-T0001.gml"
;
//
==================================================
//
Solid
(
SO
)
test
cases
//
==================================================
/**
added
22
Solid
consists
of
only
3
polygons
.
*/
public
static
final
String
SO_TOO_FEW_POLYGONS
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-SO-0001-T0001.gml"
;
/**
added
23
Shell
is
not
watertight
.
*/
public
static
final
String
SO_NOT_WATERTIGHT
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-SO-0002-T0001.gml"
;
/**
24
Two
buildings
connected
only
by
a
single
point
.
*/
public
static
final
String
SO_CONNECTED_BY_POINT
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-SO-0003-T0001.gml"
;
/**
25
Roof
point
slightly
deviates
(
e
.
g
.,
10.0
14.95
2.95
vs
10.0
15.0
3.0
).
*/
public
static
final
String
SO_ROOF_COORD_DEVIATION_1
=
"src/test/resources/SimpleSolid_SrefBS-GE-gml-SO-0004-T0001.gml"
;
/**
25
Missing
polygon
.
*/
public
static
final
String
SO_MISSING_POLYGON
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-SO-0004-T0002.gml"
;
/*
*
*
komplex
Data
from
NRW
;
whole
Quartier
*
*/
/**
26
added
EXTRA
Whole
Church
forum
.
*/
public
static
final
String
CHURCH_FORUM
=
"src/test/resources/bht/LoD2_32_344_5675_1_NW.gml"
;
/*
LOST
DATA
/**
Slight
coordinate
deviations
on
multiple
roof
polygons
(
CityGML
2.0
only
).
public
static
final
String
SO_ROOF_COORD_DEVIATION_2
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-SO-0004-T0003.gml"
;
*/
/**
added
27
Solid
geometry
actually
contains
two
buildings
.
*/
public
static
final
String
SO_TWO_BUILDINGS_IN_ONE
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-SO-0005-T0001.gml"
;
//
//
Falsches
Datei
!!!!
/**
!!! 28 Self-intersecting geometry. */
public
static
final
String
SO_SELF_INTERSECTING
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-SO-0003-T0001.gml"
;
//
ACHTUNG
FALSCHES
LABEL
/**
29
Polygon
with
wrong
orientation
.
*/
public
static
final
String
ENTER_LABEL1
=
"src/test/resources/SimpleSolid_SrefBS-GE-gml-SO-0007-T0001.gml"
;
/**
30
Polygon
with
wrong
orientation
.
ACHTUNG
FALSCHES
LABEL
*/
public
static
final
String
ENTER_LABEL2
=
"src/test/resources/SimpleSolid_SrefBS-GE-gml-SO-0007-T0002.gml"
;
/**
31
Polygon
with
wrong
orientation
.
ACHTUNG
FALSCHES
LABEL
*/
public
static
final
String
ENTER_LABEL3
=
"src/test/resources/SimpleSolid_SrefBS-GE-gml-SO-0007-T0003.gml"
;
//
/**
LOST
! 33 All polygons have wrong orientation. */
public
static
final
String
SO_WRONG_POLY_ORIENTATION_ALL
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-SO-0008-T0001.gml"
;
}
.metadata/.plugins/org.eclipse.core.resources/.history/a/50b5266078ea0010125ad88dcc4485e5
0 → 100644
View file @
c67a5961
/*-
*
Copyright
2020
Beuth
Hochschule
f
ü
r
Technik
Berlin
,
Hochschule
f
ü
r
Technik
Stuttgart
*
*
This
file
is
part
of
CityDoctor2
.
*
*
CityDoctor2
is
free
software
:
you
can
redistribute
it
and
/
or
modify
*
it
under
the
terms
of
the
GNU
Lesser
General
Public
License
as
published
by
*
the
Free
Software
Foundation
,
either
version
3
of
the
License
,
or
*
(
at
your
option
)
any
later
version
.
*
*
CityDoctor2
is
distributed
in
the
hope
that
it
will
be
useful
,
*
but
WITHOUT
ANY
WARRANTY
;
without
even
the
implied
warranty
of
*
MERCHANTABILITY
or
FITNESS
FOR
A
PARTICULAR
PURPOSE
.
See
the
*
GNU
Lesser
General
Public
License
for
more
details
.
*
*
You
should
have
received
a
copy
of
the
GNU
Lesser
General
Public
License
*
along
with
CityDoctor2
.
If
not
,
see
<
https
://
www
.
gnu
.
org
/
licenses
/>.
*/
package
de
.
hft
.
stuttgart
.
citydoctor2
.
checks
.
bht
;
import
java
.
util
.
ArrayList
;
import
java
.
util
.
Collections
;
import
java
.
util
.
List
;
import
java
.
util
.
Map
;
import
java
.
util
.
Set
;
import
Jama
.
EigenvalueDecomposition
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
check
.
Check
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
check
.
CheckError
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
check
.
CheckId
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
check
.
CheckResult
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
check
.
Requirement
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
check
.
RequirementType
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
check
.
ResultStatus
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
check
.
error
.
DegeneratedRingError
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
check
.
error
.
PointTouchesEdgeError
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
check
.
error
.
RingEdgeIntersectionError
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
checks
.
Checks
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
checks
.
util
.
CollectionUtils
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
BoundingBox
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
Edge
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
Geometry
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
LinearRing
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
Vertex
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
math
.
CovarianceMatrix
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
math
.
DistanceResult
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
math
.
Matrix3x3d
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
math
.
OrthogonalRegressionPlane
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
math
.
Segment3d
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
math
.
Vector3d
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
parser
.
ParserConfiguration
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
bht
.
AABB
;
/**
*
Checks
whether
a
ring
self
intersects
.
Also
checks
if
a
point
is
too
close
to
*
an
edge
of
the
ring
.
*
*
Axis
Aligned
Boundin
Box
Early
-
Out
-
Version
of
Matthias
Betz
's Check
* @author Baris Numanoglu
*/
public class RingSelfIntCheckAABB extends Check {
private static final String EPSILON_NAME = "minVertexDistance";
// check requirement class for default parameters
private double degeneratedRingTolerance = 0.01;
private double epsilon = Checks.MIN_VERTEX_DISTANCE_DEFAULT;
private static final List<CheckId> dependencies;
static {
ArrayList<CheckId> deps = new ArrayList<>();
deps.add(CheckId.C_GE_R_TOO_FEW_POINTS);
deps.add(CheckId.C_GE_R_NOT_CLOSED);
deps.add(CheckId.C_GE_R_DUPLICATE_POINT);
dependencies = Collections.unmodifiableList(deps);
}
@Override
public void init(Map<String, String> parameters, ParserConfiguration config) {
String epsilonString = parameters.get(EPSILON_NAME);
if (epsilonString != null) {
epsilon = Double.parseDouble(epsilonString);
}
if (parameters.containsKey(Requirement.DEGENERATED_RING_TOLERANCE)) {
degeneratedRingTolerance = Double.parseDouble(parameters.get(Requirement.DEGENERATED_RING_TOLERANCE));
}
}
@Override
public void check(LinearRing lr) {
checkRingJava(lr);
}
private void checkRingJava(LinearRing lr) {
// keep original behavior (tiny/degenerate detection first)
List<Vertex> vertices = lr.getVertices();
Vector3d centroid = CovarianceMatrix.getCentroid(vertices);
EigenvalueDecomposition ed = OrthogonalRegressionPlane.decompose(vertices, centroid);
if (checkEigenvalues(lr, vertices, ed)) {
return; // error added, stop here
}
List<Edge> edges = getEdgesForRing(lr);
// --- NEW: Broad-phase AABB for "point touches edge" test ---
// Precompute padded AABBs for all edges (padding = epsilon)
List<EdgeBox> edgeBoxes = new ArrayList<>(edges.size());
for (Edge e : edges) {
edgeBoxes.add(new EdgeBox(e, edgeAabb(e.getFrom(), e.getTo(), epsilon)));
}
// Optimized "point touches edge": first filter by padded edge AABB
for (EdgeBox eb : edgeBoxes) {
if (checkForPointsTouchingEdgeBroadPhase(lr, eb)) {
return;
}
}
// --- Original pairwise edge test, now with AABB early-out ---
for (int i = 0; i < edges.size() - 1; i++) {
Edge e1 = edges.get(i);
EdgeBox eb1 = edgeBoxes.get(i);
for (int j = i + 1; j < edges.size(); j++) {
Edge e2 = edges.get(j);
// share a vertex? skip
if (e1.getConnectionPoint(e2) != null) {
continue;
}
//skip if AABBs don'
t
overlap
EdgeBox
eb2
=
edgeBoxes
.
get
(
j
);
if
(
!overlaps(eb1.box, eb2.box)) {
continue
;
}
//
Narrow
-
phase
distance
test
(
unchanged
)
Segment3d
s1
=
new
Segment3d
(
e1
.
getFrom
(),
e1
.
getTo
());
Segment3d
s2
=
new
Segment3d
(
e2
.
getFrom
(),
e2
.
getTo
());
DistanceResult
dr
=
s1
.
getDistanceResult
(
s2
);
if
(
dr
.
distance
()
<
epsilon
)
{
CheckError
err
=
new
RingEdgeIntersectionError
(
lr
,
e1
,
e2
,
dr
.
point1
());
CheckResult
cr
=
new
CheckResult
(
this
,
ResultStatus
.
ERROR
,
err
);
lr
.
addCheckResult
(
cr
);
return
;
}
}
}
//
no
errors
detected
CheckResult
cr
=
new
CheckResult
(
this
,
ResultStatus
.
OK
,
null
);
lr
.
addCheckResult
(
cr
);
}
private
boolean
checkEigenvalues
(
LinearRing
lr
,
List
<
Vertex
>
points
,
EigenvalueDecomposition
ed
)
{
Matrix3x3d
mat
=
new
Matrix3x3d
(
ed
.
getV
().
getArray
());
List
<
Vector3d
>
rotatedVertices
=
new
ArrayList
<>();
for
(
Vertex
v
:
points
)
{
rotatedVertices
.
add
(
mat
.
mult
(
v
));
}
BoundingBox
bbox
=
BoundingBox
.
ofPoints
(
rotatedVertices
);
int
nrOfEigenvaluesBelowTolerance
=
0
;
if
(
bbox
.
getWidth
()
<
degeneratedRingTolerance
)
{
nrOfEigenvaluesBelowTolerance
++;
}
if
(
bbox
.
getHeight
()
<
degeneratedRingTolerance
)
{
nrOfEigenvaluesBelowTolerance
++;
}
if
(
bbox
.
getDepth
()
<
degeneratedRingTolerance
)
{
nrOfEigenvaluesBelowTolerance
++;
}
if
(
nrOfEigenvaluesBelowTolerance
>=
2
)
{
CheckError
err
=
new
DegeneratedRingError
(
lr
);
lr
.
addCheckResult
(
new
CheckResult
(
this
,
ResultStatus
.
ERROR
,
err
));
return
true
;
}
return
false
;
}
/**
*
Original
narrow
-
phase
"point near edge"
with
a
broad
-
phase
AABB
filter
.
*/
private
boolean
checkForPointsTouchingEdgeBroadPhase
(
LinearRing
lr
,
EdgeBox
eb
)
{
Segment3d
seg
=
new
Segment3d
(
eb
.
edge
.
getFrom
(),
eb
.
edge
.
getTo
());
for
(
Vertex
v
:
lr
.
getVertices
())
{
//
skip
endpoints
if
(
v
==
eb
.
edge
.
getFrom
()
||
v
==
eb
.
edge
.
getTo
())
{
continue
;
}
//
Broad
-
phase
:
reject
if
vertex
is
outside
padded
edge
AABB
if
(
!eb.box.encloses(v.getX(), v.getY(), v.getZ())) {
continue
;
}
//
Narrow
-
phase
:
exact
segment
-
point
distance
if
(
seg
.
getDistance
(
v
)
<
epsilon
)
{
CheckError
err
=
new
PointTouchesEdgeError
(
lr
,
eb
.
edge
,
v
);
CheckResult
cr
=
new
CheckResult
(
this
,
ResultStatus
.
ERROR
,
err
);
lr
.
addCheckResult
(
cr
);
return
true
;
}
}
return
false
;
}
private
List
<
Edge
>
getEdgesForRing
(
LinearRing
lr
)
{
List
<
Edge
>
edges
=
new
ArrayList
<>();
Geometry
geom
=
lr
.
getParent
().
getParent
();
for
(
int
i
=
0
;
i
<
lr
.
getVertices
().
size
()
-
1
;
i
++)
{
Vertex
v1
=
lr
.
getVertices
().
get
(
i
);
Vertex
v2
=
lr
.
getVertices
().
get
(
i
+
1
);
Edge
e
=
geom
.
getEdge
(
v1
,
v2
);
if
(
e
==
null
)
{
throw
new
IllegalStateException
(
"Edge between v1="
+
v1
+
" to v2="
+
v2
+
" is missing"
);
}
edges
.
add
(
e
);
}
return
edges
;
}
@
Override
public
List
<
CheckId
>
getDependencies
()
{
return
dependencies
;
}
@
Override
public
Set
<
Requirement
>
appliesToRequirements
()
{
return
CollectionUtils
.
singletonSet
(
Requirement
.
R_GE_R_SELF_INTERSECTION
);
}
@
Override
public
RequirementType
getType
()
{
return
RequirementType
.
GEOMETRY
;
}
@
Override
public
Check
createNewInstance
()
{
return
new
RingSelfIntCheckAABB
();
}
@
Override
public
CheckId
getCheckId
()
{
return
CheckId
.
C_GE_R_SELF_INTERSECTION
;
}
//
TODO
AUSLAGERN
!!!
/*
========
AABB
helpers
(
broad
-
phase
)
========
*/
private
static
final
class
EdgeBox
{
final
Edge
edge
;
final
AABB
box
;
EdgeBox
(
Edge
edge
,
AABB
box
)
{
this
.
edge
=
edge
;
this
.
box
=
box
;
}
}
/**
Builds
a
padded
AABB
around
a
segment
(
two
vertices
).
*/
private
static
AABB
edgeAabb
(
Vertex
a
,
Vertex
b
,
double
pad
)
{
double
minX
=
Math
.
min
(
a
.
getX
(),
b
.
getX
())
-
pad
;
double
minY
=
Math
.
min
(
a
.
getY
(),
b
.
getY
())
-
pad
;
double
minZ
=
Math
.
min
(
a
.
getZ
(),
b
.
getZ
())
-
pad
;
double
maxX
=
Math
.
max
(
a
.
getX
(),
b
.
getX
())
+
pad
;
double
maxY
=
Math
.
max
(
a
.
getY
(),
b
.
getY
())
+
pad
;
double
maxZ
=
Math
.
max
(
a
.
getZ
(),
b
.
getZ
())
+
pad
;
return
new
AABB
(
minX
,
minY
,
minZ
,
maxX
,
maxY
,
maxZ
);
}
/**
Returns
true
if
two
AABBs
overlap
(
inclusive
).
*/
private
static
boolean
overlaps
(
AABB
a
,
AABB
b
)
{
return
!(a.getMaxX() < b.getMinX() ||
a
.
getMinX
()
>
b
.
getMaxX
()
||
a
.
getMaxY
()
<
b
.
getMinY
()
||
a
.
getMinY
()
>
b
.
getMaxY
()
||
a
.
getMaxZ
()
<
b
.
getMinZ
()
||
a
.
getMinZ
()
>
b
.
getMaxZ
());
}
}
.metadata/.plugins/org.eclipse.core.resources/.history/a3/40d4c0da7cea0010125ad88dcc4485e5
0 → 100644
View file @
c67a5961
package
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
bht
;
import
java
.
util
.
ArrayList
;
import
java
.
util
.
Comparator
;
import
java
.
util
.
List
;
import
java
.
util
.
function
.
Function
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
ConcretePolygon
;
public
class
BVHStructures
{
/**
*
Generic
node
used
in
BVH
tree
*/
public
static
class
Node
<
E
>
{
public
List
<
Node
<
E
>>
children
=
new
ArrayList
<>();
public
AABB
aabb
;
public
E
element
;
public
Node
()
{
//
Anchor
-
3
DPoint
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
.
element
=
null
;
}
public
boolean
isLeaf
()
{
return
children
.
isEmpty
()
&&
element
!= null;
}
}
/**
*
Represents
a
pair
of
geometry
lists
resulting
from
a
split
*/
public
static
class
SplitStruct
<
E
>
{
public
List
<
E
>
list1
=
new
ArrayList
<>();
public
List
<
E
>
list2
=
new
ArrayList
<>();
}
/**
*
Stack
element
used
during
recursive
BVH
tree
construction
*/
public
static
class
StackElement
<
E
>
{
public
int
level
;
public
Node
<
E
>
node
;
public
List
<
E
>
elements
=
new
ArrayList
<>();
public
StackElement
(
int
level
,
Node
<
E
>
node
,
List
<
E
>
elements
)
{
this
.
level
=
level
;
this
.
node
=
node
;
this
.
elements
=
elements
;
}
}
/**
*
Pair
of
AABBs
and
polygon
lists
used
during
splitting
*/
public
static
class
SplitStructB
<
E
>
{
public
AABB
box1
,
box2
;
public
List
<
E
>
list1
=
new
ArrayList
<>();
public
List
<
E
>
list2
=
new
ArrayList
<>();
}
/**
*
Generic
array
-
based
BVH
node
.
*
Stores
an
AABB
and
an
associated
element
(
typically
a
leaf
object
).
*/
public
static
class
NodeB_Ar
<
E
>
{
public
AABB
aabb
;
public
E
element
;
public
NodeB_Ar
(
AABB
aabb
,
E
element
)
{
this
.
aabb
=
aabb
;
this
.
element
=
element
;
}
}
/**
*
Stack
element
used
for
array
-
based
BVH
construction
*/
public
static
class
StackElementAr
{
public
int
arrayIndex
;
public
int
level
;
public
AABB
aabb
;
public
List
<
ConcretePolygon
>
polygons
=
new
ArrayList
<>();
public
StackElementAr
(
int
arrayIndex
,
int
level
,
AABB
aabb
,
List
<
ConcretePolygon
>
polygons
)
{
this
.
arrayIndex
=
arrayIndex
;
this
.
level
=
level
;
this
.
aabb
=
aabb
;
this
.
polygons
=
polygons
;
}
}
/**
*
Creates
a
comparator
to
sort
elements
by
their
AABB
center
X
coordinate
.
*/
public
static
<
E
>
Comparator
<
E
>
compareCenterX
(
Function
<
E
,
AABB
>
aabbGetter
)
{
return
Comparator
.
comparingDouble
(
e
->
{
AABB
box
=
aabbGetter
.
apply
(
e
);
return
(
box
.
getMinX
()
+
box
.
getMaxX
())
/
2.0
;
});
}
/**
*
Creates
a
comparator
to
sort
elements
by
their
AABB
center
Y
coordinate
.
*/
public
static
<
E
>
Comparator
<
E
>
compareCenterY
(
Function
<
E
,
AABB
>
aabbGetter
)
{
return
Comparator
.
comparingDouble
(
e
->
{
AABB
box
=
aabbGetter
.
apply
(
e
);
return
(
box
.
getMinY
()
+
box
.
getMaxY
())
/
2.0
;
});
}
/**
*
Creates
a
comparator
to
sort
elements
by
their
AABB
center
Z
coordinate
.
*/
public
static
<
E
>
Comparator
<
E
>
compareCenterZ
(
Function
<
E
,
AABB
>
aabbGetter
)
{
return
Comparator
.
comparingDouble
(
e
->
{
AABB
box
=
aabbGetter
.
apply
(
e
);
return
(
box
.
getMinZ
()
+
box
.
getMaxZ
())
/
2.0
;
});
}
/**
*
Sorts
elements
by
AABB
center
along
specified
axis
.
*
*
@
param
elements
the
list
to
sort
*
@
param
axis
0
=
X
,
1
=
Y
,
2
=
Z
*
@
param
aabbGetter
a
function
to
extract
the
AABB
from
an
element
*/
public
static
<
E
>
void
sortElementsByCenterAxis
(
List
<
E
>
elements
,
int
axis
,
Function
<
E
,
AABB
>
aabbGetter
)
{
switch
(
axis
)
{
case
0
->
elements
.
sort
(
compareCenterX
(
aabbGetter
));
case
1
->
elements
.
sort
(
compareCenterY
(
aabbGetter
));
case
2
->
elements
.
sort
(
compareCenterZ
(
aabbGetter
));
default
->
throw
new
IllegalArgumentException
(
"Invalid axis index: "
+
axis
);
}
}
/**
*
Returns
the
index
of
the
longest
axis
in
the
AABB
*/
public
static
int
findLongestAxis
(
AABB
aabb
)
{
double
x
=
aabb
.
getMaxX
()
-
aabb
.
getMinX
();
double
y
=
aabb
.
getMaxY
()
-
aabb
.
getMinY
();
double
z
=
aabb
.
getMaxZ
()
-
aabb
.
getMinZ
();
if
(
x
>
y
&&
x
>
z
)
return
0
;
if
(
y
>
x
&&
y
>
z
)
return
1
;
return
2
;
}
public
static
<
E
>
AABB
getAggregateAABB
(
List
<
E
>
elements
,
Function
<
E
,
AABB
>
aabbFunc
)
{
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
;
for
(
E
e
:
elements
)
{
AABB
aabb
=
aabbFunc
.
apply
(
e
);
minX
=
Math
.
min
(
minX
,
aabb
.
getMinX
());
minY
=
Math
.
min
(
minY
,
aabb
.
getMinY
());
minZ
=
Math
.
min
(
minZ
,
aabb
.
getMinZ
());
maxX
=
Math
.
max
(
maxX
,
aabb
.
getMaxX
());
maxY
=
Math
.
max
(
maxY
,
aabb
.
getMaxY
());
maxZ
=
Math
.
max
(
maxZ
,
aabb
.
getMaxZ
());
}
return
new
AABB
(
minX
,
minY
,
minZ
,
maxX
,
maxY
,
maxZ
);
}
}
\ No newline at end of file
.metadata/.plugins/org.eclipse.core.resources/.history/a9/f0bc3f46f1e800101776afd2c6cb3760
0 → 100644
View file @
c67a5961
<?xml version="1.0" encoding="utf-8"?>
<project
xmlns=
"http://maven.apache.org/POM/4.0.0"
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
>
<modelVersion>
4.0.0
</modelVersion>
<parent>
<groupId>
de.hft.stuttgart
</groupId>
<artifactId>
CityDoctorParent
</artifactId>
<version>
3.17.2
</version>
</parent>
<properties>
<versionString>
${project.version}-${git.commit.id.abbrev}
</versionString>
</properties>
<artifactId>
CityDoctorModel
</artifactId>
<name>
CityDoctorModel
</name>
<dependencies>
<dependency>
<groupId>
org.citygml4j
</groupId>
<artifactId>
citygml4j-core
</artifactId>
</dependency>
<dependency>
<groupId>
org.citygml4j
</groupId>
<artifactId>
citygml4j-xml
</artifactId>
</dependency>
<dependency>
<groupId>
de.hft.stuttgart
</groupId>
<artifactId>
citygml4j-quality-ade
</artifactId>
</dependency>
<dependency>
<groupId>
gov.nist.math
</groupId>
<artifactId>
jama
</artifactId>
</dependency>
<dependency>
<groupId>
org.jogamp.gluegen
</groupId>
<artifactId>
gluegen-rt-main
</artifactId>
</dependency>
<dependency>
<groupId>
org.jogamp.jogl
</groupId>
<artifactId>
jogl-all-main
</artifactId>
</dependency>
<dependency>
<groupId>
junit
</groupId>
<artifactId>
junit
</artifactId>
<scope>
test
</scope>
</dependency>
<dependency>
<groupId>
org.apache.logging.log4j
</groupId>
<artifactId>
log4j-api
</artifactId>
</dependency>
<dependency>
<groupId>
org.apache.logging.log4j
</groupId>
<artifactId>
log4j-core
</artifactId>
<scope>
test
</scope>
</dependency>
<dependency>
<groupId>
org.yaml
</groupId>
<artifactId>
snakeyaml
</artifactId>
</dependency>
<dependency>
<groupId>
org.locationtech.proj4j
</groupId>
<artifactId>
proj4j
</artifactId>
</dependency>
<dependency>
<groupId>
org.locationtech.proj4j
</groupId>
<artifactId>
proj4j-epsg
</artifactId>
</dependency>
<dependency>
<groupId>
commons-io
</groupId>
<artifactId>
commons-io
</artifactId>
<scope>
compile
</scope>
</dependency>
<dependency>
<groupId>
org.locationtech.jts
</groupId>
<artifactId>
jts-core
</artifactId>
</dependency>
<dependency>
<groupId>
io.github.earcut4j
</groupId>
<artifactId>
earcut4j
</artifactId>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>
src/main/resources
</directory>
<filtering>
true
</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>
pl.project13.maven
</groupId>
<artifactId>
git-commit-id-plugin
</artifactId>
<version>
4.9.10
</version>
<executions>
<execution>
<id>
get-the-git-infos
</id>
<goals>
<goal>
revision
</goal>
</goals>
</execution>
</executions>
<configuration>
<dotGitDirectory>
${project.basedir}/../../.git
</dotGitDirectory>
<prefix>
git
</prefix>
<verbose>
false
</verbose>
<generateGitPropertiesFile>
true
</generateGitPropertiesFile>
<generateGitPropertiesFilename>
${project.build.outputDirectory}/git.properties
</generateGitPropertiesFilename>
<gitDescribe>
<skip>
false
</skip>
<always>
false
</always>
</gitDescribe>
</configuration>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
.metadata/.plugins/org.eclipse.core.resources/.history/ab/c07a27be71e900101245d5e14ea95888
0 → 100644
View file @
c67a5961
package
de
.
hft
.
stuttgart
.
citydoctor2
.
healing
.
bht
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
bht
.*;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.*;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
parser
.*;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
systemtest
.
TestUtil
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
healing
.*;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
check
.*;
//
import
de
.
hft
.
stuttgart
.
citydoctor2
.
healing
.*;
import
java
.
io
.
IOException
;
import
java
.
util
.*;
//
src
/
test
/
java
/.../
TestCityGmlAABB
.
java
import
java
.
net
.
URL
;
import
java
.
nio
.
file
.
Paths
;
public
class
TestCityGmlAABB
{
public
static
void
main
(
String
[]
args
)
throws
CityGmlParseException
,
IOException
,
InvalidGmlFileException
{
System
.
out
.
println
(
"=== CityGML AABB Test ==="
);
//
---
1
)
Ask
user
which
test
case
to
run
---
Scanner
sc
=
new
Scanner
(
System
.
in
);
System
.
out
.
print
(
"Enter TestCase ID (e.g. PO_TWO_INNERS, SO_WRONG_POLY_ORIENTATION_SINGLE) "
+
"or press Enter for default: "
);
String
id
=
sc
.
nextLine
().
trim
();
//
Default
w
ä
hlen
String
resourcePath
=
TestPaths
.
PO_TWO_INNERS
;
if
(
!id.isEmpty()) {
try
{
//
Holt
TestPaths
per
Reflection
resourcePath
=
(
String
)
TestPaths
.
class
.
getField
(
id
).
get
(
null
);
}
catch
(
ReflectiveOperationException
ex
)
{
System
.
out
.
println
(
"Unknown testcase: "
+
id
+
" (using default)"
);
}
}
String
filePathForParser
=
resolveResourceOnClasspath
(
resourcePath
);
System
.
out
.
println
(
"Using file: "
+
filePathForParser
);
//
---
2
)
Load
CityGML
model
---
ValidationConfiguration
config
=
ValidationConfiguration
.
loadStandardValidationConfig
();
//
TODO
:
Study
class
model
CityDoctorModel
model
=
de
.
hft
.
stuttgart
.
citydoctor2
.
healing
.
TestUtil
.
loadCityModel
(
filePathForParser
,
config
);
System
.
out
.
println
(
"Model loaded successfully.
\n
"
);
List
<
Building
>
buildings
=
model
.
getBuildings
();
//
---
3
)
Menu
:
choose
granularity
---
System
.
out
.
println
(
"
\n
Choose granularity:"
);
System
.
out
.
println
(
" 1) Polygon-level (broad-phase)"
);
System
.
out
.
println
(
" 2) Ring-level (EXTERIOR)"
);
System
.
out
.
println
(
" 3) Ring-level (INTERIOR)"
);
System
.
out
.
println
(
" 4) Vertex-level (fine-phase)"
);
System
.
out
.
println
(
" 5) All of the above"
);
System
.
out
.
print
(
"Your choice [1-5]: "
);
int
choice
=
readChoice
(
sc
,
1
,
5
);
boolean
doPolygon
=
(
choice
==
1
||
choice
==
5
);
boolean
doExtRing
=
(
choice
==
2
||
choice
==
5
);
boolean
doIntRing
=
(
choice
==
3
||
choice
==
5
);
boolean
doVertex
=
(
choice
==
4
||
choice
==
5
);
//
---
4
)
Run
the
selected
modes
---
if
(
doPolygon
)
runPolygonMode
(
buildings
);
if
(
doExtRing
)
runRingMode
(
buildings
,
true
);
if
(
doIntRing
)
runRingMode
(
buildings
,
false
);
if
(
doVertex
)
runVertexMode
(
buildings
);
System
.
out
.
println
(
"
\n
=== Done ==="
);
}
//
----------
Modes
----------
private
static
void
runPolygonMode
(
List
<
Building
>
buildings
)
{
System
.
out
.
println
(
"
\n
> Polygon-level AABB (broad-phase)"
);
Set
<
ConcretePolygon
>
polys
=
collectAllPolygons
(
buildings
);
AABBTree
<
ConcretePolygon
>
bvh
=
new
AABBTree
<>(
new
ArrayList
<>(
polys
),
AABBUtils
::
getAABB
);
System
.
out
.
println
(
"Polygons: "
+
polys
.
size
());
if
(
bvh
.
getRoot
()
!= null) {
System
.
out
.
print
(
"Root AABB: "
);
bvh
.
getRoot
().
aabb
.
print
();
}
}
private
static
void
runRingMode
(
List
<
Building
>
buildings
,
boolean
exterior
)
{
String
label
=
exterior
?
"EXTERIOR"
:
"INTERIOR"
;
System
.
out
.
println
(
"
\n
> Ring-level AABB ("
+
label
+
")"
);
Set
<
LinearRing
>
rings
=
exterior
?
collectExteriorRings
(
buildings
)
:
collectInteriorRings
(
buildings
);
AABBTree
<
LinearRing
>
bvh
=
new
AABBTree
<>(
new
ArrayList
<>(
rings
),
AABBUtils
::
computeAABBFromRing
);
System
.
out
.
println
(
label
+
" rings: "
+
rings
.
size
());
if
(
bvh
.
getRoot
()
!= null) {
System
.
out
.
print
(
"Root AABB: "
);
bvh
.
getRoot
().
aabb
.
print
();
}
}
private
static
void
runVertexMode
(
List
<
Building
>
buildings
)
{
System
.
out
.
println
(
"
\n
> Vertex-level AABB (fine-phase)"
);
Set
<
Vertex
>
verts
=
collectAllVertices
(
buildings
);
AABBTree
<
Vertex
>
bvh
=
new
AABBTree
<>(
new
ArrayList
<>(
verts
),
AABBUtils
::
computeAABBFromVertex
);
System
.
out
.
println
(
"Vertices: "
+
verts
.
size
());
if
(
bvh
.
getRoot
()
!= null) {
System
.
out
.
print
(
"Root AABB: "
);
bvh
.
getRoot
().
aabb
.
print
();
}
}
//
----------
Collectors
----------
/**
Collects
all
ConcretePolygons
(
unique
)
via
visitor
.
*/
private
static
Set
<
ConcretePolygon
>
collectAllPolygons
(
List
<
Building
>
buildings
)
{
Set
<
ConcretePolygon
>
set
=
new
HashSet
<>();
for
(
Building
b
:
buildings
)
{
b
.
accept
(
new
CheckableUtilsVisitor
()
{
@
Override
public
void
check
(
Polygon
poly
)
{
set
.
add
(
poly
.
getOriginal
());
}
});
}
return
set
;
}
/**
Collects
all
EXTERIOR
rings
(
unique
).
*/
private
static
Set
<
LinearRing
>
collectExteriorRings
(
List
<
Building
>
buildings
)
{
Set
<
LinearRing
>
set
=
new
HashSet
<>();
for
(
Building
b
:
buildings
)
{
b
.
accept
(
new
CheckableUtilsVisitor
()
{
@
Override
public
void
check
(
Polygon
poly
)
{
LinearRing
ext
=
poly
.
getOriginal
().
getExteriorRing
();
if
(
ext
!= null) set.add(ext);
}
});
}
return
set
;
}
/**
Collects
all
INTERIOR
rings
(
unique
).
*/
private
static
Set
<
LinearRing
>
collectInteriorRings
(
List
<
Building
>
buildings
)
{
Set
<
LinearRing
>
set
=
new
HashSet
<>();
for
(
Building
b
:
buildings
)
{
b
.
accept
(
new
CheckableUtilsVisitor
()
{
@
Override
public
void
check
(
Polygon
poly
)
{
List
<
LinearRing
>
inner
=
poly
.
getOriginal
().
getInnerRings
();
if
(
inner
!= null && !inner.isEmpty()) {
set
.
addAll
(
inner
);
}
}
});
}
return
set
;
}
/**
Collects
all
vertices
(
unique
)
from
both
exterior
and
interior
rings
.
*/
private
static
Set
<
Vertex
>
collectAllVertices
(
List
<
Building
>
buildings
)
{
Set
<
Vertex
>
set
=
new
HashSet
<>();
for
(
Building
b
:
buildings
)
{
b
.
accept
(
new
CheckableUtilsVisitor
()
{
@
Override
public
void
check
(
Polygon
poly
)
{
ConcretePolygon
cp
=
poly
.
getOriginal
();
LinearRing
ext
=
cp
.
getExteriorRing
();
if
(
ext
!= null) set.addAll(ext.getVertices());
List
<
LinearRing
>
inner
=
cp
.
getInnerRings
();
if
(
inner
!= null) {
for
(
LinearRing
lr
:
inner
)
set
.
addAll
(
lr
.
getVertices
());
}
}
});
}
return
set
;
}
//
----------
Utils
----------
/*
Helper
method
reads
choice
of
the
user
*/
private
static
int
readChoice
(
Scanner
sc
,
int
min
,
int
max
)
{
while
(
true
)
{
String
s
=
sc
.
nextLine
().
trim
();
try
{
int
v
=
Integer
.
parseInt
(
s
);
if
(
v
>=
min
&&
v
<=
max
)
return
v
;
}
catch
(
NumberFormatException
ignored
)
{}
System
.
out
.
print
(
"Please enter a number between "
+
min
+
" and "
+
max
+
": "
);
}
}
/*
Helper
method
Pathfinder
*/
private
static
String
resolveResourceOnClasspath
(
String
resourcePath
)
{
String
rp
=
normalizeResourcePath
(
resourcePath
);
//
1
)
Klassenpfad
via
Class
.
getResource
URL
url
=
TestCityGmlAABB
.
class
.
getResource
(
rp
);
//
2
)
Klassenpfad
via
Context
-
ClassLoader
:
if
(
url
==
null
)
{
ClassLoader
cl
=
Thread
.
currentThread
().
getContextClassLoader
();
String
noSlash
=
rp
.
startsWith
(
"/"
)
?
rp
.
substring
(
1
)
:
rp
;
url
=
cl
.
getResource
(
noSlash
);
}
//
3
)
Wenn
gefunden
:
in
Pfad
umwandeln
if
(
url
!= null) {
try
{
return
Paths
.
get
(
url
.
toURI
()).
toString
();
}
catch
(
Exception
e
)
{
throw
new
RuntimeException
(
"Konnte Resource-URI nicht auflösen: "
+
url
,
e
);
}
}
//
4
)
Fallbacks
:
Projekt
-
relative
Kandidaten
pr
ü
fen
String
noSlash
=
rp
.
startsWith
(
"/"
)
?
rp
.
substring
(
1
)
:
rp
;
String
[]
candidates
=
{
"src/test/resources/"
+
noSlash
,
"src/main/resources/"
+
noSlash
,
resourcePath
//
falls
bereits
ein
echter
Dateipfad
ü
bergeben
wurde
};
for
(
String
cand
:
candidates
)
{
java
.
nio
.
file
.
Path
p
=
java
.
nio
.
file
.
Paths
.
get
(
cand
);
if
(
java
.
nio
.
file
.
Files
.
exists
(
p
))
{
return
p
.
toAbsolutePath
().
toString
();
}
}
throw
new
IllegalArgumentException
(
"Resource nicht im Klassenpfad gefunden: "
+
resourcePath
+
" (versucht als: "
+
rp
+
")"
);
}
//
F
Ü
R
ALLE
F
Ä
LLE
zur
Zeit
REDUNDAD
private
static
String
normalizeResourcePath
(
String
path
)
{
String
p
=
path
.
replace
(
'\\'
,
'/'
);
//
Quellordner
-
Pr
ä
fixe
entfernen
,
falls
mit
ü
bergeben
if
(
p
.
startsWith
(
"src/test/resources/"
))
{
p
=
p
.
substring
(
"src/test/resources/"
.
length
());
}
else
if
(
p
.
startsWith
(
"src/main/resources/"
))
{
p
=
p
.
substring
(
"src/main/resources/"
.
length
());
}
//
F
ü
r
Class
.
getResource
:
f
ü
hrenden
Slash
setzen
if
(
!p.startsWith("/")) p = "/" + p;
return
p
;
}
}
.metadata/.plugins/org.eclipse.core.resources/.history/ae/300a0879f1e700101110d31642d3da88
0 → 100644
View file @
c67a5961
package
de
.
hft
.
stuttgart
.
citydoctor2
.
checks
.
bht
;
/**
*
Central
collection
of
CityGML
test
file
paths
used
for
AABB
/
healing
experiments
.
*
Files
are
located
under
{@
code
src
/
test
/
resources
}
or
{@
code
src
/
test
/
resources
/
bht
/}
*
ACHTUNG
:
mit
'!!!'
markierte
Objekte
haben
einen
falschen
Pfad
*/
public
final
class
TestPaths
{
private
TestPaths
()
{
//
utility
class
}
//
==================================================
//
Schematron
/
Validation
tests
//
==================================================
/**
!!! Not XSD valid, namespaces removed, for schematron experiments. */
public
static
final
String
SCHEMATRON
=
"CityDoctorParent/CityDoctorValidation/target/test-classes/SimpleSolid_SrefBS-Schematron-Test.gml"
;
//
CityDoctorParent
//
"src/test/resources/bht/SimpleSolid_SrefBS-Schematron-Test.gml"
;
//
==================================================
//
LinearRing
(
LR
)
test
cases
//
==================================================
/**
1
LinearRing
has
only
2
points
.
*/
public
static
final
String
LR_2POINTS
=
"src/test/resources/SimpleSolid_SrefBS-GE-gml-LR-0001-T0001.gml"
;
/**
2
LinearRing
has
3
points
but
is
not
closed
.
*/
public
static
final
String
LR_NOTCLOSED
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-LR-0001-T0002.gml"
;
/**
3
LinearRing
has
consecutive
duplicate
vertices
.
*/
public
static
final
String
LR_DUPLICATE_CONSEC
=
"src/test/resources/SimpleSolid_SrefBS-GE-gml-LR-0002-T0001.gml"
;
/**
4
LinearRing
has
non
-
consecutive
duplicate
vertices
.
*/
public
static
final
String
LR_DUPLICATE_NONCONSEC
=
"src/test/resources/SimpleSolid_SrefBS-GE-gml-LR-0002-T0002.gml"
;
/**
added
5
LinearRing
points
form
a
straight
line
.
*/
public
static
final
String
LR_LINE
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-LR-0002-T0003.gml"
;
/**
added
6
LinearRing
has
consecutive
points
closer
than
0.1
.
*/
public
static
final
String
LR_TOO_CLOSE
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-LR-0002-T0004.gml"
;
/**
added
7
LinearRing
has
too
few
points
and
duplicate
points
.
*/
public
static
final
String
LR_TOO_FEW_DUP
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-LR-0002-T0005.gml"
;
/**
8
LinearRing
is
not
closed
.
*/
public
static
final
String
LR_NOTCLOSED_2
=
"src/test/resources/SimpleSolid_SrefBS-GE-gml-LR-0003-T0001.gml"
;
/**
added
9
LinearRing
is
closed
but
with
point
distance
<
0.1
.
*/
public
static
final
String
LR_CLOSED_SMALLDIST
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-LR-0003-T0002.gml"
;
/**
10
LinearRing
has
a
loop
.
*/
public
static
final
String
LR_LOOP
=
"src/test/resources/SimpleSolid_SrefBS-GE-gml-LR-0004-T0004.gml"
;
/**
11
LinearRing
point
touches
edge
with
distance
<
0.1
.
*/
public
static
final
String
LR_TOUCH_EDGE
=
"src/test/resources/SimpleSolid_SrefBS-GE-gml-LR-0004-T0005.gml"
;
//
==================================================
//
Polygon
(
PO
)
test
cases
//
==================================================
/**
12
Inner
ring
intersects
outer
ring
.
*/
public
static
final
String
PO_INTERSECT_OUTER
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-PO-0001-T0001.gml"
;
/**
13
Polygon
has
2
inner
rings
.
*/
public
static
final
String
PO_TWO_INNERS
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-PO-0001-T0002.gml"
;
/**
14
Polygon
has
2
intersecting
inner
rings
.
*/
public
static
final
String
PO_INNER_INTERSECT
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-PO-0001-T0003.gml"
;
/**
15
Polygon
has
2
inner
rings
;
one
vertex
too
far
from
the
plane
.
*/
public
static
final
String
PO_INNER_OFF_PLANE
=
"src/test/resources/SimpleSolid_SrefBS-GE-gml-PO-0002-T0001.gml"
;
/**
added
16
Polygon
has
normal
deviation
error
.
*/
public
static
final
String
PO_NORMAL_ERROR
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-PO-0002-T0002.gml"
;
/**
17
Polygon
has
disconnected
interior
surface
.
*/
public
static
final
String
PO_DISCONNECTED_INTERIOR_1
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-PO-0003-T0001.gml"
;
/**
added
18
Polygon
has
disconnected
interior
surface
due
to
two
inner
rings
.
*/
public
static
final
String
PO_DISCONNECTED_INTERIOR_2
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-PO-0003-T0002.gml"
;
/**
added
19
Inner
ring
completely
outside
the
outer
ring
.
*/
public
static
final
String
PO_INNER_OUTSIDE
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-PO-0004-T0001.gml"
;
/**
added
20
Inner
ring
completely
inside
another
inner
ring
.
*/
public
static
final
String
PO_INNER_INSIDE_ANOTHER
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-PO-0005-T0001.gml"
;
/**
21
Two
inner
rings
with
wrong
orientation
.
*/
public
static
final
String
PO_TWO_INNERS_WRONG_ORIENT
=
"src/test/resources/SimpleSolid_SrefBS-GE-gml-PO-0006-T0001.gml"
;
//
==================================================
//
Solid
(
SO
)
test
cases
//
==================================================
/**
added
22
Solid
consists
of
only
3
polygons
.
*/
public
static
final
String
SO_TOO_FEW_POLYGONS
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-SO-0001-T0001.gml"
;
/**
added
23
Shell
is
not
watertight
.
*/
public
static
final
String
SO_NOT_WATERTIGHT
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-SO-0002-T0001.gml"
;
/**
24
Two
buildings
connected
only
by
a
single
point
.
*/
public
static
final
String
SO_CONNECTED_BY_POINT
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-SO-0003-T0001.gml"
;
/**
25
Roof
point
slightly
deviates
(
e
.
g
.,
10.0
14.95
2.95
vs
10.0
15.0
3.0
).
*/
public
static
final
String
SO_ROOF_COORD_DEVIATION_1
=
"src/test/resources/SimpleSolid_SrefBS-GE-gml-SO-0004-T0001.gml"
;
/**
25
Missing
polygon
.
*/
public
static
final
String
SO_MISSING_POLYGON
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-SO-0004-T0002.gml"
;
/*
*
*
komplex
Data
from
NRW
;
whole
Quartier
*
*/
/**
26
added
EXTRA
Whole
Church
forum
.
*/
public
static
final
String
CHURCH_FORUM
=
"src/test/resources/bht/LoD2_32_344_5675_1_NW.gml"
;
/*
LOST
DATA
/**
Slight
coordinate
deviations
on
multiple
roof
polygons
(
CityGML
2.0
only
).
public
static
final
String
SO_ROOF_COORD_DEVIATION_2
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-SO-0004-T0003.gml"
;
*/
/**
added
27
Solid
geometry
actually
contains
two
buildings
.
*/
public
static
final
String
SO_TWO_BUILDINGS_IN_ONE
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-SO-0005-T0001.gml"
;
//
//
Falsches
Datei
!!!!
/**
!!! 28 Self-intersecting geometry. */
public
static
final
String
SO_SELF_INTERSECTING
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-SO-0003-T0001.gml"
;
//
ACHTUNG
FALSCHES
LABEL
/**
29
Polygon
with
wrong
orientation
.
*/
public
static
final
String
ENTER_LABEL1
=
"src/test/resources/SimpleSolid_SrefBS-GE-gml-SO-0007-T0001.gml"
;
/**
30
Polygon
with
wrong
orientation
.
ACHTUNG
FALSCHES
LABEL
*/
public
static
final
String
ENTER_LABEL2
=
"src/test/resources/SimpleSolid_SrefBS-GE-gml-SO-0007-T0002.gml"
;
/**
31
Polygon
with
wrong
orientation
.
ACHTUNG
FALSCHES
LABEL
*/
public
static
final
String
ENTER_LABEL3
=
"src/test/resources/SimpleSolid_SrefBS-GE-gml-SO-0007-T0003.gml"
;
//
/**
LOST
! 33 All polygons have wrong orientation. */
public
static
final
String
SO_WRONG_POLY_ORIENTATION_ALL
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-SO-0008-T0001.gml"
;
}
.metadata/.plugins/org.eclipse.core.resources/.history/af/80f574e75fea0010125ad88dcc4485e5
0 → 100644
View file @
c67a5961
package
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
bht
;
import
java
.
util
.*;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
ConcretePolygon
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
LinearRing
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
Vertex
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
LinearRing
.
LinearRingType
;
public
class
Main
{
/**
*
Entry
point
for
AABB
testing
*/
public
static
void
main
(
String
[]
args
)
{
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
Point
p1
=
new
Point
(
0
,
0
,
0
);
Point
p2
=
new
Point
(
1
,
0
,
0
);
Point
p3
=
new
Point
(
0.5
,
1
,
0
);
Point
p4
=
new
Point
(
0.5
,
0.5
,
1
);
//
Define
triangle
faces
of
the
tetrahedron
ConcretePolygon
base
=
new
ConcretePolygon
();
LinearRing
baseRing
=
new
LinearRing
(
LinearRingType
.
EXTERIOR
);
baseRing
.
addVertex
(
new
Vertex
(
p1
.
getX
(),
p1
.
getY
(),
p1
.
getZ
()));
baseRing
.
addVertex
(
new
Vertex
(
p2
.
getX
(),
p2
.
getY
(),
p2
.
getZ
()));
baseRing
.
addVertex
(
new
Vertex
(
p3
.
getX
(),
p3
.
getY
(),
p3
.
getZ
()));
baseRing
.
addVertex
(
new
Vertex
(
p1
.
getX
(),
p1
.
getY
(),
p1
.
getZ
()));
base
.
setExteriorRing
(
baseRing
);
ConcretePolygon
side1
=
new
ConcretePolygon
();
LinearRing
ring1
=
new
LinearRing
(
LinearRingType
.
EXTERIOR
);
ring1
.
addVertex
(
new
Vertex
(
p1
.
getX
(),
p1
.
getY
(),
p1
.
getZ
()));
ring1
.
addVertex
(
new
Vertex
(
p2
.
getX
(),
p2
.
getY
(),
p2
.
getZ
()));
ring1
.
addVertex
(
new
Vertex
(
p4
.
getX
(),
p4
.
getY
(),
p4
.
getZ
()));
ring1
.
addVertex
(
new
Vertex
(
p1
.
getX
(),
p1
.
getY
(),
p1
.
getZ
()));
side1
.
setExteriorRing
(
ring1
);
ConcretePolygon
side2
=
new
ConcretePolygon
();
LinearRing
ring2
=
new
LinearRing
(
LinearRingType
.
EXTERIOR
);
ring2
.
addVertex
(
new
Vertex
(
p2
.
getX
(),
p2
.
getY
(),
p2
.
getZ
()));
ring2
.
addVertex
(
new
Vertex
(
p3
.
getX
(),
p3
.
getY
(),
p3
.
getZ
()));
ring2
.
addVertex
(
new
Vertex
(
p4
.
getX
(),
p4
.
getY
(),
p4
.
getZ
()));
ring2
.
addVertex
(
new
Vertex
(
p2
.
getX
(),
p2
.
getY
(),
p2
.
getZ
()));
side2
.
setExteriorRing
(
ring2
);
ConcretePolygon
side3
=
new
ConcretePolygon
();
LinearRing
ring3
=
new
LinearRing
(
LinearRingType
.
EXTERIOR
);
ring3
.
addVertex
(
new
Vertex
(
p3
.
getX
(),
p3
.
getY
(),
p3
.
getZ
()));
ring3
.
addVertex
(
new
Vertex
(
p1
.
getX
(),
p1
.
getY
(),
p1
.
getZ
()));
ring3
.
addVertex
(
new
Vertex
(
p4
.
getX
(),
p4
.
getY
(),
p4
.
getZ
()));
ring3
.
addVertex
(
new
Vertex
(
p3
.
getX
(),
p3
.
getY
(),
p3
.
getZ
()));
side3
.
setExteriorRing
(
ring3
);
List
<
ConcretePolygon
>
poly
=
Arrays
.
asList
(
base
,
side1
,
side2
,
side3
);
AABB
aabb
=
BVHStructures
.
getAggregateAABB
(
poly
);
System
.
out
.
println
(
"
\n
Computed AABB:"
);
aabb
.
print
();
/***
3
D
-
Point
-
coords
with
Test
Properties
***/
//
Inside
laying
Point
double
testInsideX
=
0.5
;
double
testInsideY
=
0.5
;
double
testInsideZ
=
0.3
;
//
Outside
laying
Point
double
testOutsideX
=
2.0
;
double
testOutsideY
=
2.0
;
double
testOutsideZ
=
2.0
;
//
On
edge
laying
Point
double
testOnEdgeX
=
1.0
;
double
testOnEdgeY
=
1.0
;
double
testOnEdgeZ
=
0.0
;
System
.
out
.
println
(
"
\n
Test point (inside): "
+
testInsideX
+
" "
+
testInsideY
+
" "
+
testInsideZ
);
System
.
out
.
println
(
"-> contained?: "
+
aabb
.
encloses
(
testInsideX
,
testInsideY
,
testInsideZ
));
System
.
out
.
println
(
"
\n
Test point (outside): "
+
testOutsideX
+
" "
+
testOutsideY
+
" "
+
testOutsideZ
);
System
.
out
.
println
(
"-> contained?: "
+
aabb
.
encloses
(
testOutsideX
,
testOutsideY
,
testOutsideZ
));
System
.
out
.
println
(
"
\n
Test point (on edge): "
+
testOnEdgeX
+
" "
+
testOnEdgeY
+
" "
+
testOnEdgeZ
);
System
.
out
.
println
(
"-> contained?: "
+
aabb
.
encloses
(
testOnEdgeX
,
testOnEdgeY
,
testOnEdgeZ
));
}
}
.metadata/.plugins/org.eclipse.core.resources/.history/b5/605de4fbf0e700101110d31642d3da88
0 → 100644
View file @
c67a5961
package
de
.
hft
.
stuttgart
.
citydoctor2
.
checks
.
aabb
;
import
java
.
util
.*;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
checks
.
aabb
.
AABB
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
checks
.
aabb
.
BVHStructures
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
checks
.
aabb
.
Point
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
ConcretePolygon
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
LinearRing
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
Vertex
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
LinearRing
.
LinearRingType
;
public
class
TestDummyAABB
{
/**
*
Entry
point
for
AABB
testing
*/
public
static
void
main
(
String
[]
args
)
{
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
Point
p1
=
new
Point
(
0
,
0
,
0
);
Point
p2
=
new
Point
(
1
,
0
,
0
);
Point
p3
=
new
Point
(
0.5
,
1
,
0
);
Point
p4
=
new
Point
(
0.5
,
0.5
,
1
);
//
Define
triangle
faces
of
the
tetrahedron
ConcretePolygon
base
=
new
ConcretePolygon
();
LinearRing
baseRing
=
new
LinearRing
(
LinearRingType
.
EXTERIOR
);
baseRing
.
addVertex
(
new
Vertex
(
p1
.
getX
(),
p1
.
getY
(),
p1
.
getZ
()));
baseRing
.
addVertex
(
new
Vertex
(
p2
.
getX
(),
p2
.
getY
(),
p2
.
getZ
()));
baseRing
.
addVertex
(
new
Vertex
(
p3
.
getX
(),
p3
.
getY
(),
p3
.
getZ
()));
baseRing
.
addVertex
(
new
Vertex
(
p1
.
getX
(),
p1
.
getY
(),
p1
.
getZ
()));
base
.
setExteriorRing
(
baseRing
);
ConcretePolygon
side1
=
new
ConcretePolygon
();
LinearRing
ring1
=
new
LinearRing
(
LinearRingType
.
EXTERIOR
);
ring1
.
addVertex
(
new
Vertex
(
p1
.
getX
(),
p1
.
getY
(),
p1
.
getZ
()));
ring1
.
addVertex
(
new
Vertex
(
p2
.
getX
(),
p2
.
getY
(),
p2
.
getZ
()));
ring1
.
addVertex
(
new
Vertex
(
p4
.
getX
(),
p4
.
getY
(),
p4
.
getZ
()));
ring1
.
addVertex
(
new
Vertex
(
p1
.
getX
(),
p1
.
getY
(),
p1
.
getZ
()));
side1
.
setExteriorRing
(
ring1
);
ConcretePolygon
side2
=
new
ConcretePolygon
();
LinearRing
ring2
=
new
LinearRing
(
LinearRingType
.
EXTERIOR
);
ring2
.
addVertex
(
new
Vertex
(
p2
.
getX
(),
p2
.
getY
(),
p2
.
getZ
()));
ring2
.
addVertex
(
new
Vertex
(
p3
.
getX
(),
p3
.
getY
(),
p3
.
getZ
()));
ring2
.
addVertex
(
new
Vertex
(
p4
.
getX
(),
p4
.
getY
(),
p4
.
getZ
()));
ring2
.
addVertex
(
new
Vertex
(
p2
.
getX
(),
p2
.
getY
(),
p2
.
getZ
()));
side2
.
setExteriorRing
(
ring2
);
ConcretePolygon
side3
=
new
ConcretePolygon
();
LinearRing
ring3
=
new
LinearRing
(
LinearRingType
.
EXTERIOR
);
ring3
.
addVertex
(
new
Vertex
(
p3
.
getX
(),
p3
.
getY
(),
p3
.
getZ
()));
ring3
.
addVertex
(
new
Vertex
(
p1
.
getX
(),
p1
.
getY
(),
p1
.
getZ
()));
ring3
.
addVertex
(
new
Vertex
(
p4
.
getX
(),
p4
.
getY
(),
p4
.
getZ
()));
ring3
.
addVertex
(
new
Vertex
(
p3
.
getX
(),
p3
.
getY
(),
p3
.
getZ
()));
side3
.
setExteriorRing
(
ring3
);
List
<
ConcretePolygon
>
poly
=
Arrays
.
asList
(
base
,
side1
,
side2
,
side3
);
AABB
aabb
=
BVHStructures
.
getAggregateAABB
(
poly
);
System
.
out
.
println
(
"
\n
Computed AABB:"
);
aabb
.
print
();
/***
3
D
-
Point
-
coords
with
Test
Properties
***/
//
Inside
laying
Point
double
testInsideX
=
0.5
;
double
testInsideY
=
0.5
;
double
testInsideZ
=
0.3
;
//
Outside
laying
Point
double
testOutsideX
=
2.0
;
double
testOutsideY
=
2.0
;
double
testOutsideZ
=
2.0
;
//
On
edge
laying
Point
double
testOnEdgeX
=
1.0
;
double
testOnEdgeY
=
1.0
;
double
testOnEdgeZ
=
0.0
;
System
.
out
.
println
(
"
\n
Test point (inside): "
+
testInsideX
+
" "
+
testInsideY
+
" "
+
testInsideZ
);
System
.
out
.
println
(
"-> contained?: "
+
aabb
.
encloses
(
testInsideX
,
testInsideY
,
testInsideZ
));
System
.
out
.
println
(
"
\n
Test point (outside): "
+
testOutsideX
+
" "
+
testOutsideY
+
" "
+
testOutsideZ
);
System
.
out
.
println
(
"-> contained?: "
+
aabb
.
encloses
(
testOutsideX
,
testOutsideY
,
testOutsideZ
));
System
.
out
.
println
(
"
\n
Test point (on edge): "
+
testOnEdgeX
+
" "
+
testOnEdgeY
+
" "
+
testOnEdgeZ
);
System
.
out
.
println
(
"-> contained?: "
+
aabb
.
encloses
(
testOnEdgeX
,
testOnEdgeY
,
testOnEdgeZ
));
}
}
.metadata/.plugins/org.eclipse.core.resources/.history/b5/d04bfe656bea0010125ad88dcc4485e5
0 → 100644
View file @
c67a5961
package
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
bht
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
ConcretePolygon
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
LinearRing
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
Vertex
;
import
java
.
util
.*;
//
import
java
.
util
.
List
;
/**
*
@
author
Baris
Numanoglu
*
*
Utility
class
providing
AABB
-
related
helper
methods
.
*
*
Contains
functionality
for
computing
axis
-
aligned
bounding
boxes
(
AABBs
)
*
from
geometric
data
structures
such
as
{@
link
ConcretePolygon
}
or
{@
link
LinearRing
}.
*
*
All
methods
are
static
.
*/
public
class
AABBUtils
{
public
static
AABB
getAABB
(
ConcretePolygon
poly
)
{
LinearRing
ring
=
poly
.
getExteriorRing
();
if
(
ring
==
null
)
return
null
;
return
computeAABBFromRing
(
ring
);
}
/**
*
Computes
an
AABB
from
a
LinearRing
by
iterating
over
its
vertices
.
*
*
@
param
ring
the
LinearRing
whose
vertices
define
the
AABB
*
@
return
AABB
enclosing
the
ring
;
returns
an
empty
AABB
if
the
ring
has
no
vertices
*/
public
static
AABB
computeAABBFromRing
(
LinearRing
ring
)
{
if
(
ring
==
null
||
ring
.
getVertices
()
==
null
||
ring
.
getVertices
().
isEmpty
())
{
return
new
AABB
(
Double
.
POSITIVE_INFINITY
,
Double
.
POSITIVE_INFINITY
,
Double
.
POSITIVE_INFINITY
,
Double
.
NEGATIVE_INFINITY
,
Double
.
NEGATIVE_INFINITY
,
Double
.
NEGATIVE_INFINITY
);
}
double
minX
=
Double
.
POSITIVE_INFINITY
;
double
minY
=
Double
.
POSITIVE_INFINITY
;
double
minZ
=
Double
.
POSITIVE_INFINITY
;
double
maxX
=
Double
.
NEGATIVE_INFINITY
;
double
maxY
=
Double
.
NEGATIVE_INFINITY
;
double
maxZ
=
Double
.
NEGATIVE_INFINITY
;
for
(
Vertex
v
:
ring
.
getVertices
())
{
double
x
=
v
.
getX
();
double
y
=
v
.
getY
();
double
z
=
v
.
getZ
();
minX
=
Math
.
min
(
minX
,
x
);
minY
=
Math
.
min
(
minY
,
y
);
minZ
=
Math
.
min
(
minZ
,
z
);
maxX
=
Math
.
max
(
maxX
,
x
);
maxY
=
Math
.
max
(
maxY
,
y
);
maxZ
=
Math
.
max
(
maxZ
,
z
);
}
return
new
AABB
(
minX
,
minY
,
minZ
,
maxX
,
maxY
,
maxZ
);
}
/**
*
PREMORDIAL
:
substitutes
the
earlier
semantic
of
AABB
-
Point
-
Init
.
*
Computes
the
min
and
max
bounds
(
6
doubles
)
from
two
points
.
*
*
@
param
p1
the
first
point
*
@
param
p2
the
second
point
*
@
return
an
array
of
6
doubles
:
[
minX
,
minY
,
minZ
,
maxX
,
maxY
,
maxZ
]
*/
public
static
double
[]
extractBoundsFromPoints
(
Point
p1
,
Point
p2
)
{
double
minX
=
Math
.
min
(
p1
.
getX
(),
p2
.
getX
());
double
minY
=
Math
.
min
(
p1
.
getY
(),
p2
.
getY
());
double
minZ
=
Math
.
min
(
p1
.
getZ
(),
p2
.
getZ
());
double
maxX
=
Math
.
max
(
p1
.
getX
(),
p2
.
getX
());
double
maxY
=
Math
.
max
(
p1
.
getY
(),
p2
.
getY
());
double
maxZ
=
Math
.
max
(
p1
.
getZ
(),
p2
.
getZ
());
return
new
double
[]
{
minX
,
minY
,
minZ
,
maxX
,
maxY
,
maxZ
};
}
////////////////////////////////////////////////////////////////////////////////////////////
/**
*
Computes
an
AABB
for
a
single
vertex
(
degenerate
AABB
with
min
=
max
=
vertex
coordinates
).
*
*
@
param
vertex
the
vertex
to
wrap
in
an
AABB
*
@
return
AABB
centered
at
the
vertex
position
*/
public
static
AABB
computeAABBFromVertex
(
Vertex
vertex
)
{
if
(
vertex
==
null
)
{
//
Return
a
degenerate
AABB
with
infinite
bounds
if
vertex
is
null
return
new
AABB
(
Double
.
POSITIVE_INFINITY
,
Double
.
POSITIVE_INFINITY
,
Double
.
POSITIVE_INFINITY
,
Double
.
NEGATIVE_INFINITY
,
Double
.
NEGATIVE_INFINITY
,
Double
.
NEGATIVE_INFINITY
);
}
double
x
=
vertex
.
getX
();
double
y
=
vertex
.
getY
();
double
z
=
vertex
.
getZ
();
//
AABB
is
degenerate
here
:
min
=
max
=(
x
,
y
,
z
)
return
new
AABB
(
x
,
y
,
z
,
x
,
y
,
z
);
}
/**
Returns
true
if
the
AABB
is
(
nearly
)
flat
in
at
least
two
axes
.
*/
public
static
boolean
isDegenerate
(
AABB
aabb
,
double
tol
)
{
double
dx
=
aabb
.
getMaxX
()
-
aabb
.
getMinX
();
double
dy
=
aabb
.
getMaxY
()
-
aabb
.
getMinY
();
double
dz
=
aabb
.
getMaxZ
()
-
aabb
.
getMinZ
();
int
flatAxes
=
0
;
if
(
dx
<=
tol
)
flatAxes
++;
if
(
dy
<=
tol
)
flatAxes
++;
if
(
dz
<=
tol
)
flatAxes
++;
return
flatAxes
>=
2
;
//
cannot
host
3
distinct
points
in
3
D
}
/**
*
Counts
distinct
vertices
of
a
ring
using
a
tolerance
.
*
Implementation
:
uniform
quantization
(
grid
hashing
)
for
speed
and
determinism
.
*/
public
static
int
countDistinctVertices
(
LinearRing
ring
,
double
tol
)
{
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
();
}
//
TODO
replace
with
older
hash
functions
from
project
//
Simple
3
D
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
;
}
/*
COMING
SOON
*/
}
.metadata/.plugins/org.eclipse.core.resources/.history/b6/80ee5ae452e900101245d5e14ea95888
0 → 100644
View file @
c67a5961
package
de
.
hft
.
stuttgart
.
citydoctor2
.
checks
.
bht
;
import
java
.
io
.
IOException
;
//
import
java
.
io
.
InputStream
;
//
new
import
java
.
util
.
ArrayList
;
import
java
.
util
.
HashMap
;
import
java
.
util
.
HashSet
;
import
java
.
util
.
List
;
import
java
.
util
.
Map
;
import
java
.
util
.
Set
;
import
java
.
util
.
Scanner
;
//
new
import
org
.
junit
.
Test
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
check
.
CheckableUtilsVisitor
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
check
.
CheckableVisitor
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
check
.
Check
;
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
.
CityObject
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
ConcretePolygon
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
Geometry
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
Polygon
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
LinearRing
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
LinearRing
.
LinearRingType
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
Vertex
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
exceptions
.
CityDoctorWriteException
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
healing
.
TestUtil
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
parser
.
CityGmlParseException
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
parser
.
InvalidGmlFileException
;
public
class
TestExample
{
//
InputStream
inStream
=
getClass
().
getClassLoader
().
getResourceAsStream
(
"SimpleSolid_SrefBS.gml"
);
//
new
//
//
if
you
want
to
load
a
src
/
test
/
resources
file
out
of
a
different
package
public
static
void
main
(
String
[]
args
)
throws
CityGmlParseException
,
IOException
,
InvalidGmlFileException
{
System
.
out
.
println
(
"Start TestExample...
\n
"
);
//
new
//
String
path
=
args
[
0
];
//
String
path
=
"src/test/resources/SimpleSolid_SrefBS.gml"
;
//
new
valid
LoD2
model
//
String
path
=
"src/test/resources/TestBuilding1.gml"
;
//
new
block
model
//
new
valid
model
with
inner
rings
String
path
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-PO-0001-T0002.gml"
;
//
too
big
,
main
gets
terminated
//
String
path
=
"src/test/resources/bht/KreishausFeuerwache.gml"
;
//
String
path
=
"src/test/resources/bht/TestBuilding_SelfInt.gml"
;
ValidationConfiguration
config
=
ValidationConfiguration
.
loadStandardValidationConfig
();
CityDoctorModel
model
=
TestUtil
.
loadCityModel
(
path
,
config
);
System
.
out
.
println
(
"
\n
Model has been loaded..."
);
//
new
//
visitor
//
filter
duplicate
polygons
out
Set
<
ConcretePolygon
>
allBuildingPolygons
=
new
HashSet
<>();
for
(
Building
b
:
model
.
getBuildings
())
{
b
.
accept
(
new
CheckableUtilsVisitor
()
{
public
void
check
(
Polygon
poly
)
{
allBuildingPolygons
.
add
(
poly
.
getOriginal
());
}
});
}
System
.
out
.
println
(
"
\n
Polygons via visitor:"
+
allBuildingPolygons
);
//
new
//
//
for
loop
List
<
Polygon
>
allBuildingPolygons2
=
new
ArrayList
<>();
for
(
Building
b
:
model
.
getBuildings
())
{
for
(
Geometry
geom
:
b
.
getGeometries
())
{
for
(
Polygon
p
:
geom
.
getPolygons
())
{
allBuildingPolygons2
.
add
(
p
);
allBuildingPolygons2
.
add
(
p
.
getOriginal
());
//
new
}
}
}
System
.
out
.
println
(
"
\n
Polygon List:"
+
allBuildingPolygons2
);
//
new
//
new
:
LinearRings
//
visitor
//
filter
duplicate
linear
rings
out
Set
<
LinearRing
>
allBuildingLinearRings
=
new
HashSet
<>();
for
(
Building
b
:
model
.
getBuildings
())
{
b
.
accept
(
new
CheckableUtilsVisitor
()
{
public
void
check
(
LinearRing
ring
)
{
allBuildingLinearRings
.
add
(
ring
);
}
});
}
System
.
out
.
println
(
"
\n
LinearRings via visitor:"
+
allBuildingLinearRings
);
//
new
//
new
:
ExteriorRings
//
visitor
//
filter
duplicate
exterior
rings
out
Set
<
LinearRing
>
allBuildingExteriorRings
=
new
HashSet
<>();
for
(
Building
b
:
model
.
getBuildings
())
{
b
.
accept
(
new
CheckableUtilsVisitor
()
{
public
void
check
(
LinearRing
ring
)
{
allBuildingExteriorRings
.
add
(
ring
.
getParent
().
getExteriorRing
());
//
ACHTUNG
getParent
}
});
}
System
.
out
.
println
(
"
\n
ExteriorRings 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
(
"
\n
ExteriorRing List:"
+
allBuildingExteriorRings2
);
//
new
//
new
:
InnerRings
//
visitor
//
filter
duplicate
inner
rings
out
Set
<
LinearRing
>
allBuildingInnerRings
=
new
HashSet
<>();
for
(
Building
b
:
model
.
getBuildings
())
{
b
.
accept
(
new
CheckableUtilsVisitor
()
{
public
void
check
(
Polygon
poly
)
{
allBuildingInnerRings
.
addAll
(
poly
.
getOriginal
().
getInnerRings
());//
ACHTUNG
getOriginal
}
});
}
System
.
out
.
println
(
"
\n
InnerRings via visitor:"
+
allBuildingInnerRings
);
//
new
//
//
new
:
InnerRings
(
List
)
//
//
for
loop
//
List
<
LinearRing
>
allBuildingInnerRings2
=
new
ArrayList
<>();
//
for
(
Building
b
:
model
.
getBuildings
())
{
//
for
(
Geometry
geom
:
b
.
getGeometries
())
{
//
for
(
Polygon
p
:
geom
.
getPolygons
())
{
//
for
(
LinearRing
lr
:
p
.
getInnerRings
())
{
//
allBuildingInnerRings2
.
add
(
lr
);
//
}
//
//
}
//
}
//
}
//
System
.
out
.
println
(
"
\n
InnerRing List:"
+
allBuildingInnerRings2
);
//
new
//
//
get
Vertices
for
LinearRing
,
ExteriorRing
and
InteriorRing
//
//
new
:
LinearRingVertices
//
//
visitor
//
//
filter
duplicate
linear
rings
out
//
Set
<
Vertex
>
allBuildingLinearRingVertices
=
new
HashSet
<>();
//
for
(
Building
b
:
model
.
getBuildings
())
{
//
b
.
accept
(
new
CheckableUtilsVisitor
()
{
//
public
void
check
(
LinearRing
ring
)
{
//
allBuildingLinearRingVertices
.
addAll
(
ring
.
getVertices
());
//
}
//
//
});
//
}
//
System
.
out
.
println
(
"
\n
LinearRingVertices via visitor:"
+
allBuildingLinearRingVertices
);
//
new
//
//
new
:
ExteriorRingVertices
//
//
visitor
//
//
filter
duplicate
exterior
rings
out
//
Set
<
Vertex
>
allBuildingExteriorRingVertices
=
new
HashSet
<>();
//
for
(
Building
b
:
model
.
getBuildings
())
{
//
b
.
accept
(
new
CheckableUtilsVisitor
()
{
//
public
void
check
(
LinearRing
ring
)
{
//
allBuildingExteriorRingVertices
.
addAll
(
ring
.
getParent
().
getOriginal
().
getExteriorRing
().
getVertices
());
//
}
//
//
});
//
}
//
System
.
out
.
println
(
"
\n
ExteriorRingVertices via visitor:"
+
allBuildingExteriorRingVertices
);
//
new
//
//
new
:
ExteriorRingVertices
(
List
)
//
//
for
loop
//
List
<
Vertex
>
allBuildingExteriorRingVertices2
=
new
ArrayList
<>();
//
for
(
Building
b
:
model
.
getBuildings
())
{
//
for
(
Geometry
geom
:
b
.
getGeometries
())
{
//
for
(
Polygon
p
:
geom
.
getPolygons
())
{
//
for
(
Vertex
v
:
p
.
getOriginal
().
getExteriorRing
().
getVertices
())
{
//
allBuildingExteriorRingVertices2
.
add
(
v
);
//
}
//
}
//
}
//
}
//
System
.
out
.
println
(
"
\n
ExteriorRingVertices List:"
+
allBuildingExteriorRingVertices2
);
//
new
//
//
new
:
InnerRingVertices
//
//
visitor
//
//
filter
duplicate
linear
vertices
out
//
Set
<
Vertex
>
allBuildingInnerRingVertices
=
new
HashSet
<>();
//
for
(
Building
b
:
model
.
getBuildings
())
{
//
b
.
accept
(
new
CheckableUtilsVisitor
()
{
//
public
void
check
(
Polygon
poly
)
{
//
poly
.
getOriginal
().
getInnerRings
().
forEach
(
ring
->
allBuildingInnerRingVertices
.
addAll
(
ring
.
getVertices
()));
//
}
//
});
//
}
//
System
.
out
.
println
(
"
\n
InnerRingVertices via visitor:"
+
allBuildingInnerRingVertices
);
//
new
//
//
new
:
InnerRingVertices
(
List
)
//
//
for
loop
//
List
<
Vertex
>
allInnerRingVertices2
=
new
ArrayList
<>();
//
for
(
Building
b
:
model
.
getBuildings
())
{
//
for
(
Geometry
geom
:
b
.
getGeometries
())
{
//
for
(
Polygon
p
:
geom
.
getPolygons
())
{
//
for
(
LinearRing
lr
:
p
.
getInnerRings
())
{
//
for
(
Vertex
v
:
lr
.
getVertices
())
{
//
allInnerRingVertices2
.
add
(
v
);
//
}
//
}
//
//
}
//
}
//
}
//
System
.
out
.
println
(
"
\n
InnerRingVertices List:"
+
allInnerRingVertices2
);
//
new
//
//
TODO
:
HashMap
to
show
Ring
and
gmlId
//
Map
<
LinearRing
,
Set
<
Vertex
>>
test
=
new
HashMap
<>();
}
}
.metadata/.plugins/org.eclipse.core.resources/.history/b7/30af50337eea0010125ad88dcc4485e5
0 → 100644
View file @
c67a5961
package
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
bht
;
import
java
.
io
.
PrintStream
;
//
TODO
:
Change
Point
-
Init
semantics
to
Double
-
Init
/**
*
Represents
a
3
D
line
segment
defined
by
a
start
and
end
point
.
*
Useful
for
geometric
computations
like
intersection
tests
,
*
ray
casting
,
or
clipping
against
bounding
volumes
such
as
AABBs
.
*/
public
class
Line
{
private
Point
start
;
private
Point
end
;
public
Line
()
{
this
.
start
=
new
Point
();
this
.
end
=
new
Point
();
}
public
Line
(
Point
start
,
Point
end
)
{
this
.
start
=
start
;
this
.
end
=
end
;
}
public
Point
getStart
()
{
return
start
;
}
public
Point
getEnd
()
{
return
end
;
}
//
Calculates
Bounding
Box
for
this
Line
public
AABB
getAABB
()
{
//
return
new
AABB
(
start
,
end
)
return
new
AABB
(
start
.
getX
(),
start
.
getY
(),
start
.
getZ
(),
end
.
getX
(),
end
.
getY
(),
end
.
getZ
());
}
/*
*
calculates
the
square
of
length
of
the
line
*
to
avoid
squarerooth
-
operation
*
*/
public
double
getLengthSquared
()
{
double
dx
=
end
.
getX
()
-
start
.
getX
();
double
dy
=
end
.
getY
()
-
start
.
getY
();
double
dz
=
end
.
getZ
()
-
start
.
getZ
();
return
dx
*
dx
+
dy
*
dy
+
dz
*
dz
;
}
//
Direction
vector
public
Point
getDir
()
{
return
new
Point
(
end
.
getX
()
-
start
.
getX
(),
end
.
getY
()
-
start
.
getY
(),
end
.
getZ
()
-
start
.
getZ
()
);
}
//
Normal
vector
public
Point
getNormDir
()
{
double
length
=
Math
.
sqrt
(
getLengthSquared
());
if
(
length
==
0
)
{
return
new
Point
(
0
,
0
,
0
);
}
return
new
Point
(
(
end
.
getX
()
-
start
.
getX
())
/
length
,
(
end
.
getY
()
-
start
.
getY
())
/
length
,
(
end
.
getZ
()
-
start
.
getZ
())
/
length
);
}
public
void
print
()
{
System
.
out
.
println
(
"Line from "
+
start
+
" to "
+
end
);
}
}
.metadata/.plugins/org.eclipse.core.resources/.history/bc/305422177eea0010125ad88dcc4485e5
0 → 100644
View file @
c67a5961
package
de
.
hft
.
stuttgart
.
citydoctor2
.
checks
.
bht
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
ConcretePolygon
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
LinearRing
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
Vertex
;
import
java
.
util
.
Arrays
;
import
java
.
util
.
List
;
//
import
de
.
hft
.
stuttgart
.
citydoctor2
.
checks
.
geometry
.*;
//
import
de
.
hft
.
stuttgart
.
citydoctor2
.
checks
.
aabb
.*;
//<-
evtl
*
geomCheks
hier
verlagern
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.*;
/**
*
Manual
test
runner
for
basic
geometry
checks
with
AABB
involvement
.
*
Without
JUnit
:
prints
results
directly
to
the
console
.
*/
public
class
GeometryChecksWithAABBTest
{
public
static
void
main
(
String
[]
args
)
{
System
.
out
.
println
(
"=== Geometry Checks with AABB – Manual Test Runner ==="
);
//
testTooFewPoints
();
testNestedRings
();
testRingSelfIntersection
();
testSolidSelfIntersection
();
System
.
out
.
println
(
"
\n
=== Test run finished ==="
);
}
//
--------------------------------------------------------------
//
NestedRingsCheck
//
--------------------------------------------------------------
private
static
void
testNestedRings
()
{
System
.
out
.
println
(
"
\n
[TEST] NestedRingsCheck"
);
//
outer
ring
LinearRing
outer
=
new
LinearRing
(
LinearRing
.
LinearRingType
.
EXTERIOR
);
outer
.
addAllVertices
(
Arrays
.
asList
(
new
Vertex
(
0
,
0
,
0
),
new
Vertex
(
1
,
0
,
0
),
new
Vertex
(
1
,
1
,
0
),
new
Vertex
(
0
,
1
,
0
),
new
Vertex
(
0
,
0
,
0
)
));
ConcretePolygon
p
=
new
ConcretePolygon
();
p
.
setExteriorRing
(
outer
);
//
inner
ring
1
LinearRing
inner1
=
new
LinearRing
(
LinearRing
.
LinearRingType
.
INTERIOR
);
inner1
.
addAllVertices
(
Arrays
.
asList
(
new
Vertex
(
0.2
,
0.2
,
0
),
new
Vertex
(
0.8
,
0.2
,
0
),
new
Vertex
(
0.8
,
0.8
,
0
),
new
Vertex
(
0.2
,
0.8
,
0
),
new
Vertex
(
0.2
,
0.2
,
0
)
));
//
inner
ring
2
inside
inner
ring
1
LinearRing
inner2
=
new
LinearRing
(
LinearRing
.
LinearRingType
.
INTERIOR
);
inner2
.
addAllVertices
(
Arrays
.
asList
(
new
Vertex
(
0.4
,
0.4
,
0
),
new
Vertex
(
0.6
,
0.4
,
0
),
new
Vertex
(
0.6
,
0.6
,
0
),
new
Vertex
(
0.4
,
0.6
,
0
),
new
Vertex
(
0.4
,
0.4
,
0
)
));
p
.
addInteriorRing
(
inner1
);
p
.
addInteriorRing
(
inner2
);
NestedRingsCheckAABB
check
=
new
NestedRingsCheckAABB
();
check
.
check
(
p
);
System
.
out
.
println
(
" - Should detect nested rings: "
+
p
.
containsAnyError
());
}
//
--------------------------------------------------------------
//
RingSelfIntCheck
//
--------------------------------------------------------------
private
static
void
testRingSelfIntersection
()
{
System
.
out
.
println
(
"
\n
[TEST] RingSelfIntCheck"
);
LinearRing
ring
=
new
LinearRing
(
LinearRing
.
LinearRingType
.
EXTERIOR
);
ring
.
addAllVertices
(
Arrays
.
asList
(
new
Vertex
(
0
,
0
,
0
),
new
Vertex
(
1
,
1
,
0
),
new
Vertex
(
1
,
0
,
0
),
new
Vertex
(
0
,
1
,
0
),
new
Vertex
(
0
,
0
,
0
)
));
ConcretePolygon
p
=
new
ConcretePolygon
();
p
.
setExteriorRing
(
ring
);
Geometry
g
=
new
Geometry
(
GeometryType
.
SOLID
,
Lod
.
LOD2
);
g
.
addPolygon
(
p
);
//
ensures
parent
links
exist
g
.
updateEdgesAndVertices
();
RingSelfIntCheckAABB
check
=
new
RingSelfIntCheckAABB
();
check
.
check
(
ring
);
System
.
out
.
println
(
" - Should detect self-intersection: "
+
ring
.
containsAnyError
());
}
//
--------------------------------------------------------------
//
SolidSelfIntCheck
//
--------------------------------------------------------------
private
static
void
testSolidSelfIntersection
()
{
System
.
out
.
println
(
"
\n
[TEST] SolidSelfIntCheck"
);
//
first
triangle
ConcretePolygon
p1
=
new
ConcretePolygon
();
LinearRing
r1
=
new
LinearRing
(
LinearRing
.
LinearRingType
.
EXTERIOR
);
r1
.
addAllVertices
(
Arrays
.
asList
(
new
Vertex
(
0
,
0
,
0
),
new
Vertex
(
1
,
0
,
0
),
new
Vertex
(
1
,
1
,
0
),
new
Vertex
(
0
,
0
,
0
)
));
p1
.
setExteriorRing
(
r1
);
//
second
triangle
overlapping
the
first
ConcretePolygon
p2
=
new
ConcretePolygon
();
LinearRing
r2
=
new
LinearRing
(
LinearRing
.
LinearRingType
.
EXTERIOR
);
r2
.
addAllVertices
(
Arrays
.
asList
(
new
Vertex
(
0
,
0
,
0
),
new
Vertex
(
1
,
1
,
0
),
new
Vertex
(
0
,
1
,
0
),
new
Vertex
(
0
,
0
,
0
)
));
p2
.
setExteriorRing
(
r2
);
Geometry
solid
=
new
Geometry
(
GeometryType
.
SOLID
,
Lod
.
LOD2
);
solid
.
getPolygons
().
addAll
(
List
.
of
(
p1
,
p2
));
SolidSelfIntCheckAABB
check
=
new
SolidSelfIntCheckAABB
();
check
.
check
(
solid
);
System
.
out
.
println
(
" - Should detect solid self-intersection: "
+
solid
.
containsAnyError
());
}
}
.metadata/.plugins/org.eclipse.core.resources/.history/bc/906d2f05d5e700101110d31642d3da88
0 → 100644
View file @
c67a5961
package
de
.
hft
.
stuttgart
.
citydoctor2
.
checks
.
bht
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
healer
.
aabb
.
bht
.*;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.*;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
parser
.*;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
check
.*;
import
java
.
io
.
IOException
;
import
java
.
util
.*;
//
src
/
test
/
java
/.../
TestCityGmlAABB
.
java
import
java
.
net
.
URL
;
import
java
.
nio
.
file
.
Paths
;
public
class
TestCityGmlAABB
{
public
static
void
main
(
String
[]
args
)
throws
CityGmlParseException
,
IOException
,
InvalidGmlFileException
{
System
.
out
.
println
(
"=== CityGML AABB Test ==="
);
//
---
1
)
Ask
user
which
test
case
to
run
---
Scanner
sc
=
new
Scanner
(
System
.
in
);
System
.
out
.
print
(
"Enter TestCase ID (e.g. PO_TWO_INNERS, SO_WRONG_POLY_ORIENTATION_SINGLE) "
+
"or press Enter for default: "
);
String
id
=
sc
.
nextLine
().
trim
();
//
Default
w
ä
hlen
String
resourcePath
=
TestPaths
.
PO_TWO_INNERS
;
if
(
!id.isEmpty()) {
try
{
//
Holt
TestPaths
per
Reflection
resourcePath
=
(
String
)
TestPaths
.
class
.
getField
(
id
).
get
(
null
);
}
catch
(
ReflectiveOperationException
ex
)
{
System
.
out
.
println
(
"Unknown testcase: "
+
id
+
" (using default)"
);
}
}
String
filePathForParser
=
resolveResourceOnClasspath
(
resourcePath
);
System
.
out
.
println
(
"Using file: "
+
filePathForParser
);
//
---
2
)
Load
CityGML
model
---
ValidationConfiguration
config
=
ValidationConfiguration
.
loadStandardValidationConfig
();
//
TODO
:
Study
class
model
CityDoctorModel
model
=
de
.
hft
.
stuttgart
.
citydoctor2
.
healing
.
TestUtil
.
loadCityModel
(
filePathForParser
,
config
);
System
.
out
.
println
(
"Model loaded successfully.
\n
"
);
List
<
Building
>
buildings
=
model
.
getBuildings
();
//
---
3
)
Menu
:
choose
granularity
---
System
.
out
.
println
(
"
\n
Choose granularity:"
);
System
.
out
.
println
(
" 1) Polygon-level (broad-phase)"
);
System
.
out
.
println
(
" 2) Ring-level (EXTERIOR)"
);
System
.
out
.
println
(
" 3) Ring-level (INTERIOR)"
);
System
.
out
.
println
(
" 4) Vertex-level (fine-phase)"
);
System
.
out
.
println
(
" 5) All of the above"
);
System
.
out
.
print
(
"Your choice [1-5]: "
);
int
choice
=
readChoice
(
sc
,
1
,
5
);
boolean
doPolygon
=
(
choice
==
1
||
choice
==
5
);
boolean
doExtRing
=
(
choice
==
2
||
choice
==
5
);
boolean
doIntRing
=
(
choice
==
3
||
choice
==
5
);
boolean
doVertex
=
(
choice
==
4
||
choice
==
5
);
//
---
4
)
Run
the
selected
modes
---
if
(
doPolygon
)
runPolygonMode
(
buildings
);
if
(
doExtRing
)
runRingMode
(
buildings
,
true
);
if
(
doIntRing
)
runRingMode
(
buildings
,
false
);
if
(
doVertex
)
runVertexMode
(
buildings
);
System
.
out
.
println
(
"
\n
=== Done ==="
);
}
//
----------
Modes
----------
private
static
void
runPolygonMode
(
List
<
Building
>
buildings
)
{
System
.
out
.
println
(
"
\n
> Polygon-level AABB (broad-phase)"
);
Set
<
ConcretePolygon
>
polys
=
collectAllPolygons
(
buildings
);
AABBTree
<
ConcretePolygon
>
bvh
=
new
AABBTree
<>(
new
ArrayList
<>(
polys
),
AABBUtils
::
getAABB
);
System
.
out
.
println
(
"Polygons: "
+
polys
.
size
());
if
(
bvh
.
getRoot
()
!= null) {
System
.
out
.
print
(
"Root AABB: "
);
bvh
.
getRoot
().
aabb
.
print
();
}
}
private
static
void
runRingMode
(
List
<
Building
>
buildings
,
boolean
exterior
)
{
String
label
=
exterior
?
"EXTERIOR"
:
"INTERIOR"
;
System
.
out
.
println
(
"
\n
> Ring-level AABB ("
+
label
+
")"
);
Set
<
LinearRing
>
rings
=
exterior
?
collectExteriorRings
(
buildings
)
:
collectInteriorRings
(
buildings
);
AABBTree
<
LinearRing
>
bvh
=
new
AABBTree
<>(
new
ArrayList
<>(
rings
),
AABBUtils
::
computeAABBFromRing
);
System
.
out
.
println
(
label
+
" rings: "
+
rings
.
size
());
if
(
bvh
.
getRoot
()
!= null) {
System
.
out
.
print
(
"Root AABB: "
);
bvh
.
getRoot
().
aabb
.
print
();
}
}
private
static
void
runVertexMode
(
List
<
Building
>
buildings
)
{
System
.
out
.
println
(
"
\n
> Vertex-level AABB (fine-phase)"
);
Set
<
Vertex
>
verts
=
collectAllVertices
(
buildings
);
AABBTree
<
Vertex
>
bvh
=
new
AABBTree
<>(
new
ArrayList
<>(
verts
),
AABBUtils
::
computeAABBFromVertex
);
System
.
out
.
println
(
"Vertices: "
+
verts
.
size
());
if
(
bvh
.
getRoot
()
!= null) {
System
.
out
.
print
(
"Root AABB: "
);
bvh
.
getRoot
().
aabb
.
print
();
}
}
//
----------
Collectors
----------
/**
Collects
all
ConcretePolygons
(
unique
)
via
visitor
.
*/
private
static
Set
<
ConcretePolygon
>
collectAllPolygons
(
List
<
Building
>
buildings
)
{
Set
<
ConcretePolygon
>
set
=
new
HashSet
<>();
for
(
Building
b
:
buildings
)
{
b
.
accept
(
new
CheckableUtilsVisitor
()
{
@
Override
public
void
check
(
Polygon
poly
)
{
set
.
add
(
poly
.
getOriginal
());
}
});
}
return
set
;
}
/**
Collects
all
EXTERIOR
rings
(
unique
).
*/
private
static
Set
<
LinearRing
>
collectExteriorRings
(
List
<
Building
>
buildings
)
{
Set
<
LinearRing
>
set
=
new
HashSet
<>();
for
(
Building
b
:
buildings
)
{
b
.
accept
(
new
CheckableUtilsVisitor
()
{
@
Override
public
void
check
(
Polygon
poly
)
{
LinearRing
ext
=
poly
.
getOriginal
().
getExteriorRing
();
if
(
ext
!= null) set.add(ext);
}
});
}
return
set
;
}
/**
Collects
all
INTERIOR
rings
(
unique
).
*/
private
static
Set
<
LinearRing
>
collectInteriorRings
(
List
<
Building
>
buildings
)
{
Set
<
LinearRing
>
set
=
new
HashSet
<>();
for
(
Building
b
:
buildings
)
{
b
.
accept
(
new
CheckableUtilsVisitor
()
{
@
Override
public
void
check
(
Polygon
poly
)
{
List
<
LinearRing
>
inner
=
poly
.
getOriginal
().
getInnerRings
();
if
(
inner
!= null && !inner.isEmpty()) {
set
.
addAll
(
inner
);
}
}
});
}
return
set
;
}
/**
Collects
all
vertices
(
unique
)
from
both
exterior
and
interior
rings
.
*/
private
static
Set
<
Vertex
>
collectAllVertices
(
List
<
Building
>
buildings
)
{
Set
<
Vertex
>
set
=
new
HashSet
<>();
for
(
Building
b
:
buildings
)
{
b
.
accept
(
new
CheckableUtilsVisitor
()
{
@
Override
public
void
check
(
Polygon
poly
)
{
ConcretePolygon
cp
=
poly
.
getOriginal
();
LinearRing
ext
=
cp
.
getExteriorRing
();
if
(
ext
!= null) set.addAll(ext.getVertices());
List
<
LinearRing
>
inner
=
cp
.
getInnerRings
();
if
(
inner
!= null) {
for
(
LinearRing
lr
:
inner
)
set
.
addAll
(
lr
.
getVertices
());
}
}
});
}
return
set
;
}
//
----------
Utils
----------
/*
Helper
method
reads
choice
of
the
user
*/
private
static
int
readChoice
(
Scanner
sc
,
int
min
,
int
max
)
{
while
(
true
)
{
String
s
=
sc
.
nextLine
().
trim
();
try
{
int
v
=
Integer
.
parseInt
(
s
);
if
(
v
>=
min
&&
v
<=
max
)
return
v
;
}
catch
(
NumberFormatException
ignored
)
{}
System
.
out
.
print
(
"Please enter a number between "
+
min
+
" and "
+
max
+
": "
);
}
}
/*
Helper
method
Pathfinder
*/
private
static
String
resolveResourceOnClasspath
(
String
resourcePath
)
{
String
rp
=
normalizeResourcePath
(
resourcePath
);
//
1
)
Klassenpfad
via
Class
.
getResource
URL
url
=
TestCityGmlAABB
.
class
.
getResource
(
rp
);
//
2
)
Klassenpfad
via
Context
-
ClassLoader
:
if
(
url
==
null
)
{
ClassLoader
cl
=
Thread
.
currentThread
().
getContextClassLoader
();
String
noSlash
=
rp
.
startsWith
(
"/"
)
?
rp
.
substring
(
1
)
:
rp
;
url
=
cl
.
getResource
(
noSlash
);
}
//
3
)
Wenn
gefunden
:
in
Pfad
umwandeln
if
(
url
!= null) {
try
{
return
Paths
.
get
(
url
.
toURI
()).
toString
();
}
catch
(
Exception
e
)
{
throw
new
RuntimeException
(
"Konnte Resource-URI nicht auflösen: "
+
url
,
e
);
}
}
//
4
)
Fallbacks
:
Projekt
-
relative
Kandidaten
pr
ü
fen
String
noSlash
=
rp
.
startsWith
(
"/"
)
?
rp
.
substring
(
1
)
:
rp
;
String
[]
candidates
=
{
"src/test/resources/"
+
noSlash
,
"src/main/resources/"
+
noSlash
,
resourcePath
//
falls
bereits
ein
echter
Dateipfad
ü
bergeben
wurde
};
for
(
String
cand
:
candidates
)
{
java
.
nio
.
file
.
Path
p
=
java
.
nio
.
file
.
Paths
.
get
(
cand
);
if
(
java
.
nio
.
file
.
Files
.
exists
(
p
))
{
return
p
.
toAbsolutePath
().
toString
();
}
}
throw
new
IllegalArgumentException
(
"Resource nicht im Klassenpfad gefunden: "
+
resourcePath
+
" (versucht als: "
+
rp
+
")"
);
}
//
F
Ü
R
ALLE
F
Ä
LLE
zur
Zeit
REDUNDAD
private
static
String
normalizeResourcePath
(
String
path
)
{
String
p
=
path
.
replace
(
'\\'
,
'/'
);
//
Quellordner
-
Pr
ä
fixe
entfernen
,
falls
mit
ü
bergeben
if
(
p
.
startsWith
(
"src/test/resources/"
))
{
p
=
p
.
substring
(
"src/test/resources/"
.
length
());
}
else
if
(
p
.
startsWith
(
"src/main/resources/"
))
{
p
=
p
.
substring
(
"src/main/resources/"
.
length
());
}
//
F
ü
r
Class
.
getResource
:
f
ü
hrenden
Slash
setzen
if
(
!p.startsWith("/")) p = "/" + p;
return
p
;
}
}
.metadata/.plugins/org.eclipse.core.resources/.history/c/70da4f49f1e700101110d31642d3da88
0 → 100644
View file @
c67a5961
package
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
bht
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
checks
.
aabb
.*;
import
java
.
io
.
IOException
;
import
java
.
util
.*;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
ConcretePolygon
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
LinearRing
;
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
static
void
main
(
String
[]
args
)
throws
CityGmlParseException
,
IOException
,
InvalidGmlFileException
{
System
.
out
.
println
(
"===TestHouseAABB==="
);
/*
*
3
D
House
of
St
.
Niclas
*
*
*/
//
Haus
-
Basis
:
W
ü
rfelgr
öß
e
2
x2x2
,
Dachh
ö
he
+
1
double
baseSize
=
2.0
;
double
height
=
2.0
;
double
roofHeight
=
1.0
;
//
Bodenpunkte
(
unten
)
Point
b1
=
new
Point
(
0
,
0
,
0
);
Point
b2
=
new
Point
(
baseSize
,
0
,
0
);
Point
b3
=
new
Point
(
baseSize
,
baseSize
,
0
);
Point
b4
=
new
Point
(
0
,
baseSize
,
0
);
//
Deckpunkte
(
oben
)
Point
t1
=
new
Point
(
0
,
0
,
height
);
Point
t2
=
new
Point
(
baseSize
,
0
,
height
);
Point
t3
=
new
Point
(
baseSize
,
baseSize
,
height
);
Point
t4
=
new
Point
(
0
,
baseSize
,
height
);
//
Dachspitze
(
Prisma
in
Mitte
der
oberen
Fl
ä
che
)
Point
roofPeak1
=
new
Point
(
baseSize
/
2
,
-
0.2
,
height
+
roofHeight
);
//
vorne
Point
roofPeak2
=
new
Point
(
baseSize
/
2
,
baseSize
+
0.2
,
height
+
roofHeight
);
//
hinten
List
<
ConcretePolygon
>
house
=
new
ArrayList
<>();
//
Boden
(
b1
,
b2
,
b3
,
b4
)
house
.
add
(
createQuadPolygon
(
b1
,
b2
,
b3
,
b4
));
//
W
ä
nde
house
.
add
(
createQuadPolygon
(
b1
,
b2
,
t2
,
t1
));
//
vorne
house
.
add
(
createQuadPolygon
(
b2
,
b3
,
t3
,
t2
));
//
rechts
house
.
add
(
createQuadPolygon
(
b3
,
b4
,
t4
,
t3
));
//
hinten
house
.
add
(
createQuadPolygon
(
b4
,
b1
,
t1
,
t4
));
//
links
//
Decke
unter
Dach
house
.
add
(
createQuadPolygon
(
t1
,
t2
,
t3
,
t4
));
//
Dach
:
zwei
Dreiecksseiten
(
links
/
rechts
)
house
.
add
(
createTrianglePolygon
(
t1
,
t2
,
roofPeak1
));
house
.
add
(
createTrianglePolygon
(
t4
,
t3
,
roofPeak2
));
//
Dach
:
Vorder
-
und
R
ü
ckfl
ä
che
(
Prisma
)
house
.
add
(
createQuadPolygon
(
t2
,
t3
,
roofPeak2
,
roofPeak1
));
house
.
add
(
createQuadPolygon
(
t1
,
t4
,
roofPeak2
,
roofPeak1
));
//
AABB
houseAABB
=
BVHStructures
.
getAggregateAABB
(
house
);
houseAABB
.
print
();
//
Define
test
points
PS
wegen
lesbarkeit
als
Liste
von
Koord
.
vorerst
double
[]
insidePoint
=
{
1.0
,
1.0
,
1.0
};
//
clearly
inside
(
center
of
the
base
cube
)
double
[]
roofPoint
=
{
1.0
,
1.0
,
2.8
};
//
inside
roof
area
but
near
the
top
double
[]
outsidePoint
=
{
3.0
,
3.0
,
3.0
};
//
clearly
outside
double
[]
edgePoint
=
{
2.0
,
2.0
,
2.0
};
//
exactly
on
the
upper
cube
corner
//
Test
containment
System
.
out
.
println
(
"
\n
Test point (inside): "
+
Arrays
.
toString
(
insidePoint
));
System
.
out
.
println
(
"-> contained? "
+
houseAABB
.
encloses
(
insidePoint
[
0
],
insidePoint
[
1
],
insidePoint
[
2
]));
System
.
out
.
println
(
"
\n
Test point (on roof): "
+
Arrays
.
toString
(
roofPoint
));
System
.
out
.
println
(
"-> contained? "
+
houseAABB
.
encloses
(
roofPoint
[
0
],
roofPoint
[
1
],
roofPoint
[
2
]));
System
.
out
.
println
(
"
\n
Test point (outside): "
+
Arrays
.
toString
(
outsidePoint
));
System
.
out
.
println
(
"-> contained? "
+
houseAABB
.
encloses
(
outsidePoint
[
0
],
outsidePoint
[
1
],
outsidePoint
[
2
]));
System
.
out
.
println
(
"
\n
Test point (on edge): "
+
Arrays
.
toString
(
edgePoint
));
System
.
out
.
println
(
"-> contained? "
+
houseAABB
.
encloses
(
edgePoint
[
0
],
edgePoint
[
1
],
edgePoint
[
2
]));
}
/**
Creates
a
triangular
polygon
from
three
points
*/
private
static
ConcretePolygon
createTrianglePolygon
(
Point
p1
,
Point
p2
,
Point
p3
)
{
//
alocate
poly
ConcretePolygon
poly
=
new
ConcretePolygon
();
//
alocate
ring
LinearRing
ring
=
new
LinearRing
(
LinearRing
.
LinearRingType
.
EXTERIOR
);
//
vertices
of
triangle
ring
.
addVertex
(
new
Vertex
(
p1
.
getX
(),
p1
.
getY
(),
p1
.
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
(
p1
.
getX
(),
p1
.
getY
(),
p1
.
getZ
()));
//
Close
ring
//
poly
.
setExteriorRing
(
ring
);
return
poly
;
}
/**
Creates
a
quadrilateral
polygon
from
four
points
*/
private
static
ConcretePolygon
createQuadPolygon
(
Point
p1
,
Point
p2
,
Point
p3
,
Point
p4
)
{
ConcretePolygon
poly
=
new
ConcretePolygon
();
LinearRing
ring
=
new
LinearRing
(
LinearRing
.
LinearRingType
.
EXTERIOR
);
ring
.
addVertex
(
new
Vertex
(
p1
.
getX
(),
p1
.
getY
(),
p1
.
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
(
p4
.
getX
(),
p4
.
getY
(),
p4
.
getZ
()));
ring
.
addVertex
(
new
Vertex
(
p1
.
getX
(),
p1
.
getY
(),
p1
.
getZ
()));
//
Close
ring
poly
.
setExteriorRing
(
ring
);
return
poly
;
}
}
.metadata/.plugins/org.eclipse.core.resources/.history/c0/6091b0b52699001017e0d034282fa54d
0 → 100644
View file @
c67a5961
package
de
.
hft
.
stuttgart
.
citydoctor2
.
healing
.
bht
;
/**
*
Central
collection
of
CityGML
test
file
paths
used
for
AABB
/
healing
experiments
.
*
Files
are
located
under
{@
code
src
/
test
/
resources
}
or
{@
code
src
/
test
/
resources
/
bht
/}
*
ACHTUNG
:
mit
'!!!'
markierte
Objekte
haben
einen
falschen
Pfad
*/
public
final
class
TestPaths
{
private
TestPaths
()
{
//
utility
class
}
//
==================================================
//
Schematron
/
Validation
tests
//
==================================================
/**
!!! Not XSD valid, namespaces removed, for schematron experiments. */
public
static
final
String
SCHEMATRON
=
"CityDoctorParent/CityDoctorValidation/target/test-classes/SimpleSolid_SrefBS-Schematron-Test.gml"
;
//
CityDoctorParent
//
"src/test/resources/bht/SimpleSolid_SrefBS-Schematron-Test.gml"
;
//
==================================================
//
LinearRing
(
LR
)
test
cases
//
==================================================
/**
1
LinearRing
has
only
2
points
.
*/
public
static
final
String
LR_2POINTS
=
"src/test/resources/SimpleSolid_SrefBS-GE-gml-LR-0001-T0001.gml"
;
/**
2
LinearRing
has
3
points
but
is
not
closed
.
*/
public
static
final
String
LR_NOTCLOSED
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-LR-0001-T0002.gml"
;
/**
3
LinearRing
has
consecutive
duplicate
vertices
.
*/
public
static
final
String
LR_DUPLICATE_CONSEC
=
"src/test/resources/SimpleSolid_SrefBS-GE-gml-LR-0002-T0001.gml"
;
/**
4
LinearRing
has
non
-
consecutive
duplicate
vertices
.
*/
public
static
final
String
LR_DUPLICATE_NONCONSEC
=
"src/test/resources/SimpleSolid_SrefBS-GE-gml-LR-0002-T0002.gml"
;
/**
added
5
LinearRing
points
form
a
straight
line
.
*/
public
static
final
String
LR_LINE
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-LR-0002-T0003.gml"
;
/**
added
6
LinearRing
has
consecutive
points
closer
than
0.1
.
*/
public
static
final
String
LR_TOO_CLOSE
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-LR-0002-T0004.gml"
;
/**
added
7
LinearRing
has
too
few
points
and
duplicate
points
.
*/
public
static
final
String
LR_TOO_FEW_DUP
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-LR-0002-T0005.gml"
;
/**
8
LinearRing
is
not
closed
.
*/
public
static
final
String
LR_NOTCLOSED_2
=
"src/test/resources/SimpleSolid_SrefBS-GE-gml-LR-0003-T0001.gml"
;
/**
added
9
LinearRing
is
closed
but
with
point
distance
<
0.1
.
*/
public
static
final
String
LR_CLOSED_SMALLDIST
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-LR-0003-T0002.gml"
;
/**
10
LinearRing
has
a
loop
.
*/
public
static
final
String
LR_LOOP
=
"src/test/resources/SimpleSolid_SrefBS-GE-gml-LR-0004-T0004.gml"
;
/**
11
LinearRing
point
touches
edge
with
distance
<
0.1
.
*/
public
static
final
String
LR_TOUCH_EDGE
=
"src/test/resources/SimpleSolid_SrefBS-GE-gml-LR-0004-T0005.gml"
;
//
==================================================
//
Polygon
(
PO
)
test
cases
//
==================================================
/**
12
Inner
ring
intersects
outer
ring
.
*/
public
static
final
String
PO_INTERSECT_OUTER
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-PO-0001-T0001.gml"
;
/**
13
Polygon
has
2
inner
rings
.
*/
public
static
final
String
PO_TWO_INNERS
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-PO-0001-T0002.gml"
;
/**
14
Polygon
has
2
intersecting
inner
rings
.
*/
public
static
final
String
PO_INNER_INTERSECT
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-PO-0001-T0003.gml"
;
/**
15
Polygon
has
2
inner
rings
;
one
vertex
too
far
from
the
plane
.
*/
public
static
final
String
PO_INNER_OFF_PLANE
=
"src/test/resources/SimpleSolid_SrefBS-GE-gml-PO-0002-T0001.gml"
;
/**
added
16
Polygon
has
normal
deviation
error
.
*/
public
static
final
String
PO_NORMAL_ERROR
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-PO-0002-T0002.gml"
;
/**
17
Polygon
has
disconnected
interior
surface
.
*/
public
static
final
String
PO_DISCONNECTED_INTERIOR_1
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-PO-0003-T0001.gml"
;
/**
added
18
Polygon
has
disconnected
interior
surface
due
to
two
inner
rings
.
*/
public
static
final
String
PO_DISCONNECTED_INTERIOR_2
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-PO-0003-T0002.gml"
;
/**
added
19
Inner
ring
completely
outside
the
outer
ring
.
*/
public
static
final
String
PO_INNER_OUTSIDE
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-PO-0004-T0001.gml"
;
/**
added
20
Inner
ring
completely
inside
another
inner
ring
.
*/
public
static
final
String
PO_INNER_INSIDE_ANOTHER
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-PO-0005-T0001.gml"
;
/**
21
Two
inner
rings
with
wrong
orientation
.
*/
public
static
final
String
PO_TWO_INNERS_WRONG_ORIENT
=
"src/test/resources/SimpleSolid_SrefBS-GE-gml-PO-0006-T0001.gml"
;
//
==================================================
//
Solid
(
SO
)
test
cases
//
==================================================
/**
added
22
Solid
consists
of
only
3
polygons
.
*/
public
static
final
String
SO_TOO_FEW_POLYGONS
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-SO-0001-T0001.gml"
;
/**
added
23
Shell
is
not
watertight
.
*/
public
static
final
String
SO_NOT_WATERTIGHT
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-SO-0002-T0001.gml"
;
/**
24
Two
buildings
connected
only
by
a
single
point
.
*/
public
static
final
String
SO_CONNECTED_BY_POINT
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-SO-0003-T0001.gml"
;
/**
25
Roof
point
slightly
deviates
(
e
.
g
.,
10.0
14.95
2.95
vs
10.0
15.0
3.0
).
*/
public
static
final
String
SO_ROOF_COORD_DEVIATION_1
=
"src/test/resources/SimpleSolid_SrefBS-GE-gml-SO-0004-T0001.gml"
;
/**
25
Missing
polygon
.
*/
public
static
final
String
SO_MISSING_POLYGON
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-SO-0004-T0002.gml"
;
/**
LOST
! 26 Slight coordinate deviations on multiple roof polygons (CityGML 2.0 only). */
public
static
final
String
SO_ROOF_COORD_DEVIATION_2
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-SO-0004-T0003.gml"
;
/**
added
27
Solid
geometry
actually
contains
two
buildings
.
*/
public
static
final
String
SO_TWO_BUILDINGS_IN_ONE
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-SO-0005-T0001.gml"
;
//
Falsches
Datei
!!!!
/**
!!! 28 Self-intersecting geometry. */
public
static
final
String
SO_SELF_INTERSECTING
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-SO-0003-T0001.gml"
;
//
ACHTUNG
FALSCHES
LABEL
/**
29
Polygon
with
wrong
orientation
.
*/
public
static
final
String
ENTER_LABEL1
=
"src/test/resources/SimpleSolid_SrefBS-GE-gml-SO-0007-T0001.gml"
;
/**
30
Polygon
with
wrong
orientation
.
ACHTUNG
FALSCHES
LABEL
*/
public
static
final
String
ENTER_LABEL2
=
"src/test/resources/SimpleSolid_SrefBS-GE-gml-SO-0007-T0002.gml"
;
/**
31
Polygon
with
wrong
orientation
.
ACHTUNG
FALSCHES
LABEL
*/
public
static
final
String
ENTER_LABEL3
=
"src/test/resources/SimpleSolid_SrefBS-GE-gml-SO-0007-T0003.gml"
;
//
/**
LOST
! 33 All polygons have wrong orientation. */
public
static
final
String
SO_WRONG_POLY_ORIENTATION_ALL
=
"src/test/resources/bht/SimpleSolid_SrefBS-GE-gml-SO-0008-T0001.gml"
;
}
.metadata/.plugins/org.eclipse.core.resources/.history/c1/7096723af4e700101110d31642d3da88
0 → 100644
View file @
c67a5961
package
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
bht
;
import
java
.
util
.*;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
checks
.
aabb
.
AABB
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
checks
.
aabb
.
BVHStructures
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
checks
.
aabb
.
Point
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
ConcretePolygon
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
LinearRing
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
Vertex
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
LinearRing
.
LinearRingType
;
public
class
TestDummyAABB
{
/**
*
Entry
point
for
AABB
testing
*/
public
static
void
main
(
String
[]
args
)
{
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
Point
p1
=
new
Point
(
0
,
0
,
0
);
Point
p2
=
new
Point
(
1
,
0
,
0
);
Point
p3
=
new
Point
(
0.5
,
1
,
0
);
Point
p4
=
new
Point
(
0.5
,
0.5
,
1
);
//
Define
triangle
faces
of
the
tetrahedron
ConcretePolygon
base
=
new
ConcretePolygon
();
LinearRing
baseRing
=
new
LinearRing
(
LinearRingType
.
EXTERIOR
);
baseRing
.
addVertex
(
new
Vertex
(
p1
.
getX
(),
p1
.
getY
(),
p1
.
getZ
()));
baseRing
.
addVertex
(
new
Vertex
(
p2
.
getX
(),
p2
.
getY
(),
p2
.
getZ
()));
baseRing
.
addVertex
(
new
Vertex
(
p3
.
getX
(),
p3
.
getY
(),
p3
.
getZ
()));
baseRing
.
addVertex
(
new
Vertex
(
p1
.
getX
(),
p1
.
getY
(),
p1
.
getZ
()));
base
.
setExteriorRing
(
baseRing
);
ConcretePolygon
side1
=
new
ConcretePolygon
();
LinearRing
ring1
=
new
LinearRing
(
LinearRingType
.
EXTERIOR
);
ring1
.
addVertex
(
new
Vertex
(
p1
.
getX
(),
p1
.
getY
(),
p1
.
getZ
()));
ring1
.
addVertex
(
new
Vertex
(
p2
.
getX
(),
p2
.
getY
(),
p2
.
getZ
()));
ring1
.
addVertex
(
new
Vertex
(
p4
.
getX
(),
p4
.
getY
(),
p4
.
getZ
()));
ring1
.
addVertex
(
new
Vertex
(
p1
.
getX
(),
p1
.
getY
(),
p1
.
getZ
()));
side1
.
setExteriorRing
(
ring1
);
ConcretePolygon
side2
=
new
ConcretePolygon
();
LinearRing
ring2
=
new
LinearRing
(
LinearRingType
.
EXTERIOR
);
ring2
.
addVertex
(
new
Vertex
(
p2
.
getX
(),
p2
.
getY
(),
p2
.
getZ
()));
ring2
.
addVertex
(
new
Vertex
(
p3
.
getX
(),
p3
.
getY
(),
p3
.
getZ
()));
ring2
.
addVertex
(
new
Vertex
(
p4
.
getX
(),
p4
.
getY
(),
p4
.
getZ
()));
ring2
.
addVertex
(
new
Vertex
(
p2
.
getX
(),
p2
.
getY
(),
p2
.
getZ
()));
side2
.
setExteriorRing
(
ring2
);
ConcretePolygon
side3
=
new
ConcretePolygon
();
LinearRing
ring3
=
new
LinearRing
(
LinearRingType
.
EXTERIOR
);
ring3
.
addVertex
(
new
Vertex
(
p3
.
getX
(),
p3
.
getY
(),
p3
.
getZ
()));
ring3
.
addVertex
(
new
Vertex
(
p1
.
getX
(),
p1
.
getY
(),
p1
.
getZ
()));
ring3
.
addVertex
(
new
Vertex
(
p4
.
getX
(),
p4
.
getY
(),
p4
.
getZ
()));
ring3
.
addVertex
(
new
Vertex
(
p3
.
getX
(),
p3
.
getY
(),
p3
.
getZ
()));
side3
.
setExteriorRing
(
ring3
);
List
<
ConcretePolygon
>
poly
=
Arrays
.
asList
(
base
,
side1
,
side2
,
side3
);
AABB
aabb
=
BVHStructures
.
getAggregateAABB
(
poly
);
System
.
out
.
println
(
"
\n
Computed AABB:"
);
aabb
.
print
();
/***
3
D
-
Point
-
coords
with
Test
Properties
***/
//
Inside
laying
Point
double
testInsideX
=
0.5
;
double
testInsideY
=
0.5
;
double
testInsideZ
=
0.3
;
//
Outside
laying
Point
double
testOutsideX
=
2.0
;
double
testOutsideY
=
2.0
;
double
testOutsideZ
=
2.0
;
//
On
edge
laying
Point
double
testOnEdgeX
=
1.0
;
double
testOnEdgeY
=
1.0
;
double
testOnEdgeZ
=
0.0
;
System
.
out
.
println
(
"
\n
Test point (inside): "
+
testInsideX
+
" "
+
testInsideY
+
" "
+
testInsideZ
);
System
.
out
.
println
(
"-> contained?: "
+
aabb
.
encloses
(
testInsideX
,
testInsideY
,
testInsideZ
));
System
.
out
.
println
(
"
\n
Test point (outside): "
+
testOutsideX
+
" "
+
testOutsideY
+
" "
+
testOutsideZ
);
System
.
out
.
println
(
"-> contained?: "
+
aabb
.
encloses
(
testOutsideX
,
testOutsideY
,
testOutsideZ
));
System
.
out
.
println
(
"
\n
Test point (on edge): "
+
testOnEdgeX
+
" "
+
testOnEdgeY
+
" "
+
testOnEdgeZ
);
System
.
out
.
println
(
"-> contained?: "
+
aabb
.
encloses
(
testOnEdgeX
,
testOnEdgeY
,
testOnEdgeZ
));
}
}
.metadata/.plugins/org.eclipse.core.resources/.history/c3/f0ac3dad7cea0010125ad88dcc4485e5
0 → 100644
View file @
c67a5961
package
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
bht
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
ConcretePolygon
;
//
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
Edge
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
LinearRing
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
Vertex
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
math
.
Vector3d
;
import
java
.
util
.*;
//
import
java
.
util
.
List
;
/**
*
@
author
Baris
Numanoglu
*
*
Utility
class
providing
AABB
-
related
helper
methods
.
*
*
Contains
functionality
for
computing
axis
-
aligned
bounding
boxes
(
AABBs
)
*
from
geometric
data
structures
such
as
{@
link
ConcretePolygon
}
or
{@
link
LinearRing
}.
*
*
All
methods
are
static
.
*/
public
class
AABBUtils
{
public
static
AABB
getAABB
(
ConcretePolygon
poly
)
{
LinearRing
ring
=
poly
.
getExteriorRing
();
if
(
ring
==
null
)
return
null
;
return
computeAABBFromRing
(
ring
);
}
/**
*
Computes
an
AABB
from
a
LinearRing
by
iterating
over
its
vertices
.
*
*
@
param
ring
the
LinearRing
whose
vertices
define
the
AABB
*
@
return
AABB
enclosing
the
ring
;
returns
an
empty
AABB
if
the
ring
has
no
vertices
*/
public
static
AABB
computeAABBFromRing
(
LinearRing
ring
)
{
if
(
ring
==
null
||
ring
.
getVertices
()
==
null
||
ring
.
getVertices
().
isEmpty
())
{
return
new
AABB
(
Double
.
POSITIVE_INFINITY
,
Double
.
POSITIVE_INFINITY
,
Double
.
POSITIVE_INFINITY
,
Double
.
NEGATIVE_INFINITY
,
Double
.
NEGATIVE_INFINITY
,
Double
.
NEGATIVE_INFINITY
);
}
double
minX
=
Double
.
POSITIVE_INFINITY
;
double
minY
=
Double
.
POSITIVE_INFINITY
;
double
minZ
=
Double
.
POSITIVE_INFINITY
;
double
maxX
=
Double
.
NEGATIVE_INFINITY
;
double
maxY
=
Double
.
NEGATIVE_INFINITY
;
double
maxZ
=
Double
.
NEGATIVE_INFINITY
;
for
(
Vertex
v
:
ring
.
getVertices
())
{
double
x
=
v
.
getX
();
double
y
=
v
.
getY
();
double
z
=
v
.
getZ
();
minX
=
Math
.
min
(
minX
,
x
);
minY
=
Math
.
min
(
minY
,
y
);
minZ
=
Math
.
min
(
minZ
,
z
);
maxX
=
Math
.
max
(
maxX
,
x
);
maxY
=
Math
.
max
(
maxY
,
y
);
maxZ
=
Math
.
max
(
maxZ
,
z
);
}
return
new
AABB
(
minX
,
minY
,
minZ
,
maxX
,
maxY
,
maxZ
);
}
/**
*
PREMORDIAL
:
substitutes
the
earlier
semantic
of
AABB
-
Point
-
Init
.
*
Computes
the
min
and
max
bounds
(
6
doubles
)
from
two
points
.
*
*
@
param
p1
the
first
point
*
@
param
p2
the
second
point
*
@
return
an
array
of
6
doubles
:
[
minX
,
minY
,
minZ
,
maxX
,
maxY
,
maxZ
]
*/
public
static
double
[]
extractBoundsFromPoints
(
Point
p1
,
Point
p2
)
{
double
minX
=
Math
.
min
(
p1
.
getX
(),
p2
.
getX
());
double
minY
=
Math
.
min
(
p1
.
getY
(),
p2
.
getY
());
double
minZ
=
Math
.
min
(
p1
.
getZ
(),
p2
.
getZ
());
double
maxX
=
Math
.
max
(
p1
.
getX
(),
p2
.
getX
());
double
maxY
=
Math
.
max
(
p1
.
getY
(),
p2
.
getY
());
double
maxZ
=
Math
.
max
(
p1
.
getZ
(),
p2
.
getZ
());
return
new
double
[]
{
minX
,
minY
,
minZ
,
maxX
,
maxY
,
maxZ
};
}
//
NOTE
:
May
replaced
later
:
double
[]
extractBoundsFromPoints
(
List
<?
extends
Point
>
points
)??
public
static
AABB
aabbFromVector3d
(
List
<?
extends
Vector3d
>
points
)
{
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
;
for
(
Vector3d
p
:
points
)
{
minX
=
Math
.
min
(
minX
,
p
.
getX
());
minY
=
Math
.
min
(
minY
,
p
.
getY
());
minZ
=
Math
.
min
(
minZ
,
p
.
getZ
());
maxX
=
Math
.
max
(
maxX
,
p
.
getX
());
maxY
=
Math
.
max
(
maxY
,
p
.
getY
());
maxZ
=
Math
.
max
(
maxZ
,
p
.
getZ
());
}
return
new
AABB
(
minX
,
minY
,
minZ
,
maxX
,
maxY
,
maxZ
);
}
/**
*
Computes
an
AABB
for
a
single
vertex
(
degenerate
AABB
with
min
=
max
=
vertex
coordinates
).
*
*
@
param
vertex
the
vertex
to
wrap
in
an
AABB
*
@
return
AABB
centered
at
the
vertex
position
*/
public
static
AABB
computeAABBFromVertex
(
Vertex
vertex
)
{
if
(
vertex
==
null
)
{
//
Return
a
degenerate
AABB
with
infinite
bounds
if
vertex
is
null
return
new
AABB
(
Double
.
POSITIVE_INFINITY
,
Double
.
POSITIVE_INFINITY
,
Double
.
POSITIVE_INFINITY
,
Double
.
NEGATIVE_INFINITY
,
Double
.
NEGATIVE_INFINITY
,
Double
.
NEGATIVE_INFINITY
);
}
double
x
=
vertex
.
getX
();
double
y
=
vertex
.
getY
();
double
z
=
vertex
.
getZ
();
//
AABB
is
degenerate
here
:
min
=
max
=(
x
,
y
,
z
)
return
new
AABB
(
x
,
y
,
z
,
x
,
y
,
z
);
}
/**
Returns
true
if
the
AABB
is
(
nearly
)
flat
in
at
least
two
axes
.
*/
public
static
boolean
isDegenerate
(
AABB
aabb
,
double
tol
)
{
double
dx
=
aabb
.
getMaxX
()
-
aabb
.
getMinX
();
double
dy
=
aabb
.
getMaxY
()
-
aabb
.
getMinY
();
double
dz
=
aabb
.
getMaxZ
()
-
aabb
.
getMinZ
();
int
flatAxes
=
0
;
if
(
dx
<=
tol
)
flatAxes
++;
if
(
dy
<=
tol
)
flatAxes
++;
if
(
dz
<=
tol
)
flatAxes
++;
return
flatAxes
>=
2
;
//
cannot
host
3
distinct
points
in
3
D
}
/**
*
Counts
distinct
vertices
of
a
ring
using
a
tolerance
.
*
Implementation
:
uniform
quantization
(
grid
hashing
)
for
speed
and
determinism
.
*/
public
static
int
countDistinctVertices
(
LinearRing
ring
,
double
tol
)
{
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
3
D
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
;
}
/**
Returns
true
if
'outer'
fully
contains
'inner'
(
inclusive
)
in
axis
-
aligned
sense
.
*/
public
static
boolean
containsAabb
(
AABB
outer
,
AABB
inner
)
{
return
outer
.
getMinX
()
<=
inner
.
getMinX
()
&&
outer
.
getMinY
()
<=
inner
.
getMinY
()
&&
outer
.
getMinZ
()
<=
inner
.
getMinZ
()
&&
outer
.
getMaxX
()
>=
inner
.
getMaxX
()
&&
outer
.
getMaxY
()
>=
inner
.
getMaxY
()
&&
outer
.
getMaxZ
()
>=
inner
.
getMaxZ
();
}
/**
Builds
a
padded
AABB
around
a
segment
(
two
vertices
).
*/
public
static
AABB
edgeAabb
(
Vertex
a
,
Vertex
b
,
double
pad
)
{
double
minX
=
Math
.
min
(
a
.
getX
(),
b
.
getX
())
-
pad
;
double
minY
=
Math
.
min
(
a
.
getY
(),
b
.
getY
())
-
pad
;
double
minZ
=
Math
.
min
(
a
.
getZ
(),
b
.
getZ
())
-
pad
;
double
maxX
=
Math
.
max
(
a
.
getX
(),
b
.
getX
())
+
pad
;
double
maxY
=
Math
.
max
(
a
.
getY
(),
b
.
getY
())
+
pad
;
double
maxZ
=
Math
.
max
(
a
.
getZ
(),
b
.
getZ
())
+
pad
;
return
new
AABB
(
minX
,
minY
,
minZ
,
maxX
,
maxY
,
maxZ
);
}
/**
Returns
true
if
two
AABBs
overlap
(
inclusive
).
*/
public
static
boolean
overlaps
(
AABB
a
,
AABB
b
)
{
return
!(a.getMaxX() < b.getMinX() ||
a
.
getMinX
()
>
b
.
getMaxX
()
||
a
.
getMaxY
()
<
b
.
getMinY
()
||
a
.
getMinY
()
>
b
.
getMaxY
()
||
a
.
getMaxZ
()
<
b
.
getMinZ
()
||
a
.
getMinZ
()
>
b
.
getMaxZ
());
}
}
.metadata/.plugins/org.eclipse.core.resources/.history/c8/7080726371e900101245d5e14ea95888
0 → 100644
View file @
c67a5961
package
de
.
hft
.
stuttgart
.
citydoctor2
.
healing
.
bht
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.
bht
.*;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
datastructure
.*;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
parser
.*;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
systemtest
.
TestUtil
;
import
de
.
hft
.
stuttgart
.
citydoctor2
.
check
.*;
//
import
de
.
hft
.
stuttgart
.
citydoctor2
.
healing
.*;
import
java
.
io
.
IOException
;
import
java
.
util
.*;
//
src
/
test
/
java
/.../
TestCityGmlAABB
.
java
import
java
.
net
.
URL
;
import
java
.
nio
.
file
.
Paths
;
public
class
TestCityGmlAABB
{
public
static
void
main
(
String
[]
args
)
throws
CityGmlParseException
,
IOException
,
InvalidGmlFileException
{
System
.
out
.
println
(
"=== CityGML AABB Test ==="
);
//
---
1
)
Ask
user
which
test
case
to
run
---
Scanner
sc
=
new
Scanner
(
System
.
in
);
System
.
out
.
print
(
"Enter TestCase ID (e.g. PO_TWO_INNERS, SO_WRONG_POLY_ORIENTATION_SINGLE) "
+
"or press Enter for default: "
);
String
id
=
sc
.
nextLine
().
trim
();
//
Default
w
ä
hlen
String
resourcePath
=
TestPaths
.
PO_TWO_INNERS
;
if
(
!id.isEmpty()) {
try
{
//
Holt
TestPaths
per
Reflection
resourcePath
=
(
String
)
TestPaths
.
class
.
getField
(
id
).
get
(
null
);
}
catch
(
ReflectiveOperationException
ex
)
{
System
.
out
.
println
(
"Unknown testcase: "
+
id
+
" (using default)"
);
}
}
String
filePathForParser
=
resolveResourceOnClasspath
(
resourcePath
);
System
.
out
.
println
(
"Using file: "
+
filePathForParser
);
//
---
2
)
Load
CityGML
model
---
ValidationConfiguration
config
=
ValidationConfiguration
.
loadStandardValidationConfig
();
//
TODO
:
Study
class
model
CityDoctorModel
model
=
TestUtil
.
loadCityModel
(
filePathForParser
,
config
);
System
.
out
.
println
(
"Model loaded successfully.
\n
"
);
List
<
Building
>
buildings
=
model
.
getBuildings
();
//
---
3
)
Menu
:
choose
granularity
---
System
.
out
.
println
(
"
\n
Choose granularity:"
);
System
.
out
.
println
(
" 1) Polygon-level (broad-phase)"
);
System
.
out
.
println
(
" 2) Ring-level (EXTERIOR)"
);
System
.
out
.
println
(
" 3) Ring-level (INTERIOR)"
);
System
.
out
.
println
(
" 4) Vertex-level (fine-phase)"
);
System
.
out
.
println
(
" 5) All of the above"
);
System
.
out
.
print
(
"Your choice [1-5]: "
);
int
choice
=
readChoice
(
sc
,
1
,
5
);
boolean
doPolygon
=
(
choice
==
1
||
choice
==
5
);
boolean
doExtRing
=
(
choice
==
2
||
choice
==
5
);
boolean
doIntRing
=
(
choice
==
3
||
choice
==
5
);
boolean
doVertex
=
(
choice
==
4
||
choice
==
5
);
//
---
4
)
Run
the
selected
modes
---
if
(
doPolygon
)
runPolygonMode
(
buildings
);
if
(
doExtRing
)
runRingMode
(
buildings
,
true
);
if
(
doIntRing
)
runRingMode
(
buildings
,
false
);
if
(
doVertex
)
runVertexMode
(
buildings
);
System
.
out
.
println
(
"
\n
=== Done ==="
);
}
//
----------
Modes
----------
private
static
void
runPolygonMode
(
List
<
Building
>
buildings
)
{
System
.
out
.
println
(
"
\n
> Polygon-level AABB (broad-phase)"
);
Set
<
ConcretePolygon
>
polys
=
collectAllPolygons
(
buildings
);
AABBTree
<
ConcretePolygon
>
bvh
=
new
AABBTree
<>(
new
ArrayList
<>(
polys
),
AABBUtils
::
getAABB
);
System
.
out
.
println
(
"Polygons: "
+
polys
.
size
());
if
(
bvh
.
getRoot
()
!= null) {
System
.
out
.
print
(
"Root AABB: "
);
bvh
.
getRoot
().
aabb
.
print
();
}
}
private
static
void
runRingMode
(
List
<
Building
>
buildings
,
boolean
exterior
)
{
String
label
=
exterior
?
"EXTERIOR"
:
"INTERIOR"
;
System
.
out
.
println
(
"
\n
> Ring-level AABB ("
+
label
+
")"
);
Set
<
LinearRing
>
rings
=
exterior
?
collectExteriorRings
(
buildings
)
:
collectInteriorRings
(
buildings
);
AABBTree
<
LinearRing
>
bvh
=
new
AABBTree
<>(
new
ArrayList
<>(
rings
),
AABBUtils
::
computeAABBFromRing
);
System
.
out
.
println
(
label
+
" rings: "
+
rings
.
size
());
if
(
bvh
.
getRoot
()
!= null) {
System
.
out
.
print
(
"Root AABB: "
);
bvh
.
getRoot
().
aabb
.
print
();
}
}
private
static
void
runVertexMode
(
List
<
Building
>
buildings
)
{
System
.
out
.
println
(
"
\n
> Vertex-level AABB (fine-phase)"
);
Set
<
Vertex
>
verts
=
collectAllVertices
(
buildings
);
AABBTree
<
Vertex
>
bvh
=
new
AABBTree
<>(
new
ArrayList
<>(
verts
),
AABBUtils
::
computeAABBFromVertex
);
System
.
out
.
println
(
"Vertices: "
+
verts
.
size
());
if
(
bvh
.
getRoot
()
!= null) {
System
.
out
.
print
(
"Root AABB: "
);
bvh
.
getRoot
().
aabb
.
print
();
}
}
//
----------
Collectors
----------
/**
Collects
all
ConcretePolygons
(
unique
)
via
visitor
.
*/
private
static
Set
<
ConcretePolygon
>
collectAllPolygons
(
List
<
Building
>
buildings
)
{
Set
<
ConcretePolygon
>
set
=
new
HashSet
<>();
for
(
Building
b
:
buildings
)
{
b
.
accept
(
new
CheckableUtilsVisitor
()
{
@
Override
public
void
check
(
Polygon
poly
)
{
set
.
add
(
poly
.
getOriginal
());
}
});
}
return
set
;
}
/**
Collects
all
EXTERIOR
rings
(
unique
).
*/
private
static
Set
<
LinearRing
>
collectExteriorRings
(
List
<
Building
>
buildings
)
{
Set
<
LinearRing
>
set
=
new
HashSet
<>();
for
(
Building
b
:
buildings
)
{
b
.
accept
(
new
CheckableUtilsVisitor
()
{
@
Override
public
void
check
(
Polygon
poly
)
{
LinearRing
ext
=
poly
.
getOriginal
().
getExteriorRing
();
if
(
ext
!= null) set.add(ext);
}
});
}
return
set
;
}
/**
Collects
all
INTERIOR
rings
(
unique
).
*/
private
static
Set
<
LinearRing
>
collectInteriorRings
(
List
<
Building
>
buildings
)
{
Set
<
LinearRing
>
set
=
new
HashSet
<>();
for
(
Building
b
:
buildings
)
{
b
.
accept
(
new
CheckableUtilsVisitor
()
{
@
Override
public
void
check
(
Polygon
poly
)
{
List
<
LinearRing
>
inner
=
poly
.
getOriginal
().
getInnerRings
();
if
(
inner
!= null && !inner.isEmpty()) {
set
.
addAll
(
inner
);
}
}
});
}
return
set
;
}
/**
Collects
all
vertices
(
unique
)
from
both
exterior
and
interior
rings
.
*/
private
static
Set
<
Vertex
>
collectAllVertices
(
List
<
Building
>
buildings
)
{
Set
<
Vertex
>
set
=
new
HashSet
<>();
for
(
Building
b
:
buildings
)
{
b
.
accept
(
new
CheckableUtilsVisitor
()
{
@
Override
public
void
check
(
Polygon
poly
)
{
ConcretePolygon
cp
=
poly
.
getOriginal
();
LinearRing
ext
=
cp
.
getExteriorRing
();
if
(
ext
!= null) set.addAll(ext.getVertices());
List
<
LinearRing
>
inner
=
cp
.
getInnerRings
();
if
(
inner
!= null) {
for
(
LinearRing
lr
:
inner
)
set
.
addAll
(
lr
.
getVertices
());
}
}
});
}
return
set
;
}
//
----------
Utils
----------
/*
Helper
method
reads
choice
of
the
user
*/
private
static
int
readChoice
(
Scanner
sc
,
int
min
,
int
max
)
{
while
(
true
)
{
String
s
=
sc
.
nextLine
().
trim
();
try
{
int
v
=
Integer
.
parseInt
(
s
);
if
(
v
>=
min
&&
v
<=
max
)
return
v
;
}
catch
(
NumberFormatException
ignored
)
{}
System
.
out
.
print
(
"Please enter a number between "
+
min
+
" and "
+
max
+
": "
);
}
}
/*
Helper
method
Pathfinder
*/
private
static
String
resolveResourceOnClasspath
(
String
resourcePath
)
{
String
rp
=
normalizeResourcePath
(
resourcePath
);
//
1
)
Klassenpfad
via
Class
.
getResource
URL
url
=
TestCityGmlAABB
.
class
.
getResource
(
rp
);
//
2
)
Klassenpfad
via
Context
-
ClassLoader
:
if
(
url
==
null
)
{
ClassLoader
cl
=
Thread
.
currentThread
().
getContextClassLoader
();
String
noSlash
=
rp
.
startsWith
(
"/"
)
?
rp
.
substring
(
1
)
:
rp
;
url
=
cl
.
getResource
(
noSlash
);
}
//
3
)
Wenn
gefunden
:
in
Pfad
umwandeln
if
(
url
!= null) {
try
{
return
Paths
.
get
(
url
.
toURI
()).
toString
();
}
catch
(
Exception
e
)
{
throw
new
RuntimeException
(
"Konnte Resource-URI nicht auflösen: "
+
url
,
e
);
}
}
//
4
)
Fallbacks
:
Projekt
-
relative
Kandidaten
pr
ü
fen
String
noSlash
=
rp
.
startsWith
(
"/"
)
?
rp
.
substring
(
1
)
:
rp
;
String
[]
candidates
=
{
"src/test/resources/"
+
noSlash
,
"src/main/resources/"
+
noSlash
,
resourcePath
//
falls
bereits
ein
echter
Dateipfad
ü
bergeben
wurde
};
for
(
String
cand
:
candidates
)
{
java
.
nio
.
file
.
Path
p
=
java
.
nio
.
file
.
Paths
.
get
(
cand
);
if
(
java
.
nio
.
file
.
Files
.
exists
(
p
))
{
return
p
.
toAbsolutePath
().
toString
();
}
}
throw
new
IllegalArgumentException
(
"Resource nicht im Klassenpfad gefunden: "
+
resourcePath
+
" (versucht als: "
+
rp
+
")"
);
}
//
F
Ü
R
ALLE
F
Ä
LLE
zur
Zeit
REDUNDAD
private
static
String
normalizeResourcePath
(
String
path
)
{
String
p
=
path
.
replace
(
'\\'
,
'/'
);
//
Quellordner
-
Pr
ä
fixe
entfernen
,
falls
mit
ü
bergeben
if
(
p
.
startsWith
(
"src/test/resources/"
))
{
p
=
p
.
substring
(
"src/test/resources/"
.
length
());
}
else
if
(
p
.
startsWith
(
"src/main/resources/"
))
{
p
=
p
.
substring
(
"src/main/resources/"
.
length
());
}
//
F
ü
r
Class
.
getResource
:
f
ü
hrenden
Slash
setzen
if
(
!p.startsWith("/")) p = "/" + p;
return
p
;
}
}
Prev
1
2
3
4
5
6
7
…
22
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