forked from s_ranjbar/city_retrofit
113 lines
3.7 KiB
Python
113 lines
3.7 KiB
Python
"""
|
|
export a city into Geojson format
|
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
|
Copyright © 2022 Concordia CERC group
|
|
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
|
"""
|
|
import json
|
|
from pathlib import Path
|
|
|
|
import numpy as np
|
|
import pyproj
|
|
from pyproj import Transformer
|
|
|
|
from hub.helpers.geometry_helper import GeometryHelper
|
|
|
|
|
|
class Geojson:
|
|
"""
|
|
Export to geojson format
|
|
"""
|
|
def __init__(self, city, path, target_buildings):
|
|
self._city = city
|
|
self._file_path = Path(path / f'{self._city.name}.geojson').resolve()
|
|
try:
|
|
srs_name = self._city.srs_name
|
|
if self._city.srs_name in GeometryHelper.srs_transformations:
|
|
srs_name = GeometryHelper.srs_transformations[self._city.srs_name]
|
|
input_reference = pyproj.CRS(srs_name) # Projected coordinate system from input data
|
|
except pyproj.exceptions.CRSError as err:
|
|
raise pyproj.exceptions.CRSError from err
|
|
self._to_gps = Transformer.from_crs(input_reference, pyproj.CRS('EPSG:4326'))
|
|
if target_buildings is None:
|
|
target_buildings = [b.name for b in self._city.buildings]
|
|
self._geojson_skeleton = {
|
|
'type': 'FeatureCollection',
|
|
'features': []
|
|
}
|
|
self._feature_skeleton = {
|
|
'type': 'Feature',
|
|
'geometry': {
|
|
'type': 'Polygon',
|
|
'coordinates': []
|
|
},
|
|
'properties': {}
|
|
}
|
|
self._export()
|
|
|
|
def _export(self):
|
|
for building in self._city.buildings:
|
|
if len(building.grounds) == 1:
|
|
ground = building.grounds[0]
|
|
feature = self._polygon(ground)
|
|
else:
|
|
feature = self._multipolygon(building.grounds)
|
|
feature['id'] = building.name
|
|
feature['properties']['height'] = f'{building.max_height - building.lower_corner[2]}'
|
|
feature['properties']['function'] = f'{building.function}'
|
|
feature['properties']['year_of_construction'] = f'{building.year_of_construction}'
|
|
feature['properties']['aliases'] = building.aliases
|
|
feature['properties']['elevation'] = f'{building.lower_corner[2]}'
|
|
self._geojson_skeleton['features'].append(feature)
|
|
with open(self._file_path, 'w', encoding='utf-8') as f:
|
|
json.dump(self._geojson_skeleton, f, indent=2)
|
|
|
|
def _polygon(self, ground):
|
|
feature = {
|
|
'type': 'Feature',
|
|
'geometry': {
|
|
'type': 'Polygon',
|
|
'coordinates': []
|
|
},
|
|
'properties': {}
|
|
}
|
|
ground_coordinates = []
|
|
for coordinate in ground.solid_polygon.coordinates:
|
|
gps_coordinate = self._to_gps.transform(coordinate[0], coordinate[1])
|
|
ground_coordinates.insert(0, [gps_coordinate[1], gps_coordinate[0]])
|
|
|
|
first_gps_coordinate = self._to_gps.transform(
|
|
ground.solid_polygon.coordinates[0][0],
|
|
ground.solid_polygon.coordinates[0][1]
|
|
)
|
|
ground_coordinates.insert(0, [first_gps_coordinate[1], first_gps_coordinate[0]])
|
|
feature['geometry']['coordinates'].append(ground_coordinates)
|
|
return feature
|
|
|
|
def _multipolygon(self, grounds):
|
|
feature = {
|
|
'type': 'Feature',
|
|
'geometry': {
|
|
'type': 'MultiPolygon',
|
|
'coordinates': []
|
|
},
|
|
'properties': {}
|
|
}
|
|
polygons = []
|
|
for ground in grounds:
|
|
ground_coordinates = []
|
|
for coordinate in ground.solid_polygon.coordinates:
|
|
gps_coordinate = self._to_gps.transform(coordinate[0], coordinate[1])
|
|
ground_coordinates.insert(0, [gps_coordinate[1], gps_coordinate[0]])
|
|
|
|
first_gps_coordinate = self._to_gps.transform(
|
|
ground.solid_polygon.coordinates[0][0],
|
|
ground.solid_polygon.coordinates[0][1]
|
|
)
|
|
ground_coordinates.insert(0, [first_gps_coordinate[1], first_gps_coordinate[0]])
|
|
polygons.append(ground_coordinates)
|
|
feature['geometry']['coordinates'].append(polygons)
|
|
return feature
|
|
|
|
|