2021-03-16 16:58:52 -04:00
|
|
|
"""
|
|
|
|
Obj module parses obj files and import the geometry into the city model structure
|
|
|
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
2022-04-08 09:35:33 -04:00
|
|
|
Copyright © 2022 Concordia CERC group
|
|
|
|
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
2021-03-16 16:58:52 -04:00
|
|
|
"""
|
2021-04-07 14:20:13 -04:00
|
|
|
import trimesh.exchange.load
|
|
|
|
from trimesh import Scene
|
|
|
|
import trimesh.geometry
|
2023-01-24 10:51:50 -05:00
|
|
|
from hub.city_model_structure.city import City
|
|
|
|
from hub.city_model_structure.building import Building
|
|
|
|
from hub.city_model_structure.building_demand.surface import Surface
|
|
|
|
from hub.city_model_structure.attributes.polygon import Polygon
|
2021-03-16 16:58:52 -04:00
|
|
|
|
|
|
|
|
|
|
|
class Obj:
|
|
|
|
"""
|
|
|
|
Obj class
|
|
|
|
"""
|
|
|
|
def __init__(self, path):
|
|
|
|
self._city = None
|
2023-05-30 17:13:49 -04:00
|
|
|
with open(path, 'r', encoding='utf8') as file:
|
2021-04-07 14:20:13 -04:00
|
|
|
self._scene = trimesh.exchange.load.load(file, file_type='obj', force='scene')
|
|
|
|
self._corners = self._scene.bounds_corners
|
2021-11-16 07:57:47 -05:00
|
|
|
_bound_corner_min = None
|
|
|
|
_bound_corner_max = None
|
2021-04-07 14:20:13 -04:00
|
|
|
for corner in self._corners:
|
|
|
|
if _bound_corner_min is None:
|
|
|
|
_bound_corner_min = corner
|
|
|
|
elif _bound_corner_max is None:
|
|
|
|
_bound_corner_max = corner
|
|
|
|
else:
|
|
|
|
_bound_corner_min[0] = min(_bound_corner_min[0], corner[0])
|
|
|
|
_bound_corner_min[1] = min(_bound_corner_min[1], corner[1])
|
|
|
|
_bound_corner_min[2] = min(_bound_corner_min[2], corner[2])
|
|
|
|
_bound_corner_max[0] = max(_bound_corner_max[0], corner[0])
|
|
|
|
_bound_corner_max[1] = max(_bound_corner_max[1], corner[1])
|
|
|
|
_bound_corner_max[2] = max(_bound_corner_max[2], corner[2])
|
|
|
|
self._lower_corner = _bound_corner_min
|
|
|
|
self._upper_corner = _bound_corner_max
|
2021-03-16 16:58:52 -04:00
|
|
|
|
|
|
|
@property
|
2021-04-07 14:20:13 -04:00
|
|
|
def scene(self) -> Scene:
|
2021-08-27 12:51:30 -04:00
|
|
|
"""
|
2021-08-30 14:39:24 -04:00
|
|
|
Get obj scene
|
2021-08-27 12:51:30 -04:00
|
|
|
"""
|
2021-03-16 16:58:52 -04:00
|
|
|
return self._scene
|
2021-04-07 11:47:39 -04:00
|
|
|
|
|
|
|
@property
|
2021-04-07 14:20:13 -04:00
|
|
|
def city(self) -> City:
|
2021-08-27 12:51:30 -04:00
|
|
|
"""
|
2021-08-30 14:39:24 -04:00
|
|
|
Get city out of an obj file
|
2021-08-27 12:51:30 -04:00
|
|
|
"""
|
2023-01-26 07:41:56 -05:00
|
|
|
lod = 0
|
2021-04-07 11:47:39 -04:00
|
|
|
if self._city is None:
|
2021-04-07 14:20:13 -04:00
|
|
|
# todo: refactor this method to clearly choose the obj type
|
|
|
|
# todo: where do we get this information from?
|
|
|
|
srs_name = 'EPSG:26911'
|
2021-04-07 11:47:39 -04:00
|
|
|
|
2021-04-07 14:20:13 -04:00
|
|
|
self._city = City(self._lower_corner, self._upper_corner, srs_name)
|
|
|
|
scene = self.scene.geometry
|
|
|
|
keys = scene.keys()
|
|
|
|
for key in keys:
|
|
|
|
name = key
|
|
|
|
# todo: where do we get this information from?
|
|
|
|
lod = 1
|
|
|
|
year_of_construction = 0
|
|
|
|
function = ''
|
|
|
|
|
|
|
|
obj = scene[key]
|
|
|
|
surfaces = []
|
|
|
|
for face in obj.faces:
|
|
|
|
points = []
|
|
|
|
for vertex_index in face:
|
|
|
|
points.append(obj.vertices[vertex_index])
|
|
|
|
solid_polygon = Polygon(points)
|
|
|
|
perimeter_polygon = solid_polygon
|
|
|
|
surface = Surface(solid_polygon, perimeter_polygon)
|
|
|
|
surfaces.append(surface)
|
2022-11-28 13:44:02 -05:00
|
|
|
building = Building(name, surfaces, year_of_construction, function, terrains=None)
|
2021-04-07 14:31:16 -04:00
|
|
|
self._city.add_city_object(building)
|
2022-11-25 15:25:59 -05:00
|
|
|
self._city.level_of_detail.geometry = lod
|
2023-05-12 09:27:29 -04:00
|
|
|
for building in self._city.buildings:
|
|
|
|
building.level_of_detail.geometry = lod
|
|
|
|
|
2021-04-07 11:47:39 -04:00
|
|
|
return self._city
|