Commit 1e3e7d11 authored by Eric Duminil's avatar Eric Duminil
Browse files

Using PicoCli for GreenEnricher

parent 5621631f
......@@ -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>
......@@ -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();
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment