Commits (3)
...@@ -10,7 +10,6 @@ from pathlib import Path ...@@ -10,7 +10,6 @@ from pathlib import Path
from collections import namedtuple from collections import namedtuple
import folium import folium
import kdtree
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import matplotlib.ticker as plticker import matplotlib.ticker as plticker
import numpy as np import numpy as np
...@@ -19,7 +18,8 @@ from pyproj import Transformer ...@@ -19,7 +18,8 @@ from pyproj import Transformer
from shapely import LineString, geometry, wkt from shapely import LineString, geometry, wkt
from shapely.ops import transform from shapely.ops import transform
from import_existing_trees import get_existing_trees from tree import Forest
from import_existing_trees import get_existing_forest
# TODO: Use Args # TODO: Use Args
# TODO: Document # TODO: Document
...@@ -30,8 +30,7 @@ from import_existing_trees import get_existing_trees ...@@ -30,8 +30,7 @@ from import_existing_trees import get_existing_trees
# From RegionChooser, or https://transfer.hft-stuttgart.de/gitlab/circulargreensimcity/circulargreensimcity/-/wikis/Fallstudien/Gromb%C3%BChl # From RegionChooser, or https://transfer.hft-stuttgart.de/gitlab/circulargreensimcity/circulargreensimcity/-/wikis/Fallstudien/Gromb%C3%BChl
WKT = "POLYGON((9.947021 49.803063, 9.947011 49.800917, 9.955025 49.800810, 9.955110 49.803019, 9.947021 49.803063))" WKT = "POLYGON((9.947021 49.803063, 9.947011 49.800917, 9.955025 49.800810, 9.955110 49.803019, 9.947021 49.803063))"
# Replace with None if no existing tree should be imported # Replace with None if no existing tree should be imported
EXISTING_TREES = 'Trees_ideal_2_20240227/Trees_ideal_2_20240227.shp' EXISTING_TREES = 'existing_trees/Trees_ideal_2_20240227.shp'
# WKT = "POLYGON((9.170419 48.782366, 9.170032 48.780825, 9.169904 48.780401, 9.170440 48.778733, 9.176877 48.780118, 9.177006 48.781193, 9.177049 48.782564, 9.176298 48.782593, 9.175440 48.782409, 9.174646 48.783399, 9.170419 48.782366))"
# Fellbach # Fellbach
# WKT = "POLYGON((9.271353 48.811327, 9.271911 48.809010, 9.272147 48.807187, 9.275838 48.807173, 9.275602 48.806749, 9.276138 48.806325, 9.277683 48.806424, 9.277319 48.812514, 9.275581 48.811991, 9.271353 48.811327))" # WKT = "POLYGON((9.271353 48.811327, 9.271911 48.809010, 9.272147 48.807187, 9.275838 48.807173, 9.275602 48.806749, 9.276138 48.806325, 9.277683 48.806424, 9.277319 48.812514, 9.275581 48.811991, 9.271353 48.811327))"
EPSG_ID = 25832 EPSG_ID = 25832
...@@ -100,17 +99,9 @@ def set_plot(bounds, to_local_coordinates): ...@@ -100,17 +99,9 @@ def set_plot(bounds, to_local_coordinates):
return ax return ax
def place_trees(existing_trees_coords, ways, region, to_local, tree_distance, min_distance_2): def place_trees(forest, ways, region, to_local, tree_distance, min_distance_2):
local_region = transform(to_local.transform, region) local_region = transform(to_local.transform, region)
existing_trees = kdtree.create(existing_trees_coords or [(0, 0)], dimensions=2)
tree_xs = []
tree_ys = []
for x, y in existing_trees_coords:
tree_xs.append(x)
tree_ys.append(y)
for way in ways: for way in ways:
width = float(way.tags.get("width", 0)) width = float(way.tags.get("width", 0))
highway = way.tags.get("highway") highway = way.tags.get("highway")
...@@ -146,12 +137,9 @@ def place_trees(existing_trees_coords, ways, region, to_local, tree_distance, mi ...@@ -146,12 +137,9 @@ def place_trees(existing_trees_coords, ways, region, to_local, tree_distance, mi
x = potential_tree.x x = potential_tree.x
y = potential_tree.y y = potential_tree.y
if local_region.contains(geometry.Point(x, y)): if local_region.contains(geometry.Point(x, y)):
_nearest_tree, distance_2 = existing_trees.search_nn((x, y)) forest.add_tree_if_possible(min_distance_2, x, y)
if distance_2 > min_distance_2:
existing_trees.add((x, y)) return forest.xs_ys
tree_xs.append(x)
tree_ys.append(y)
return tree_xs, tree_ys
def plot_trees(bounds, tree_xs, tree_ys, tree_distance): def plot_trees(bounds, tree_xs, tree_ys, tree_distance):
...@@ -215,15 +203,17 @@ def main(wkt_polygon, epsg_id, tree_distance, min_distance, import_tree_shp): ...@@ -215,15 +203,17 @@ def main(wkt_polygon, epsg_id, tree_distance, min_distance, import_tree_shp):
ways = get_osm_roads(bounds) ways = get_osm_roads(bounds)
if import_tree_shp: if import_tree_shp:
existing_trees = get_existing_trees(import_tree_shp) existing_forest = get_existing_forest(import_tree_shp)
else: else:
existing_trees = [] existing_forest = Forest()
print(existing_forest)
to_local = Transformer.from_crs("EPSG:4326", f"EPSG:{epsg_id}", always_xy=True) to_local = Transformer.from_crs("EPSG:4326", f"EPSG:{epsg_id}", always_xy=True)
set_plot(bounds, to_local) set_plot(bounds, to_local)
tree_xs, tree_ys = place_trees(existing_trees, ways, region, tree_xs, tree_ys = place_trees(existing_forest, ways, region, to_local, tree_distance, min_distance**2)
to_local, tree_distance, min_distance**2) print(existing_forest)
plot_trees(bounds, tree_xs, tree_ys, tree_distance) plot_trees(bounds, tree_xs, tree_ys, tree_distance)
export_map(bounds, tree_xs, tree_ys, epsg_id) export_map(bounds, tree_xs, tree_ys, epsg_id)
......
import geopandas as gpd import geopandas as gpd
from tree import Tree, Forest
def get_existing_trees(shp_input): def get_existing_forest(shp_input):
print(f"Importing {shp_input}") print(f"Importing {shp_input}")
df = gpd.read_file(shp_input) df = gpd.read_file(shp_input)
coords = [(p.x, p.y) for p in df.geometry] trees = [Tree(p.x, p.y) for p in df.geometry]
return coords return Forest(trees)
if __name__ == "__main__":
print(repr(get_existing_forest('existing_trees/Trees_ideal_2_20240227.shp')))
from dataclasses import dataclass
import kdtree
@dataclass
class Tree:
x: float
y: float
z: float = 0
height: float = None
radius: float = None
description: str = None
type: str = None
def __len__(self):
return 2 # x & y
def __getitem__(self, i):
return [self.x, self.y][i]
class Forest:
def __init__(self, existing_trees=[]):
if existing_trees:
self.kd_tree = kdtree.create(existing_trees, dimensions=2)
else:
self.kd_tree = kdtree.create([(0, 0)], dimensions=2)
self.trees = existing_trees
def add_tree_if_possible(self, min_distance_2, x, y, *params):
_nearest_tree, distance_2 = self.kd_tree.search_nn((x, y))
if distance_2 > min_distance_2:
self.kd_tree.add((x, y))
self.trees.append(Tree(x, y, *params))
@property
def xs_ys(self):
xs, ys = [], []
for tree in self.trees:
xs.append(tree.x)
ys.append(tree.y)
return xs, ys
def __str__(self):
return f"Forest with {len(self.trees)} trees."
def __repr__(self):
return "\n".join([str(self)] + [str(tree) for tree in self.trees])