Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
CircularGreenSimCity
CircularGreenSimCity
Commits
1e3e7d11
Commit
1e3e7d11
authored
Feb 17, 2025
by
Eric Duminil
Browse files
Using PicoCli for GreenEnricher
parent
5621631f
Changes
2
Hide whitespace changes
Inline
Side-by-side
enrich-citygml-with-greenarea/pom.xml
View file @
1e3e7d11
...
...
@@ -23,8 +23,8 @@
</releases>
</repository>
</repositories>
<build>
<plugins>
<plugin>
...
...
@@ -87,5 +87,12 @@
<artifactId>
citygml4j-xml
</artifactId>
<version>
3.0.0-rc.5
</version>
</dependency>
<!-- https://mvnrepository.com/artifact/info.picocli/picocli -->
<dependency>
<groupId>
info.picocli
</groupId>
<artifactId>
picocli
</artifactId>
<version>
4.6.1
</version>
</dependency>
</dependencies>
</project>
\ No newline at end of file
</project>
enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/GreenEnricher.java
View file @
1e3e7d11
...
...
@@ -46,7 +46,6 @@ import org.locationtech.jts.geom.LineString;
import
org.locationtech.jts.geom.MultiPolygon
;
import
org.locationtech.jts.geom.Point
;
import
org.locationtech.jts.geom.Polygon
;
import
org.locationtech.jts.io.ParseException
;
import
org.locationtech.jts.io.WKTReader
;
import
org.locationtech.proj4j.BasicCoordinateTransform
;
import
org.locationtech.proj4j.CRSFactory
;
...
...
@@ -71,10 +70,32 @@ import de.hft.stuttgart.citygml.green.osm.jaxb.OsmWay;
import
de.hft.stuttgart.citygml.green.osm.jaxb.WayNode
;
import
jakarta.xml.bind.JAXBContext
;
import
jakarta.xml.bind.JAXBException
;
import
picocli.CommandLine
;
import
picocli.CommandLine.Command
;
import
picocli.CommandLine.Option
;
import
picocli.CommandLine.Parameters
;
public
class
GreenEnricher
@Command
(
name
=
"GreenEnricher"
,
mixinStandardHelpOptions
=
true
,
version
=
"GreenEnricher 1.0"
,
description
=
"Enriches CityGML files with green areas using OSM data."
)
public
class
GreenEnricher
implements
Runnable
{
@Parameters
(
index
=
"0"
,
description
=
"The input CityGML file."
)
private
Path
citygmlInput
;
@Parameters
(
index
=
"1"
,
description
=
"The input shapefile with trees, in Baumkataster format."
)
private
Path
treeShapefileInput
;
@Parameters
(
index
=
"2"
,
description
=
"The suffix which should be added to the input CityGML filename."
)
private
String
outputSuffix
;
@Option
(
names
=
{
"-w"
,
"--wkt"
},
description
=
"Optional WKT polygon to cut the region after processing."
)
private
String
wkt
;
public
static
void
main
(
String
[]
args
)
{
int
exitCode
=
new
CommandLine
(
new
GreenEnricher
()).
execute
(
args
);
System
.
exit
(
exitCode
);
}
private
static
final
int
BOUNDING_BOX_INCREASE_IN_M
=
100
;
// in degrees
...
...
@@ -113,79 +134,79 @@ public class GreenEnricher
private
static
BasicCoordinateTransform
backTransform
;
public
static
final
GeometryFactory
GEOM_FACTORY
=
new
GeometryFactory
();
public
static
void
main
(
String
[]
args
)
throws
IOException
,
CityGMLContextException
,
CityGMLReadException
,
InterruptedException
,
CityGMLWriteException
,
JAXBException
,
ParseException
{
System
.
out
.
println
(
"Reading CityGML file"
);
Path
inFile
=
Paths
.
get
(
args
[
0
]);
Path
baumKatasterPath
=
Paths
.
get
(
args
[
1
]);
String
outputSuffix
=
args
[
2
];
Polygon
wktPolygon
=
null
;
if
(
args
.
length
==
4
)
{
WKTReader
wktReader
=
new
WKTReader
();
Geometry
wktGeometry
=
wktReader
.
read
(
args
[
3
]);
if
(!(
wktGeometry
instanceof
Polygon
))
{
throw
new
IllegalArgumentException
(
"WKT is not a polygon"
);
}
wktPolygon
=
(
Polygon
)
wktGeometry
;
CoordinateReferenceSystem
utm32
=
CRS_FACTORY
.
createFromName
(
"EPSG:25832"
);
BasicCoordinateTransform
bct
=
new
BasicCoordinateTransform
(
wgs84
,
utm32
);
wktPolygon
.
apply
((
CoordinateFilter
)
c
->
{
ProjCoordinate
p1
=
new
ProjCoordinate
();
p1
.
x
=
c
.
x
;
p1
.
y
=
c
.
y
;
ProjCoordinate
p2
=
new
ProjCoordinate
();
bct
.
transform
(
p1
,
p2
);
c
.
x
=
p2
.
x
;
c
.
y
=
p2
.
y
;
});
wktPolygon
.
geometryChanged
();
}
CityModel
cityModel
=
readCityGml
(
inFile
);
createTransformers
(
cityModel
);
OsmData
osmData
=
new
OsmData
();
String
boundingBoxString
=
GreenEnricher
.
extractAndConvertBoundingBox
(
cityModel
,
osmData
);
String
boundingBoxBasename
=
boundingBoxString
.
replace
(
","
,
"__"
).
replace
(
'.'
,
'_'
);
Path
osmCache
=
Paths
.
get
(
"data"
,
"cache"
,
"osm_response_"
+
boundingBoxBasename
+
".xml"
);
if
(!
Files
.
exists
(
osmCache
))
{
System
.
out
.
println
(
"Downloading OSM data for "
+
boundingBoxString
);
HttpResponse
<
String
>
response
=
GreenEnricher
.
getOsmData
(
boundingBoxString
);
Files
.
write
(
osmCache
,
response
.
body
().
getBytes
(
StandardCharsets
.
UTF_8
));
}
String
osmResponse
=
Files
.
readString
(
osmCache
);
System
.
out
.
println
(
"Parsing OSM response"
);
parseOsmResponse
(
osmResponse
,
osmData
);
System
.
out
.
println
(
"Fit data in bounding box"
);
if
(
wktPolygon
!=
null
)
{
fitToPolygon
(
osmData
,
wktPolygon
);
}
else
{
fitToBoundingBox
(
osmData
);
}
@Override
public
void
run
()
{
try
{
System
.
out
.
println
(
"Reading CityGML file"
);
Polygon
wktPolygon
=
null
;
if
(
wkt
!=
null
)
{
WKTReader
wktReader
=
new
WKTReader
();
Geometry
wktGeometry
=
wktReader
.
read
(
wkt
);
if
(!(
wktGeometry
instanceof
Polygon
))
{
throw
new
IllegalArgumentException
(
"WKT is not a polygon"
);
}
wktPolygon
=
(
Polygon
)
wktGeometry
;
CoordinateReferenceSystem
utm32
=
CRS_FACTORY
.
createFromName
(
"EPSG:25832"
);
BasicCoordinateTransform
bct
=
new
BasicCoordinateTransform
(
wgs84
,
utm32
);
wktPolygon
.
apply
((
CoordinateFilter
)
c
->
{
ProjCoordinate
p1
=
new
ProjCoordinate
();
p1
.
x
=
c
.
x
;
p1
.
y
=
c
.
y
;
ProjCoordinate
p2
=
new
ProjCoordinate
();
bct
.
transform
(
p1
,
p2
);
c
.
x
=
p2
.
x
;
c
.
y
=
p2
.
y
;
});
wktPolygon
.
geometryChanged
();
}
CityModel
cityModel
=
readCityGml
(
citygmlInput
);
createTransformers
(
cityModel
);
OsmData
osmData
=
new
OsmData
();
String
boundingBoxString
=
GreenEnricher
.
extractAndConvertBoundingBox
(
cityModel
,
osmData
);
String
boundingBoxBasename
=
boundingBoxString
.
replace
(
","
,
"__"
).
replace
(
'.'
,
'_'
);
Path
osmCache
=
Paths
.
get
(
"data"
,
"cache"
,
"osm_response_"
+
boundingBoxBasename
+
".xml"
);
if
(!
Files
.
exists
(
osmCache
))
{
System
.
out
.
println
(
"Downloading OSM data for "
+
boundingBoxString
);
HttpResponse
<
String
>
response
=
GreenEnricher
.
getOsmData
(
boundingBoxString
);
Files
.
write
(
osmCache
,
response
.
body
().
getBytes
(
StandardCharsets
.
UTF_8
));
}
String
osmResponse
=
Files
.
readString
(
osmCache
);
System
.
out
.
println
(
"Filter intersecting areas"
);
List
<
GreenArea
>
greenAreas
=
osmData
.
getGreenAreas
();
removeDuplicateAreas
(
greenAreas
);
System
.
out
.
println
(
"Parsing OSM response"
);
parseOsmResponse
(
osmResponse
,
osmData
);
convertGreenAreasToCityGML
(
cityModel
,
greenAreas
);
convertWaterAreasToCityGML
(
cityModel
,
osmData
);
if
(
wktPolygon
!=
null
)
{
System
.
out
.
println
(
"Fit data in WKT Polygon"
);
fitToPolygon
(
osmData
,
wktPolygon
);
}
else
{
System
.
out
.
println
(
"Fit data in bounding box"
);
fitToBoundingBox
(
osmData
);
}
// trees
TreeUtils
.
insertTrees
(
cityModel
,
osmData
,
baumKatasterPath
,
wktPolygon
);
System
.
out
.
println
(
"Filter intersecting areas"
);
List
<
GreenArea
>
greenAreas
=
osmData
.
getGreenAreas
();
removeDuplicateAreas
(
greenAreas
);
clampToGround
(
cityModel
);
convertGreenAreasToCityGML
(
cityModel
,
greenAreas
);
convertWaterAreasToCityGML
(
cityModel
,
osmData
);
String
inputString
=
inFile
.
getFileName
().
toString
();
String
inputPathWithoutFileEnding
=
inputString
.
substring
(
0
,
inputString
.
lastIndexOf
(
'.'
));
Path
outputPath
=
Paths
.
get
(
"data"
,
inputPathWithoutFileEnding
+
"_"
+
outputSuffix
+
".gml"
);
System
.
out
.
println
(
"Writing output file."
);
writeCityGML
(
cityModel
,
outputPath
);
System
.
out
.
println
(
"Done"
);
// trees
TreeUtils
.
insertTrees
(
cityModel
,
osmData
,
treeShapefileInput
,
wktPolygon
);
}
clampToGround
(
cityModel
);
String
inputString
=
citygmlInput
.
getFileName
().
toString
();
String
inputPathWithoutFileEnding
=
inputString
.
substring
(
0
,
inputString
.
lastIndexOf
(
'.'
));
Path
outputPath
=
Paths
.
get
(
"data"
,
inputPathWithoutFileEnding
+
"_"
+
outputSuffix
+
".gml"
);
System
.
out
.
println
(
"Writing output file to "
+
outputPath
);
writeCityGML
(
cityModel
,
outputPath
);
System
.
out
.
println
(
"Done"
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
}
public
static
void
fitToPolygon
(
OsmData
osmData
,
Polygon
wktPolygon
)
{
fitGreenAreasToBounds
(
wktPolygon
,
osmData
.
getGreenAreas
());
...
...
@@ -201,7 +222,6 @@ public class GreenEnricher
}
}
public
static
void
createTransformers
(
CityModel
cityModel
)
{
String
epsgCode
=
extractEpsgCode
(
cityModel
);
sourceCRS
=
CRS_FACTORY
.
createFromName
(
epsgCode
);
...
...
@@ -209,13 +229,12 @@ public class GreenEnricher
backTransform
=
new
BasicCoordinateTransform
(
wgs84
,
sourceCRS
);
}
public
static
void
convertWaterAreasToCityGML
(
CityModel
cityModel
,
OsmData
osmData
)
{
for
(
WaterArea
waterArea
:
osmData
.
getWaterAreas
())
{
WaterBody
wb
=
new
WaterBody
();
org
.
xmlobjects
.
gml
.
model
.
geometry
.
primitives
.
Polygon
poly
=
convertToCityGmlPoly
(
waterArea
.
getArea
());
if
(
poly
==
null
)
{
//
System.out.println("Skipping WaterBody " + waterArea.getArea());
//
System.out.println("Skipping WaterBody " + waterArea.getArea());
continue
;
}
MultiSurface
ms
=
new
MultiSurface
();
...
...
@@ -230,7 +249,7 @@ public class GreenEnricher
for
(
GreenArea
ga
:
greenAreas
)
{
org
.
xmlobjects
.
gml
.
model
.
geometry
.
primitives
.
Polygon
poly
=
convertToCityGmlPoly
(
ga
.
getArea
());
if
(
poly
==
null
)
{
//
System.out.println("Skipping " + ga.getArea());
//
System.out.println("Skipping " + ga.getArea());
continue
;
}
PlantCover
cover
=
new
PlantCover
();
...
...
@@ -256,7 +275,6 @@ public class GreenEnricher
}
}
private
static
void
fitLandUseAreasToBounds
(
Geometry
bounds
,
List
<
LandUseArea
>
landUseAreas
)
{
List
<
LandUseArea
>
newLandUseAreas
=
new
ArrayList
<>();
for
(
LandUseArea
landUseArea
:
landUseAreas
)
{
...
...
@@ -277,7 +295,6 @@ public class GreenEnricher
landUseAreas
.
addAll
(
newLandUseAreas
);
}
private
static
void
fitRoadAreasToBounds
(
Geometry
bounds
,
List
<
RoadArea
>
roadAreas
)
{
List
<
RoadArea
>
newRoadAreas
=
new
ArrayList
<>();
for
(
RoadArea
roadArea
:
roadAreas
)
{
...
...
@@ -298,7 +315,6 @@ public class GreenEnricher
roadAreas
.
addAll
(
newRoadAreas
);
}
private
static
void
fitGreenAreasToBounds
(
Geometry
bounds
,
List
<
GreenArea
>
greenAreas
)
{
List
<
GreenArea
>
newGreenAreas
=
new
ArrayList
<>();
for
(
GreenArea
greenArea
:
greenAreas
)
{
...
...
@@ -346,7 +362,7 @@ public class GreenEnricher
GreenArea
area2
=
greenAreas
.
get
(
j
);
if
(
area1
.
getArea
().
intersects
(
area2
.
getArea
()))
{
Geometry
difference
=
area1
.
getArea
().
difference
(
area2
.
getArea
());
//
System.out.println(difference);
//
System.out.println(difference);
if
(
difference
instanceof
MultiPolygon
)
{
MultiPolygon
multi
=
(
MultiPolygon
)
difference
;
Polygon
poly1
=
(
Polygon
)
multi
.
getGeometryN
(
0
);
...
...
@@ -475,9 +491,11 @@ public class GreenEnricher
if
(
member
.
getRole
().
isBlank
())
{
// assume outer ring
// check if this ring is closed
if
(!
coordinates
.
isEmpty
()
&&
coordinates
.
get
(
0
).
equals2D
(
coordinates
.
get
(
coordinates
.
size
()
-
1
)))
{
if
(!
coordinates
.
isEmpty
()
&&
coordinates
.
get
(
0
).
equals2D
(
coordinates
.
get
(
coordinates
.
size
()
-
1
)))
{
// ring is closed, create a polygon out of it
Polygon
polygon
=
GEOM_FACTORY
.
createPolygon
(
coordinates
.
toArray
(
new
Coordinate
[
coordinates
.
size
()]));
Polygon
polygon
=
GEOM_FACTORY
.
createPolygon
(
coordinates
.
toArray
(
new
Coordinate
[
coordinates
.
size
()]));
coordinates
.
clear
();
polygons
.
add
(
polygon
);
}
...
...
@@ -634,28 +652,30 @@ public class GreenEnricher
data
.
getWaterAreas
().
add
(
new
WaterArea
(
polygon
));
}
//
validateRing(outerRing);
//
validateRing(outerRing);
// create the outer ring
//
org.locationtech.jts.geom.LinearRing outerLinearRing = geomFactory
//
.createLinearRing(outerRing.toArray(new Coordinate[outerRing.size()]));
//
org.locationtech.jts.geom.LinearRing outerLinearRing = geomFactory
//
.createLinearRing(outerRing.toArray(new Coordinate[outerRing.size()]));
//
// // create the inner rings
// List<org.locationtech.jts.geom.LinearRing> innerLinearRings = new ArrayList<>();
// for (List<Coordinate> innerRing : innerRings) {
// org.locationtech.jts.geom.LinearRing innerLinearRing = geomFactory
// .createLinearRing(innerRing.toArray(new Coordinate[innerRing.size()]));
// innerLinearRings.add(innerLinearRing);
// }
// // create the inner rings
// List<org.locationtech.jts.geom.LinearRing> innerLinearRings = new
// ArrayList<>();
// for (List<Coordinate> innerRing : innerRings) {
// org.locationtech.jts.geom.LinearRing innerLinearRing = geomFactory
// .createLinearRing(innerRing.toArray(new Coordinate[innerRing.size()]));
// innerLinearRings.add(innerLinearRing);
// }
//
//
if (outerRing.isEmpty()) {
//
return false;
//
}
//
if (outerRing.isEmpty()) {
//
return false;
//
}
//
// // create the polygon
// Polygon polygon = geomFactory.createPolygon(outerLinearRing,
// innerLinearRings.toArray(new org.locationtech.jts.geom.LinearRing[innerLinearRings.size()]));
// // create the polygon
// Polygon polygon = geomFactory.createPolygon(outerLinearRing,
// innerLinearRings.toArray(new
// org.locationtech.jts.geom.LinearRing[innerLinearRings.size()]));
//
//
data.getGreenAreas().add(new GreenArea(polygon));
//
data.getGreenAreas().add(new GreenArea(polygon));
return
true
;
}
...
...
@@ -684,9 +704,10 @@ public class GreenEnricher
ProjCoordinate
converted
=
convertCoordinatesFrom84
(
lon
,
lat
);
coordinates
.
add
(
new
Coordinate
(
converted
.
x
,
converted
.
y
));
}
else
if
(
"tag"
.
equals
(
child
.
getNodeName
()))
{
// if (existTagWithValue(child, "k", "natural") && existTagWithValue(child, "v", "tree_row")) {
// line = true;
// }
// if (existTagWithValue(child, "k", "natural") && existTagWithValue(child, "v",
// "tree_row")) {
// line = true;
// }
if
((
existTagWithValue
(
child
,
"k"
,
"natural"
)
&&
existTagWithValue
(
child
,
"v"
,
"water"
))
||
existTagWithValue
(
child
,
"k"
,
"waterway"
))
{
water
=
true
;
...
...
@@ -831,13 +852,12 @@ public class GreenEnricher
return
result
;
}
public
static
void
convertRoadAreasToCityGML
(
CityModel
cityModel
,
OsmData
osmData
)
{
for
(
RoadArea
roadArea
:
osmData
.
getRoadAreas
())
{
Road
road
=
new
Road
();
org
.
xmlobjects
.
gml
.
model
.
geometry
.
primitives
.
Polygon
poly
=
convertToCityGmlPoly
(
roadArea
.
getArea
());
if
(
poly
==
null
)
{
//
System.out.println("Skipping RoadArea: " + roadArea.getArea());
//
System.out.println("Skipping RoadArea: " + roadArea.getArea());
continue
;
}
MultiSurface
ms
=
new
MultiSurface
();
...
...
@@ -848,13 +868,12 @@ public class GreenEnricher
}
}
public
static
void
convertLandUseAreasToCityGML
(
CityModel
cityModel
,
OsmData
osmData
)
{
for
(
LandUseArea
landUseArea
:
osmData
.
getLandUseAreas
())
{
LandUse
landUse
=
new
LandUse
();
org
.
xmlobjects
.
gml
.
model
.
geometry
.
primitives
.
Polygon
poly
=
convertToCityGmlPoly
(
landUseArea
.
getArea
());
if
(
poly
==
null
)
{
//
System.out.println("Skipping RoadArea: " + landUseArea.getArea());
//
System.out.println("Skipping RoadArea: " + landUseArea.getArea());
continue
;
}
MultiSurface
ms
=
new
MultiSurface
();
...
...
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