2020-06-16 15:34:35 -04:00
|
|
|
"""
|
|
|
|
CityObject module
|
|
|
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
2022-04-08 09:35:33 -04:00
|
|
|
Copyright © 2022 Concordia CERC group
|
|
|
|
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
2020-06-16 15:34:35 -04:00
|
|
|
"""
|
2021-08-26 09:19:38 -04:00
|
|
|
|
2023-02-23 06:56:13 -05:00
|
|
|
from __future__ import annotations
|
2020-06-16 16:06:33 -04:00
|
|
|
from typing import List, Union
|
2021-08-26 09:19:38 -04:00
|
|
|
|
2023-05-12 09:27:29 -04:00
|
|
|
from hub.city_model_structure.level_of_detail import LevelOfDetail
|
2023-01-24 10:51:50 -05:00
|
|
|
from hub.city_model_structure.iot.sensor import Sensor
|
|
|
|
from hub.city_model_structure.building_demand.surface import Surface
|
|
|
|
from hub.city_model_structure.attributes.polyhedron import Polyhedron
|
2023-02-23 06:56:13 -05:00
|
|
|
|
2023-01-24 10:51:50 -05:00
|
|
|
from hub.helpers.configuration_helper import ConfigurationHelper
|
2021-06-01 18:31:50 -04:00
|
|
|
|
2020-05-18 13:25:08 -04:00
|
|
|
|
|
|
|
class CityObject:
|
2020-06-16 15:34:35 -04:00
|
|
|
"""
|
|
|
|
class CityObject
|
|
|
|
"""
|
2022-11-28 13:13:55 -05:00
|
|
|
def __init__(self, name, surfaces):
|
2020-06-16 16:19:14 -04:00
|
|
|
self._name = name
|
2023-05-12 09:27:29 -04:00
|
|
|
self._level_of_detail = LevelOfDetail()
|
2020-06-16 16:06:33 -04:00
|
|
|
self._surfaces = surfaces
|
2021-04-01 10:36:07 -04:00
|
|
|
self._type = None
|
|
|
|
self._city_object_lower_corner = None
|
2023-02-23 07:25:04 -05:00
|
|
|
self._city_object_upper_corner = None
|
2021-03-08 18:27:14 -05:00
|
|
|
self._detailed_polyhedron = None
|
|
|
|
self._simplified_polyhedron = None
|
2021-04-01 10:36:07 -04:00
|
|
|
self._min_x = ConfigurationHelper().max_coordinate
|
|
|
|
self._min_y = ConfigurationHelper().max_coordinate
|
|
|
|
self._min_z = ConfigurationHelper().max_coordinate
|
2023-02-23 07:25:04 -05:00
|
|
|
self._max_x = ConfigurationHelper().min_coordinate
|
|
|
|
self._max_y = ConfigurationHelper().min_coordinate
|
|
|
|
self._max_z = ConfigurationHelper().min_coordinate
|
2021-04-01 10:36:07 -04:00
|
|
|
self._centroid = None
|
2023-03-15 14:21:38 -04:00
|
|
|
self._volume = None
|
2023-05-30 17:13:49 -04:00
|
|
|
self._external_temperature = {}
|
|
|
|
self._ground_temperature = {}
|
|
|
|
self._global_horizontal = {}
|
|
|
|
self._diffuse = {}
|
|
|
|
self._beam = {}
|
2021-06-02 09:30:01 -04:00
|
|
|
self._sensors = []
|
2023-02-23 06:56:13 -05:00
|
|
|
self._neighbours = None
|
2020-06-16 15:34:35 -04:00
|
|
|
|
2023-05-12 09:27:29 -04:00
|
|
|
@property
|
|
|
|
def level_of_detail(self) -> LevelOfDetail:
|
|
|
|
"""
|
|
|
|
Get level of detail of different aspects of the city: geometry, construction and usage
|
|
|
|
:return: LevelOfDetail
|
|
|
|
"""
|
|
|
|
return self._level_of_detail
|
|
|
|
|
2022-03-08 19:19:52 -05:00
|
|
|
@property
|
|
|
|
def name(self):
|
|
|
|
"""
|
2022-04-08 09:35:33 -04:00
|
|
|
Get city object name
|
2022-03-08 19:19:52 -05:00
|
|
|
:return: str
|
|
|
|
"""
|
|
|
|
return self._name
|
|
|
|
|
2021-04-01 10:36:07 -04:00
|
|
|
@property
|
2021-09-16 13:45:27 -04:00
|
|
|
def type(self) -> str:
|
2021-04-01 10:36:07 -04:00
|
|
|
"""
|
2021-08-30 14:39:24 -04:00
|
|
|
Get city object type
|
2021-04-01 10:36:07 -04:00
|
|
|
:return: str
|
|
|
|
"""
|
|
|
|
return self._type
|
|
|
|
|
2020-06-16 16:06:33 -04:00
|
|
|
@property
|
2021-09-16 13:45:27 -04:00
|
|
|
def volume(self) -> float:
|
2020-06-16 16:06:33 -04:00
|
|
|
"""
|
2021-08-30 14:39:24 -04:00
|
|
|
Get city object volume in cubic meters
|
2020-06-16 16:06:33 -04:00
|
|
|
:return: float
|
|
|
|
"""
|
2023-03-15 14:21:38 -04:00
|
|
|
if self._volume is None:
|
|
|
|
self._volume = self.simplified_polyhedron.volume
|
|
|
|
return self._volume
|
|
|
|
|
|
|
|
@volume.setter
|
|
|
|
def volume(self, value):
|
2023-08-07 16:56:01 -04:00
|
|
|
"""
|
|
|
|
Set city object volume in cubic meters
|
|
|
|
:param value: float
|
|
|
|
"""
|
2023-03-15 14:21:38 -04:00
|
|
|
self._volume = value
|
2021-03-01 16:42:03 -05:00
|
|
|
|
|
|
|
@property
|
2021-06-09 14:23:45 -04:00
|
|
|
def detailed_polyhedron(self) -> Polyhedron:
|
2021-03-01 16:42:03 -05:00
|
|
|
"""
|
2021-08-30 14:39:24 -04:00
|
|
|
Get city object polyhedron including details such as holes
|
2021-03-01 16:42:03 -05:00
|
|
|
:return: Polyhedron
|
|
|
|
"""
|
2021-03-08 18:27:14 -05:00
|
|
|
if self._detailed_polyhedron is None:
|
|
|
|
polygons = []
|
|
|
|
for surface in self.surfaces:
|
|
|
|
polygons.append(surface.solid_polygon)
|
2021-04-01 15:51:09 -04:00
|
|
|
if surface.holes_polygons is not None:
|
|
|
|
for hole_polygon in surface.holes_polygons:
|
2021-03-08 18:27:14 -05:00
|
|
|
polygons.append(hole_polygon)
|
|
|
|
self._detailed_polyhedron = Polyhedron(polygons)
|
|
|
|
return self._detailed_polyhedron
|
|
|
|
|
|
|
|
@property
|
2021-06-09 14:23:45 -04:00
|
|
|
def simplified_polyhedron(self) -> Polyhedron:
|
2021-03-08 18:27:14 -05:00
|
|
|
"""
|
2021-08-30 14:39:24 -04:00
|
|
|
Get city object polyhedron, just the simple lod2 representation
|
2021-03-08 18:27:14 -05:00
|
|
|
:return: Polyhedron
|
|
|
|
"""
|
|
|
|
if self._simplified_polyhedron is None:
|
|
|
|
polygons = []
|
|
|
|
for surface in self.surfaces:
|
|
|
|
polygons.append(surface.perimeter_polygon)
|
|
|
|
self._simplified_polyhedron = Polyhedron(polygons)
|
|
|
|
return self._simplified_polyhedron
|
2020-06-16 16:06:33 -04:00
|
|
|
|
|
|
|
@property
|
|
|
|
def surfaces(self) -> List[Surface]:
|
|
|
|
"""
|
2021-08-30 14:39:24 -04:00
|
|
|
Get city object surfaces
|
2020-06-16 16:06:33 -04:00
|
|
|
:return: [Surface]
|
|
|
|
"""
|
|
|
|
return self._surfaces
|
|
|
|
|
2023-04-18 12:21:00 -04:00
|
|
|
@surfaces.setter
|
|
|
|
def surfaces(self, value):
|
|
|
|
"""
|
|
|
|
Set city object surfaces
|
|
|
|
:return: [Surface]
|
|
|
|
"""
|
|
|
|
self._surfaces = value
|
|
|
|
|
2020-06-16 16:06:33 -04:00
|
|
|
def surface(self, name) -> Union[Surface, None]:
|
|
|
|
"""
|
|
|
|
Get the city object surface with a given name
|
|
|
|
:param name: str
|
|
|
|
:return: None or Surface
|
|
|
|
"""
|
|
|
|
for s in self.surfaces:
|
|
|
|
if s.name == name:
|
|
|
|
return s
|
|
|
|
return None
|
|
|
|
|
2021-04-15 10:04:44 -04:00
|
|
|
def surface_by_id(self, identification_number) -> Union[Surface, None]:
|
|
|
|
"""
|
|
|
|
Get the city object surface with a given name
|
|
|
|
:param identification_number: str
|
|
|
|
:return: None or Surface
|
|
|
|
"""
|
|
|
|
for s in self.surfaces:
|
|
|
|
if str(s.id) == str(identification_number):
|
|
|
|
return s
|
|
|
|
return None
|
|
|
|
|
2020-06-16 16:06:33 -04:00
|
|
|
@property
|
2021-09-01 09:39:27 -04:00
|
|
|
def centroid(self) -> List[float]:
|
2020-06-16 16:06:33 -04:00
|
|
|
"""
|
2021-08-30 14:39:24 -04:00
|
|
|
Get city object centroid
|
2020-06-16 16:06:33 -04:00
|
|
|
:return: [x,y,z]
|
|
|
|
"""
|
2021-04-01 10:36:07 -04:00
|
|
|
if self._centroid is None:
|
|
|
|
self._centroid = self.simplified_polyhedron.centroid
|
|
|
|
return self._centroid
|
2020-11-04 08:54:10 -05:00
|
|
|
|
2020-06-16 16:19:14 -04:00
|
|
|
@property
|
2021-09-16 13:45:27 -04:00
|
|
|
def max_height(self) -> float:
|
2020-06-16 16:19:14 -04:00
|
|
|
"""
|
2021-08-30 14:39:24 -04:00
|
|
|
Get city object maximal height in meters
|
2020-06-16 16:19:14 -04:00
|
|
|
:return: float
|
|
|
|
"""
|
2021-03-08 18:27:14 -05:00
|
|
|
return self.simplified_polyhedron.max_z
|
2021-04-01 10:36:07 -04:00
|
|
|
|
|
|
|
@property
|
2021-09-16 13:45:27 -04:00
|
|
|
def external_temperature(self) -> {float}:
|
2021-04-01 10:36:07 -04:00
|
|
|
"""
|
2021-08-30 14:39:24 -04:00
|
|
|
Get external temperature surrounding the city object in Celsius
|
2023-08-07 12:32:33 -04:00
|
|
|
:return: dict{dict{[float]}}
|
2021-04-01 10:36:07 -04:00
|
|
|
"""
|
|
|
|
return self._external_temperature
|
|
|
|
|
|
|
|
@external_temperature.setter
|
|
|
|
def external_temperature(self, value):
|
|
|
|
"""
|
2021-08-30 14:39:24 -04:00
|
|
|
Set external temperature surrounding the city object in Celsius
|
2023-08-07 12:32:33 -04:00
|
|
|
:param value: dict{dict{[float]}}
|
2021-04-01 10:36:07 -04:00
|
|
|
"""
|
|
|
|
self._external_temperature = value
|
|
|
|
|
2023-03-20 11:07:43 -04:00
|
|
|
@property
|
|
|
|
def ground_temperature(self) -> dict:
|
|
|
|
"""
|
|
|
|
Get ground temperature under the city object in Celsius at different depths in meters for different time steps
|
|
|
|
example of use: {month: {0.5: [10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10]}}
|
|
|
|
:return: dict{dict{[float]}}
|
|
|
|
"""
|
|
|
|
return self._ground_temperature
|
|
|
|
|
|
|
|
@ground_temperature.setter
|
|
|
|
def ground_temperature(self, value):
|
|
|
|
"""
|
|
|
|
Set ground temperature under the city object in Celsius at different depths
|
|
|
|
:param value: dict{dict{[float]}}
|
|
|
|
"""
|
|
|
|
self._ground_temperature = value
|
|
|
|
|
2021-04-01 10:36:07 -04:00
|
|
|
@property
|
|
|
|
def global_horizontal(self) -> dict:
|
|
|
|
"""
|
2023-08-08 10:19:35 -04:00
|
|
|
Get global horizontal radiation surrounding the city object in J/m2
|
2023-08-07 12:32:33 -04:00
|
|
|
:return: dict{dict{[float]}}
|
2021-04-01 10:36:07 -04:00
|
|
|
"""
|
|
|
|
return self._global_horizontal
|
|
|
|
|
|
|
|
@global_horizontal.setter
|
|
|
|
def global_horizontal(self, value):
|
|
|
|
"""
|
2023-08-08 10:19:35 -04:00
|
|
|
Set global horizontal radiation surrounding the city object in J/m2
|
2023-08-07 12:32:33 -04:00
|
|
|
:param value: dict{dict{[float]}}
|
2021-04-01 10:36:07 -04:00
|
|
|
"""
|
|
|
|
self._global_horizontal = value
|
|
|
|
|
|
|
|
@property
|
|
|
|
def diffuse(self) -> dict:
|
|
|
|
"""
|
2023-08-08 10:19:35 -04:00
|
|
|
Get diffuse radiation surrounding the city object in J/m2
|
2023-08-07 12:32:33 -04:00
|
|
|
:return: dict{dict{[float]}}
|
2021-04-01 10:36:07 -04:00
|
|
|
"""
|
|
|
|
return self._diffuse
|
|
|
|
|
|
|
|
@diffuse.setter
|
|
|
|
def diffuse(self, value):
|
|
|
|
"""
|
2023-08-08 10:19:35 -04:00
|
|
|
Set diffuse radiation surrounding the city object in J/m2
|
2023-08-07 12:32:33 -04:00
|
|
|
:param value: dict{dict{[float]}}
|
2021-04-01 10:36:07 -04:00
|
|
|
"""
|
|
|
|
self._diffuse = value
|
|
|
|
|
|
|
|
@property
|
|
|
|
def beam(self) -> dict:
|
|
|
|
"""
|
2023-08-08 10:19:35 -04:00
|
|
|
Get beam radiation surrounding the city object in J/m2
|
2023-08-07 12:32:33 -04:00
|
|
|
:return: dict{dict{[float]}}
|
2021-04-01 10:36:07 -04:00
|
|
|
"""
|
|
|
|
return self._beam
|
|
|
|
|
|
|
|
@beam.setter
|
|
|
|
def beam(self, value):
|
|
|
|
"""
|
2023-08-08 10:19:35 -04:00
|
|
|
Set beam radiation surrounding the city object in J/m2
|
2023-08-07 12:32:33 -04:00
|
|
|
:param value: dict{dict{[float]}}
|
2021-04-01 10:36:07 -04:00
|
|
|
"""
|
|
|
|
self._beam = value
|
|
|
|
|
|
|
|
@property
|
2021-06-23 09:53:33 -04:00
|
|
|
def lower_corner(self):
|
2021-06-02 09:30:01 -04:00
|
|
|
"""
|
2021-08-30 14:39:24 -04:00
|
|
|
Get city object lower corner coordinates [x, y, z]
|
|
|
|
:return: [x,y,z]
|
2021-06-02 09:30:01 -04:00
|
|
|
"""
|
2021-04-01 10:36:07 -04:00
|
|
|
if self._city_object_lower_corner is None:
|
|
|
|
self._city_object_lower_corner = [self._min_x, self._min_y, self._min_z]
|
|
|
|
return self._city_object_lower_corner
|
2021-06-02 09:30:01 -04:00
|
|
|
|
2023-02-23 07:25:04 -05:00
|
|
|
@property
|
|
|
|
def upper_corner(self):
|
|
|
|
"""
|
|
|
|
Get city object upper corner coordinates [x, y, z]
|
|
|
|
:return: [x,y,z]
|
|
|
|
"""
|
|
|
|
if self._city_object_upper_corner is None:
|
|
|
|
self._city_object_upper_corner = [self._max_x, self._max_y, self._max_z]
|
|
|
|
return self._city_object_upper_corner
|
|
|
|
|
2021-06-02 09:30:01 -04:00
|
|
|
@property
|
|
|
|
def sensors(self) -> List[Sensor]:
|
|
|
|
"""
|
2021-08-30 14:39:24 -04:00
|
|
|
Get sensors belonging to the city object
|
2021-06-02 09:30:01 -04:00
|
|
|
:return: [Sensor]
|
|
|
|
"""
|
|
|
|
return self._sensors
|
|
|
|
|
|
|
|
@sensors.setter
|
|
|
|
def sensors(self, value):
|
|
|
|
"""
|
2021-08-30 14:39:24 -04:00
|
|
|
Set sensors belonging to the city object
|
2021-06-02 09:30:01 -04:00
|
|
|
:param value: [Sensor]
|
|
|
|
"""
|
2021-06-03 13:34:41 -04:00
|
|
|
self._sensors = value
|
2023-02-23 06:56:13 -05:00
|
|
|
|
|
|
|
@property
|
|
|
|
def neighbours(self) -> Union[None, List[CityObject]]:
|
|
|
|
"""
|
|
|
|
Get the list of neighbour_objects and their properties associated to the current city_object
|
|
|
|
"""
|
|
|
|
return self._neighbours
|
|
|
|
|
|
|
|
@neighbours.setter
|
|
|
|
def neighbours(self, value):
|
|
|
|
"""
|
|
|
|
Set the list of neighbour_objects and their properties associated to the current city_object
|
|
|
|
"""
|
|
|
|
self._neighbours = value
|