Rollback behnam changes and add sra export to the export factory
This commit is contained in:
parent
dcf23c239b
commit
bfd4868005
|
@ -42,6 +42,13 @@ class Surface:
|
||||||
self._name = uuid.uuid4()
|
self._name = uuid.uuid4()
|
||||||
return self._name
|
return self._name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def id(self):
|
||||||
|
"""
|
||||||
|
Surface id
|
||||||
|
:return str
|
||||||
|
"""
|
||||||
|
return str(self.name)[:8]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def swr(self):
|
def swr(self):
|
||||||
|
|
|
@ -14,6 +14,7 @@ from pyproj import Transformer
|
||||||
from city_model_structure.building import Building
|
from city_model_structure.building import Building
|
||||||
from city_model_structure.city_object import CityObject
|
from city_model_structure.city_object import CityObject
|
||||||
from helpers.geometry_helper import GeometryHelper
|
from helpers.geometry_helper import GeometryHelper
|
||||||
|
from helpers.location import Location
|
||||||
import math
|
import math
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,9 +33,11 @@ class City:
|
||||||
# todo: right now extracted at city level, in the future should be extracted also at building level if exist
|
# todo: right now extracted at city level, in the future should be extracted also at building level if exist
|
||||||
self._location = None
|
self._location = None
|
||||||
self._country_code = None
|
self._country_code = None
|
||||||
|
self._climate_reference_city = None
|
||||||
|
self._climate_file = None
|
||||||
|
|
||||||
@property
|
|
||||||
def _get_location(self):
|
def _get_location(self) -> Location:
|
||||||
if self._location is None:
|
if self._location is None:
|
||||||
gps = pyproj.CRS('EPSG:4326') # LatLon with WGS84 datum used by GPS units and Google Earth
|
gps = pyproj.CRS('EPSG:4326') # LatLon with WGS84 datum used by GPS units and Google Earth
|
||||||
try:
|
try:
|
||||||
|
@ -54,7 +57,7 @@ class City:
|
||||||
City country code
|
City country code
|
||||||
:return: str
|
:return: str
|
||||||
"""
|
"""
|
||||||
return self._get_location[0]
|
return self._get_location().city
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
|
@ -62,7 +65,23 @@ class City:
|
||||||
City name
|
City name
|
||||||
:return: str
|
:return: str
|
||||||
"""
|
"""
|
||||||
return self._get_location[1]
|
return self._get_location().city
|
||||||
|
|
||||||
|
@property
|
||||||
|
def climate_reference_city(self):
|
||||||
|
return self._climate_reference_city
|
||||||
|
|
||||||
|
@climate_reference_city.setter
|
||||||
|
def climate_reference_city(self, value):
|
||||||
|
self._climate_reference_city = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def climate_file(self):
|
||||||
|
return self._climate_file
|
||||||
|
|
||||||
|
@climate_file.setter
|
||||||
|
def climate_file(self, value):
|
||||||
|
self._climate_file = value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def city_objects(self) -> Union[List[CityObject], None]:
|
def city_objects(self) -> Union[List[CityObject], None]:
|
||||||
|
|
|
@ -7,6 +7,7 @@ Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@conc
|
||||||
from exports.formats.stl import Stl
|
from exports.formats.stl import Stl
|
||||||
from exports.formats.obj import Obj
|
from exports.formats.obj import Obj
|
||||||
from exports.formats.energy_ade import EnergyAde
|
from exports.formats.energy_ade import EnergyAde
|
||||||
|
from exports.formats.simplified_radiosity_algorithm import SimplifiedRadiosityAlgorithm
|
||||||
|
|
||||||
|
|
||||||
class ExportsFactory:
|
class ExportsFactory:
|
||||||
|
@ -44,6 +45,14 @@ class ExportsFactory:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _obj(self):
|
def _obj(self):
|
||||||
|
"""
|
||||||
|
Export the city geometry to obj
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
return Obj(self._city, self._path)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _grounded_obj(self):
|
||||||
"""
|
"""
|
||||||
Export the city geometry to obj
|
Export the city geometry to obj
|
||||||
:return: None
|
:return: None
|
||||||
|
@ -58,6 +67,10 @@ class ExportsFactory:
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _sra(self):
|
||||||
|
return SimplifiedRadiosityAlgorithm(self._city, (self._path/ f'{self._city.name}_sra.xml'))
|
||||||
|
|
||||||
def export(self):
|
def export(self):
|
||||||
"""
|
"""
|
||||||
Export the city model structure to the given export type
|
Export the city model structure to the given export type
|
||||||
|
|
83
exports/formats/simplified_radiosity_algorithm.py
Normal file
83
exports/formats/simplified_radiosity_algorithm.py
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
"""
|
||||||
|
Simplified Radiosity Algorithm
|
||||||
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
|
Copyright © 2020 Project Author Guillermo.GutierrezMorote@concordia.ca
|
||||||
|
"""
|
||||||
|
from pathlib import Path
|
||||||
|
import xmltodict
|
||||||
|
|
||||||
|
class SimplifiedRadiosityAlgorithm:
|
||||||
|
|
||||||
|
def __init__(self, city, file_name, begin_month=1, begin_day=1, end_month=12, end_day=31):
|
||||||
|
self._file_name = file_name
|
||||||
|
self._begin_month = begin_month
|
||||||
|
self._begin_day = begin_day
|
||||||
|
self._end_month = end_month
|
||||||
|
self._end_day = end_day
|
||||||
|
self._city = city
|
||||||
|
self._export()
|
||||||
|
|
||||||
|
def _correct_point(self, point):
|
||||||
|
# correct the x, y, z values into the reference frame set by city lower_corner
|
||||||
|
x = point[0] - self._city.lower_corner[0]
|
||||||
|
y = point[1] - self._city.lower_corner[1]
|
||||||
|
z = point[2] - self._city.lower_corner[2]
|
||||||
|
return [x, y, z]
|
||||||
|
|
||||||
|
def _export(self):
|
||||||
|
print('export')
|
||||||
|
buildings = []
|
||||||
|
for building_index, building in enumerate(self._city.buildings):
|
||||||
|
building_dict = {
|
||||||
|
'@Name': f'{building.name}',
|
||||||
|
'@id': f'{building_index}',
|
||||||
|
'@key': f'{building.name}',
|
||||||
|
'@Simulate': 'True'
|
||||||
|
}
|
||||||
|
walls, roofs, floors = [], [], []
|
||||||
|
for surface in building.surfaces:
|
||||||
|
surface_dict = {
|
||||||
|
'@id': f'{surface.id}',
|
||||||
|
'@ShortWaveReflectance': f'{surface.swr}'
|
||||||
|
}
|
||||||
|
for point_index, point in enumerate(surface.perimeter_polygon.points):
|
||||||
|
# todo: check corrected points
|
||||||
|
point = self._correct_point(point)
|
||||||
|
surface_dict[f'V{point_index}'] = {
|
||||||
|
'@x': f'{point[0]}',
|
||||||
|
'@y': f'{point[1]}',
|
||||||
|
'@z': f'{point[2]}'
|
||||||
|
}
|
||||||
|
if surface.type == 'Wall':
|
||||||
|
walls.append(surface_dict)
|
||||||
|
elif surface.type == 'Roof':
|
||||||
|
roofs.append(surface_dict)
|
||||||
|
else:
|
||||||
|
floors.append(surface_dict)
|
||||||
|
building_dict['Wall'] = walls
|
||||||
|
building_dict['Roof'] = roofs
|
||||||
|
building_dict['Floor'] = floors
|
||||||
|
buildings.append(building_dict)
|
||||||
|
sra = {
|
||||||
|
'CitySim': {
|
||||||
|
'@name': f'{self._file_name.name}',
|
||||||
|
'Simulation': {
|
||||||
|
'@beginMonth': f'{self._begin_month}',
|
||||||
|
'@beginDay': f'{self._begin_day}',
|
||||||
|
'@endMonth': f'{self._end_month}',
|
||||||
|
'@endDay': f'{self._end_day}',
|
||||||
|
},
|
||||||
|
'Climate': {
|
||||||
|
'@location': f'{self._city.climate_file}',
|
||||||
|
'@city': f'{self._city.climate_reference_city}'
|
||||||
|
},
|
||||||
|
'District': {
|
||||||
|
'FarFieldObstructions': None,
|
||||||
|
'Building': buildings
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
with open(self._file_name, "w") as file:
|
||||||
|
file.write(xmltodict.unparse(sra, pretty=True, short_empty_elements=True))
|
||||||
|
return
|
|
@ -12,6 +12,7 @@ from trimesh import intersections
|
||||||
from helpers.configuration_helper import ConfigurationHelper
|
from helpers.configuration_helper import ConfigurationHelper
|
||||||
from city_model_structure.attributes.polygon import Polygon
|
from city_model_structure.attributes.polygon import Polygon
|
||||||
from city_model_structure.attributes.polyhedron import Polyhedron
|
from city_model_structure.attributes.polyhedron import Polyhedron
|
||||||
|
from helpers.location import Location
|
||||||
|
|
||||||
|
|
||||||
class GeometryHelper:
|
class GeometryHelper:
|
||||||
|
@ -192,12 +193,12 @@ class GeometryHelper:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_location(latitude, longitude):
|
def get_location(latitude, longitude):
|
||||||
url = 'https://nominatim.openstreetmap.org/reverse?lat={latitude}&lon={longitude}&format=json'
|
url = 'https://nominatim.openstreetmap.org/reverse?lat={latitude}&lon={longitude}&format=json'
|
||||||
resp = requests.get(url.format(latitude=latitude, longitude=longitude))
|
response = requests.get(url.format(latitude=latitude, longitude=longitude))
|
||||||
if resp.status_code != 200:
|
if response.status_code != 200:
|
||||||
# This means something went wrong.
|
# This means something went wrong.
|
||||||
raise Exception('GET /tasks/ {}'.format(resp.status_code))
|
raise Exception('GET /tasks/ {}'.format(response.status_code))
|
||||||
else:
|
else:
|
||||||
response = resp.json()
|
response = response.json()
|
||||||
# todo: this is wrong, remove in the future
|
# todo: this is wrong, remove in the future
|
||||||
city = 'new_york_city'
|
city = 'new_york_city'
|
||||||
country = 'us'
|
country = 'us'
|
||||||
|
@ -205,7 +206,7 @@ class GeometryHelper:
|
||||||
city = response['address']['city']
|
city = response['address']['city']
|
||||||
if 'country_code' in response['address']:
|
if 'country_code' in response['address']:
|
||||||
country = response['address']['country_code']
|
country = response['address']['country_code']
|
||||||
return [country, city]
|
return Location(country, city)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def distance_between_points(vertex1, vertex2):
|
def distance_between_points(vertex1, vertex2):
|
||||||
|
|
12
helpers/location.py
Normal file
12
helpers/location.py
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
class Location:
|
||||||
|
def __init__(self, country, city):
|
||||||
|
self._country = country
|
||||||
|
self._city = city
|
||||||
|
|
||||||
|
@property
|
||||||
|
def city(self):
|
||||||
|
return self._city
|
||||||
|
|
||||||
|
@property
|
||||||
|
def country(self):
|
||||||
|
return self._country
|
|
@ -5,13 +5,13 @@ Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@conc
|
||||||
"""
|
"""
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import xmltodict
|
import xmltodict
|
||||||
import time
|
|
||||||
|
|
||||||
from city_model_structure.city import City
|
from city_model_structure.city import City
|
||||||
from city_model_structure.building import Building
|
from city_model_structure.building import Building
|
||||||
from city_model_structure.attributes.surface import Surface
|
from city_model_structure.attributes.surface import Surface
|
||||||
from helpers.geometry_helper import GeometryHelper
|
from helpers.geometry_helper import GeometryHelper
|
||||||
from city_model_structure.attributes.polygon import Polygon
|
from city_model_structure.attributes.polygon import Polygon
|
||||||
|
from city_model_structure.attributes.thermal_zone import ThermalZone
|
||||||
|
|
||||||
|
|
||||||
class CityGml:
|
class CityGml:
|
||||||
|
@ -70,51 +70,48 @@ class CityGml:
|
||||||
City model structure enriched with the geometry information
|
City model structure enriched with the geometry information
|
||||||
:return: City
|
:return: City
|
||||||
"""
|
"""
|
||||||
init = time.process_time_ns()
|
|
||||||
if self._city is None:
|
if self._city is None:
|
||||||
# todo: refactor this method to clearly choose the gml type
|
# todo: refactor this method to clearly choose the gml type
|
||||||
self._city = City(self._lower_corner, self._upper_corner, self._srs_name)
|
self._city = City(self._lower_corner, self._upper_corner, self._srs_name)
|
||||||
i = 0
|
i = 0
|
||||||
for o in self._gml['CityModel']['cityObjectMember']:
|
for o in self._gml['CityModel']['cityObjectMember']:
|
||||||
gmlbuilding = o['Building']
|
i += 1
|
||||||
for build in gmlbuilding['consistsOfBuildingPart']:
|
lod = 0
|
||||||
buildingpart = build['BuildingPart']
|
surfaces = []
|
||||||
i += 1
|
if 'lod1Solid' in o['Building']:
|
||||||
lod = 0
|
lod += 1
|
||||||
surfaces = []
|
surfaces = CityGml._lod1_solid(o)
|
||||||
if 'lod1Solid' in buildingpart:
|
elif 'lod1MultiSurface' in o['Building']:
|
||||||
lod += 1
|
lod += 1
|
||||||
surfaces = CityGml._lod1_solid(o)
|
surfaces = CityGml._lod1_multi_surface(o)
|
||||||
elif 'lod1MultiSurface' in buildingpart:
|
elif 'lod2MultiSurface' in o['Building']:
|
||||||
lod += 1
|
# todo: check if this is a real case or a miss-formed citygml
|
||||||
surfaces = CityGml._lod1_multi_surface(o)
|
lod = 2
|
||||||
elif 'lod2MultiSurface' in buildingpart:
|
surfaces = surfaces + CityGml._lod2_solid_multi_surface(o)
|
||||||
# todo: check if this is a real case or a miss-formed citygml
|
else:
|
||||||
lod = 2
|
for bound in o['Building']['boundedBy']:
|
||||||
surfaces = surfaces + CityGml._lod2_solid_multi_surface(o)
|
surface_type = next(iter(bound))
|
||||||
else:
|
if 'lod2MultiSurface' in bound[surface_type]:
|
||||||
for bound in buildingpart['boundedBy']:
|
lod = 2
|
||||||
surface_type = next(iter(bound))
|
surfaces = surfaces + CityGml._lod2(bound)
|
||||||
if 'lod2MultiSurface' in bound[surface_type]:
|
if 'lod3Solid' in o['Building']:
|
||||||
lod = 2
|
lod += 4
|
||||||
surfaces = surfaces + CityGml._lod2(bound)
|
if 'lod4Solid' in o['Building']:
|
||||||
if 'lod3Solid' in o['Building']:
|
lod += 8
|
||||||
lod += 4
|
name = o['Building']['@id']
|
||||||
if 'lod4Solid' in o['Building']:
|
lod_terrain_str = 'lod' + str(lod) + 'TerrainIntersection'
|
||||||
lod += 8
|
terrains = []
|
||||||
name = o['Building']['@id']
|
if lod_terrain_str in o['Building']:
|
||||||
lod_terrain_str = 'lod' + str(lod) + 'TerrainIntersection'
|
terrains = self._terrains(o, lod_terrain_str)
|
||||||
terrains = []
|
year_of_construction = None
|
||||||
if lod_terrain_str in o['Building']:
|
function = None
|
||||||
terrains = self._terrains(o, lod_terrain_str)
|
if 'yearOfConstruction' in o['Building']:
|
||||||
year_of_construction = None
|
year_of_construction = o['Building']['yearOfConstruction']
|
||||||
function = None
|
if 'function' in o['Building']:
|
||||||
if 'yearOfConstruction' in buildingpart:
|
function = o['Building']['function']
|
||||||
year_of_construction = buildingpart['yearOfConstruction']
|
building = Building(name, lod, surfaces, year_of_construction, function, self._lower_corner, terrains)
|
||||||
if 'function' in o['Building']:
|
self._city.add_city_object(building)
|
||||||
function = o['Building']['function']
|
|
||||||
self._city.add_city_object(Building(name, lod, surfaces, terrains, year_of_construction, function,
|
|
||||||
self._lower_corner))
|
|
||||||
return self._city
|
return self._city
|
||||||
|
|
||||||
def _terrains(self, city_object, lod_terrain_str):
|
def _terrains(self, city_object, lod_terrain_str):
|
||||||
|
@ -150,10 +147,8 @@ class CityGml:
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _lod2_solid_multi_surface(o):
|
def _lod2_solid_multi_surface(o):
|
||||||
for i in buildingpart['boundedBy']:
|
|
||||||
surfacedata = i
|
|
||||||
polygons = [Polygon(CityGml._remove_last_point(s['Polygon']['exterior']['LinearRing']['posList']))
|
polygons = [Polygon(CityGml._remove_last_point(s['Polygon']['exterior']['LinearRing']['posList']))
|
||||||
for s in surfacedata['OuterCeilingSurface']['lod2MultiSurface']['MultiSurface']['surfaceMember']]
|
for s in o['Building']['lod2MultiSurface']['MultiSurface']['surfaceMember']]
|
||||||
return [Surface(p,p) for p in polygons]
|
return [Surface(p,p) for p in polygons]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -181,7 +176,7 @@ class CityGml:
|
||||||
if 'CompositeSurface' in s:
|
if 'CompositeSurface' in s:
|
||||||
surfaces = surfaces + CityGml._lod2_composite_surface(s)
|
surfaces = surfaces + CityGml._lod2_composite_surface(s)
|
||||||
else:
|
else:
|
||||||
surfaces = surfaces + CityGml._lod2_multi_surface(s, surface_type)
|
surfaces = surfaces + CityGml._lod2_multi_surface(s, GeometryHelper.gml_surface_to_libs(surface_type))
|
||||||
return surfaces
|
return surfaces
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
|
@ -35,6 +35,9 @@ class TestExports(TestCase):
|
||||||
PhysicsFactory('ca', self._city_gml).enrich()
|
PhysicsFactory('ca', self._city_gml).enrich()
|
||||||
UsageFactory('ca', self._city_gml).enrich()
|
UsageFactory('ca', self._city_gml).enrich()
|
||||||
SchedulesFactory('comnet', self._city_gml).enrich()
|
SchedulesFactory('comnet', self._city_gml).enrich()
|
||||||
|
cli = 'C:\\Users\\Pilar\\PycharmProjects\\monthlyenergybalance\\tests_data\\weather\\inseldb_Summerland.cli'
|
||||||
|
self._city_gml.climate_file = Path(cli)
|
||||||
|
self._city_gml.climate_reference_city = 'Summerland'
|
||||||
for building in self._city_gml.buildings:
|
for building in self._city_gml.buildings:
|
||||||
building.heating['month'] = pd.DataFrame({'INSEL': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]})
|
building.heating['month'] = pd.DataFrame({'INSEL': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]})
|
||||||
building.cooling['month'] = pd.DataFrame({'INSEL': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]})
|
building.cooling['month'] = pd.DataFrame({'INSEL': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]})
|
||||||
|
@ -54,3 +57,6 @@ class TestExports(TestCase):
|
||||||
|
|
||||||
def test_energy_ade_export(self):
|
def test_energy_ade_export(self):
|
||||||
self._export('energy_ade')
|
self._export('energy_ade')
|
||||||
|
|
||||||
|
def test_sra_export(self):
|
||||||
|
self._export('sra')
|
Loading…
Reference in New Issue
Block a user