diff --git a/enrich-citygml-with-greenarea/data/cache/.gitignore b/enrich-citygml-with-greenarea/data/cache/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..b81c7954b78b3bc416ac236a505b0fd58627746e --- /dev/null +++ b/enrich-citygml-with-greenarea/data/cache/.gitignore @@ -0,0 +1 @@ +*.xml \ No newline at end of file diff --git a/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/alkis/AlkisGreenEnricher.java b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/alkis/AlkisGreenEnricher.java index c22e04c803f5289eddae0aeb28f8e7784c9fbd68..7d8cff10d41eb92dad9f397e39799a539b74e0e6 100644 --- a/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/alkis/AlkisGreenEnricher.java +++ b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/alkis/AlkisGreenEnricher.java @@ -2,17 +2,16 @@ package de.hft.stuttgart.citygml.green.alkis; import java.io.IOException; import java.net.MalformedURLException; +import java.net.http.HttpResponse; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; - import org.citygml4j.core.model.core.CityModel; import org.citygml4j.xml.CityGMLContextException; import org.citygml4j.xml.reader.CityGMLReadException; @@ -26,7 +25,6 @@ import org.locationtech.jts.geom.MultiPolygon; import org.locationtech.jts.geom.Polygon; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; - import de.hft.stuttgart.citygml.green.osm.GreenArea; import de.hft.stuttgart.citygml.green.osm.GreenEnricher; import de.hft.stuttgart.citygml.green.osm.LandUseArea; @@ -35,25 +33,29 @@ import de.hft.stuttgart.citygml.green.osm.RoadArea; import de.hft.stuttgart.citygml.green.osm.TreeUtils; import jakarta.xml.bind.JAXBException; -public class AlkisGreenEnricher { - + +public class AlkisGreenEnricher +{ + private static Set greenAreaTypes = new HashSet<>(); private static Set roadAreaTypes = new HashSet<>(); - + static { greenAreaTypes.add("Wald"); greenAreaTypes.add("Landwirtschaft"); greenAreaTypes.add("Friedhof"); greenAreaTypes.add("Gehölz"); greenAreaTypes.add("Sport-, Freizeit- und Erholungsfläche"); - + roadAreaTypes.add("Weg"); roadAreaTypes.add("Straßenverkehr"); roadAreaTypes.add("Bahnverkehr"); - + } - - public static void main(String[] args) throws IOException, CityGMLContextException, CityGMLReadException, JAXBException, CityGMLWriteException { + + public static void main(String[] args) + throws IOException, InterruptedException, CityGMLContextException, CityGMLReadException, JAXBException, + CityGMLWriteException { System.out.println("Reading CityGML file"); Path inFile = Paths.get(args[0]); CityModel cityModel = GreenEnricher.readCityGml(inFile); @@ -62,33 +64,37 @@ public class AlkisGreenEnricher { OsmData osmData = new OsmData(); String boundingBoxString = GreenEnricher.extractAndConvertBoundingBox(cityModel, osmData); -// HttpResponse response = getOsmData(boundingBoxString); -// Files.write(Path.of("osm_response.xml"), response.body().getBytes(StandardCharsets.UTF_8)); -// String osmResponse = response.body(); - String osmResponse = Files.readString(Paths.get("data", "osm_response.xml")); + 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 response = GreenEnricher.getOsmData(boundingBoxString); + Files.write(osmCache, response.body().getBytes(StandardCharsets.UTF_8)); + } + String osmResponse = Files.readString(osmCache); System.out.println("Parsing OSM response"); GreenEnricher.parseOsmResponse(osmResponse, osmData); - + // ignore green areas from osm osmData.getGreenAreas().clear(); - + parseAlkisData(osmData); System.out.println("Fit data in bounding box"); GreenEnricher.fitToBoundingBox(osmData); - + GreenEnricher.convertGreenAreasToCityGML(cityModel, osmData.getGreenAreas()); GreenEnricher.convertWaterAreasToCityGML(cityModel, osmData); GreenEnricher.convertRoadAreasToCityGML(cityModel, osmData); GreenEnricher.converLandUseAreasToCityGML(cityModel, osmData); - + TreeUtils.insertTrees(cityModel, osmData); - + GreenEnricher.clampToGround(cityModel); - + String inputString = inFile.getFileName().toString(); String inputPathWithoutFileEnding = inputString.substring(0, inputString.lastIndexOf('.')); Path outputPath = Paths.get("data", inputPathWithoutFileEnding + "_with_alkis_greens_realistic.gml"); @@ -101,7 +107,7 @@ public class AlkisGreenEnricher { private static void parseAlkisData(OsmData osmData) throws MalformedURLException, IOException { Path alkisDataPath = Paths.get("data", "tn_09663", "Nutzung.shp"); - + Map readParameters = new HashMap<>(); readParameters.put("url", alkisDataPath.toUri().toURL()); readParameters.put("charset", StandardCharsets.UTF_8); @@ -111,15 +117,15 @@ public class AlkisGreenEnricher { FeatureSource source = dataStore.getFeatureSource(typeName); FeatureCollection collection = source.getFeatures(); - + List greenAreas = osmData.getGreenAreas(); List roadAreas = osmData.getRoadAreas(); List landUseAreas = osmData.getLandUseAreas(); - + try (FeatureIterator features = collection.features()) { while (features.hasNext()) { SimpleFeature feature = features.next(); - + MultiPolygon geometry = (MultiPolygon) feature.getAttribute("the_geom"); String nutzart = feature.getAttribute("nutzart").toString(); if (geometry.getNumGeometries() > 1) { diff --git a/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/GreenEnricher.java b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/GreenEnricher.java index 9c6d8aa7509571bd7fd1d735c0f8262b2cb5533c..9e3f2ac94d6f7de6a2b3dc345427dc8af5cd5bd1 100644 --- a/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/GreenEnricher.java +++ b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/GreenEnricher.java @@ -18,9 +18,7 @@ import java.util.Set; import java.util.UUID; import java.util.regex.Matcher; import java.util.regex.Pattern; - import javax.xml.parsers.ParserConfigurationException; - import org.citygml4j.core.model.CityGMLVersion; import org.citygml4j.core.model.building.Building; import org.citygml4j.core.model.core.AbstractCityObject; @@ -62,7 +60,6 @@ import org.xmlobjects.gml.model.geometry.aggregates.MultiSurfaceProperty; import org.xmlobjects.gml.model.geometry.primitives.AbstractRingProperty; import org.xmlobjects.gml.model.geometry.primitives.LinearRing; import org.xmlobjects.gml.model.geometry.primitives.SurfaceProperty; - import de.hft.stuttgart.citygml.green.osm.jaxb.OSM; import de.hft.stuttgart.citygml.green.osm.jaxb.OsmMember; import de.hft.stuttgart.citygml.green.osm.jaxb.OsmNode; @@ -73,7 +70,9 @@ import de.hft.stuttgart.citygml.green.osm.jaxb.WayNode; import jakarta.xml.bind.JAXBContext; import jakarta.xml.bind.JAXBException; -public class GreenEnricher { + +public class GreenEnricher +{ private static final int BOUNDING_BOX_INCREASE_IN_M = 100; @@ -123,9 +122,9 @@ public class GreenEnricher { OsmData osmData = new OsmData(); String boundingBoxString = extractAndConvertBoundingBox(cityModel, osmData); -// HttpResponse response = getOsmData(boundingBoxString); -// Files.write(Path.of("osm_response.xml"), response.body().getBytes(StandardCharsets.UTF_8)); -// String osmResponse = response.body(); + // HttpResponse response = getOsmData(boundingBoxString); + // Files.write(Path.of("osm_response.xml"), response.body().getBytes(StandardCharsets.UTF_8)); + // String osmResponse = response.body(); String osmResponse = Files.readString(Paths.get("data", "osm_response.xml")); System.out.println("Parsing OSM response"); @@ -143,7 +142,7 @@ public class GreenEnricher { // trees TreeUtils.insertTrees(cityModel, osmData); - + clampToGround(cityModel); String inputString = inFile.getFileName().toString(); @@ -229,7 +228,7 @@ public class GreenEnricher { landUseArea.setArea((Polygon) intersection); } } - landUseAreas.addAll(newLandUseAreas); + landUseAreas.addAll(newLandUseAreas); } @@ -318,6 +317,7 @@ public class GreenEnricher { } } } + public static void clampToGround(CityModel cityModel) { for (AbstractCityObjectProperty afp : cityModel.getCityObjectMembers()) { AbstractCityObject af = afp.getObject(); @@ -376,7 +376,7 @@ public class GreenEnricher { return result; } - private static HttpResponse getOsmData(String boundingBoxString) throws IOException, InterruptedException { + public static HttpResponse getOsmData(String boundingBoxString) throws IOException, InterruptedException { String data = OSM_STRING.replace("{{bbox}}", boundingBoxString); String body = URLEncoder.encode("data", StandardCharsets.UTF_8) + "=" + URLEncoder.encode(data, StandardCharsets.UTF_8); @@ -436,7 +436,7 @@ public class GreenEnricher { } } } - + if (!coordinates.isEmpty() && coordinates.get(0).equals2D(coordinates.get(coordinates.size() - 1))) { // one huge polygon apparently Polygon polygon = GEOM_FACTORY.createPolygon(coordinates.toArray(new Coordinate[coordinates.size()])); @@ -445,13 +445,13 @@ public class GreenEnricher { } else { // line } - + for (OsmTag tag : rel.getTags()) { if ("water".equals(tag.getValue()) || "waterway".equals(tag.getKey())) { isWater = true; } } - + if (isWater) { for (Polygon p : polygons) { data.getWaterAreas().add(new WaterArea(p)); @@ -587,28 +587,28 @@ 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()])); -// -// // create the inner rings -// List innerLinearRings = new ArrayList<>(); -// for (List innerRing : innerRings) { -// org.locationtech.jts.geom.LinearRing innerLinearRing = geomFactory -// .createLinearRing(innerRing.toArray(new Coordinate[innerRing.size()])); -// innerLinearRings.add(innerLinearRing); -// } -// -// if (outerRing.isEmpty()) { -// return false; -// } -// -// // create the polygon -// Polygon polygon = geomFactory.createPolygon(outerLinearRing, -// innerLinearRings.toArray(new org.locationtech.jts.geom.LinearRing[innerLinearRings.size()])); -// -// data.getGreenAreas().add(new GreenArea(polygon)); + // org.locationtech.jts.geom.LinearRing outerLinearRing = geomFactory + // .createLinearRing(outerRing.toArray(new Coordinate[outerRing.size()])); + // + // // create the inner rings + // List innerLinearRings = new ArrayList<>(); + // for (List innerRing : innerRings) { + // org.locationtech.jts.geom.LinearRing innerLinearRing = geomFactory + // .createLinearRing(innerRing.toArray(new Coordinate[innerRing.size()])); + // innerLinearRings.add(innerLinearRing); + // } + // + // if (outerRing.isEmpty()) { + // return false; + // } + // + // // create the polygon + // Polygon polygon = geomFactory.createPolygon(outerLinearRing, + // innerLinearRings.toArray(new org.locationtech.jts.geom.LinearRing[innerLinearRings.size()])); + // + // data.getGreenAreas().add(new GreenArea(polygon)); return true; } @@ -637,9 +637,9 @@ 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; diff --git a/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/TreeUtils.java b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/TreeUtils.java index 105ca738b360c4a21e3bec423cf1f2f46d6178bb..aefaeb6444a561c9b9c2265e6d1b68e4acf44c0c 100644 --- a/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/TreeUtils.java +++ b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/TreeUtils.java @@ -4,7 +4,6 @@ import java.io.IOException; import java.nio.file.Paths; import java.util.Iterator; import java.util.UUID; - import org.citygml4j.core.model.core.AbstractCityObjectProperty; import org.citygml4j.core.model.core.CityModel; import org.citygml4j.core.model.vegetation.SolitaryVegetationObject; @@ -13,23 +12,26 @@ import org.xmlobjects.gml.model.basictypes.Code; import org.xmlobjects.gml.model.geometry.aggregates.MultiSurface; import org.xmlobjects.gml.model.geometry.aggregates.MultiSurfaceProperty; -public class TreeUtils { - + +public class TreeUtils +{ + public static void insertTrees(CityModel cityModel, OsmData osmData) throws IOException { - TreeKatasterData katasterData = TreeKatasterData.parseTreeKatasterData(Paths.get("data", "Trees_realisticScenario_20240201.shp")); + TreeKatasterData katasterData = TreeKatasterData + .parseTreeKatasterData(Paths.get("data", "Trees", "Trees_realisticScenario_20240201.shp")); generateTreesFromKataster(cityModel, katasterData); -// TreeKatasterData katasterData2 = TreeKatasterData.parseTreeKatasterData(Paths.get("data", "Trees_realistic_20240201.shp")); -// generateTreesFromKataster(cityModel, katasterData2); + // TreeKatasterData katasterData2 = TreeKatasterData.parseTreeKatasterData(Paths.get("data", "Trees_realistic_20240201.shp")); + // generateTreesFromKataster(cityModel, katasterData2); // All kataster trees are taken, osm trees are removed filterDuplicateTreesFromOSM(osmData, katasterData); -// filterDuplicateTreesFromOSM(osmData, katasterData2); - + // filterDuplicateTreesFromOSM(osmData, katasterData2); + generateTreesFromOSM(cityModel, osmData); } - + private static void filterDuplicateTreesFromOSM(OsmData osmData, TreeKatasterData katasterData) { for (Iterator iterator = osmData.getTreePoints().iterator(); iterator.hasNext();) { TreePoint tp = iterator.next(); @@ -41,7 +43,7 @@ public class TreeUtils { } } } - + private static void generateTreesFromOSM(CityModel cityModel, OsmData osmData) { for (TreePoint tp : osmData.getTreePoints()) { // standard tree diff --git a/enrich-citygml-with-greenarea/src/test/java/de/hft/stuttgart/citygml/green/alkis/AlkisGreenEnricherTest.java b/enrich-citygml-with-greenarea/src/test/java/de/hft/stuttgart/citygml/green/alkis/AlkisGreenEnricherTest.java index b128b5d3bc07739f9c597a88754628178052c1bf..61980c3ec73997f4288e4bdd2669524435be7092 100644 --- a/enrich-citygml-with-greenarea/src/test/java/de/hft/stuttgart/citygml/green/alkis/AlkisGreenEnricherTest.java +++ b/enrich-citygml-with-greenarea/src/test/java/de/hft/stuttgart/citygml/green/alkis/AlkisGreenEnricherTest.java @@ -1,20 +1,15 @@ package de.hft.stuttgart.citygml.green.alkis; -import java.io.IOException; - -import org.citygml4j.xml.CityGMLContextException; -import org.citygml4j.xml.reader.CityGMLReadException; -import org.citygml4j.xml.writer.CityGMLWriteException; import org.junit.jupiter.api.Test; -import jakarta.xml.bind.JAXBException; -class AlkisGreenEnricherTest { +class AlkisGreenEnricherTest +{ @Test - void testAlkisGreen() throws IOException, CityGMLContextException, CityGMLReadException, JAXBException, CityGMLWriteException { - String[] args = new String[] {"data/Grombühl_v4_case_study.gml"}; - + void testAlkisGreen() throws Exception { + String[] args = new String[] { "data/Grombühl_v4_case_study.gml" }; + AlkisGreenEnricher.main(args); }