From 638d200a279528dfdd4e74681a1bfdf3b4871a19 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Fri, 23 Aug 2024 14:24:53 +0500 Subject: [PATCH] fix error switching to point cloud representation Previously it wasn't handled and would always result in errors. It seems the only way to load point cloud representation to BBIM was by loading IFC file and only if this is the only representation of the element. --- src/bonsai/bonsai/bim/import_ifc.py | 24 ++++-------------------- src/bonsai/bonsai/tool/geometry.py | 13 ++++++++++--- src/bonsai/bonsai/tool/loader.py | 20 ++++++++++++++++++++ 3 files changed, 34 insertions(+), 23 deletions(-) diff --git a/src/bonsai/bonsai/bim/import_ifc.py b/src/bonsai/bonsai/bim/import_ifc.py index 6dd8d2e940..c5eae6c4d9 100644 --- a/src/bonsai/bonsai/bim/import_ifc.py +++ b/src/bonsai/bonsai/bim/import_ifc.py @@ -827,28 +827,12 @@ class IfcImporter: def create_pointcloud( self, product: ifcopenshell.entity_instance, representation: ifcopenshell.entity_instance ) -> Union[ifcopenshell.entity_instance, None]: - placement_matrix = self.get_element_matrix(product) - vertex_list = [] - for item in representation.Items: - if item.is_a("IfcCartesianPointList3D"): - vertex_list.extend( - mathutils.Vector(list(coordinates)) * self.unit_scale for coordinates in item.CoordList - ) - elif item.is_a("IfcCartesianPointList2D"): - vertex_list.extend( - mathutils.Vector(list(coordinates)).to_3d() * self.unit_scale for coordinates in item.CoordList - ) - elif item.is_a("IfcCartesianPoint"): - vertex_list.append(mathutils.Vector(list(item.Coordinates)) * self.unit_scale) - - if len(vertex_list) == 0: - return None - - mesh_name = tool.Geometry.get_representation_name(representation) - mesh = bpy.data.meshes.new(mesh_name) - mesh.from_pydata(vertex_list, [], []) + mesh = tool.Loader.create_point_cloud_mesh(representation) + if mesh is None: + return tool.Ifc.link(representation, mesh) + placement_matrix = self.get_element_matrix(product) obj = bpy.data.objects.new(tool.Loader.get_name(product), mesh) self.set_matrix_world(obj, tool.Loader.apply_blender_offset_to_matrix_world(obj, placement_matrix)) self.link_element(product, obj) diff --git a/src/bonsai/bonsai/tool/geometry.py b/src/bonsai/bonsai/tool/geometry.py index 910b921550..59bcdc0173 100644 --- a/src/bonsai/bonsai/tool/geometry.py +++ b/src/bonsai/bonsai/tool/geometry.py @@ -585,6 +585,16 @@ class Geometry(bonsai.core.tool.Geometry): settings.set("keep-bounding-boxes", True) context = representation.ContextOfItems + ifc_importer = bonsai.bim.import_ifc.IfcImporter(ifc_import_settings) + ifc_importer.file = tool.Ifc.get() + + # create_shape doesn't support point cloud representations. + if representation.RepresentationType in ("PointCloud", "Point"): + mesh = tool.Loader.create_point_cloud_mesh(representation) + if mesh is None: + raise Exception(f"Failed to process point cloud representation: {representation}.") + return mesh + if element.is_a("IfcTypeProduct"): # You may only specify a single representation when creating shapes for types try: @@ -606,9 +616,6 @@ class Geometry(bonsai.core.tool.Geometry): settings.set("dimensionality", ifcopenshell.ifcopenshell_wrapper.CURVES_SURFACES_AND_SOLIDS) shape = ifcopenshell.geom.create_shape(settings, element, representation) - ifc_importer = bonsai.bim.import_ifc.IfcImporter(ifc_import_settings) - ifc_importer.file = tool.Ifc.get() - if element.is_a("IfcAnnotation") and element.ObjectType == "DRAWING": mesh = ifc_importer.create_camera(element, shape) if element.is_a("IfcAnnotation") and ifc_importer.is_curve_annotation(element): diff --git a/src/bonsai/bonsai/tool/loader.py b/src/bonsai/bonsai/tool/loader.py index 10fba187fb..8afbbae24b 100644 --- a/src/bonsai/bonsai/tool/loader.py +++ b/src/bonsai/bonsai/tool/loader.py @@ -651,6 +651,26 @@ class Loader(bonsai.core.tool.Loader): except: pass + @classmethod + def create_point_cloud_mesh(cls, representation: ifcopenshell.entity_instance) -> Union[bpy.types.Mesh, None]: + unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get()) + vertex_list = [] + for item in representation.Items: + if item.is_a("IfcCartesianPointList3D"): + vertex_list.extend(Vector(list(coordinates)) * unit_scale for coordinates in item.CoordList) + elif item.is_a("IfcCartesianPointList2D"): + vertex_list.extend(Vector(list(coordinates)).to_3d() * unit_scale for coordinates in item.CoordList) + elif item.is_a("IfcCartesianPoint"): + vertex_list.append(Vector(list(item.Coordinates)) * unit_scale) + + if len(vertex_list) == 0: + return None + + mesh_name = tool.Geometry.get_representation_name(representation) + mesh = bpy.data.meshes.new(mesh_name) + mesh.from_pydata(vertex_list, [], []) + return mesh + @classmethod def get_offset_point(cls, ifc_file: ifcopenshell.file) -> Union[npt.NDArray[np.float64], None]: elements_checked = 0