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
ffdae21a
Commit
ffdae21a
authored
Jul 31, 2024
by
Riegel
Browse files
Open Source release of CityDoctor GUI
parent
a5a82382
Pipeline
#10029
failed with stage
in 8 seconds
Changes
249
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
CityDoctorParent/CityDoctorHealer/src/assembly/streamingStandardConfig.yml
0 → 100644
View file @
ffdae21a
requirements
:
R_GE_R_TOO_FEW_POINTS
:
enabled
:
true
R_GE_R_NOT_CLOSED
:
enabled
:
true
R_GE_R_CONSECUTIVE_POINTS_SAME
:
enabled
:
true
R_GE_R_SELF_INTERSECTION
:
enabled
:
true
R_GE_S_MULTIPLE_CONNECTED_COMPONENTS
:
enabled
:
true
R_GE_P_INTERIOR_DISCONNECTED
:
enabled
:
true
R_GE_P_INTERSECTING_RINGS
:
enabled
:
true
R_GE_P_NON_PLANAR
:
enabled
:
true
parameters
:
# one of ("distance", "angle", "both")
type
:
distance
# in m
distanceTolerance
:
0.01
# in degree
angleTolerance
:
1
R_GE_P_HOLE_OUTSIDE
:
enabled
:
true
R_GE_P_ORIENTATION_RINGS_SAME
:
enabled
:
true
R_GE_P_INNER_RINGS_NESTED
:
enabled
:
true
R_GE_S_TOO_FEW_POLYGONS
:
enabled
:
true
R_GE_S_NOT_CLOSED
:
enabled
:
true
R_GE_S_NON_MANIFOLD_EDGE
:
enabled
:
true
R_GE_S_POLYGON_WRONG_ORIENTATION
:
enabled
:
true
R_GE_S_ALL_POLYGONS_WRONG_ORIENTATION
:
enabled
:
true
R_GE_S_NON_MANIFOLD_VERTEX
:
enabled
:
true
R_GE_S_SELF_INTERSECTION
:
enabled
:
true
R_SE_BS_IS_WALL
:
enabled
:
false
parameters
:
lowerAngle
:
'
45'
upperAngle
:
'
135'
R_SE_BS_IS_FLOOR
:
enabled
:
false
R_SE_BS_GROUND_UNFRAGMENTED
:
enabled
:
false
R_SE_BS_IS_GROUND
:
enabled
:
false
R_SE_BS_IS_CEILING
:
enabled
:
false
globalParameters
:
numberOfRoundingPlaces
:
8
# in m
minVertexDistance
:
0.0001
schematronPath
:
'
checkForSolid.xml'
useStreaming
:
true
xmlValidation
:
false
CityDoctorParent/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/CppInitializer.java
0 → 100644
View file @
ffdae21a
/** --------------------------------------------------
* Hochschule f�r Technik Stuttgart
* Fachbereich Vermessung , Informatik und Mathematik
* Schellingstr . 24
* D - 70174 Stuttgart
*
* Projekt CityDoktor
*
* Copyright (c) 2011 HFT Stuttgart. All rights reserved.
* HFT Stuttgart and its licensors retain all intellectual property and
* proprietary rights in and to this software and related documentation.
* Any use, reproduction, disclosure, or distribution of this software
* and related documentation without an express license agreement from
* HFT Stuttgart is strictly prohibited.
*
* Please refer to the applicable HFT Stuttgart end user license agreement (EULA)
* associated with this source code for terms and conditions that govern
* your use of this HFT Stuttgart software.
*
* 11.09.2012
* bogdahn
* @author
* @version
*
*/
package
de.hft.stuttgart.citydoctor2
;
import
org.apache.logging.log4j.LogManager
;
import
org.apache.logging.log4j.Logger
;
import
de.hft.stuttgart.citydoctor2.connect.edge.NativeException
;
/**
* @author bogdahn
*
*/
public
class
CppInitializer
{
private
static
final
String
SUN_ARCH_DATA_MODEL
=
"sun.arch.data.model"
;
private
static
Logger
logger
=
LogManager
.
getLogger
(
CppInitializer
.
class
);
private
static
native
boolean
initCppLibrary
()
throws
NativeException
;
private
static
native
boolean
checkVersions
(
String
jdkVersion
)
throws
NativeException
;
public
static
synchronized
void
initCpp
()
{
// init CPP JNI Checks
String
dataModel
=
System
.
getProperty
(
SUN_ARCH_DATA_MODEL
);
if
(
dataModel
.
equals
(
"64"
))
{
// System.loadLibrary( "CityDoctor2CPP-windows-x64-sgd" ); // debug dll
System
.
loadLibrary
(
"../CityDoctorHealer/lib/CityDoctor2CPP-windows-x64-s"
);
// System.loadLibrary("CityDoctor2CPP-windows-x64-s");
// System.loadLibrary("lib/libTestHeal");
}
else
if
(
dataModel
.
equals
(
"32"
))
{
// System.loadLibrary( "CityDoctor2CPP-windows-x86-sgd" ); // debug dll
// System.loadLibrary("../CityDoctorHealer/lib/CityDoctor2CPP-windows-x86-s");
// System.loadLibrary("CityDoctor2CPP-windows-x86-s");
System
.
err
.
println
(
"Load native library failed."
);
System
.
err
.
println
(
"Unknown architecture: "
+
dataModel
);
System
.
err
.
println
(
"Valid values are: \"64\""
);
System
.
err
.
println
(
"No library will be loaded"
);
}
else
{
System
.
err
.
println
(
"Load native library failed."
);
System
.
err
.
println
(
"Unknown architecture: "
+
dataModel
);
System
.
err
.
println
(
"Valid values are: \"64\""
);
System
.
err
.
println
(
"No library will be loaded"
);
}
try
{
if
(
initCppLibrary
())
{
// checkVersions(System.getProperty("java.version")); // TODO : checkVersions
// funktioniert noch nicht!!
}
}
catch
(
NativeException
ne
)
{
System
.
err
.
println
(
"Native Exception"
);
System
.
err
.
println
(
ne
.
getType
());
System
.
err
.
println
(
ne
.
getMessage
());
ne
.
printStackTrace
();
System
.
exit
(
1
);
}
catch
(
IllegalArgumentException
e
)
{
e
.
printStackTrace
();
System
.
exit
(
1
);
}
}
private
CppInitializer
()
{
// only static utility
}
}
CityDoctorParent/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/connect/edge/CppFeature.java
0 → 100644
View file @
ffdae21a
package
de.hft.stuttgart.citydoctor2.connect.edge
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
de.hft.stuttgart.citydoctor2.datastructure.BoundarySurface
;
import
de.hft.stuttgart.citydoctor2.datastructure.Geometry
;
import
de.hft.stuttgart.citydoctor2.datastructure.LinearRing
;
import
de.hft.stuttgart.citydoctor2.datastructure.Lod
;
import
de.hft.stuttgart.citydoctor2.datastructure.Polygon
;
import
de.hft.stuttgart.citydoctor2.datastructure.Vertex
;
/**
* @author wewetzer
* @version 1.0
*/
public
class
CppFeature
extends
CppReferenceHandlingBase
{
private
native
long
createCppFeature
(
String
type
)
throws
OutOfMemoryError
;
private
native
void
disposeCppFeature
(
long
ptrToCppFeature
)
throws
NativePointerCastException
;
// setting geometry and attributes
private
native
boolean
setGeometry
(
long
ptrToFeature
,
int
geomType
,
double
[]
pointArray
,
int
[]
pointIdMap
,
int
[]
polygonArray
,
int
[]
polygonIdMap
)
throws
NativeException
;
private
native
boolean
setLoD
(
long
ptrToFeature
,
int
LoD
)
throws
NativeException
;
// gets the id of a corresponding C++ entity to a given Java entity id
private
native
int
getCppPointId
(
long
ptrToFeature
,
int
javaPointId
)
throws
NativeException
;
private
native
int
getCppPolygonId
(
long
ptrToFeature
,
int
javaPolygonId
)
throws
NativeException
;
private
native
double
[]
getPoints
(
long
ptrToFeature
)
throws
NativeException
;
// debug native methods
private
native
void
printMesh
(
long
ptrToFeature
)
throws
NativeException
;
private
native
void
writeMeshToInventor
(
long
ptrToFeature
,
String
fileName
)
throws
NativeException
;
private
String
type
;
public
CppFeature
(
String
type
)
{
this
.
type
=
type
;
createCppObject
();
}
/**
* Creates an C++ feature object
*
* @throws IllegalStateException Thrown if the encapsulated "long-Pointer"
* isn't 0
* @throws NativeOutOfMemoryException If there is no more memory on the native
* side
*
* @see {@link disposeCppObject}
* @see de.hft.stuttgart.citydoctor2.connect.edge.CppReferenceHandlingBase#createCppObject()
*/
private
void
createCppObject
()
{
if
(
0L
!=
ptrToCppObject
)
{
throw
new
IllegalStateException
(
"Can't create new C++ object, there is already one!"
);
}
// Maybe an exception is thrown
ptrToCppObject
=
createCppFeature
(
type
);
}
@Override
public
void
disposeCppObject
()
throws
NativePointerCastException
{
if
(
0L
!=
ptrToCppObject
)
{
disposeCppFeature
(
ptrToCppObject
);
ptrToCppObject
=
0L
;
}
}
public
void
setGeometry
(
Geometry
geometry
)
throws
NativeException
{
checkNullPointer
();
CppGeometryData
geometryData
=
createCppFeatureInput
(
geometry
);
setGeometry
(
ptrToCppObject
,
0
,
geometryData
.
pointArr
,
geometryData
.
pointIdMap
,
geometryData
.
polygonArr
,
geometryData
.
polygonIdMap
);
}
public
void
setLoD
(
Lod
lod
)
throws
NativeException
{
checkNullPointer
();
int
LoD
=
-
1
;
if
(
lod
==
Lod
.
LOD0
)
{
LoD
=
0
;
}
else
if
(
lod
==
Lod
.
LOD1
)
{
LoD
=
1
;
}
else
if
(
lod
==
Lod
.
LOD2
)
{
LoD
=
2
;
}
else
if
(
lod
==
Lod
.
LOD3
)
{
LoD
=
3
;
}
else
if
(
lod
==
Lod
.
LOD4
)
{
LoD
=
4
;
}
setLoD
(
ptrToCppObject
,
LoD
);
}
/**
* Returns the id of the corresponding C++ point to a given Java point id
*
* @param javaPointId The given Java point id
* @return The corresponding C++ point id
* @throws IllegalArgumentException If the feature pointer is 0
* @throws NativeException If an error occurred during the execution of
* the native code
*/
public
int
getCppPointId
(
int
javaPointId
)
throws
NativeException
{
checkNullPointer
();
return
this
.
getCppPointId
(
ptrToCppObject
,
javaPointId
);
}
/**
* Returns the id of the corresponding C++ polygon to a given java polygon
* id
*
* @param javaPolygonId The given Java polygon id
* @return The corresponding C++ polygon id
* @throws IllegalArgumentException If the feature pointer is 0
* @throws NativeException If an error occurred during the execution of
* the native code
*/
public
int
getCppPolygonId
(
int
javaPolygonId
)
throws
NativeException
{
checkNullPointer
();
return
this
.
getCppPolygonId
(
ptrToCppObject
,
javaPolygonId
);
}
public
double
[]
getPoints
()
throws
NativeException
{
checkNullPointer
();
return
this
.
getPoints
(
ptrToCppObject
);
}
/**
* Debug method, that prints the mesh
*
* @throws IllegalArgumentException If the feature pointer is 0
* @throws NativeException If an error occurred during the execution of
* the native code
*/
public
void
printMesh
()
throws
NativeException
{
checkNullPointer
();
this
.
printMesh
(
ptrToCppObject
);
}
/**
* Writes the current stored level of detail 1 mesh in the file "filename.iv" as
* Open Inventor file.
*
* @param fileName The name of the output file
* @throws IllegalArgumentException If the feature pointer is 0
* @throws NativeException If an error occurred during the execution of
* the native code n
*/
public
void
writeMeshToInventor
(
String
fileName
)
throws
NativeException
{
checkNullPointer
();
this
.
writeMeshToInventor
(
ptrToCppObject
,
fileName
);
}
/**
* Writes the current stored level of detail 2 mesh in the file "filename.iv" as
* Open Inventor file.
*
* @param fileName The name of the output file
* @throws IllegalArgumentException If the feature pointer is 0
* @throws NativeException If an error occurred during the execution of
* the native code n
*/
private
void
printGeomDataAsCppCode
(
CppGeometryData
cppGeoData
)
{
System
.
out
.
println
(
"\n \n \n"
);
double
[]
pnts
=
cppGeoData
.
pointArr
;
System
.
out
.
println
(
"const size_t numCoords = "
+
pnts
.
length
/
3
+
";"
);
System
.
out
.
println
(
"Coordinate3d * coords["
+
pnts
.
length
/
3
+
"];"
);
for
(
int
i
=
0
;
i
<
pnts
.
length
;
i
+=
3
)
{
System
.
out
.
print
(
"coords[ "
+
i
/
3
+
" ] = new Coordinate3d( "
);
System
.
out
.
println
(
pnts
[
i
]
+
", "
+
pnts
[
i
+
1
]
+
", "
+
pnts
[
i
+
2
]
+
" );"
);
}
System
.
out
.
println
(
""
);
int
[]
polys
=
cppGeoData
.
polygonArr
;
System
.
out
.
println
(
"const size_t numPolys = "
+
cppGeoData
.
polygonIdMap
.
length
+
";"
);
System
.
out
.
println
(
"const size_t sizePolys = "
+
polys
.
length
+
";"
);
System
.
out
.
print
(
"int polyArr[] = {"
);
for
(
int
i
=
0
;
i
<
polys
.
length
-
1
;
++
i
)
{
if
(-
1
==
polys
[
i
])
{
System
.
out
.
println
();
System
.
out
.
print
(
" "
+
polys
[
i
]
+
", "
);
}
else
if
(-
2
==
polys
[
i
])
{
System
.
out
.
print
(
" "
+
polys
[
i
]
+
", "
);
}
else
{
System
.
out
.
print
(
" "
+
polys
[
i
]
+
", "
);
}
}
System
.
out
.
println
(
" "
+
polys
[
polys
.
length
-
1
]
+
" \n};\n"
);
if
(
cppGeoData
.
boundarySurfaceTypeArr
.
length
>
0
)
{
System
.
out
.
println
(
"BoundarySurfaceType types[numPolys] = {"
);
for
(
int
i
=
0
;
i
<
cppGeoData
.
boundarySurfaceTypeArr
.
length
;
i
++)
{
switch
(
cppGeoData
.
boundarySurfaceTypeArr
[
i
])
{
case
(
1
):
{
System
.
out
.
println
(
" roofsurface,"
);
break
;
}
case
(
2
):
{
System
.
out
.
println
(
" wallsurface,"
);
break
;
}
case
(
3
):
{
System
.
out
.
println
(
" groundsurface,"
);
break
;
}
default
:
{
System
.
out
.
println
(
" undefined,"
);
}
}
;
}
System
.
out
.
println
(
"};"
);
System
.
out
.
println
(
"return createHouse( coords, numCoords, polyArr, numPolys, sizePolys, types, true);"
);
}
}
/**
* generates all the necessary geometric input for the CppFeature
*
* @param geom
*/
private
CppGeometryData
createCppFeatureInput
(
Geometry
geometry
)
{
// ====================================================================
// Vertices
List
<
Vertex
>
vertices
=
geometry
.
getVertices
();
double
[]
pointArr
=
new
double
[
vertices
.
size
()
*
3
];
int
[]
pointIdMap
=
new
int
[
vertices
.
size
()];
Map
<
Vertex
,
Integer
>
vertexToIndexMap
=
new
HashMap
<>(
vertices
.
size
());
for
(
int
i
=
0
;
i
<
vertices
.
size
();
i
++)
{
Vertex
v
=
vertices
.
get
(
i
);
vertexToIndexMap
.
put
(
v
,
i
);
pointArr
[
i
*
3
+
0
]
=
v
.
getX
();
pointArr
[
i
*
3
+
1
]
=
v
.
getY
();
pointArr
[
i
*
3
+
2
]
=
v
.
getZ
();
pointIdMap
[
i
]
=
i
;
}
// ====================================================================
// Polygons & BoundarySurfaceType
List
<
Polygon
>
polygons
=
geometry
.
getPolygons
();
int
numReferencedVertices
=
0
;
int
[]
polygonIdMap
=
new
int
[
polygons
.
size
()];
for
(
int
i
=
0
;
i
<
polygons
.
size
();
i
++)
{
Polygon
p
=
polygons
.
get
(
i
);
polygonIdMap
[
i
]
=
i
;
numReferencedVertices
+=
p
.
getExteriorRing
().
getVertices
().
size
();
for
(
LinearRing
lr
:
p
.
getInnerRings
())
{
numReferencedVertices
+=
lr
.
getVertices
().
size
();
}
}
int
[]
polygonArr
=
new
int
[
numReferencedVertices
];
int
[]
boundarySurfaceTypeArr
=
new
int
[
polygons
.
size
()];
int
polyCounter
=
0
;
for
(
int
polyIndex
=
0
;
polyIndex
<
polygons
.
size
();
polyIndex
++)
{
Polygon
p
=
polygons
.
get
(
polyIndex
);
// exterior ring = -1
polygonArr
[
polyCounter
++]
=
-
1
;
for
(
int
i
=
0
;
i
<
p
.
getExteriorRing
().
getVertices
().
size
()
-
1
;
i
++)
{
Vertex
v
=
p
.
getExteriorRing
().
getVertices
().
get
(
i
);
int
id
=
vertexToIndexMap
.
get
(
v
);
polygonArr
[
polyCounter
++]
=
id
;
}
for
(
LinearRing
lr
:
p
.
getInnerRings
())
{
// interior ring = -2
polygonArr
[
polyCounter
++]
=
-
2
;
for
(
int
i
=
0
;
i
<
lr
.
getVertices
().
size
()
-
1
;
i
++)
{
Vertex
v
=
lr
.
getVertices
().
get
(
i
);
int
id
=
vertexToIndexMap
.
get
(
v
);
polygonArr
[
polyCounter
++]
=
id
;
}
}
if
(
geometry
.
getLod
()
==
Lod
.
LOD2
)
{
BoundarySurface
bs
=
p
.
getPartOfSurface
();
if
(
bs
!=
null
)
{
boundarySurfaceTypeArr
[
polyIndex
]
=
bs
.
getType
().
ordinal
();
}
else
{
boundarySurfaceTypeArr
[
polyIndex
]
=
999999
;
}
}
}
return
new
CppGeometryData
(
pointArr
,
pointIdMap
,
polygonArr
,
polygonIdMap
,
boundarySurfaceTypeArr
);
}
private
class
CppGeometryData
{
private
double
[]
pointArr
;
private
int
[]
pointIdMap
;
private
int
[]
polygonArr
;
private
int
[]
polygonIdMap
;
private
int
[]
boundarySurfaceTypeArr
;
private
CppGeometryData
(
double
[]
pointArr
,
int
[]
pointIdMap
,
int
[]
polygonArr
,
int
[]
polygonIdMap
,
int
[]
bfTypeArr
)
{
this
.
pointArr
=
pointArr
;
this
.
pointIdMap
=
pointIdMap
;
this
.
polygonArr
=
polygonArr
;
this
.
polygonIdMap
=
polygonIdMap
;
this
.
boundarySurfaceTypeArr
=
bfTypeArr
;
}
}
public
String
getType
()
{
return
type
;
}
}
CityDoctorParent/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/connect/edge/CppHealResult.java
0 → 100644
View file @
ffdae21a
package
de.hft.stuttgart.citydoctor2.connect.edge
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Objects
;
import
de.hft.stuttgart.citydoctor2.datastructure.ConcretePolygon
;
import
de.hft.stuttgart.citydoctor2.datastructure.Geometry
;
import
de.hft.stuttgart.citydoctor2.datastructure.LinearRing
;
import
de.hft.stuttgart.citydoctor2.datastructure.LinearRing.LinearRingType
;
import
de.hft.stuttgart.citydoctor2.datastructure.Polygon
;
import
de.hft.stuttgart.citydoctor2.datastructure.Vertex
;
public
class
CppHealResult
extends
CppReferenceHandlingBase
{
private
native
void
delete
(
long
ptr
);
private
native
int
[]
getChangedOrAddedVertexIds
(
long
ptr
);
private
native
double
[]
getChangedOrAddedVertexValues
(
long
ptr
);
private
native
int
[]
getChangedOrAddedPolygonIds
(
long
ptr
);
private
native
int
[]
getChangedOrAddedPolygon
(
long
ptr
,
int
id
);
public
CppHealResult
(
long
ptr
)
{
ptrToCppObject
=
ptr
;
}
@Override
public
void
disposeCppObject
()
{
if
(
ptrToCppObject
!=
0
)
{
delete
(
ptrToCppObject
);
ptrToCppObject
=
0
;
}
}
public
void
mergeIntoGeometry
(
Geometry
geom
)
{
Map
<
Integer
,
Vertex
>
vertexMap
=
updateVertices
(
geom
);
int
[]
changedPolygons
=
getChangedOrAddedPolygonIds
(
ptrToCppObject
);
List
<
Polygon
>
deletedPolygons
=
new
ArrayList
<>();
for
(
int
i
=
0
;
i
<
changedPolygons
.
length
;
i
++)
{
int
polyId
=
changedPolygons
[
i
];
int
[]
vertices
=
getChangedOrAddedPolygon
(
ptrToCppObject
,
polyId
);
if
(
vertices
==
null
||
vertices
.
length
==
0
)
{
if
(
polyId
>=
geom
.
getPolygons
().
size
())
{
throw
new
IllegalStateException
(
"Cannot delete a polygon which does not exist"
);
}
Polygon
p
=
geom
.
getPolygons
().
get
(
polyId
);
deletedPolygons
.
add
(
p
);
}
else
{
Polygon
p
;
if
(
polyId
<
geom
.
getPolygons
().
size
())
{
p
=
geom
.
getPolygons
().
get
(
polyId
);
// empty the polygon
p
.
removeRings
();
}
else
{
p
=
new
ConcretePolygon
();
geom
.
addPolygon
(
p
);
}
createPolygon
(
geom
,
vertexMap
,
vertices
,
p
);
}
}
for
(
Polygon
p
:
deletedPolygons
)
{
geom
.
getPolygons
().
remove
(
p
);
}
}
private
void
createPolygon
(
Geometry
geom
,
Map
<
Integer
,
Vertex
>
vertexMap
,
int
[]
vertices
,
Polygon
p
)
{
LinearRing
lr
=
null
;
for
(
int
j
=
0
;
j
<
vertices
.
length
;
j
++)
{
if
(
vertices
[
j
]
==
-
1
)
{
if
(
p
.
getExteriorRing
()
!=
null
)
{
throw
new
IllegalStateException
(
"Cannot create a polygon with more than 1 exterior rings"
);
}
lr
=
new
LinearRing
(
LinearRingType
.
EXTERIOR
);
p
.
setExteriorRing
(
lr
);
}
else
if
(
vertices
[
j
]
==
-
2
)
{
lr
=
new
LinearRing
(
LinearRingType
.
INTERIOR
);
p
.
addInteriorRing
(
lr
);
}
else
{
Objects
.
requireNonNull
(
lr
,
"No ring type specified, before supplying vertices"
);
int
index
=
vertices
[
j
];
Vertex
v
;
if
(
index
<
geom
.
getVertices
().
size
())
{
v
=
geom
.
getVertices
().
get
(
index
);
}
else
{
v
=
vertexMap
.
get
(
index
);
}
Objects
.
requireNonNull
(
v
,
"Polygon references vertex, which does not exist"
);
lr
.
addVertex
(
v
);
}
}
// close the rings
p
.
getExteriorRing
().
addVertex
(
p
.
getExteriorRing
().
getVertices
().
get
(
0
));
for
(
LinearRing
inner
:
p
.
getInnerRings
())
{
inner
.
addVertex
(
inner
.
getVertices
().
get
(
0
));
}
}
private
Map
<
Integer
,
Vertex
>
updateVertices
(
Geometry
geom
)
{
int
[]
changedVertices
=
getChangedOrAddedVertexIds
(
ptrToCppObject
);
double
[]
changedVertexValues
=
getChangedOrAddedVertexValues
(
ptrToCppObject
);
Map
<
Integer
,
Vertex
>
vertexMap
=
new
HashMap
<>();
for
(
int
i
=
0
;
i
<
changedVertices
.
length
;
i
++)
{
int
id
=
changedVertices
[
i
];
double
x
=
changedVertexValues
[
i
*
3
+
0
];
double
y
=
changedVertexValues
[
i
*
3
+
1
];
double
z
=
changedVertexValues
[
i
*
3
+
2
];
if
(
id
>=
geom
.
getVertices
().
size
())
{
// new vertex
Vertex
newV
=
new
Vertex
(
x
,
y
,
z
);
vertexMap
.
put
(
id
,
newV
);
System
.
out
.
println
(
"New Vertex: "
+
newV
);
}
else
{
// change vertex
Vertex
changedV
=
geom
.
getVertices
().
get
(
id
);
System
.
out
.
print
(
"Changed Vertex from "
+
changedV
+
" to "
);
changedV
.
setX
(
x
);
changedV
.
setY
(
y
);
changedV
.
setZ
(
z
);
System
.
out
.
println
(
changedV
);
}
}
return
vertexMap
;
}
public
void
print
()
{
int
[]
changedVertices
=
getChangedOrAddedVertexIds
(
ptrToCppObject
);
System
.
out
.
println
(
"Changed or added vertex ids: "
+
Arrays
.
toString
(
changedVertices
));
double
[]
changedVertexValues
=
getChangedOrAddedVertexValues
(
ptrToCppObject
);
if
(
changedVertices
.
length
*
3
!=
changedVertexValues
.
length
)
{
throw
new
IllegalStateException
(
"Number of indices and number of values do not match"
);
}
for
(
int
i
=
0
;
i
<
changedVertices
.
length
;
i
++)
{
System
.
out
.
println
(
String
.
format
(
"Vertex %d = [%f, %f, %f]"
,
changedVertices
[
i
],
changedVertexValues
[
i
*
3
+
0
],
changedVertexValues
[
i
*
3
+
1
],
changedVertexValues
[
i
*
3
+
2
]));
}
System
.
out
.
println
();
int
[]
changedPolygons
=
getChangedOrAddedPolygonIds
(
ptrToCppObject
);
System
.
out
.
println
(
"Changed or added polygon ids: "
+
Arrays
.
toString
(
changedPolygons
));
for
(
int
i
=
0
;
i
<
changedPolygons
.
length
;
i
++)
{
int
polyId
=
changedPolygons
[
i
];
System
.
out
.
println
(
"Polygon "
+
polyId
+
":"
);
int
[]
vertices
=
getChangedOrAddedPolygon
(
ptrToCppObject
,
polyId
);
if
(
vertices
==
null
||
vertices
.
length
==
0
)
{
System
.
out
.
println
(
"deleted"
);
}
else
{
for
(
int
j
=
0
;
j
<
vertices
.
length
;
j
++)
{
if
(
vertices
[
j
]
==
-
1
)
{
System
.
out
.
println
(
"Exterior ring:"
);
}
else
if
(
vertices
[
j
]
==
-
2
)
{
System
.
out
.
println
(
"Interior ring:"
);
}
else
{
System
.
out
.
println
(
vertices
[
j
]);
}
}
}
}
}
public
boolean
isEmpty
()
{
int
[]
changedVertices
=
getChangedOrAddedVertexIds
(
ptrToCppObject
);
int
[]
changedPolygons
=
getChangedOrAddedPolygonIds
(
ptrToCppObject
);
if
(
changedVertices
.
length
==
0
&&
changedPolygons
.
length
==
0
)
return
true
;
return
false
;
}
}
CityDoctorParent/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/connect/edge/CppHealing.java
0 → 100644
View file @
ffdae21a
package
de.hft.stuttgart.citydoctor2.connect.edge
;
public
abstract
class
CppHealing
extends
CppReferenceHandlingBase
{
// Checks will operate on this VPDFeature
CppFeature
feature
;
public
CppHealing
(
CppFeature
feature
)
{
this
.
feature
=
feature
;
}
public
CppFeature
getNestedFeature
()
{
return
feature
;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#equals(java.lang.Object)
*/
//*************************************************************************************
// vorerst auskommentiert, da CppChecks nicht mehr verwendet wird
// @Override
// public boolean equals(Object obj)
// {
// if (obj instanceof CppChecks)
// {
// return (super.equals(obj) && (feature == ((CppChecks)obj).feature));
// }
// else
// {
// return super.equals(obj);
// }
// }
//**************************************************************************************
/*
* (non-Javadoc)
*
* @see java.lang.Object#hashCode()
*/
@Override
public
int
hashCode
()
{
int
hash
=
super
.
hashCode
();
hash
=
hash
*
19
+
feature
.
hashCode
()
*
3
;
return
hash
;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public
String
toString
()
{
StringBuffer
sf
=
new
StringBuffer
();
sf
.
append
(
super
.
toString
());
sf
.
append
(
"Feature:\n\t"
);
sf
.
append
(
feature
);
return
sf
.
toString
();
}
}
\ No newline at end of file
CityDoctorParent/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/connect/edge/CppHealingResultChangeType.java
0 → 100644
View file @
ffdae21a
package
de.hft.stuttgart.citydoctor2.connect.edge
;
public
enum
CppHealingResultChangeType
{
ADD
,
DELETE
,
CHANGE
,
REPLACE
}
CityDoctorParent/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/connect/edge/CppHealingResultType.java
0 → 100644
View file @
ffdae21a
package
de.hft.stuttgart.citydoctor2.connect.edge
;
public
enum
CppHealingResultType
{
VERTEX
,
POLYGON
,
EDGE
}
CityDoctorParent/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/connect/edge/CppPolygonHealing.java
0 → 100644
View file @
ffdae21a
package
de.hft.stuttgart.citydoctor2.connect.edge
;
// im alten CD:
//
public
class
CppPolygonHealing
extends
CppHealing
{
// ----- native methods
// create and release stored C++ polygon check object
private
native
long
createCppPolygonHealing
(
long
ptrToCppFeature
)
throws
OutOfMemoryError
;
private
native
void
disposeCppPolygonHealing
(
long
ptrToCppFeature
)
throws
NativePointerCastException
;
// healing
private
native
long
healPlanarity
(
long
ptrToCppFeature
,
int
[]
polyIds
)
throws
NativeException
,
IllegalArgumentException
;
private
native
long
healSolidNotClosed
(
long
ptrToCppFeature
)
throws
NativeException
,
IllegalArgumentException
;
public
CppPolygonHealing
(
CppFeature
feature
)
{
super
(
feature
);
}
/**
* Creates an C++ object to use the native solid check methods.
*
* @throws IllegalStateException Thrown if the encapsulated "long-Pointer" isn't
* 0
* @throws OutOfMemoryError If there is no more memory on the native side
*
* @see {@link disposeCppObject}
* @see de.hft.stuttgart.citydoctor.connect.edGe.CppReferenceHandlingBase#createCppObject()
*/
public
void
createCppObject
()
throws
IllegalStateException
,
OutOfMemoryError
{
if
(
0L
!=
ptrToCppObject
)
{
throw
new
IllegalStateException
(
"Can't create new C++ object, there is allready one!"
);
}
// Maybe an exception is thrown and there should be no crap in ptrToCppObject
long
tmpPointer
=
createCppPolygonHealing
(
feature
.
ptrToCppObject
);
ptrToCppObject
=
tmpPointer
;
}
@Override
public
void
disposeCppObject
()
throws
NativePointerCastException
{
if
(
0L
!=
ptrToCppObject
)
{
disposeCppPolygonHealing
(
this
.
ptrToCppObject
);
ptrToCppObject
=
0L
;
}
}
public
CppHealResult
healPlanarity
(
int
[]
polyIds
)
throws
NativeException
,
IllegalArgumentException
{
checkNullPointer
();
return
new
CppHealResult
(
healPlanarity
(
this
.
feature
.
ptrToCppObject
,
polyIds
));
}
public
CppHealResult
healSolidNotClosed
()
throws
NativeException
,
IllegalArgumentException
{
checkNullPointer
();
return
new
CppHealResult
(
healSolidNotClosed
(
this
.
feature
.
ptrToCppObject
));
}
}
CityDoctorParent/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/connect/edge/CppReferenceHandlingBase.java
0 → 100644
View file @
ffdae21a
package
de.hft.stuttgart.citydoctor2.connect.edge
;
/**
* This class is part of the JNI interface which controls the access to the
* check- and heal kernel in native C++ code.<br>
* It's represent a base class for classes which encapsulates a C++ object.
* Therefor two abstract methods {@link createCppObject} and
* {@link disposeCppObject} are defined, to create and dispose a C++ object. All
* non-abstract subclasses are requested to implement at least the two native
* methods<br>
* <br>
* <code>
* native long create[MeaningfulName](long ptrToCppFeature);<br>
* native void dispose[MeaningfulName](long ptrToCppPolygonCheck);
* </code><br>
* <br>
*
* @author wewetzer
* @version 1.0
*
*/
public
abstract
class
CppReferenceHandlingBase
{
// This long holds the address of an C++ object
long
ptrToCppObject
=
0L
;
/**
* This method frees the occupied memory of the created C++ object. The method
* should be called after the instance of an child class is nor longer needed,
* to avoid memory leaks.
*
* @see {@link createCppObject}
*/
public
abstract
void
disposeCppObject
();
/**
* Checks if the pointer to the corresponding C++ object is 0. In this case an
* exception is thrown. This method should be called at first in every method,
* that uses native methods!
*
* @throws IllegalArgumentException if the pointer to the corresponding C++
* object i 0
*/
public
void
checkNullPointer
()
{
if
(
0L
==
ptrToCppObject
)
{
throw
new
IllegalArgumentException
(
"C++ object pointer is null"
);
}
}
@Override
public
boolean
equals
(
Object
obj
)
{
if
(
this
==
obj
)
{
return
true
;
}
if
(
obj
==
null
)
{
return
false
;
}
if
(
getClass
()
!=
obj
.
getClass
())
{
return
false
;
}
CppReferenceHandlingBase
other
=
(
CppReferenceHandlingBase
)
obj
;
return
ptrToCppObject
==
other
.
ptrToCppObject
;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#finalize()
*/
@Override
protected
void
finalize
()
throws
Throwable
{
if
(
0L
!=
ptrToCppObject
)
{
disposeCppObject
();
}
}
@Override
public
int
hashCode
()
{
final
int
prime
=
31
;
int
result
=
1
;
result
=
prime
*
result
+
(
int
)
(
ptrToCppObject
^
(
ptrToCppObject
>>>
32
));
return
result
;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public
String
toString
()
{
return
(
"ptrToCppObject\n\t"
+
ptrToCppObject
+
"\n"
);
}
}
CityDoctorParent/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/connect/edge/CppTestHeal.java
0 → 100644
View file @
ffdae21a
package
de.hft.stuttgart.citydoctor2.connect.edge
;
public
class
CppTestHeal
{
private
CppTestHeal
()
{
// only static usage
}
private
static
native
long
healGeometry
(
long
ptrToCppFeature
);
public
static
CppHealResult
healGeometry
(
CppFeature
feature
)
{
return
new
CppHealResult
(
healGeometry
(
feature
.
ptrToCppObject
));
}
}
CityDoctorParent/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/connect/edge/NativeException.java
0 → 100644
View file @
ffdae21a
package
de.hft.stuttgart.citydoctor2.connect.edge
;
/**
* This class represents the parent class of all exceptions thrown by the native
* c++ library for the check- and healkernel for the project CityDoctor. An
* additionally sting field has been added to identify the thrown Exception, if
* not a specialized exception has been caught. This keeps the code clearly
* arranged, because most of the exception that will be thrown represents an
* severe error in C++, so there it doesn't makes sense to carry on with the
* java program
*
* @author wewetzer
* @version 1.0
*/
public
abstract
class
NativeException
extends
RuntimeException
{
private
static
final
long
serialVersionUID
=
443321035265866910L
;
String
exceptionType
=
"not specified"
;
/**
* Standard constructor.
*/
public
NativeException
()
{
super
(
"Message not specified"
);
}
/**
* Constructs a NativeException with the given message an the given type
*
* @param message The message of the exception
*/
public
NativeException
(
String
message
)
{
super
(
message
);
}
/**
* Returns the type of the exception
*
* @return The type of the exception
*/
public
String
getType
()
{
return
exceptionType
;
}
}
CityDoctorParent/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/connect/edge/NativePointerCastException.java
0 → 100644
View file @
ffdae21a
package
de.hft.stuttgart.citydoctor2.connect.edge
;
/**
* @author wewetzer
* @version 1.0
*/
public
class
NativePointerCastException
extends
NativeException
{
// version control for serialization
private
static
final
long
serialVersionUID
=
1L
;
public
NativePointerCastException
()
{
exceptionType
=
"Native pointer cast exception"
;
}
public
NativePointerCastException
(
String
message
)
{
super
(
message
);
exceptionType
=
"Native pointer cast exception"
;
}
}
CityDoctorParent/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/healer/GeometryFilter.java
0 → 100644
View file @
ffdae21a
package
de.hft.stuttgart.citydoctor2.healer
;
import
java.util.Objects
;
import
java.util.Set
;
import
de.hft.stuttgart.citydoctor2.check.Check
;
import
de.hft.stuttgart.citydoctor2.check.CheckId
;
import
de.hft.stuttgart.citydoctor2.check.RequirementType
;
import
de.hft.stuttgart.citydoctor2.check.Requirement
;
import
de.hft.stuttgart.citydoctor2.datastructure.Geometry
;
public
class
GeometryFilter
extends
Check
{
private
GeometryListener
l
;
@Override
public
void
check
(
Geometry
geom
)
{
l
.
visit
(
geom
);
}
public
GeometryFilter
(
GeometryListener
l
)
{
Objects
.
requireNonNull
(
l
);
this
.
l
=
l
;
}
@Override
public
RequirementType
getType
()
{
return
null
;
}
@Override
public
Check
createNewInstance
()
{
return
null
;
}
@Override
public
CheckId
getCheckId
()
{
return
null
;
}
@Override
public
Set
<
Requirement
>
appliesToRequirements
()
{
return
null
;
}
}
CityDoctorParent/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/healer/GeometryListener.java
0 → 100644
View file @
ffdae21a
package
de.hft.stuttgart.citydoctor2.healer
;
import
de.hft.stuttgart.citydoctor2.datastructure.Geometry
;
public
interface
GeometryListener
{
public
void
visit
(
Geometry
geom
);
}
CityDoctorParent/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/healer/Healer.java
0 → 100644
View file @
ffdae21a
package
de.hft.stuttgart.citydoctor2.healer
;
import
java.io.BufferedOutputStream
;
import
java.io.ByteArrayInputStream
;
import
java.io.ByteArrayOutputStream
;
import
java.io.File
;
import
java.io.FileNotFoundException
;
import
java.io.IOException
;
import
java.util.ArrayList
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Objects
;
import
org.apache.logging.log4j.LogManager
;
import
org.apache.logging.log4j.Logger
;
import
org.citygml4j.core.ade.ADEException
;
import
org.citygml4j.core.model.CityGMLVersion
;
import
org.citygml4j.core.model.core.AbstractCityObject
;
import
org.citygml4j.core.model.core.AbstractCityObjectProperty
;
import
org.citygml4j.core.model.core.CityModel
;
import
org.citygml4j.core.util.geometry.GeometryFactory
;
import
org.citygml4j.xml.CityGMLContext
;
import
org.citygml4j.xml.writer.CityGMLOutputFactory
;
import
org.citygml4j.xml.writer.CityGMLWriteException
;
import
org.citygml4j.xml.writer.CityGMLWriter
;
import
de.hft.stuttgart.citydoctor2.CityDoctorValidation
;
import
de.hft.stuttgart.citydoctor2.check.AbstractCheck
;
import
de.hft.stuttgart.citydoctor2.check.CheckError
;
import
de.hft.stuttgart.citydoctor2.check.Checker
;
import
de.hft.stuttgart.citydoctor2.check.HealingMethod
;
import
de.hft.stuttgart.citydoctor2.check.ModificationListener
;
import
de.hft.stuttgart.citydoctor2.check.ValidationConfiguration
;
import
de.hft.stuttgart.citydoctor2.check.error.AttributeMissingError
;
import
de.hft.stuttgart.citydoctor2.check.error.AttributeValueWrongError
;
import
de.hft.stuttgart.citydoctor2.checkresult.utility.CheckReportWriteException
;
import
de.hft.stuttgart.citydoctor2.checks.SvrlContentHandler
;
import
de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel
;
import
de.hft.stuttgart.citydoctor2.datastructure.CityObject
;
import
de.hft.stuttgart.citydoctor2.datastructure.Geometry
;
import
de.hft.stuttgart.citydoctor2.datastructure.LinearRing
;
import
de.hft.stuttgart.citydoctor2.datastructure.Polygon
;
import
de.hft.stuttgart.citydoctor2.datastructure.Vertex
;
import
de.hft.stuttgart.citydoctor2.exceptions.CityDoctorWriteException
;
import
de.hft.stuttgart.citydoctor2.parameter.ArgumentParser
;
import
de.hft.stuttgart.citydoctor2.parser.CityGmlConsumer
;
import
de.hft.stuttgart.citydoctor2.parser.CityGmlParseException
;
import
de.hft.stuttgart.citydoctor2.parser.CityGmlParser
;
import
de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException
;
import
de.hft.stuttgart.citydoctor2.parser.ParserConfiguration
;
import
de.hft.stuttgart.citydoctor2.reporting.XmlStreamReporter
;
import
de.hft.stuttgart.citydoctor2.reporting.pdf.PdfStreamReporter
;
import
de.hft.stuttgart.citydoctor2.utils.Localization
;
import
de.hft.stuttgart.quality.QualityADEModule
;
public
class
Healer
{
private
static
final
Logger
logger
=
LogManager
.
getLogger
(
Healer
.
class
);
private
int
numIterations
=
200
;
private
int
schematronIterations
=
2
;
private
Checker
checker
;
private
ModificationListener
l
;
private
HealingPlan
plan
;
static
{
// CppInitializer.initCpp();
}
public
static
void
main
(
String
[]
args
)
throws
CityGmlParseException
,
IOException
,
InvalidGmlFileException
,
CityDoctorWriteException
{
ArgumentParser
argParser
=
new
ArgumentParser
(
args
);
String
inputFile
=
CityDoctorValidation
.
getInputFile
(
argParser
,
false
);
String
outputFile
=
getOutputFile
(
argParser
);
String
xmlOutput
=
CityDoctorValidation
.
getXmlOutput
(
argParser
);
String
pdfOutput
=
CityDoctorValidation
.
getPdfOutput
(
argParser
);
ValidationConfiguration
config
=
CityDoctorValidation
.
getValidationConfig
(
argParser
,
true
);
startHealingProcess
(
inputFile
,
outputFile
,
xmlOutput
,
pdfOutput
,
config
);
}
private
static
void
startHealingProcess
(
String
inputFile
,
String
outputFile
,
String
xmlOutput
,
String
pdfOutput
,
ValidationConfiguration
config
)
throws
CityGmlParseException
,
IOException
,
InvalidGmlFileException
,
CityDoctorWriteException
{
ParserConfiguration
parserConfig
=
config
.
getParserConfiguration
();
if
(
config
.
isUseStreaming
())
{
Healer
.
streamHeal
(
new
File
(
inputFile
),
outputFile
,
xmlOutput
,
pdfOutput
,
config
);
}
else
{
CityDoctorModel
model
=
CityGmlParser
.
parseCityGmlFile
(
inputFile
,
parserConfig
);
Checker
c
=
new
Checker
(
config
,
model
);
Healer
healer
=
new
Healer
(
c
,
(
ModificationListener
)
null
);
healer
.
healModel
(
model
);
model
.
saveAs
(
outputFile
,
true
);
}
}
public
static
void
streamHeal
(
File
inputFile
,
String
outputFileName
,
String
xmlOutput
,
String
pdfOutput
,
ValidationConfiguration
config
)
throws
CityGmlParseException
,
IOException
{
if
(!
inputFile
.
exists
()
||
!
inputFile
.
isFile
())
{
logger
.
error
(
"Inputfile does not exist or is not a file: {}"
,
inputFile
.
getAbsolutePath
());
}
Checker
c
=
new
Checker
(
config
,
null
);
Healer
healer
=
new
Healer
(
c
,
(
ModificationListener
)
null
);
try
(
BufferedOutputStream
xmlBos
=
Checker
.
getXmlOutputMaybe
(
xmlOutput
);
BufferedOutputStream
pdfBos
=
Checker
.
getPdfOutputMaybe
(
pdfOutput
))
{
String
fileName
=
inputFile
.
getName
();
XmlStreamReporter
xmlReporter
;
if
(
xmlBos
!=
null
)
{
xmlReporter
=
new
XmlStreamReporter
(
xmlBos
,
fileName
,
config
);
}
else
{
xmlReporter
=
null
;
}
PdfStreamReporter
pdfReporter
;
if
(
pdfBos
!=
null
)
{
pdfReporter
=
new
PdfStreamReporter
(
pdfBos
,
fileName
,
config
);
}
else
{
pdfReporter
=
null
;
}
CityGmlConsumer
coConsumer
=
new
CityGmlConsumer
()
{
@Override
public
void
accept
(
CityObject
co
)
{
healer
.
healCityObject
(
co
);
}
};
CityGmlParser
.
streamCityGml
(
inputFile
,
config
.
getParserConfiguration
(),
coConsumer
,
outputFileName
);
Checker
.
writeReport
(
xmlReporter
);
Checker
.
writeReport
(
pdfReporter
);
}
catch
(
CheckReportWriteException
e
)
{
logger
.
error
(
Localization
.
getText
(
"Checker.failReports"
),
e
);
}
}
private
static
String
getOutputFile
(
ArgumentParser
argParser
)
{
String
outputFile
;
if
(!
argParser
.
containsOption
(
"out"
))
{
logger
.
error
(
"No output file specified. (-out [FILE])"
);
System
.
exit
(
10
);
}
List
<
String
>
outFiles
=
argParser
.
getValues
(
"out"
);
if
(
outFiles
.
size
()
!=
1
)
{
logger
.
error
(
"Specify exactly one file as output."
);
System
.
exit
(
11
);
}
outputFile
=
outFiles
.
get
(
0
);
return
outputFile
;
}
public
static
void
heal
(
File
in
,
File
configFile
,
File
out
)
throws
FileNotFoundException
,
CityGmlParseException
,
InvalidGmlFileException
,
CityDoctorWriteException
{
ValidationConfiguration
config
;
if
(
configFile
==
null
)
{
config
=
ValidationConfiguration
.
loadStandardValidationConfig
();
}
else
{
config
=
ValidationConfiguration
.
loadValidationConfig
(
configFile
.
getAbsolutePath
());
}
CityDoctorModel
model
=
CityGmlParser
.
parseCityGmlFile
(
in
.
getAbsolutePath
(),
config
.
getParserConfiguration
());
Checker
c
=
new
Checker
(
config
,
model
);
Healer
healer
=
new
Healer
(
c
,
(
ModificationListener
)
null
);
healer
.
healModel
(
model
);
model
.
saveAs
(
out
.
getAbsolutePath
(),
true
);
}
public
Healer
(
Checker
c
)
{
this
(
c
,
(
ModificationListener
)
null
);
}
public
Healer
(
Checker
c
,
ModificationListener
l
)
{
plan
=
HealingMethods
.
createHealingPlanFromAllMethods
();
checker
=
c
;
if
(
l
==
null
)
{
// create useless modification listener to avoid having to check on == null
l
=
new
ModificationListener
()
{
@Override
public
void
polygonRemoved
(
Polygon
p
)
{
// not observing anything
}
@Override
public
void
polygonAdded
(
Polygon
p
)
{
// not observing anything
}
};
}
this
.
l
=
l
;
}
public
Healer
(
Checker
c
,
ModificationListener
l
,
HealingPlan
plan
)
{
this
(
c
,
l
);
this
.
plan
=
Objects
.
requireNonNull
(
plan
);
}
public
Healer
(
Checker
c
,
HealingPlan
plan
)
{
this
(
c
);
this
.
plan
=
Objects
.
requireNonNull
(
plan
);
}
public
void
setNumberOfIterations
(
int
iterations
)
{
if
(
iterations
<
1
)
{
throw
new
IllegalArgumentException
(
"Iterations may not be lower than 1"
);
}
numIterations
=
iterations
;
}
public
void
healModel
(
CityDoctorModel
model
)
{
model
.
createFeatureStream
().
forEach
(
this
::
healCityObject
);
}
public
void
healCityObject
(
CityObject
co
)
{
logger
.
info
(
"Repairing feature {}"
,
co
.
getGmlId
());
String
schematronPath
=
checker
.
getConfig
().
getSchematronFilePath
();
if
(
schematronPath
!=
null
&&
!
schematronPath
.
isEmpty
())
{
healSemanticErrors
(
co
);
}
// healing geometries
GeometryFilter
filter
=
new
GeometryFilter
(
g
->
heal
(
g
,
co
));
co
.
accept
(
filter
);
}
private
void
healSemanticErrors
(
CityObject
co
)
{
// if a schematron file has been declared this needs to execute
for
(
int
i
=
0
;
i
<
schematronIterations
;
i
++)
{
co
.
clearAllContainedCheckResults
();
executeSchematron
(
co
);
List
<
CheckError
>
errors
=
new
ArrayList
<>();
co
.
collectContainedErrors
(
errors
);
boolean
healedSomething
=
false
;
for
(
CheckError
err
:
errors
)
{
if
(
err
instanceof
AttributeMissingError
||
err
instanceof
AttributeValueWrongError
)
{
for
(
HealingMethod
m
:
plan
.
getHealingMethods
())
{
if
(
err
.
accept
(
m
,
l
))
{
healedSomething
=
true
;
break
;
}
}
}
}
if
(!
healedSomething
)
{
// nothing was changed, don't check for anything more
break
;
}
}
// recheck for geometry errors as they were removed when executing the
// schematron stuff
co
.
prepareForChecking
();
checker
.
executeChecksForCheckable
(
co
);
if
(
checker
.
getConfig
().
getParserConfiguration
().
useLowMemoryConsumption
())
{
co
.
clearMetaInformation
();
}
}
private
void
executeSchematron
(
CityObject
co
)
{
ValidationConfiguration
config
=
checker
.
getConfig
();
try
{
GeometryFactory
factory
=
GeometryFactory
.
newInstance
();
// write geometries in citygml4j datastructure
co
.
reCreateGeometries
(
factory
,
checker
.
getConfig
().
getParserConfiguration
());
byte
[]
gml
=
writeCityGml
(
co
.
getGmlObject
());
// remove them again to save memory
co
.
unsetGmlGeometries
();
SvrlContentHandler
handler
=
Checker
.
executeSchematronValidationIfAvailable
(
config
,
new
ByteArrayInputStream
(
gml
));
if
(
handler
!=
null
)
{
handler
.
getFeatureErrors
().
computeIfPresent
(
co
.
getGmlId
().
getGmlString
(),
(
key
,
list
)
->
{
Checker
.
handleSchematronErrorsForCityObject
(
list
,
co
);
return
list
;
});
}
}
catch
(
CityGMLWriteException
e
)
{
throw
new
IllegalStateException
(
e
);
}
}
/**
* Writes one feature to a byte array.
*
* @param aco the feature to write
* @return the byte array containing the feature
* @throws ADEException
* @throws CityGMLBuilderException
* @throws CityGMLWriteException
*/
private
byte
[]
writeCityGml
(
AbstractCityObject
aco
)
throws
CityGMLWriteException
{
CityModel
model
=
new
CityModel
();
model
.
getCityObjectMembers
().
add
(
new
AbstractCityObjectProperty
(
aco
));
CityGMLContext
context
=
CityGmlParser
.
getContext
();
CityGMLOutputFactory
outputFactory
=
context
.
createCityGMLOutputFactory
(
CityGMLVersion
.
v2_0
);
ByteArrayOutputStream
out
=
new
ByteArrayOutputStream
();
try
(
CityGMLWriter
writer
=
outputFactory
.
createCityGMLWriter
(
out
))
{
writer
.
withIndent
(
" "
);
writer
.
withDefaultPrefixes
();
writer
.
withPrefix
(
"qual"
,
QualityADEModule
.
NAMESPACE_URI
);
writer
.
withSchemaLocation
(
QualityADEModule
.
NAMESPACE_URI
,
QualityADEModule
.
NAMESPACE_URI
+
"/qualityAde.xsd"
);
writer
.
withDefaultSchemaLocations
();
writer
.
write
(
model
);
writer
.
flush
();
return
out
.
toByteArray
();
}
}
public
void
heal
(
Geometry
geom
,
CityObject
co
)
{
heal
(
geom
,
co
,
numIterations
);
}
public
void
heal
(
Geometry
geom
,
CityObject
co
,
int
numIterations
)
{
if
(
checker
.
getConfig
().
getParserConfiguration
().
useLowMemoryConsumption
())
{
co
.
prepareForChecking
();
}
if
(!
co
.
isValidated
())
{
// check it if it has not been checked yet
checker
.
executeChecksForCheckable
(
co
);
}
try
{
for
(
int
i
=
0
;
i
<
numIterations
;
i
++)
{
List
<
CheckError
>
errors
=
collectErrorsFromGeometry
(
geom
);
if
(
errors
.
isEmpty
())
{
break
;
}
else
{
logger
.
debug
(
"Found errors: "
);
for
(
CheckError
err
:
errors
)
{
logger
.
debug
(
err
.
getErrorId
());
}
}
boolean
cannotBeHealed
=
executeHealingLoop
(
errors
);
logger
.
debug
(
"End heal iteration: {}"
,
(
i
+
1
));
if
(
cannotBeHealed
)
{
logger
.
debug
(
"Geometry: {} cannot be healed"
,
geom
.
getGmlId
());
// break iteration loop, nothing more to be done
break
;
}
co
.
prepareForChecking
();
filterOutDuplicateVertices
(
co
);
// recheck for errors
checker
.
executeChecksForCheckable
(
co
);
}
}
catch
(
Exception
e
)
{
logger
.
debug
(
"Failed to heal geometry"
,
e
);
}
finally
{
if
(
checker
.
getConfig
().
getParserConfiguration
().
useLowMemoryConsumption
())
{
co
.
clearMetaInformation
();
}
}
}
private
void
filterOutDuplicateVertices
(
CityObject
co
)
{
Map
<
Vertex
,
Vertex
>
map
=
new
HashMap
<>();
co
.
accept
(
new
AbstractCheck
()
{
@Override
public
void
check
(
LinearRing
ring
)
{
for
(
int
i
=
0
;
i
<
ring
.
getVertices
().
size
();
i
++)
{
Vertex
v
=
ring
.
getVertices
().
get
(
i
);
Vertex
duplicate
=
map
.
get
(
v
);
if
(
duplicate
==
null
)
{
map
.
put
(
v
,
v
);
}
else
if
(
duplicate
!=
v
)
{
ring
.
getVertices
().
set
(
i
,
duplicate
);
}
}
}
});
}
private
boolean
executeHealingLoop
(
List
<
CheckError
>
errors
)
{
for
(
HealingMethod
method
:
plan
.
getHealingMethods
())
{
for
(
CheckError
err
:
errors
)
{
if
(
err
.
accept
(
method
,
l
))
{
// geometry got changed, update, recheck, restart
return
false
;
}
}
}
return
true
;
}
private
List
<
CheckError
>
collectErrorsFromGeometry
(
Geometry
geom
)
{
List
<
CheckError
>
errors
=
new
ArrayList
<>();
geom
.
collectContainedErrors
(
errors
);
return
errors
;
}
}
CityDoctorParent/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/healer/HealingMethodPrototype.java
0 → 100644
View file @
ffdae21a
package
de.hft.stuttgart.citydoctor2.healer
;
import
de.hft.stuttgart.citydoctor2.check.HealingMethod
;
public
class
HealingMethodPrototype
{
public
HealingMethod
method
;
public
static
HealingMethodPrototype
of
(
HealingMethod
method
)
{
return
new
HealingMethodPrototype
(
method
);
}
public
HealingMethodPrototype
(
HealingMethod
method
)
{
this
.
method
=
method
;
}
public
HealingMethod
createMethod
()
{
return
method
.
createNew
();
}
}
CityDoctorParent/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/healer/HealingMethods.java
0 → 100644
View file @
ffdae21a
package
de.hft.stuttgart.citydoctor2.healer
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.List
;
import
de.hft.stuttgart.citydoctor2.healing.GeometrySimplifier
;
import
de.hft.stuttgart.citydoctor2.healing.HealAllPolygonsWrongOrientationError
;
import
de.hft.stuttgart.citydoctor2.healing.HealConsecutivePointsSameError
;
import
de.hft.stuttgart.citydoctor2.healing.HealHoleOutsideError
;
import
de.hft.stuttgart.citydoctor2.healing.HealMainBuilding
;
import
de.hft.stuttgart.citydoctor2.healing.HealMissingSolid
;
import
de.hft.stuttgart.citydoctor2.healing.HealNonManifoldEdgeError
;
import
de.hft.stuttgart.citydoctor2.healing.HealPlanarPolygonError
;
import
de.hft.stuttgart.citydoctor2.healing.HealPolygonWithoutSurface
;
import
de.hft.stuttgart.citydoctor2.healing.HealPolygonWrongOrientationError
;
import
de.hft.stuttgart.citydoctor2.healing.HealRingNotClosedError
;
import
de.hft.stuttgart.citydoctor2.healing.HealRingSelfIntError
;
import
de.hft.stuttgart.citydoctor2.healing.HealSameOrientationError
;
import
de.hft.stuttgart.citydoctor2.healing.HealSolidNotClosedError
;
import
de.hft.stuttgart.citydoctor2.healing.HealTooFewPoints
;
import
de.hft.stuttgart.citydoctor2.healing.HealWrongDormers
;
public
class
HealingMethods
{
private
static
List
<
HealingMethodPrototype
>
healingMethods
;
private
HealingMethods
()
{
// only static access
}
static
{
healingMethods
=
new
ArrayList
<>();
healingMethods
.
add
(
HealingMethodPrototype
.
of
(
new
HealMissingSolid
()));
healingMethods
.
add
(
HealingMethodPrototype
.
of
(
new
HealMainBuilding
()));
healingMethods
.
add
(
HealingMethodPrototype
.
of
(
new
HealConsecutivePointsSameError
()));
healingMethods
.
add
(
HealingMethodPrototype
.
of
(
new
HealTooFewPoints
()));
healingMethods
.
add
(
HealingMethodPrototype
.
of
(
new
HealRingNotClosedError
()));
healingMethods
.
add
(
HealingMethodPrototype
.
of
(
new
HealRingSelfIntError
()));
healingMethods
.
add
(
HealingMethodPrototype
.
of
(
new
HealPlanarPolygonError
()));
// healingMethods.add(HealingMethodPrototype.of(new HealPlanarPolygonCpp()));
healingMethods
.
add
(
HealingMethodPrototype
.
of
(
new
HealSameOrientationError
()));
healingMethods
.
add
(
HealingMethodPrototype
.
of
(
new
HealHoleOutsideError
()));
healingMethods
.
add
(
HealingMethodPrototype
.
of
(
new
HealNonManifoldEdgeError
()));
healingMethods
.
add
(
HealingMethodPrototype
.
of
(
new
HealSolidNotClosedError
()));
// healingMethods.add(HealingMethodPrototype.of(new HealSolidNotClosedCpp()));
healingMethods
.
add
(
HealingMethodPrototype
.
of
(
new
HealPolygonWrongOrientationError
()));
healingMethods
.
add
(
HealingMethodPrototype
.
of
(
new
GeometrySimplifier
()));
healingMethods
.
add
(
HealingMethodPrototype
.
of
(
new
HealWrongDormers
()));
healingMethods
.
add
(
HealingMethodPrototype
.
of
(
new
HealAllPolygonsWrongOrientationError
()));
healingMethods
.
add
(
HealingMethodPrototype
.
of
(
new
HealPolygonWithoutSurface
()));
healingMethods
=
Collections
.
unmodifiableList
(
healingMethods
);
}
public
static
HealingPlan
createHealingPlanFromAllMethods
()
{
HealingPlan
plan
=
new
HealingPlan
();
for
(
HealingMethodPrototype
proto
:
healingMethods
)
{
plan
.
addHealingMethod
(
proto
.
createMethod
());
}
return
plan
;
}
public
static
List
<
HealingMethodPrototype
>
getAvailableHealingMethods
()
{
return
healingMethods
;
}
}
CityDoctorParent/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/healer/HealingPlan.java
0 → 100644
View file @
ffdae21a
package
de.hft.stuttgart.citydoctor2.healer
;
import
java.util.ArrayList
;
import
java.util.List
;
import
de.hft.stuttgart.citydoctor2.check.HealingMethod
;
public
class
HealingPlan
{
private
List
<
HealingMethod
>
methods
;
public
HealingPlan
()
{
methods
=
new
ArrayList
<>();
}
public
void
addHealingMethod
(
HealingMethod
method
)
{
methods
.
add
(
method
);
}
public
List
<
HealingMethod
>
getHealingMethods
()
{
return
methods
;
}
@Override
public
String
toString
()
{
return
"HealingPlan [methods="
+
methods
+
"]"
;
}
}
CityDoctorParent/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/healing/GeometrySimplifier.java
0 → 100644
View file @
ffdae21a
package
de.hft.stuttgart.citydoctor2.healing
;
import
java.util.ArrayList
;
import
java.util.HashSet
;
import
java.util.List
;
import
java.util.Set
;
import
org.apache.logging.log4j.LogManager
;
import
org.apache.logging.log4j.Logger
;
import
de.hft.stuttgart.citydoctor2.check.HealingID
;
import
de.hft.stuttgart.citydoctor2.check.HealingMethod
;
import
de.hft.stuttgart.citydoctor2.check.ModificationListener
;
import
de.hft.stuttgart.citydoctor2.check.error.MultipleConnectedComponentsError
;
import
de.hft.stuttgart.citydoctor2.datastructure.ConcretePolygon
;
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.LinearRing.LinearRingType
;
import
de.hft.stuttgart.citydoctor2.datastructure.Polygon
;
import
de.hft.stuttgart.citydoctor2.datastructure.Vertex
;
import
de.hft.stuttgart.citydoctor2.healing.math.EdgeGraph
;
import
de.hft.stuttgart.citydoctor2.math.Plane
;
public
class
GeometrySimplifier
implements
HealingMethod
{
private
static
final
Logger
logger
=
LogManager
.
getLogger
(
GeometrySimplifier
.
class
);
private
static
final
double
EPSILON
=
0.1
;
@Override
public
HealingID
getID
()
{
return
HealingID
.
S_GEOMETRIC_SIMPLIFIER
;
}
@Override
public
boolean
visit
(
MultipleConnectedComponentsError
err
,
ModificationListener
l
)
{
logger
.
debug
(
"Executing Repair for MultipleConnectedComponentsError"
);
// first merge similar polygons
for
(
List
<
Polygon
>
component
:
err
.
getComponents
())
{
for
(
int
i
=
0
;
i
<
component
.
size
()
-
1
;
i
++)
{
Polygon
p0
=
component
.
get
(
i
);
Plane
plane
=
new
Plane
(
p0
.
calculateNormalNormalized
(),
p0
.
getExteriorRing
().
getVertices
().
get
(
0
));
for
(
int
j
=
i
+
1
;
j
<
component
.
size
();
j
++)
{
Polygon
p1
=
component
.
get
(
j
);
if
(
isPolygonInPlane
(
plane
,
p1
)
&&
isPolygonConnectedViaEdge
(
p0
,
p1
,
err
.
getGeometry
()))
{
ConcretePolygon
p
=
mergePolygons
(
p0
,
p1
);
p1
.
remove
();
err
.
getGeometry
().
replacePolygon
(
p0
,
p
);
return
true
;
}
}
}
}
return
false
;
}
private
boolean
isPolygonConnectedViaEdge
(
Polygon
p1
,
Polygon
p2
,
Geometry
g
)
{
List
<
Edge
>
edges
=
g
.
getEdgesAdjacentTo
(
p1
);
for
(
Edge
e
:
edges
)
{
if
(
e
.
getAdjacentPolygons
().
contains
(
p2
))
{
return
true
;
}
}
return
false
;
}
private
ConcretePolygon
mergePolygons
(
Polygon
p1
,
Polygon
p2
)
{
Geometry
geom
=
p1
.
getParent
();
List
<
Edge
>
edgesP1
=
geom
.
getEdgesAdjacentTo
(
p1
);
List
<
Edge
>
edgesP2
=
geom
.
getEdgesAdjacentTo
(
p2
);
Set
<
Edge
>
setOfEdgesFromP1
=
new
HashSet
<>(
edgesP1
);
Set
<
Edge
>
duplicateEdges
=
new
HashSet
<>();
for
(
Edge
e
:
edgesP2
)
{
if
(
setOfEdgesFromP1
.
contains
(
e
))
{
duplicateEdges
.
add
(
e
);
}
}
if
(
duplicateEdges
.
isEmpty
())
{
throw
new
IllegalStateException
(
"Trying to merge two polygon which are not connected "
+
p1
.
getGmlId
()
+
", "
+
p2
.
getGmlId
());
}
List
<
Edge
>
newEdges
=
new
ArrayList
<>();
filterDuplicateEdges
(
edgesP1
,
duplicateEdges
,
newEdges
);
filterDuplicateEdges
(
edgesP2
,
duplicateEdges
,
newEdges
);
if
(
newEdges
.
isEmpty
())
{
return
copyPolygon
(
p1
);
}
List
<
List
<
Edge
>>
rings
=
findCyclesInEdges
(
newEdges
);
// find the exterior ring in the new rings
ConcretePolygon
p
=
new
ConcretePolygon
();
List
<
LinearRing
>
newRings
=
new
ArrayList
<>();
for
(
List
<
Edge
>
edges
:
rings
)
{
LinearRing
ring
=
createRingFromEdges
(
edges
);
newRings
.
add
(
ring
);
}
if
(
rings
.
size
()
==
1
)
{
// only one ring -> the ring is an exterior
LinearRing
ext
=
newRings
.
get
(
0
);
ext
.
setType
(
LinearRingType
.
EXTERIOR
);
p
.
setParent
(
geom
);
p
.
setExteriorRing
(
ext
);
return
p
;
}
else
{
for
(
LinearRing
lr
:
newRings
)
{
if
(
isRingExterior
(
newRings
,
lr
))
{
return
createPolygon
(
newRings
,
lr
,
p
);
}
}
throw
new
IllegalStateException
(
"Merging polygons produced intersecting edges,"
+
" no exterior ring could be found"
);
}
}
private
ConcretePolygon
copyPolygon
(
Polygon
p1
)
{
ConcretePolygon
newPoly
=
new
ConcretePolygon
();
ConcretePolygon
original
=
p1
.
getOriginal
();
LinearRing
ext
=
new
LinearRing
(
LinearRingType
.
EXTERIOR
);
newPoly
.
setExteriorRing
(
ext
);
for
(
Vertex
v
:
original
.
getExteriorRing
().
getVertices
())
{
ext
.
addVertex
(
v
);
}
for
(
LinearRing
lr
:
original
.
getInnerRings
())
{
LinearRing
inner
=
new
LinearRing
(
LinearRingType
.
INTERIOR
);
newPoly
.
addInteriorRing
(
inner
);
for
(
Vertex
v
:
lr
.
getVertices
())
{
inner
.
addVertex
(
v
);
}
}
return
newPoly
;
}
private
ConcretePolygon
createPolygon
(
List
<
LinearRing
>
newRings
,
LinearRing
lr
,
ConcretePolygon
p
)
{
lr
.
setType
(
LinearRingType
.
EXTERIOR
);
p
.
setExteriorRing
(
lr
);
for
(
LinearRing
innerRing
:
newRings
)
{
if
(
lr
==
innerRing
)
{
continue
;
}
p
.
addInteriorRing
(
innerRing
);
}
return
p
;
}
private
boolean
isRingExterior
(
List
<
LinearRing
>
newRings
,
LinearRing
lr
)
{
for
(
LinearRing
other
:
newRings
)
{
if
(
lr
==
other
)
{
continue
;
}
for
(
Vertex
v
:
lr
.
getVertices
())
{
if
(
other
.
isPointInside
(
v
))
{
return
false
;
}
}
}
return
true
;
}
private
LinearRing
createRingFromEdges
(
List
<
Edge
>
edges
)
{
Edge
startEdge
=
edges
.
get
(
0
);
Vertex
start
=
startEdge
.
getFrom
();
Vertex
currentVertex
=
startEdge
.
getTo
();
edges
.
remove
(
0
);
LinearRing
lr
=
new
LinearRing
(
LinearRingType
.
INTERIOR
);
lr
.
addVertex
(
start
);
lr
.
addVertex
(
currentVertex
);
while
(!
edges
.
isEmpty
())
{
boolean
removedEdge
=
false
;
for
(
Edge
e
:
edges
)
{
Vertex
oppositeV
=
e
.
getOppositeVertex
(
currentVertex
);
if
(
oppositeV
!=
null
)
{
lr
.
addVertex
(
oppositeV
);
currentVertex
=
oppositeV
;
edges
.
remove
(
e
);
removedEdge
=
true
;
break
;
}
}
if
(!
removedEdge
)
{
// avoid endless loop in case of errors
logger
.
error
(
"Could not create ring from edges, edges are not a loop"
);
break
;
}
}
return
lr
;
}
private
void
filterDuplicateEdges
(
List
<
Edge
>
edges
,
Set
<
Edge
>
duplicateEdges
,
List
<
Edge
>
newEdges
)
{
for
(
Edge
e
:
edges
)
{
if
(!
duplicateEdges
.
contains
(
e
))
{
newEdges
.
add
(
e
);
}
}
}
private
List
<
List
<
Edge
>>
findCyclesInEdges
(
List
<
Edge
>
edges
)
{
EdgeGraph
graph
=
new
EdgeGraph
();
for
(
Edge
e
:
edges
)
{
graph
.
addEdge
(
e
,
edges
);
}
return
graph
.
getCycles
();
}
private
boolean
isPolygonInPlane
(
Plane
plane
,
Polygon
potentialPoly
)
{
for
(
Vertex
v
:
potentialPoly
.
getExteriorRing
().
getVertices
())
{
if
(
plane
.
getDistance
(
v
)
>
EPSILON
)
{
return
false
;
}
}
return
true
;
}
@Override
public
GeometrySimplifier
createNew
()
{
return
new
GeometrySimplifier
();
}
}
CityDoctorParent/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/healing/HealAllPolygonsWrongOrientationError.java
0 → 100644
View file @
ffdae21a
package
de.hft.stuttgart.citydoctor2.healing
;
import
java.util.Collections
;
import
org.apache.logging.log4j.LogManager
;
import
org.apache.logging.log4j.Logger
;
import
de.hft.stuttgart.citydoctor2.check.HealingID
;
import
de.hft.stuttgart.citydoctor2.check.HealingMethod
;
import
de.hft.stuttgart.citydoctor2.check.ModificationListener
;
import
de.hft.stuttgart.citydoctor2.check.error.AllPolygonsWrongOrientationError
;
import
de.hft.stuttgart.citydoctor2.datastructure.Geometry
;
import
de.hft.stuttgart.citydoctor2.datastructure.LinearRing
;
import
de.hft.stuttgart.citydoctor2.datastructure.Polygon
;
public
class
HealAllPolygonsWrongOrientationError
implements
HealingMethod
{
private
static
final
Logger
logger
=
LogManager
.
getLogger
(
HealAllPolygonsWrongOrientationError
.
class
);
@Override
public
boolean
visit
(
AllPolygonsWrongOrientationError
err
,
ModificationListener
l
)
{
logger
.
debug
(
"Executing Repair for AllPolygonsWrongOrientationError"
);
Geometry
geom
=
err
.
getGeometry
();
for
(
Polygon
p
:
geom
.
getPolygons
())
{
Collections
.
reverse
(
p
.
getExteriorRing
().
getVertices
());
for
(
LinearRing
lr
:
p
.
getInnerRings
())
{
Collections
.
reverse
(
lr
.
getVertices
());
}
}
return
true
;
}
@Override
public
HealAllPolygonsWrongOrientationError
createNew
()
{
return
new
HealAllPolygonsWrongOrientationError
();
}
@Override
public
HealingID
getID
()
{
return
HealingID
.
S_ALL_POLYGONS_WRONG_ORIENTATION
;
}
}
Prev
1
2
3
4
5
6
…
13
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