Commit 3e042784 authored by Matthias Betz's avatar Matthias Betz
Browse files

add alkis land use parsing

parent eacaa411
...@@ -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;
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 { 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; 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);
String epsgCode = extractEpsgCode(cityModel); createTransformers(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(); public static void createTransformers(CityModel cityModel) {
Map<String, Object> readParameters = new HashMap<>(); String epsgCode = extractEpsgCode(cityModel);
readParameters.put("url", path.toUri().toURL()); sourceCRS = CRS_FACTORY.createFromName(epsgCode);
readParameters.put("charset", StandardCharsets.UTF_8); transform = new BasicCoordinateTransform(sourceCRS, targetCRS);
DataStore dataStore = DataStoreFinder.getDataStore(readParameters); backTransform = new BasicCoordinateTransform(targetCRS, sourceCRS);
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;
} }
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; 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) { 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(); treePoints.add(new TreePoint(point));
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));
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;
...@@ -42,5 +44,13 @@ public class OsmData { ...@@ -42,5 +44,13 @@ public class OsmData {
public List<TreeRow> getTreeRows() { public List<TreeRow> getTreeRows() {
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