From ccd43258cee55e5e7376f34ad89b818565ea97dd Mon Sep 17 00:00:00 2001 From: Matthias Betz Date: Wed, 8 Mar 2023 13:39:33 +0100 Subject: [PATCH] year of construction and tree analyzer --- enrich-citygml-with-greenarea/pom.xml | 20 ++++ .../green/kataster/StandardTreeFinder.java | 98 +++++++++++++++ .../citygml/green/osm/GreenEnricher.java | 10 +- .../hft/stuttgart/citygml/green/osm/Tree.java | 53 ++++++++ .../citygml/green/osm/TreeKatasterData.java | 17 +++ .../analysis/YearOfConstructionAnalyzer.java | 113 ++++++++++++++++++ 6 files changed, 307 insertions(+), 4 deletions(-) create mode 100644 enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/kataster/StandardTreeFinder.java create mode 100644 enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/Tree.java create mode 100644 enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/TreeKatasterData.java create mode 100644 enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/yoc/analysis/YearOfConstructionAnalyzer.java diff --git a/enrich-citygml-with-greenarea/pom.xml b/enrich-citygml-with-greenarea/pom.xml index 344cc07..995be0a 100644 --- a/enrich-citygml-with-greenarea/pom.xml +++ b/enrich-citygml-with-greenarea/pom.xml @@ -10,7 +10,27 @@ 17 + + + osgeo + OSGeo Release Repository + https://repo.osgeo.org/repository/release/ + + false + + + true + + + + + + + org.geotools + gt-shapefile + 24.5 + org.junit.jupiter diff --git a/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/kataster/StandardTreeFinder.java b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/kataster/StandardTreeFinder.java new file mode 100644 index 0000000..d3f5032 --- /dev/null +++ b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/kataster/StandardTreeFinder.java @@ -0,0 +1,98 @@ +package de.hft.stuttgart.citygml.green.kataster; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.IntSummaryStatistics; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +import org.geotools.data.DataStore; +import org.geotools.data.DataStoreFinder; +import org.geotools.data.FeatureSource; +import org.geotools.feature.FeatureCollection; +import org.geotools.feature.FeatureIterator; +import org.opengis.feature.simple.SimpleFeature; +import org.opengis.feature.simple.SimpleFeatureType; + +public class StandardTreeFinder { + + public static void main(String[] args) throws IOException { + + File f = new File("data/Baum.shp"); + + Map treeTypes = new HashMap<>(); + List ages = new ArrayList<>(); + List treeHeights = new ArrayList<>(); + List crownWidths = new ArrayList<>(); + List trunkCircs = new ArrayList<>(); + + Map map = new HashMap<>(); + map.put("url", f.toURI().toURL()); + map.put("charset", StandardCharsets.UTF_8); + + DataStore dataStore = DataStoreFinder.getDataStore(map); + String typeName = dataStore.getTypeNames()[0]; + + FeatureSource source = + dataStore.getFeatureSource(typeName); + + int featureCount = 0; + FeatureCollection collection = source.getFeatures(); + try (FeatureIterator features = collection.features()) { + while (features.hasNext()) { + featureCount++; + SimpleFeature feature = features.next(); + String type = feature.getAttribute("Baumart").toString(); + treeTypes.compute(type, (k, v) -> { + if (v == null) { + v = new AtomicInteger(0); + } + v.incrementAndGet(); + return v; + }); + Object ageObject = feature.getAttribute("Alter am S"); + if (ageObject != null) { + ages.add(Integer.parseInt(ageObject.toString())); + } + Object treeHeight = feature.getAttribute("Baumhöhe"); + if (treeHeight != null) { + treeHeights.add(Integer.parseInt(treeHeight.toString())); + } + Object crownWidth = feature.getAttribute("Kronenbrei"); + if (crownWidth != null) { + crownWidths.add(Float.parseFloat(crownWidth.toString())); + } + Object trunkCirc = feature.getAttribute("Stammumfan"); + if (trunkCirc != null) { + trunkCircs.add(Integer.parseInt(trunkCirc.toString())); + } + } + } + + System.out.println("Number of trees: " + featureCount); + + for (Entry e : treeTypes.entrySet()) { + System.out.println(e.getKey() + ": " + e.getValue()); + } + + System.out.println(); + IntSummaryStatistics treeHeightsStatistics = treeHeights.stream().collect(Collectors.summarizingInt(Integer::intValue)); + System.out.println("TreeHeightAverage: " + treeHeightsStatistics.getAverage()); + + IntSummaryStatistics agesStatistics = ages.stream().collect(Collectors.summarizingInt(Integer::intValue)); + System.out.println("AverageAge: " + agesStatistics); + + Double averageCrown = crownWidths.stream().collect(Collectors.averagingDouble(Float::doubleValue)); + System.out.println("AverageCrownWidth: " + averageCrown); + + Double averageTrunkCirc = trunkCircs.stream().collect(Collectors.averagingInt(Integer::intValue)); + System.out.println("AverageTrunkCirc: " + averageTrunkCirc); + } + +} 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 101ac9e..b634629 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 @@ -112,6 +112,8 @@ public class GreenEnricher { System.out.println("Reading CityGML file"); Path inFile = Paths.get(args[0]); CityModel cityModel = readCityGml(inFile); + + String epsgCode = extractEpsgCode(cityModel); sourceCRS = CRS_FACTORY.createFromName(epsgCode); @@ -123,7 +125,7 @@ public class GreenEnricher { // 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("osm_response.xml")); + String osmResponse = Files.readString(Paths.get("data", "osm_response.xml")); System.out.println("Parsing OSM response"); parseOsmResponse(osmResponse, osmData); @@ -146,12 +148,12 @@ public class GreenEnricher { for (TreePoint tp : osmData.getTreePoints()) { double trunkRadius = 0.2; - double trunkHeight = 1; + double trunkHeight = 3; Coordinate coordinate = tp.getPoint().getCoordinate(); if (Double.isNaN(coordinate.z)) { coordinate.z = 0; } - MultiSurface generatedTree = TreeGenerator.generateTree(coordinate, trunkRadius, trunkHeight, 5, 5, 10); + MultiSurface generatedTree = TreeGenerator.generateTree(coordinate, trunkRadius, trunkHeight, 3, 3, 10); SolitaryVegetationObject cover = new SolitaryVegetationObject(); cover.setId(UUID.randomUUID().toString()); cover.setLod2MultiSurface(new MultiSurfaceProperty(generatedTree)); @@ -166,7 +168,7 @@ public class GreenEnricher { String inputString = inFile.getFileName().toString(); String inputPathWithoutFileEnding = inputString.substring(0, inputString.lastIndexOf('.')); - Path outputPath = Paths.get(inputPathWithoutFileEnding + "_with_greens.gml"); + Path outputPath = Paths.get("data", inputPathWithoutFileEnding + "_with_greens.gml"); System.out.println("Writing output file."); writeCityGML(cityModel, outputPath); System.out.println("Done"); diff --git a/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/Tree.java b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/Tree.java new file mode 100644 index 0000000..ba8b68f --- /dev/null +++ b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/Tree.java @@ -0,0 +1,53 @@ +package de.hft.stuttgart.citygml.green.osm; + +import org.locationtech.jts.geom.Coordinate; + +public class Tree { + + private Coordinate point; + private double trunkHeight; + private double trunkRadius; + private double crownRadius; + private double crownHeight; + + public Coordinate getPoint() { + return point; + } + + public void setPoint(Coordinate point) { + this.point = point; + } + + public double getTrunkHeight() { + return trunkHeight; + } + + public void setTrunkHeight(double trunkHeight) { + this.trunkHeight = trunkHeight; + } + + public double getTrunkRadius() { + return trunkRadius; + } + + public void setTrunkRadius(double trunkRadius) { + this.trunkRadius = trunkRadius; + } + + public double getCrownRadius() { + return crownRadius; + } + + public void setCrownRadius(double crownRadius) { + this.crownRadius = crownRadius; + } + + public double getCrownHeight() { + return crownHeight; + } + + public void setCrownHeight(double crownHeight) { + this.crownHeight = crownHeight; + } + +} diff --git a/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/TreeKatasterData.java b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/TreeKatasterData.java new file mode 100644 index 0000000..fac9652 --- /dev/null +++ b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/TreeKatasterData.java @@ -0,0 +1,17 @@ +package de.hft.stuttgart.citygml.green.osm; + +import java.util.ArrayList; +import java.util.List; + +public class TreeKatasterData { + + private List trees; + + public List getTrees() { + if (trees == null) { + trees = new ArrayList<>(); + } + return trees; + } + +} diff --git a/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/yoc/analysis/YearOfConstructionAnalyzer.java b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/yoc/analysis/YearOfConstructionAnalyzer.java new file mode 100644 index 0000000..8f11b33 --- /dev/null +++ b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/yoc/analysis/YearOfConstructionAnalyzer.java @@ -0,0 +1,113 @@ +package de.hft.stuttgart.citygml.yoc.analysis; + +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.nio.file.Paths; +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.citygml4j.core.model.CityGMLVersion; +import org.citygml4j.core.model.building.Building; +import org.citygml4j.core.model.core.AbstractCityObject; +import org.citygml4j.core.model.core.AbstractCityObjectProperty; +import org.citygml4j.core.model.core.AbstractFeature; +import org.citygml4j.core.model.core.CityModel; +import org.citygml4j.xml.CityGMLContext; +import org.citygml4j.xml.CityGMLContextException; +import org.citygml4j.xml.module.citygml.CoreModule; +import org.citygml4j.xml.reader.CityGMLInputFactory; +import org.citygml4j.xml.reader.CityGMLReadException; +import org.citygml4j.xml.reader.CityGMLReader; +import org.citygml4j.xml.writer.CityGMLOutputFactory; +import org.citygml4j.xml.writer.CityGMLWriteException; +import org.citygml4j.xml.writer.CityGMLWriter; +import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.GeometryFactory; +import org.locationtech.jts.geom.Point; +import org.xmlobjects.gml.model.geometry.DirectPosition; + +public class YearOfConstructionAnalyzer { + + public static void main(String[] args) throws CityGMLContextException, CityGMLReadException, CityGMLWriteException { + Path inputFile = Paths.get("data", "Grombühl_v3.gml"); + CityModel cityModel = readCityGml(inputFile); + List cityObjectMembers = cityModel.getCityObjectMembers(); + Map missingYocUsageCount = new HashMap<>(); + + GeometryFactory factory = new GeometryFactory(); + Map centersMap = new HashMap<>(); + + for (AbstractCityObjectProperty acop : cityObjectMembers) { + AbstractCityObject abstractCityObject = acop.getObject(); + if (abstractCityObject instanceof Building b) { + DirectPosition center = b.computeEnvelope().getCenter(); + Point point = factory.createPoint(new Coordinate(center.getValue().get(0), center.getValue().get(1))); + centersMap.put(point, b); + } + } + + for (AbstractCityObjectProperty acop : cityObjectMembers) { + AbstractCityObject abstractCityObject = acop.getObject(); + if (abstractCityObject instanceof Building b && b.getDateOfConstruction() == null) { + String function = b.getFunctions().get(0).getValue(); + if ("31001_1000".equals(function)) { + DirectPosition center = b.computeEnvelope().getCenter(); + double lowestDistance = Double.MAX_VALUE; + Point point = factory.createPoint(new Coordinate(center.getValue().get(0), center.getValue().get(1))); + Building nearestBuilding = null; + for (Entry e : centersMap.entrySet()) { + if (e.getValue() == b) { + continue; + } + if (e.getKey().distance(point) < lowestDistance && e.getValue().getDateOfConstruction() != null) { + lowestDistance = e.getKey().distance(point); + nearestBuilding = e.getValue(); + } + } + + if (nearestBuilding == null) { + throw new IllegalStateException(); + } + System.out.println("Assigning " + b.getId() + " yoc of: " + nearestBuilding.getDateOfConstruction()); + b.setDateOfConstruction(nearestBuilding.getDateOfConstruction()); + } + missingYocUsageCount.compute(function, (k, v) -> { + if (v == null) { + v = new AtomicInteger(0); + } + v.getAndIncrement(); + return v; + }); + } + } + writeCityGML(cityModel, Paths.get("out.gml")); + } + + private static CityModel readCityGml(Path inFile) throws CityGMLContextException, CityGMLReadException { + CityGMLContext context = CityGMLContext.newInstance(); + CityGMLInputFactory in = context.createCityGMLInputFactory(); + try (CityGMLReader reader = in.createCityGMLReader(inFile)) { + AbstractFeature feature = reader.next(); + if (feature instanceof CityModel cm) { + return cm; + } + } + throw new IllegalStateException("CityGML does not contain a CityModel feature type"); + } + + private static void writeCityGML(CityModel cityModel, Path outputPath) + throws CityGMLWriteException, CityGMLContextException { + CityGMLContext context = CityGMLContext.newInstance(); + CityGMLVersion version = CityGMLVersion.v2_0; + CityGMLOutputFactory out = context.createCityGMLOutputFactory(version); + + try (CityGMLWriter writer = out.createCityGMLWriter(outputPath, StandardCharsets.UTF_8.name())) { + writer.withIndent(" ").withDefaultSchemaLocations().withDefaultPrefixes() + .withDefaultNamespace(CoreModule.of(version).getNamespaceURI()).write(cityModel); + } + } + +} -- GitLab