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

add alkis land use parsing

parent eacaa411
......@@ -25,6 +25,19 @@
</repositories>
<dependencies>
<!-- https://mvnrepository.com/artifact/jakarta.xml.bind/jakarta.xml.bind-api -->
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>4.0.0</version>
<scope>runtime</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.geotools/gt-shapefile -->
<dependency>
<groupId>org.geotools</groupId>
......
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;
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 {
private List<TreeRow> treeRows = new ArrayList<>();
private List<Waterway> waterways = new ArrayList<>();
private List<WaterArea> waterAreas = new ArrayList<>();
private List<RoadArea> roadAreas = new ArrayList<>();
private List<LandUseArea> landUseAreas = new ArrayList<>();
public void setBoundingBox(Polygon boundingBox) {
this.boundingBox = boundingBox;
......@@ -42,5 +44,13 @@ public class OsmData {
public List<TreeRow> getTreeRows() {
return treeRows;
}
public List<RoadArea> getRoadAreas() {
return roadAreas;
}
public List<LandUseArea> getLandUseAreas() {
return landUseAreas;
}
}
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 {
List<Coordinate> secondRing = ringCoordinates.get(1);
for (int i = 0; i < secondRing.size(); i++) {
Coordinate[] coordArray = new Coordinate[] { topPoint, secondRing.get(i), secondRing.get((i + 1) % secondRing.size()), topPoint };
Polygon polygon = GreenEnricher.geomFactory.createPolygon(coordArray);
Polygon polygon = GreenEnricher.GEOM_FACTORY.createPolygon(coordArray);
var convertedPoly = GreenEnricher.convertToCityGmlPoly(polygon);
ms.getSurfaceMember().add(new SurfaceProperty(convertedPoly));
}
......@@ -118,7 +118,7 @@ public class TreeGenerator {
Coordinate p3 = bottomRing.get(j);
Coordinate p4 = bottomRing.get(nextRingIndex);
Coordinate[] coordArray = new Coordinate[] { p1, p3, p4, p2, p1 };
Polygon polygon = GreenEnricher.geomFactory.createPolygon(coordArray);
Polygon polygon = GreenEnricher.GEOM_FACTORY.createPolygon(coordArray);
var convertedPoly = GreenEnricher.convertToCityGmlPoly(polygon);
ms.getSurfaceMember().add(new SurfaceProperty(convertedPoly));
}
......@@ -131,7 +131,7 @@ public class TreeGenerator {
Coordinate p1 = bottomRing.get(i);
Coordinate p2 = bottomRing.get(nextRingIndex);
Coordinate[] coordArray = new Coordinate[] { p2, p1, bottomPoint, p2 };
Polygon polygon = GreenEnricher.geomFactory.createPolygon(coordArray);
Polygon polygon = GreenEnricher.GEOM_FACTORY.createPolygon(coordArray);
var convertedPoly = GreenEnricher.convertToCityGmlPoly(polygon);
ms.getSurfaceMember().add(new SurfaceProperty(convertedPoly));
}
......@@ -140,7 +140,7 @@ public class TreeGenerator {
}
private static Polygon convertPolygon(List<Coordinate> trunkWestCoordinateList) {
return GreenEnricher.geomFactory
return GreenEnricher.GEOM_FACTORY
.createPolygon(trunkWestCoordinateList.toArray(new Coordinate[trunkWestCoordinateList.size()]));
}
......
package de.hft.stuttgart.citygml.green.osm;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.geotools.data.DataStore;
import org.geotools.data.DataStoreFinder;
import org.geotools.data.FeatureSource;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureIterator;
import org.locationtech.jts.geom.Point;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
public class TreeKatasterData {
public static final double TRUNK_PERCENTAGE = 0.2;
public static final double CROWN_PERCENTAGE = 1 - TRUNK_PERCENTAGE;
private List<Tree> trees;
public static TreeKatasterData parseTreeKatasterData(Path path) throws IOException {
TreeKatasterData result = new TreeKatasterData();
Map<String, Object> readParameters = new HashMap<>();
readParameters.put("url", path.toUri().toURL());
readParameters.put("charset", StandardCharsets.UTF_8);
DataStore dataStore = DataStoreFinder.getDataStore(readParameters);
String typeName = dataStore.getTypeNames()[0];
FeatureSource<SimpleFeatureType, SimpleFeature> source = dataStore.getFeatureSource(typeName);
FeatureCollection<SimpleFeatureType, SimpleFeature> collection = source.getFeatures();
try (FeatureIterator<SimpleFeature> features = collection.features()) {
while (features.hasNext()) {
SimpleFeature feature = features.next();
Tree tree = new Tree();
Point p = (Point) feature.getAttribute("the_geom");
tree.setPoint(p);
String type = feature.getAttribute("Bezeichnun").toString();
tree.setType(type);
Object treeHeightObject = feature.getAttribute("Baumhöhe");
if (treeHeightObject == null) {
continue;
}
int treeHeight = Integer.parseInt(treeHeightObject.toString());
double crownHeight = CROWN_PERCENTAGE * treeHeight;
double trunkHeight = TRUNK_PERCENTAGE * treeHeight;
tree.setCrownHeight(crownHeight);
tree.setTrunkHeight(trunkHeight);
Object crownWidth = feature.getAttribute("Kronenbrei");
if (crownWidth == null) {
continue;
}
tree.setCrownRadius(Float.parseFloat(crownWidth.toString()) / 2);
Object trunkCirc = feature.getAttribute("Stammumfan");
if (trunkCirc == null) {
continue;
}
tree.setTrunkRadius(Integer.parseInt(trunkCirc.toString()) / (2 * Math.PI) / 100);
result.getTrees().add(tree);
}
}
return result;
}
public List<Tree> getTrees() {
if (trees == null) {
trees = new ArrayList<>();
......
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);
}
}
Markdown is supported
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