From 0ed6c2d9356e677468e96d033c9ac55a48ac12b7 Mon Sep 17 00:00:00 2001 From: guille Date: Fri, 10 Mar 2023 14:04:00 -0500 Subject: [PATCH 1/2] Partial correction of persistence business logic --- hub/exports/db_factory.py | 62 +++++++++---------- hub/helpers/geometry_helper.py | 2 +- hub/persistence/repositories/city.py | 54 ++++------------ .../repositories/simulation_results.py | 30 ++------- 4 files changed, 45 insertions(+), 103 deletions(-) diff --git a/hub/exports/db_factory.py b/hub/exports/db_factory.py index c003510f..a0ddcda5 100644 --- a/hub/exports/db_factory.py +++ b/hub/exports/db_factory.py @@ -23,44 +23,40 @@ 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 city_by_id(self, city_id): - """ - 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 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 simulation_results_by_city_id(self, city_id): - """ - 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 simulation_results_by_city_object_id(self, city_object_id): - """ - 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) - def application_info(self, application_uuid): + """ + Retrieve the application info for the given uuid + :param application_uuid: the uuid for the application + """ return self._application.get_by_uuid(application_uuid) - def user_info(self, name, password, application_id): - return self._user.get_by_name_application_id_and_password(name, password, application_id) - def user_login(self, name, password, application_uuid): + """ + Retrieve the user info + :param name: the user name + :param password: the user password + :param application_uuid: the application uuid + """ return self._user.get_by_name_application_uuid_and_password(name, password, application_uuid) - def building_info(self, name, city_id): - return self._city_object.get_by_name_and_city(name, city_id) + def results(self, user_id, application_id, cities, result_names=[]): + """ + Retrieve the simulation results for the given cities + :param user_id: the user id owning the results + :param application_id: the application id owning the results + :param cities: dictionary containing the city and building names for the results + :param result_names: if given, filter the results to the selected names + """ + results = [] + for city in cities['cities'].keys(): + city_id = self._city.get_by_user_id_application_id_and_name(user_id, application_id, city).id + for building_name in cities[city]: + city_object_id = self._city_object.get_by_name_and_city(building_name, city_id).id + results.append(self._simulation_results.get_simulation_results_by_city_id_city_object_id_and_names( + city_id, + city_object_id, + result_names)) + return results + diff --git a/hub/helpers/geometry_helper.py b/hub/helpers/geometry_helper.py index eb66ee1f..d46eb71b 100644 --- a/hub/helpers/geometry_helper.py +++ b/hub/helpers/geometry_helper.py @@ -65,8 +65,8 @@ class GeometryHelper: @staticmethod def city_mapping(city, building_names=None): """ - Returns a shared_information dictionary like + Returns a shared_information dictionary like { "building_name" : [{line: 0 coordinate_1: [x,y,z], coordinate_2:[x, y, z], points: 0}] } diff --git a/hub/persistence/repositories/city.py b/hub/persistence/repositories/city.py index ebfccaad..52e59204 100644 --- a/hub/persistence/repositories/city.py +++ b/hub/persistence/repositories/city.py @@ -109,51 +109,19 @@ class City(Repository): except SQLAlchemyError as err: logger.error(f'Error while fetching city: {err}') - def get_by_id(self, city_id: int) -> Model: + def get_by_user_id_application_id_and_name(self, user_id, application_id, city_name): """ - Fetch a City based on the id - :param city_id: the city id - :return: a city + Fetch city based on the user who created it + :param user_id: the user id + :param application_id: the application id + :param city_name: the city name + :return: ModelCity """ try: - return self.session.execute(select(Model).where(Model.id == city_id)).first()[0] - except SQLAlchemyError as err: - logger.error(f'Error while fetching city: {err}') - - def _get_by_hub_version_and_name(self, hub_release: str, city_name: str) -> Model: - """ - Fetch a City based on the name and hub project - :param hub_release: the hub release - :param city_name: the name of the city - :return: a city - """ - try: - return self.session.execute(select(Model) - .where(Model.hub_release == hub_release, Model.name == city_name) - ).first() - except SQLAlchemyError as err: - logger.error(f'Error while fetching city: {err}') - - def get_by_name(self, city_name: str) -> [Model]: - """ - Fetch city based on the name - :param city_name: the name of the building - :return: [ModelCity] with the provided name - """ - try: - result_set = self.session.execute(select(Model).where(Model.name == city_name)) - return [building[0] for building in result_set] + result_set = self.session.execute(select(Model).where(Model.user_id == user_id, + Model.application_id == application_id, + Model.name == city_name + )).first()[0] + return result_set except SQLAlchemyError as err: logger.error(f'Error while fetching city by name: {err}') - - def get_by_user(self, user_id: int) -> [Model]: - """ - Fetch city based on the user who created it - :param user_id: the id of the user - :return: [ModelCity] with the provided name - """ - try: - result_set = self.session.execute(select(Model).where(Model.user_id == user_id)) - return [building[0] for building in result_set] - except SQLAlchemyError as err: - logger.error(f'Error while fetching city by name: {err}') diff --git a/hub/persistence/repositories/simulation_results.py b/hub/persistence/repositories/simulation_results.py index 1b5027a2..53524bba 100644 --- a/hub/persistence/repositories/simulation_results.py +++ b/hub/persistence/repositories/simulation_results.py @@ -44,11 +44,11 @@ class SimulationResults(Repository): :return SimulationResults or Dictionary """ if city_id is not None: - city = self.get_city(city_id) + city = self._get_city(city_id) if city is None: return {'message': f'City does not exists'} else: - city_object = self.get_city_object(city_object_id) + city_object = self._get_city_object(city_object_id) if city_object is None: return {'message': f'City object does not exists'} try: @@ -114,7 +114,7 @@ class SimulationResults(Repository): except SQLAlchemyError as err: logger.error(f'Error while deleting application: {err}') - def get_city(self, city_id) -> [City]: + def _get_city(self, city_id) -> [City]: """ Fetch a city object based city id :param city_id: a city identifier @@ -125,28 +125,6 @@ class SimulationResults(Repository): except SQLAlchemyError as err: logger.error(f'Error while fetching city by city_id: {err}') - def get_simulation_results_by_id(self, sim_id) -> [Model]: - """ - Fetch simulation results by id - :param sim_id: a simulation result identifier - :return: [Model] with the provided sim_id - """ - try: - return self.session.execute(select(Model).where(Model.id == sim_id)).first() - except SQLAlchemyError as err: - logger.error(f'Error while fetching simulation results by sim_id: {err}') - - def get_simulation_results_by_name(self, name) -> [Model]: - """ - Fetch simulation results by name - :param name: the name of the simulation results - :return: [Model] with the provided name - """ - try: - return self.session.execute(select(Model).where(Model.name == name)) - except SQLAlchemyError as err: - logger.error(f'Error while fetching simulation results by name: {err}') - def get_simulation_results_by_city_id(self, city_id) -> [Model]: """ Fetch simulation results by name @@ -169,7 +147,7 @@ class SimulationResults(Repository): except SQLAlchemyError as err: logger.error(f'Error while fetching simulation results by name: {err}') - def get_city_object(self, city_object_id) -> [CityObject]: + def _get_city_object(self, city_object_id) -> [CityObject]: """ Fetch a city object based city id :param city_object_id: a city object identifier From 77743fea1c2e12d8467f25348b7dfa2ba96b9fe0 Mon Sep 17 00:00:00 2001 From: Pilar Date: Fri, 10 Mar 2023 14:09:41 -0500 Subject: [PATCH 2/2] rolling back changes --- hub/helpers/geometry_helper.py | 69 ++++++++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 15 deletions(-) diff --git a/hub/helpers/geometry_helper.py b/hub/helpers/geometry_helper.py index 2eabbbe0..d46eb71b 100644 --- a/hub/helpers/geometry_helper.py +++ b/hub/helpers/geometry_helper.py @@ -6,16 +6,16 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca Code contributors: Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca """ 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): @@ -63,7 +63,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 +71,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,21 +88,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} 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: @@ -114,8 +154,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: