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
22fce970
Commit
22fce970
authored
Jul 11, 2024
by
Riegel
Browse files
Added basis for implementation of InteriorFacesCheck
parent
492d1673
Pipeline
#9796
failed with stage
in 47 seconds
Changes
7
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/check/CheckId.java
View file @
22fce970
...
...
@@ -37,6 +37,7 @@ public class CheckId implements Serializable {
public
static
final
CheckId
C_GE_R_NULL_AREA
=
new
CheckId
(
"C_GE_R_NULL_AREA"
);
public
static
final
CheckId
C_GE_S_NON_MANIFOLD_EDGE
=
new
CheckId
(
"C_GE_S_NON_MANIFOLD_EDGE"
);
public
static
final
CheckId
C_GE_S_POLYGON_WRONG_ORIENTATION
=
new
CheckId
(
"C_GE_S_POLYGON_WRONG_ORIENTATION"
);
public
static
final
CheckId
C_GE_S_INTERIOR_FACE
=
new
CheckId
(
"C_GE_S_INTERIOR_FACE"
);
public
static
final
CheckId
C_GE_S_ALL_POLYGONS_WRONG_ORIENTATION
=
new
CheckId
(
"C_GE_S_ALL_POLYGONS_WRONG_ORIENTATION"
);
public
static
final
CheckId
C_GE_S_NON_MANIFOLD_VERTEX
=
new
CheckId
(
"C_GE_S_NON_MANIFOLD_VERTEX"
);
...
...
CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/check/ErrorId.java
View file @
22fce970
...
...
@@ -47,6 +47,7 @@ public class ErrorId implements Serializable {
public
static
final
ErrorId
GE_R_NULL_AREA
=
new
ErrorId
(
"GE_R_NULL_AREA"
);
public
static
final
ErrorId
GE_R_TOO_FEW_POINTS
=
new
ErrorId
(
"GE_R_TOO_FEW_POINTS"
);
public
static
final
ErrorId
GE_S_NON_MANIFOLD_EDGE
=
new
ErrorId
(
"GE_S_NON_MANIFOLD_EDGE"
);
public
static
final
ErrorId
GE_S_INTERIOR_FACE
=
new
ErrorId
(
"GE_S_INTERIOR_FACE"
);
public
static
final
ErrorId
GE_P_NON_PLANAR_POLYGON_NORMALS_DEVIATION
=
new
ErrorId
(
"GE_P_NON_PLANAR_POLYGON_NORMALS_DEVIATION"
);
public
static
final
ErrorId
GE_P_NON_PLANAR_POLYGON_DISTANCE_PLANE
=
new
ErrorId
(
...
...
CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/check/Requirement.java
View file @
22fce970
...
...
@@ -47,6 +47,7 @@ public class Requirement implements Serializable {
public
static
final
Requirement
R_GE_P_INNER_RINGS_NESTED
=
new
Requirement
(
"R_GE_P_INNER_RINGS_NESTED"
,
RequirementType
.
GEOMETRY
);
public
static
final
Requirement
R_GE_S_TOO_FEW_POLYGONS
=
new
Requirement
(
"R_GE_S_TOO_FEW_POLYGONS"
,
RequirementType
.
GEOMETRY
);
public
static
final
Requirement
R_GE_S_NOT_CLOSED
=
new
Requirement
(
"R_GE_S_NOT_CLOSED"
,
RequirementType
.
GEOMETRY
);
public
static
final
Requirement
R_GE_S_INTERIOR_FACE
=
new
Requirement
(
"R_GE_S_INTERIOR_FACE"
,
RequirementType
.
GEOMETRY
);
public
static
final
Requirement
R_GE_S_NON_MANIFOLD_EDGE
=
new
Requirement
(
"R_GE_S_NON_MANIFOLD_EDGE"
,
RequirementType
.
GEOMETRY
);
public
static
final
Requirement
R_GE_S_POLYGON_WRONG_ORIENTATION
=
new
Requirement
(
"R_GE_S_POLYGON_WRONG_ORIENTATION"
,
RequirementType
.
GEOMETRY
);
...
...
CityDoctorParent/CityDoctorModel/src/main/java/de/hft/stuttgart/citydoctor2/check/error/InteriorFaceError.java
0 → 100644
View file @
22fce970
package
de.hft.stuttgart.citydoctor2.check.error
;
import
java.util.List
;
import
de.hft.stuttgart.citydoctor2.check.CheckError
;
import
de.hft.stuttgart.citydoctor2.check.ErrorId
;
import
de.hft.stuttgart.citydoctor2.check.ErrorReport
;
import
de.hft.stuttgart.citydoctor2.check.ErrorType
;
import
de.hft.stuttgart.citydoctor2.check.ErrorVisitor
;
import
de.hft.stuttgart.citydoctor2.check.HealingMethod
;
import
de.hft.stuttgart.citydoctor2.check.ModificationListener
;
import
de.hft.stuttgart.citydoctor2.datastructure.Geometry
;
import
de.hft.stuttgart.citydoctor2.datastructure.GmlElement
;
import
de.hft.stuttgart.citydoctor2.datastructure.Polygon
;
/**
* If a polygon is fully inside a solid geometry this error is created.
*
* @author Alexander Riegel
*/
public
class
InteriorFaceError
implements
CheckError
{
private
static
final
long
serialVersionUID
=
6633158315015689806L
;
private
List
<
Polygon
>
polygons
;
private
Geometry
geom
;
public
InteriorFaceError
(
Geometry
geom
,
List
<
Polygon
>
polygons
)
{
super
();
this
.
polygons
=
polygons
;
this
.
geom
=
geom
;
}
public
Geometry
getGeometry
()
{
return
geom
;
}
public
List
<
Polygon
>
getPolygons
(){
return
polygons
;
}
@Override
public
ErrorType
getType
()
{
return
ErrorType
.
ERROR
;
}
@Override
public
ErrorId
getErrorId
()
{
return
ErrorId
.
GE_S_INTERIOR_FACE
;
}
@Override
public
GmlElement
getFeature
()
{
return
getGeometry
();
}
@Override
public
void
accept
(
ErrorVisitor
errorVisitor
)
{
errorVisitor
.
visit
(
this
);
}
public
String
toString
()
{
return
"InteriorFaceError [Polygons="
+
polygons
+
", geom="
+
geom
+
"]"
;
}
@Override
public
boolean
accept
(
HealingMethod
method
,
ModificationListener
l
)
{
return
method
.
visit
(
this
,
l
);
}
@Override
public
void
report
(
ErrorReport
report
)
{
report
.
add
(
geom
);
polygons
.
forEach
(
x
->
report
.
add
(
x
));
}
}
CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/checks/Checks.java
View file @
22fce970
...
...
@@ -34,6 +34,7 @@ import de.hft.stuttgart.citydoctor2.checks.geometry.AllPolygonsWrongOrientationC
import
de.hft.stuttgart.citydoctor2.checks.geometry.DuplicatePointsCheck
;
import
de.hft.stuttgart.citydoctor2.checks.geometry.HoleOutsideCheck
;
import
de.hft.stuttgart.citydoctor2.checks.geometry.InteriorDisconnectedCheck
;
import
de.hft.stuttgart.citydoctor2.checks.geometry.InteriorFacesCheck
;
import
de.hft.stuttgart.citydoctor2.checks.geometry.ManifoldVertexCheck
;
import
de.hft.stuttgart.citydoctor2.checks.geometry.MultipleConnectedComponentCheck
;
import
de.hft.stuttgart.citydoctor2.checks.geometry.NestedRingsCheck
;
...
...
@@ -102,6 +103,7 @@ public class Checks {
publish
(
new
PolygonWrongOrientationCheck
());
publish
(
new
AllPolygonsWrongOrientationCheck
());
publish
(
new
TooFewPolygonsCheck
());
publish
(
new
InteriorFacesCheck
());
publish
(
new
ManifoldVertexCheck
());
publish
(
new
SolidSelfIntCheck
());
...
...
CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/checks/geometry/InteriorFacesCheck.java
0 → 100644
View file @
22fce970
package
de.hft.stuttgart.citydoctor2.checks.geometry
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.List
;
import
java.util.Set
;
import
de.hft.stuttgart.citydoctor2.check.Check
;
import
de.hft.stuttgart.citydoctor2.check.CheckId
;
import
de.hft.stuttgart.citydoctor2.check.Requirement
;
import
de.hft.stuttgart.citydoctor2.check.RequirementType
;
import
de.hft.stuttgart.citydoctor2.checks.util.CollectionUtils
;
import
de.hft.stuttgart.citydoctor2.datastructure.Geometry
;
import
de.hft.stuttgart.citydoctor2.datastructure.GeometryType
;
/**
* This class checks if a solid geometry has polygons that are fully enclosed inside the boundary surfaces.
*
* @author Alexander Riegel
*/
public
class
InteriorFacesCheck
extends
Check
{
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
);
deps
.
add
(
CheckId
.
C_GE_R_SELF_INTERSECTION
);
deps
.
add
(
CheckId
.
C_GE_P_INTERIOR_DISCONNECTED
);
deps
.
add
(
CheckId
.
C_GE_P_INTERSECTING_RINGS
);
deps
.
add
(
CheckId
.
C_GE_P_NON_PLANAR
);
deps
.
add
(
CheckId
.
C_GE_S_TOO_FEW_POLYGONS
);
dependencies
=
Collections
.
unmodifiableList
(
deps
);
}
@Override
public
void
check
(
Geometry
g
)
{
// only check solids
if
(
g
.
getType
()
!=
GeometryType
.
SOLID
)
{
return
;
}
// TODO: Implement check logic
// Assuming geometry is well defined (no holes or dangling polygons).
// Check should run just before the ManifoldEdgesCheck
// Step 1:
// Check pairs of polygons for their distance
// if they are too closely together (within EPSILON) add them to confirmed set
// Step 2:
// get centroid of each polygon and move it EPSILON * normalized polygon normal vector
// if that point is inside the solid's geometry, add polygon to confirmed set
// Step 3:
// Use intersections of the polygon normal vector(raycast from centroid)
// with other polygons to establish a list of suspects.
// Check all found suspects for number of intersections.
// Use intersection count to eliminate wrongly suspected polygons
// After sorting in ascending number of intersections:
// 0 intersections are safe to remove from suspects (safe)
// 1 intersection is guaranteed to be an interior face (confirmed)
// Move these polygons into their respective sets
// Intersection counts >= 2 require more analysis,
// using dot product of the normalized polygon normal vectors.
// Count the number of positive (same face direction) and negative (opposite face directions) dot products.
// If the intersected polygon is in the confirmed set, ignore them
// If positive count = negative count, move into preliminary safe set
//
}
@Override
public
Set
<
Requirement
>
appliesToRequirements
()
{
return
CollectionUtils
.
singletonSet
(
Requirement
.
R_GE_S_INTERIOR_FACE
);
}
@Override
public
List
<
CheckId
>
getDependencies
()
{
return
dependencies
;
}
@Override
public
RequirementType
getType
()
{
return
RequirementType
.
GEOMETRY
;
}
@Override
public
Check
createNewInstance
()
{
return
new
InteriorFacesCheck
();
}
@Override
public
CheckId
getCheckId
()
{
return
CheckId
.
C_GE_S_INTERIOR_FACE
;
}
}
CityDoctorParent/CityDoctorValidation/src/test/java/de/hft/stuttgart/citydoctor2/checks/geometry/InteriorFacesCheckTest.java
0 → 100644
View file @
22fce970
package
de.hft.stuttgart.citydoctor2.checks.geometry
;
import
static
org
.
junit
.
Assert
.
assertTrue
;
import
java.util.List
;
import
org.junit.Before
;
import
org.junit.Test
;
import
de.hft.stuttgart.citydoctor2.check.CheckError
;
import
de.hft.stuttgart.citydoctor2.check.CheckResult
;
import
de.hft.stuttgart.citydoctor2.check.ErrorId
;
import
de.hft.stuttgart.citydoctor2.check.ResultStatus
;
import
de.hft.stuttgart.citydoctor2.check.error.InteriorFaceError
;
import
de.hft.stuttgart.citydoctor2.datastructure.Geometry
;
import
de.hft.stuttgart.citydoctor2.datastructure.Polygon
;
import
de.hft.stuttgart.citydoctor2.datastructure.Vertex
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertFalse
;
import
static
org
.
junit
.
Assert
.
assertNotNull
;
import
static
de
.
hft
.
stuttgart
.
citydoctor2
.
checks
.
util
.
GeometryTestUtils
.
createGoodGeometry
;
import
static
de
.
hft
.
stuttgart
.
citydoctor2
.
checks
.
util
.
GeometryTestUtils
.
createVertex
;
import
static
de
.
hft
.
stuttgart
.
citydoctor2
.
checks
.
util
.
GeometryTestUtils
.
addPolygon
;
public
class
InteriorFacesCheckTest
{
Geometry
geom
;
@Before
public
void
setup
()
{
geom
=
createGoodGeometry
();
}
@Test
public
void
testGoodGeometry
()
{
InteriorFacesCheck
check
=
new
InteriorFacesCheck
();
check
.
check
(
geom
);
CheckResult
cr
=
geom
.
getCheckResult
(
check
);
assertNotNull
(
"Check result must not be null"
,
cr
);
assertEquals
(
"Good geometry must return OK check result"
,
ResultStatus
.
OK
,
cr
.
getResultStatus
());
}
@Test
public
void
testSimpleGeometryWithInteriorFace
()
{
Vertex
v0
=
createVertex
(
5
,
0
,
0
,
geom
);
Vertex
v1
=
createVertex
(
5
,
0
,
10
,
geom
);
Vertex
v2
=
createVertex
(
5
,
10
,
10
,
geom
);
Vertex
v3
=
createVertex
(
5
,
10
,
0
,
geom
);
Polygon
insertedInteriorFace
=
addPolygon
(
geom
,
v0
,
v1
,
v2
,
v3
);
geom
.
updateEdgesAndVertices
();
InteriorFacesCheck
check
=
new
InteriorFacesCheck
();
check
.
check
(
geom
);
CheckResult
cr
=
geom
.
getCheckResult
(
check
);
assertNotNull
(
cr
);
assertEquals
(
"Check should have detected an error"
,
ResultStatus
.
ERROR
,
cr
.
getResultStatus
());
assertEquals
(
"ID of found Error should be GE_S_INTERIOR_FACE"
,
ErrorId
.
GE_S_INTERIOR_FACE
,
cr
.
getError
().
getErrorId
());
CheckError
foundError
=
cr
.
getError
();
assertTrue
(
"Check should have returned a InteriorFaceError"
,
foundError
instanceof
InteriorFaceError
);
List
<
Polygon
>
interiorFaces
=
((
InteriorFaceError
)
foundError
).
getPolygons
();
assertNotNull
(
interiorFaces
);
assertTrue
(
"InteriorFaces should have a single entry"
,
interiorFaces
.
size
()
==
1
);
Polygon
foundInteriorFace
=
interiorFaces
.
getFirst
();
assertEquals
(
"Found interior face should be the inserted polygon"
,
insertedInteriorFace
,
foundInteriorFace
);
}
}
Riegel
@22rial1mpg
mentioned in commit
216ab18a
·
Jul 12, 2024
mentioned in commit
216ab18a
mentioned in commit 216ab18abfcaf32a62ba7a2063ba16eaf55c04e4
Toggle commit list
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