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
3032c1f9
Commit
3032c1f9
authored
May 26, 2026
by
Numanoglu
Browse files
Add synthetic sweep planarity test models
parent
cec0e9d5
Pipeline
#12402
passed with stage
in 2 minutes and 17 seconds
Changes
2
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/HealPlanarPolygonErrorTest.java
View file @
3032c1f9
...
@@ -36,6 +36,30 @@ import org.junit.experimental.categories.Category;
...
@@ -36,6 +36,30 @@ import org.junit.experimental.categories.Category;
public
class
HealPlanarPolygonErrorTest
{
public
class
HealPlanarPolygonErrorTest
{
@Test
public
void
testRaisedTopCornerCubeHasNonPlanarPolygon
()
{
Building
building
=
SyntheticSweepPlanarityModelFactory
.
createRaisedTopCornerCube
();
Geometry
geom
=
building
.
getGeometries
().
get
(
0
);
PlanarCheck
check
=
new
PlanarCheck
();
geom
.
accept
(
check
);
check
.
check
(
geom
);
Assert
.
assertTrue
(
geom
.
containsError
(
CheckId
.
C_GE_P_NON_PLANAR
));
}
@Test
public
void
testExistingHealerModelHasNonPlanarPolygon
()
{
Building
building
=
SyntheticSweepPlanarityModelFactory
.
createExistingHealerTestModel
();
Geometry
geom
=
building
.
getGeometries
().
get
(
0
);
PlanarCheck
check
=
new
PlanarCheck
();
geom
.
accept
(
check
);
check
.
check
(
geom
);
Assert
.
assertTrue
(
geom
.
containsError
(
CheckId
.
C_GE_P_NON_PLANAR
));
}
@Test
@Test
public
void
testPlanarPlaneDistance
()
throws
CityGmlParseException
,
IOException
,
InvalidGmlFileException
{
public
void
testPlanarPlaneDistance
()
throws
CityGmlParseException
,
IOException
,
InvalidGmlFileException
{
// Model with a non planar wall on the east side
// Model with a non planar wall on the east side
...
...
CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/SyntheticSweepPlanarityModel
Test
.java
→
CityDoctorParent/Extensions/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healing/SyntheticSweepPlanarityModel
Factory
.java
View file @
3032c1f9
...
@@ -4,11 +4,7 @@ import java.io.File;
...
@@ -4,11 +4,7 @@ import java.io.File;
import
org.citygml4j.core.model.CityGMLVersion
;
import
org.citygml4j.core.model.CityGMLVersion
;
import
org.citygml4j.core.model.core.CityModel
;
import
org.citygml4j.core.model.core.CityModel
;
import
org.junit.Assert
;
import
org.junit.Test
;
import
de.hft.stuttgart.citydoctor2.check.CheckId
;
import
de.hft.stuttgart.citydoctor2.checks.geometry.PlanarCheck
;
import
de.hft.stuttgart.citydoctor2.database.UnconnectedCache
;
import
de.hft.stuttgart.citydoctor2.database.UnconnectedCache
;
import
de.hft.stuttgart.citydoctor2.datastructure.Building
;
import
de.hft.stuttgart.citydoctor2.datastructure.Building
;
import
de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel
;
import
de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel
;
...
@@ -24,36 +20,61 @@ import de.hft.stuttgart.citydoctor2.datastructure.Vertex;
...
@@ -24,36 +20,61 @@ import de.hft.stuttgart.citydoctor2.datastructure.Vertex;
import
de.hft.stuttgart.citydoctor2.exceptions.CityDoctorWriteException
;
import
de.hft.stuttgart.citydoctor2.exceptions.CityDoctorWriteException
;
import
de.hft.stuttgart.citydoctor2.parser.ParserConfiguration
;
import
de.hft.stuttgart.citydoctor2.parser.ParserConfiguration
;
public
class
SyntheticSweepPlanarityModel
Test
{
public
class
SyntheticSweepPlanarityModel
Factory
{
public
static
void
main
(
String
[]
args
)
throws
CityDoctorWriteException
{
public
static
void
main
(
String
[]
args
)
throws
CityDoctorWriteException
{
exportBuildingForGui
(
createSweepPlanarityCubeWithRaisedTopCorner
(),
new
File
(
"sweep-planarity-raised-top-corner.gml"
));
exportForGui
(
exportBuildingForGui
(
createNonPlanarSweepBox
(),
new
File
(
"sweep-planarity-existing-healer-test-model.gml"
));
createRaisedTopCornerCube
(),
new
File
(
"sweep-planarity-raised-top-corner.gml"
),
"SweepPlanarityRaisedTopCorner"
);
exportForGui
(
createExistingHealerTestModel
(),
new
File
(
"sweep-planarity-existing-healer-test-model.gml"
),
"SweepPlanarityExistingHealerTestModel"
);
exportForGui
(
createWallWithProtrudingWindowInnerRingPoint
(),
new
File
(
"sweep-case1-wall-window-inner-ring-point.gml"
),
"SweepCase1WallWindowInnerRingPoint"
);
exportForGui
(
createWallWithProtrudingFacadePolygonPoint
(),
new
File
(
"sweep-case1-wall-facade-polygon-point.gml"
),
"SweepCase1WallFacadePolygonPoint"
);
exportForGui
(
createSlopedRoofWithProtrudingOpeningRingPoint
(),
new
File
(
"sweep-case1-sloped-roof-opening-ring-point.gml"
),
"SweepCase1SlopedRoofOpeningRingPoint"
);
}
}
static
Building
createNonPlanarCube
(
double
boxsize
,
double
bottomerr
,
double
topLift
)
{
Building
building
=
new
Building
();
Geometry
geom
=
new
Geometry
(
GeometryType
.
SOLID
,
Lod
.
LOD2
,
Orientation
.
OUTWARD
);
building
.
addGeometry
(
geom
);
@Test
Vertex
v0
=
new
Vertex
(
0
,
0
,
0
);
public
void
testSyntheticSweepPlanarityCubeHasNonPlanarTopFace
()
{
Vertex
v1
=
new
Vertex
(
boxsize
,
0
,
0
);
Building
building
=
createSweepPlanarityCubeWithRaisedTopCorner
();
Vertex
v4
=
new
Vertex
(
boxsize
,
boxsize
,
bottomerr
);
Geometry
geom
=
building
.
getGeometries
().
get
(
0
);
Vertex
v6
=
new
Vertex
(
0
,
boxsize
,
0
);
Vertex
v8
=
new
Vertex
(
boxsize
,
0
,
boxsize
);
PlanarCheck
check
=
new
PlanarCheck
();
Vertex
v9
=
new
Vertex
(
boxsize
,
boxsize
,
boxsize
);
geom
.
accept
(
check
);
Vertex
v10
=
new
Vertex
(
0
,
boxsize
,
boxsize
);
check
.
check
(
geom
);
Vertex
v11
=
new
Vertex
(
0
,
0
,
boxsize
+
topLift
);
Assert
.
assertTrue
(
geom
.
containsError
(
CheckId
.
C_GE_P_NON_PLANAR
));
addPolygon
(
geom
,
v0
,
v1
,
v4
,
v6
);
}
addPolygon
(
geom
,
v1
,
v8
,
v9
,
v4
);
addPolygon
(
geom
,
v8
,
v11
,
v10
,
v9
);
addPolygon
(
geom
,
v0
,
v6
,
v10
,
v11
);
addPolygon
(
geom
,
v4
,
v9
,
v10
,
v6
);
addPolygon
(
geom
,
v0
,
v11
,
v8
,
v1
);
@Test
geom
.
updateEdgesAndVertices
();
public
void
exportSyntheticSweepPlanarityCubeForGui
()
throws
CityDoctorWriteException
{
return
building
;
exportBuildingForGui
(
createSweepPlanarityCubeWithRaisedTopCorner
(),
new
File
(
"sweep-planarity-raised-top-corner.gml"
));
}
@Test
public
void
exportNonPlanarSweepBoxForGui
()
throws
CityDoctorWriteException
{
exportBuildingForGui
(
createNonPlanarSweepBox
(),
new
File
(
"sweep-planarity-existing-healer-test-model.gml"
));
}
}
static
Building
create
SweepPlanarityCubeWith
RaisedTopCorner
()
{
static
Building
createRaisedTopCorner
Cube
()
{
Building
building
=
new
Building
();
Building
building
=
new
Building
();
Geometry
geom
=
new
Geometry
(
GeometryType
.
SOLID
,
Lod
.
LOD2
,
Orientation
.
OUTWARD
);
Geometry
geom
=
new
Geometry
(
GeometryType
.
SOLID
,
Lod
.
LOD2
,
Orientation
.
OUTWARD
);
building
.
addGeometry
(
geom
);
building
.
addGeometry
(
geom
);
...
@@ -78,7 +99,83 @@ public class SyntheticSweepPlanarityModelTest {
...
@@ -78,7 +99,83 @@ public class SyntheticSweepPlanarityModelTest {
return
building
;
return
building
;
}
}
static
Building
createNonPlanarSweepBox
()
{
/**
* Fall 1 model: one point of a window-like inner ring protrudes from an otherwise
* planar wall. The intended target plane is x = 0 and the protruding ring point
* has no outgoing solid edge, so it should be orthogonally projected back.
*/
static
Building
createWallWithProtrudingWindowInnerRingPoint
()
{
Building
building
=
new
Building
();
Geometry
geom
=
new
Geometry
(
GeometryType
.
MULTI_SURFACE
,
Lod
.
LOD2
,
Orientation
.
OUTWARD
);
building
.
addGeometry
(
geom
);
Polygon
wall
=
addPolygon
(
geom
,
new
Vertex
(
0
,
0
,
0
),
new
Vertex
(
0
,
6
,
0
),
new
Vertex
(
0
,
6
,
4
),
new
Vertex
(
0
,
0
,
4
));
addInteriorRing
(
wall
,
new
Vertex
(
0
,
2
,
1
),
new
Vertex
(
0
,
4
,
1
),
new
Vertex
(
0.3
,
4
,
3
),
new
Vertex
(
0
,
2
,
3
));
geom
.
updateEdgesAndVertices
();
return
building
;
}
/**
* Fall 1 model: a separate facade/window polygon should lie on the wall plane
* x = 0, but one polygon corner sticks out. Because the facade polygon is not
* topologically connected to a solid edge, the faulty point is a pure projection
* case.
*/
static
Building
createWallWithProtrudingFacadePolygonPoint
()
{
Building
building
=
new
Building
();
Geometry
geom
=
new
Geometry
(
GeometryType
.
MULTI_SURFACE
,
Lod
.
LOD2
,
Orientation
.
OUTWARD
);
building
.
addGeometry
(
geom
);
addPolygon
(
geom
,
new
Vertex
(
0
,
0
,
0
),
new
Vertex
(
0
,
6
,
0
),
new
Vertex
(
0
,
6
,
4
),
new
Vertex
(
0
,
0
,
4
));
addPolygon
(
geom
,
new
Vertex
(
0
,
2
,
1
),
new
Vertex
(
0
,
4
,
1
),
new
Vertex
(
0.3
,
4
,
3
),
new
Vertex
(
0
,
2
,
3
));
geom
.
updateEdgesAndVertices
();
return
building
;
}
/**
* Fall 1 model: an opening ring in a sloped roof has one point outside the roof
* plane. This checks projection to a general oblique target plane instead of an
* axis-aligned wall plane.
*/
static
Building
createSlopedRoofWithProtrudingOpeningRingPoint
()
{
Building
building
=
new
Building
();
Geometry
geom
=
new
Geometry
(
GeometryType
.
MULTI_SURFACE
,
Lod
.
LOD2
,
Orientation
.
OUTWARD
);
building
.
addGeometry
(
geom
);
Polygon
roof
=
addPolygon
(
geom
,
new
Vertex
(
0
,
0
,
2
),
new
Vertex
(
4
,
0
,
4
),
new
Vertex
(
4
,
4
,
4
),
new
Vertex
(
0
,
4
,
2
));
addInteriorRing
(
roof
,
new
Vertex
(
1
,
1
,
2.5
),
new
Vertex
(
3
,
1
,
3.5
),
new
Vertex
(
3
,
3
,
4.0
),
new
Vertex
(
1
,
3
,
2.5
));
geom
.
updateEdgesAndVertices
();
return
building
;
}
static
Building
createExistingHealerTestModel
()
{
Building
building
=
new
Building
();
Building
building
=
new
Building
();
Geometry
geom
=
new
Geometry
(
GeometryType
.
SOLID
,
Lod
.
LOD2
,
Orientation
.
OUTWARD
);
Geometry
geom
=
new
Geometry
(
GeometryType
.
SOLID
,
Lod
.
LOD2
,
Orientation
.
OUTWARD
);
building
.
addGeometry
(
geom
);
building
.
addGeometry
(
geom
);
...
@@ -103,27 +200,27 @@ public class SyntheticSweepPlanarityModelTest {
...
@@ -103,27 +200,27 @@ public class SyntheticSweepPlanarityModelTest {
return
building
;
return
building
;
}
}
private
static
CityDoctorModel
createCityDoctorModel
(
Building
building
,
File
sourceFile
)
{
private
static
void
exportForGui
(
Building
building
,
File
output
,
String
gmlId
)
throws
CityDoctorWriteException
{
CityDoctorModel
model
=
createCityDoctorModel
(
building
,
output
,
gmlId
);
model
.
saveAs
(
output
.
getAbsolutePath
(),
false
);
System
.
out
.
println
(
"Open in CityDoctor GUI:"
);
System
.
out
.
println
(
output
.
getAbsolutePath
());
}
private
static
CityDoctorModel
createCityDoctorModel
(
Building
building
,
File
sourceFile
,
String
gmlId
)
{
ParserConfiguration
config
=
new
ParserConfiguration
(
8
,
false
);
ParserConfiguration
config
=
new
ParserConfiguration
(
8
,
false
);
CityDoctorModel
model
=
new
CityDoctorModel
(
config
,
sourceFile
,
new
UnconnectedCache
());
CityDoctorModel
model
=
new
CityDoctorModel
(
config
,
sourceFile
,
new
UnconnectedCache
());
model
.
setParsedCityGMLVersion
(
CityGMLVersion
.
v2_0
);
model
.
setParsedCityGMLVersion
(
CityGMLVersion
.
v2_0
);
model
.
setCityModel
(
new
CityModel
());
model
.
setCityModel
(
new
CityModel
());
org
.
citygml4j
.
core
.
model
.
building
.
Building
gmlBuilding
=
new
org
.
citygml4j
.
core
.
model
.
building
.
Building
();
org
.
citygml4j
.
core
.
model
.
building
.
Building
gmlBuilding
=
new
org
.
citygml4j
.
core
.
model
.
building
.
Building
();
gmlBuilding
.
setId
(
"SyntheticSweepPlanarityRaisedCorner"
);
gmlBuilding
.
setId
(
gmlId
);
building
.
setGmlObject
(
gmlBuilding
);
building
.
setGmlObject
(
gmlBuilding
);
model
.
addBuilding
(
building
);
model
.
addBuilding
(
building
);
return
model
;
return
model
;
}
}
private
static
void
exportBuildingForGui
(
Building
building
,
File
output
)
throws
CityDoctorWriteException
{
CityDoctorModel
model
=
createCityDoctorModel
(
building
,
output
);
model
.
saveAs
(
output
.
getAbsolutePath
(),
false
);
System
.
out
.
println
(
"Open in CityDoctor GUI:"
);
System
.
out
.
println
(
output
.
getAbsolutePath
());
}
private
static
Polygon
addPolygon
(
Geometry
geom
,
Vertex
...
vertices
)
{
private
static
Polygon
addPolygon
(
Geometry
geom
,
Vertex
...
vertices
)
{
Polygon
polygon
=
new
ConcretePolygon
();
Polygon
polygon
=
new
ConcretePolygon
();
geom
.
addPolygon
(
polygon
);
geom
.
addPolygon
(
polygon
);
...
@@ -136,4 +233,14 @@ public class SyntheticSweepPlanarityModelTest {
...
@@ -136,4 +233,14 @@ public class SyntheticSweepPlanarityModelTest {
return
polygon
;
return
polygon
;
}
}
private
static
LinearRing
addInteriorRing
(
Polygon
polygon
,
Vertex
...
vertices
)
{
LinearRing
ring
=
new
LinearRing
(
LinearRingType
.
INTERIOR
);
polygon
.
addInteriorRing
(
ring
);
for
(
Vertex
vertex
:
vertices
)
{
ring
.
addVertex
(
vertex
);
}
ring
.
addVertex
(
vertices
[
0
]);
return
ring
;
}
}
}
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