forked from s_ranjbar/city_retrofit
testing building separation in storeys with the new configuration of geometry using polygons and polyhedrons (NOT working yet).
This commit is contained in:
parent
dbbe3d56fc
commit
9a40cfa54b
|
@ -376,8 +376,7 @@ class Polyhedron:
|
|||
self._max_z = ConfigurationHelper().min_coordinate
|
||||
for polygon in self._polygons:
|
||||
for point in polygon.points:
|
||||
if self._max_z < point[2]:
|
||||
self._max_z = point[2]
|
||||
self._max_z = max(self._max_z, point[2])
|
||||
return self._max_z
|
||||
|
||||
@property
|
||||
|
@ -450,15 +449,14 @@ class Polyhedron:
|
|||
return self._min_x
|
||||
|
||||
@property
|
||||
def center(self):
|
||||
def centroid(self):
|
||||
"""
|
||||
Polyhedron centroid
|
||||
:return: [x,y,z]
|
||||
"""
|
||||
x = (self.max_x + self.min_x) / 2
|
||||
y = (self.max_y + self.min_y) / 2
|
||||
z = (self.max_z + self.min_z) / 2
|
||||
return [x, y, z]
|
||||
if self._centroid is None:
|
||||
self._centroid = self.trimesh.centroid
|
||||
return self._centroid
|
||||
|
||||
def stl_export(self, full_path):
|
||||
"""
|
||||
|
|
|
@ -14,6 +14,9 @@ from city_model_structure.attributes.thermal_zone import ThermalZone
|
|||
from city_model_structure.attributes.usage_zone import UsageZone
|
||||
from city_model_structure.city_object import CityObject
|
||||
from helpers.geometry_helper import GeometryHelper as gh
|
||||
from helpers.configuration_helper import ConfigurationHelper
|
||||
import math
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class Building(CityObject):
|
||||
|
@ -21,15 +24,14 @@ class Building(CityObject):
|
|||
Building(CityObject) class
|
||||
"""
|
||||
def __init__(self, name, lod, surfaces, terrains, year_of_construction, function, city_lower_corner):
|
||||
# todo: take the default values out of the classes!!
|
||||
super().__init__(lod, surfaces, name)
|
||||
self._basement_heated = None
|
||||
self._attic_heated = None
|
||||
self._terrains = terrains
|
||||
self._year_of_construction = year_of_construction
|
||||
self._function = function
|
||||
#todo: change lower_corner to building lower_corner instead city lower corner
|
||||
self._lower_corner = city_lower_corner
|
||||
self._city_lower_corner = city_lower_corner
|
||||
self._building_lower_corner = None
|
||||
self._heated = None
|
||||
self._cooled = None
|
||||
self._average_storey_height = None
|
||||
|
@ -43,6 +45,10 @@ class Building(CityObject):
|
|||
self._global_horizontal = dict()
|
||||
self._diffuse = dict()
|
||||
self._beam = dict()
|
||||
self._min_x = ConfigurationHelper().max_coordinate
|
||||
self._min_y = ConfigurationHelper().max_coordinate
|
||||
self._min_z = ConfigurationHelper().max_coordinate
|
||||
self._centroid = None
|
||||
|
||||
# ToDo: Check this for LOD4
|
||||
self._thermal_zones = []
|
||||
|
@ -54,8 +60,10 @@ class Building(CityObject):
|
|||
t_zones.bounded = [ThermalBoundary(s, [t_zones]) for s in t_zones.surfaces]
|
||||
surface_id = 0
|
||||
for surface in self.surfaces:
|
||||
surface.lower_corner = self._lower_corner
|
||||
surface.parent(self, surface_id)
|
||||
self._min_x = min(self._min_x, surface.min_x)
|
||||
self._min_y = min(self._min_y, surface.min_y)
|
||||
self._min_z = min(self._min_z, surface.min_z)
|
||||
surface_id += 1
|
||||
|
||||
@property
|
||||
|
@ -303,24 +311,47 @@ class Building(CityObject):
|
|||
"""
|
||||
self._beam = value
|
||||
|
||||
@property
|
||||
def building_lower_corner(self):
|
||||
if self._building_lower_corner is None:
|
||||
self._building_lower_corner = [self._min_x, self._min_y, self._min_z]
|
||||
return self._building_lower_corner
|
||||
|
||||
@property
|
||||
def storeys(self):
|
||||
storeys = []
|
||||
# todo: these values are not read yet from the files
|
||||
# number_of_storeys = self.storeys_above_ground
|
||||
# height = self.average_storey_height
|
||||
number_of_storeys = 4
|
||||
height = 1.5
|
||||
height = self.average_storey_height
|
||||
if self.storeys_above_ground is not None:
|
||||
number_of_storeys = self.storeys_above_ground
|
||||
else:
|
||||
number_of_storeys = math.floor(float(self.max_height) / height) + 1
|
||||
print('number_of_storeys', number_of_storeys)
|
||||
last_storey_height = float(self.max_height) - height*(number_of_storeys-1)
|
||||
print('last_storey_height', last_storey_height)
|
||||
if last_storey_height < height/2:
|
||||
number_of_storeys -= 1
|
||||
print('number storeys', number_of_storeys)
|
||||
trimesh = self.simplified_polyhedron.trimesh
|
||||
normal_plane = [0, 0, -1]
|
||||
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)]
|
||||
print(n)
|
||||
point_plane = [self.building_lower_corner[0], self.building_lower_corner[1],
|
||||
self.building_lower_corner[2] + height*(n+1)]
|
||||
print('point plane', point_plane)
|
||||
print('rest trimesh', rest_trimesh.volume)
|
||||
trimeshes = gh.divide_mesh_by_plane(rest_trimesh, normal_plane, point_plane)
|
||||
print('number meshes', len(trimeshes))
|
||||
storey = trimeshes[0]
|
||||
file_name = 'storey_' + str(n) + '.obj'
|
||||
path_name = (Path(__file__).parent.parent / 'tests' / 'tests_outputs' / file_name).resolve()
|
||||
with open(path_name, 'w') as file:
|
||||
file.write(storey.export(file_type='obj'))
|
||||
rest_trimesh = trimeshes[1]
|
||||
file_name = 'rest_trimesh_' + str(n) + '.obj'
|
||||
path_name = (Path(__file__).parent.parent / 'tests' / 'tests_outputs' / file_name).resolve()
|
||||
with open(path_name, 'w') as file:
|
||||
file.write(rest_trimesh.export(file_type='obj'))
|
||||
storeys.append(storey)
|
||||
storeys.append(rest_trimesh)
|
||||
return storeys
|
||||
|
@ -338,7 +369,8 @@ class Building(CityObject):
|
|||
self._floor_area += surface.perimeter_polygon.area
|
||||
return self._floor_area
|
||||
|
||||
# todo: erase this function, only for rabeehs case
|
||||
@floor_area.setter
|
||||
def floor_area(self, value):
|
||||
self._floor_area = value
|
||||
@property
|
||||
def centroid(self):
|
||||
if self._centroid is None:
|
||||
self._centroid = self.simplified_polyhedron.centroid
|
||||
return self._centroid
|
||||
|
|
|
@ -15,7 +15,6 @@ from city_model_structure.building import Building
|
|||
from city_model_structure.city_object import CityObject
|
||||
from helpers.geometry_helper import GeometryHelper
|
||||
import math
|
||||
import time
|
||||
|
||||
|
||||
class City:
|
||||
|
@ -191,7 +190,7 @@ class City:
|
|||
selected_region_upper_corner = [center[0] + radius, center[1] + radius, center[2] + radius]
|
||||
selected_region_city = City(selected_region_lower_corner, selected_region_upper_corner, srs_name=self.srs_name)
|
||||
for city_object in self.city_objects:
|
||||
location = city_object.location
|
||||
location = city_object.centroid
|
||||
distance = math.sqrt(math.pow(location[0]-center[0], 2) + math.pow(location[1]-center[1], 2)
|
||||
+ math.pow(location[2]-center[2], 2))
|
||||
if distance < radius:
|
||||
|
|
|
@ -88,12 +88,12 @@ class CityObject:
|
|||
return None
|
||||
|
||||
@property
|
||||
def location(self):
|
||||
def centroid(self):
|
||||
"""
|
||||
City object location
|
||||
:return: [x,y,z]
|
||||
"""
|
||||
return self.simplified_polyhedron.center
|
||||
return self.simplified_polyhedron.centroid
|
||||
|
||||
@property
|
||||
def max_height(self):
|
||||
|
|
|
@ -2,3 +2,4 @@
|
|||
[buildings]
|
||||
max_location_distance_for_shared_walls = 5.0
|
||||
min_coordinate = -1.7976931348623157e+308
|
||||
max_coordinate = 1.7976931348623157e+308
|
||||
|
|
|
@ -31,3 +31,11 @@ class ConfigurationHelper:
|
|||
:return: float
|
||||
"""
|
||||
return self._config.getfloat('buildings', 'min_coordinate')
|
||||
|
||||
@property
|
||||
def max_coordinate(self) -> float:
|
||||
"""
|
||||
Configured maximal coordinate value
|
||||
:return: float
|
||||
"""
|
||||
return self._config.getfloat('buildings', 'max_coordinate')
|
||||
|
|
42
tests/test_building.py
Normal file
42
tests/test_building.py
Normal file
|
@ -0,0 +1,42 @@
|
|||
"""
|
||||
Building test
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2020 Project Author Pilar Monsalvete Álvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
from pathlib import Path
|
||||
from unittest import TestCase
|
||||
from imports.geometry_factory import GeometryFactory
|
||||
|
||||
|
||||
class MyTestCase(TestCase):
|
||||
"""
|
||||
TestBuilding TestCase 1
|
||||
"""
|
||||
def setUp(self) -> None:
|
||||
"""
|
||||
Test setup
|
||||
:return: None
|
||||
"""
|
||||
self._city_gml = None
|
||||
self._example_path = (Path(__file__).parent / 'tests_data').resolve()
|
||||
|
||||
def _get_citygml(self, file):
|
||||
if self._city_gml is None:
|
||||
file_path = (self._example_path / file).resolve()
|
||||
self._city_gml = GeometryFactory('citygml', file_path)._city_debug
|
||||
self.assertIsNotNone(self._city_gml, 'city is none')
|
||||
return self._city_gml
|
||||
|
||||
def test_storeys_division(self):
|
||||
file = 'kelowna.gml'
|
||||
city = self._get_citygml(file)
|
||||
for building in city.buildings:
|
||||
if building.name == 'BLD126221':
|
||||
building.average_storey_height = 1.5
|
||||
print(building.name)
|
||||
print(building.volume)
|
||||
print(building.floor_area)
|
||||
print(building.max_height)
|
||||
print(building.centroid)
|
||||
print(len(building.storeys))
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
TestGeometryFactory test and validate the city model structure geometric parameters
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||
Contributors Pilar Monsalvete Álvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
@ -79,7 +80,7 @@ class TestGeometryFactory(TestCase):
|
|||
for building in city.buildings:
|
||||
self.assertIsNotNone(building.name, 'building name is none')
|
||||
self.assertIsNotNone(building.lod, 'building lod is none')
|
||||
self.assertIsNotNone(building.location, 'building location is none')
|
||||
self.assertIsNotNone(building.centroid, 'building centroid is none')
|
||||
self.assertIsNotNone(building.year_of_construction, 'building year_of_construction is none')
|
||||
self.assertIsNotNone(building.function, 'building function is none')
|
||||
self.assertIsNotNone(building.volume, 'building volume is none')
|
||||
|
@ -223,17 +224,6 @@ class TestGeometryFactory(TestCase):
|
|||
for building in city.buildings:
|
||||
self.assertIsNotNone(building.volume, 'building volume is none')
|
||||
|
||||
def test_divide_mesh_by_plane(self):
|
||||
file = 'FZK-Haus-LoD-all-KIT-IAI-KHH-B36-V1.gml'
|
||||
# todo @Guille: this file has 5 lods (0, 1, 2, 3 and 4), all as one single city_object.
|
||||
# Only lod1 is read and saved
|
||||
city = self._get_citygml(file)
|
||||
for building in city.buildings:
|
||||
print(building.name)
|
||||
print(building.volume)
|
||||
print(building.thermal_zones[0].floor_area)
|
||||
print(len(building.storeys))
|
||||
|
||||
def test_surface(self):
|
||||
coordinates = '0.0 0.0 0.0 0.0 4.0 0.0 4.0 4.0 0.0 4.0 0.0 0.0 0.0 0.0 0.0 ' \
|
||||
'1.0 1.0 0.0 2.0 1.0 0.0 2.0 2.0 0.0 1.0 2.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 ' \
|
||||
|
|
Loading…
Reference in New Issue
Block a user