hub/city_model_structure/attributes/surface.py

215 lines
5.3 KiB
Python
Raw Normal View History

2020-10-28 13:42:58 -04:00
"""
Surface module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
contributors Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
2020-10-28 13:42:58 -04:00
"""
from __future__ import annotations
2020-10-28 13:42:58 -04:00
import numpy as np
import uuid
from city_model_structure.attributes.polygon import Polygon
2020-10-28 13:42:58 -04:00
class Surface:
"""
Surface class
"""
def __init__(self, solid_polygon, perimeter_polygon, holes_polygons=None, surface_type=None, swr=None):
2020-10-28 13:42:58 -04:00
self._type = surface_type
self._swr = swr
self._name = None
self._id = None
2020-10-28 13:42:58 -04:00
self._azimuth = None
self._inclination = None
self._area_above_ground = None
self._area_below_ground = None
self._parent = None
2021-04-07 14:20:13 -04:00
self._bounds_lower_corner = None
self._bounds_upper_corner = None
2020-10-28 13:42:58 -04:00
self._shared_surfaces = []
self._global_irradiance = dict()
self._perimeter_polygon = perimeter_polygon
self._holes_polygons = holes_polygons
self._solid_polygons = solid_polygon
2020-10-28 13:42:58 -04:00
@property
def name(self):
"""
Surface name
:return: str
"""
if self._name is None:
self._name = str(uuid.uuid4())
2020-10-28 13:42:58 -04:00
return self._name
@property
def id(self):
"""
Surface id
:return str
"""
if self._id is None:
self._id = self.name.replace('-', '').replace('a', '').replace('b', '').replace('c', '').replace('d', '')
self._id = self._id.replace('e', '').replace('f', '')
print(self._id)
return self._id
2020-10-28 13:42:58 -04:00
@property
def swr(self):
"""
Get surface short wave reflectance
:return: float
"""
return self._swr
@swr.setter
def swr(self, value):
"""
Set surface short wave reflectance
:param value: float
:return: None
"""
self._swr = value
def _max_coord(self, axis):
if axis == 'x':
axis = 0
elif axis == 'y':
axis = 1
else:
axis = 2
max_coordinate = ''
for point in self.perimeter_polygon.points:
if max_coordinate == '':
max_coordinate = point[axis]
elif max_coordinate < point[axis]:
max_coordinate = point[axis]
return max_coordinate
2020-10-28 13:42:58 -04:00
def _min_coord(self, axis):
if axis == 'x':
axis = 0
elif axis == 'y':
axis = 1
else:
axis = 2
min_coordinate = ''
for point in self.perimeter_polygon.points:
2020-10-28 13:42:58 -04:00
if min_coordinate == '':
min_coordinate = point[axis]
elif min_coordinate > point[axis]:
min_coordinate = point[axis]
return min_coordinate
@property
2021-04-07 14:20:13 -04:00
def bounds_lower_corner(self):
if self._bounds_lower_corner is None:
self._bounds_lower_corner = [self._min_coord('x'), self._min_coord('y'), self._min_coord('z')]
return self._bounds_lower_corner
@property
2021-04-07 14:20:13 -04:00
def bounds_upper_corner(self):
if self._bounds_upper_corner is None:
self._bounds_upper_corner = [self._max_coord('x'), self._max_coord('y'), self._max_coord('z')]
return self._bounds_upper_corner
2020-10-28 13:42:58 -04:00
@property
def area_above_ground(self):
"""
Surface area above ground in square meters
:return: float
"""
if self._area_above_ground is None:
self._area_above_ground = self.perimeter_polygon.area - self.area_below_ground
2020-10-28 13:42:58 -04:00
return self._area_above_ground
# todo: to be implemented
2020-10-28 13:42:58 -04:00
@property
def area_below_ground(self):
"""
Surface area below ground in square meters
:return: float
"""
return 0.0
2020-10-28 13:42:58 -04:00
@property
def azimuth(self):
"""
Surface azimuth in radians
:return: float
"""
if self._azimuth is None:
normal = self.perimeter_polygon.normal
2020-10-28 13:42:58 -04:00
self._azimuth = np.arctan2(normal[1], normal[0])
return self._azimuth
@property
def inclination(self):
"""
Surface inclination in radians
:return: float
"""
if self._inclination is None:
self._inclination = np.arccos(self.perimeter_polygon.normal[2])
2020-10-28 13:42:58 -04:00
return self._inclination
@property
def type(self):
"""
Surface type Ground, Wall or Roof
:return: str
"""
if self._type is None:
grad = np.rad2deg(self.inclination)
if grad >= 170:
self._type = 'Ground'
elif 80 <= grad <= 100:
self._type = 'Wall'
else:
self._type = 'Roof'
return self._type
@property
def global_irradiance(self) -> dict:
2020-10-28 13:42:58 -04:00
"""
global irradiance on surface in Wh/m2
:return: dict{DataFrame(float)}
2020-10-28 13:42:58 -04:00
"""
return self._global_irradiance
2020-10-28 13:42:58 -04:00
@global_irradiance.setter
def global_irradiance(self, value):
2020-10-28 13:42:58 -04:00
"""
global irradiance on surface in Wh/m2
:param value: dict{DataFrame(float)}
2020-10-28 13:42:58 -04:00
"""
self._global_irradiance = value
2020-10-28 13:42:58 -04:00
@property
def perimeter_polygon(self) -> Polygon:
2020-10-28 13:42:58 -04:00
"""
total surface defined by the perimeter, merging solid and holes
:return: Polygon
2020-10-28 13:42:58 -04:00
"""
return self._perimeter_polygon
2020-10-28 13:42:58 -04:00
@property
def solid_polygon(self) -> Polygon:
2020-10-28 13:42:58 -04:00
"""
solid surface
:return: Polygon
"""
return self._solid_polygons
2020-12-01 07:33:23 -05:00
@property
def holes_polygons(self) -> [Polygon]:
"""
hole surfaces, a list of hole polygons found in the surface
:return: None, [] or [Polygon]
None -> not known whether holes exist in reality or not due to low level of detail of input data
[] -> no holes in the surface
[Polygon] -> one or more holes in the surface
"""
return self._holes_polygons