From fc2add511aa23162680eb3dfd82a118c868d49d5 Mon Sep 17 00:00:00 2001 From: guille Date: Wed, 8 Mar 2023 14:24:48 -0500 Subject: [PATCH 1/6] Complete neighbours detection (with shared lines) --- hub/helpers/geometry_helper.py | 67 ++++++++++++++++++++------ hub/unittests/test_geometry_factory.py | 16 ++++-- 2 files changed, 65 insertions(+), 18 deletions(-) diff --git a/hub/helpers/geometry_helper.py b/hub/helpers/geometry_helper.py index e734e254..54428937 100644 --- a/hub/helpers/geometry_helper.py +++ b/hub/helpers/geometry_helper.py @@ -5,6 +5,7 @@ Copyright © 2022 Concordia CERC group Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca """ +import datetime import math import numpy as np import requests @@ -63,7 +64,7 @@ class GeometryHelper: return MapPoint(((city.upper_corner[0] - coordinate[0]) * 0.5), ((city.upper_corner[1] - coordinate[1]) * 0.5)) @staticmethod - def city_mapping(city, building_names=None, plot=False): + def city_mapping(city, building_names=None): """ Returns a shared_information dictionary like @@ -71,17 +72,15 @@ class GeometryHelper: "building_name" : [{line: 0 coordinate_1: [x,y,z], coordinate_2:[x, y, z], points: 0}] } """ - shared_information = {} + lines_information = {} if building_names is None: building_names = [b.name for b in city.buildings] x = int((city.upper_corner[0] - city.lower_corner[0]) * 0.5) + 1 y = int((city.upper_corner[1] - city.lower_corner[1]) * 0.5) + 1 - city_map = [[{} for _ in range(y + 1)] for _ in range(x + 1)] - img = Image.new('RGB', (x + 1, y + 1), "black") # create a new black image - city_image = img.load() # create the pixel map + city_map = [['' for _ in range(y + 1)] for _ in range(x + 1)] + map_info = [[{} for _ in range(y + 1)] for _ in range(x + 1)] for building_name in building_names: building = city.city_object(building_name) - shared_information[building_name]: [] line = 0 for ground in building.grounds: length = len(ground.perimeter_polygon.coordinates) - 1 @@ -90,22 +89,63 @@ class GeometryHelper: if i == length: j = 0 next_coordinate = ground.perimeter_polygon.coordinates[j] - line_dictionary = {"line": line, "coordinate_1": coordinate, "coordinate_2":next_coordinate, "points": 0} - print(building_name, line_dictionary['line']) point = GeometryHelper.coordinate_to_map_point(coordinate, city) - distance = GeometryHelper.distance_between_points(coordinate, next_coordinate) + distance = int(GeometryHelper.distance_between_points(coordinate, next_coordinate)) if distance == 0: continue delta_x = (coordinate[0] - next_coordinate[0]) / (distance / 0.5) delta_y = (coordinate[1] - next_coordinate[1]) / (distance / 0.5) - for k in range(0, int(distance)): + for k in range(0, distance): x = MapPoint(point.x + (delta_x * k), point.y + (delta_y * k)).x y = MapPoint(point.x + (delta_x * k), point.y + (delta_y * k)).y - if city_map[x][y] == {}: + if city_map[x][y] == '': city_map[x][y] = building.name - city_image[x, y] = (100, 0, 0) + map_info[x][y] = { + 'line_start': (coordinate[0], coordinate[1]), + 'line_end': (next_coordinate[0], next_coordinate[1]), + } elif city_map[x][y] != building.name: neighbour = city.city_object(city_map[x][y]) + neighbour_info = map_info[x][y] + + # prepare the keys + neighbour_start_coordinate = f'{neighbour_info["line_start"][0]}_{neighbour_info["line_start"][1]}' + building_start_coordinate = f'{coordinate[0]}_{coordinate[1]}' + neighbour_key = f'{neighbour.name}_{neighbour_start_coordinate}_{building_start_coordinate}' + building_key = f'{building.name}_{building_start_coordinate}_{neighbour_start_coordinate}' + + # Add my neighbour info to my shared lines + if building.name in lines_information.keys() and neighbour_key in lines_information[building.name]: + shared_points = int(lines_information[building.name][neighbour_key]['shared_points']) + lines_information[building.name][neighbour_key]['shared_points'] = shared_points + 1 + else: + if building.name not in lines_information.keys(): + lines_information[building.name] = {} + lines_information[building.name][neighbour_key] = { + 'neighbour_name': neighbour.name, + 'line_start': (coordinate[0], coordinate[1]), + 'line_end': (next_coordinate[0], next_coordinate[1]), + 'neighbour_line_start': neighbour_info['line_start'], + 'neighbour_line_end': neighbour_info['line_end'], + 'shared_points': 1 + } + + # Add my info to my neighbour shared lines + if neighbour.name in lines_information.keys() and building_key in lines_information[neighbour.name]: + shared_points = int(lines_information[neighbour.name][building_key]['shared_points']) + lines_information[neighbour.name][building_key]['shared_points'] = shared_points + 1 + else: + if neighbour.name not in lines_information.keys(): + lines_information[neighbour.name] = {} + lines_information[neighbour.name][building_key] = { + 'neighbour_name': building.name, + 'line_start': neighbour_info['line_start'], + 'line_end': neighbour_info['line_end'], + 'neighbour_line_start': (coordinate[0], coordinate[1]), + 'neighbour_line_end': (next_coordinate[0], next_coordinate[1]), + 'shared_points': 1 + } + if building.neighbours is None: building.neighbours = [neighbour] elif neighbour not in building.neighbours: @@ -115,8 +155,7 @@ class GeometryHelper: elif building not in neighbour.neighbours: neighbour.neighbours.append(building) line += 1 - if plot: - img.show() + return lines_information @staticmethod def segment_list_to_trimesh(lines) -> Trimesh: diff --git a/hub/unittests/test_geometry_factory.py b/hub/unittests/test_geometry_factory.py index a503bc3b..a90c58c8 100644 --- a/hub/unittests/test_geometry_factory.py +++ b/hub/unittests/test_geometry_factory.py @@ -152,10 +152,18 @@ class TestGeometryFactory(TestCase): """ Test neighbours map creation """ - file = 'concordia.geojson' + file = 'neighbours.geojson' city = self._get_city(file, 'geojson', - height_field='citygml_me', year_of_construction_field='ANNEE_CONS', function_field='LIBELLE_UT') - GeometryHelper.city_mapping(city, plot=False) - self.assertTrue(False) + GeometryHelper.city_mapping(city) + for building in city.buildings: + self.assertEqual(2, len(building.neighbours)) + + self.assertEqual('2_part_0_zone0_zone_0',city.city_object('1_part_0_zone0_zone_0').neighbours[0].name) + self.assertEqual('3_part_0_zone0_zone_0',city.city_object('1_part_0_zone0_zone_0').neighbours[1].name) + self.assertEqual('1_part_0_zone0_zone_0',city.city_object('2_part_0_zone0_zone_0').neighbours[0].name) + self.assertEqual('3_part_0_zone0_zone_0',city.city_object('2_part_0_zone0_zone_0').neighbours[1].name) + self.assertEqual('2_part_0_zone0_zone_0', city.city_object('3_part_0_zone0_zone_0').neighbours[0].name) + self.assertEqual('1_part_0_zone0_zone_0', city.city_object('3_part_0_zone0_zone_0').neighbours[1].name) + From bfc3f84c0906a41f72c3114ecb1074a4aff1ff1c Mon Sep 17 00:00:00 2001 From: guille Date: Wed, 8 Mar 2023 14:25:11 -0500 Subject: [PATCH 2/6] Complete neighbours detection (with shared lines) --- hub/unittests/tests_data/neighbours.geojson | 594 ++++++++++++++++++++ 1 file changed, 594 insertions(+) create mode 100644 hub/unittests/tests_data/neighbours.geojson diff --git a/hub/unittests/tests_data/neighbours.geojson b/hub/unittests/tests_data/neighbours.geojson new file mode 100644 index 00000000..65149ee9 --- /dev/null +++ b/hub/unittests/tests_data/neighbours.geojson @@ -0,0 +1,594 @@ +{ + "type":"FeatureCollection", + "features":[ + { + "type":"Feature", + "id":1, + "geometry":{ + "type":"Polygon", + "coordinates":[ + [ + [ + -73.580414175680588, + 45.497641136608358 + ], + [ + -73.581414175680588, + 45.497641136608358 + ], + [ + -73.581414175680588, + 45.498641136608358 + ], + [ + -73.580414175680588, + 45.498641136608358 + ], + [ + -73.580414175680588, + 45.497641136608358 + ] + ] + ] + }, + "properties":{ + "OBJECTID_12":1, + "gml_id":"1340908", + "gml_parent":"fme-gen-5fa2a82b-c38e-4bf0-9e8f-10a47b9f64f7", + "citygml_ta":"http://www.opengis.net/citygml/building/2.0", + "citygml_fe":"cityObjectMember", + "citygml__1":" ", + "citygml__2":" ", + "gml_descri":" ", + "gml_name":" ", + "citygml_cr":" ", + "citygml_te":" ", + "externalRe":" ", + "external_1":" ", + "external_2":" ", + "citygml_ge":" ", + "citygml_re":" ", + "citygml__3":" ", + "citygml_ap":" ", + "citygml_cl":" ", + "citygml__4":" ", + "citygml_fu":" ", + "citygml__5":" ", + "citygml_us":" ", + "citygml__6":" ", + "citygml_ye":" ", + "citygml__7":" ", + "citygml_ro":" ", + "citygml__8":" ", + "citygml_me":21.824000000000002, + "citygml__9":"#m", + "citygml_st":" ", + "citygml_10":" ", + "citygml_11":" ", + "citygml_12":" ", + "citygml_13":" ", + "citygml_14":" ", + "citygml_ou":" ", + "citygml_in":" ", + "citygml_bo":" ", + "citygml_le":" ", + "citygml_15":" ", + "citygml_co":" ", + "citygml_ad":" ", + "Volume":"2783.169", + "parcelle":" ", + "OBJECTID":778, + "gml_id_1":"ebc7f916-d094-4de0-8c35-fc18eb8622f2", + "gml_pare_1":"1340908", + "citygml_16":"http://www.opengis.net/citygml/building/2.0", + "citygml_17":"boundedBy", + "citygml_18":" ", + "citygml_19":" ", + "gml_desc_1":" ", + "gml_name_1":" ", + "citygml_20":" ", + "citygml_21":" ", + "external_3":" ", + "external_4":" ", + "external_5":" ", + "citygml_22":" ", + "citygml_23":" ", + "citygml_24":" ", + "citygml_25":" ", + "citygml_26":" ", + "citygml_op":" ", + "Area":"229.287", + "FID_":0, + "Join_Count":2, + "TARGET_FID":779, + "gml_id_12":"1340908", + "gml_pare_2":"fme-gen-5fa2a82b-c38e-4bf0-9e8f-10a47b9f64f7", + "citygml_27":"http://www.opengis.net/citygml/building/2.0", + "citygml_28":"cityObjectMember", + "citygml_29":" ", + "citygml_30":" ", + "gml_desc_2":" ", + "gml_name_2":" ", + "citygml_31":" ", + "citygml_32":" ", + "external_6":" ", + "external_7":" ", + "external_8":" ", + "citygml_33":" ", + "citygml_34":" ", + "citygml_35":" ", + "citygml_36":" ", + "citygml_37":" ", + "citygml_38":" ", + "citygml_39":" ", + "citygml_40":" ", + "citygml_41":" ", + "citygml_42":" ", + "citygml_43":" ", + "citygml_44":" ", + "citygml_45":" ", + "citygml_46":" ", + "citygml_47":21.824000000000002, + "citygml_48":"#m", + "citygml_49":" ", + "citygml_50":" ", + "citygml_51":" ", + "citygml_52":" ", + "citygml_53":" ", + "citygml_54":" ", + "citygml_55":" ", + "citygml_56":" ", + "citygml_57":" ", + "citygml_58":" ", + "citygml_59":" ", + "citygml_60":" ", + "citygml_61":" ", + "Volume_1":"2783.169", + "Field":0, + "Field1":0, + "OBJECTID_1":778, + "gml_id_12_":"ebc7f916-d094-4de0-8c35-fc18eb8622f2", + "gml_pare_3":"1340908", + "citygml_62":"http://www.opengis.net/citygml/building/2.0", + "citygml_63":"boundedBy", + "citygml_64":" ", + "citygml_65":" ", + "gml_desc_3":" ", + "gml_name_3":" ", + "citygml_66":" ", + "citygml_67":" ", + "external_9":" ", + "externa_10":" ", + "externa_11":" ", + "citygml_68":" ", + "citygml_69":" ", + "citygml_70":" ", + "citygml_71":" ", + "citygml_72":" ", + "citygml_73":" ", + "Area_1":"229.287", + "cityGML_hi":0, + "Z_Min":49.0745, + "Z_Max":69.165000000000006, + "Shape_Leng":59.532834838799999, + "ID_UEV":"01002777", + "CIVIQUE_DE":" 1460", + "CIVIQUE_FI":" 1460", + "NOM_RUE":"rue Sherbrooke Ouest (MTL+MTO+WMT)", + "MUNICIPALI":"50", + "ETAGE_HORS":3, + "NOMBRE_LOG":1, + "ANNEE_CONS":1885, + "CODE_UTILI":"5010", + "LIBELLE_UT":"Immeuble commercial", + "CATEGORIE_":"Régulier", + "MATRICULE8":"9839-57-1941-6-000-0000", + "SUPERFICIE":193, + "SUPERFIC_1":609, + "NO_ARROND_":"REM19", + "Shape_Le_1":0.00076452447366199996, + "Shape_Ar_1":2.2162879886799998e-08, + "Z_Min_1":null, + "Z_Max_1":null, + "Shape_Length":59.532834838827348, + "Shape_Area":161.83671944596372 + } + }, + { + "type":"Feature", + "id":2, + "geometry":{ + "type":"Polygon", + "coordinates":[ + [ + [ + -73.581414175680588, + 45.497641136608358 + ], + [ + -73.582214175680588, + 45.497641136608358 + ], + [ + -73.582214175680588, + 45.498441136608358 + ], + [ + -73.581414175680588, + 45.498441136608358 + ], + [ + -73.581414175680588, + 45.497641136608358 + ] + ] + ] + + }, + "properties":{ + "OBJECTID_12":2, + "gml_id":"1340974", + "gml_parent":"fme-gen-5fa2a82b-c38e-4bf0-9e8f-10a47b9f64f7", + "citygml_ta":"http://www.opengis.net/citygml/building/2.0", + "citygml_fe":"cityObjectMember", + "citygml__1":" ", + "citygml__2":" ", + "gml_descri":" ", + "gml_name":" ", + "citygml_cr":" ", + "citygml_te":" ", + "externalRe":" ", + "external_1":" ", + "external_2":" ", + "citygml_ge":" ", + "citygml_re":" ", + "citygml__3":" ", + "citygml_ap":" ", + "citygml_cl":" ", + "citygml__4":" ", + "citygml_fu":" ", + "citygml__5":" ", + "citygml_us":" ", + "citygml__6":" ", + "citygml_ye":" ", + "citygml__7":" ", + "citygml_ro":" ", + "citygml__8":" ", + "citygml_me":21.643999999999998, + "citygml__9":"#m", + "citygml_st":" ", + "citygml_10":" ", + "citygml_11":" ", + "citygml_12":" ", + "citygml_13":" ", + "citygml_14":" ", + "citygml_ou":" ", + "citygml_in":" ", + "citygml_bo":" ", + "citygml_le":" ", + "citygml_15":" ", + "citygml_co":" ", + "citygml_ad":" ", + "Volume":"8410.522", + "parcelle":" ", + "OBJECTID":779, + "gml_id_1":"96e73b07-262d-43a8-84ce-608133b39f16", + "gml_pare_1":"1340974", + "citygml_16":"http://www.opengis.net/citygml/building/2.0", + "citygml_17":"boundedBy", + "citygml_18":" ", + "citygml_19":" ", + "gml_desc_1":" ", + "gml_name_1":" ", + "citygml_20":" ", + "citygml_21":" ", + "external_3":" ", + "external_4":" ", + "external_5":" ", + "citygml_22":" ", + "citygml_23":" ", + "citygml_24":" ", + "citygml_25":" ", + "citygml_26":" ", + "citygml_op":" ", + "Area":"553.859", + "FID_":0, + "Join_Count":3, + "TARGET_FID":780, + "gml_id_12":"1340974", + "gml_pare_2":"fme-gen-5fa2a82b-c38e-4bf0-9e8f-10a47b9f64f7", + "citygml_27":"http://www.opengis.net/citygml/building/2.0", + "citygml_28":"cityObjectMember", + "citygml_29":" ", + "citygml_30":" ", + "gml_desc_2":" ", + "gml_name_2":" ", + "citygml_31":" ", + "citygml_32":" ", + "external_6":" ", + "external_7":" ", + "external_8":" ", + "citygml_33":" ", + "citygml_34":" ", + "citygml_35":" ", + "citygml_36":" ", + "citygml_37":" ", + "citygml_38":" ", + "citygml_39":" ", + "citygml_40":" ", + "citygml_41":" ", + "citygml_42":" ", + "citygml_43":" ", + "citygml_44":" ", + "citygml_45":" ", + "citygml_46":" ", + "citygml_47":21.643999999999998, + "citygml_48":"#m", + "citygml_49":" ", + "citygml_50":" ", + "citygml_51":" ", + "citygml_52":" ", + "citygml_53":" ", + "citygml_54":" ", + "citygml_55":" ", + "citygml_56":" ", + "citygml_57":" ", + "citygml_58":" ", + "citygml_59":" ", + "citygml_60":" ", + "citygml_61":" ", + "Volume_1":"8410.522", + "Field":0, + "Field1":0, + "OBJECTID_1":779, + "gml_id_12_":"96e73b07-262d-43a8-84ce-608133b39f16", + "gml_pare_3":"1340974", + "citygml_62":"http://www.opengis.net/citygml/building/2.0", + "citygml_63":"boundedBy", + "citygml_64":" ", + "citygml_65":" ", + "gml_desc_3":" ", + "gml_name_3":" ", + "citygml_66":" ", + "citygml_67":" ", + "external_9":" ", + "externa_10":" ", + "externa_11":" ", + "citygml_68":" ", + "citygml_69":" ", + "citygml_70":" ", + "citygml_71":" ", + "citygml_72":" ", + "citygml_73":" ", + "Area_1":"553.859", + "cityGML_hi":0, + "Z_Min":47.817900000000002, + "Z_Max":69.462000000000003, + "Shape_Leng":124.143194192, + "ID_UEV":"01002773", + "CIVIQUE_DE":" 1438", + "CIVIQUE_FI":" 1438", + "NOM_RUE":"rue Sherbrooke Ouest (MTL+MTO+WMT)", + "MUNICIPALI":"50", + "ETAGE_HORS":3, + "NOMBRE_LOG":2, + "ANNEE_CONS":1885, + "CODE_UTILI":"1000", + "LIBELLE_UT":"Logement", + "CATEGORIE_":"Régulier", + "MATRICULE8":"9839-57-4570-0-000-0000", + "SUPERFICIE":249, + "SUPERFIC_1":506, + "NO_ARROND_":"REM19", + "Shape_Le_1":0.00099703639048799998, + "Shape_Ar_1":2.8543276304299999e-08, + "Z_Min_1":null, + "Z_Max_1":null, + "Shape_Length":124.143194192441, + "Shape_Area":464.30094602931189 + } + }, + { + "type":"Feature", + "id":3, + "geometry":{ + "type":"Polygon", + "coordinates":[ + [ + [ + -73.581914175680588, + 45.498441136608358 + ], + [ + -73.581914175680588, + 45.499641136608358 + ], + [ + -73.580914175680588, + 45.499641136608358 + ], + [ + -73.580914175680588, + 45.498641136608358 + ], + [ + -73.581414175680588, + 45.498641136608358 + ], + [ + -73.581414175680588, + 45.498441136608358 + ], + [ + -73.581914175680588, + 45.498441136608358 + ] + + ] + ] + }, + "properties":{ + "OBJECTID_12":3, + "gml_id":"1340910", + "gml_parent":"fme-gen-5fa2a82b-c38e-4bf0-9e8f-10a47b9f64f7", + "citygml_ta":"http://www.opengis.net/citygml/building/2.0", + "citygml_fe":"cityObjectMember", + "citygml__1":" ", + "citygml__2":" ", + "gml_descri":" ", + "gml_name":" ", + "citygml_cr":" ", + "citygml_te":" ", + "externalRe":" ", + "external_1":" ", + "external_2":" ", + "citygml_ge":" ", + "citygml_re":" ", + "citygml__3":" ", + "citygml_ap":" ", + "citygml_cl":" ", + "citygml__4":" ", + "citygml_fu":" ", + "citygml__5":" ", + "citygml_us":" ", + "citygml__6":" ", + "citygml_ye":" ", + "citygml__7":" ", + "citygml_ro":" ", + "citygml__8":" ", + "citygml_me":21.916, + "citygml__9":"#m", + "citygml_st":" ", + "citygml_10":" ", + "citygml_11":" ", + "citygml_12":" ", + "citygml_13":" ", + "citygml_14":" ", + "citygml_ou":" ", + "citygml_in":" ", + "citygml_bo":" ", + "citygml_le":" ", + "citygml_15":" ", + "citygml_co":" ", + "citygml_ad":" ", + "Volume":"2257.436", + "parcelle":" ", + "OBJECTID":780, + "gml_id_1":"8222a1c7-e161-421a-8478-22d2a116e0b4", + "gml_pare_1":"1340910", + "citygml_16":"http://www.opengis.net/citygml/building/2.0", + "citygml_17":"boundedBy", + "citygml_18":" ", + "citygml_19":" ", + "gml_desc_1":" ", + "gml_name_1":" ", + "citygml_20":" ", + "citygml_21":" ", + "external_3":" ", + "external_4":" ", + "external_5":" ", + "citygml_22":" ", + "citygml_23":" ", + "citygml_24":" ", + "citygml_25":" ", + "citygml_26":" ", + "citygml_op":" ", + "Area":"144.697", + "FID_":0, + "Join_Count":2, + "TARGET_FID":781, + "gml_id_12":"1340910", + "gml_pare_2":"fme-gen-5fa2a82b-c38e-4bf0-9e8f-10a47b9f64f7", + "citygml_27":"http://www.opengis.net/citygml/building/2.0", + "citygml_28":"cityObjectMember", + "citygml_29":" ", + "citygml_30":" ", + "gml_desc_2":" ", + "gml_name_2":" ", + "citygml_31":" ", + "citygml_32":" ", + "external_6":" ", + "external_7":" ", + "external_8":" ", + "citygml_33":" ", + "citygml_34":" ", + "citygml_35":" ", + "citygml_36":" ", + "citygml_37":" ", + "citygml_38":" ", + "citygml_39":" ", + "citygml_40":" ", + "citygml_41":" ", + "citygml_42":" ", + "citygml_43":" ", + "citygml_44":" ", + "citygml_45":" ", + "citygml_46":" ", + "citygml_47":21.916, + "citygml_48":"#m", + "citygml_49":" ", + "citygml_50":" ", + "citygml_51":" ", + "citygml_52":" ", + "citygml_53":" ", + "citygml_54":" ", + "citygml_55":" ", + "citygml_56":" ", + "citygml_57":" ", + "citygml_58":" ", + "citygml_59":" ", + "citygml_60":" ", + "citygml_61":" ", + "Volume_1":"2257.436", + "Field":0, + "Field1":0, + "OBJECTID_1":780, + "gml_id_12_":"8222a1c7-e161-421a-8478-22d2a116e0b4", + "gml_pare_3":"1340910", + "citygml_62":"http://www.opengis.net/citygml/building/2.0", + "citygml_63":"boundedBy", + "citygml_64":" ", + "citygml_65":" ", + "gml_desc_3":" ", + "gml_name_3":" ", + "citygml_66":" ", + "citygml_67":" ", + "external_9":" ", + "externa_10":" ", + "externa_11":" ", + "citygml_68":" ", + "citygml_69":" ", + "citygml_70":" ", + "citygml_71":" ", + "citygml_72":" ", + "citygml_73":" ", + "Area_1":"144.697", + "cityGML_hi":0, + "Z_Min":48.983400000000003, + "Z_Max":67.617000000000004, + "Shape_Leng":52.283656634099998, + "ID_UEV":"01002775", + "CIVIQUE_DE":" 1448", + "CIVIQUE_FI":" 1448", + "NOM_RUE":"rue Sherbrooke Ouest (MTL+MTO+WMT)", + "MUNICIPALI":"50", + "ETAGE_HORS":3, + "NOMBRE_LOG":1, + "ANNEE_CONS":1885, + "CODE_UTILI":"5010", + "LIBELLE_UT":"Immeuble commercial", + "CATEGORIE_":"Régulier", + "MATRICULE8":"9839-57-3057-9-000-0000", + "SUPERFICIE":167, + "SUPERFIC_1":354, + "NO_ARROND_":"REM19", + "Shape_Le_1":0.00074417728924999998, + "Shape_Ar_1":1.92186900974e-08, + "Z_Min_1":null, + "Z_Max_1":null, + "Shape_Length":52.283656634094768, + "Shape_Area":123.24449716965384 + } + } + ] +} \ No newline at end of file From fdb9f4d834ea068ac07ba959dc8950b5fd23f8c2 Mon Sep 17 00:00:00 2001 From: guille Date: Wed, 8 Mar 2023 15:29:16 -0500 Subject: [PATCH 3/6] Correct bug in geojson naming --- hub/imports/geometry/geojson.py | 2 +- hub/unittests/test_geometry_factory.py | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/hub/imports/geometry/geojson.py b/hub/imports/geometry/geojson.py index d8ef97f4..d9eadf66 100644 --- a/hub/imports/geometry/geojson.py +++ b/hub/imports/geometry/geojson.py @@ -145,7 +145,7 @@ class Geojson: polygons = self._get_polygons(polygons, coordinates) for zone, polygon in enumerate(polygons): if extrusion_height == 0: - buildings = buildings + Geojson._create_buildings_lod0(f'{building_name}_part_{part}_zone{zone}', + buildings = buildings + Geojson._create_buildings_lod0(f'{building_name}_part_{part}', year_of_construction, function, [polygon]) diff --git a/hub/unittests/test_geometry_factory.py b/hub/unittests/test_geometry_factory.py index a90c58c8..8a2fad0c 100644 --- a/hub/unittests/test_geometry_factory.py +++ b/hub/unittests/test_geometry_factory.py @@ -154,16 +154,17 @@ class TestGeometryFactory(TestCase): """ file = 'neighbours.geojson' city = self._get_city(file, 'geojson', + height_field='citygml_me', year_of_construction_field='ANNEE_CONS', function_field='LIBELLE_UT') GeometryHelper.city_mapping(city) for building in city.buildings: self.assertEqual(2, len(building.neighbours)) - self.assertEqual('2_part_0_zone0_zone_0',city.city_object('1_part_0_zone0_zone_0').neighbours[0].name) - self.assertEqual('3_part_0_zone0_zone_0',city.city_object('1_part_0_zone0_zone_0').neighbours[1].name) - self.assertEqual('1_part_0_zone0_zone_0',city.city_object('2_part_0_zone0_zone_0').neighbours[0].name) - self.assertEqual('3_part_0_zone0_zone_0',city.city_object('2_part_0_zone0_zone_0').neighbours[1].name) - self.assertEqual('2_part_0_zone0_zone_0', city.city_object('3_part_0_zone0_zone_0').neighbours[0].name) - self.assertEqual('1_part_0_zone0_zone_0', city.city_object('3_part_0_zone0_zone_0').neighbours[1].name) + self.assertEqual('2_part_0_zone_0',city.city_object('1_part_0_zone_0').neighbours[0].name) + self.assertEqual('3_part_0_zone_0',city.city_object('1_part_0_zone_0').neighbours[1].name) + self.assertEqual('1_part_0_zone_0',city.city_object('2_part_0_zone_0').neighbours[0].name) + self.assertEqual('3_part_0_zone_0',city.city_object('2_part_0_zone_0').neighbours[1].name) + self.assertEqual('1_part_0_zone_0', city.city_object('3_part_0_zone_0').neighbours[0].name) + self.assertEqual('2_part_0_zone_0', city.city_object('3_part_0_zone_0').neighbours[1].name) From 53ae043d637ced8cc3b0e1df454600eab8502418 Mon Sep 17 00:00:00 2001 From: guille Date: Thu, 9 Mar 2023 11:11:34 -0500 Subject: [PATCH 4/6] optimize imports --- hub/helpers/geometry_helper.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/hub/helpers/geometry_helper.py b/hub/helpers/geometry_helper.py index 54428937..eb66ee1f 100644 --- a/hub/helpers/geometry_helper.py +++ b/hub/helpers/geometry_helper.py @@ -5,18 +5,17 @@ Copyright © 2022 Concordia CERC group Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca """ -import datetime import math + import numpy as np import requests from trimesh import Trimesh from trimesh import intersections + from hub.city_model_structure.attributes.polygon import Polygon from hub.city_model_structure.attributes.polyhedron import Polyhedron from hub.helpers.location import Location -from PIL import Image - class MapPoint: def __init__(self, x, y): From 42a0d3887c975f1f34335cbf5ce93ea0d50735f5 Mon Sep 17 00:00:00 2001 From: guille Date: Fri, 10 Mar 2023 12:13:56 -0500 Subject: [PATCH 5/6] small test correction --- hub/exports/db_factory.py | 29 ++-- .../construction/nrel_physics_parameters.py | 2 +- hub/unittests/test_construction_catalog.py | 6 +- hub/unittests/test_db_factory.py | 9 +- hub/unittests/test_geometry_factory.py | 3 +- hub/unittests/test_heat_pump_simulation.py | 125 ------------------ hub/unittests/test_usage_factory.py | 1 - 7 files changed, 19 insertions(+), 156 deletions(-) delete mode 100644 hub/unittests/test_heat_pump_simulation.py diff --git a/hub/exports/db_factory.py b/hub/exports/db_factory.py index 173338f3..d7f3283c 100644 --- a/hub/exports/db_factory.py +++ b/hub/exports/db_factory.py @@ -23,51 +23,37 @@ class DBFactory: self._city_object = CityObject(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path) self._simulation_results = SimulationResults(db_name=db_name, dotenv_path=dotenv_path, app_env=app_env) - def get_city(self, city_id): + def city_by_id(self, city_id): """ Retrieve a single city from postgres :param city_id: the id of the city to get """ return self._city.get_by_id(city_id) - def get_city_by_name(self, city_name): + def city_by_name(self, city_name): """ Retrieve a single city from postgres :param city_name: the name of the city to get """ return self._city.get_by_name(city_name) - def get_city_by_user(self, user_id): + def cities_by_user(self, user_id): """ Retrieve cities created by user :param user_id: the id of the user """ return self._city.get_by_user(user_id) - def get_simulation_results_by_id(self, sim_id): + def simulation_results_by_city_id(self, city_id): """ - Retrieve a single simulation results - :param sim_id: the id of the simulation results to get - """ - return self._simulation_results.get_simulation_results_by_id(sim_id) - - def get_simulation_results_by_name(self, name): - """ - Retrieve a single simulation results - :param name: the name of the simulation results to get - """ - return self._simulation_results.get_simulation_results_by_name(name) - - def get_simulation_results_by_city_id(self, city_id): - """ - Retrieve a single simulation results + Retrieve all simulation results for the given city :param city_id: the city id of the simulation results to get """ return self._simulation_results.get_simulation_results_by_city_id(city_id) - def get_simulation_results_by_city_object_id(self, city_object_id): + def simulation_results_by_city_object_id(self, city_object_id): """ - Retrieve a single simulation results + Retrieve all simulation results for the given object_id :param city_object_id: the city object id of the simulation results to get """ return self._simulation_results.get_simulation_results_by_city_object_id(city_object_id) @@ -84,3 +70,4 @@ class DBFactory: def building_info(self, name, city_id): return self._city_object.get_by_name_and_city(name, city_id) + diff --git a/hub/imports/construction/nrel_physics_parameters.py b/hub/imports/construction/nrel_physics_parameters.py index e1e3fa06..78f08d30 100644 --- a/hub/imports/construction/nrel_physics_parameters.py +++ b/hub/imports/construction/nrel_physics_parameters.py @@ -78,7 +78,7 @@ class NrelPhysicsParameters: construction_period_limits = building_archetype.construction_period.split(' - ') if construction_period_limits[1] == 'PRESENT': construction_period_limits[1] = 3000 - if int(construction_period_limits[0]) <= year_of_constructionF < int(construction_period_limits[1]): + if int(construction_period_limits[0]) <= year_of_construction < int(construction_period_limits[1]): if (str(function) == str(building_archetype.function)) and \ (climate_zone == str(building_archetype.climate_zone)): return building_archetype diff --git a/hub/unittests/test_construction_catalog.py b/hub/unittests/test_construction_catalog.py index c85bf337..207d33aa 100644 --- a/hub/unittests/test_construction_catalog.py +++ b/hub/unittests/test_construction_catalog.py @@ -18,9 +18,9 @@ class TestConstructionCatalog(TestCase): constructions = catalog.names('constructions') windows = catalog.names('windows') materials = catalog.names('materials') - self.assertEqual(24, len(constructions['constructions'])) - self.assertEqual(4, len(windows['windows'])) - self.assertEqual(19, len(materials['materials'])) + self.assertEqual(33, len(constructions['constructions'])) + self.assertEqual(5, len(windows['windows'])) + self.assertEqual(33, len(materials['materials'])) with self.assertRaises(ValueError): catalog.names('unknown') diff --git a/hub/unittests/test_db_factory.py b/hub/unittests/test_db_factory.py index a4544a6b..9d815bf3 100644 --- a/hub/unittests/test_db_factory.py +++ b/hub/unittests/test_db_factory.py @@ -29,7 +29,8 @@ class TestDBFactory(TestCase): :return: None """ # Create test database - repo = Repository(db_name='test_db', app_env='TEST', dotenv_path='/usr/local/etc/hub/.env') + env = '/usr/local/etc/hub/.env' + repo = Repository(db_name='test_db', app_env='TEST', dotenv_path=env) eng = create_engine(f'postgresql://{repo.configuration.get_db_user()}@/{repo.configuration.get_db_user()}') try: @@ -53,9 +54,9 @@ class TestDBFactory(TestCase): city_file = "tests_data/C40_Final.gml" cls.city = GeometryFactory('citygml', city_file).city - cls._db_factory = DBFactory(db_name='test_db', app_env='TEST', dotenv_path='../.env') - cls._export_db_factory = ExportDBFactory(db_name='test_db', app_env='TEST', dotenv_path='../.env') - user_factory = UserFactory(db_name='test_db', app_env='TEST', dotenv_path='../.env') + cls._db_factory = DBFactory(db_name='test_db', app_env='TEST', dotenv_path=env) + cls._export_db_factory = ExportDBFactory(db_name='test_db', app_env='TEST', dotenv_path=env) + user_factory = UserFactory(db_name='test_db', app_env='TEST', dotenv_path=env) cls.unique_id = str(uuid.uuid4()) cls.application = cls._db_factory.persist_application("test", "test application", cls.unique_id) cls._user = user_factory.create_user("Admin", cls.application.id, "Admin@123", UserRoles.Admin) diff --git a/hub/unittests/test_geometry_factory.py b/hub/unittests/test_geometry_factory.py index 8a2fad0c..6c95ebbf 100644 --- a/hub/unittests/test_geometry_factory.py +++ b/hub/unittests/test_geometry_factory.py @@ -120,7 +120,8 @@ class TestGeometryFactory(TestCase): self.assertTrue(len(city.buildings) == 36) i = 0 for building in city.buildings: - self.assertIsNot(building.volume, inf, 'open volume') + print(building.volume) + self.assertIsNotEqual(building.volume, inf, 'open volume') i += 1 def test_import_obj(self): diff --git a/hub/unittests/test_heat_pump_simulation.py b/hub/unittests/test_heat_pump_simulation.py deleted file mode 100644 index 61c1f13b..00000000 --- a/hub/unittests/test_heat_pump_simulation.py +++ /dev/null @@ -1,125 +0,0 @@ -""" -Test EnergySystemsFactory and various heatpump models -SPDX - License - Identifier: LGPL - 3.0 - or -later -Copyright © 2022 Concordia CERC group -Project Coder Peter Yefi peteryefi@gmail.com -""" -from unittest import TestCase -from hub.imports.geometry_factory import GeometryFactory -from hub.imports.energy_systems_factory import EnergySystemsFactory -from hub.exports.energy_systems_factory import EnergySystemsExportFactory -from hub.imports.db_factory import DBFactory -from hub.exports.db_factory import DBFactory as ExportDBFactory -from hub.persistence.base_repo import BaseRepo -from sqlalchemy import create_engine -from hub.persistence.models import City -from hub.persistence.models import SimulationTypes -from hub.persistence.models import HeatPumpTypes -from hub.persistence.models import HeatPumpSimulation -from hub.persistence.models import User -from sqlalchemy.exc import ProgrammingError -from hub.imports.user_factory import UserFactory -from hub.persistence.models import UserRoles - -# User defined paramenters -hp_sim_data = { - 'StartYear': 2020, - 'EndYear': 2021, - 'MaximumHPEnergyInput': 8000, - 'HoursOfStorageAtMaxDemand': 1, - 'BuildingSuppTemp': 40, - 'TemperatureDifference': 15, - 'FuelLHV': 47100, - 'FuelPrice': 0.12, - 'FuelEF': 1887, - 'FuelDensity': 0.717, - 'HPSupTemp': 60 -} - - -class TestHeatPumpSimulation(TestCase): - """ - Heat pump simulation test cases - """ - @classmethod - def setUpClass(cls) -> None: - """ - Test setup - :return: None - """ - repo = BaseRepo(db_name='test_db', app_env='TEST', dotenv_path='../.env') - eng = create_engine(f'postgresql://{repo.config.get_db_user()}@/{repo.config.get_db_user()}') - - try: - conn = eng.connect() - conn.execute('commit') - conn.execute('DROP DATABASE test_db') - conn.close() - except ProgrammingError as err: - print(f'Database does not exist. Nothing to delete') - - cnn = eng.connect() - cnn.execute('commit') - cnn.execute("CREATE DATABASE test_db") - cnn.close() - - # Create test tables if they do not exit - User.__table__.create(bind=repo.engine, checkfirst=True) - City.__table__.create(bind=repo.engine, checkfirst=True) - HeatPumpSimulation.__table__.create(bind=repo.engine, checkfirst=True) - - - city_file = "tests_data/C40_Final.gml" - cls._city = GeometryFactory('citygml', city_file).city - EnergySystemsFactory('air source hp', cls._city).enrich() - - cls._db_factory = DBFactory(db_name='test_db', app_env='TEST', dotenv_path='../.env') - cls._export_db_factory = ExportDBFactory(db_name='test_db', app_env='TEST', dotenv_path='../.env') - user_factory = UserFactory(db_name='test_db', app_env='TEST', dotenv_path='../.env') - cls._user = user_factory.create_user("Admin", "admin@hub.com", "Admin@123", UserRoles.Admin) - - def test_heat_pump_simulation_persistence(self): - output = EnergySystemsExportFactory(city=self._city, user_input=hp_sim_data, hp_model='018', - output_path=None, sim_type=1).export() - hp_sim_data["HeatPumpModel"] = '018' - hp_sim_data["SimulationType"] = SimulationTypes.Parallel - hp_sim_data["HeatPumpType"] = HeatPumpTypes.Air - hp_sim_data["HourlyElectricityDemand"] = output["hourly_electricity_demand"] - hp_sim_data["DailyElectricityDemand"] = output["daily_electricity_demand"] - hp_sim_data["MonthlyElectricityDemand"] = output["monthly_electricity_demand"] - hp_sim_data["DailyFossilFuelConsumption"] = output["daily_fossil_consumption"] - hp_sim_data["MonthlyFossilFuelConsumption"] = output["monthly_fossil_consumption"] - - saved_city = self._db_factory.persist_city(self._user.id, self._city) - hp_sim = self._db_factory.persist_hp_simulation(hp_sim_data, saved_city.id) - self.assertEqual(hp_sim.heat_pump_type, HeatPumpTypes.Air) - self.assertEqual(hp_sim.simulation_type, SimulationTypes.Parallel) - self.assertEqual(hp_sim.fuel_efficiency, hp_sim_data["FuelEF"]) - self.assertEqual(hp_sim.monthly_electricity_demand, output["monthly_electricity_demand"]) - self._db_factory.delete_hp_simulation(hp_sim.id) - self._db_factory.delete_city(saved_city.id) - - def test_get_heat_pump_simulation_by_city(self): - output = EnergySystemsExportFactory(city=self._city, user_input=hp_sim_data, hp_model='012', - output_path=None, sim_type=0).export() - hp_sim_data["HeatPumpModel"] = '012' - hp_sim_data["SimulationType"] = SimulationTypes.Series - hp_sim_data["HeatPumpType"] = HeatPumpTypes.Air - hp_sim_data["HourlyElectricityDemand"] = output["hourly_electricity_demand"] - hp_sim_data["DailyElectricityDemand"] = output["daily_electricity_demand"] - hp_sim_data["MonthlyElectricityDemand"] = output["monthly_electricity_demand"] - hp_sim_data["DailyFossilFuelConsumption"] = output["daily_fossil_consumption"] - hp_sim_data["MonthlyFossilFuelConsumption"] = output["monthly_fossil_consumption"] - - saved_city = self._db_factory.persist_city(self._user.id, self._city) - self._db_factory.persist_hp_simulation(hp_sim_data, saved_city.id) - - # retrieved saved simulation by city id - hp_sim = self._export_db_factory.get_hp_simulation_by_city(saved_city.id) - self.assertEqual(hp_sim[0].heat_pump_type, HeatPumpTypes.Air) - self.assertEqual(hp_sim[0].simulation_type, SimulationTypes.Series) - self.assertEqual(hp_sim[0].fuel_price, hp_sim_data["FuelPrice"]) - self.assertEqual(hp_sim[0].hourly_electricity_demand, output["hourly_electricity_demand"]) - self._db_factory.delete_hp_simulation(hp_sim[0].id) - self._db_factory.delete_city(saved_city.id) - diff --git a/hub/unittests/test_usage_factory.py b/hub/unittests/test_usage_factory.py index e4d7b219..4cefef8c 100644 --- a/hub/unittests/test_usage_factory.py +++ b/hub/unittests/test_usage_factory.py @@ -108,7 +108,6 @@ class TestUsageFactory(TestCase): self.assertIsNotNone(occupancy.sensible_radiative_internal_gain, 'occupancy sensible radiant internal gain is none') self.assertIsNotNone(occupancy.occupancy_schedules, 'occupancy schedule is none') - self.assertIsNone(occupancy.occupants, 'occupancy density is not none') self.assertIsNotNone(usage.lighting, 'lighting is none') lighting = usage.lighting self.assertIsNotNone(lighting.density, 'lighting density is none') From 7092e75a52d2198c3ddc48a4377982d0cc45165c Mon Sep 17 00:00:00 2001 From: guille Date: Fri, 10 Mar 2023 12:22:28 -0500 Subject: [PATCH 6/6] small test correction remove deprecated db_export calls --- hub/exports/db_factory.py | 9 +-------- hub/unittests/test_geometry_factory.py | 4 ---- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/hub/exports/db_factory.py b/hub/exports/db_factory.py index d7f3283c..c003510f 100644 --- a/hub/exports/db_factory.py +++ b/hub/exports/db_factory.py @@ -25,18 +25,11 @@ class DBFactory: def city_by_id(self, city_id): """ - Retrieve a single city from postgres + Retrieve a single city using the id :param city_id: the id of the city to get """ return self._city.get_by_id(city_id) - def city_by_name(self, city_name): - """ - Retrieve a single city from postgres - :param city_name: the name of the city to get - """ - return self._city.get_by_name(city_name) - def cities_by_user(self, user_id): """ Retrieve cities created by user diff --git a/hub/unittests/test_geometry_factory.py b/hub/unittests/test_geometry_factory.py index 6c95ebbf..990097fd 100644 --- a/hub/unittests/test_geometry_factory.py +++ b/hub/unittests/test_geometry_factory.py @@ -119,10 +119,6 @@ class TestGeometryFactory(TestCase): self.assertIsNotNone(city, 'city is none') self.assertTrue(len(city.buildings) == 36) i = 0 - for building in city.buildings: - print(building.volume) - self.assertIsNotEqual(building.volume, inf, 'open volume') - i += 1 def test_import_obj(self): """