Commits (3)
......@@ -10,7 +10,6 @@ from pathlib import Path
from collections import namedtuple
import folium
import kdtree
import matplotlib.pyplot as plt
import matplotlib.ticker as plticker
import numpy as np
......@@ -19,7 +18,8 @@ from pyproj import Transformer
from shapely import LineString, geometry, wkt
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: Document
......@@ -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
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
EXISTING_TREES = 'Trees_ideal_2_20240227/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))"
EXISTING_TREES = 'existing_trees/Trees_ideal_2_20240227.shp'
# 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))"
EPSG_ID = 25832
......@@ -100,17 +99,9 @@ def set_plot(bounds, to_local_coordinates):
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)
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:
width = float(way.tags.get("width", 0))
highway = way.tags.get("highway")
......@@ -146,12 +137,9 @@ def place_trees(existing_trees_coords, ways, region, to_local, tree_distance, mi
x = potential_tree.x
y = potential_tree.y
if local_region.contains(geometry.Point(x, y)):
_nearest_tree, distance_2 = existing_trees.search_nn((x, y))
if distance_2 > min_distance_2:
existing_trees.add((x, y))
tree_xs.append(x)
tree_ys.append(y)
return tree_xs, tree_ys
forest.add_tree_if_possible(min_distance_2, x, y)
return forest.xs_ys
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):
ways = get_osm_roads(bounds)
if import_tree_shp:
existing_trees = get_existing_trees(import_tree_shp)
existing_forest = get_existing_forest(import_tree_shp)
else:
existing_trees = []
existing_forest = Forest()
print(existing_forest)
to_local = Transformer.from_crs("EPSG:4326", f"EPSG:{epsg_id}", always_xy=True)
set_plot(bounds, to_local)
tree_xs, tree_ys = place_trees(existing_trees, ways, region,
to_local, tree_distance, min_distance**2)
tree_xs, tree_ys = place_trees(existing_forest, ways, region, to_local, tree_distance, min_distance**2)
print(existing_forest)
plot_trees(bounds, tree_xs, tree_ys, tree_distance)
export_map(bounds, tree_xs, tree_ys, epsg_id)
......
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}")
df = gpd.read_file(shp_input)
coords = [(p.x, p.y) for p in df.geometry]
return coords
trees = [Tree(p.x, p.y) for p in df.geometry]
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])