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/main/java/de/hft/stuttgart/citydoctor2/healing/HealConsecutivePointsSameError.java
0 → 100644
View file @
ffdae21a
package
de.hft.stuttgart.citydoctor2.healing
;
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.ConsecutivePointSameError
;
import
de.hft.stuttgart.citydoctor2.datastructure.LinearRing
;
import
de.hft.stuttgart.citydoctor2.datastructure.Vertex
;
import
de.hft.stuttgart.citydoctor2.math.Vector3d
;
public
class
HealConsecutivePointsSameError
implements
HealingMethod
{
private
static
final
Logger
logger
=
LogManager
.
getLogger
(
HealConsecutivePointsSameError
.
class
);
@Override
public
boolean
visit
(
ConsecutivePointSameError
err
,
ModificationListener
l
)
{
logger
.
debug
(
"Executing Repair for ConsecutivePointSameError"
);
LinearRing
lr
=
err
.
getRing
();
Vertex
consV1
=
err
.
getVertex1
();
Vertex
consV2
=
err
.
getVertex2
();
for
(
int
i
=
0
;
i
<
lr
.
getVertices
().
size
()
-
1
;
i
++)
{
Vertex
v1
=
lr
.
getVertices
().
get
(
i
+
0
);
Vertex
v2
=
lr
.
getVertices
().
get
(
i
+
1
);
if
(
v1
==
consV1
&&
v2
==
consV2
)
{
Vector3d
middle
=
v1
.
plus
(
v2
).
mult
(
0.5
);
v2
.
setX
(
middle
.
getX
());
v2
.
setY
(
middle
.
getY
());
v2
.
setZ
(
middle
.
getZ
());
lr
.
getVertices
().
remove
(
i
);
return
true
;
}
}
return
false
;
}
@Override
public
HealConsecutivePointsSameError
createNew
()
{
return
new
HealConsecutivePointsSameError
();
}
@Override
public
HealingID
getID
()
{
return
HealingID
.
R_CONSECUTIVE_POINTS_SAME
;
}
}
CityDoctorParent/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/healing/HealHoleOutsideError.java
0 → 100644
View file @
ffdae21a
package
de.hft.stuttgart.citydoctor2.healing
;
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.PolygonHoleOutsideError
;
import
de.hft.stuttgart.citydoctor2.datastructure.LinearRing
;
public
class
HealHoleOutsideError
implements
HealingMethod
{
private
static
final
Logger
logger
=
LogManager
.
getLogger
(
HealHoleOutsideError
.
class
);
@Override
public
boolean
visit
(
PolygonHoleOutsideError
err
,
ModificationListener
l
)
{
logger
.
debug
(
"Executing Repair for PolygonHoleOutsideError"
);
for
(
LinearRing
lr
:
err
.
getHolesOutside
())
{
err
.
getPolygon
().
removeInnerRing
(
lr
);
}
return
true
;
}
@Override
public
HealHoleOutsideError
createNew
()
{
return
new
HealHoleOutsideError
();
}
@Override
public
HealingID
getID
()
{
return
HealingID
.
P_HOLE_OUTSIDE
;
}
}
CityDoctorParent/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/healing/HealMainBuilding.java
0 → 100644
View file @
ffdae21a
package
de.hft.stuttgart.citydoctor2.healing
;
import
org.apache.logging.log4j.LogManager
;
import
org.apache.logging.log4j.Logger
;
import
org.citygml4j.core.model.building.BuildingPartProperty
;
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.AttributeMissingError
;
import
de.hft.stuttgart.citydoctor2.datastructure.BoundarySurface
;
import
de.hft.stuttgart.citydoctor2.datastructure.BoundarySurfaceType
;
import
de.hft.stuttgart.citydoctor2.datastructure.Building
;
import
de.hft.stuttgart.citydoctor2.datastructure.BuildingPart
;
import
de.hft.stuttgart.citydoctor2.datastructure.Geometry
;
import
de.hft.stuttgart.citydoctor2.datastructure.Polygon
;
public
class
HealMainBuilding
implements
HealingMethod
{
private
static
final
HealingID
ID
=
new
HealingID
(
"SE_MISSING_MAIN_BUILDING"
);
private
static
final
Logger
logger
=
LogManager
.
getLogger
(
HealMainBuilding
.
class
);
@Override
public
HealingMethod
createNew
()
{
return
new
HealMainBuilding
();
}
@Override
public
boolean
visit
(
AttributeMissingError
err
,
ModificationListener
l
)
{
if
(!(
err
.
getFeature
()
instanceof
Building
))
{
return
false
;
}
if
(!
err
.
getNameOfAttribute
().
equalsIgnoreCase
(
"Main Building"
))
{
return
false
;
}
logger
.
debug
(
"Executing Repair for AttributeMissingError with message Main Building"
);
Building
b
=
(
Building
)
err
.
getFeature
();
System
.
out
.
println
(
"Building: "
+
b
.
getGmlId
());
BuildingPart
largestPart
=
null
;
double
largestArea
=
0
;
for
(
BuildingPart
part
:
b
.
getBuildingParts
())
{
double
area
=
0
;
for
(
BoundarySurface
bs
:
part
.
getBoundarySurfaces
())
{
if
(
bs
.
getType
()
==
BoundarySurfaceType
.
GROUND
)
{
Geometry
geometry
=
bs
.
getHighestLodGeometry
();
for
(
Polygon
p
:
geometry
.
getPolygons
())
{
area
+=
p
.
getArea
();
}
}
}
if
(
area
>
largestArea
)
{
largestPart
=
part
;
largestArea
=
area
;
}
}
if
(
largestPart
==
null
)
{
// no suitable part found
return
false
;
}
System
.
out
.
println
(
"Part: "
+
largestPart
.
getGmlId
()
+
" has area: "
+
largestArea
);
b
.
getBuildingParts
().
remove
(
largestPart
);
var
gmlBuilding
=
(
org
.
citygml4j
.
core
.
model
.
building
.
Building
)
b
.
getGmlObject
();
BuildingPartProperty
buildingPartProp
=
findBuildingPartProp
(
largestPart
,
gmlBuilding
);
if
(
buildingPartProp
==
null
)
{
return
false
;
}
gmlBuilding
.
getBuildingParts
().
remove
(
buildingPartProp
);
b
.
getGeometries
().
addAll
(
largestPart
.
getGeometries
());
b
.
getBoundarySurfaces
().
addAll
(
largestPart
.
getBoundarySurfaces
());
b
.
getBuildingInstallations
().
addAll
(
largestPart
.
getBuildingInstallations
());
org
.
citygml4j
.
core
.
model
.
building
.
BuildingPart
partObject
=
buildingPartProp
.
getObject
();
gmlBuilding
.
getBoundaries
().
addAll
(
partObject
.
getBoundaries
());
gmlBuilding
.
getBuildingInstallations
().
addAll
(
partObject
.
getBuildingInstallations
());
gmlBuilding
.
setRoofType
(
partObject
.
getRoofType
());
gmlBuilding
.
getHeights
().
clear
();
gmlBuilding
.
getHeights
().
addAll
(
partObject
.
getHeights
());
return
true
;
}
private
BuildingPartProperty
findBuildingPartProp
(
BuildingPart
largestPart
,
org
.
citygml4j
.
core
.
model
.
building
.
Building
gmlBuilding
)
{
for
(
BuildingPartProperty
prop
:
gmlBuilding
.
getBuildingParts
())
{
if
(
prop
.
getObject
()
!=
null
&&
prop
.
getObject
()
==
largestPart
.
getGmlObject
())
{
return
prop
;
}
}
return
null
;
}
@Override
public
HealingID
getID
()
{
return
ID
;
}
}
CityDoctorParent/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/healing/HealMissingSolid.java
0 → 100644
View file @
ffdae21a
/*-
* 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.healing
;
import
java.util.ArrayList
;
import
java.util.List
;
import
org.apache.logging.log4j.LogManager
;
import
org.apache.logging.log4j.Logger
;
import
de.hft.stuttgart.citydoctor2.check.AbstractCheck
;
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.AttributeMissingError
;
import
de.hft.stuttgart.citydoctor2.datastructure.AbstractBuilding
;
import
de.hft.stuttgart.citydoctor2.datastructure.BoundarySurface
;
import
de.hft.stuttgart.citydoctor2.datastructure.Building
;
import
de.hft.stuttgart.citydoctor2.datastructure.Installation
;
import
de.hft.stuttgart.citydoctor2.datastructure.BuildingPart
;
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.GeometryType
;
import
de.hft.stuttgart.citydoctor2.datastructure.GmlElement
;
import
de.hft.stuttgart.citydoctor2.datastructure.LinkedPolygon
;
import
de.hft.stuttgart.citydoctor2.datastructure.Lod
;
import
de.hft.stuttgart.citydoctor2.datastructure.Polygon
;
public
class
HealMissingSolid
implements
HealingMethod
{
private
static
final
Logger
logger
=
LogManager
.
getLogger
(
HealMissingSolid
.
class
);
@Override
public
HealingMethod
createNew
()
{
return
new
HealMissingSolid
();
}
@Override
public
boolean
visit
(
AttributeMissingError
err
,
ModificationListener
l
)
{
logger
.
debug
(
"Executing Repair for AttributeMissingError"
);
if
(
err
.
getNameOfAttribute
().
equalsIgnoreCase
(
"lod1solid"
))
{
return
createSolid
(
err
.
getFeature
(),
Lod
.
LOD1
);
}
else
if
(
err
.
getNameOfAttribute
().
equalsIgnoreCase
(
"lod2solid"
))
{
return
createSolid
(
err
.
getFeature
(),
Lod
.
LOD2
);
}
else
if
(
err
.
getNameOfAttribute
().
equalsIgnoreCase
(
"lod3solid"
))
{
return
createSolid
(
err
.
getFeature
(),
Lod
.
LOD3
);
}
else
if
(
err
.
getNameOfAttribute
().
equalsIgnoreCase
(
"lod4solid"
))
{
return
createSolid
(
err
.
getFeature
(),
Lod
.
LOD4
);
}
else
if
(
err
.
getNameOfAttribute
().
equalsIgnoreCase
(
"any solid"
))
{
return
createSolid
(
err
.
getFeature
());
}
return
false
;
}
private
boolean
createSolid
(
GmlElement
feature
)
{
if
(
feature
instanceof
AbstractBuilding
ab
)
{
List
<
Polygon
>
findPolygons
=
collectPolygons
(
ab
);
if
(
findPolygons
.
isEmpty
())
{
return
false
;
}
Lod
highestLod
=
Lod
.
LOD1
;
for
(
Polygon
p
:
findPolygons
)
{
if
(
p
.
getParent
().
getLod
().
isHigher
(
highestLod
))
{
highestLod
=
p
.
getParent
().
getLod
();
}
}
return
createSolid
(
feature
,
highestLod
);
}
return
false
;
}
private
boolean
createSolid
(
GmlElement
feature
,
Lod
lod
)
{
if
(
feature
instanceof
Building
building
)
{
boolean
createdSolidInMainFeature
=
createSolidInFeature
(
lod
,
building
);
boolean
hasCreatedSolid
=
createdSolidInMainFeature
;
for
(
BuildingPart
part
:
building
.
getBuildingParts
())
{
boolean
createdSolidInPart
=
createSolidInFeature
(
lod
,
part
);
hasCreatedSolid
=
hasCreatedSolid
||
createdSolidInPart
;
}
return
hasCreatedSolid
;
}
else
if
(
feature
instanceof
BuildingPart
part
)
{
return
createSolidInFeature
(
lod
,
part
);
}
return
false
;
}
private
List
<
Polygon
>
collectPolygons
(
CityObject
co
)
{
List
<
Polygon
>
polygons
=
new
ArrayList
<>();
AbstractCheck
polygonCheck
=
new
AbstractCheck
()
{
@Override
public
void
check
(
Polygon
p
)
{
if
(!
p
.
isLink
())
{
polygons
.
add
(
p
);
}
}
};
co
.
accept
(
polygonCheck
);
return
polygons
;
}
private
boolean
createSolidInFeature
(
Lod
lod
,
AbstractBuilding
building
)
{
Geometry
geom
=
new
Geometry
(
GeometryType
.
SOLID
,
lod
);
List
<
Polygon
>
polygons
=
collectPolygons
(
building
,
lod
,
geom
);
for
(
Polygon
p
:
polygons
)
{
geom
.
addPolygon
(
p
);
}
if
(
geom
.
getPolygons
().
isEmpty
())
{
// no geometry has been created
return
false
;
}
// remove both solid and multisurface geometry
building
.
removeGeometry
(
lod
);
building
.
addGeometry
(
geom
);
return
true
;
}
private
List
<
Polygon
>
collectPolygons
(
AbstractBuilding
feature
,
Lod
lod
,
Geometry
solidGeometry
)
{
List
<
Polygon
>
polygons
=
new
ArrayList
<>();
// collect all concrete polygons from main geometry if any
for
(
Geometry
geom
:
feature
.
getGeometries
())
{
if
(
geom
.
getLod
().
equals
(
lod
))
{
for
(
Polygon
p
:
geom
.
getPolygons
())
{
if
(!
p
.
isLink
())
{
// concrete polygon, add to list
polygons
.
add
(
p
);
}
}
}
}
for
(
BoundarySurface
bs
:
feature
.
getBoundarySurfaces
())
{
collectPolygons
(
bs
,
lod
,
polygons
,
solidGeometry
);
}
for
(
Installation
bi
:
feature
.
getBuildingInstallations
())
{
collectPolygons
(
bi
,
lod
,
polygons
,
solidGeometry
);
for
(
BoundarySurface
bs
:
bi
.
getBoundarySurfaces
())
{
collectPolygons
(
bs
,
lod
,
polygons
,
solidGeometry
);
}
}
return
polygons
;
}
/**
* Only find concretePolygons and add them as link to the list
*
* @param co
* @param lod
* @param polygons
*/
private
void
collectPolygons
(
CityObject
co
,
Lod
lod
,
List
<
Polygon
>
polygons
,
Geometry
solidGeometry
)
{
for
(
Geometry
geom
:
co
.
getGeometries
())
{
if
(
geom
.
getLod
().
equals
(
lod
))
{
for
(
Polygon
p
:
geom
.
getPolygons
())
{
if
(
p
instanceof
ConcretePolygon
cp
)
{
// concrete polygon, create link and add to list
polygons
.
add
(
new
LinkedPolygon
(
cp
,
solidGeometry
));
}
}
}
}
}
@Override
public
HealingID
getID
()
{
return
HealingID
.
SE_MISSING_LOD2_SOLID
;
}
}
CityDoctorParent/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/healing/HealNonManifoldEdgeError.java
0 → 100644
View file @
ffdae21a
package
de.hft.stuttgart.citydoctor2.healing
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Map.Entry
;
import
java.util.concurrent.atomic.AtomicInteger
;
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.NonManifoldEdgeError
;
import
de.hft.stuttgart.citydoctor2.datastructure.Edge
;
import
de.hft.stuttgart.citydoctor2.datastructure.Polygon
;
import
de.hft.stuttgart.citydoctor2.datastructure.Vertex
;
import
de.hft.stuttgart.citydoctor2.math.Segment3d
;
import
de.hft.stuttgart.citydoctor2.math.Vector2d
;
import
de.hft.stuttgart.citydoctor2.math.Vector3d
;
import
de.hft.stuttgart.citydoctor2.utils.Pair
;
public
class
HealNonManifoldEdgeError
implements
HealingMethod
{
private
static
final
Logger
logger
=
LogManager
.
getLogger
(
HealNonManifoldEdgeError
.
class
);
@Override
public
boolean
visit
(
NonManifoldEdgeError
err
,
ModificationListener
l
)
{
logger
.
debug
(
"Executing Repair for NonManifoldEdgeError"
);
// count the number of manifold edges per polygon
Map
<
Polygon
,
AtomicInteger
>
errorCountMap
=
new
HashMap
<>();
for
(
Edge
e
:
err
.
getEdges
())
{
for
(
Polygon
p
:
e
.
getAdjacentPolygons
())
{
AtomicInteger
count
=
errorCountMap
.
computeIfAbsent
(
p
,
k
->
new
AtomicInteger
(
0
));
count
.
incrementAndGet
();
}
}
// find the polygons with the highest number of error edges
List
<
Pair
<
Polygon
,
AtomicInteger
>>
faultyPolygons
=
new
ArrayList
<>();
for
(
Entry
<
Polygon
,
AtomicInteger
>
e
:
errorCountMap
.
entrySet
())
{
faultyPolygons
.
add
(
new
Pair
<
Polygon
,
AtomicInteger
>(
e
.
getKey
(),
e
.
getValue
()));
}
Collections
.
sort
(
faultyPolygons
,
(
o1
,
o2
)
->
o2
.
getValue1
().
intValue
()
-
o1
.
getValue1
().
intValue
());
int
highestValue
=
faultyPolygons
.
get
(
0
).
getValue1
().
intValue
();
// remove the polygon with the highest amount, if it is the only one with the
// highest number
return
removeHighestPolygon
(
err
,
errorCountMap
,
faultyPolygons
,
highestValue
,
l
);
}
private
boolean
removePolygonWithWrongAngle
(
NonManifoldEdgeError
err
,
ModificationListener
l
)
{
Edge
errorEdge
=
err
.
getEdges
().
get
(
0
);
List
<
Polygon
>
polygons
=
errorEdge
.
getAdjacentPolygons
();
Segment3d
edgeSegment
=
new
Segment3d
(
errorEdge
.
getFrom
(),
errorEdge
.
getTo
());
List
<
Pair
<
Vector3d
,
Polygon
>>
normals
=
collectNormalsofAdjacentPolygons
(
errorEdge
,
polygons
,
edgeSegment
);
Vector3d
center
=
err
.
getGeometry
().
getCenter
();
Vector3d
centerNormal
=
edgeSegment
.
getNormalThroughPoint
(
center
);
Vector3d
edgeDir
=
errorEdge
.
getTo
().
minus
(
errorEdge
.
getFrom
());
double
x
=
Math
.
abs
(
edgeDir
.
getX
());
double
y
=
Math
.
abs
(
edgeDir
.
getY
());
double
z
=
Math
.
abs
(
edgeDir
.
getZ
());
Vector2d
projectedCenterNormal
;
List
<
Pair
<
Vector2d
,
Polygon
>>
projectedNormals
=
new
ArrayList
<>();
if
(
x
>
y
&&
x
>
z
)
{
for
(
Pair
<
Vector3d
,
Polygon
>
normal
:
normals
)
{
Vector3d
normalVec
=
normal
.
getValue0
();
Vector2d
projectedNormal
=
new
Vector2d
(
normalVec
.
getY
(),
normalVec
.
getZ
());
projectedNormal
.
normalize
();
projectedNormals
.
add
(
new
Pair
<>(
projectedNormal
,
normal
.
getValue1
()));
}
projectedCenterNormal
=
new
Vector2d
(
centerNormal
.
getY
(),
centerNormal
.
getZ
());
}
else
if
(
y
>
x
&&
y
>
z
)
{
for
(
Pair
<
Vector3d
,
Polygon
>
normal
:
normals
)
{
Vector3d
normalVec
=
normal
.
getValue0
();
Vector2d
projectedNormal
=
new
Vector2d
(
normalVec
.
getX
(),
normalVec
.
getZ
());
projectedNormal
.
normalize
();
projectedNormals
.
add
(
new
Pair
<>(
projectedNormal
,
normal
.
getValue1
()));
}
projectedCenterNormal
=
new
Vector2d
(
centerNormal
.
getX
(),
centerNormal
.
getZ
());
}
else
{
for
(
Pair
<
Vector3d
,
Polygon
>
normal
:
normals
)
{
Vector3d
normalVec
=
normal
.
getValue0
();
Vector2d
projectedNormal
=
new
Vector2d
(
normalVec
.
getX
(),
normalVec
.
getY
());
projectedNormal
.
normalize
();
projectedNormals
.
add
(
new
Pair
<>(
projectedNormal
,
normal
.
getValue1
()));
}
projectedCenterNormal
=
new
Vector2d
(
centerNormal
.
getX
(),
centerNormal
.
getY
());
}
projectedCenterNormal
.
normalize
();
double
normalAngle
=
Math
.
atan2
(
projectedCenterNormal
.
getY
(),
projectedCenterNormal
.
getX
());
removePolygonsWithWrongAngle
(
err
,
errorEdge
,
projectedNormals
,
normalAngle
,
l
);
return
true
;
}
private
void
removePolygonsWithWrongAngle
(
NonManifoldEdgeError
err
,
Edge
errorEdge
,
List
<
Pair
<
Vector2d
,
Polygon
>>
projectedNormals
,
double
normalAngle
,
ModificationListener
l
)
{
Polygon
lowestPolygon
=
null
;
Polygon
highestPolygon
=
null
;
double
lowestAngle
=
500
d
;
double
highestAngle
=
-
500
d
;
for
(
Pair
<
Vector2d
,
Polygon
>
normal
:
projectedNormals
)
{
Vector2d
normalVec
=
normal
.
getValue0
();
double
angle
=
Math
.
atan2
(
normalVec
.
getY
(),
normalVec
.
getX
());
angle
=
angle
-
normalAngle
;
if
(
angle
>
Math
.
PI
)
{
angle
-=
2
*
Math
.
PI
;
}
if
(
angle
<
Math
.
PI
)
{
angle
+=
2
*
Math
.
PI
;
}
if
(
angle
<
lowestAngle
)
{
lowestAngle
=
angle
;
lowestPolygon
=
normal
.
getValue1
();
}
if
(
angle
>
highestAngle
)
{
highestAngle
=
angle
;
highestPolygon
=
normal
.
getValue1
();
}
}
for
(
Polygon
p
:
errorEdge
.
getAdjacentPolygons
())
{
if
(
p
!=
lowestPolygon
&&
p
!=
highestPolygon
)
{
l
.
polygonRemoved
(
p
);
p
.
remove
();
return
;
}
}
}
private
List
<
Pair
<
Vector3d
,
Polygon
>>
collectNormalsofAdjacentPolygons
(
Edge
errorEdge
,
List
<
Polygon
>
polygons
,
Segment3d
edgeSegment
)
{
List
<
Pair
<
Vector3d
,
Polygon
>>
normals
=
new
ArrayList
<>();
for
(
Polygon
p
:
polygons
)
{
for
(
Vertex
v
:
p
.
getExteriorRing
().
getVertices
())
{
if
(
v
!=
errorEdge
.
getFrom
()
&&
v
!=
errorEdge
.
getTo
())
{
Vector3d
normal
=
edgeSegment
.
getNormalThroughPoint
(
v
);
normals
.
add
(
new
Pair
<>(
normal
,
p
));
break
;
}
}
}
return
normals
;
}
private
boolean
removeHighestPolygon
(
NonManifoldEdgeError
err
,
Map
<
Polygon
,
AtomicInteger
>
errorCountMap
,
List
<
Pair
<
Polygon
,
AtomicInteger
>>
faultyPolygons
,
int
highestValue
,
ModificationListener
l
)
{
if
(
faultyPolygons
.
get
(
1
).
getValue1
().
intValue
()
!=
highestValue
)
{
// remove faulty polygon
Polygon
poly
=
faultyPolygons
.
get
(
0
).
getValue0
();
l
.
polygonRemoved
(
poly
);
poly
.
remove
();
return
true
;
}
else
{
// two polygons have the same amount of error edges
// search for more error edges, where number of half edges is < 2 (not closed
// error)
searchForNotClosedEdges
(
err
,
errorCountMap
,
faultyPolygons
,
highestValue
);
// resort the polygons again
Collections
.
sort
(
faultyPolygons
,
(
o1
,
o2
)
->
o2
.
getValue1
().
intValue
()
-
o1
.
getValue1
().
intValue
());
highestValue
=
faultyPolygons
.
get
(
0
).
getValue1
().
intValue
();
if
(
faultyPolygons
.
get
(
1
).
getValue1
().
intValue
()
!=
highestValue
)
{
// remove faulty polygon
Polygon
poly
=
faultyPolygons
.
get
(
0
).
getValue0
();
l
.
polygonRemoved
(
poly
);
poly
.
remove
();
return
true
;
}
else
{
removePolygonWithWrongAngle
(
err
,
l
);
return
true
;
}
}
}
private
void
searchForNotClosedEdges
(
NonManifoldEdgeError
err
,
Map
<
Polygon
,
AtomicInteger
>
errorCountMap
,
List
<
Pair
<
Polygon
,
AtomicInteger
>>
faultyPolygons
,
int
highestValue
)
{
int
index
=
0
;
while
(
index
<
faultyPolygons
.
size
()
&&
faultyPolygons
.
get
(
index
).
getValue1
().
intValue
()
==
highestValue
)
{
Polygon
p
=
faultyPolygons
.
get
(
index
).
getValue0
();
List
<
Edge
>
edges
=
err
.
getGeometry
().
getEdgesAdjacentTo
(
p
);
for
(
Edge
e
:
edges
)
{
if
(
e
.
getNumberOfAllHalfEdges
()
<
2
)
{
// found another error edge
for
(
Polygon
temp
:
e
.
getAdjacentPolygons
())
{
AtomicInteger
count
=
errorCountMap
.
computeIfAbsent
(
temp
,
k
->
new
AtomicInteger
(
0
));
count
.
incrementAndGet
();
}
}
}
index
++;
}
}
@Override
public
HealNonManifoldEdgeError
createNew
()
{
return
new
HealNonManifoldEdgeError
();
}
@Override
public
HealingID
getID
()
{
return
HealingID
.
S_NON_MANIFOLD_EDGE
;
}
}
CityDoctorParent/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/healing/HealPlanarPolygonCpp.java
0 → 100644
View file @
ffdae21a
package
de.hft.stuttgart.citydoctor2.healing
;
import
java.util.ArrayList
;
import
java.util.List
;
import
org.apache.logging.log4j.LogManager
;
import
org.apache.logging.log4j.Logger
;
import
de.hft.stuttgart.citydoctor2.check.CheckId
;
import
de.hft.stuttgart.citydoctor2.check.CheckResult
;
import
de.hft.stuttgart.citydoctor2.check.ErrorId
;
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.ResultStatus
;
import
de.hft.stuttgart.citydoctor2.check.error.NonPlanarPolygonDistancePlaneError
;
import
de.hft.stuttgart.citydoctor2.connect.edge.CppFeature
;
import
de.hft.stuttgart.citydoctor2.connect.edge.CppHealResult
;
import
de.hft.stuttgart.citydoctor2.connect.edge.CppPolygonHealing
;
import
de.hft.stuttgart.citydoctor2.datastructure.Geometry
;
import
de.hft.stuttgart.citydoctor2.datastructure.Polygon
;
public
class
HealPlanarPolygonCpp
implements
HealingMethod
{
private
static
final
Logger
logger
=
LogManager
.
getLogger
(
HealPlanarPolygonCpp
.
class
);
@Override
public
HealingMethod
createNew
()
{
return
new
HealPlanarPolygonCpp
();
}
@Override
public
boolean
visit
(
NonPlanarPolygonDistancePlaneError
err
,
ModificationListener
l
)
{
logger
.
debug
(
"Executing Repair for NonPlanarPolygonDistancePlaneError"
);
// ----------------------------------------------
// get Geometry and Geometry informations
// ----------------------------------------------
Geometry
geometry
;
if
(
err
.
getPolygon
().
isLinkedTo
())
{
geometry
=
err
.
getPolygon
().
getLinkedFromPolygon
().
getParent
();
}
else
{
geometry
=
err
.
getPolygon
().
getParent
();
}
List
<
Integer
>
polyIdsList
=
new
ArrayList
<>();
for
(
int
i
=
0
;
i
<
geometry
.
getPolygons
().
size
();
i
++)
{
Polygon
p
=
geometry
.
getPolygons
().
get
(
i
);
CheckResult
cr
=
p
.
getCheckResult
(
CheckId
.
C_GE_P_NON_PLANAR
);
if
(
cr
.
getResultStatus
()
==
ResultStatus
.
ERROR
&&
cr
.
getError
().
getErrorId
()
==
ErrorId
.
GE_P_NON_PLANAR_POLYGON_DISTANCE_PLANE
)
{
polyIdsList
.
add
(
i
);
}
}
int
[]
polyIds
=
new
int
[
polyIdsList
.
size
()];
for
(
int
i
=
0
;
i
<
polyIdsList
.
size
();
i
++)
{
polyIds
[
i
]
=
polyIdsList
.
get
(
i
);
}
String
gmlId_string
=
geometry
.
getParent
().
getGmlId
().
toString
();
// ----------------------------------------------
// create feature and fill feature with geometry
// ----------------------------------------------
CppFeature
feature
=
new
CppFeature
(
gmlId_string
);
feature
.
setGeometry
(
geometry
);
feature
.
setLoD
(
geometry
.
getLod
());
// ----------------------------------------------
// start healing method
// ----------------------------------------------
CppPolygonHealing
cppPolygonHealing
=
new
CppPolygonHealing
(
feature
);
cppPolygonHealing
.
createCppObject
();
CppHealResult
healResult
=
cppPolygonHealing
.
healPlanarity
(
polyIds
);
if
(
healResult
.
isEmpty
())
return
false
;
healResult
.
mergeIntoGeometry
(
geometry
);
// ----------------------------------------------
// dispose cpp Objects
// ----------------------------------------------
cppPolygonHealing
.
disposeCppObject
();
feature
.
disposeCppObject
();
return
true
;
}
@Override
public
HealingID
getID
()
{
return
HealingID
.
P_NON_PLANAR_POLYGON_CPP
;
}
}
CityDoctorParent/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/healing/HealPlanarPolygonError.java
0 → 100644
View file @
ffdae21a
package
de.hft.stuttgart.citydoctor2.healing
;
import
java.util.HashSet
;
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.NonPlanarPolygonDistancePlaneError
;
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.math.Plane
;
import
de.hft.stuttgart.citydoctor2.math.Vector3d
;
public
class
HealPlanarPolygonError
implements
HealingMethod
{
private
static
final
Logger
logger
=
LogManager
.
getLogger
(
HealPlanarPolygonError
.
class
);
@Override
public
boolean
visit
(
NonPlanarPolygonDistancePlaneError
err
,
ModificationListener
l
)
{
logger
.
debug
(
"Executing Repair for NonPlanarPolygonDistancePlaneError"
);
Plane
plane
=
err
.
getPlane
();
Polygon
p
=
err
.
getPolygon
();
Set
<
Vertex
>
vertices
=
new
HashSet
<>();
// collect all vertices, eliminating duplicates
collectVertices
(
p
,
vertices
);
// project each vertex to the plane and change the coordinates of existing
// vertices
for
(
Vertex
v
:
vertices
)
{
Vector3d
newPoint
=
plane
.
projectPointToPlane
(
v
);
v
.
setX
(
newPoint
.
getX
());
v
.
setY
(
newPoint
.
getY
());
v
.
setZ
(
newPoint
.
getZ
());
}
return
true
;
}
private
void
collectVertices
(
Polygon
p
,
Set
<
Vertex
>
vertices
)
{
collectVertices
(
p
.
getExteriorRing
(),
vertices
);
for
(
LinearRing
lr
:
p
.
getInnerRings
())
{
collectVertices
(
lr
,
vertices
);
}
}
private
void
collectVertices
(
LinearRing
ring
,
Set
<
Vertex
>
vertices
)
{
for
(
Vertex
v
:
ring
.
getVertices
())
{
vertices
.
add
(
v
);
}
}
@Override
public
HealPlanarPolygonError
createNew
()
{
return
new
HealPlanarPolygonError
();
}
@Override
public
HealingID
getID
()
{
return
HealingID
.
P_NON_PLANAR_POLYGON
;
}
}
CityDoctorParent/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/healing/HealPolygonWithoutSurface.java
0 → 100644
View file @
ffdae21a
package
de.hft.stuttgart.citydoctor2.healing
;
import
org.citygml4j.core.model.construction.AbstractConstructionSurface
;
import
org.citygml4j.core.model.construction.GroundSurface
;
import
org.citygml4j.core.model.construction.RoofSurface
;
import
org.citygml4j.core.model.construction.WallSurface
;
import
org.citygml4j.core.model.core.AbstractSpaceBoundaryProperty
;
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.PolygonWithoutSurfaceError
;
import
de.hft.stuttgart.citydoctor2.datastructure.AbstractBuilding
;
import
de.hft.stuttgart.citydoctor2.datastructure.BoundarySurface
;
import
de.hft.stuttgart.citydoctor2.datastructure.BoundarySurfaceType
;
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.GeometryType
;
import
de.hft.stuttgart.citydoctor2.datastructure.LinkedPolygon
;
import
de.hft.stuttgart.citydoctor2.datastructure.Polygon
;
import
de.hft.stuttgart.citydoctor2.math.Vector3d
;
public
class
HealPolygonWithoutSurface
implements
HealingMethod
{
@Override
public
boolean
visit
(
PolygonWithoutSurfaceError
err
,
ModificationListener
l
)
{
Polygon
polygon
=
err
.
getPolygon
();
if
(!(
polygon
instanceof
ConcretePolygon
cp
))
{
return
false
;
}
CityObject
parent
=
polygon
.
getParent
().
getParent
();
if
(!(
parent
instanceof
AbstractBuilding
ab
))
{
return
false
;
}
Vector3d
n
=
polygon
.
calculateNormal
();
double
tilt
=
Math
.
acos
(
n
.
getZ
()
/
n
.
getLength
())
*
180
/
Math
.
PI
;
AbstractConstructionSurface
acs
;
BoundarySurface
bs
=
new
BoundarySurface
(
null
);
if
(
tilt
<
75.0
)
{
acs
=
new
RoofSurface
();
bs
.
setType
(
BoundarySurfaceType
.
ROOF
);
}
else
if
(
tilt
>
75.0
&&
tilt
<
170.0
)
{
acs
=
new
WallSurface
();
bs
.
setType
(
BoundarySurfaceType
.
WALL
);
}
else
if
(
tilt
>
170.0
)
{
acs
=
new
GroundSurface
();
bs
.
setType
(
BoundarySurfaceType
.
GROUND
);
}
else
{
return
false
;
}
bs
.
setGmlObject
(
acs
);
addBoundarySurfaceToBuilding
(
cp
,
ab
,
bs
);
ab
.
getGmlObject
().
getBoundaries
().
add
(
new
AbstractSpaceBoundaryProperty
(
acs
));
return
true
;
}
private
void
addBoundarySurfaceToBuilding
(
ConcretePolygon
cp
,
AbstractBuilding
ab
,
BoundarySurface
bs
)
{
Geometry
parentGeometry
=
cp
.
getParent
();
parentGeometry
.
getPolygons
().
remove
(
cp
);
ab
.
addBoundarySurface
(
bs
);
Geometry
geom
=
new
Geometry
(
GeometryType
.
MULTI_SURFACE
,
parentGeometry
.
getLod
());
bs
.
addGeometry
(
geom
);
geom
.
addPolygon
(
cp
);
parentGeometry
.
addPolygon
(
new
LinkedPolygon
(
cp
,
parentGeometry
));
}
@Override
public
HealingID
getID
()
{
return
HealingID
.
SE_POLYGON_WITHOUT_SURFACE
;
}
@Override
public
HealingMethod
createNew
()
{
return
new
HealPolygonWithoutSurface
();
}
}
CityDoctorParent/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/healing/HealPolygonWrongOrientationError.java
0 → 100644
View file @
ffdae21a
package
de.hft.stuttgart.citydoctor2.healing
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.HashMap
;
import
java.util.LinkedList
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Map.Entry
;
import
java.util.Random
;
import
java.util.concurrent.atomic.AtomicInteger
;
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.PolygonWrongOrientationError
;
import
de.hft.stuttgart.citydoctor2.datastructure.Edge
;
import
de.hft.stuttgart.citydoctor2.datastructure.LinearRing
;
import
de.hft.stuttgart.citydoctor2.datastructure.Polygon
;
import
de.hft.stuttgart.citydoctor2.utils.Pair
;
public
class
HealPolygonWrongOrientationError
implements
HealingMethod
{
private
static
final
Logger
logger
=
LogManager
.
getLogger
(
HealPolygonWrongOrientationError
.
class
);
private
Random
r
=
new
Random
();
@Override
public
boolean
visit
(
PolygonWrongOrientationError
err
,
ModificationListener
l
)
{
logger
.
debug
(
"Executing Repair for PolygonWrongOrientationError"
);
Map
<
Polygon
,
AtomicInteger
>
polygonCounter
=
new
HashMap
<>();
for
(
Edge
e
:
err
.
getEdges
())
{
for
(
Polygon
p
:
e
.
getAdjacentPolygons
())
{
AtomicInteger
counter
=
polygonCounter
.
computeIfAbsent
(
p
,
k
->
new
AtomicInteger
(
0
));
counter
.
incrementAndGet
();
}
}
LinkedList
<
Pair
<
Polygon
,
AtomicInteger
>>
data
=
new
LinkedList
<>();
for
(
Entry
<
Polygon
,
AtomicInteger
>
e
:
polygonCounter
.
entrySet
())
{
data
.
add
(
new
Pair
<>(
e
.
getKey
(),
e
.
getValue
()));
}
Collections
.
sort
(
data
,
(
o1
,
o2
)
->
o2
.
getValue1
().
get
()
-
o1
.
getValue1
().
get
());
Pair
<
Polygon
,
AtomicInteger
>
item
=
data
.
pop
();
// stupid random stuff
// attempt to avoid creating an endless loop in some cases by reversing the same
// polygon over and over again
// choose a polygon randomly from a list, all must have the same number of
// faulty edges connected to them
List
<
Pair
<
Polygon
,
AtomicInteger
>>
samePolygons
=
new
ArrayList
<>();
samePolygons
.
add
(
item
);
for
(
Pair
<
Polygon
,
AtomicInteger
>
temp
:
data
)
{
if
(
temp
.
getValue1
().
get
()
==
item
.
getValue1
().
get
())
{
samePolygons
.
add
(
temp
);
}
else
{
break
;
}
}
int
index
=
r
.
nextInt
(
samePolygons
.
size
());
Polygon
p
=
samePolygons
.
get
(
index
).
getValue0
();
Collections
.
reverse
(
p
.
getExteriorRing
().
getVertices
());
for
(
LinearRing
lr
:
p
.
getInnerRings
())
{
Collections
.
reverse
(
lr
.
getVertices
());
}
return
true
;
}
@Override
public
HealingMethod
createNew
()
{
return
new
HealPolygonWrongOrientationError
();
}
@Override
public
HealingID
getID
()
{
return
HealingID
.
S_POLYGON_WRONG_ORIENTATION
;
}
}
CityDoctorParent/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/healing/HealRingNotClosedError.java
0 → 100644
View file @
ffdae21a
package
de.hft.stuttgart.citydoctor2.healing
;
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.RingNotClosedError
;
import
de.hft.stuttgart.citydoctor2.datastructure.LinearRing
;
public
class
HealRingNotClosedError
implements
HealingMethod
{
private
static
final
Logger
logger
=
LogManager
.
getLogger
(
HealRingNotClosedError
.
class
);
@Override
public
boolean
visit
(
RingNotClosedError
err
,
ModificationListener
l
)
{
logger
.
debug
(
"Executing Repair for RingNotClosedError"
);
LinearRing
ring
=
err
.
getRing
();
// add another point to close the ring
// Geometry doesn't matter
// only used for adjacency, but vertex already contained in ring
ring
.
addVertex
(
ring
.
getVertices
().
get
(
0
));
return
true
;
}
@Override
public
HealRingNotClosedError
createNew
()
{
return
new
HealRingNotClosedError
();
}
@Override
public
HealingID
getID
()
{
return
HealingID
.
R_NOT_CLOSED
;
}
}
CityDoctorParent/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/healing/HealRingSelfIntError.java
0 → 100644
View file @
ffdae21a
package
de.hft.stuttgart.citydoctor2.healing
;
import
java.util.HashMap
;
import
java.util.Map
;
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.PointTouchesEdgeError
;
import
de.hft.stuttgart.citydoctor2.check.error.RingDuplicatePointError
;
import
de.hft.stuttgart.citydoctor2.check.error.RingEdgeIntersectionError
;
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.math.Vector3d
;
import
de.hft.stuttgart.citydoctor2.math.graph.KDTree
;
public
class
HealRingSelfIntError
implements
HealingMethod
{
private
static
final
Logger
logger
=
LogManager
.
getLogger
(
HealRingSelfIntError
.
class
);
@Override
public
boolean
visit
(
RingEdgeIntersectionError
err
,
ModificationListener
l
)
{
logger
.
info
(
"Executing Repair for RingEdgeIntersectionError"
);
// introduce a new vertex and create two rings out of one
LinearRing
r
=
err
.
getRing
();
Geometry
geom
=
r
.
getParent
().
getParent
();
LinearRing
r1
=
new
LinearRing
(
r
.
getType
());
LinearRing
r2
=
new
LinearRing
(
r
.
getType
());
// if exterior ring -> 2 new polygons, otherwise only 2 inner rings
if
(
err
.
getRing
().
getType
()
==
LinearRingType
.
EXTERIOR
)
{
ConcretePolygon
p1
=
new
ConcretePolygon
();
p1
.
setExteriorRing
(
r1
);
ConcretePolygon
p2
=
new
ConcretePolygon
();
p2
.
setExteriorRing
(
r2
);
geom
.
replacePolygon
(
err
.
getRing
().
getParent
(),
p1
,
p2
);
}
else
{
Polygon
parent
=
err
.
getRing
().
getParent
();
parent
.
removeInnerRing
(
err
.
getRing
());
parent
.
addInteriorRing
(
r1
);
parent
.
addInteriorRing
(
r2
);
}
LinearRing
currentRing
=
r1
;
Vertex
inter
=
new
Vertex
(
err
.
getIntersection
());
inter
=
checkDuplicatePoints
(
geom
,
inter
);
for
(
int
i
=
0
;
i
<
r
.
getVertices
().
size
()
-
1
;
i
++)
{
Vertex
v
=
r
.
getVertices
().
get
(
i
);
currentRing
.
addVertex
(
v
);
Vertex
nextV
=
r
.
getVertices
().
get
(
i
+
1
);
Edge
e1
=
err
.
getEdge1
();
Edge
e2
=
err
.
getEdge2
();
if
(
e1
.
formedByIgnoreDirection
(
v
,
nextV
)
||
e2
.
formedByIgnoreDirection
(
v
,
nextV
))
{
currentRing
.
addVertex
(
inter
);
// switch rings
if
(
currentRing
==
r1
)
{
currentRing
=
r2
;
}
else
{
currentRing
=
r1
;
}
}
}
// close both rings
r1
.
addVertex
(
r1
.
getVertices
().
get
(
0
));
r2
.
addVertex
(
r2
.
getVertices
().
get
(
0
));
return
true
;
}
private
Vertex
checkDuplicatePoints
(
Geometry
geom
,
Vertex
inter
)
{
KDTree
tree
=
new
KDTree
();
for
(
Vertex
v
:
geom
.
getVertices
())
{
tree
.
add
(
v
);
}
Vertex
newVertex
=
tree
.
getFirstNodeInRadius
(
inter
,
0.0001
);
if
(
newVertex
==
null
)
{
newVertex
=
inter
;
}
return
newVertex
;
}
@Override
public
boolean
visit
(
RingDuplicatePointError
err
,
ModificationListener
l
)
{
logger
.
info
(
"Executing Repair for RingDuplicatePointError"
);
LinearRing
r
=
err
.
getRing
();
// merge points together in case they are different
Vertex
duplicate1
=
err
.
getVertex1
();
Vertex
duplicate2
=
err
.
getVertex2
();
double
x
=
(
duplicate1
.
getX
()
+
duplicate2
.
getX
())
/
2
;
double
y
=
(
duplicate1
.
getY
()
+
duplicate2
.
getY
())
/
2
;
double
z
=
(
duplicate1
.
getZ
()
+
duplicate2
.
getZ
())
/
2
;
Vector3d
avgPoint
=
new
Vector3d
(
x
,
y
,
z
);
duplicate1
.
setX
(
avgPoint
.
getX
());
duplicate1
.
setY
(
avgPoint
.
getY
());
duplicate1
.
setZ
(
avgPoint
.
getZ
());
duplicate2
.
setX
(
avgPoint
.
getX
());
duplicate2
.
setY
(
avgPoint
.
getY
());
duplicate2
.
setZ
(
avgPoint
.
getZ
());
// create 2 new rings touching in the duplicate point
LinearRing
r1
=
new
LinearRing
(
r
.
getType
());
LinearRing
r2
=
new
LinearRing
(
r
.
getType
());
if
(
r
.
getType
()
==
LinearRingType
.
EXTERIOR
)
{
createNewPolygonsFromRings
(
r
,
r1
,
r2
);
}
else
{
// replace inner ring with two new ones
r
.
getParent
().
removeInnerRing
(
r
);
r
.
getParent
().
addInteriorRing
(
r1
);
r
.
getParent
().
addInteriorRing
(
r2
);
}
LinearRing
currentRing
=
r1
;
// do not use the last vertex
for
(
int
i
=
0
;
i
<
r
.
getVertices
().
size
()
-
1
;
i
++)
{
Vertex
v
=
r
.
getVertices
().
get
(
i
);
if
(
v
==
duplicate1
||
v
==
err
.
getVertex2
())
{
// switch rings
if
(
currentRing
==
r2
)
{
currentRing
=
r1
;
}
else
{
currentRing
=
r2
;
}
}
currentRing
.
addVertex
(
v
);
}
// close both rings
r1
.
addVertex
(
r1
.
getVertices
().
get
(
0
));
r2
.
addVertex
(
r2
.
getVertices
().
get
(
0
));
eliminateIdenticalPointsWithDifferentInstance
(
err
.
getRing
().
getParent
().
getParent
());
return
true
;
}
private
void
eliminateIdenticalPointsWithDifferentInstance
(
Geometry
geom
)
{
Map
<
Vertex
,
Vertex
>
vertexMap
=
new
HashMap
<>();
for
(
Polygon
p
:
geom
.
getPolygons
())
{
checkRing
(
p
.
getExteriorRing
(),
vertexMap
);
for
(
LinearRing
ring
:
p
.
getInnerRings
())
{
checkRing
(
ring
,
vertexMap
);
}
}
}
private
void
checkRing
(
LinearRing
ring
,
Map
<
Vertex
,
Vertex
>
vertexMap
)
{
for
(
int
i
=
0
;
i
<
ring
.
getVertices
().
size
();
i
++)
{
Vertex
v
=
ring
.
getVertices
().
get
(
i
);
if
(
vertexMap
.
containsKey
(
v
))
{
ring
.
getVertices
().
set
(
i
,
vertexMap
.
get
(
v
));
}
else
{
vertexMap
.
put
(
v
,
v
);
}
}
}
private
void
createNewPolygonsFromRings
(
LinearRing
r
,
LinearRing
r1
,
LinearRing
r2
)
{
Polygon
p
=
r
.
getParent
();
Geometry
geom
=
p
.
getParent
();
// create two new polygons
ConcretePolygon
p1
=
new
ConcretePolygon
();
p1
.
setExteriorRing
(
r1
);
ConcretePolygon
p2
=
new
ConcretePolygon
();
p2
.
setExteriorRing
(
r2
);
// replace the old polygon with the new ones
geom
.
replacePolygon
(
p
,
p1
,
p2
);
}
@Override
public
boolean
visit
(
PointTouchesEdgeError
err
,
ModificationListener
l
)
{
logger
.
debug
(
"Executing Repair for PointTouchesEdgeError"
);
Edge
e
=
err
.
getEdge
();
for
(
LinearRing
r
:
e
.
getAdjacentRings
())
{
int
index
=
-
1
;
for
(
int
i
=
0
;
i
<
r
.
getVertices
().
size
()
-
1
;
i
++)
{
Vertex
v1
=
r
.
getVertices
().
get
(
i
);
Vertex
v2
=
r
.
getVertices
().
get
(
i
+
1
);
if
(
e
.
getOppositeVertex
(
v1
)
==
v2
)
{
index
=
i
;
break
;
}
}
if
(
index
==
-
1
)
{
StringBuilder
sb
=
new
StringBuilder
(
"Ring does not contain edge.\n"
);
sb
.
append
(
"Ring: "
);
sb
.
append
(
r
.
getGmlId
().
toString
());
sb
.
append
(
'\n'
);
for
(
Vertex
v
:
r
.
getVertices
())
{
sb
.
append
(
v
);
sb
.
append
(
'\n'
);
}
sb
.
append
(
"Edge:"
);
sb
.
append
(
'\n'
);
sb
.
append
(
e
.
getFrom
());
sb
.
append
(
'\n'
);
sb
.
append
(
e
.
getTo
());
throw
new
IllegalStateException
(
sb
.
toString
());
}
r
.
getVertices
().
add
(
index
+
1
,
err
.
getVertex
());
}
return
true
;
}
@Override
public
HealRingSelfIntError
createNew
()
{
return
new
HealRingSelfIntError
();
}
@Override
public
HealingID
getID
()
{
return
HealingID
.
R_SELF_INTERSECTION
;
}
}
CityDoctorParent/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/healing/HealSameOrientationError.java
0 → 100644
View file @
ffdae21a
package
de.hft.stuttgart.citydoctor2.healing
;
import
java.util.Collections
;
import
java.util.List
;
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.PolygonSameOrientationError
;
import
de.hft.stuttgart.citydoctor2.datastructure.Vertex
;
public
class
HealSameOrientationError
implements
HealingMethod
{
private
static
final
Logger
logger
=
LogManager
.
getLogger
(
HealSameOrientationError
.
class
);
@Override
public
boolean
visit
(
PolygonSameOrientationError
err
,
ModificationListener
l
)
{
logger
.
debug
(
"Executing Repair for PolygonSameOrientationError"
);
List
<
Vertex
>
vertices
=
err
.
getInnerRing
().
getVertices
();
Collections
.
reverse
(
vertices
);
return
true
;
}
@Override
public
HealSameOrientationError
createNew
()
{
return
new
HealSameOrientationError
();
}
@Override
public
HealingID
getID
()
{
return
HealingID
.
P_SAME_ORIENTATION
;
}
}
CityDoctorParent/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/healing/HealSolidNotClosedCpp.java
0 → 100644
View file @
ffdae21a
package
de.hft.stuttgart.citydoctor2.healing
;
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.SolidNotClosedError
;
import
de.hft.stuttgart.citydoctor2.connect.edge.CppFeature
;
import
de.hft.stuttgart.citydoctor2.connect.edge.CppHealResult
;
import
de.hft.stuttgart.citydoctor2.connect.edge.CppPolygonHealing
;
import
de.hft.stuttgart.citydoctor2.datastructure.Geometry
;
public
class
HealSolidNotClosedCpp
implements
HealingMethod
{
private
static
final
Logger
logger
=
LogManager
.
getLogger
(
HealSolidNotClosedCpp
.
class
);
@Override
public
HealingMethod
createNew
()
{
return
new
HealSolidNotClosedCpp
();
}
@Override
public
boolean
visit
(
SolidNotClosedError
err
,
ModificationListener
l
)
{
logger
.
debug
(
"Executing Repair for PolygonSameOrientationError"
);
// Wenn auf CPP Seite implementiert dann das hier entfernen:
if
(
HealSolidNotClosedError
.
fixVerticesCloseToEdges
(
err
))
{
// maybe errors are fixed don't try other fixes until next iteration
return
true
;
}
// Bis hier
// ----------------------------------------------
// get Geometry and Geometry informations
// ----------------------------------------------
Geometry
geometry
=
err
.
getGeometry
();
String
gmlId_string
=
geometry
.
getParent
().
getGmlId
().
toString
();
// ----------------------------------------------
// create feature and fill feature with geometry
// ----------------------------------------------
CppFeature
feature
=
new
CppFeature
(
gmlId_string
);
// MeshSurface surface = MeshSurface.of(geometry);
// DebugUtils.printPolygon3d(surface.getPolygons().toArray(new CDPolygonNs[0]));
// DebugUtils.printGeoknechtPolygon(surface.getPolygons().toArray(new CDPolygonNs[0]));
feature
.
setGeometry
(
geometry
);
feature
.
setLoD
(
geometry
.
getLod
());
// ----------------------------------------------
// start healing method
// ----------------------------------------------
CppPolygonHealing
cppPolygonHealing
=
new
CppPolygonHealing
(
feature
);
cppPolygonHealing
.
createCppObject
();
CppHealResult
healResult
=
cppPolygonHealing
.
healSolidNotClosed
();
if
(
healResult
.
isEmpty
())
return
false
;
healResult
.
mergeIntoGeometry
(
geometry
);
// ----------------------------------------------
// dispose cpp Objects
// ----------------------------------------------
cppPolygonHealing
.
disposeCppObject
();
feature
.
disposeCppObject
();
return
true
;
}
@Override
public
HealingID
getID
()
{
return
HealingID
.
S_NOT_CLOSED_CPP
;
}
}
CityDoctorParent/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/healing/HealSolidNotClosedError.java
0 → 100644
View file @
ffdae21a
package
de.hft.stuttgart.citydoctor2.healing
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.LinkedList
;
import
java.util.List
;
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.SolidNotClosedError
;
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
;
import
de.hft.stuttgart.citydoctor2.math.Segment3d
;
import
de.hft.stuttgart.citydoctor2.math.Vector3d
;
public
class
HealSolidNotClosedError
implements
HealingMethod
{
private
static
final
Logger
logger
=
LogManager
.
getLogger
(
HealSolidNotClosedError
.
class
);
private
static
double
epsilon
=
0.1
;
@Override
public
boolean
visit
(
SolidNotClosedError
err
,
ModificationListener
l
)
{
logger
.
debug
(
"Executing Repair for SolidNotClosedError"
);
if
(
fixVerticesCloseToEdges
(
err
))
{
// maybe errors are fixed don't try other fixes until next iteration
return
true
;
}
return
fixMissingPolygons
(
err
);
}
private
boolean
fixMissingPolygons
(
SolidNotClosedError
err
)
{
if
(
err
.
getErrorEdges
().
size
()
<=
1
)
{
// what to do with only one edge? Impossible?
logger
.
error
(
"{} only has one error edge, cannot fix"
,
err
.
getGeometry
());
return
false
;
}
List
<
LinkedList
<
Edge
>>
candidatesForPolygon
=
new
ArrayList
<>();
for
(
Edge
e0
:
err
.
getErrorEdges
())
{
for
(
Edge
e1
:
err
.
getErrorEdges
())
{
if
(
e1
==
e0
)
{
// don't check same edge
continue
;
}
Vertex
v0
=
e0
.
getConnectionPoint
(
e1
);
if
(
v0
!=
null
)
{
// connected edges
Vector3d
ab
=
getVectorFromPoint
(
e0
,
v0
);
Vector3d
ac
=
getVectorFromPoint
(
e1
,
v0
);
Vector3d
norm
=
ab
.
cross
(
ac
);
Plane
plane
=
new
Plane
(
norm
,
v0
);
LinkedList
<
Edge
>
connectedEdges
=
new
LinkedList
<>();
connectedEdges
.
add
(
e0
);
connectedEdges
.
add
(
e1
);
// collect all other edges which are in the same plane and connected
collectEdgesConnectedAndInPlane
(
err
,
e0
,
e1
,
plane
,
connectedEdges
);
candidatesForPolygon
.
add
(
connectedEdges
);
}
}
}
// build a polygon for the side where the most edges are available
if
(
candidatesForPolygon
.
isEmpty
())
{
return
false
;
}
Collections
.
sort
(
candidatesForPolygon
,
(
o1
,
o2
)
->
o2
.
size
()
-
o1
.
size
());
LinkedList
<
Edge
>
candidate
=
candidatesForPolygon
.
get
(
0
);
// build a new polygon out of the connected edges
buildPolygonFromEdges
(
err
.
getGeometry
(),
candidate
);
// have added a polygon, don't try to add more in this iteration
return
true
;
}
private
void
buildPolygonFromEdges
(
Geometry
geom
,
LinkedList
<
Edge
>
connectedEdges
)
{
Polygon
p
=
new
ConcretePolygon
();
geom
.
addPolygon
(
p
);
LinearRing
ext
=
new
LinearRing
(
LinearRingType
.
EXTERIOR
);
p
.
setExteriorRing
(
ext
);
// edges form a loop?
EdgeGraph
graph
=
new
EdgeGraph
();
for
(
Edge
e
:
connectedEdges
)
{
graph
.
addEdge
(
e
,
connectedEdges
);
}
List
<
List
<
Edge
>>
cycles
=
graph
.
getCycles
();
// edges form a loop when nr edges >= nr vertices
if
(!
cycles
.
isEmpty
())
{
// loop
createRingFromLoop
(
cycles
.
get
(
0
),
ext
);
}
else
{
// no cycle means open ring
createRingFromNotClosedEdges
(
connectedEdges
,
ext
);
}
}
private
void
createRingFromNotClosedEdges
(
List
<
Edge
>
connectedEdges
,
LinearRing
ext
)
{
Edge
firstEdge
=
connectedEdges
.
get
(
0
);
connectedEdges
.
remove
(
0
);
ext
.
addVertex
(
firstEdge
.
getFrom
());
ext
.
addVertex
(
firstEdge
.
getTo
());
Vertex
currentVertex
=
firstEdge
.
getTo
();
boolean
insertAtEnd
=
true
;
while
(!
connectedEdges
.
isEmpty
())
{
boolean
addedEdge
=
false
;
for
(
Edge
e
:
connectedEdges
)
{
Vertex
oppositeV
=
e
.
getOppositeVertex
(
currentVertex
);
if
(
oppositeV
!=
null
)
{
// found a connected edge
// insert point depending where the edge is connected
insertPointIntoRing
(
ext
,
insertAtEnd
,
oppositeV
);
currentVertex
=
oppositeV
;
connectedEdges
.
remove
(
e
);
addedEdge
=
true
;
break
;
}
}
if
(!
addedEdge
)
{
if
(!
insertAtEnd
)
{
// could not add more edges to lr, stop here
// close ring
ext
.
addVertex
(
ext
.
getVertices
().
get
(
0
));
return
;
}
// no more edges in this direction, go the other direction
insertAtEnd
=
false
;
currentVertex
=
firstEdge
.
getFrom
();
}
}
// close ring
ext
.
addVertex
(
ext
.
getVertices
().
get
(
0
));
}
private
void
insertPointIntoRing
(
LinearRing
ext
,
boolean
insertAtEnd
,
Vertex
oppositeV
)
{
if
(
insertAtEnd
)
{
ext
.
addVertex
(
oppositeV
);
}
else
{
// insert at the beginning
ext
.
addVertex
(
0
,
oppositeV
);
}
}
private
void
createRingFromLoop
(
List
<
Edge
>
connectedEdges
,
LinearRing
ext
)
{
Edge
firstEdge
=
connectedEdges
.
get
(
0
);
connectedEdges
.
remove
(
0
);
ext
.
addVertex
(
firstEdge
.
getFrom
());
ext
.
addVertex
(
firstEdge
.
getTo
());
Vertex
currentVertex
=
firstEdge
.
getTo
();
while
(!
connectedEdges
.
isEmpty
())
{
boolean
addedEdge
=
false
;
for
(
Edge
e
:
connectedEdges
)
{
Vertex
oppositeV
=
e
.
getOppositeVertex
(
currentVertex
);
if
(
oppositeV
!=
null
)
{
ext
.
addVertex
(
oppositeV
);
currentVertex
=
oppositeV
;
connectedEdges
.
remove
(
e
);
addedEdge
=
true
;
break
;
}
}
if
(!
addedEdge
)
{
return
;
}
}
}
private
void
collectEdgesConnectedAndInPlane
(
SolidNotClosedError
err
,
Edge
e0
,
Edge
e1
,
Plane
plane
,
LinkedList
<
Edge
>
connectedEdges
)
{
for
(
Edge
e2
:
err
.
getErrorEdges
())
{
if
(
e2
==
e0
||
e2
==
e1
)
{
// don't check the starting edges
continue
;
}
boolean
connected
=
isConnectedToEdges
(
connectedEdges
,
e2
);
if
(
connected
&&
plane
.
getDistance
(
e2
.
getTo
())
<
epsilon
&&
plane
.
getDistance
(
e2
.
getFrom
())
<
epsilon
)
{
// edge is in plane and connected
connectedEdges
.
add
(
e2
);
}
}
}
private
boolean
isConnectedToEdges
(
List
<
Edge
>
connectedEdges
,
Edge
e2
)
{
for
(
Edge
planeEdge
:
connectedEdges
)
{
if
(
planeEdge
.
getConnectionPoint
(
e2
)
!=
null
)
{
return
true
;
}
}
return
false
;
}
private
Vector3d
getVectorFromPoint
(
Edge
e0
,
Vertex
v0
)
{
Vector3d
ab
;
if
(
v0
==
e0
.
getTo
())
{
ab
=
e0
.
getFrom
().
minus
(
v0
);
}
else
{
ab
=
e0
.
getTo
().
minus
(
v0
);
}
return
ab
;
}
public
static
boolean
fixVerticesCloseToEdges
(
SolidNotClosedError
err
)
{
boolean
changed
=
false
;
Geometry
geom
=
err
.
getGeometry
();
for
(
Edge
e
:
err
.
getErrorEdges
())
{
Segment3d
seg
=
new
Segment3d
(
e
.
getFrom
(),
e
.
getTo
());
for
(
Vertex
v
:
geom
.
getVertices
())
{
if
(
v
==
e
.
getFrom
()
||
v
==
e
.
getTo
())
{
continue
;
}
// check if there is an edge adjacent to the vertex that goes in the same
// direction
if
(
seg
.
getDistance
(
v
)
<
epsilon
&&
doParallelEdgesExist
(
geom
,
seg
,
v
))
{
addVertexToEdge
(
e
,
v
);
changed
=
true
;
}
}
}
return
changed
;
}
private
static
boolean
doParallelEdgesExist
(
Geometry
geom
,
Segment3d
seg
,
Vertex
v
)
{
Vector3d
dir
=
seg
.
getPointB
().
minus
(
seg
.
getPointA
());
dir
=
dir
.
normalize
();
for
(
Edge
e2
:
geom
.
getEdgesAdjacentTo
(
v
))
{
Vector3d
dir2
=
e2
.
getTo
().
minus
(
e2
.
getFrom
());
dir2
=
dir2
.
normalize
();
if
(
Math
.
abs
(
dir2
.
dot
(
dir
))
>
0.99
)
{
// at least one edge is parallel
return
true
;
}
}
return
false
;
}
private
static
void
addVertexToEdge
(
Edge
e
,
Vertex
v
)
{
for
(
LinearRing
lr
:
e
.
getAdjacentRings
())
{
for
(
int
i
=
0
;
i
<
lr
.
getVertices
().
size
()
-
1
;
i
++)
{
Vertex
v1
=
lr
.
getVertices
().
get
(
i
);
Vertex
v2
=
lr
.
getVertices
().
get
(
i
+
1
);
if
(
e
.
formedByIgnoreDirection
(
v1
,
v2
))
{
lr
.
addVertex
(
i
+
1
,
v
);
break
;
}
}
}
}
@Override
public
HealSolidNotClosedError
createNew
()
{
return
new
HealSolidNotClosedError
();
}
@Override
public
HealingID
getID
()
{
return
HealingID
.
S_NOT_CLOSED
;
}
}
CityDoctorParent/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/healing/HealTooFewPoints.java
0 → 100644
View file @
ffdae21a
package
de.hft.stuttgart.citydoctor2.healing
;
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.RingTooFewPointsError
;
import
de.hft.stuttgart.citydoctor2.datastructure.LinearRing
;
import
de.hft.stuttgart.citydoctor2.datastructure.LinearRing.LinearRingType
;
public
class
HealTooFewPoints
implements
HealingMethod
{
private
static
final
Logger
logger
=
LogManager
.
getLogger
(
HealTooFewPoints
.
class
);
@Override
public
boolean
visit
(
RingTooFewPointsError
err
,
ModificationListener
l
)
{
logger
.
debug
(
"Executing Repair for RingTooFewPointsError"
);
LinearRing
ring
=
err
.
getRing
();
// ring is only a line, remove ring
if
(
ring
.
getType
()
==
LinearRingType
.
INTERIOR
)
{
ring
.
getParent
().
removeInnerRing
(
ring
);
}
else
{
// remove whole polygon
ring
.
getParent
().
remove
();
}
return
true
;
}
@Override
public
HealTooFewPoints
createNew
()
{
return
new
HealTooFewPoints
();
}
@Override
public
HealingID
getID
()
{
return
HealingID
.
R_TOO_FEW_POINTS
;
}
}
CityDoctorParent/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/healing/HealWrongDormers.java
0 → 100644
View file @
ffdae21a
package
de.hft.stuttgart.citydoctor2.healing
;
import
java.util.List
;
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.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.math.Plane
;
import
de.hft.stuttgart.citydoctor2.math.Vector3d
;
public
class
HealWrongDormers
implements
HealingMethod
{
private
static
final
Logger
logger
=
LogManager
.
getLogger
(
HealWrongDormers
.
class
);
private
static
final
double
EPSILON
=
0.2
;
@Override
public
boolean
visit
(
MultipleConnectedComponentsError
err
,
ModificationListener
l
)
{
logger
.
debug
(
"Executing Repair for MultipleConnectedComponentsError"
);
for
(
int
i
=
0
;
i
<
err
.
getComponents
().
size
()
-
1
;
i
++)
{
List
<
Polygon
>
component1
=
err
.
getComponents
().
get
(
i
);
for
(
int
j
=
i
+
1
;
j
<
err
.
getComponents
().
size
();
j
++)
{
List
<
Polygon
>
component2
=
err
.
getComponents
().
get
(
j
);
if
(
checkForOverlappingPolygons
(
component1
,
component2
))
{
return
true
;
}
}
}
return
false
;
}
private
boolean
checkForOverlappingPolygons
(
List
<
Polygon
>
component1
,
List
<
Polygon
>
component2
)
{
for
(
Polygon
p1
:
component1
)
{
for
(
Polygon
p2
:
component2
)
{
if
(
isPolygonInOtherPolygon
(
p1
,
p2
))
{
// p1 is in p2
createInnerRing
(
p1
,
p2
);
return
true
;
}
if
(
isPolygonInOtherPolygon
(
p2
,
p1
))
{
// p2 is in p1
createInnerRing
(
p2
,
p1
);
return
true
;
}
}
}
return
false
;
}
private
void
createInnerRing
(
Polygon
poly1
,
Polygon
poly2
)
{
LinearRing
innerRing
=
new
LinearRing
(
LinearRingType
.
INTERIOR
);
poly2
.
addInteriorRing
(
innerRing
);
for
(
Vertex
v
:
poly1
.
getExteriorRing
().
getVertices
())
{
innerRing
.
addVertex
(
v
);
}
poly1
.
remove
();
}
private
boolean
isPolygonInOtherPolygon
(
Polygon
poly1
,
Polygon
poly2
)
{
Plane
plane
=
calculatePlane
(
poly2
);
for
(
Vertex
v
:
poly1
.
getExteriorRing
().
getVertices
())
{
if
(
plane
.
getDistance
(
v
)
>
EPSILON
||
!
poly2
.
isPointInsideExteriorRing
(
v
))
{
return
false
;
}
}
return
true
;
}
private
Plane
calculatePlane
(
Polygon
p
)
{
Vector3d
normal
=
p
.
calculateNormalNormalized
();
return
new
Plane
(
normal
,
p
.
getExteriorRing
().
getVertices
().
get
(
0
));
}
@Override
public
HealWrongDormers
createNew
()
{
return
new
HealWrongDormers
();
}
@Override
public
HealingID
getID
()
{
return
HealingID
.
S_WRONG_DORMERS
;
}
}
CityDoctorParent/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/healing/math/EdgeGraph.java
0 → 100644
View file @
ffdae21a
package
de.hft.stuttgart.citydoctor2.healing.math
;
import
java.util.ArrayList
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
de.hft.stuttgart.citydoctor2.datastructure.Edge
;
public
class
EdgeGraph
{
private
Map
<
Edge
,
EdgeNode
>
nodes
=
new
HashMap
<>();
public
void
addEdge
(
Edge
e
,
List
<
Edge
>
edges
)
{
if
(
nodes
.
containsKey
(
e
))
{
return
;
}
EdgeNode
node
=
new
EdgeNode
(
e
);
nodes
.
put
(
e
,
node
);
for
(
Edge
childEdge
:
getEdgesConnected
(
e
,
edges
))
{
EdgeNode
childNode
=
nodes
.
get
(
childEdge
);
if
(
childNode
!=
null
&&
childNode
!=
node
)
{
node
.
addChild
(
childNode
);
childNode
.
addChild
(
node
);
}
}
}
private
List
<
Edge
>
getEdgesConnected
(
Edge
e
,
List
<
Edge
>
edges
)
{
List
<
Edge
>
result
=
new
ArrayList
<>();
for
(
Edge
potentialEdge
:
edges
)
{
if
(
potentialEdge
.
getConnectionPoint
(
e
)
!=
null
)
{
result
.
add
(
potentialEdge
);
}
}
return
result
;
}
public
List
<
List
<
Edge
>>
getCycles
()
{
List
<
List
<
Edge
>>
cycles
=
new
ArrayList
<>();
for
(
EdgeNode
n
:
nodes
.
values
())
{
List
<
Edge
>
edges
=
new
ArrayList
<>();
n
.
collectConnectedEdges
(
edges
,
null
);
if
(
edges
.
size
()
>
2
)
{
cycles
.
add
(
edges
);
}
}
return
cycles
;
}
}
CityDoctorParent/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/healing/math/EdgeNode.java
0 → 100644
View file @
ffdae21a
package
de.hft.stuttgart.citydoctor2.healing.math
;
import
java.util.ArrayList
;
import
java.util.List
;
import
de.hft.stuttgart.citydoctor2.datastructure.Edge
;
public
class
EdgeNode
{
private
Edge
e
;
private
boolean
visited
=
false
;
public
boolean
finished
=
false
;
private
List
<
EdgeNode
>
children
=
new
ArrayList
<>();
public
EdgeNode
(
Edge
e
)
{
this
.
e
=
e
;
}
public
void
resetVisit
()
{
visited
=
false
;
}
public
Edge
getEdge
()
{
return
e
;
}
public
void
addChild
(
EdgeNode
childNode
)
{
children
.
add
(
childNode
);
}
public
List
<
EdgeNode
>
getChildren
()
{
return
children
;
}
public
boolean
collectConnectedEdges
(
List
<
Edge
>
edges
,
EdgeNode
parent
)
{
if
(
finished
)
{
return
false
;
}
if
(
visited
)
{
createCycle
(
edges
);
return
true
;
}
visited
=
true
;
edges
.
add
(
e
);
for
(
EdgeNode
n
:
children
)
{
if
(
n
!=
parent
&&
n
.
collectConnectedEdges
(
edges
,
this
))
{
// found cycle
return
true
;
}
}
edges
.
remove
(
edges
.
size
()
-
1
);
finished
=
true
;
return
false
;
}
private
void
createCycle
(
List
<
Edge
>
edges
)
{
for
(
int
i
=
0
;
i
<
edges
.
size
();
i
++)
{
Edge
compare
=
edges
.
get
(
i
);
if
(
compare
==
e
)
{
for
(
int
j
=
0
;
j
<
i
;
j
++)
{
edges
.
remove
(
0
);
}
}
}
}
}
CityDoctorParent/CityDoctorHealer/src/main/java/de/hft/stuttgart/citydoctor2/optimization/MeshGenerator.java
0 → 100644
View file @
ffdae21a
/*-
* 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.optimization
;
import
java.util.ArrayList
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Map.Entry
;
import
de.hft.stuttgart.citydoctor2.datastructure.BoundarySurface
;
import
de.hft.stuttgart.citydoctor2.datastructure.Building
;
import
de.hft.stuttgart.citydoctor2.datastructure.Installation
;
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.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.math.Triangle3d
;
import
de.hft.stuttgart.citydoctor2.math.Vector3d
;
import
de.hft.stuttgart.citydoctor2.tesselation.TesselatedPolygon
;
public
class
MeshGenerator
{
private
static
final
double
EPSILON
=
0.0001
;
private
MeshGenerator
()
{
}
public
static
void
replaceGeometryWithMeshedGeometry
(
Building
b
,
double
maxArea
)
{
replacePolygonsInGeometry
(
b
,
maxArea
);
for
(
BoundarySurface
bs
:
b
.
getBoundarySurfaces
())
{
replacePolygonsInGeometry
(
bs
,
maxArea
);
}
for
(
Installation
bi
:
b
.
getBuildingInstallations
())
{
replacePolygonsInGeometry
(
bi
,
maxArea
);
for
(
BoundarySurface
bs
:
bi
.
getBoundarySurfaces
())
{
replacePolygonsInGeometry
(
bs
,
maxArea
);
}
}
}
private
static
void
replacePolygonsInGeometry
(
CityObject
co
,
double
maxArea
)
{
for
(
Geometry
geom
:
co
.
getGeometries
())
{
Map
<
Polygon
,
List
<
ConcretePolygon
>>
replacementPolys
=
new
HashMap
<>();
for
(
Polygon
p
:
geom
.
getPolygons
())
{
if
(!
p
.
isLink
()
&&
(
p
.
getExteriorRing
().
getVertices
().
size
()
>
4
||
!
p
.
getInnerRings
().
isEmpty
()))
{
TesselatedPolygon
tesselate
=
p
.
tesselate
();
List
<
ConcretePolygon
>
newPolys
=
new
ArrayList
<>();
for
(
Triangle3d
t
:
tesselate
.
getTriangles
())
{
addTriangles
(
t
,
maxArea
,
newPolys
);
}
replacementPolys
.
put
(
p
,
newPolys
);
}
}
for
(
Entry
<
Polygon
,
List
<
ConcretePolygon
>>
r
:
replacementPolys
.
entrySet
())
{
geom
.
replacePolygon
(
r
.
getKey
(),
r
.
getValue
().
toArray
(
new
ConcretePolygon
[
r
.
getValue
().
size
()]));
}
}
}
private
static
void
addTriangles
(
Triangle3d
t
,
double
precision
,
List
<
ConcretePolygon
>
newPolys
)
{
double
area
=
t
.
getArea
();
if
(
area
>
precision
)
{
double
dis1
=
t
.
getP1
().
getDistance
(
t
.
getP2
());
double
dis2
=
t
.
getP2
().
getDistance
(
t
.
getP3
());
double
dis3
=
t
.
getP1
().
getDistance
(
t
.
getP3
());
if
(
dis1
>=
dis2
&&
dis1
>=
dis3
)
{
splitTriangles
(
t
.
getP1
(),
t
.
getP2
(),
t
.
getP3
(),
precision
,
newPolys
);
return
;
}
if
(
dis2
>=
dis1
&&
dis2
>=
dis3
)
{
splitTriangles
(
t
.
getP2
(),
t
.
getP3
(),
t
.
getP1
(),
precision
,
newPolys
);
return
;
}
splitTriangles
(
t
.
getP3
(),
t
.
getP1
(),
t
.
getP2
(),
precision
,
newPolys
);
}
else
if
(
area
>
EPSILON
)
{
ConcretePolygon
newPoly
=
new
ConcretePolygon
();
LinearRing
ext
=
new
LinearRing
(
LinearRingType
.
EXTERIOR
);
newPoly
.
setExteriorRing
(
ext
);
Vertex
v1
=
new
Vertex
(
t
.
getP1
());
ext
.
addVertex
(
v1
);
ext
.
addVertex
(
new
Vertex
(
t
.
getP2
()));
ext
.
addVertex
(
new
Vertex
(
t
.
getP3
()));
ext
.
addVertex
(
v1
);
newPolys
.
add
(
newPoly
);
}
}
private
static
void
splitTriangles
(
Vector3d
v0
,
Vector3d
v1
,
Vector3d
v2
,
double
precision
,
List
<
ConcretePolygon
>
newPolys
)
{
double
x
=
0.5
*
(
v0
.
getX
()
+
v1
.
getX
());
double
y
=
0.5
*
(
v0
.
getY
()
+
v1
.
getY
());
double
z
=
0.5
*
(
v0
.
getZ
()
+
v1
.
getZ
());
Vector3d
vNeu
=
new
Vector3d
(
x
,
y
,
z
);
Triangle3d
tNeu1
=
new
Triangle3d
(
v0
,
vNeu
,
v2
);
Triangle3d
tNeu2
=
new
Triangle3d
(
v2
,
vNeu
,
v1
);
addTriangles
(
tNeu1
,
precision
,
newPolys
);
addTriangles
(
tNeu2
,
precision
,
newPolys
);
}
}
CityDoctorParent/CityDoctorHealer/src/test/java/de/hft/stuttgart/citydoctor2/healer/HealingTestUtil.java
0 → 100644
View file @
ffdae21a
package
de.hft.stuttgart.citydoctor2.healer
;
import
java.io.IOException
;
import
de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel
;
import
de.hft.stuttgart.citydoctor2.parser.CityGmlParseException
;
import
de.hft.stuttgart.citydoctor2.parser.ParserConfiguration
;
import
de.hft.stuttgart.citydoctor2.parser.CityGmlParser
;
import
de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException
;
public
class
HealingTestUtil
{
private
HealingTestUtil
()
{
// only static access
}
public
static
CityDoctorModel
loadCityModel
(
String
path
)
throws
CityGmlParseException
,
IOException
,
InvalidGmlFileException
{
ParserConfiguration
config
=
new
ParserConfiguration
(
8
,
false
);
CityDoctorModel
m
=
CityGmlParser
.
parseCityGmlFile
(
path
,
config
);
return
m
;
}
}
Prev
1
2
3
4
5
6
7
…
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