forked from s_ranjbar/city_retrofit
Partial implementation energy ADE, till geometry export (LOD2) this commit is broken, due some missing attribute (max_(coord)) at surface class
This commit is contained in:
parent
dbbe3d56fc
commit
636047b99c
|
@ -7,6 +7,7 @@ contributors: Pilar Monsalvete pilar_monsalvete@yahoo.es
|
||||||
|
|
||||||
|
|
||||||
from typing import List
|
from typing import List
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
from city_model_structure.attributes.surface import Surface
|
from city_model_structure.attributes.surface import Surface
|
||||||
from city_model_structure.attributes.thermal_boundary import ThermalBoundary
|
from city_model_structure.attributes.thermal_boundary import ThermalBoundary
|
||||||
|
@ -35,6 +36,7 @@ class Building(CityObject):
|
||||||
self._average_storey_height = None
|
self._average_storey_height = None
|
||||||
self._storeys_above_ground = None
|
self._storeys_above_ground = None
|
||||||
self._floor_area = None
|
self._floor_area = None
|
||||||
|
self._roof_type = None
|
||||||
self._usage_zones = []
|
self._usage_zones = []
|
||||||
self._type = 'building'
|
self._type = 'building'
|
||||||
self._heating = dict()
|
self._heating = dict()
|
||||||
|
@ -43,7 +45,9 @@ class Building(CityObject):
|
||||||
self._global_horizontal = dict()
|
self._global_horizontal = dict()
|
||||||
self._diffuse = dict()
|
self._diffuse = dict()
|
||||||
self._beam = dict()
|
self._beam = dict()
|
||||||
|
self._grounds = []
|
||||||
|
self._roofs = []
|
||||||
|
self._walls = []
|
||||||
# ToDo: Check this for LOD4
|
# ToDo: Check this for LOD4
|
||||||
self._thermal_zones = []
|
self._thermal_zones = []
|
||||||
if self.lod < 4:
|
if self.lod < 4:
|
||||||
|
@ -52,11 +56,34 @@ class Building(CityObject):
|
||||||
|
|
||||||
for t_zones in self._thermal_zones:
|
for t_zones in self._thermal_zones:
|
||||||
t_zones.bounded = [ThermalBoundary(s, [t_zones]) for s in t_zones.surfaces]
|
t_zones.bounded = [ThermalBoundary(s, [t_zones]) for s in t_zones.surfaces]
|
||||||
surface_id = 0
|
|
||||||
for surface in self.surfaces:
|
for surface in self.surfaces:
|
||||||
surface.lower_corner = self._lower_corner
|
if surface.type == 'Ground':
|
||||||
surface.parent(self, surface_id)
|
self._grounds.append(surface)
|
||||||
surface_id += 1
|
elif surface.type == 'Wall':
|
||||||
|
self._walls.append(surface)
|
||||||
|
else:
|
||||||
|
self._roofs.append(surface)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def grounds(self) -> [Surface]:
|
||||||
|
"""
|
||||||
|
Building ground surfaces
|
||||||
|
"""
|
||||||
|
return self._grounds
|
||||||
|
|
||||||
|
@property
|
||||||
|
def roofs(self) -> [Surface]:
|
||||||
|
"""
|
||||||
|
Building roof surfaces
|
||||||
|
"""
|
||||||
|
return self._roofs
|
||||||
|
|
||||||
|
@property
|
||||||
|
def walls(self) -> [Surface]:
|
||||||
|
"""
|
||||||
|
Building wall surfaces
|
||||||
|
"""
|
||||||
|
return self._walls
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def usage_zones(self) -> List[UsageZone]:
|
def usage_zones(self) -> List[UsageZone]:
|
||||||
|
@ -325,6 +352,21 @@ class Building(CityObject):
|
||||||
storeys.append(rest_trimesh)
|
storeys.append(rest_trimesh)
|
||||||
return storeys
|
return storeys
|
||||||
|
|
||||||
|
@property
|
||||||
|
def roof_type(self):
|
||||||
|
"""
|
||||||
|
Roof type for the building flat or pitch
|
||||||
|
"""
|
||||||
|
if self._roof_type is None:
|
||||||
|
self._roof_type = 'flat'
|
||||||
|
for roof in self.roofs:
|
||||||
|
grads = np.rad2deg(roof.inclination)
|
||||||
|
if 355 > grads > 5:
|
||||||
|
self._roof_type = 'pitch'
|
||||||
|
break
|
||||||
|
print (self._roof_type)
|
||||||
|
return self._roof_type
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def floor_area(self):
|
def floor_area(self):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -53,25 +53,26 @@ class EnergyAde:
|
||||||
for building in self._city.buildings:
|
for building in self._city.buildings:
|
||||||
building_dic = {
|
building_dic = {
|
||||||
'bldg:Building': {
|
'bldg:Building': {
|
||||||
'@gml:id': building.name,
|
'@gml:id': building.name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
building_dic = EnergyAde._get_measures(building, building_dic)
|
building_dic = EnergyAde._measures(building, building_dic)
|
||||||
|
building_dic = EnergyAde._building_geometry(building, building_dic, self._city)
|
||||||
buildings.append(building_dic)
|
buildings.append(building_dic)
|
||||||
|
|
||||||
energy_ade['core:CityModel']['core:cityObjectMember'] = buildings
|
energy_ade['core:CityModel']['core:cityObjectMember'] = buildings
|
||||||
file_name = self._city.name + '_ade.gml'
|
file_name = self._city.name + '_ade.gml'
|
||||||
file_path = Path(self._path / file_name).resolve()
|
file_path = Path(self._path / file_name).resolve()
|
||||||
with open(file_path, 'w' ) as file:
|
with open(file_path, 'w' ) as file:
|
||||||
file.write(xmltodict.unparse(energy_ade,pretty=True))
|
file.write(xmltodict.unparse(energy_ade,pretty=True, short_empty_elements=True))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_measures(building, building_dic):
|
def _measures(building, building_dic):
|
||||||
measures = []
|
measures = []
|
||||||
measure = EnergyAde._get_measure(building.heating, 'year', 'Energy demand heating', 'INSEL')
|
measure = EnergyAde._measure(building.heating, 'year', 'Energy demand heating', 'INSEL')
|
||||||
if measure is not None:
|
if measure is not None:
|
||||||
measures.append(measure)
|
measures.append(measure)
|
||||||
measure = EnergyAde._get_measure(building.cooling, 'year', 'Energy demand cooling', 'INSEL')
|
measure = EnergyAde._measure(building.cooling, 'year', 'Energy demand cooling', 'INSEL')
|
||||||
if measure is not None:
|
if measure is not None:
|
||||||
measures.append(measure)
|
measures.append(measure)
|
||||||
if len(measures) != 0:
|
if len(measures) != 0:
|
||||||
|
@ -80,12 +81,12 @@ class EnergyAde:
|
||||||
periods = []
|
periods = []
|
||||||
for key in building.heating:
|
for key in building.heating:
|
||||||
if key != 'year':
|
if key != 'year':
|
||||||
period = EnergyAde._get_period(building.heating, key, 'Heating energy', 'INSEL')
|
period = EnergyAde._period(building.heating, key, 'Heating energy', 'INSEL')
|
||||||
periods.append(period)
|
periods.append(period)
|
||||||
|
|
||||||
for key in building.cooling:
|
for key in building.cooling:
|
||||||
if key != 'year':
|
if key != 'year':
|
||||||
period = EnergyAde._get_period(building.cooling, key, 'Cooling energy', 'INSEL')
|
period = EnergyAde._period(building.cooling, key, 'Cooling energy', 'INSEL')
|
||||||
periods.append(period)
|
periods.append(period)
|
||||||
|
|
||||||
if len(periods) != 0:
|
if len(periods) != 0:
|
||||||
|
@ -94,7 +95,7 @@ class EnergyAde:
|
||||||
return building_dic
|
return building_dic
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_measure(measure_dict, key_value, name, source):
|
def _measure(measure_dict, key_value, name, source):
|
||||||
measure = None
|
measure = None
|
||||||
if key_value in measure_dict:
|
if key_value in measure_dict:
|
||||||
measure = {
|
measure = {
|
||||||
|
@ -107,7 +108,7 @@ class EnergyAde:
|
||||||
return measure
|
return measure
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_period(measure_dict, key_value, description, source):
|
def _period(measure_dict, key_value, description, source):
|
||||||
period = {
|
period = {
|
||||||
'@gml:id': uuid.uuid4(),
|
'@gml:id': uuid.uuid4(),
|
||||||
'energy:energyAmount': {
|
'energy:energyAmount': {
|
||||||
|
@ -130,4 +131,106 @@ class EnergyAde:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return period
|
return period
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _building_geometry(building, building_dic, city):
|
||||||
|
|
||||||
|
building_dic['bldg:function'] = building.function
|
||||||
|
building_dic['bldg:usage'] = ', '.join([u.usage for u in building.usage_zones])
|
||||||
|
building_dic['bldg:yearOfConstruction'] = building.year_of_construction
|
||||||
|
building_dic['bldg:roofType'] = building.roof_type
|
||||||
|
|
||||||
|
building_dic['bldg:measuredHeight'] = {
|
||||||
|
'@uom': 'm',
|
||||||
|
'#text': f'{building.max_height}'
|
||||||
|
}
|
||||||
|
|
||||||
|
building_dic['bldg:storeysAboveGround'] = building.storeys_above_ground
|
||||||
|
if building.lod == 1:
|
||||||
|
building_dic = EnergyAde._lod1(building, building_dic, city)
|
||||||
|
elif building.lod == 2:
|
||||||
|
building_dic = EnergyAde._lod2(building, building_dic, city)
|
||||||
|
else:
|
||||||
|
raise NotImplementedError('Only lod 1 and 2 can be exported')
|
||||||
|
return building_dic
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _lod1(building, building_dic, city):
|
||||||
|
raise NotImplementedError('Only lod 1 and 2 can be exported')
|
||||||
|
@staticmethod
|
||||||
|
def _lod2(building, building_dic, city):
|
||||||
|
surface_members = []
|
||||||
|
boundaries = [{
|
||||||
|
'gml:Envelope': {
|
||||||
|
'@srsName': city.srs_name,
|
||||||
|
'@srsDimension': 3,
|
||||||
|
'gml:lowerCorner': ' '.join([str(e) for e in city.lower_corner]),
|
||||||
|
'gml:upperCorner': ' '.join([str(e) for e in city.upper_corner])
|
||||||
|
}}]
|
||||||
|
for surface in building.surfaces:
|
||||||
|
surface_member = { '@xlink:href': f'#PolyId{surface.name}'}
|
||||||
|
surface_members.append(surface_member)
|
||||||
|
if surface.type == 'Wall':
|
||||||
|
surface_type = 'bldg:WallSurface'
|
||||||
|
elif surface.type == 'Ground':
|
||||||
|
surface_type = 'bldg:GroundSurface'
|
||||||
|
else:
|
||||||
|
surface_type = 'bldg:RoofSurface'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
surface_dic = {
|
||||||
|
surface_type: {
|
||||||
|
'@gml:id': f'GML_{uuid.uuid4()}',
|
||||||
|
'gml:name': f'{surface.name} ({surface.type})',
|
||||||
|
'gml:boundedBy': {
|
||||||
|
'gml:Envelope': {
|
||||||
|
'@srsName': city.srs_name,
|
||||||
|
'gml:lowerCorner': f'{surface.min_x} {surface.min_y} {surface.min_z}',
|
||||||
|
'gml:upperCorner': f'{surface.max_x} {surface.max_y} {surface.max_z}'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'bldg:lod2MultiSurface': {
|
||||||
|
'gml:MultiSurface': {
|
||||||
|
'@srsName': city.srs_name,
|
||||||
|
'@gml:id': f'GML_{uuid.uuid4()}',
|
||||||
|
'surfaceMember': {
|
||||||
|
'gml:Polygon': {
|
||||||
|
'@srsName': city.srs_name,
|
||||||
|
'@gml:id': f'#PolyId{surface.name}',
|
||||||
|
'gml:exterior': {
|
||||||
|
'gml:LinearRing': {
|
||||||
|
'@gml:id': f'#PolyId{surface.name}_0',
|
||||||
|
'gml:posList': {
|
||||||
|
'@srsDimension': '3',
|
||||||
|
'@count': len(surface.points_list) + 1,
|
||||||
|
'#text': f'{" ".join(map(str, surface.points_list))} {" ".join(map(str, surface.points[0]))}'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print(surface_dic)
|
||||||
|
boundaries.append(surface_dic)
|
||||||
|
print(surface_dic)
|
||||||
|
building_dic['bldg:lod2Solid'] = {
|
||||||
|
'gml:Solid': {
|
||||||
|
'@gml:id': f'GML_{uuid.uuid4()}',
|
||||||
|
'gml:exterior': {
|
||||||
|
'gml:CompositeSurface': {
|
||||||
|
'@srsName': city.srs_name,
|
||||||
|
'@gml:id': f'GML_{uuid.uuid4()}',
|
||||||
|
'gml:surfaceMember': surface_members
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
building_dic['gml:boundedBy'] = boundaries
|
||||||
|
print(building_dic)
|
||||||
|
return building_dic
|
|
@ -9,4 +9,4 @@ from exports.formats.triangular import Triangular
|
||||||
|
|
||||||
class Stl(Triangular):
|
class Stl(Triangular):
|
||||||
def __init__(self, city, path):
|
def __init__(self, city, path):
|
||||||
super().__init__(city, path, 'stl')
|
super().__init__(city, path, 'stl', write_mode='wb')
|
||||||
|
|
|
@ -8,20 +8,22 @@ from trimesh import Trimesh
|
||||||
|
|
||||||
|
|
||||||
class Triangular:
|
class Triangular:
|
||||||
def __init__(self, city, path, triangular_format):
|
def __init__(self, city, path, triangular_format, write_mode='w'):
|
||||||
self._city = city
|
self._city = city
|
||||||
self._path = path
|
self._path = path
|
||||||
self._triangular_format = triangular_format
|
self._triangular_format = triangular_format
|
||||||
|
self._write_mode = write_mode
|
||||||
self._export()
|
self._export()
|
||||||
|
|
||||||
|
|
||||||
def _export(self):
|
def _export(self):
|
||||||
if self._city.name is None:
|
if self._city.name is None:
|
||||||
self._city.name = 'unknown_city'
|
self._city.name = 'unknown_city'
|
||||||
file_name = self._city.name + '.' + self._triangular_format
|
file_name = self._city.name + '.' + self._triangular_format
|
||||||
file_path = (Path(self._path).resolve() / file_name).resolve()
|
file_path = (Path(self._path).resolve() / file_name).resolve()
|
||||||
print(file_path)
|
|
||||||
trimesh = Trimesh()
|
trimesh = Trimesh()
|
||||||
for building in self._city.buildings:
|
for building in self._city.buildings:
|
||||||
trimesh = trimesh.union(building.simplified_polyhedron.trimesh)
|
trimesh = trimesh.union(building.simplified_polyhedron.trimesh)
|
||||||
with open(file_path, 'w') as file:
|
|
||||||
|
with open(file_path, self._write_mode) as file:
|
||||||
file.write(trimesh.export(file_type=self._triangular_format))
|
file.write(trimesh.export(file_type=self._triangular_format))
|
||||||
|
|
|
@ -6,6 +6,7 @@ Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@conc
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
|
from imports.geometry_factory import GeometryFactory
|
||||||
from exports.exports_factory import ExportsFactory
|
from exports.exports_factory import ExportsFactory
|
||||||
from city_model_structure.city import City
|
from city_model_structure.city import City
|
||||||
|
|
||||||
|
@ -25,7 +26,7 @@ class TestExports(TestCase):
|
||||||
|
|
||||||
def _get_city(self):
|
def _get_city(self):
|
||||||
if self._city_gml is None:
|
if self._city_gml is None:
|
||||||
file_path = (self._example_path / 'kelowna.pickle').resolve()
|
file_path = (self._example_path / 'one_building_in_kelowna.pickle').resolve()
|
||||||
self._city_gml = City.load(file_path)
|
self._city_gml = City.load(file_path)
|
||||||
return self._city_gml
|
return self._city_gml
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user