From 92f4cb0ffa89362203a16fb1721e35d6d80ab609 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Fri, 23 Aug 2024 16:23:03 +0500 Subject: [PATCH] fix error reloading camera representation After 4b4ede7 it was leading to non-existing code --- src/bonsai/bonsai/bim/module/drawing/prop.py | 7 +++ src/bonsai/bonsai/tool/drawing.py | 58 ++++---------------- src/bonsai/bonsai/tool/geometry.py | 2 +- src/bonsai/bonsai/tool/loader.py | 58 ++++++++++++++++++++ 4 files changed, 76 insertions(+), 49 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/drawing/prop.py b/src/bonsai/bonsai/bim/module/drawing/prop.py index a794ae720f..b0190e0165 100644 --- a/src/bonsai/bonsai/bim/module/drawing/prop.py +++ b/src/bonsai/bonsai/bim/module/drawing/prop.py @@ -68,6 +68,8 @@ def get_location_hint(self, context): def update_diagram_scale(self, context): + if not self.update_props: + return if not context.scene.camera or context.scene.camera.data != self.id_data: return element = tool.Ifc.get_entity(context.scene.camera) @@ -94,6 +96,8 @@ def update_diagram_scale(self, context): def update_is_nts(self, context): + if not self.update_props: + return if not context.scene.camera or context.scene.camera.data != self.id_data: return element = tool.Ifc.get_entity(context.scene.camera) @@ -220,6 +224,8 @@ def update_has_annotation(self, context): def update_layer(self, context, name, value): + if not self.update_props: + return if not context.scene.camera or context.scene.camera.data != self.id_data: return element = tool.Ifc.get_entity(context.scene.camera) @@ -400,6 +406,7 @@ class BIMCameraProperties(PropertyGroup): filter_mode: StringProperty(name="Filter Mode", default="NONE") include_filter_groups: CollectionProperty(type=BIMFilterGroup, name="Include Filter") exclude_filter_groups: CollectionProperty(type=BIMFilterGroup, name="Exclude Filter") + update_props: BoolProperty(name="Enable Props Auto Update", default=True) # For now, this JSON dump are all the parameters that determine a camera's "Block representation" # By checking this, you will know whether or not the camera IFC representation needs to be refreshed diff --git a/src/bonsai/bonsai/tool/drawing.py b/src/bonsai/bonsai/tool/drawing.py index 9e5eee0a96..0b8dc7533e 100644 --- a/src/bonsai/bonsai/tool/drawing.py +++ b/src/bonsai/bonsai/tool/drawing.py @@ -689,53 +689,15 @@ class Drawing(bonsai.core.tool.Drawing): def import_drawing(cls, drawing: ifcopenshell.entity_instance) -> bpy.types.Object: settings = ifcopenshell.geom.settings() - camera_type = "ORTHO" - body = ifcopenshell.util.representation.get_representation(drawing, "Model", "Body", "MODEL_VIEW") - if "IfcRectangularPyramid" in {e.is_a() for e in tool.Ifc.get().traverse(body)}: - camera_type = "PERSP" + representation = ifcopenshell.util.representation.get_representation(drawing, "Model", "Body", "MODEL_VIEW") + assert representation shape = ifcopenshell.geom.create_shape(settings, drawing) - geometry = shape.geometry - - v = geometry.verts - x = [v[i] for i in range(0, len(v), 3)] - y = [v[i + 1] for i in range(0, len(v), 3)] - z = [v[i + 2] for i in range(0, len(v), 3)] - width = max(x) - min(x) - height = max(y) - min(y) - depth = max(z) - min(z) - - camera = bpy.data.cameras.new(tool.Loader.get_mesh_name_from_shape(geometry)) - camera.type = camera_type - camera.show_limits = True - - if camera_type == "ORTHO": - camera.clip_start = 0.002 # Technically 0, but Blender doesn't allow this, so 2mm it is! - camera.clip_end = depth - - camera.BIMCameraProperties.width = width - camera.BIMCameraProperties.height = height - elif camera_type == "PERSP": - abs_min_z = abs(min(z)) - abs_max_z = abs(max(z)) - camera.clip_start = abs_max_z - camera.clip_end = abs_min_z - max_res = 1000 - - camera.BIMCameraProperties.width = width - camera.BIMCameraProperties.height = height - - if width > height: - fov = 2 * math.atan(width / (2 * abs_min_z)) - else: - fov = 2 * math.atan(height / (2 * abs_min_z)) - - camera.angle = fov - + camera = tool.Loader.create_camera(drawing, representation, shape) tool.Loader.link_mesh(shape, camera) obj = bpy.data.objects.new(tool.Loader.get_name(drawing), camera) - cls.import_camera_props(drawing, obj) + cls.import_camera_props(drawing, camera) tool.Ifc.link(drawing, obj) mat = Matrix(ifcopenshell.util.shape.get_shape_matrix(shape)) @@ -750,14 +712,14 @@ class Drawing(bonsai.core.tool.Drawing): return obj @classmethod - def import_camera_props(cls, drawing: ifcopenshell.entity_instance, obj: bpy.types.Object) -> None: + def import_camera_props(cls, drawing: ifcopenshell.entity_instance, camera: bpy.types.Camera) -> None: from bonsai.bim.module.drawing.prop import get_diagram_scales # Temporarily clear the definition id to prevent prop update callbacks to IFC. - ifc_definition_id = obj.BIMObjectProperties.ifc_definition_id - obj.BIMObjectProperties.ifc_definition_id = 0 + camera_props = camera.BIMCameraProperties + update_props = camera_props.update_props + camera_props.update_props = False - camera = obj.data camera.BIMCameraProperties.has_underlay = False camera.BIMCameraProperties.has_linework = True camera.BIMCameraProperties.has_annotation = True @@ -791,7 +753,7 @@ class Drawing(bonsai.core.tool.Drawing): if "IsNTS" in pset: camera.BIMCameraProperties.is_nts = bool(pset["IsNTS"]) - obj.BIMObjectProperties.ifc_definition_id = ifc_definition_id + camera_props.update_props = update_props @classmethod def import_drawings(cls) -> None: @@ -1906,7 +1868,7 @@ class Drawing(bonsai.core.tool.Drawing): if obj.name in element_obj_names or not tool.Ifc.get_entity(obj) ] - cls.import_camera_props(drawing, camera) + cls.import_camera_props(drawing, camera.data) for obj in selected_objects_before: obj.hide_set(False) diff --git a/src/bonsai/bonsai/tool/geometry.py b/src/bonsai/bonsai/tool/geometry.py index 59bcdc0173..2ab8d261e2 100644 --- a/src/bonsai/bonsai/tool/geometry.py +++ b/src/bonsai/bonsai/tool/geometry.py @@ -617,7 +617,7 @@ class Geometry(bonsai.core.tool.Geometry): shape = ifcopenshell.geom.create_shape(settings, element, representation) if element.is_a("IfcAnnotation") and element.ObjectType == "DRAWING": - mesh = ifc_importer.create_camera(element, shape) + mesh = tool.Loader.create_camera(element, representation, shape) if element.is_a("IfcAnnotation") and ifc_importer.is_curve_annotation(element): mesh = ifc_importer.create_curve(element, shape) elif shape: diff --git a/src/bonsai/bonsai/tool/loader.py b/src/bonsai/bonsai/tool/loader.py index 8afbbae24b..701ea6a83e 100644 --- a/src/bonsai/bonsai/tool/loader.py +++ b/src/bonsai/bonsai/tool/loader.py @@ -19,12 +19,14 @@ from __future__ import annotations import os import re +import math import bpy import bmesh import ifcopenshell.geom import ifcopenshell.util.element import ifcopenshell.util.geolocation import ifcopenshell.util.placement +import ifcopenshell.util.representation import ifcopenshell.util.shape import ifcopenshell.util.unit import bonsai.core.tool @@ -671,6 +673,62 @@ class Loader(bonsai.core.tool.Loader): mesh.from_pydata(vertex_list, [], []) return mesh + @classmethod + def create_camera( + cls, + element: ifcopenshell.entity_instance, + representation: ifcopenshell.entity_instance, + shape: Union[ifcopenshell.geom.ShapeElementType, ifcopenshell.geom.ShapeType], + ) -> bpy.types.Camera: + from bonsai.bim.module.drawing.prop import get_diagram_scales + + if isinstance(shape, ifcopenshell.geom.ShapeElementType): + geometry = shape.geometry + else: + geometry = shape + + v = geometry.verts + x = [v[i] for i in range(0, len(v), 3)] + y = [v[i + 1] for i in range(0, len(v), 3)] + z = [v[i + 2] for i in range(0, len(v), 3)] + width = max(x) - min(x) + height = max(y) - min(y) + depth = max(z) - min(z) + + camera_type = "ORTHO" + if "IfcRectangularPyramid" in {e.is_a() for e in tool.Ifc.get().traverse(representation)}: + camera_type = "PERSP" + + camera = bpy.data.cameras.new(tool.Loader.get_mesh_name_from_shape(geometry)) + camera.type = camera_type + camera.show_limits = True + + if camera_type == "ORTHO": + camera.clip_start = 0.002 # Technically 0, but Blender doesn't allow this, so 2mm it is! + camera.clip_end = depth + + camera.BIMCameraProperties.width = width + camera.BIMCameraProperties.height = height + elif camera_type == "PERSP": + abs_min_z = abs(min(z)) + abs_max_z = abs(max(z)) + camera.clip_start = abs_max_z + camera.clip_end = abs_min_z + max_res = 1000 + + camera.BIMCameraProperties.width = width + camera.BIMCameraProperties.height = height + + if width > height: + fov = 2 * math.atan(width / (2 * abs_min_z)) + else: + fov = 2 * math.atan(height / (2 * abs_min_z)) + + camera.angle = fov + + tool.Drawing.import_camera_props(element, camera) + return camera + @classmethod def get_offset_point(cls, ifc_file: ifcopenshell.file) -> Union[npt.NDArray[np.float64], None]: elements_checked = 0