Add the building/city_objects hierarchy to the city
This commit is contained in:
parent
16e33b3772
commit
4a58387f23
317
city_model_structure/building.py
Normal file
317
city_model_structure/building.py
Normal file
|
@ -0,0 +1,317 @@
|
|||
"""
|
||||
CityObject module
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||
"""
|
||||
from pathlib import Path
|
||||
from typing import Union, List
|
||||
|
||||
import matplotlib.patches as patches
|
||||
import numpy as np
|
||||
from matplotlib import pylab
|
||||
from shapely import ops
|
||||
from shapely.geometry import MultiPolygon
|
||||
|
||||
from city_model_structure.polyhedron import Polyhedron
|
||||
from city_model_structure.surface import Surface
|
||||
from city_model_structure.thermal_boundary import ThermalBoundary
|
||||
from city_model_structure.thermal_zone import ThermalZone
|
||||
from city_model_structure.usage_zone import UsageZone
|
||||
from city_model_structure.city_object import CityObject
|
||||
|
||||
|
||||
class Building(CityObject):
|
||||
"""
|
||||
CityObject class
|
||||
"""
|
||||
def __init__(self, name, lod, surfaces, terrains, year_of_construction, function, lower_corner, attic_heated=0,
|
||||
basement_heated=0):
|
||||
super().__init__(lod)
|
||||
self._name = name
|
||||
self._surfaces = surfaces
|
||||
self._basement_heated = basement_heated
|
||||
self._attic_heated = attic_heated
|
||||
self._terrains = terrains
|
||||
self._year_of_construction = year_of_construction
|
||||
self._function = function
|
||||
self._lower_corner = lower_corner
|
||||
self._average_storey_height = None
|
||||
self._storeys_above_ground = None
|
||||
self._foot_print = None
|
||||
self._usage_zones = []
|
||||
self._type = 'building'
|
||||
|
||||
# ToDo: Check this for LOD4
|
||||
self._thermal_zones = []
|
||||
if self.lod < 8:
|
||||
# for lod under 4 is just one thermal zone
|
||||
self._thermal_zones.append(ThermalZone(self.surfaces))
|
||||
|
||||
for t_zones in self._thermal_zones:
|
||||
t_zones.bounded = [ThermalBoundary(s, [t_zones]) for s in t_zones.surfaces]
|
||||
surface_id = 0
|
||||
for surface in self._surfaces:
|
||||
surface.lower_corner = self._lower_corner
|
||||
surface.parent(self, surface_id)
|
||||
surface_id += 1
|
||||
|
||||
@property
|
||||
def usage_zones(self) -> List[UsageZone]:
|
||||
"""
|
||||
Get city object usage zones
|
||||
:return: [UsageZone]
|
||||
"""
|
||||
return self._usage_zones
|
||||
|
||||
@usage_zones.setter
|
||||
def usage_zones(self, values):
|
||||
"""
|
||||
Set city objects usage zones
|
||||
:param values: [UsageZones]
|
||||
:return: None
|
||||
"""
|
||||
# ToDo: this is only valid for one usage zone need to be revised for multiple usage zones.
|
||||
self._usage_zones = values
|
||||
for thermal_zone in self.thermal_zones:
|
||||
thermal_zone.usage_zones = [(100, usage_zone) for usage_zone in values]
|
||||
|
||||
@property
|
||||
def terrains(self) -> List[Surface]:
|
||||
"""
|
||||
Get city object terrain surfaces
|
||||
:return: [Surface]
|
||||
"""
|
||||
return self._terrains
|
||||
|
||||
@property
|
||||
def attic_heated(self):
|
||||
"""
|
||||
Get if the city object attic is heated
|
||||
:return: Boolean
|
||||
"""
|
||||
return self._attic_heated
|
||||
|
||||
@attic_heated.setter
|
||||
def attic_heated(self, value):
|
||||
"""
|
||||
Set if the city object attic is heated
|
||||
:param value: Boolean
|
||||
:return: None
|
||||
"""
|
||||
self._attic_heated = value
|
||||
|
||||
@property
|
||||
def basement_heated(self):
|
||||
"""
|
||||
Get if the city object basement is heated
|
||||
:return: Boolean
|
||||
"""
|
||||
return self._basement_heated
|
||||
|
||||
@basement_heated.setter
|
||||
def basement_heated(self, value):
|
||||
"""
|
||||
Set if the city object basement is heated
|
||||
:param value: Boolean
|
||||
:return: None
|
||||
"""
|
||||
self._attic_heated = value
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""
|
||||
City object name
|
||||
:return: str
|
||||
"""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def lod(self):
|
||||
"""
|
||||
City object level of detail 1, 2, 3 or 4
|
||||
:return: int
|
||||
"""
|
||||
return self._lod
|
||||
|
||||
@property
|
||||
def surfaces(self) -> List[Surface]:
|
||||
"""
|
||||
City object surfaces
|
||||
:return: [Surface]
|
||||
"""
|
||||
return self._surfaces
|
||||
|
||||
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
|
||||
|
||||
@property
|
||||
def thermal_zones(self) -> List[ThermalZone]:
|
||||
"""
|
||||
City object thermal zones
|
||||
:return: [ThermalZone]
|
||||
"""
|
||||
return self._thermal_zones
|
||||
|
||||
@property
|
||||
def volume(self):
|
||||
"""
|
||||
City object volume in cubic meters
|
||||
:return: float
|
||||
"""
|
||||
if self._polyhedron is None:
|
||||
self._polyhedron = Polyhedron(self.surfaces)
|
||||
return self._polyhedron.volume
|
||||
|
||||
@property
|
||||
def heated_volume(self):
|
||||
"""
|
||||
City object heated volume in cubic meters
|
||||
:return: float
|
||||
"""
|
||||
if self._polyhedron is None:
|
||||
self._polyhedron = Polyhedron(self.surfaces)
|
||||
# ToDo: this need to be the calculated based on the basement and attic heated values
|
||||
return self._polyhedron.volume
|
||||
|
||||
def stl_export(self, path):
|
||||
"""
|
||||
Export the city object to stl file (city_object_name.stl) to the given path
|
||||
:param path: str
|
||||
:return: None
|
||||
"""
|
||||
# todo: this is a method just for debugging, it will be soon removed
|
||||
if self._polyhedron is None:
|
||||
self._polyhedron = Polyhedron(self.surfaces)
|
||||
full_path = (Path(path) / (self._name + '.stl')).resolve()
|
||||
self._polyhedron.export(full_path)
|
||||
|
||||
@property
|
||||
def year_of_construction(self):
|
||||
"""
|
||||
City object year of construction
|
||||
:return: int
|
||||
"""
|
||||
return self._year_of_construction
|
||||
|
||||
@property
|
||||
def function(self):
|
||||
"""
|
||||
City object function
|
||||
:return: str
|
||||
"""
|
||||
return self._function
|
||||
|
||||
@property
|
||||
def average_storey_height(self):
|
||||
"""
|
||||
Get city object average storey height in meters
|
||||
:return: float
|
||||
"""
|
||||
return self._average_storey_height
|
||||
|
||||
@average_storey_height.setter
|
||||
def average_storey_height(self, value):
|
||||
"""
|
||||
Set city object average storey height in meters
|
||||
:param value: float
|
||||
:return: None
|
||||
"""
|
||||
self._average_storey_height = value
|
||||
|
||||
@property
|
||||
def storeys_above_ground(self):
|
||||
"""
|
||||
Get city object storeys number above ground
|
||||
:return: int
|
||||
"""
|
||||
return self._storeys_above_ground
|
||||
|
||||
@storeys_above_ground.setter
|
||||
def storeys_above_ground(self, value):
|
||||
"""
|
||||
Set city object storeys number above ground
|
||||
:param value: int
|
||||
:return:
|
||||
"""
|
||||
self._storeys_above_ground = value
|
||||
|
||||
@staticmethod
|
||||
def _tuple_to_point(xy_tuple):
|
||||
return [xy_tuple[0], xy_tuple[1], 0.0]
|
||||
|
||||
def _plot(self, polygon):
|
||||
points = ()
|
||||
for point_tuple in polygon.exterior.coords:
|
||||
almost_equal = False
|
||||
for point in points:
|
||||
point_1 = Building._tuple_to_point(point)
|
||||
point_2 = Building._tuple_to_point(point_tuple)
|
||||
if self._geometry.almost_equal(point_1, point_2):
|
||||
almost_equal = True
|
||||
break
|
||||
if not almost_equal:
|
||||
points = points + (point_tuple,)
|
||||
points = points + (points[0],)
|
||||
pylab.scatter([point[0] for point in points], [point[1] for point in points])
|
||||
pylab.gca().add_patch(patches.Polygon(points, closed=True, fill=True))
|
||||
pylab.grid()
|
||||
pylab.show()
|
||||
|
||||
@property
|
||||
def foot_print(self) -> Surface:
|
||||
"""
|
||||
City object foot print surface
|
||||
:return: Surface
|
||||
"""
|
||||
if self._foot_print is None:
|
||||
shapelys = []
|
||||
union = None
|
||||
for surface in self.surfaces:
|
||||
if surface.shapely.is_empty or not surface.shapely.is_valid:
|
||||
continue
|
||||
shapelys.append(surface.shapely)
|
||||
union = ops.unary_union(shapelys)
|
||||
shapelys = [union]
|
||||
if isinstance(union, MultiPolygon):
|
||||
Exception('foot print returns a multipolygon')
|
||||
points_list = []
|
||||
for point_tuple in union.exterior.coords:
|
||||
# ToDo: should be Z 0.0 or min Z?
|
||||
point = Building._tuple_to_point(point_tuple)
|
||||
almost_equal = False
|
||||
for existing_point in points_list:
|
||||
if self._geometry.almost_equal(point, existing_point):
|
||||
almost_equal = True
|
||||
break
|
||||
if not almost_equal:
|
||||
points_list.append(point)
|
||||
points_list = np.reshape(points_list, len(points_list) * 3)
|
||||
points = np.array_str(points_list).replace('[', '').replace(']', '')
|
||||
self._foot_print = Surface(points, remove_last=False, is_projected=True)
|
||||
return self._foot_print
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
"""
|
||||
City object type
|
||||
:return: str
|
||||
"""
|
||||
return self._type
|
||||
|
||||
@property
|
||||
def max_height(self):
|
||||
"""
|
||||
City object maximal height in meters
|
||||
:return: float
|
||||
"""
|
||||
if self._polyhedron is None:
|
||||
self._polyhedron = Polyhedron(self.surfaces)
|
||||
return self._polyhedron.max_z
|
|
@ -10,6 +10,7 @@ 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
|
||||
|
||||
|
||||
|
@ -18,12 +19,12 @@ class City:
|
|||
City class
|
||||
"""
|
||||
|
||||
def __init__(self, lower_corner, upper_corner, srs_name, city_objects=None):
|
||||
self._city_objects = None
|
||||
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._city_objects = city_objects
|
||||
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
|
||||
|
@ -62,10 +63,42 @@ class City:
|
|||
@property
|
||||
def city_objects(self) -> Union[List[CityObject], None]:
|
||||
"""
|
||||
CityObjects belonging to the city
|
||||
:return: None or a list of CityObjects
|
||||
City objects belonging to the city
|
||||
:return: None or [CityObject]
|
||||
"""
|
||||
return self._city_objects
|
||||
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):
|
||||
|
@ -89,7 +122,7 @@ class City:
|
|||
:param name:str
|
||||
:return: None or CityObject
|
||||
"""
|
||||
for city_object in self.city_objects:
|
||||
for city_object in self.buildings:
|
||||
if city_object.name == name:
|
||||
return city_object
|
||||
return None
|
||||
|
@ -100,13 +133,15 @@ class City:
|
|||
:param new_city_object:CityObject
|
||||
:return: None
|
||||
"""
|
||||
if self._city_objects is None:
|
||||
self._city_objects = []
|
||||
for city_object in self.city_objects:
|
||||
for surface in city_object.surfaces:
|
||||
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._city_objects.append(new_city_object)
|
||||
self._buildings.append(new_city_object)
|
||||
|
||||
@property
|
||||
def srs_name(self):
|
||||
|
|
|
@ -1,320 +1,8 @@
|
|||
"""
|
||||
CityObject module
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||
"""
|
||||
from pathlib import Path
|
||||
from typing import Union, List
|
||||
|
||||
import matplotlib.patches as patches
|
||||
import numpy as np
|
||||
from matplotlib import pylab
|
||||
from shapely import ops
|
||||
from shapely.geometry import MultiPolygon
|
||||
|
||||
from city_model_structure.polyhedron import Polyhedron
|
||||
from city_model_structure.surface import Surface
|
||||
from city_model_structure.thermal_boundary import ThermalBoundary
|
||||
from city_model_structure.thermal_zone import ThermalZone
|
||||
from city_model_structure.usage_zone import UsageZone
|
||||
from helpers.geometry_helper import GeometryHelper
|
||||
|
||||
|
||||
class CityObject:
|
||||
"""
|
||||
CityObject class
|
||||
"""
|
||||
def __init__(self, name, lod, surfaces, terrains, year_of_construction, function, lower_corner, attic_heated=0,
|
||||
basement_heated=0):
|
||||
self._name = name
|
||||
def __init__(self, lod):
|
||||
self._lod = lod
|
||||
self._surfaces = surfaces
|
||||
self._polyhedron = None
|
||||
self._basement_heated = basement_heated
|
||||
self._attic_heated = attic_heated
|
||||
self._terrains = terrains
|
||||
self._year_of_construction = year_of_construction
|
||||
self._function = function
|
||||
self._lower_corner = lower_corner
|
||||
self._geometry = GeometryHelper()
|
||||
self._average_storey_height = None
|
||||
self._storeys_above_ground = None
|
||||
self._foot_print = None
|
||||
self._usage_zones = []
|
||||
# ToDo: this need to be changed when we have other city_objects beside "buildings"
|
||||
self._type = 'building'
|
||||
|
||||
# ToDo: Check this for LOD4
|
||||
self._thermal_zones = []
|
||||
if self.lod < 8:
|
||||
# for lod under 4 is just one thermal zone
|
||||
self._thermal_zones.append(ThermalZone(self.surfaces))
|
||||
|
||||
for t_zones in self._thermal_zones:
|
||||
t_zones.bounded = [ThermalBoundary(s, [t_zones]) for s in t_zones.surfaces]
|
||||
surface_id = 0
|
||||
for surface in self._surfaces:
|
||||
surface.lower_corner = self._lower_corner
|
||||
surface.parent(self, surface_id)
|
||||
surface_id += 1
|
||||
|
||||
@property
|
||||
def usage_zones(self) -> List[UsageZone]:
|
||||
"""
|
||||
Get city object usage zones
|
||||
:return: [UsageZone]
|
||||
"""
|
||||
return self._usage_zones
|
||||
|
||||
@usage_zones.setter
|
||||
def usage_zones(self, values):
|
||||
"""
|
||||
Set city objects usage zones
|
||||
:param values: [UsageZones]
|
||||
:return: None
|
||||
"""
|
||||
# ToDo: this is only valid for one usage zone need to be revised for multiple usage zones.
|
||||
self._usage_zones = values
|
||||
for thermal_zone in self.thermal_zones:
|
||||
thermal_zone.usage_zones = [(100, usage_zone) for usage_zone in values]
|
||||
|
||||
@property
|
||||
def terrains(self) -> List[Surface]:
|
||||
"""
|
||||
Get city object terrain surfaces
|
||||
:return: [Surface]
|
||||
"""
|
||||
return self._terrains
|
||||
|
||||
@property
|
||||
def attic_heated(self):
|
||||
"""
|
||||
Get if the city object attic is heated
|
||||
:return: Boolean
|
||||
"""
|
||||
return self._attic_heated
|
||||
|
||||
@attic_heated.setter
|
||||
def attic_heated(self, value):
|
||||
"""
|
||||
Set if the city object attic is heated
|
||||
:param value: Boolean
|
||||
:return: None
|
||||
"""
|
||||
self._attic_heated = value
|
||||
|
||||
@property
|
||||
def basement_heated(self):
|
||||
"""
|
||||
Get if the city object basement is heated
|
||||
:return: Boolean
|
||||
"""
|
||||
return self._basement_heated
|
||||
|
||||
@basement_heated.setter
|
||||
def basement_heated(self, value):
|
||||
"""
|
||||
Set if the city object basement is heated
|
||||
:param value: Boolean
|
||||
:return: None
|
||||
"""
|
||||
self._attic_heated = value
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""
|
||||
City object name
|
||||
:return: str
|
||||
"""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def lod(self):
|
||||
"""
|
||||
City object level of detail 1, 2, 3 or 4
|
||||
:return: int
|
||||
"""
|
||||
return self._lod
|
||||
|
||||
@property
|
||||
def surfaces(self) -> List[Surface]:
|
||||
"""
|
||||
City object surfaces
|
||||
:return: [Surface]
|
||||
"""
|
||||
return self._surfaces
|
||||
|
||||
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
|
||||
|
||||
@property
|
||||
def thermal_zones(self) -> List[ThermalZone]:
|
||||
"""
|
||||
City object thermal zones
|
||||
:return: [ThermalZone]
|
||||
"""
|
||||
return self._thermal_zones
|
||||
|
||||
@property
|
||||
def volume(self):
|
||||
"""
|
||||
City object volume in cubic meters
|
||||
:return: float
|
||||
"""
|
||||
if self._polyhedron is None:
|
||||
self._polyhedron = Polyhedron(self.surfaces)
|
||||
return self._polyhedron.volume
|
||||
|
||||
@property
|
||||
def heated_volume(self):
|
||||
"""
|
||||
City object heated volume in cubic meters
|
||||
:return: float
|
||||
"""
|
||||
if self._polyhedron is None:
|
||||
self._polyhedron = Polyhedron(self.surfaces)
|
||||
# ToDo: this need to be the calculated based on the basement and attic heated values
|
||||
return self._polyhedron.volume
|
||||
|
||||
def stl_export(self, path):
|
||||
"""
|
||||
Export the city object to stl file (city_object_name.stl) to the given path
|
||||
:param path: str
|
||||
:return: None
|
||||
"""
|
||||
# todo: this is a method just for debugging, it will be soon removed
|
||||
if self._polyhedron is None:
|
||||
self._polyhedron = Polyhedron(self.surfaces)
|
||||
full_path = (Path(path) / (self._name + '.stl')).resolve()
|
||||
self._polyhedron.export(full_path)
|
||||
|
||||
@property
|
||||
def year_of_construction(self):
|
||||
"""
|
||||
City object year of construction
|
||||
:return: int
|
||||
"""
|
||||
return self._year_of_construction
|
||||
|
||||
@property
|
||||
def function(self):
|
||||
"""
|
||||
City object function
|
||||
:return: str
|
||||
"""
|
||||
return self._function
|
||||
|
||||
@property
|
||||
def average_storey_height(self):
|
||||
"""
|
||||
Get city object average storey height in meters
|
||||
:return: float
|
||||
"""
|
||||
return self._average_storey_height
|
||||
|
||||
@average_storey_height.setter
|
||||
def average_storey_height(self, value):
|
||||
"""
|
||||
Set city object average storey height in meters
|
||||
:param value: float
|
||||
:return: None
|
||||
"""
|
||||
self._average_storey_height = value
|
||||
|
||||
@property
|
||||
def storeys_above_ground(self):
|
||||
"""
|
||||
Get city object storeys number above ground
|
||||
:return: int
|
||||
"""
|
||||
return self._storeys_above_ground
|
||||
|
||||
@storeys_above_ground.setter
|
||||
def storeys_above_ground(self, value):
|
||||
"""
|
||||
Set city object storeys number above ground
|
||||
:param value: int
|
||||
:return:
|
||||
"""
|
||||
self._storeys_above_ground = value
|
||||
|
||||
@staticmethod
|
||||
def _tuple_to_point(xy_tuple):
|
||||
return [xy_tuple[0], xy_tuple[1], 0.0]
|
||||
|
||||
def _plot(self, polygon):
|
||||
points = ()
|
||||
for point_tuple in polygon.exterior.coords:
|
||||
almost_equal = False
|
||||
for point in points:
|
||||
point_1 = CityObject._tuple_to_point(point)
|
||||
point_2 = CityObject._tuple_to_point(point_tuple)
|
||||
if self._geometry.almost_equal(point_1, point_2):
|
||||
almost_equal = True
|
||||
break
|
||||
if not almost_equal:
|
||||
points = points + (point_tuple,)
|
||||
points = points + (points[0],)
|
||||
pylab.scatter([point[0] for point in points], [point[1] for point in points])
|
||||
pylab.gca().add_patch(patches.Polygon(points, closed=True, fill=True))
|
||||
pylab.grid()
|
||||
pylab.show()
|
||||
|
||||
@property
|
||||
def foot_print(self) -> Surface:
|
||||
"""
|
||||
City object foot print surface
|
||||
:return: Surface
|
||||
"""
|
||||
if self._foot_print is None:
|
||||
shapelys = []
|
||||
union = None
|
||||
for surface in self.surfaces:
|
||||
if surface.shapely.is_empty or not surface.shapely.is_valid:
|
||||
continue
|
||||
shapelys.append(surface.shapely)
|
||||
union = ops.unary_union(shapelys)
|
||||
shapelys = [union]
|
||||
if isinstance(union, MultiPolygon):
|
||||
Exception('foot print returns a multipolygon')
|
||||
points_list = []
|
||||
for point_tuple in union.exterior.coords:
|
||||
# ToDo: should be Z 0.0 or min Z?
|
||||
point = CityObject._tuple_to_point(point_tuple)
|
||||
almost_equal = False
|
||||
for existing_point in points_list:
|
||||
if self._geometry.almost_equal(point, existing_point):
|
||||
almost_equal = True
|
||||
break
|
||||
if not almost_equal:
|
||||
points_list.append(point)
|
||||
points_list = np.reshape(points_list, len(points_list) * 3)
|
||||
points = np.array_str(points_list).replace('[', '').replace(']', '')
|
||||
self._foot_print = Surface(points, remove_last=False, is_projected=True)
|
||||
return self._foot_print
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
"""
|
||||
City object type
|
||||
:return: str
|
||||
"""
|
||||
return self._type
|
||||
|
||||
@property
|
||||
def max_height(self):
|
||||
"""
|
||||
City object maximal height in meters
|
||||
:return: float
|
||||
"""
|
||||
if self._polyhedron is None:
|
||||
self._polyhedron = Polyhedron(self.surfaces)
|
||||
return self._polyhedron.max_z
|
||||
|
|
|
@ -26,7 +26,7 @@ class ThermalOpening:
|
|||
Get thermal opening openable ratio, NOT IMPLEMENTED
|
||||
:return: Exception
|
||||
"""
|
||||
raise Exception('Not implemented')
|
||||
raise NotImplementedError()
|
||||
|
||||
@openable_ratio.setter
|
||||
def openable_ratio(self, value):
|
||||
|
@ -35,7 +35,7 @@ class ThermalOpening:
|
|||
:param value: Any
|
||||
:return: Exception
|
||||
"""
|
||||
raise Exception('Not implemented')
|
||||
raise NotImplementedError()
|
||||
|
||||
@property
|
||||
def conductivity(self):
|
||||
|
|
|
@ -7,7 +7,7 @@ import numpy as np
|
|||
import xmltodict
|
||||
|
||||
from city_model_structure.city import City
|
||||
from city_model_structure.city_object import CityObject
|
||||
from city_model_structure.building import Building
|
||||
from city_model_structure.surface import Surface
|
||||
from helpers.geometry_helper import GeometryHelper
|
||||
|
||||
|
@ -115,6 +115,6 @@ class CityGml:
|
|||
year_of_construction = o['Building']['yearOfConstruction']
|
||||
if 'function' in o['Building']:
|
||||
function = o['Building']['function']
|
||||
self._city.add_city_object(CityObject(name, lod, surfaces, terrains, year_of_construction, function,
|
||||
self._lower_corner))
|
||||
self._city.add_city_object(Building(name, lod, surfaces, terrains, year_of_construction, function,
|
||||
self._lower_corner))
|
||||
return self._city
|
||||
|
|
|
@ -14,4 +14,4 @@ class UsNewYorkCityPhysicsParameters(UsBasePhysicsParameters):
|
|||
def __init__(self, city, base_path):
|
||||
self._city = city
|
||||
climate_zone = 'ASHRAE_2004:4A'
|
||||
super().__init__(climate_zone, self._city.city_objects, Pf.function, base_path)
|
||||
super().__init__(climate_zone, self._city.buildings, Pf.function, base_path)
|
||||
|
|
|
@ -14,4 +14,4 @@ class UsPhysicsParameters(UsBasePhysicsParameters):
|
|||
def __init__(self, city, base_path):
|
||||
self._city = city
|
||||
self._climate_zone = UsToLibraryTypes.city_to_climate_zone(city.name)
|
||||
super().__init__(self._climate_zone, self._city.city_objects, lambda function: function, base_path)
|
||||
super().__init__(self._climate_zone, self._city.buildings, lambda function: function, base_path)
|
||||
|
|
|
@ -35,8 +35,8 @@ class TestGeometryFactory(TestCase):
|
|||
:return: None
|
||||
"""
|
||||
city = self._get_citygml()
|
||||
self.assertIsNotNone(city.city_objects, 'city_objects is none')
|
||||
for city_object in city.city_objects:
|
||||
self.assertIsNotNone(city.buildings, 'city_objects is none')
|
||||
for city_object in city.buildings:
|
||||
self.assertIsNotNone(city.city_object(city_object.name), 'city_object return none')
|
||||
self.assertIsNotNone(city.srs_name, 'srs_name is none')
|
||||
self.assertIsNotNone(city.lower_corner, 'lower_corner is none')
|
||||
|
@ -50,7 +50,7 @@ class TestGeometryFactory(TestCase):
|
|||
:return: None
|
||||
"""
|
||||
city = self._get_citygml()
|
||||
for city_object in city.city_objects:
|
||||
for city_object in city.buildings:
|
||||
self.assertIsNotNone(city_object.name, 'city_object name is none')
|
||||
self.assertIsNotNone(city_object.lod, 'city_object lod is none')
|
||||
self.assertIsNotNone(city_object.year_of_construction, 'city_object year_of_construction is none')
|
||||
|
@ -78,7 +78,7 @@ class TestGeometryFactory(TestCase):
|
|||
:return: None
|
||||
"""
|
||||
city = self._get_citygml()
|
||||
for city_object in city.city_objects:
|
||||
for city_object in city.buildings:
|
||||
for surface in city_object.surfaces:
|
||||
self.assertIsNotNone(surface.name, 'surface name is none')
|
||||
self.assertIsNotNone(surface.area, 'surface area is none')
|
||||
|
@ -109,7 +109,7 @@ class TestGeometryFactory(TestCase):
|
|||
:return: None
|
||||
"""
|
||||
city = self._get_citygml()
|
||||
for city_object in city.city_objects:
|
||||
for city_object in city.buildings:
|
||||
for thermal_zone in city_object.thermal_zones:
|
||||
self.assertIsNotNone(thermal_zone.surfaces, 'thermal_zone surfaces is none')
|
||||
self.assertIsNotNone(thermal_zone.bounded, 'thermal_zone bounded is none')
|
||||
|
@ -135,7 +135,7 @@ class TestGeometryFactory(TestCase):
|
|||
:return: None
|
||||
"""
|
||||
city = self._get_citygml()
|
||||
for city_object in city.city_objects:
|
||||
for city_object in city.buildings:
|
||||
for thermal_zone in city_object.thermal_zones:
|
||||
for thermal_boundary in thermal_zone.bounded:
|
||||
self.assertIsNotNone(thermal_boundary.type, 'thermal_boundary type is none')
|
||||
|
@ -165,7 +165,7 @@ class TestGeometryFactory(TestCase):
|
|||
:return: None
|
||||
"""
|
||||
city = self._get_citygml()
|
||||
for city_object in city.city_objects:
|
||||
for city_object in city.buildings:
|
||||
for thermal_zone in city_object.thermal_zones:
|
||||
for thermal_boundary in thermal_zone.bounded:
|
||||
for thermal_opening in thermal_boundary.thermal_openings:
|
||||
|
|
|
@ -42,7 +42,7 @@ class TestPhysicsFactory(TestCase):
|
|||
:return: None
|
||||
"""
|
||||
city = self._get_city_with_physics()
|
||||
for city_object in city.city_objects:
|
||||
for city_object in city.buildings:
|
||||
self.assertIsNotNone(city_object.average_storey_height, 'average_storey_height is none')
|
||||
self.assertIsNotNone(city_object.storeys_above_ground, 'storeys_above_ground is none')
|
||||
for thermal_zone in city_object.thermal_zones:
|
||||
|
|
|
@ -21,7 +21,7 @@ class UsBaseUsageParameters:
|
|||
path = str(Path.cwd() / 'data/usage/de_library.xml')
|
||||
with open(path) as xml:
|
||||
self._library = xmltodict.parse(xml.read(), force_list='zoneUsageVariant')
|
||||
for city_object in self._city.city_objects:
|
||||
for city_object in self._city.buildings:
|
||||
# ToDo: Right now is just one usage zone but will be multiple in the future
|
||||
usage_zone = UsageZone()
|
||||
usage_zone.usage = function_to_usage(city_object.function)
|
||||
|
|
Loading…
Reference in New Issue
Block a user