Commit b951138d authored by Eric Duminil's avatar Eric Duminil
Browse files

Format

parent ed51d96f
......@@ -16,27 +16,24 @@ Data license: https://www.govdata.de/dl-de/by-2-0
Eric Duminil, 2025
"""
from pathlib import Path
from math import floor
import subprocess
import re
import urllib.request
import subprocess
import time
import urllib.request
import zipfile
from math import floor
from pathlib import Path
from pyproj import CRS
from pyproj import Transformer
from pyproj import CRS, Transformer
from shapely import wkt
from shapely.ops import transform
from shapely.geometry import Point
from shapely.ops import transform
# TODO: Write tests
# TODO: Use logging
from german_laender_wkt import german_laender
from get_coordinates_by_zipcode import get_coordinates_by_zipcode
from german_laender_wkt import german_laender
# TODO: Write tests
# TODO: Use logging
COORDINATES_REGEX = re.compile(r"(\-?\d+\.\d*) (\-?\d+\.\d*)")
......@@ -44,7 +41,7 @@ COORDINATES_REGEX = re.compile(r"(\-?\d+\.\d*) (\-?\d+\.\d*)")
###### User input ##########
# Values can be either a WKT POLYGON or MULTIPOLYGON, a Zipcode, or Zipcodes separated by a comma.
REGIONS = {
"BW": german_laender['Baden-Württemberg'],
"BW": "POLYGON((9.211240 48.769258, 9.209040 48.770220, 9.208547 48.770708, 9.207206 48.771295, 9.206390 48.771521, 9.204834 48.771528, 9.204405 48.771775, 9.204019 48.772249, 9.203708 48.772907, 9.203981 48.774104, 9.203949 48.774485, 9.204378 48.774994, 9.206169 48.774994, 9.207478 48.775843, 9.208637 48.775899, 9.213776 48.776981, 9.215085 48.775610, 9.216072 48.773736, 9.217350 48.770910, 9.217801 48.769326, 9.214365 48.767755, 9.211240 48.769258))"
# "Freiburg": "79098,79102",
# "AnotherRegion": "Another WKT Polygon...",
# "YetAnotherRegion": "Another ZIP code",
......@@ -56,13 +53,11 @@ EXTRACT_REGIONS = True
CITYGML_SERVER = "https://opengeodata.lgl-bw.de/data/lod2"
RASTER = 2 # [km]
KILOMETER = 1000 # [m]
BUNDESLAND = 'bw'
KILOMETER = 1000 # [m]
BUNDESLAND = "bw"
# UTM32N, used in BW. https://epsg.io/32632
TO_LOCAL_CRS = Transformer.from_crs(CRS.from_epsg(4326),
CRS.from_epsg(32632),
always_xy=True)
TO_LOCAL_CRS = Transformer.from_crs(CRS.from_epsg(4326), CRS.from_epsg(32632), always_xy=True)
UTM = 32
......@@ -72,14 +67,15 @@ GML_GLOB = "LoD2_*/LoD2_*.gml"
if EXTRACT_REGIONS:
try:
SIMSTADT_FOLDER = next(x for x in Path.home().glob('Desktop/SimStadt*_0.*/') if x.is_dir())
SIMSTADT_FOLDER = next(x for x in Path.home().glob("Desktop/SimStadt*_0.*/") if x.is_dir())
print(f"RegionChooser has been found in {SIMSTADT_FOLDER}")
except StopIteration:
exit("No SimStadt installation found!"
"\nPlease copy a SimStadt installation to the desktop,"
"\nset EXTRACT_REGIONS to False,"
"\nor set SIMSTADT_FOLDER manually: SIMSTADT_FOLDER = Path('/path/to/SimStadt')"
)
exit(
"No SimStadt installation found!"
"\nPlease copy a SimStadt installation to the desktop,"
"\nset EXTRACT_REGIONS to False,"
"\nor set SIMSTADT_FOLDER manually: SIMSTADT_FOLDER = Path('/path/to/SimStadt')"
)
def coordinates_to_grid(longitude: float, latitude: float) -> tuple[int, int]:
......@@ -94,10 +90,10 @@ def coordinates_to_grid(longitude: float, latitude: float) -> tuple[int, int]:
def wkt_polygon_to_grid_coords(location_name: str, wkt: str) -> tuple[int, int, int, int]:
"""Returns (x, y) of lower-left and bottom-right tiles, containing a given region."""
if 'POLYGON' not in wkt:
if "POLYGON" not in wkt:
raise ValueError(f"wkt for {location_name} should be a WKT POLYGON or MULTIPOLYGON")
coordinates = re.findall(r'\-?\d+\.\d+', wkt)
coordinates = re.findall(r"\-?\d+\.\d+", wkt)
lons = [float(lon) for lon in coordinates[::2]]
lats = [float(lat) for lat in coordinates[1::2]]
......@@ -105,8 +101,7 @@ def wkt_polygon_to_grid_coords(location_name: str, wkt: str) -> tuple[int, int,
min_lon, max_lon = min(lons), max(lons)
min_lat, max_lat = min(lats), max(lats)
print("%s (%.3f°N %.3f°E -> %.3f°N %.3f°E)" %
(location_name, max_lat, min_lon, min_lat, max_lon))
print("%s (%.3f°N %.3f°E -> %.3f°N %.3f°E)" % (location_name, max_lat, min_lon, min_lat, max_lon))
x1, y1 = coordinates_to_grid(min_lon, min_lat)
x2, y2 = coordinates_to_grid(max_lon, max_lat)
......@@ -131,7 +126,7 @@ def download_whole_region(output_dir: Path, wkt_region: str, x1: int, x2: int, y
if local_zip.exists():
print(f" {local_zip.name} already in {output_dir.name}/")
else:
print(f" Download {citygml_zip} to {output_dir.name}/ ", end='')
print(f" Download {citygml_zip} to {output_dir.name}/ ", end="")
try:
urllib.request.urlretrieve(citygml_url, local_zip)
except urllib.error.HTTPError as e:
......@@ -141,7 +136,7 @@ def download_whole_region(output_dir: Path, wkt_region: str, x1: int, x2: int, y
time.sleep(WAIT_BETWEEN_DOWNLOADS)
print("✅")
print(f" Extract {citygml_zip} to {output_dir.name}/ ", end='')
print(f" Extract {citygml_zip} to {output_dir.name}/ ", end="")
print("✅")
print("")
with zipfile.ZipFile(local_zip, "r") as zip_ref:
......@@ -150,44 +145,48 @@ def download_whole_region(output_dir: Path, wkt_region: str, x1: int, x2: int, y
def extract_region(output_dir: Path, location_name: str, wkt: str) -> None:
"""Uses RegionChooser to extract a given region from all the CityGML files found in subfolder."""
output_file = output_dir / (location_name + '.gml')
output_file = output_dir / (location_name + ".gml")
if output_file.exists():
print(f" {output_file} already exists. Not extracting.")
return
region_chooser_libs = Path(SIMSTADT_FOLDER).expanduser() / 'lib/*'
region_chooser_libs = Path(SIMSTADT_FOLDER).expanduser() / "lib/*"
gml_inputs = list(output_dir.glob(GML_GLOB))
if len(gml_inputs) == 0:
print("Error: No CityGML found. At least part of the region should be in Baden-Württemberg!")
return
params_path = output_dir / 'params.txt'
wkt_path = output_dir / 'region.wkt'
params_path = output_dir / "params.txt"
wkt_path = output_dir / "region.wkt"
local_wkt = convert_wkt_to_local(wkt)
print(f" Extracting {output_file}.")
with open(wkt_path, 'w') as f:
with open(wkt_path, "w") as f:
f.write(local_wkt)
with open(params_path, 'w') as f:
with open(params_path, "w") as f:
f.write("--input\n")
f.write(','.join(f"{gml.as_posix()}" for gml in gml_inputs))
f.write(",".join(f"{gml.as_posix()}" for gml in gml_inputs))
f.write("\n")
f.write("--output\n")
f.write(f'"{output_file.as_posix()}"\n')
f.write('--local\n')
f.write("--local\n")
f.write("--wkt\n")
f.write(f'"{wkt_path.as_posix()}"\n')
result = subprocess.run(['java', '-classpath', f'{region_chooser_libs}',
'eu.simstadt.regionchooser.RegionChooserCLI',
f'@{params_path}'
],
text=True,
capture_output=True,
check=False
)
if (result.stderr):
result = subprocess.run(
[
"java",
"-classpath",
f"{region_chooser_libs}",
"eu.simstadt.regionchooser.RegionChooserCLI",
f"@{params_path}",
],
text=True,
capture_output=True,
check=False,
)
if result.stderr:
print(result.stderr)
if result.returncode != 0:
raise ValueError(f"RegionChooser failed with code {result.returncode}")
......@@ -201,17 +200,18 @@ def get_wkt(wkt_or_zipcode: str) -> str:
"70567"
"70567,70569"
"""
if 'POLYGON' in wkt_or_zipcode:
if "POLYGON" in wkt_or_zipcode:
return wkt_or_zipcode
return get_coordinates_by_zipcode(wkt_or_zipcode.split(','))
return get_coordinates_by_zipcode(wkt_or_zipcode.split(","))
def main(regions: dict[str, str]) -> None:
"""Downloads ZIP files, extracts CityGML files, and selects desired region."""
for location_name, wkt_or_zipcode in regions.items():
if ' ' in location_name:
if " " in location_name:
raise ValueError("Location name should not contain spaces: 'Some City' -> 'SomeCity'")
output_dir = SCRIPT_DIR / (location_name + '.proj')
output_dir = SCRIPT_DIR / (location_name + ".proj")
output_dir.mkdir(parents=True, exist_ok=True)
wkt = get_wkt(wkt_or_zipcode)
x1, x2, y1, y2 = wkt_polygon_to_grid_coords(location_name, wkt)
......@@ -231,5 +231,5 @@ def convert_wkt_to_local(wkt):
return COORDINATES_REGEX.sub(convert_coordinates, wkt)
if __name__ == '__main__':
if __name__ == "__main__":
main(REGIONS)
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment