From 340b84817a6613fe21c1e1fa276fd95f15562a7f Mon Sep 17 00:00:00 2001 From: majidrezaei93 Date: Thu, 3 Oct 2024 18:27:21 -0400 Subject: [PATCH] feat: add csv handler to geometry factory --- hub/imports/geometry/csv.py | 85 +++++++++++++++++++++++++++++++++ hub/imports/geometry_factory.py | 22 ++++++++- 2 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 hub/imports/geometry/csv.py diff --git a/hub/imports/geometry/csv.py b/hub/imports/geometry/csv.py new file mode 100644 index 00000000..4978b375 --- /dev/null +++ b/hub/imports/geometry/csv.py @@ -0,0 +1,85 @@ +import csv +import uuid +from decimal import Decimal, InvalidOperation +from hub.city_model_structure.simplified_building import SimplifiedBuilding +from hub.city_model_structure.simplified_city import SimplifiedCity + +class Csv: + """ + CSV class + """ + + def __init__(self, + path, + year_of_construction_field=None, + function_field=None, + function_to_hub=None, + total_floor_area_field=None): + self._simplified_city = None + self._year_of_construction_field = year_of_construction_field + self._function_field = function_field + self._function_to_hub = function_to_hub + self._total_floor_area_field = total_floor_area_field + with open(path, 'r', encoding='utf8') as csv_file: + reader = csv.DictReader(csv_file) + self._csv_data = [row for row in reader] + + def safe_int(self, value): + if value in ('NULL', '', None): + return None + try: + return int(value) + except ValueError: + return None + + def safe_float(self, value): + if value in ('NULL', '', None): + return None + try: + return float(value) + except ValueError: + return None + + def safe_decimal(self, value): + if value in ('NULL', '', None): + return None + try: + return Decimal(value) + except InvalidOperation: + return None + + @property + def city(self) -> SimplifiedCity: + if self._simplified_city is None: + self._simplified_city = SimplifiedCity() + for row in self._csv_data: + year_of_construction = None + if self._year_of_construction_field: + year_of_construction = self.safe_int(row[self._year_of_construction_field]) + + function = None + if self._function_field: + function = row[self._function_field] + if self._function_to_hub: + function = self._function_to_hub.get(function, function) + + total_floor_area = None + if self._total_floor_area_field: + total_floor_area = self.safe_float(row[self._total_floor_area_field]) + + if 'id_provinc' in row and row['id_provinc']: + building_name = str(self.safe_decimal(row['id_provinc'])) + else: + building_name = str(uuid.uuid4()) + + building = SimplifiedBuilding( + name=building_name, + total_floor_area=total_floor_area, + year_of_construction=year_of_construction, + function=function + ) + + if building.total_floor_area is not None and building.total_floor_area >= 25: + self._simplified_city.add_city_object(building) + + return self._simplified_city diff --git a/hub/imports/geometry_factory.py b/hub/imports/geometry_factory.py index 21dba708..6e47ebfc 100644 --- a/hub/imports/geometry_factory.py +++ b/hub/imports/geometry_factory.py @@ -6,10 +6,12 @@ Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca """ from hub.city_model_structure.city import City +from hub.city_model_structure.simplified_city import SimplifiedCity from hub.helpers.utils import validate_import_export_type from hub.imports.geometry.citygml import CityGml from hub.imports.geometry.geojson import Geojson from hub.imports.geometry.obj import Obj +from hub.imports.geometry.csv import Csv class GeometryFactory: @@ -23,7 +25,8 @@ class GeometryFactory: year_of_construction_field=None, function_field=None, function_to_hub=None, - hub_crs=None): + hub_crs=None, + total_floor_area_field=None): self._file_type = '_' + file_type.lower() validate_import_export_type(GeometryFactory, file_type) self._path = path @@ -33,6 +36,7 @@ class GeometryFactory: self._function_field = function_field self._function_to_hub = function_to_hub self._hub_crs = hub_crs + self._total_floor_area_field = total_floor_area_field @property def _citygml(self) -> City: @@ -68,6 +72,14 @@ class GeometryFactory: self._function_to_hub, self._hub_crs).city + @property + def _csv(self) -> SimplifiedCity: + return Csv(self._path, + self._year_of_construction_field, + self._function_field, + self._function_to_hub, + self._total_floor_area_field).city + @property def city(self) -> City: """ @@ -75,3 +87,11 @@ class GeometryFactory: :return: City """ return getattr(self, self._file_type, lambda: None) + + @property + def simplified_city(self) -> SimplifiedCity: + """ + Enrich the city given to the class using the class given handler + :return: SimplifiedCity + """ + return getattr(self, self._file_type, lambda: None)