Citygml can now generate the envelop out of the buildings

This commit is contained in:
Guille Gutierrez 2022-06-07 13:31:35 -04:00
parent 88eb9006ea
commit 920d95eef2
6 changed files with 70 additions and 26 deletions

View File

@ -115,7 +115,7 @@ class Idf:
lower_z = lower_corner[2] lower_z = lower_corner[2]
points_list = [] points_list = []
for point in points: for point in points:
point_tuple = (point[0]-lower_x, point[1]-lower_y, point[2]-lower_z) point_tuple = (point[0] - lower_x, point[1] - lower_y, point[2] - lower_z)
points_list.append(point_tuple) points_list.append(point_tuple)
return points_list return points_list
@ -279,7 +279,7 @@ class Idf:
def _add_window_construction_and_material(self, thermal_opening): def _add_window_construction_and_material(self, thermal_opening):
for window_material in self._idf.idfobjects[self._WINDOW_MATERIAL_SIMPLE]: for window_material in self._idf.idfobjects[self._WINDOW_MATERIAL_SIMPLE]:
if window_material['UFactor'] == thermal_opening.overall_u_value and \ if window_material['UFactor'] == thermal_opening.overall_u_value and \
window_material['Solar_Heat_Gain_Coefficient'] == thermal_opening.g_value: window_material['Solar_Heat_Gain_Coefficient'] == thermal_opening.g_value:
return return
order = str(len(self._idf.idfobjects[self._WINDOW_MATERIAL_SIMPLE]) + 1) order = str(len(self._idf.idfobjects[self._WINDOW_MATERIAL_SIMPLE]) + 1)
@ -407,7 +407,11 @@ class Idf:
Reporting_Frequency="Hourly", Reporting_Frequency="Hourly",
) )
self._idf.match() self._idf.match()
self._idf.intersect_match() try:
self._idf.intersect_match()
except IndexError:
# seems to be a bug from geomeppy when surfaces cannot be intersected
pass
self._idf.saveas(str(self._output_file)) self._idf.saveas(str(self._output_file))
return self._idf return self._idf
@ -482,7 +486,7 @@ class Idf:
for material in self._idf.idfobjects[self._WINDOW_MATERIAL_SIMPLE]: for material in self._idf.idfobjects[self._WINDOW_MATERIAL_SIMPLE]:
if material['Name'] == glazing: if material['Name'] == glazing:
if material['UFactor'] == opening.overall_u_value and \ if material['UFactor'] == opening.overall_u_value and \
material['Solar_Heat_Gain_Coefficient'] == opening.g_value: material['Solar_Heat_Gain_Coefficient'] == opening.g_value:
return True return True
return False return False

View File

@ -4,6 +4,9 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group Copyright © 2022 Concordia CERC group
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
""" """
import math
import sys
import numpy as np import numpy as np
import xmltodict import xmltodict
from city_model_structure.city import City from city_model_structure.city import City
@ -22,6 +25,8 @@ class CityGml:
self._city = None self._city = None
self._lod1_tags = ['lod1Solid', 'lod1MultiSurface'] self._lod1_tags = ['lod1Solid', 'lod1MultiSurface']
self._lod2_tags = ['lod2Solid', 'lod2MultiSurface', 'lod2MultiCurve'] self._lod2_tags = ['lod2Solid', 'lod2MultiSurface', 'lod2MultiCurve']
self._lower_corner = None
self._upper_corner = None
with open(path) as gml: with open(path) as gml:
# Clean the namespaces is an important task to prevent wrong ns:field due poor citygml_classes implementations # Clean the namespaces is an important task to prevent wrong ns:field due poor citygml_classes implementations
force_list = ('cityObjectMember', 'curveMember', 'boundedBy', 'surfaceMember', 'consistsOfBuildingPart') force_list = ('cityObjectMember', 'curveMember', 'boundedBy', 'surfaceMember', 'consistsOfBuildingPart')
@ -48,17 +53,45 @@ class CityGml:
self._city_objects = None self._city_objects = None
self._geometry = GeometryHelper() self._geometry = GeometryHelper()
if 'boundedBy' in self._gml['CityModel']:
for bound in self._gml['CityModel']['boundedBy']: for bound in self._gml['CityModel']['boundedBy']:
envelope = bound['Envelope'] envelope = bound['Envelope']
if '#text' in envelope['lowerCorner']: if '#text' in envelope['lowerCorner']:
self._lower_corner = np.fromstring(envelope['lowerCorner']['#text'], dtype=float, sep=' ') self._lower_corner = np.fromstring(envelope['lowerCorner']['#text'], dtype=float, sep=' ')
self._upper_corner = np.fromstring(envelope['upperCorner']['#text'], dtype=float, sep=' ') self._upper_corner = np.fromstring(envelope['upperCorner']['#text'], dtype=float, sep=' ')
else: else:
self._lower_corner = np.fromstring(envelope['lowerCorner'], dtype=float, sep=' ') self._lower_corner = np.fromstring(envelope['lowerCorner'], dtype=float, sep=' ')
self._upper_corner = np.fromstring(envelope['upperCorner'], dtype=float, sep=' ') self._upper_corner = np.fromstring(envelope['upperCorner'], dtype=float, sep=' ')
if '@srsName' in envelope: if '@srsName' in envelope:
self._srs_name = envelope['@srsName'] self._srs_name = envelope['@srsName']
else:
# get the boundary from the city objects instead
for city_object_member in self._gml['CityModel']['cityObjectMember']:
city_object = city_object_member['Building']
if 'boundedBy' in city_object:
for bound in city_object['boundedBy']:
if 'Envelope' not in bound:
continue
envelope = bound['Envelope']
self._srs_name = envelope['@srsName']
lower_corner = None
upper_corner = None
if '#text' in envelope['lowerCorner']:
lower_corner = np.fromstring(envelope['lowerCorner']['#text'], dtype=float, sep=' ')
upper_corner = np.fromstring(envelope['upperCorner']['#text'], dtype=float, sep=' ')
else:
lower_corner = np.fromstring(envelope['lowerCorner'], dtype=float, sep=' ')
upper_corner = np.fromstring(envelope['upperCorner'], dtype=float, sep=' ')
if self._lower_corner is None:
self._lower_corner = lower_corner
self._upper_corner = upper_corner
else:
self._lower_corner[0] = min(self._lower_corner[0], lower_corner[0])
self._lower_corner[1] = min(self._lower_corner[1], lower_corner[1])
self._lower_corner[2] = min(self._lower_corner[2], lower_corner[2])
self._upper_corner[0] = max(self._upper_corner[0], upper_corner[0])
self._upper_corner[1] = max(self._upper_corner[1], upper_corner[1])
self._upper_corner[2] = max(self._upper_corner[2], upper_corner[2])
@property @property
def content(self): def content(self):

View File

@ -48,19 +48,26 @@ class CityGmlLod2(CityGmlBase):
try: try:
surface_encoding, surface_subtype = cls._surface_encoding(bounded[surface_type]) surface_encoding, surface_subtype = cls._surface_encoding(bounded[surface_type])
except NotImplementedError: except NotImplementedError:
continue continue
for member in bounded[surface_type][surface_encoding][surface_subtype]['surfaceMember']: for member in bounded[surface_type][surface_encoding][surface_subtype]['surfaceMember']:
if '@srsDimension' in member['Polygon']['exterior']['LinearRing']['posList']: if 'CompositeSurface' in member:
gml_points = member['Polygon']['exterior']['LinearRing']['posList']["#text"] for composite_members in member['CompositeSurface']['surfaceMember']:
for composite_member in composite_members['CompositeSurface']['surfaceMember']:
surfaces.append(cls._add_member_surface(composite_member, surface_type))
else: else:
gml_points = member['Polygon']['exterior']['LinearRing']['posList'] surfaces.append(cls._add_member_surface(member, surface_type))
solid_points = cls._solid_points(cls._remove_last_point(gml_points))
polygon = Polygon(solid_points)
surface = Surface(polygon, polygon, surface_type=GeometryHelper.gml_surface_to_libs(surface_type))
surfaces.append(surface)
return surfaces return surfaces
@classmethod
def _add_member_surface(cls, member, surface_type):
if '@srsDimension' in member['Polygon']['exterior']['LinearRing']['posList']:
gml_points = member['Polygon']['exterior']['LinearRing']['posList']["#text"]
else:
gml_points = member['Polygon']['exterior']['LinearRing']['posList']
solid_points = cls._solid_points(cls._remove_last_point(gml_points))
polygon = Polygon(solid_points)
return Surface(polygon, polygon, surface_type=GeometryHelper.gml_surface_to_libs(surface_type))
@classmethod @classmethod
def _multi_curve(cls, city_object_member): def _multi_curve(cls, city_object_member):
raise NotImplementedError('multi curve') raise NotImplementedError('multi curve')

View File

@ -66,4 +66,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 Rhino(self._path).city return CityGml(self._path).city

View File

@ -41,7 +41,7 @@ class TestGeometryFactory(TestCase):
def _get_rhino(self, file): def _get_rhino(self, file):
file_path = (self._example_path / file).resolve() file_path = (self._example_path / file).resolve()
self._city = GeometryFactory('rhino', file_path).city_debug self._city = GeometryFactory('rhino', file_path).city
self.assertIsNotNone(self._city, 'city is none') self.assertIsNotNone(self._city, 'city is none')
return self._city return self._city

View File

@ -14,4 +14,4 @@ class TestConstructionCatalog(TestCase):
catalog = UsageCatalogFactory('comnet').catalog catalog = UsageCatalogFactory('comnet').catalog
self.assertIsNotNone(catalog, 'catalog is none') self.assertIsNotNone(catalog, 'catalog is none')
content = catalog.entries() content = catalog.entries()
self.assertEqual(len(content.usages), 33, 'Wrong number of usages') self.assertEqual(len(content.usages), 32, 'Wrong number of usages')