diff --git a/city_model_structure/monthly_to_hourly_demand.py b/city_model_structure/monthly_to_hourly_demand.py index 2773c018..ea6d9b21 100644 --- a/city_model_structure/monthly_to_hourly_demand.py +++ b/city_model_structure/monthly_to_hourly_demand.py @@ -31,6 +31,9 @@ class MonthlyToHourlyDemand: for usage_zone in self._building.usage_zones: temp_set = float(usage_zone.heating_setpoint)-3 temp_back = float(usage_zone.heating_setback)-3 + # todo: if these are data frames, then they should be called as (Occupancy should be in low case): + # usage_zone.schedules.Occupancy + # self._conditioning_seasons.heating occupancy = Occupants().get_complete_year_schedule(usage_zone.schedules['Occupancy']) heating_schedule = self._conditioning_seasons['heating'] @@ -65,7 +68,8 @@ class MonthlyToHourlyDemand: for day in range(1, month_range[1] + 1): for hour in range(0, 24): -# monthly_demand = self._building.heating[cte.MONTH]['INSEL'][month-1] +# monthly_demand = self._building.heating[cte.MONTH]['INSEL'][month-1] or maybe: +# monthly_demand = self._building.heating[cte.MONTH].INSEL[month-1] monthly_demand = self._building.heating[cte.MONTH][month-1] if monthly_demand == 'NaN': monthly_demand = 0 diff --git a/exports/formats/obj.py b/exports/formats/obj.py index 45648fef..12ee1942 100644 --- a/exports/formats/obj.py +++ b/exports/formats/obj.py @@ -9,7 +9,6 @@ from exports.formats.triangular import Triangular from pathlib import Path from imports.geometry_factory import GeometryFactory import trimesh.exchange.obj -from trimesh import Trimesh class Obj(Triangular): diff --git a/exports/formats/simplified_radiosity_algorithm.py b/exports/formats/simplified_radiosity_algorithm.py index ebb2c238..562e3348 100644 --- a/exports/formats/simplified_radiosity_algorithm.py +++ b/exports/formats/simplified_radiosity_algorithm.py @@ -47,9 +47,9 @@ class SimplifiedRadiosityAlgorithm: '@y': f'{point[1]}', '@z': f'{point[2]}' } - if surface.type == 'WallSurface': + if surface.type == 'Wall': walls.append(surface_dict) - elif surface.type == 'RoofSurface': + elif surface.type == 'Roof': roofs.append(surface_dict) else: floors.append(surface_dict) diff --git a/helpers/geometry_helper.py b/helpers/geometry_helper.py index 317b4427..30a8ddf2 100644 --- a/helpers/geometry_helper.py +++ b/helpers/geometry_helper.py @@ -160,15 +160,6 @@ class GeometryHelper: return [trimesh_1, trimesh_2] - @staticmethod - def gml_surface_to_libs(surface): - if surface == 'WallSurface': - return 'Wall' - elif surface == 'GroundSurface': - return 'Ground' - else: - return 'Roof' - @staticmethod def get_location(latitude, longitude): url = 'https://nominatim.openstreetmap.org/reverse?lat={latitude}&lon={longitude}&format=json' diff --git a/imports/constructions/helpers/construction_helper.py b/imports/constructions/helpers/construction_helper.py index ae0195d9..2863f55a 100644 --- a/imports/constructions/helpers/construction_helper.py +++ b/imports/constructions/helpers/construction_helper.py @@ -78,12 +78,12 @@ class ConstructionHelper: nrcan_window_types = ['window'] # todo: review with the same idea, to define a internal set and do the conversion to NREL nrcan_construction_types = { - 'WallSurface': 'wall', + 'Wall': 'wall', 'ground wall': 'basement_wall', - 'GroundSurface': 'floor', + 'Ground': 'floor', 'attic floor': 'attic floor', 'interior slab': 'interior slab', - 'RoofSurface': 'roof' + 'Roof': 'roof' } @staticmethod diff --git a/imports/geometry/citygml.py b/imports/geometry/citygml.py index 9c915f29..b051988f 100644 --- a/imports/geometry/citygml.py +++ b/imports/geometry/citygml.py @@ -8,10 +8,9 @@ import xmltodict from city_model_structure.city import City from city_model_structure.building import Building -from helpers.geometry_helper import GeometryHelper +from city_model_structure.attributes.surface import Surface +from imports.geometry.helpers.geometry_helper import GeometryHelper from city_model_structure.attributes.polygon import Polygon -from imports.geometry.citygml_lod2 import CityGmlLod2 -from imports.geometry.citygml_lod1 import CityGmlLod1 class CityGml: @@ -44,7 +43,6 @@ class CityGml: 'http://www.opengis.net/citygml/2.0': None }, force_list=('cityObjectMember', 'curveMember', 'boundedBy', 'surfaceMember')) self._city_objects = None - self._geometry = GeometryHelper() for bound in self._gml['CityModel']['boundedBy']: envelope = bound['Envelope'] if '#text' in envelope['lowerCorner']: @@ -74,29 +72,27 @@ class CityGml: # todo: refactor this method to clearly choose the gml type self._city = City(self._lower_corner, self._upper_corner, self._srs_name) i = 0 + building_part = None for o in self._gml['CityModel']['cityObjectMember']: i += 1 lod = 0 surfaces = [] if 'lod1Solid' in o['Building']: lod += 1 - surfaces = CityGmlLod1.lod1_solid(o) + surfaces = CityGml._lod1_solid(o) elif 'lod1MultiSurface' in o['Building']: lod += 1 - surfaces = CityGmlLod1.lod1_multi_surface(o) - elif 'lod2Solid' in o['Building']: - lod += 1 - surfaces = CityGmlLod2.lod2_solid(o) + surfaces = CityGml._lod1_multi_surface(o) elif 'lod2MultiSurface' in o['Building']: # todo: check if this is a real case or a miss-formed citygml lod = 2 - surfaces = surfaces + CityGmlLod2.lod2_solid_multi_surface(o) + surfaces = surfaces + CityGml._lod2_solid_multi_surface(o) else: for bound in o['Building']['boundedBy']: surface_type = next(iter(bound)) if 'lod2MultiSurface' in bound[surface_type]: lod = 2 - surfaces = surfaces + CityGmlLod2.lod2(bound) + surfaces = surfaces + CityGml._lod2(bound) if 'lod3Solid' in o['Building']: lod += 4 if 'lod4Solid' in o['Building']: @@ -109,11 +105,20 @@ class CityGml: function = None year_of_construction = None - name = o['Building']['@id'] - if 'yearOfConstruction' in o['Building']: - year_of_construction = o['Building']['yearOfConstruction'] - if 'function' in o['Building']: - function = o['Building']['function'] + if 'consistsOfBuildingPart' in o['Building']: + if 'BuildingPart' in o['Building']['consistsOfBuildingPart']: + name = o['Building']['consistsOfBuildingPart']['BuildingPart']['name'] + if 'yearOfConstruction' in o['Building']['consistsOfBuildingPart']['BuildingPart']: + year_of_construction = o['Building']['consistsOfBuildingPart']['BuildingPart']['yearOfConstruction'] + if 'function' in o['Building']['consistsOfBuildingPart']['BuildingPart']: + function = o['Building']['consistsOfBuildingPart']['BuildingPart']['function'] + + else: + name = o['Building']['@id'] + if 'yearOfConstruction' in o['Building']: + year_of_construction = o['Building']['yearOfConstruction'] + if 'function' in o['Building']: + function = o['Building']['function'] self._city.add_city_object(Building(name, lod, surfaces, year_of_construction, function, self._lower_corner, terrains)) return self._city @@ -128,10 +133,88 @@ class CityGml: terrains = [] for curve in curves: curve_points = np.fromstring(curve, dtype=float, sep=' ') - curve_points = self._geometry.to_points_matrix(curve_points) + curve_points = GeometryHelper.to_points_matrix(curve_points) terrains.append(curve_points) return terrains + @staticmethod + def _lod1_solid(o): + try: + solid_points = [CityGml._solid_points(CityGml._remove_last_point(s['Polygon']['exterior']['LinearRing']['posList']['#text'])) + for s in o['Building']['lod1Solid']['Solid']['exterior']['CompositeSurface']['surfaceMember']] + except TypeError: + solid_points = [CityGml._solid_points(CityGml._remove_last_point(s['Polygon']['exterior']['LinearRing']['posList'])) + for s in o['Building']['lod1Solid']['Solid']['exterior']['CompositeSurface']['surfaceMember']] + + return [Surface(Polygon(sp),Polygon(sp)) for sp in solid_points] + + @staticmethod + def _lod1_multi_surface(o): + solid_points = [CityGml._solid_points(CityGml._remove_last_point(s['Polygon']['exterior']['LinearRing']['posList'])) + for s in o['Building']['lod1MultiSurface']['MultiSurface']['surfaceMember']] + return [Surface(Polygon(sp),Polygon(sp)) for sp in solid_points] + + @staticmethod + def _lod2_solid_multi_surface(o): + if 'boundedBy' in o['Building']['consistsOfBuildingPart']['BuildingPart']: + if 'RoofSurface' in o['Building']['consistsOfBuildingPart']['BuildingPart']['boundedBy']: + if o['Building']['consistsOfBuildingPart']['BuildingPart']['boundedBy']['RoofSurface']['lod2MultiSurface'] != 'None': + polygons = [Polygon(CityGml._remove_last_point(s['Polygon']['exterior']['LinearRing']['posList'])) + for s in o['Building']['consistsOfBuildingPart']['BuildingPart']['boundedBy']['RoofSurface']['lod2MultiSurface']['MultiSurface']['surfaceMember']] + + elif 'WallSurface' in o['Building']['consistsOfBuildingPart']['BuildingPart']['boundedBy']: + if o['Building']['consistsOfBuildingPart']['BuildingPart']['boundedBy']['WallSurface']['lod2MultiSurface'] != 'None': + polygons = [Polygon(CityGml._remove_last_point(s['Polygon']['exterior']['LinearRing']['posList'])) + for s in o['Building']['consistsOfBuildingPart']['BuildingPart']['boundedBy']['WallSurface']['lod2MultiSurface']['MultiSurface']['surfaceMember']] + else: + polygons = [Polygon(CityGml._remove_last_point(s['Polygon']['exterior']['LinearRing']['posList'])) + for s in o['Building']['lod2MultiSurface']['MultiSurface']['surfaceMember']] + return [Surface(p, p) for p in polygons] + + @staticmethod + def _lod2_composite_surface(s): + solid_points = [CityGml._solid_points((CityGml._remove_last_point(sm['Polygon']['exterior']['LinearRing']['posList']))) + for sm in s['CompositeSurface']['surfaceMember']] + return [Surface(Polygon(sp), Polygon(sp)) for sp in solid_points] + + @staticmethod + def _lod2_multi_surface(s, surface_type): + # todo: this need to be changed into surface bounded? + try: + solid_points = [CityGml._solid_points(CityGml._remove_last_point(s['Polygon']['exterior']['LinearRing']['posList'] + ['#text']))] + except TypeError: + solid_points = [CityGml._solid_points(CityGml._remove_last_point(s['Polygon']['exterior']['LinearRing'] + ['posList']))] + return [Surface(Polygon(sp), Polygon(sp), surface_type=GeometryHelper.gml_surface_to_libs(surface_type)) for sp in solid_points] + + @staticmethod + def _lod2(bound): + surfaces = [] + for surface_type in iter(bound): + for s in bound[surface_type]['lod2MultiSurface']['MultiSurface']['surfaceMember']: + if 'CompositeSurface' in s: + surfaces = surfaces + CityGml._lod2_composite_surface(s) + else: + surfaces = surfaces + CityGml._lod2_multi_surface(s, surface_type) + return surfaces + + @staticmethod + def _remove_last_point(points): + array = points.split(' ') + res = " " + return res.join(array[0:len(array) - 3]) + + @staticmethod + def _solid_points(coordinates) -> np.ndarray: + """ + Solid surface point matrix [[x, y, z],[x, y, z],...] + :parameter coordinates: string from file + :return: np.ndarray + """ + solid_points = np.fromstring(coordinates, dtype=float, sep=' ') + solid_points = GeometryHelper.to_points_matrix(solid_points) + return solid_points @staticmethod def _holes_points(holes_coordinates) -> [np.ndarray]: @@ -173,7 +256,7 @@ class CityGml: for point in perimeter_points: duplicated_point = False for p in pv: - if GeometryHelper().almost_equal(0.0, p, point): + if GeometryHelper.almost_equal(0.0, p, point): duplicated_point = True if not duplicated_point: pv = np.append(pv, [point], axis=0) diff --git a/imports/geometry/helpers/geometry_helper.py b/imports/geometry/helpers/geometry_helper.py index 6d5995c2..5db04968 100644 --- a/imports/geometry/helpers/geometry_helper.py +++ b/imports/geometry/helpers/geometry_helper.py @@ -314,4 +314,13 @@ class GeometryHelper: :return: Boolean """ delta = self.distance_between_points(v1, v2) - return delta <= delta_max \ No newline at end of file + return delta <= delta_max + + @staticmethod + def gml_surface_to_libs(surface): + if surface == 'WallSurface': + return 'Wall' + elif surface == 'GroundSurface': + return 'Ground' + else: + return 'Roof' diff --git a/imports/usage_factory.py b/imports/usage_factory.py index 5cbf77e8..90e708b3 100644 --- a/imports/usage_factory.py +++ b/imports/usage_factory.py @@ -11,7 +11,7 @@ class UsageFactory: """ UsageFactory class """ - def __init__(self, handler, city, base_path=Path(Path(__file__).parent.parent / 'data/usages')): + def __init__(self, handler, city, base_path=Path(Path(__file__).parent.parent / 'data/usage')): self._handler = '_' + handler.lower().replace(' ', '_') self._city = city self._base_path = base_path diff --git a/non_functional_tests/test_sensors_factory.py b/non_functional_tests/test_sensors_factory.py index a309e0d1..378db55c 100644 --- a/non_functional_tests/test_sensors_factory.py +++ b/non_functional_tests/test_sensors_factory.py @@ -23,7 +23,8 @@ class TestSensorsFactory(TestCase): :return: """ self._city = TestSensorsFactory._mockup_city() - self._end_point = (Path(__file__).parent / 'tests_data/EV-GM energy demand weekly report_01-26-20_04-30.csv').resolve() + self._end_point = (Path(__file__).parent / + 'tests_data/EV-GM energy demand weekly report_01-26-20_04-30.csv').resolve() @staticmethod def _mockup_city(): @@ -55,4 +56,3 @@ class TestSensorsFactory(TestCase): sensor.add_period(update) row = sensor.measures.loc[sensor.measures["Date time"] == '2020-01-19 23:55:00']['Energy consumption'].iloc[0] self.assertTrue(f'{row}' == '12345.0') -