diff --git a/.idea/libs.iml b/.idea/libs.iml
index c268a131..7d99385a 100644
--- a/.idea/libs.iml
+++ b/.idea/libs.iml
@@ -6,7 +6,7 @@
-
+
diff --git a/city_model_structure/attributes/polyhedron.py b/city_model_structure/attributes/polyhedron.py
index d9d6a2bb..d04a47b9 100644
--- a/city_model_structure/attributes/polyhedron.py
+++ b/city_model_structure/attributes/polyhedron.py
@@ -25,7 +25,7 @@ class Polyhedron:
self._volume = None
self._faces = None
self._vertices = None
- self._mesh = None
+ self._trimesh = None
self._centroid = None
self._max_z = None
self._max_y = None
@@ -348,10 +348,10 @@ class Polyhedron:
return self._faces
@property
- def polyhedron_trimesh(self):
- if self._mesh is None:
- self._mesh = Trimesh(vertices=self.vertices, faces=self.faces)
- return self._mesh
+ def trimesh(self) -> Trimesh:
+ if self._trimesh is None:
+ self._trimesh = Trimesh(vertices=self.vertices, faces=self.faces)
+ return self._trimesh
@property
def volume(self):
@@ -360,10 +360,10 @@ class Polyhedron:
:return: float
"""
if self._volume is None:
- if not self.polyhedron_trimesh.is_volume:
+ if not self.trimesh.is_volume:
self._volume = np.inf
else:
- self._volume = self.polyhedron_trimesh.volume
+ self._volume = self.trimesh.volume
return self._volume
@property
@@ -466,7 +466,7 @@ class Polyhedron:
:param full_path: str
:return: None
"""
- self.polyhedron_trimesh.export(full_path, 'stl_ascii')
+ self.trimesh.export(full_path, 'stl_ascii')
def obj_export(self, full_path):
"""
@@ -474,7 +474,7 @@ class Polyhedron:
:param full_path: str
:return: None
"""
- self.polyhedron_trimesh.export(full_path, 'obj')
+ self.trimesh.export(full_path, 'obj')
def show(self):
- self.polyhedron_trimesh.show()
+ self.trimesh.show()
diff --git a/city_model_structure/building.py b/city_model_structure/building.py
index 90d97647..75a37371 100644
--- a/city_model_structure/building.py
+++ b/city_model_structure/building.py
@@ -311,18 +311,18 @@ class Building(CityObject):
# height = self.average_storey_height
number_of_storeys = 4
height = 1.5
- mesh = self.simplified_polyhedron.polyhedron_trimesh
+ trimesh = self.simplified_polyhedron.trimesh
normal_plane = [0, 0, -1]
- rest_mesh = mesh
+ rest_trimesh = trimesh
for n in range(0, number_of_storeys - 1):
# todo: I need the lower corner of the building!!
# point_plane = [self._lower_corner[0], self._lower_corner[1], self._lower_corner[2] + height]
point_plane = [self._lower_corner[0] + 0.5, self._lower_corner[1] + 0.5, self._lower_corner[2] + height * (n + 1)]
- meshes = gh.divide_mesh_by_plane(rest_mesh, normal_plane, point_plane)
- storey = meshes[0]
- rest_mesh = meshes[1]
+ trimeshes = gh.divide_mesh_by_plane(rest_trimesh, normal_plane, point_plane)
+ storey = trimeshes[0]
+ rest_trimesh = trimeshes[1]
storeys.append(storey)
- storeys.append(rest_mesh)
+ storeys.append(rest_trimesh)
return storeys
@property
diff --git a/exports/exports_factory.py b/exports/exports_factory.py
new file mode 100644
index 00000000..04f2f9be
--- /dev/null
+++ b/exports/exports_factory.py
@@ -0,0 +1,58 @@
+"""
+ExportsFactory export a city into several formats
+SPDX - License - Identifier: LGPL - 3.0 - or -later
+Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
+"""
+
+from exports.formats.stl import Stl
+from exports.formats.obj import Obj
+
+class ExportsFactory:
+ """
+ Exports factory class
+ """
+ def __init__(self, export_type, city, path):
+ self._city = city
+ self._export_type = '_' + export_type.lower()
+ self._path = path
+
+ @property
+ def _citygml(self):
+ """
+ Export to citygml with application domain extensions
+ :return: None
+ """
+ raise NotImplementedError()
+
+ @property
+ def _stl(self):
+ """
+ Export the city geometry to stl
+ :return: None
+ """
+ return Stl(self._city, self._path)
+
+ @property
+ def _obj(self):
+ """
+ Export the city geometry to obj
+ :return: None
+ """
+ return Obj(self._city, self._path)
+
+ @property
+ def _idf(self):
+ """
+ Export the city to Energy+ idf format
+ :return:
+ """
+ raise NotImplementedError()
+
+ @property
+ def export(self):
+ """
+ Export the city model structure to the given export type
+ :return: City
+ """
+ return getattr(self, self._export_type, lambda: None)
+
diff --git a/exports/idf_helper.py b/exports/formats/idf.py
similarity index 99%
rename from exports/idf_helper.py
rename to exports/formats/idf.py
index 1c5efbf2..d5758911 100644
--- a/exports/idf_helper.py
+++ b/exports/formats/idf.py
@@ -10,7 +10,7 @@ from pathlib import Path
import helpers.constants as cte
-class IdfHelper:
+class Idf:
_THERMOSTAT = 'HVACTEMPLATE:THERMOSTAT'
_IDEAL_LOAD_AIR_SYSTEM = 'HVACTEMPLATE:ZONE:IDEALLOADSAIRSYSTEM'
_SURFACE = 'BUILDINGSURFACE:DETAILED'
diff --git a/exports/formats/obj.py b/exports/formats/obj.py
new file mode 100644
index 00000000..56e30706
--- /dev/null
+++ b/exports/formats/obj.py
@@ -0,0 +1,5 @@
+from exports.formats.triangular import Triangular
+
+class Obj(Triangular):
+ def __init__(self, city, path):
+ super().__init__(city, path, 'obj')
diff --git a/exports/formats/stl.py b/exports/formats/stl.py
new file mode 100644
index 00000000..915d455d
--- /dev/null
+++ b/exports/formats/stl.py
@@ -0,0 +1,5 @@
+from exports.formats.triangular import Triangular
+
+class Stl(Triangular):
+ def __init__(self, city, path):
+ super().__init__(city, path, 'stl')
diff --git a/exports/formats/triangular.py b/exports/formats/triangular.py
new file mode 100644
index 00000000..de5b9ec4
--- /dev/null
+++ b/exports/formats/triangular.py
@@ -0,0 +1,21 @@
+from pathlib import Path
+from trimesh import Trimesh
+
+class Triangular:
+ def __init__(self, city, path, triangular_format):
+ self._city = city
+ self._path = path
+ self._triangular_format = triangular_format
+ self._files()
+
+ def _files(self):
+ if self._city.name is None:
+ self._city.name = 'unknown_city'
+ file_name = self._city.name + '.' + self._triangular_format
+ file_path = (Path(self._path).resolve() / file_name).resolve()
+ print(file_path)
+ trimesh = Trimesh()
+ for building in self._city.buildings:
+ trimesh = trimesh.union(building.simplified_polyhedron.trimesh)
+ with open(file_path, 'w') as file:
+ file.write(trimesh.export(file_type=self._triangular_format))
diff --git a/tests/test_exports.py b/tests/test_exports.py
new file mode 100644
index 00000000..99ddb926
--- /dev/null
+++ b/tests/test_exports.py
@@ -0,0 +1,39 @@
+"""
+TestExports test and validate the city export formats
+SPDX - License - Identifier: LGPL - 3.0 - or -later
+Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
+"""
+
+from pathlib import Path
+from unittest import TestCase
+from imports.geometry_factory import GeometryFactory
+from exports.exports_factory import ExportsFactory
+
+class TestExports(TestCase):
+ """
+ TestGeometryFactory TestCase 1
+ """
+ def setUp(self) -> None:
+ """
+ Test setup
+ :return: None
+ """
+ self._city_gml = None
+ self._example_path = (Path(__file__).parent / 'tests_data').resolve()
+ self._output_path = (Path(__file__).parent / 'tests_outputs').resolve()
+
+ def _get_city(self):
+ if self._city_gml is None:
+ file_path = (self._example_path / '20buildings.gml').resolve()
+ self._city_gml = GeometryFactory('citygml', file_path).city
+ return self._city_gml
+
+ def _export(self, export_type):
+ self._city_gml = self._get_city()
+ ExportsFactory(export_type, self._city_gml, self._output_path).export
+
+ def test_obj_export(self):
+ self._export('obj')
+
+ def test_stl_export(self):
+ self._export('stl')
diff --git a/tests/test_geometry_factory.py b/tests/test_geometry_factory.py
index 945e0eec..8d56a706 100644
--- a/tests/test_geometry_factory.py
+++ b/tests/test_geometry_factory.py
@@ -21,7 +21,7 @@ class TestGeometryFactory(TestCase):
:return: None
"""
self._city_gml = None
- self._example_path = (Path(__file__).parent.parent / 'tests_data').resolve()
+ self._example_path = (Path(__file__).parent / 'tests_data').resolve()
def _get_citygml(self, file):
if self._city_gml is None:
diff --git a/tests/test_idf.py b/tests/test_idf.py
index 87775f20..1b474107 100644
--- a/tests/test_idf.py
+++ b/tests/test_idf.py
@@ -9,7 +9,6 @@ from imports.geometry_factory import GeometryFactory
from imports.physics_factory import PhysicsFactory
from imports.usage_factory import UsageFactory
from imports.schedules_factory import SchedulesFactory
-from exports.idf_helper import IdfHelper
import os
import glob
@@ -25,8 +24,8 @@ class TestIdf(TestCase):
:return: None
"""
self._city_gml = None
- self._example_path = (Path(__file__).parent.parent / 'tests_data').resolve()
- self._output_path = (Path(__file__).parent / 'ep_outputs').resolve()
+ self._example_path = (Path(__file__).parent / 'tests_data').resolve()
+ self._output_path = (Path(__file__).parent / 'tests_outputs').resolve()
def _get_city(self):
if self._city_gml is None:
diff --git a/tests/test_physics_factory.py b/tests/test_physics_factory.py
index 991aa7d3..5ea71ea6 100644
--- a/tests/test_physics_factory.py
+++ b/tests/test_physics_factory.py
@@ -21,7 +21,7 @@ class TestPhysicsFactory(TestCase):
"""
self._city_gml = None
self._nyc_with_physics = None
- self._example_path = (Path(__file__).parent.parent / 'tests_data').resolve()
+ self._example_path = (Path(__file__).parent / 'tests_data').resolve()
def _get_citygml(self, file_path):
if self._city_gml is None:
diff --git a/tests/test_schedules_factory.py b/tests/test_schedules_factory.py
index 23aa08a6..3894d5a2 100644
--- a/tests/test_schedules_factory.py
+++ b/tests/test_schedules_factory.py
@@ -23,7 +23,7 @@ class TestSchedulesFactory(TestCase):
:return: None
"""
self._city_gml_with_usage = None
- self._example_path = (Path(__file__).parent.parent / 'tests_data').resolve()
+ self._example_path = (Path(__file__).parent / 'tests_data').resolve()
@property
def _handler(self):
diff --git a/tests/test_usage_factory.py b/tests/test_usage_factory.py
index 2f671b27..e6f01e0e 100644
--- a/tests/test_usage_factory.py
+++ b/tests/test_usage_factory.py
@@ -21,7 +21,7 @@ class TestUsageFactory(TestCase):
"""
self._city_gml = None
self._nyc_with_usage = None
- self._example_path = (Path(__file__).parent.parent / 'tests_data').resolve()
+ self._example_path = (Path(__file__).parent / 'tests_data').resolve()
def _get_citygml(self, file_path):
if self._city_gml is None:
diff --git a/tests/test_weather_factory.py b/tests/test_weather_factory.py
index 0bc0f45e..0033ba28 100644
--- a/tests/test_weather_factory.py
+++ b/tests/test_weather_factory.py
@@ -22,7 +22,7 @@ class TestWeatherFactory(TestCase):
self._city_gml = None
self._city_with_weather = None
self._city_name = 'new_york_city'
- self._example_path = (Path(__file__).parent.parent / 'tests_data').resolve()
+ self._example_path = (Path(__file__).parent / 'tests_data').resolve()
def _get_citygml(self, file_path):
if self._city_gml is None:
@@ -32,7 +32,7 @@ class TestWeatherFactory(TestCase):
def _get_city_with_weather(self):
if self._city_with_weather is None:
- file_path = (Path(__file__).parent.parent / 'tests_data' / '20buildings.gml').resolve()
+ file_path = (Path(__file__).parent / 'tests_data' / '20buildings.gml').resolve()
self._city_with_weather = self._get_citygml(file_path)
WeatherFactory('dat', self._city_with_weather, city_name=self._city_name, base_path=self._example_path)
return self._city_with_weather
@@ -54,7 +54,7 @@ class TestWeatherFactory(TestCase):
self.assertFalse(values.empty, 'wrong value beam')
def test_weather_xls(self):
- file_path = (Path(__file__).parent.parent / 'tests_data' / 'iso_52016_1_2017_lod2.gml').resolve()
+ file_path = (Path(__file__).parent / 'tests_data' / 'iso_52016_1_2017_lod2.gml').resolve()
city_with_weather = self._get_citygml(file_path)
WeatherFactory('xls', city_with_weather, city_name=self._city_name, base_path=self._example_path)
for building in city_with_weather.buildings:
diff --git a/tests_data/20190815_mitte_out_MC_FloursurfaceADD.gml b/tests/tests_data/20190815_mitte_out_MC_FloursurfaceADD.gml
similarity index 100%
rename from tests_data/20190815_mitte_out_MC_FloursurfaceADD.gml
rename to tests/tests_data/20190815_mitte_out_MC_FloursurfaceADD.gml
diff --git a/tests_data/20buildings.gml b/tests/tests_data/20buildings.gml
similarity index 100%
rename from tests_data/20buildings.gml
rename to tests/tests_data/20buildings.gml
diff --git a/tests_data/EngHT_Flat_model_lod1.gml b/tests/tests_data/EngHT_Flat_model_lod1.gml
similarity index 100%
rename from tests_data/EngHT_Flat_model_lod1.gml
rename to tests/tests_data/EngHT_Flat_model_lod1.gml
diff --git a/tests_data/ISO_52016_1_BESTEST_ClimData_2016.08.24.xls b/tests/tests_data/ISO_52016_1_BESTEST_ClimData_2016.08.24.xls
similarity index 100%
rename from tests_data/ISO_52016_1_BESTEST_ClimData_2016.08.24.xls
rename to tests/tests_data/ISO_52016_1_BESTEST_ClimData_2016.08.24.xls
diff --git a/tests_data/bld100087.gml b/tests/tests_data/bld100087.gml
similarity index 100%
rename from tests_data/bld100087.gml
rename to tests/tests_data/bld100087.gml
diff --git a/tests_data/building_lod2.gml b/tests/tests_data/building_lod2.gml
similarity index 100%
rename from tests_data/building_lod2.gml
rename to tests/tests_data/building_lod2.gml
diff --git a/tests_data/buildings.gml b/tests/tests_data/buildings.gml
similarity index 100%
rename from tests_data/buildings.gml
rename to tests/tests_data/buildings.gml
diff --git a/tests_data/energy+.idd b/tests/tests_data/energy+.idd
similarity index 100%
rename from tests_data/energy+.idd
rename to tests/tests_data/energy+.idd
diff --git a/tests_data/inseldb_new_york_city.dat b/tests/tests_data/inseldb_new_york_city.dat
similarity index 100%
rename from tests_data/inseldb_new_york_city.dat
rename to tests/tests_data/inseldb_new_york_city.dat
diff --git a/tests_data/iso_52016_1_2017_lod2.gml b/tests/tests_data/iso_52016_1_2017_lod2.gml
similarity index 100%
rename from tests_data/iso_52016_1_2017_lod2.gml
rename to tests/tests_data/iso_52016_1_2017_lod2.gml
diff --git a/tests_data/lod2_buildings.gml b/tests/tests_data/lod2_buildings.gml
similarity index 100%
rename from tests_data/lod2_buildings.gml
rename to tests/tests_data/lod2_buildings.gml
diff --git a/tests_data/minimal.idf b/tests/tests_data/minimal.idf
similarity index 100%
rename from tests_data/minimal.idf
rename to tests/tests_data/minimal.idf
diff --git a/tests_data/montreal.epw b/tests/tests_data/montreal.epw
similarity index 100%
rename from tests_data/montreal.epw
rename to tests/tests_data/montreal.epw
diff --git a/tests_data/subway.osm b/tests/tests_data/subway.osm
similarity index 100%
rename from tests_data/subway.osm
rename to tests/tests_data/subway.osm
diff --git a/tests/tests_outputs/.gitignore b/tests/tests_outputs/.gitignore
new file mode 100644
index 00000000..86d0cb27
--- /dev/null
+++ b/tests/tests_outputs/.gitignore
@@ -0,0 +1,4 @@
+# Ignore everything in this directory
+*
+# Except this file
+!.gitignore
\ No newline at end of file