forked from s_ranjbar/city_retrofit
162 lines
3.9 KiB
Python
162 lines
3.9 KiB
Python
"""
|
|
City module
|
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
|
Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
|
"""
|
|
import sys
|
|
from typing import List, Union
|
|
|
|
import pyproj
|
|
import reverse_geocoder as rg
|
|
from pyproj import Transformer
|
|
|
|
from city_model_structure.building import Building
|
|
from city_model_structure.city_object import CityObject
|
|
|
|
|
|
class City:
|
|
"""
|
|
City class
|
|
"""
|
|
|
|
def __init__(self, lower_corner, upper_corner, srs_name, buildings=None):
|
|
self._buildings = None
|
|
self._name = None
|
|
self._lower_corner = lower_corner
|
|
self._upper_corner = upper_corner
|
|
self._buildings = buildings
|
|
self._srs_name = srs_name
|
|
# todo: right now extracted at city level, in the future should be extracted also at building level if exist
|
|
self._location = None
|
|
|
|
def _get_location(self):
|
|
if self._location is None:
|
|
gps = pyproj.CRS('EPSG:4326') # LatLon with WGS84 datum used by GPS units and Google Earth
|
|
try:
|
|
input_reference = pyproj.CRS(self.srs_name) # Projected coordinate system from input data
|
|
except pyproj.exceptions.CRSError:
|
|
print('Invalid projection reference system, please check the input data. (e.g. in CityGML files: srs_name)')
|
|
sys.exit()
|
|
transformer = Transformer.from_crs(input_reference, gps)
|
|
coordinates = transformer.transform(self.lower_corner[0], self.lower_corner[1])
|
|
self._location = rg.search(coordinates)
|
|
return self._location
|
|
|
|
@property
|
|
def country_code(self):
|
|
"""
|
|
City country code
|
|
:return: str
|
|
"""
|
|
return self._get_location()[0]['cc']
|
|
|
|
@property
|
|
def name(self):
|
|
"""
|
|
City name
|
|
:return: str
|
|
"""
|
|
if self._name is None:
|
|
self._name = self._get_location()[0]['name']
|
|
return self._name
|
|
|
|
@property
|
|
def city_objects(self) -> Union[List[CityObject], None]:
|
|
"""
|
|
City objects belonging to the city
|
|
:return: None or [CityObject]
|
|
"""
|
|
return self.buildings
|
|
|
|
@property
|
|
def buildings(self) -> Union[List[Building], None]:
|
|
"""
|
|
Buildings belonging to the city
|
|
:return: None or [Building]
|
|
"""
|
|
return self._buildings
|
|
|
|
@property
|
|
def trees(self) -> NotImplementedError:
|
|
"""
|
|
Trees belonging to the city
|
|
:return: NotImplementedError
|
|
"""
|
|
raise NotImplementedError
|
|
|
|
@property
|
|
def bixi_features(self) -> NotImplementedError:
|
|
"""
|
|
Bixi features belonging to the city
|
|
:return: NotImplementedError
|
|
"""
|
|
raise NotImplementedError
|
|
|
|
@property
|
|
def composting_plants(self) -> NotImplementedError:
|
|
"""
|
|
Composting plants belonging to the city
|
|
:return: NotImplementedError
|
|
"""
|
|
raise NotImplementedError
|
|
|
|
@property
|
|
def lower_corner(self):
|
|
"""
|
|
City lower corner
|
|
:return: [x,y,z]
|
|
"""
|
|
return self._lower_corner
|
|
|
|
@property
|
|
def upper_corner(self):
|
|
"""
|
|
City upper corner
|
|
:return: [x,y,z]
|
|
"""
|
|
return self._upper_corner
|
|
|
|
def city_object(self, name) -> Union[CityObject, None]:
|
|
"""
|
|
Retrieve the city CityObject with the given name
|
|
:param name:str
|
|
:return: None or CityObject
|
|
"""
|
|
for city_object in self.buildings:
|
|
if city_object.name == name:
|
|
return city_object
|
|
return None
|
|
|
|
def add_city_object(self, new_city_object):
|
|
"""
|
|
Add a CityObject to the city
|
|
:param new_city_object:CityObject
|
|
:return: None
|
|
"""
|
|
if new_city_object.type != 'building':
|
|
raise NotImplementedError(new_city_object.type)
|
|
if self._buildings is None:
|
|
self._buildings = []
|
|
for building in self.buildings:
|
|
for surface in building.surfaces:
|
|
for surface2 in new_city_object.surfaces:
|
|
surface.shared(surface2)
|
|
self._buildings.append(new_city_object)
|
|
|
|
@property
|
|
def srs_name(self):
|
|
"""
|
|
srs name
|
|
:return: str
|
|
"""
|
|
return self._srs_name
|
|
|
|
@name.setter
|
|
def name(self, value):
|
|
"""
|
|
Set the city name
|
|
:param value:str
|
|
:return: None
|
|
"""
|
|
self._name = value
|