Add unit tests and requirements for geopandas factory.

Geopandas factory now can receive a geojson file or a pandas data frame by using the optional variable data_frame in the constructor to be consistent with the rest of the factories

So from:
 ConstructionFactory('gpandas', dataframe)
to:
 ConstructionFactory('gpandas, '', dataframe)
This commit is contained in:
Guille Gutierrez 2022-11-16 16:26:45 -05:00
parent d91da411fd
commit a617f598ff
6 changed files with 48 additions and 15 deletions

View File

@ -8,6 +8,8 @@ Project Coder: Milad Aghamohamadnia --- milad.aghamohamadnia@concordia.ca
import trimesh import trimesh
import trimesh.exchange.load import trimesh.exchange.load
import trimesh.geometry import trimesh.geometry
import trimesh.creation
import trimesh.repair
from shapely.geometry import Point from shapely.geometry import Point
from shapely.geometry import Polygon as ShapelyPoly from shapely.geometry import Polygon as ShapelyPoly
from trimesh import Scene from trimesh import Scene
@ -25,16 +27,17 @@ class GPandas:
GeoPandas class GeoPandas class
""" """
def __init__(self, gdataframe, srs_name='EPSG:26911'): def __init__(self, dataframe, srs_name='EPSG:26911'):
"""_summary_ """_summary_
Arguments: Arguments:
gdataframe {Geopandas.Dataframe} -- input geometry data in geopandas table dataframe {Geopandas.Dataframe} -- input geometry data in geopandas table
Keyword Arguments: Keyword Arguments:
srs_name {str} -- coordinate system of coordinate system (default: {'EPSG:26911'}) srs_name {str} -- coordinate system of coordinate system (default: {'EPSG:26911'})
""" """
self._srs_name = srs_name self._srs_name = srs_name
self._city = None self._city = None
self._scene = gdataframe self._scene = dataframe
self._scene = self._scene.to_crs(self._srs_name) self._scene = self._scene.to_crs(self._srs_name)
min_x, min_y, max_x, max_y = self._scene.total_bounds min_x, min_y, max_x, max_y = self._scene.total_bounds
self._lower_corner = [min_x, min_y, 0] self._lower_corner = [min_x, min_y, 0]
@ -70,15 +73,13 @@ class GPandas:
function = cte.INDUSTRY function = cte.INDUSTRY
surfaces = [] surfaces = []
face_normal = building_mesh.face_normals
for face_index, face in enumerate(building_mesh.faces): for face_index, face in enumerate(building_mesh.faces):
points = [] points = []
for vertex_index in face: for vertex_index in face:
points.append(building_mesh.vertices[vertex_index]) points.append(building_mesh.vertices[vertex_index])
solid_polygon = Polygon(points) solid_polygon = Polygon(points)
perimeter_polygon = solid_polygon perimeter_polygon = solid_polygon
s_type = cte.GROUND if face_normal[face_index][2] == -1 else (cte.ROOF if face_normal[face_index][2] == 1 else cte.WALL) surface = Surface(solid_polygon, perimeter_polygon)
surface = Surface(solid_polygon, perimeter_polygon, surface_type=s_type)
surfaces.append(surface) surfaces.append(surface)
building = Building(name, lod, surfaces, year_of_construction, function, self._lower_corner, terrains=None) building = Building(name, lod, surfaces, year_of_construction, function, self._lower_corner, terrains=None)
self._city.add_city_object(building) self._city.add_city_object(building)

View File

@ -11,15 +11,16 @@ from imports.geometry.obj import Obj
from imports.geometry.osm_subway import OsmSubway from imports.geometry.osm_subway import OsmSubway
from imports.geometry.rhino import Rhino from imports.geometry.rhino import Rhino
from imports.geometry.gpandas import GPandas from imports.geometry.gpandas import GPandas
import geopandas
class GeometryFactory: class GeometryFactory:
""" """
GeometryFactory class GeometryFactory class
""" """
def __init__(self, file_type, path): def __init__(self, file_type, path, data_frame=None):
self._file_type = '_' + file_type.lower() self._file_type = '_' + file_type.lower()
self._path = path self._path = path
self._data_frame = data_frame
@property @property
def _citygml(self) -> City: def _citygml(self) -> City:
@ -44,7 +45,9 @@ class GeometryFactory:
Enrich the city by using GeoPandas information as data source Enrich the city by using GeoPandas information as data source
:return: City :return: City
""" """
return GPandas(self._path).city if self._data_frame is None:
self._data_frame = geopandas.read_file(self._path)
return GPandas(self._data_frame).city
@property @property
def _osm_subway(self) -> City: def _osm_subway(self) -> City:
@ -76,4 +79,4 @@ class GeometryFactory:
Enrich the city given to the class using the class given handler Enrich the city given to the class using the class given handler
:return: City :return: City
""" """
return CityGml(self._path).city return GPandas(geopandas.read_file(self._path)).city

View File

@ -17,3 +17,5 @@ scipy
PyYAML PyYAML
pyecore==0.12.2 pyecore==0.12.2
shapely shapely
geopandas
triangle

View File

@ -93,9 +93,7 @@ class TestGeometryFactory(TestCase):
_construction_keys = ['nrel'] _construction_keys = ['nrel']
_usage_keys = ['comnet', 'hft'] _usage_keys = ['comnet', 'hft']
for construction_key in _construction_keys: for construction_key in _construction_keys:
print('construction key: ', construction_key)
for usage_key in _usage_keys: for usage_key in _usage_keys:
print('usage key: ', usage_key)
# construction factory called first # construction factory called first
city = self._get_citygml(file) city = self._get_citygml(file)
for building in city.buildings: for building in city.buildings:

View File

@ -8,9 +8,11 @@ from pathlib import Path
from unittest import TestCase from unittest import TestCase
from numpy import inf from numpy import inf
from pyproj import Proj, transform
from imports.geometry_factory import GeometryFactory from imports.geometry_factory import GeometryFactory
from imports.construction_factory import ConstructionFactory from imports.construction_factory import ConstructionFactory
import geopandas
class TestGeometryFactory(TestCase): class TestGeometryFactory(TestCase):
@ -32,6 +34,12 @@ class TestGeometryFactory(TestCase):
self.assertIsNotNone(self._city, 'city is none') self.assertIsNotNone(self._city, 'city is none')
return self._city return self._city
def _get_geojson(self, file):
file_path = (self._example_path / file).resolve()
self._city = GeometryFactory('gpandas', file_path).city_debug
self.assertIsNotNone(self._city, 'city is none')
return self._city
def _get_obj(self, file): def _get_obj(self, file):
# todo: solve the incongruities between city and city_debug # todo: solve the incongruities between city and city_debug
file_path = (self._example_path / file).resolve() file_path = (self._example_path / file).resolve()
@ -151,13 +159,16 @@ class TestGeometryFactory(TestCase):
""" """
Test geopandas import Test geopandas import
""" """
file = 'kelowna.obj' file = 'sample.geojson'
city = self._get_obj(file) city = self._get_geojson(file)
self.assertIsNotNone(city, 'city is none') self.assertIsNotNone(city, 'city is none')
self.assertTrue(len(city.buildings) == 1) self.assertTrue(len(city.buildings) == 1)
self._check_buildings(city) self._check_buildings(city)
for building in city.buildings: for building in city.buildings:
self._check_surfaces(building) self._check_surfaces(building)
self.assertEqual(1912.0898135701814, building.volume)
self.assertEqual(146.19493345171213, building.floor_area)
# osm # osm
def test_subway(self): def test_subway(self):

View File

@ -0,0 +1,18 @@
{ "type": "FeatureCollection",
"features": [
{ "type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[ [[-73.5027962600162, 45.6572759731914], [-73.5027463586105, 45.6572669735158], [-73.5027513584185, 45.6572530729948], [-73.5026715592026, 45.6572412737672], [-73.5026410593539, 45.6573430727752], [-73.5027703584728, 45.6573621728624], [-73.5027962600162, 45.6572759731914]] ]
]
},
"properties": {
"geom": {"type": "Polygon", "crs": {"type": "name", "properties": {"name": "urn:ogc:def:crs:EPSG::4326"}}, "coordinates": [[[3849322.0855625975, 6060583.24800576], [3849326.3956304314, 6060584.796717078], [3849327.0180495544, 6060583.089519385], [3849333.725799462, 6060585.837955164], [3849328.71788522, 6060598.03498192], [3849317.850609142, 6060593.57976506], [3849322.0855625975, 6060583.24800576]]]},
"height_mean": 13.0790429485,
"year_built": 2000
}
}
]
}