diff --git a/enrich-citygml-with-greenarea/pom.xml b/enrich-citygml-with-greenarea/pom.xml index 995be0a3753bfb186e257f471715f4135a2e0a6a..e1f3cba033f79f44f1f113e61192d95c22c4f5bb 100644 --- a/enrich-citygml-with-greenarea/pom.xml +++ b/enrich-citygml-with-greenarea/pom.xml @@ -25,6 +25,19 @@ </repositories> <dependencies> + <!-- https://mvnrepository.com/artifact/jakarta.xml.bind/jakarta.xml.bind-api --> + <dependency> + <groupId>jakarta.xml.bind</groupId> + <artifactId>jakarta.xml.bind-api</artifactId> + <version>4.0.0</version> + </dependency> + <dependency> + <groupId>com.sun.xml.bind</groupId> + <artifactId>jaxb-impl</artifactId> + <version>4.0.0</version> + <scope>runtime</scope> + </dependency> + <!-- https://mvnrepository.com/artifact/org.geotools/gt-shapefile --> <dependency> <groupId>org.geotools</groupId> 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 new file mode 100644 index 0000000000000000000000000000000000000000..9ddcda468a754aceaca4af742fb25b553e1e5a39 --- /dev/null +++ b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/alkis/AlkisGreenEnricher.java @@ -0,0 +1,139 @@ +package de.hft.stuttgart.citygml.green.alkis; + +import java.io.IOException; +import java.net.MalformedURLException; +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; +import org.citygml4j.xml.writer.CityGMLWriteException; +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.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; +import de.hft.stuttgart.citygml.green.osm.OsmData; +import de.hft.stuttgart.citygml.green.osm.RoadArea; +import de.hft.stuttgart.citygml.green.osm.TreeUtils; +import jakarta.xml.bind.JAXBException; + +public class AlkisGreenEnricher { + + private static Set<String> greenAreaTypes = new HashSet<>(); + private static Set<String> 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 { + System.out.println("Reading CityGML file"); + Path inFile = Paths.get(args[0]); + CityModel cityModel = GreenEnricher.readCityGml(inFile); + + GreenEnricher.createTransformers(cityModel); + + OsmData osmData = new OsmData(); + String boundingBoxString = GreenEnricher.extractAndConvertBoundingBox(cityModel, osmData); +// HttpResponse<String> 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"); + 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.gml"); + System.out.println("Writing output file."); + GreenEnricher.writeCityGML(cityModel, outputPath); + System.out.println("Done"); + + + } + + private static void parseAlkisData(OsmData osmData) throws MalformedURLException, IOException { + Path alkisDataPath = Paths.get("data", "tn_09663", "Nutzung.shp"); + + Map<String, Object> readParameters = new HashMap<>(); + readParameters.put("url", alkisDataPath.toUri().toURL()); + readParameters.put("charset", StandardCharsets.UTF_8); + DataStore dataStore = DataStoreFinder.getDataStore(readParameters); + String typeName = dataStore.getTypeNames()[0]; + + FeatureSource<SimpleFeatureType, SimpleFeature> source = dataStore.getFeatureSource(typeName); + + FeatureCollection<SimpleFeatureType, SimpleFeature> collection = source.getFeatures(); + + List<GreenArea> greenAreas = osmData.getGreenAreas(); + List<RoadArea> roadAreas = osmData.getRoadAreas(); + List<LandUseArea> landUseAreas = osmData.getLandUseAreas(); + + try (FeatureIterator<SimpleFeature> 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) { + throw new IllegalStateException(); + } + if (greenAreaTypes.contains(nutzart)) { + greenAreas.add(new GreenArea((Polygon) geometry.getGeometryN(0))); + } else if (roadAreaTypes.contains(nutzart)) { + roadAreas.add(new RoadArea((Polygon) geometry.getGeometryN(0))); + } else { + landUseAreas.add(new LandUseArea((Polygon) geometry.getGeometryN(0))); + } + } + } + } + +} 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 c8193c30278a71e29f9ba470501b8c6283b1a5ab..8c0edaed5bcc045c46fd6ff7d2b3015e02082887 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 @@ -1,8 +1,7 @@ package de.hft.stuttgart.citygml.green.osm; -import java.io.ByteArrayInputStream; import java.io.IOException; -import java.net.MalformedURLException; +import java.io.StringReader; import java.net.URI; import java.net.URLEncoder; import java.net.http.HttpClient; @@ -13,20 +12,13 @@ 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.Iterator; import java.util.List; -import java.util.Map; import java.util.Set; import java.util.UUID; -import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.xml.XMLConstants; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.citygml4j.core.model.CityGMLVersion; @@ -34,12 +26,10 @@ 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.AbstractGenericAttribute; -import org.citygml4j.core.model.core.AbstractGenericAttributeProperty; import org.citygml4j.core.model.core.CityModel; -import org.citygml4j.core.model.generics.StringAttribute; +import org.citygml4j.core.model.landuse.LandUse; +import org.citygml4j.core.model.transportation.Road; import org.citygml4j.core.model.vegetation.PlantCover; -import org.citygml4j.core.model.vegetation.SolitaryVegetationObject; import org.citygml4j.core.model.waterbody.WaterBody; import org.citygml4j.core.visitor.ObjectWalker; import org.citygml4j.xml.CityGMLContext; @@ -51,11 +41,6 @@ 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.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.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.Geometry; import org.locationtech.jts.geom.GeometryFactory; @@ -67,12 +52,8 @@ import org.locationtech.proj4j.BasicCoordinateTransform; import org.locationtech.proj4j.CRSFactory; import org.locationtech.proj4j.CoordinateReferenceSystem; import org.locationtech.proj4j.ProjCoordinate; -import org.opengis.feature.simple.SimpleFeature; -import org.opengis.feature.simple.SimpleFeatureType; -import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; -import org.xml.sax.SAXException; import org.xmlobjects.gml.model.geometry.DirectPosition; import org.xmlobjects.gml.model.geometry.DirectPositionList; import org.xmlobjects.gml.model.geometry.Envelope; @@ -82,10 +63,17 @@ 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; +import de.hft.stuttgart.citygml.green.osm.jaxb.OsmRelation; +import de.hft.stuttgart.citygml.green.osm.jaxb.OsmTag; +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; + public class GreenEnricher { - - private static final double TRUNK_PERCENTAGE = 0.2; - private static final double CROWN_PERCENTAGE = 1 - TRUNK_PERCENTAGE; private static final int BOUNDING_BOX_INCREASE_IN_M = 100; @@ -113,6 +101,7 @@ public class GreenEnricher { nwr["type"="waterway"]; nwr["waterway"="stream"]; nwr["water"="pond"]; + nwr["landuse"="vineyard"]; ); out geom;"""; @@ -122,23 +111,18 @@ public class GreenEnricher { private static CoordinateReferenceSystem targetCRS = CRS_FACTORY.createFromName("EPSG:4326"); private static BasicCoordinateTransform transform; private static BasicCoordinateTransform backTransform; - public static GeometryFactory geomFactory = new GeometryFactory(); + public static final GeometryFactory GEOM_FACTORY = new GeometryFactory(); public static void main(String[] args) throws IOException, CityGMLContextException, CityGMLReadException, - InterruptedException, ParserConfigurationException, SAXException, CityGMLWriteException { + InterruptedException, ParserConfigurationException, CityGMLWriteException, JAXBException { 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); - transform = new BasicCoordinateTransform(sourceCRS, targetCRS); - backTransform = new BasicCoordinateTransform(targetCRS, sourceCRS); + createTransformers(cityModel); OsmData osmData = new OsmData(); - String boundingBoxString = extractAndConvertBoundingBox(cityModel, epsgCode, osmData); + String boundingBoxString = extractAndConvertBoundingBox(cityModel, osmData); // HttpResponse<String> response = getOsmData(boundingBoxString); // Files.write(Path.of("osm_response.xml"), response.body().getBytes(StandardCharsets.UTF_8)); // String osmResponse = response.body(); @@ -146,9 +130,6 @@ public class GreenEnricher { System.out.println("Parsing OSM response"); parseOsmResponse(osmResponse, osmData); - createBoundingBox(cityModel, osmData); - -// List<GreenArea> newGreenAreas = new ArrayList<>(); System.out.println("Fit data in bounding box"); fitToBoundingBox(osmData); @@ -160,134 +141,30 @@ public class GreenEnricher { convertGreenAreasToCityGML(cityModel, greenAreas); convertWaterAreasToCityGML(cityModel, osmData); - for (Waterway waterWay : osmData.getWaterways()) { - } - // trees + TreeUtils.insertTrees(cityModel, osmData); - TreeKatasterData katasterData = parseTreeKatasterData(Paths.get("data", "Baum.shp")); - for (Iterator<TreePoint> iterator = osmData.getTreePoints().iterator(); iterator.hasNext();) { - TreePoint tp = iterator.next(); - // if another tree from kataster is within 3m ignore it - for (Tree tree : katasterData.getTrees()) { - if (tp.getPoint().distance(tree.getPoint()) < 3) { - iterator.remove(); - } - } - } - - for (Tree tree : katasterData.getTrees()) { - double trunkRadius = tree.getTrunkRadius(); - double trunkHeight = tree.getTrunkHeight(); - double crownHeight = tree.getCrownHeight(); - double crownRadius = tree.getCrownRadius(); - - Coordinate coordinate = tree.getPoint().getCoordinate(); - if (Double.isNaN(coordinate.z)) { - coordinate.z = 0; - } - MultiSurface generatedTree = TreeGenerator.generateTree(coordinate, trunkRadius, trunkHeight, crownRadius, crownRadius, crownHeight); - SolitaryVegetationObject cover = new SolitaryVegetationObject(); - StringAttribute typeAttribute = new StringAttribute("type", tree.getType()); - AbstractGenericAttributeProperty attributeProp = new AbstractGenericAttributeProperty(typeAttribute); - cover.getGenericAttributes().add(attributeProp); - cover.setId(UUID.randomUUID().toString()); - cover.setLod2MultiSurface(new MultiSurfaceProperty(generatedTree)); - cityModel.getCityObjectMembers().add(new AbstractCityObjectProperty(cover)); - - } - - - for (TreePoint tp : osmData.getTreePoints()) { - // standard tree - double trunkRadius = 0.89 / (2 * Math.PI); - double trunkHeight = TRUNK_PERCENTAGE * 11.46; - double crownHeight = CROWN_PERCENTAGE * 11.46; - double crownRadius = 8 / 2d; - Coordinate coordinate = tp.getPoint().getCoordinate(); - if (Double.isNaN(coordinate.z)) { - coordinate.z = 0; - } - MultiSurface generatedTree = TreeGenerator.generateTree(coordinate, trunkRadius, trunkHeight, crownRadius, crownRadius, crownHeight); - SolitaryVegetationObject cover = new SolitaryVegetationObject(); - StringAttribute typeAttribute = new StringAttribute("type", "Acer campestre"); - AbstractGenericAttributeProperty attributeProp = new AbstractGenericAttributeProperty(typeAttribute); - cover.getGenericAttributes().add(attributeProp); - cover.setId(UUID.randomUUID().toString()); - cover.setLod2MultiSurface(new MultiSurfaceProperty(generatedTree)); - cityModel.getCityObjectMembers().add(new AbstractCityObjectProperty(cover)); - } - - - - -// -// for (TreeRow tr : osmData.getTreeRows()) { -// System.out.println(tr); -// } - clampToGround(cityModel); String inputString = inFile.getFileName().toString(); String inputPathWithoutFileEnding = inputString.substring(0, inputString.lastIndexOf('.')); - Path outputPath = Paths.get("data", inputPathWithoutFileEnding + "_with_greens.gml"); + Path outputPath = Paths.get("data", inputPathWithoutFileEnding + "_with_osm_greens.gml"); System.out.println("Writing output file."); writeCityGML(cityModel, outputPath); System.out.println("Done"); } - private static TreeKatasterData parseTreeKatasterData(Path path) throws IOException { - TreeKatasterData result = new TreeKatasterData(); - Map<String, Object> readParameters = new HashMap<>(); - readParameters.put("url", path.toUri().toURL()); - readParameters.put("charset", StandardCharsets.UTF_8); - DataStore dataStore = DataStoreFinder.getDataStore(readParameters); - String typeName = dataStore.getTypeNames()[0]; - - FeatureSource<SimpleFeatureType, SimpleFeature> source = - dataStore.getFeatureSource(typeName); - - FeatureCollection<SimpleFeatureType, SimpleFeature> collection = source.getFeatures(); - try (FeatureIterator<SimpleFeature> features = collection.features()) { - while (features.hasNext()) { - SimpleFeature feature = features.next(); - Tree tree = new Tree(); - - Point p = (Point) feature.getAttribute("the_geom"); - tree.setPoint(p); - - String type = feature.getAttribute("Bezeichnun").toString(); - tree.setType(type); - - Object treeHeightObject = feature.getAttribute("Baumhöhe"); - if (treeHeightObject == null) { - continue; - } - int treeHeight = Integer.parseInt(treeHeightObject.toString()); - double crownHeight = CROWN_PERCENTAGE * treeHeight; - double trunkHeight = TRUNK_PERCENTAGE * treeHeight; - tree.setCrownHeight(crownHeight); - tree.setTrunkHeight(trunkHeight); - - Object crownWidth = feature.getAttribute("Kronenbrei"); - if (crownWidth == null) { - continue; - } - tree.setCrownRadius(Float.parseFloat(crownWidth.toString()) / 2); - Object trunkCirc = feature.getAttribute("Stammumfan"); - if (trunkCirc == null) { - continue; - } - tree.setTrunkRadius(Integer.parseInt(trunkCirc.toString()) / (2 * Math.PI) / 100); - - result.getTrees().add(tree); - } - } - return result; + + public static void createTransformers(CityModel cityModel) { + String epsgCode = extractEpsgCode(cityModel); + sourceCRS = CRS_FACTORY.createFromName(epsgCode); + transform = new BasicCoordinateTransform(sourceCRS, targetCRS); + backTransform = new BasicCoordinateTransform(targetCRS, sourceCRS); } - private static void convertWaterAreasToCityGML(CityModel cityModel, OsmData osmData) { + + 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()); @@ -303,7 +180,7 @@ public class GreenEnricher { } } - private static void convertGreenAreasToCityGML(CityModel cityModel, List<GreenArea> greenAreas) { + public static void convertGreenAreasToCityGML(CityModel cityModel, List<GreenArea> greenAreas) { for (GreenArea ga : greenAreas) { org.xmlobjects.gml.model.geometry.primitives.Polygon poly = convertToCityGmlPoly(ga.getArea()); if (poly == null) { @@ -319,8 +196,65 @@ public class GreenEnricher { } } - private static void fitToBoundingBox(OsmData osmData) { - List<GreenArea> greenAreas = osmData.getGreenAreas(); + public static void fitToBoundingBox(OsmData osmData) { + fitGreenAreas(osmData, osmData.getGreenAreas()); + fitRoadAreas(osmData, osmData.getRoadAreas()); + fitLandUseAreas(osmData, osmData.getLandUseAreas()); + + clipWaterAreasToBoundingBox(osmData); + + for (Iterator<TreePoint> iterator = osmData.getTreePoints().iterator(); iterator.hasNext();) { + TreePoint tp = iterator.next(); + if (!osmData.getBoundingBox().contains(tp.getPoint())) { + iterator.remove(); + } + } + } + + + private static void fitLandUseAreas(OsmData osmData, List<LandUseArea> landUseAreas) { + List<LandUseArea> newLandUseAreas = new ArrayList<>(); + for (LandUseArea landUseArea : landUseAreas) { + Polygon area = landUseArea.getArea(); + Geometry intersection = area.intersection(osmData.getBoundingBox()); + if (intersection instanceof MultiPolygon multi) { + Polygon poly1 = (Polygon) multi.getGeometryN(0); + landUseArea.setArea(poly1); + for (int k = 1; k < multi.getNumGeometries(); k++) { + LandUseArea newLandUseArea = new LandUseArea(); + newLandUseArea.setArea((Polygon) multi.getGeometryN(k)); + newLandUseAreas.add(newLandUseArea); + } + } else { + landUseArea.setArea((Polygon) intersection); + } + } + landUseAreas.addAll(newLandUseAreas); + } + + + private static void fitRoadAreas(OsmData osmData, List<RoadArea> roadAreas) { + List<RoadArea> newRoadAreas = new ArrayList<>(); + for (RoadArea roadArea : roadAreas) { + Polygon area = roadArea.getArea(); + Geometry intersection = area.intersection(osmData.getBoundingBox()); + if (intersection instanceof MultiPolygon multi) { + Polygon poly1 = (Polygon) multi.getGeometryN(0); + roadArea.setArea(poly1); + for (int k = 1; k < multi.getNumGeometries(); k++) { + RoadArea newRoadArea = new RoadArea(); + newRoadArea.setArea((Polygon) multi.getGeometryN(k)); + newRoadAreas.add(newRoadArea); + } + } else { + roadArea.setArea((Polygon) intersection); + } + } + roadAreas.addAll(newRoadAreas); + } + + + private static void fitGreenAreas(OsmData osmData, List<GreenArea> greenAreas) { List<GreenArea> newGreenAreas = new ArrayList<>(); for (GreenArea greenArea : greenAreas) { Polygon area = greenArea.getArea(); @@ -338,16 +272,6 @@ public class GreenEnricher { } } greenAreas.addAll(newGreenAreas); - - clipWaterAreasToBoundingBox(osmData); - - for (Iterator<TreePoint> iterator = osmData.getTreePoints().iterator(); iterator.hasNext();) { - TreePoint tp = iterator.next(); - if (!osmData.getBoundingBox().contains(tp.getPoint())) { - iterator.remove(); - } - } - } private static void clipWaterAreasToBoundingBox(OsmData osmData) { @@ -394,25 +318,7 @@ public class GreenEnricher { } } } - - private static void createBoundingBox(CityModel cityModel, OsmData osmData) { - // TODO Auto-generated method stub - - } - -// private static MultiSurface generateTree(Point p) { -// double radiusTrunk = 0.2; -// -// MultiSurface result = new MultiSurface(); -// -// // trunk -// Coordinate center = p.getCoordinate(); -// List<Coordinate> coords = new ArrayList<>(); -// coords.add(new Coordinate(center.x, center.y + radiusTrunk)); -// coords.add(new Coordinate(center.x + radiusTrunk / 2, center.y + Math.cos(0.5) * radiusTrunk)); -// } - - private static void clampToGround(CityModel cityModel) { + public static void clampToGround(CityModel cityModel) { for (AbstractCityObjectProperty afp : cityModel.getCityObjectMembers()) { AbstractCityObject af = afp.getObject(); if (af instanceof Building b) { @@ -487,7 +393,7 @@ public class GreenEnricher { return response; } - private static void writeCityGML(CityModel cityModel, Path outputPath) + public static void writeCityGML(CityModel cityModel, Path outputPath) throws CityGMLWriteException, CityGMLContextException { CityGMLContext context = CityGMLContext.newInstance(); CityGMLVersion version = CityGMLVersion.v2_0; @@ -499,28 +405,110 @@ public class GreenEnricher { } } - private static OsmData parseOsmResponse(String osmResponse, OsmData osmData) - throws ParserConfigurationException, SAXException, IOException { - Document document = createDomFromOsmResponse(osmResponse); + public static void parseOsmResponse(String osmResponse, OsmData osmData) throws JAXBException { + JAXBContext context = JAXBContext.newInstance(OSM.class); + OSM osm = (OSM) context.createUnmarshaller().unmarshal(new StringReader(osmResponse)); + parseTrees(osmData.getTreePoints(), osm.getNodes()); + parseWays(osmData, osm); + parseRelations(osmData, osm); + } - // root element - Node osmItem = document.getChildNodes().item(0); - NodeList childNodes = osmItem.getChildNodes(); + private static void parseRelations(OsmData data, OSM osm) { + for (OsmRelation rel : osm.getRelations()) { + boolean isWater = false; - Set<String> usedIds = new HashSet<>(); + List<Polygon> polygons = new ArrayList<>(); + List<Coordinate> coordinates = new ArrayList<>(); + for (OsmMember member : rel.getMembers()) { + for (WayNode nd : member.getNodes()) { + ProjCoordinate converted = convertCoordinatesFrom84(nd.getLon(), nd.getLat()); + coordinates.add(new Coordinate(converted.x, converted.y)); + } - for (int i = 0; i < childNodes.getLength(); i++) { - Node node = childNodes.item(i); - if (parseTreeIfPossible(osmData.getTreePoints(), node, usedIds)) { - continue; + if (member.getRole().isBlank()) { + // assume outer ring + // check if this ring is closed + if (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()])); + coordinates.clear(); + polygons.add(polygon); + } + } } - if (parseGreenAreasIfPossible(osmData, node, usedIds)) { - continue; + + 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()])); + coordinates.clear(); + polygons.add(polygon); + } else { + // line + } + + for (OsmTag tag : rel.getTags()) { + if ("water".equals(tag.getValue()) || "waterway".equals(tag.getKey())) { + isWater = true; + } } - parseGreenRelationsIfPossible(osmData, node, usedIds); + + if (isWater) { + for (Polygon p : polygons) { + data.getWaterAreas().add(new WaterArea(p)); + } + } else { + for (Polygon p : polygons) { + data.getGreenAreas().add(new GreenArea(p)); + } + } + } + } + + private static void parseWays(OsmData data, OSM osm) { + for (OsmWay way : osm.getWays()) { + boolean water = false; + // search if it is water of green stuff + for (OsmTag tag : way.getTags()) { + if ("water".equals(tag.getValue()) || "waterway".equals(tag.getKey())) { + water = true; + } + } - return osmData; + List<Coordinate> coordinates = new ArrayList<>(); + for (WayNode nd : way.getNodes()) { + ProjCoordinate converted = convertCoordinatesFrom84(nd.getLon(), nd.getLat()); + coordinates.add(new Coordinate(converted.x, converted.y)); + } + + boolean isLine = false; + if (!coordinates.get(0).equals(coordinates.get(coordinates.size() - 1))) { + // assume line if start and end coordinate do not match? + isLine = true; + } + + if (water) { + if (isLine) { + LineString lineString = GEOM_FACTORY + .createLineString(coordinates.toArray(new Coordinate[coordinates.size()])); + data.getWaterways().add(new Waterway(lineString)); + } else { + Polygon polygon = GEOM_FACTORY + .createPolygon(coordinates.toArray(new Coordinate[coordinates.size()])); + data.getWaterAreas().add(new WaterArea(polygon)); + } + } else { + if (isLine) { + LineString lineString = GEOM_FACTORY + .createLineString(coordinates.toArray(new Coordinate[coordinates.size()])); + data.getTreeRows().add(new TreeRow(lineString)); + } else { + Polygon polygon = GEOM_FACTORY + .createPolygon(coordinates.toArray(new Coordinate[coordinates.size()])); + data.getGreenAreas().add(new GreenArea(polygon)); + } + } + } } private static boolean parseGreenRelationsIfPossible(OsmData data, Node node, Set<String> usedIds) { @@ -583,17 +571,17 @@ public class GreenEnricher { } if (water) { - org.locationtech.jts.geom.LinearRing outerLinearRing = geomFactory + org.locationtech.jts.geom.LinearRing outerLinearRing = GEOM_FACTORY .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 + org.locationtech.jts.geom.LinearRing innerLinearRing = GEOM_FACTORY .createLinearRing(innerRing.toArray(new Coordinate[innerRing.size()])); innerLinearRings.add(innerLinearRing); } - Polygon polygon = geomFactory.createPolygon(outerLinearRing, + Polygon polygon = GEOM_FACTORY.createPolygon(outerLinearRing, innerLinearRings.toArray(new org.locationtech.jts.geom.LinearRing[innerLinearRings.size()])); data.getWaterAreas().add(new WaterArea(polygon)); @@ -625,16 +613,6 @@ public class GreenEnricher { } - private static void validateRing(List<Coordinate> outerRing) { - if (outerRing.isEmpty()) { - return; - } - if (!outerRing.get(0).equals(outerRing.get(outerRing.size() - 1))) { - // close ring - outerRing.add(outerRing.get(0)); - } - } - private static boolean parseGreenAreasIfPossible(OsmData data, Node node, Set<String> usedIds) { if (!"way".equals(node.getNodeName())) { return false; @@ -676,20 +654,20 @@ public class GreenEnricher { if (water) { if (line) { - LineString lineString = geomFactory + LineString lineString = GEOM_FACTORY .createLineString(coordinates.toArray(new Coordinate[coordinates.size()])); data.getWaterways().add(new Waterway(lineString)); } else { - Polygon polygon = geomFactory.createPolygon(coordinates.toArray(new Coordinate[coordinates.size()])); + Polygon polygon = GEOM_FACTORY.createPolygon(coordinates.toArray(new Coordinate[coordinates.size()])); data.getWaterAreas().add(new WaterArea(polygon)); } } else { if (line) { - LineString lineString = geomFactory + LineString lineString = GEOM_FACTORY .createLineString(coordinates.toArray(new Coordinate[coordinates.size()])); data.getTreeRows().add(new TreeRow(lineString)); } else { - Polygon polygon = geomFactory.createPolygon(coordinates.toArray(new Coordinate[coordinates.size()])); + Polygon polygon = GEOM_FACTORY.createPolygon(coordinates.toArray(new Coordinate[coordinates.size()])); data.getGreenAreas().add(new GreenArea(polygon)); } } @@ -709,41 +687,15 @@ public class GreenEnricher { return namedItem.getNodeValue(); } - private static boolean parseTreeIfPossible(List<TreePoint> treePoints, Node node, Set<String> usedIds) { - if (!"node".equals(node.getNodeName())) { - return false; - } - String id = node.getAttributes().getNamedItem("id").getNodeValue(); - if (usedIds.contains(id)) { - System.out.println("Already used node id " + id); - return true; + private static void parseTrees(List<TreePoint> treePoints, List<OsmNode> nodes) { + for (OsmNode node : nodes) { + ProjCoordinate converted = convertCoordinatesFrom84(node.getLon(), node.getLat()); + Point point = GEOM_FACTORY.createPoint(new Coordinate(converted.x, converted.y)); + treePoints.add(new TreePoint(point)); } - usedIds.add(id); - double lat = Double.parseDouble(node.getAttributes().getNamedItem("lat").getNodeValue()); - double lon = Double.parseDouble(node.getAttributes().getNamedItem("lon").getNodeValue()); - ProjCoordinate converted = convertCoordinatesFrom84(lon, lat); - Point point = geomFactory.createPoint(new Coordinate(converted.x, converted.y)); - treePoints.add(new TreePoint(point)); - return true; - } - - private static Document createDomFromOsmResponse(String body) - throws ParserConfigurationException, SAXException, IOException { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - // to be compliant, completely disable DOCTYPE declaration: - factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); - // or completely disable external entities declarations: - factory.setFeature("http://xml.org/sax/features/external-general-entities", false); - factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); - // or prohibit the use of all protocols by external entities: - factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); - factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); - DocumentBuilder builder = factory.newDocumentBuilder(); - ByteArrayInputStream input = new ByteArrayInputStream(body.getBytes(StandardCharsets.UTF_8)); - return builder.parse(input); } - private static CityModel readCityGml(Path inFile) throws CityGMLContextException, CityGMLReadException { + public static CityModel readCityGml(Path inFile) throws CityGMLContextException, CityGMLReadException { CityGMLContext context = CityGMLContext.newInstance(); CityGMLInputFactory in = context.createCityGMLInputFactory(); try (CityGMLReader reader = in.createCityGMLReader(inFile)) { @@ -774,7 +726,7 @@ public class GreenEnricher { return srsName; } - private static String extractAndConvertBoundingBox(CityModel cityModel, String epsgCode, OsmData osmData) { + public static String extractAndConvertBoundingBox(CityModel cityModel, OsmData osmData) { Envelope calculatedEnvelope = cityModel.computeEnvelope(); DirectPosition lowerCorner = calculatedEnvelope.getLowerCorner(); @@ -805,7 +757,7 @@ public class GreenEnricher { bboxCoordinates.add(new Coordinate(lowerCorner.getValue().get(0) - BOUNDING_BOX_INCREASE_IN_M, lowerCorner.getValue().get(1) - BOUNDING_BOX_INCREASE_IN_M)); - Polygon poly = geomFactory.createPolygon(bboxCoordinates.toArray(new Coordinate[bboxCoordinates.size()])); + Polygon poly = GEOM_FACTORY.createPolygon(bboxCoordinates.toArray(new Coordinate[bboxCoordinates.size()])); osmData.setBoundingBox(poly); return lowerCornerProjected.y + "," + lowerCornerProjected.x + "," + upperCornerProjected.y + "," @@ -832,4 +784,38 @@ 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()); + continue; + } + MultiSurface ms = new MultiSurface(); + road.setId(UUID.randomUUID().toString()); + ms.getSurfaceMember().add(new SurfaceProperty(poly)); + road.setLod0MultiSurface(new MultiSurfaceProperty(ms)); + cityModel.getCityObjectMembers().add(new AbstractCityObjectProperty(road)); + } + } + + + public static void converLandUseAreasToCityGML(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()); + continue; + } + MultiSurface ms = new MultiSurface(); + landUse.setId(UUID.randomUUID().toString()); + ms.getSurfaceMember().add(new SurfaceProperty(poly)); + landUse.setLod0MultiSurface(new MultiSurfaceProperty(ms)); + cityModel.getCityObjectMembers().add(new AbstractCityObjectProperty(landUse)); + } + } + } diff --git a/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/LandUseArea.java b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/LandUseArea.java new file mode 100644 index 0000000000000000000000000000000000000000..2acbb244baf6a92df45655bb8c6459176371462f --- /dev/null +++ b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/LandUseArea.java @@ -0,0 +1,29 @@ +package de.hft.stuttgart.citygml.green.osm; + +import org.locationtech.jts.geom.Polygon; + +public class LandUseArea { + + private Polygon area; + + public LandUseArea() { + } + + public LandUseArea(Polygon area) { + this.area = area; + } + + public void setArea(Polygon area) { + this.area = area; + } + + public Polygon getArea() { + return area; + } + + @Override + public String toString() { + return "LandUseArea [area=" + area + "]"; + } + +} diff --git a/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/OsmData.java b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/OsmData.java index 0ae87234c69238e0d6964678d8793b9f2cffd6a3..b9535e1874b0e2dd888293f0535a0ecafe6e6413 100644 --- a/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/OsmData.java +++ b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/OsmData.java @@ -14,6 +14,8 @@ public class OsmData { private List<TreeRow> treeRows = new ArrayList<>(); private List<Waterway> waterways = new ArrayList<>(); private List<WaterArea> waterAreas = new ArrayList<>(); + private List<RoadArea> roadAreas = new ArrayList<>(); + private List<LandUseArea> landUseAreas = new ArrayList<>(); public void setBoundingBox(Polygon boundingBox) { this.boundingBox = boundingBox; @@ -42,5 +44,13 @@ public class OsmData { public List<TreeRow> getTreeRows() { return treeRows; } + + public List<RoadArea> getRoadAreas() { + return roadAreas; + } + + public List<LandUseArea> getLandUseAreas() { + return landUseAreas; + } } diff --git a/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/RoadArea.java b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/RoadArea.java new file mode 100644 index 0000000000000000000000000000000000000000..2b8042412489a5848b44db5457676d46a71125c4 --- /dev/null +++ b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/RoadArea.java @@ -0,0 +1,29 @@ +package de.hft.stuttgart.citygml.green.osm; + +import org.locationtech.jts.geom.Polygon; + +public class RoadArea { + + private Polygon area; + + public RoadArea() { + } + + public RoadArea(Polygon area) { + this.area = area; + } + + public void setArea(Polygon area) { + this.area = area; + } + + public Polygon getArea() { + return area; + } + + @Override + public String toString() { + return "RoadArea [area=" + area + "]"; + } + +} diff --git a/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/TreeGenerator.java b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/TreeGenerator.java index 198b9afa5d195c2e260a058ccd482a9482fad2c4..02ce93db7e6b31693298f11d76cc8883e959a9ae 100644 --- a/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/TreeGenerator.java +++ b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/TreeGenerator.java @@ -104,7 +104,7 @@ public class TreeGenerator { List<Coordinate> secondRing = ringCoordinates.get(1); for (int i = 0; i < secondRing.size(); i++) { Coordinate[] coordArray = new Coordinate[] { topPoint, secondRing.get(i), secondRing.get((i + 1) % secondRing.size()), topPoint }; - Polygon polygon = GreenEnricher.geomFactory.createPolygon(coordArray); + Polygon polygon = GreenEnricher.GEOM_FACTORY.createPolygon(coordArray); var convertedPoly = GreenEnricher.convertToCityGmlPoly(polygon); ms.getSurfaceMember().add(new SurfaceProperty(convertedPoly)); } @@ -118,7 +118,7 @@ public class TreeGenerator { Coordinate p3 = bottomRing.get(j); Coordinate p4 = bottomRing.get(nextRingIndex); Coordinate[] coordArray = new Coordinate[] { p1, p3, p4, p2, p1 }; - Polygon polygon = GreenEnricher.geomFactory.createPolygon(coordArray); + Polygon polygon = GreenEnricher.GEOM_FACTORY.createPolygon(coordArray); var convertedPoly = GreenEnricher.convertToCityGmlPoly(polygon); ms.getSurfaceMember().add(new SurfaceProperty(convertedPoly)); } @@ -131,7 +131,7 @@ public class TreeGenerator { Coordinate p1 = bottomRing.get(i); Coordinate p2 = bottomRing.get(nextRingIndex); Coordinate[] coordArray = new Coordinate[] { p2, p1, bottomPoint, p2 }; - Polygon polygon = GreenEnricher.geomFactory.createPolygon(coordArray); + Polygon polygon = GreenEnricher.GEOM_FACTORY.createPolygon(coordArray); var convertedPoly = GreenEnricher.convertToCityGmlPoly(polygon); ms.getSurfaceMember().add(new SurfaceProperty(convertedPoly)); } @@ -140,7 +140,7 @@ public class TreeGenerator { } private static Polygon convertPolygon(List<Coordinate> trunkWestCoordinateList) { - return GreenEnricher.geomFactory + return GreenEnricher.GEOM_FACTORY .createPolygon(trunkWestCoordinateList.toArray(new Coordinate[trunkWestCoordinateList.size()])); } 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 index fac9652025825d78b5d7160873596976cb21d811..355da9aec5cdfb54475d904d54e3ae981015ac01 100644 --- 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 @@ -1,12 +1,78 @@ package de.hft.stuttgart.citygml.green.osm; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; + +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.locationtech.jts.geom.Point; +import org.opengis.feature.simple.SimpleFeature; +import org.opengis.feature.simple.SimpleFeatureType; public class TreeKatasterData { + public static final double TRUNK_PERCENTAGE = 0.2; + public static final double CROWN_PERCENTAGE = 1 - TRUNK_PERCENTAGE; + private List<Tree> trees; + public static TreeKatasterData parseTreeKatasterData(Path path) throws IOException { + TreeKatasterData result = new TreeKatasterData(); + Map<String, Object> readParameters = new HashMap<>(); + readParameters.put("url", path.toUri().toURL()); + readParameters.put("charset", StandardCharsets.UTF_8); + DataStore dataStore = DataStoreFinder.getDataStore(readParameters); + String typeName = dataStore.getTypeNames()[0]; + + FeatureSource<SimpleFeatureType, SimpleFeature> source = dataStore.getFeatureSource(typeName); + + FeatureCollection<SimpleFeatureType, SimpleFeature> collection = source.getFeatures(); + try (FeatureIterator<SimpleFeature> features = collection.features()) { + while (features.hasNext()) { + SimpleFeature feature = features.next(); + Tree tree = new Tree(); + + Point p = (Point) feature.getAttribute("the_geom"); + tree.setPoint(p); + + String type = feature.getAttribute("Bezeichnun").toString(); + tree.setType(type); + + Object treeHeightObject = feature.getAttribute("Baumhöhe"); + if (treeHeightObject == null) { + continue; + } + int treeHeight = Integer.parseInt(treeHeightObject.toString()); + double crownHeight = CROWN_PERCENTAGE * treeHeight; + double trunkHeight = TRUNK_PERCENTAGE * treeHeight; + tree.setCrownHeight(crownHeight); + tree.setTrunkHeight(trunkHeight); + + Object crownWidth = feature.getAttribute("Kronenbrei"); + if (crownWidth == null) { + continue; + } + tree.setCrownRadius(Float.parseFloat(crownWidth.toString()) / 2); + Object trunkCirc = feature.getAttribute("Stammumfan"); + if (trunkCirc == null) { + continue; + } + tree.setTrunkRadius(Integer.parseInt(trunkCirc.toString()) / (2 * Math.PI) / 100); + + result.getTrees().add(tree); + } + } + return result; + } + public List<Tree> getTrees() { if (trees == null) { trees = new ArrayList<>(); 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 new file mode 100644 index 0000000000000000000000000000000000000000..970d52e784ad0029f7b77bd67a80ed5b2de745fe --- /dev/null +++ b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/TreeUtils.java @@ -0,0 +1,83 @@ +package de.hft.stuttgart.citygml.green.osm; + +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; +import org.locationtech.jts.geom.Coordinate; +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 static void insertTrees(CityModel cityModel, OsmData osmData) throws IOException { + TreeKatasterData katasterData = TreeKatasterData.parseTreeKatasterData(Paths.get("data", "Baum.shp")); + generateTreesFromKataster(cityModel, katasterData); + + // All kataster trees are taken, osm trees are removed + filterDuplicateTreesFromOSM(osmData, katasterData); + + generateTreesFromOSM(cityModel, osmData); + + } + + private static void filterDuplicateTreesFromOSM(OsmData osmData, TreeKatasterData katasterData) { + for (Iterator<TreePoint> iterator = osmData.getTreePoints().iterator(); iterator.hasNext();) { + TreePoint tp = iterator.next(); + // if another tree from kataster is within 3m ignore it + for (Tree tree : katasterData.getTrees()) { + if (tp.getPoint().distance(tree.getPoint()) < 3) { + iterator.remove(); + } + } + } + } + + private static void generateTreesFromOSM(CityModel cityModel, OsmData osmData) { + for (TreePoint tp : osmData.getTreePoints()) { + // standard tree + double trunkRadius = 0.89 / (2 * Math.PI); + double trunkHeight = TreeKatasterData.TRUNK_PERCENTAGE * 11.46; + double crownHeight = TreeKatasterData.CROWN_PERCENTAGE * 11.46; + double crownRadius = 8 / 2d; + Coordinate coordinate = tp.getPoint().getCoordinate(); + if (Double.isNaN(coordinate.z)) { + coordinate.z = 0; + } + MultiSurface generatedTree = TreeGenerator.generateTree(coordinate, trunkRadius, trunkHeight, crownRadius, + crownRadius, crownHeight); + SolitaryVegetationObject cover = new SolitaryVegetationObject(); + cover.setSpecies(new Code("Acer campestre")); + cover.setId(UUID.randomUUID().toString()); + cover.setLod2MultiSurface(new MultiSurfaceProperty(generatedTree)); + cityModel.getCityObjectMembers().add(new AbstractCityObjectProperty(cover)); + } + } + + private static void generateTreesFromKataster(CityModel cityModel, TreeKatasterData katasterData) { + for (Tree tree : katasterData.getTrees()) { + double trunkRadius = tree.getTrunkRadius(); + double trunkHeight = tree.getTrunkHeight(); + double crownHeight = tree.getCrownHeight(); + double crownRadius = tree.getCrownRadius(); + + Coordinate coordinate = tree.getPoint().getCoordinate(); + if (Double.isNaN(coordinate.z)) { + coordinate.z = 0; + } + MultiSurface generatedTree = TreeGenerator.generateTree(coordinate, trunkRadius, trunkHeight, crownRadius, + crownRadius, crownHeight); + SolitaryVegetationObject cover = new SolitaryVegetationObject(); + cover.setSpecies(new Code(tree.getType())); + cover.setId(UUID.randomUUID().toString()); + cover.setLod2MultiSurface(new MultiSurfaceProperty(generatedTree)); + cityModel.getCityObjectMembers().add(new AbstractCityObjectProperty(cover)); + } + } + +} diff --git a/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/jaxb/Bounds.java b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/jaxb/Bounds.java new file mode 100644 index 0000000000000000000000000000000000000000..5db5a4740c54edc21845c1e013db01c5df2025fd --- /dev/null +++ b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/jaxb/Bounds.java @@ -0,0 +1,35 @@ +package de.hft.stuttgart.citygml.green.osm.jaxb; + +import jakarta.xml.bind.annotation.XmlAttribute; + +public class Bounds { + + @XmlAttribute(name = "minlat") + private double minLat; + + @XmlAttribute(name = "minlon") + private double minLon; + + @XmlAttribute(name = "maxlat") + private double maxLat; + + @XmlAttribute(name = "maxlon") + private double maxLon; + + public double getMaxLat() { + return maxLat; + } + + public double getMaxLon() { + return maxLon; + } + + public double getMinLat() { + return minLat; + } + + public double getMinLon() { + return minLon; + } + +} diff --git a/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/jaxb/Meta.java b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/jaxb/Meta.java new file mode 100644 index 0000000000000000000000000000000000000000..c0bde7b82bc036334e7b57c978d25282de8d309d --- /dev/null +++ b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/jaxb/Meta.java @@ -0,0 +1,14 @@ +package de.hft.stuttgart.citygml.green.osm.jaxb; + +import jakarta.xml.bind.annotation.XmlAttribute; + +public class Meta { + + @XmlAttribute(name = "osm_base") + private String osmBase; + + public String getOsmBase() { + return osmBase; + } + +} diff --git a/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/jaxb/OSM.java b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/jaxb/OSM.java new file mode 100644 index 0000000000000000000000000000000000000000..e848a0e2d1e1f6748affccf726ec58190cca8579 --- /dev/null +++ b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/jaxb/OSM.java @@ -0,0 +1,79 @@ +package de.hft.stuttgart.citygml.green.osm.jaxb; + +import java.util.ArrayList; +import java.util.List; + +import jakarta.xml.bind.annotation.XmlAttribute; +import jakarta.xml.bind.annotation.XmlElement; +import jakarta.xml.bind.annotation.XmlElements; +import jakarta.xml.bind.annotation.XmlRootElement; + +@XmlRootElement(name = "osm") +public class OSM { + + @XmlAttribute + private String version; + + @XmlAttribute + private String generator; + + @XmlElement + private String note; + + @XmlElement + private Meta meta; + + @XmlElement + private Bounds bounds; + + @XmlElements(value = { @XmlElement(name = "node", type = OsmNode.class) }) + private List<OsmNode> nodes; + + @XmlElements(value = { @XmlElement(name = "way", type = OsmWay.class) }) + private List<OsmWay> ways; + + @XmlElements(value = { @XmlElement(name = "relation", type = OsmRelation.class) }) + private List<OsmRelation> relations; + + public List<OsmRelation> getRelations() { + if (relations == null) { + relations = new ArrayList<>(); + } + return relations; + } + + public List<OsmWay> getWays() { + if (ways == null) { + ways = new ArrayList<>(); + } + return ways; + } + + public List<OsmNode> getNodes() { + if (nodes == null) { + nodes = new ArrayList<>(); + } + return nodes; + } + + public Bounds getBounds() { + return bounds; + } + + public String getVersion() { + return version; + } + + public String getGenerator() { + return generator; + } + + public String getNote() { + return note; + } + + public Meta getMeta() { + return meta; + } + +} diff --git a/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/jaxb/OsmMember.java b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/jaxb/OsmMember.java new file mode 100644 index 0000000000000000000000000000000000000000..d86f30bac9e64a60b90a0d4cee787b9ee41f8f5e --- /dev/null +++ b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/jaxb/OsmMember.java @@ -0,0 +1,43 @@ +package de.hft.stuttgart.citygml.green.osm.jaxb; + +import java.util.ArrayList; +import java.util.List; + +import jakarta.xml.bind.annotation.XmlAttribute; +import jakarta.xml.bind.annotation.XmlElement; +import jakarta.xml.bind.annotation.XmlElements; + +public class OsmMember { + + @XmlAttribute + private String type; + + @XmlAttribute + private String ref; + + @XmlAttribute + private String role; + + @XmlElements(value = { @XmlElement(name = "nd", type = WayNode.class) }) + private List<WayNode> nodes; + + public List<WayNode> getNodes() { + if (nodes == null) { + nodes = new ArrayList<>(); + } + return nodes; + } + + public String getRef() { + return ref; + } + + public String getRole() { + return role; + } + + public String getType() { + return type; + } + +} diff --git a/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/jaxb/OsmNode.java b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/jaxb/OsmNode.java new file mode 100644 index 0000000000000000000000000000000000000000..f6c290da3814ad657500e1e87bffaa200fe51174 --- /dev/null +++ b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/jaxb/OsmNode.java @@ -0,0 +1,44 @@ +package de.hft.stuttgart.citygml.green.osm.jaxb; + +import java.util.ArrayList; +import java.util.List; + +import jakarta.xml.bind.annotation.XmlAttribute; +import jakarta.xml.bind.annotation.XmlElement; +import jakarta.xml.bind.annotation.XmlElements; + +public class OsmNode { + + @XmlAttribute + private String id; + + @XmlAttribute + private double lat; + + @XmlAttribute + private double lon; + + @XmlElements(value = { @XmlElement(name = "tag", type = OsmTag.class) }) + private List<OsmTag> tags; + + public String getId() { + return id; + } + + public double getLat() { + return lat; + } + + public double getLon() { + return lon; + } + + public List<OsmTag> getTags() { + if (tags == null) { + tags = new ArrayList<>(); + } + return tags; + } + + +} diff --git a/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/jaxb/OsmRelation.java b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/jaxb/OsmRelation.java new file mode 100644 index 0000000000000000000000000000000000000000..b5ad87cdc5c1c6c1eb33ffb2a04a893b8e8e4b18 --- /dev/null +++ b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/jaxb/OsmRelation.java @@ -0,0 +1,48 @@ +package de.hft.stuttgart.citygml.green.osm.jaxb; + +import java.util.ArrayList; +import java.util.List; + +import jakarta.xml.bind.annotation.XmlAttribute; +import jakarta.xml.bind.annotation.XmlElement; +import jakarta.xml.bind.annotation.XmlElements; + +public class OsmRelation { + + @XmlAttribute + private String id; + + @XmlElement + private Bounds bounds; + + @XmlElements(value = { @XmlElement(name = "member", type = OsmMember.class) }) + private List<OsmMember> members; + + @XmlElements(value = { @XmlElement(name = "tag", type = OsmTag.class) }) + private List<OsmTag> tags; + + + public List<OsmTag> getTags() { + if (tags == null) { + tags = new ArrayList<>(); + } + return tags; + } + + public List<OsmMember> getMembers() { + if (members == null) { + members = new ArrayList<>(); + } + return members; + } + + public Bounds getBounds() { + return bounds; + } + + public String getId() { + return id; + } + + +} diff --git a/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/jaxb/OsmTag.java b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/jaxb/OsmTag.java new file mode 100644 index 0000000000000000000000000000000000000000..95f7e73e4d442e99bb180121ee380a98a5acf5be --- /dev/null +++ b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/jaxb/OsmTag.java @@ -0,0 +1,21 @@ +package de.hft.stuttgart.citygml.green.osm.jaxb; + +import jakarta.xml.bind.annotation.XmlAttribute; + +public class OsmTag { + + @XmlAttribute(name = "k") + private String key; + + @XmlAttribute(name = "v") + private String value; + + public String getKey() { + return key; + } + + public String getValue() { + return value; + } + +} diff --git a/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/jaxb/OsmWay.java b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/jaxb/OsmWay.java new file mode 100644 index 0000000000000000000000000000000000000000..9872cb612b202b6be0e124e5ee8fd176c0cdc9fd --- /dev/null +++ b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/jaxb/OsmWay.java @@ -0,0 +1,47 @@ +package de.hft.stuttgart.citygml.green.osm.jaxb; + +import java.util.ArrayList; +import java.util.List; + +import jakarta.xml.bind.annotation.XmlAttribute; +import jakarta.xml.bind.annotation.XmlElement; +import jakarta.xml.bind.annotation.XmlElements; + +public class OsmWay { + + @XmlAttribute + private String id; + + @XmlElement + private Bounds bounds; + + @XmlElements(value = { @XmlElement(name = "nd", type = WayNode.class) }) + private List<WayNode> nodes; + + @XmlElements(value = { @XmlElement(name = "tag", type = OsmTag.class) }) + private List<OsmTag> tags; + + + public List<OsmTag> getTags() { + if (tags == null) { + tags = new ArrayList<>(); + } + return tags; + } + + public String getId() { + return id; + } + + public Bounds getBounds() { + return bounds; + } + + public List<WayNode> getNodes() { + if (nodes == null) { + nodes = new ArrayList<>(); + } + return nodes; + } + +} diff --git a/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/jaxb/WayNode.java b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/jaxb/WayNode.java new file mode 100644 index 0000000000000000000000000000000000000000..d7d365ab3f423bc99daf761a0823e5dca0c3cf21 --- /dev/null +++ b/enrich-citygml-with-greenarea/src/main/java/de/hft/stuttgart/citygml/green/osm/jaxb/WayNode.java @@ -0,0 +1,28 @@ +package de.hft.stuttgart.citygml.green.osm.jaxb; + +import jakarta.xml.bind.annotation.XmlAttribute; + +public class WayNode { + + @XmlAttribute + private String ref; + + @XmlAttribute + private double lat; + + @XmlAttribute + private double lon; + + public double getLat() { + return lat; + } + + public double getLon() { + return lon; + } + + public String getRef() { + return ref; + } + +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..4ed60d453a5ff7222eaad33debc7b1a84a64c7ea --- /dev/null +++ b/enrich-citygml-with-greenarea/src/test/java/de/hft/stuttgart/citygml/green/alkis/AlkisGreenEnricherTest.java @@ -0,0 +1,21 @@ +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 { + + @Test + void testAlkisGreen() throws IOException, CityGMLContextException, CityGMLReadException, JAXBException, CityGMLWriteException { + String[] args = new String[] {"data/Grombühl_v3.gml"}; + + AlkisGreenEnricher.main(args); + } + +}