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