You need to sign in or sign up before continuing.
Commit 3e042784 authored by Matthias Betz's avatar Matthias Betz
Browse files

add alkis land use parsing

Showing with 989 additions and 254 deletions
+989 -254
...@@ -25,6 +25,19 @@ ...@@ -25,6 +25,19 @@
</repositories> </repositories>
<dependencies> <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 --> <!-- https://mvnrepository.com/artifact/org.geotools/gt-shapefile -->
<dependency> <dependency>
<groupId>org.geotools</groupId> <groupId>org.geotools</groupId>
......
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)));
}
}
}
}
}
package de.hft.stuttgart.citygml.green.osm; package de.hft.stuttgart.citygml.green.osm;
import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.net.MalformedURLException; import java.io.StringReader;
import java.net.URI; import java.net.URI;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.net.http.HttpClient; import java.net.http.HttpClient;
...@@ -13,20 +12,13 @@ import java.nio.file.Files; ...@@ -13,20 +12,13 @@ import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; 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 javax.xml.parsers.ParserConfigurationException;
import org.citygml4j.core.model.CityGMLVersion; import org.citygml4j.core.model.CityGMLVersion;
...@@ -34,12 +26,10 @@ import org.citygml4j.core.model.building.Building; ...@@ -34,12 +26,10 @@ import org.citygml4j.core.model.building.Building;
import org.citygml4j.core.model.core.AbstractCityObject; import org.citygml4j.core.model.core.AbstractCityObject;
import org.citygml4j.core.model.core.AbstractCityObjectProperty; import org.citygml4j.core.model.core.AbstractCityObjectProperty;
import org.citygml4j.core.model.core.AbstractFeature; 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.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.PlantCover;
import org.citygml4j.core.model.vegetation.SolitaryVegetationObject;
import org.citygml4j.core.model.waterbody.WaterBody; import org.citygml4j.core.model.waterbody.WaterBody;
import org.citygml4j.core.visitor.ObjectWalker; import org.citygml4j.core.visitor.ObjectWalker;
import org.citygml4j.xml.CityGMLContext; import org.citygml4j.xml.CityGMLContext;
...@@ -51,11 +41,6 @@ import org.citygml4j.xml.reader.CityGMLReader; ...@@ -51,11 +41,6 @@ import org.citygml4j.xml.reader.CityGMLReader;
import org.citygml4j.xml.writer.CityGMLOutputFactory; import org.citygml4j.xml.writer.CityGMLOutputFactory;
import org.citygml4j.xml.writer.CityGMLWriteException; import org.citygml4j.xml.writer.CityGMLWriteException;
import org.citygml4j.xml.writer.CityGMLWriter; 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.Coordinate;
import org.locationtech.jts.geom.Geometry; import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryFactory; import org.locationtech.jts.geom.GeometryFactory;
...@@ -67,12 +52,8 @@ import org.locationtech.proj4j.BasicCoordinateTransform; ...@@ -67,12 +52,8 @@ import org.locationtech.proj4j.BasicCoordinateTransform;
import org.locationtech.proj4j.CRSFactory; import org.locationtech.proj4j.CRSFactory;
import org.locationtech.proj4j.CoordinateReferenceSystem; import org.locationtech.proj4j.CoordinateReferenceSystem;
import org.locationtech.proj4j.ProjCoordinate; 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.Node;
import org.w3c.dom.NodeList; import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.xmlobjects.gml.model.geometry.DirectPosition; import org.xmlobjects.gml.model.geometry.DirectPosition;
import org.xmlobjects.gml.model.geometry.DirectPositionList; import org.xmlobjects.gml.model.geometry.DirectPositionList;
import org.xmlobjects.gml.model.geometry.Envelope; import org.xmlobjects.gml.model.geometry.Envelope;
...@@ -82,10 +63,17 @@ import org.xmlobjects.gml.model.geometry.primitives.AbstractRingProperty; ...@@ -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.LinearRing;
import org.xmlobjects.gml.model.geometry.primitives.SurfaceProperty; import org.xmlobjects.gml.model.geometry.primitives.SurfaceProperty;
public class GreenEnricher { 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;
private static final double TRUNK_PERCENTAGE = 0.2; public class GreenEnricher {
private static final double CROWN_PERCENTAGE = 1 - TRUNK_PERCENTAGE;
private static final int BOUNDING_BOX_INCREASE_IN_M = 100; private static final int BOUNDING_BOX_INCREASE_IN_M = 100;
...@@ -113,6 +101,7 @@ public class GreenEnricher { ...@@ -113,6 +101,7 @@ public class GreenEnricher {
nwr["type"="waterway"]; nwr["type"="waterway"];
nwr["waterway"="stream"]; nwr["waterway"="stream"];
nwr["water"="pond"]; nwr["water"="pond"];
nwr["landuse"="vineyard"];
); );
out geom;"""; out geom;""";
...@@ -122,23 +111,18 @@ public class GreenEnricher { ...@@ -122,23 +111,18 @@ public class GreenEnricher {
private static CoordinateReferenceSystem targetCRS = CRS_FACTORY.createFromName("EPSG:4326"); private static CoordinateReferenceSystem targetCRS = CRS_FACTORY.createFromName("EPSG:4326");
private static BasicCoordinateTransform transform; private static BasicCoordinateTransform transform;
private static BasicCoordinateTransform backTransform; 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, public static void main(String[] args) throws IOException, CityGMLContextException, CityGMLReadException,
InterruptedException, ParserConfigurationException, SAXException, CityGMLWriteException { InterruptedException, ParserConfigurationException, CityGMLWriteException, JAXBException {
System.out.println("Reading CityGML file"); System.out.println("Reading CityGML file");
Path inFile = Paths.get(args[0]); Path inFile = Paths.get(args[0]);
CityModel cityModel = readCityGml(inFile); CityModel cityModel = readCityGml(inFile);
createTransformers(cityModel);
String epsgCode = extractEpsgCode(cityModel);
sourceCRS = CRS_FACTORY.createFromName(epsgCode);
transform = new BasicCoordinateTransform(sourceCRS, targetCRS);
backTransform = new BasicCoordinateTransform(targetCRS, sourceCRS);
OsmData osmData = new OsmData(); OsmData osmData = new OsmData();
String boundingBoxString = extractAndConvertBoundingBox(cityModel, epsgCode, osmData); String boundingBoxString = extractAndConvertBoundingBox(cityModel, osmData);
// HttpResponse<String> response = getOsmData(boundingBoxString); // HttpResponse<String> response = getOsmData(boundingBoxString);
// Files.write(Path.of("osm_response.xml"), response.body().getBytes(StandardCharsets.UTF_8)); // Files.write(Path.of("osm_response.xml"), response.body().getBytes(StandardCharsets.UTF_8));
// String osmResponse = response.body(); // String osmResponse = response.body();
...@@ -146,9 +130,6 @@ public class GreenEnricher { ...@@ -146,9 +130,6 @@ public class GreenEnricher {
System.out.println("Parsing OSM response"); System.out.println("Parsing OSM response");
parseOsmResponse(osmResponse, osmData); parseOsmResponse(osmResponse, osmData);
createBoundingBox(cityModel, osmData);
// List<GreenArea> newGreenAreas = new ArrayList<>();
System.out.println("Fit data in bounding box"); System.out.println("Fit data in bounding box");
fitToBoundingBox(osmData); fitToBoundingBox(osmData);
...@@ -160,134 +141,30 @@ public class GreenEnricher { ...@@ -160,134 +141,30 @@ public class GreenEnricher {
convertGreenAreasToCityGML(cityModel, greenAreas); convertGreenAreasToCityGML(cityModel, greenAreas);
convertWaterAreasToCityGML(cityModel, osmData); convertWaterAreasToCityGML(cityModel, osmData);
for (Waterway waterWay : osmData.getWaterways()) {
}
// trees // 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); clampToGround(cityModel);
String inputString = inFile.getFileName().toString(); String inputString = inFile.getFileName().toString();
String inputPathWithoutFileEnding = inputString.substring(0, inputString.lastIndexOf('.')); 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."); System.out.println("Writing output file.");
writeCityGML(cityModel, outputPath); writeCityGML(cityModel, outputPath);
System.out.println("Done"); 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"); public static void createTransformers(CityModel cityModel) {
tree.setPoint(p); String epsgCode = extractEpsgCode(cityModel);
sourceCRS = CRS_FACTORY.createFromName(epsgCode);
String type = feature.getAttribute("Bezeichnun").toString(); transform = new BasicCoordinateTransform(sourceCRS, targetCRS);
tree.setType(type); backTransform = new BasicCoordinateTransform(targetCRS, sourceCRS);
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;
}
private static void convertWaterAreasToCityGML(CityModel cityModel, OsmData osmData) { public static void convertWaterAreasToCityGML(CityModel cityModel, OsmData osmData) {
for (WaterArea waterArea : osmData.getWaterAreas()) { for (WaterArea waterArea : osmData.getWaterAreas()) {
WaterBody wb = new WaterBody(); WaterBody wb = new WaterBody();
org.xmlobjects.gml.model.geometry.primitives.Polygon poly = convertToCityGmlPoly(waterArea.getArea()); org.xmlobjects.gml.model.geometry.primitives.Polygon poly = convertToCityGmlPoly(waterArea.getArea());
...@@ -303,7 +180,7 @@ public class GreenEnricher { ...@@ -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) { for (GreenArea ga : greenAreas) {
org.xmlobjects.gml.model.geometry.primitives.Polygon poly = convertToCityGmlPoly(ga.getArea()); org.xmlobjects.gml.model.geometry.primitives.Polygon poly = convertToCityGmlPoly(ga.getArea());
if (poly == null) { if (poly == null) {
...@@ -319,8 +196,65 @@ public class GreenEnricher { ...@@ -319,8 +196,65 @@ public class GreenEnricher {
} }
} }
private static void fitToBoundingBox(OsmData osmData) { public static void fitToBoundingBox(OsmData osmData) {
List<GreenArea> greenAreas = osmData.getGreenAreas(); 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<>(); List<GreenArea> newGreenAreas = new ArrayList<>();
for (GreenArea greenArea : greenAreas) { for (GreenArea greenArea : greenAreas) {
Polygon area = greenArea.getArea(); Polygon area = greenArea.getArea();
...@@ -338,16 +272,6 @@ public class GreenEnricher { ...@@ -338,16 +272,6 @@ public class GreenEnricher {
} }
} }
greenAreas.addAll(newGreenAreas); 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) { private static void clipWaterAreasToBoundingBox(OsmData osmData) {
...@@ -394,25 +318,7 @@ public class GreenEnricher { ...@@ -394,25 +318,7 @@ public class GreenEnricher {
} }
} }
} }
public static void clampToGround(CityModel cityModel) {
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) {
for (AbstractCityObjectProperty afp : cityModel.getCityObjectMembers()) { for (AbstractCityObjectProperty afp : cityModel.getCityObjectMembers()) {
AbstractCityObject af = afp.getObject(); AbstractCityObject af = afp.getObject();
if (af instanceof Building b) { if (af instanceof Building b) {
...@@ -487,7 +393,7 @@ public class GreenEnricher { ...@@ -487,7 +393,7 @@ public class GreenEnricher {
return response; return response;
} }
private static void writeCityGML(CityModel cityModel, Path outputPath) public static void writeCityGML(CityModel cityModel, Path outputPath)
throws CityGMLWriteException, CityGMLContextException { throws CityGMLWriteException, CityGMLContextException {
CityGMLContext context = CityGMLContext.newInstance(); CityGMLContext context = CityGMLContext.newInstance();
CityGMLVersion version = CityGMLVersion.v2_0; CityGMLVersion version = CityGMLVersion.v2_0;
...@@ -499,28 +405,110 @@ public class GreenEnricher { ...@@ -499,28 +405,110 @@ public class GreenEnricher {
} }
} }
private static OsmData parseOsmResponse(String osmResponse, OsmData osmData) public static void parseOsmResponse(String osmResponse, OsmData osmData) throws JAXBException {
throws ParserConfigurationException, SAXException, IOException { JAXBContext context = JAXBContext.newInstance(OSM.class);
Document document = createDomFromOsmResponse(osmResponse); OSM osm = (OSM) context.createUnmarshaller().unmarshal(new StringReader(osmResponse));
parseTrees(osmData.getTreePoints(), osm.getNodes());
parseWays(osmData, osm);
parseRelations(osmData, osm);
}
// root element private static void parseRelations(OsmData data, OSM osm) {
Node osmItem = document.getChildNodes().item(0); for (OsmRelation rel : osm.getRelations()) {
NodeList childNodes = osmItem.getChildNodes(); 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++) { if (member.getRole().isBlank()) {
Node node = childNodes.item(i); // assume outer ring
if (parseTreeIfPossible(osmData.getTreePoints(), node, usedIds)) { // check if this ring is closed
continue; 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;
} }
parseGreenRelationsIfPossible(osmData, node, usedIds);
} }
return osmData; 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;
}
}
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;
}
}
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) { private static boolean parseGreenRelationsIfPossible(OsmData data, Node node, Set<String> usedIds) {
...@@ -583,17 +571,17 @@ public class GreenEnricher { ...@@ -583,17 +571,17 @@ public class GreenEnricher {
} }
if (water) { if (water) {
org.locationtech.jts.geom.LinearRing outerLinearRing = geomFactory org.locationtech.jts.geom.LinearRing outerLinearRing = GEOM_FACTORY
.createLinearRing(outerRing.toArray(new Coordinate[outerRing.size()])); .createLinearRing(outerRing.toArray(new Coordinate[outerRing.size()]));
// create the inner rings // create the inner rings
List<org.locationtech.jts.geom.LinearRing> innerLinearRings = new ArrayList<>(); List<org.locationtech.jts.geom.LinearRing> innerLinearRings = new ArrayList<>();
for (List<Coordinate> innerRing : innerRings) { 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()])); .createLinearRing(innerRing.toArray(new Coordinate[innerRing.size()]));
innerLinearRings.add(innerLinearRing); innerLinearRings.add(innerLinearRing);
} }
Polygon polygon = geomFactory.createPolygon(outerLinearRing, Polygon polygon = GEOM_FACTORY.createPolygon(outerLinearRing,
innerLinearRings.toArray(new org.locationtech.jts.geom.LinearRing[innerLinearRings.size()])); innerLinearRings.toArray(new org.locationtech.jts.geom.LinearRing[innerLinearRings.size()]));
data.getWaterAreas().add(new WaterArea(polygon)); data.getWaterAreas().add(new WaterArea(polygon));
...@@ -625,16 +613,6 @@ public class GreenEnricher { ...@@ -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) { private static boolean parseGreenAreasIfPossible(OsmData data, Node node, Set<String> usedIds) {
if (!"way".equals(node.getNodeName())) { if (!"way".equals(node.getNodeName())) {
return false; return false;
...@@ -676,20 +654,20 @@ public class GreenEnricher { ...@@ -676,20 +654,20 @@ public class GreenEnricher {
if (water) { if (water) {
if (line) { if (line) {
LineString lineString = geomFactory LineString lineString = GEOM_FACTORY
.createLineString(coordinates.toArray(new Coordinate[coordinates.size()])); .createLineString(coordinates.toArray(new Coordinate[coordinates.size()]));
data.getWaterways().add(new Waterway(lineString)); data.getWaterways().add(new Waterway(lineString));
} else { } 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)); data.getWaterAreas().add(new WaterArea(polygon));
} }
} else { } else {
if (line) { if (line) {
LineString lineString = geomFactory LineString lineString = GEOM_FACTORY
.createLineString(coordinates.toArray(new Coordinate[coordinates.size()])); .createLineString(coordinates.toArray(new Coordinate[coordinates.size()]));
data.getTreeRows().add(new TreeRow(lineString)); data.getTreeRows().add(new TreeRow(lineString));
} else { } 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)); data.getGreenAreas().add(new GreenArea(polygon));
} }
} }
...@@ -709,41 +687,15 @@ public class GreenEnricher { ...@@ -709,41 +687,15 @@ public class GreenEnricher {
return namedItem.getNodeValue(); return namedItem.getNodeValue();
} }
private static boolean parseTreeIfPossible(List<TreePoint> treePoints, Node node, Set<String> usedIds) { private static void parseTrees(List<TreePoint> treePoints, List<OsmNode> nodes) {
if (!"node".equals(node.getNodeName())) { for (OsmNode node : nodes) {
return false; ProjCoordinate converted = convertCoordinatesFrom84(node.getLon(), node.getLat());
} Point point = GEOM_FACTORY.createPoint(new Coordinate(converted.x, converted.y));
String id = node.getAttributes().getNamedItem("id").getNodeValue();
if (usedIds.contains(id)) {
System.out.println("Already used node id " + id);
return true;
}
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)); 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(); CityGMLContext context = CityGMLContext.newInstance();
CityGMLInputFactory in = context.createCityGMLInputFactory(); CityGMLInputFactory in = context.createCityGMLInputFactory();
try (CityGMLReader reader = in.createCityGMLReader(inFile)) { try (CityGMLReader reader = in.createCityGMLReader(inFile)) {
...@@ -774,7 +726,7 @@ public class GreenEnricher { ...@@ -774,7 +726,7 @@ public class GreenEnricher {
return srsName; return srsName;
} }
private static String extractAndConvertBoundingBox(CityModel cityModel, String epsgCode, OsmData osmData) { public static String extractAndConvertBoundingBox(CityModel cityModel, OsmData osmData) {
Envelope calculatedEnvelope = cityModel.computeEnvelope(); Envelope calculatedEnvelope = cityModel.computeEnvelope();
DirectPosition lowerCorner = calculatedEnvelope.getLowerCorner(); DirectPosition lowerCorner = calculatedEnvelope.getLowerCorner();
...@@ -805,7 +757,7 @@ public class GreenEnricher { ...@@ -805,7 +757,7 @@ public class GreenEnricher {
bboxCoordinates.add(new Coordinate(lowerCorner.getValue().get(0) - BOUNDING_BOX_INCREASE_IN_M, bboxCoordinates.add(new Coordinate(lowerCorner.getValue().get(0) - BOUNDING_BOX_INCREASE_IN_M,
lowerCorner.getValue().get(1) - 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); osmData.setBoundingBox(poly);
return lowerCornerProjected.y + "," + lowerCornerProjected.x + "," + upperCornerProjected.y + "," return lowerCornerProjected.y + "," + lowerCornerProjected.x + "," + upperCornerProjected.y + ","
...@@ -832,4 +784,38 @@ public class GreenEnricher { ...@@ -832,4 +784,38 @@ public class GreenEnricher {
return result; 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));
}
}
} }
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 + "]";
}
}
...@@ -14,6 +14,8 @@ public class OsmData { ...@@ -14,6 +14,8 @@ public class OsmData {
private List<TreeRow> treeRows = new ArrayList<>(); private List<TreeRow> treeRows = new ArrayList<>();
private List<Waterway> waterways = new ArrayList<>(); private List<Waterway> waterways = new ArrayList<>();
private List<WaterArea> waterAreas = 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) { public void setBoundingBox(Polygon boundingBox) {
this.boundingBox = boundingBox; this.boundingBox = boundingBox;
...@@ -43,4 +45,12 @@ public class OsmData { ...@@ -43,4 +45,12 @@ public class OsmData {
return treeRows; return treeRows;
} }
public List<RoadArea> getRoadAreas() {
return roadAreas;
}
public List<LandUseArea> getLandUseAreas() {
return landUseAreas;
}
} }
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 + "]";
}
}
...@@ -104,7 +104,7 @@ public class TreeGenerator { ...@@ -104,7 +104,7 @@ public class TreeGenerator {
List<Coordinate> secondRing = ringCoordinates.get(1); List<Coordinate> secondRing = ringCoordinates.get(1);
for (int i = 0; i < secondRing.size(); i++) { for (int i = 0; i < secondRing.size(); i++) {
Coordinate[] coordArray = new Coordinate[] { topPoint, secondRing.get(i), secondRing.get((i + 1) % secondRing.size()), topPoint }; 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); var convertedPoly = GreenEnricher.convertToCityGmlPoly(polygon);
ms.getSurfaceMember().add(new SurfaceProperty(convertedPoly)); ms.getSurfaceMember().add(new SurfaceProperty(convertedPoly));
} }
...@@ -118,7 +118,7 @@ public class TreeGenerator { ...@@ -118,7 +118,7 @@ public class TreeGenerator {
Coordinate p3 = bottomRing.get(j); Coordinate p3 = bottomRing.get(j);
Coordinate p4 = bottomRing.get(nextRingIndex); Coordinate p4 = bottomRing.get(nextRingIndex);
Coordinate[] coordArray = new Coordinate[] { p1, p3, p4, p2, p1 }; 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); var convertedPoly = GreenEnricher.convertToCityGmlPoly(polygon);
ms.getSurfaceMember().add(new SurfaceProperty(convertedPoly)); ms.getSurfaceMember().add(new SurfaceProperty(convertedPoly));
} }
...@@ -131,7 +131,7 @@ public class TreeGenerator { ...@@ -131,7 +131,7 @@ public class TreeGenerator {
Coordinate p1 = bottomRing.get(i); Coordinate p1 = bottomRing.get(i);
Coordinate p2 = bottomRing.get(nextRingIndex); Coordinate p2 = bottomRing.get(nextRingIndex);
Coordinate[] coordArray = new Coordinate[] { p2, p1, bottomPoint, p2 }; 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); var convertedPoly = GreenEnricher.convertToCityGmlPoly(polygon);
ms.getSurfaceMember().add(new SurfaceProperty(convertedPoly)); ms.getSurfaceMember().add(new SurfaceProperty(convertedPoly));
} }
...@@ -140,7 +140,7 @@ public class TreeGenerator { ...@@ -140,7 +140,7 @@ public class TreeGenerator {
} }
private static Polygon convertPolygon(List<Coordinate> trunkWestCoordinateList) { private static Polygon convertPolygon(List<Coordinate> trunkWestCoordinateList) {
return GreenEnricher.geomFactory return GreenEnricher.GEOM_FACTORY
.createPolygon(trunkWestCoordinateList.toArray(new Coordinate[trunkWestCoordinateList.size()])); .createPolygon(trunkWestCoordinateList.toArray(new Coordinate[trunkWestCoordinateList.size()]));
} }
......
package de.hft.stuttgart.citygml.green.osm; 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.ArrayList;
import java.util.HashMap;
import java.util.List; 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 class TreeKatasterData {
public static final double TRUNK_PERCENTAGE = 0.2;
public static final double CROWN_PERCENTAGE = 1 - TRUNK_PERCENTAGE;
private List<Tree> trees; 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() { public List<Tree> getTrees() {
if (trees == null) { if (trees == null) {
trees = new ArrayList<>(); trees = new ArrayList<>();
......
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));
}
}
}
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;
}
}
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;
}
}
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;
}
}
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;
}
}
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;
}
}
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;
}
}
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;
}
}
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;
}
}
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;
}
}
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);
}
}
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