diff --git a/src/bonsai/bonsai/bim/module/drawing/handler.py b/src/bonsai/bonsai/bim/module/drawing/handler.py index 5c164b8c9e..75bf62d506 100644 --- a/src/bonsai/bonsai/bim/module/drawing/handler.py +++ b/src/bonsai/bonsai/bim/module/drawing/handler.py @@ -45,6 +45,10 @@ def set_active_camera_resolution(scene: bpy.types.Scene) -> None: return assert isinstance((camera := camera_obj.data), bpy.types.Camera) props = tool.Drawing.get_camera_props(camera) + + if camera.type != props.camera_type: + camera.type = props.camera_type + ortho_scale, aspect_ratio = props.get_scale_and_aspect_ratio() scene_render = scene.render if (camera.ortho_scale != ortho_scale) or not tool.Cad.is_x( diff --git a/src/bonsai/bonsai/bim/module/drawing/prop.py b/src/bonsai/bonsai/bim/module/drawing/prop.py index 3980271c93..992c20adde 100644 --- a/src/bonsai/bonsai/bim/module/drawing/prop.py +++ b/src/bonsai/bonsai/bim/module/drawing/prop.py @@ -46,7 +46,7 @@ from bpy.props import ( CollectionProperty, BoolVectorProperty, ) -from typing import TYPE_CHECKING, Literal, Any, Callable +from typing import TYPE_CHECKING, Literal, Any, Callable, get_args diagram_scales_enum = [] @@ -57,11 +57,11 @@ def purge(): diagram_scales_enum = [] -def update_target_view(self, context): +def update_target_view(self: "DocProperties", context: bpy.types.Context) -> None: DrawingsData.data["location_hint"] = DrawingsData.location_hint() -def get_location_hint(self, context): +def get_location_hint(self: "DocProperties", context: bpy.types.Context) -> list[tuple[str, str, str]]: if not DrawingsData.is_loaded: DrawingsData.load() return DrawingsData.data["location_hint"] @@ -232,6 +232,12 @@ def update_has_linework(self: "BIMCameraProperties", context: bpy.types.Context) update_layer(self, context, "HasLinework", self.has_linework) +def update_target_view(self: "BIMCameraProperties", context: bpy.types.Context) -> None: + if self.target_view != "MODEL_VIEW": + self.camera_type = "ORTHO" + update_layer(self, context, "TargetView", self.target_view) + + def update_dpi(self: "BIMCameraProperties", context: bpy.types.Context) -> None: update_layer(self, context, "DPI", self.dpi) @@ -497,6 +503,18 @@ def update_width_height(self: "BIMCameraProperties", context: bpy.types.Context) self.update_camera_resolution() +def update_camera_type(self: "BIMCameraProperties", context: bpy.types.Context) -> None: + assert isinstance(camera := self.id_data, bpy.types.Camera) + camera.type = self.camera_type + + +CameraType = Literal["PERSP", "ORTHO"] +CAMERA_TYPE_NAMES: dict[CameraType, str] = { + "PERSP": "Perspective", + "ORTHO": "Ortographic", +} + + class BIMCameraProperties(PropertyGroup): linework_mode: EnumProperty( items=[ @@ -547,7 +565,7 @@ class BIMCameraProperties(PropertyGroup): name="Target View", default="PLAN_VIEW", items=TARGET_VIEW_ITEMS, - update=get_update_layer_callback("target_view", "TargetView"), + update=update_target_view, ) representation: StringProperty(name="Representation") @@ -560,6 +578,13 @@ class BIMCameraProperties(PropertyGroup): dpi: IntProperty(name="DPI", default=75, update=update_dpi) width: FloatProperty(name="Width", default=50, subtype="DISTANCE", update=update_width_height) height: FloatProperty(name="Height", default=50, subtype="DISTANCE", update=update_width_height) + # Bonsai property is needed to prevent user from using unsupported panoramic camera. + camera_type: EnumProperty( + name="Camera Type", + default="ORTHO", + items=[(key, name, "") for key, name in CAMERA_TYPE_NAMES.items()], + update=update_camera_type, + ) is_nts: BoolProperty(name="Is NTS", update=update_is_nts) active_drawing_style_index: IntProperty(name="Active Drawing Style Index") filter_mode: StringProperty(name="Filter Mode", default="NONE") @@ -591,6 +616,7 @@ class BIMCameraProperties(PropertyGroup): dpi: int width: float height: float + camera_type: CameraType is_nts: bool active_drawing_style_index: int filter_mode: str @@ -618,6 +644,7 @@ class BIMCameraProperties(PropertyGroup): representation = json.dumps( { + "type": self.camera_type, "matrix": [[round_(v) for v in row] for row in matrix_world], "raster_x": self.raster_x, "raster_y": self.raster_y, diff --git a/src/bonsai/bonsai/bim/module/drawing/ui.py b/src/bonsai/bonsai/bim/module/drawing/ui.py index 0e7a95bdba..b81ac7f737 100644 --- a/src/bonsai/bonsai/bim/module/drawing/ui.py +++ b/src/bonsai/bonsai/bim/module/drawing/ui.py @@ -74,6 +74,10 @@ class BIM_PT_camera(Panel): row = self.layout.row(align=True) row.prop(props, "target_view") + if props.target_view == "MODEL_VIEW": + row = self.layout.row() + row.prop(props, "camera_type") + row = self.layout.row() row.prop(props, "linework_mode") if props.linework_mode == "OPENCASCADE": diff --git a/src/bonsai/bonsai/tool/drawing.py b/src/bonsai/bonsai/tool/drawing.py index a021b608c4..7e7f0b4c31 100644 --- a/src/bonsai/bonsai/tool/drawing.py +++ b/src/bonsai/bonsai/tool/drawing.py @@ -303,9 +303,9 @@ class Drawing(bonsai.core.tool.Drawing): camera.location = (0, 0, 1.5) # The view shall be 1.5m above the origin camera_data.show_limits = True if location_hint == "PERSPECTIVE": - camera_data.type = "PERSP" + props.camera_type = "PERSP" else: - camera_data.type = "ORTHO" + props.camera_type = "ORTHO" camera_data.ortho_scale = 50 # The default of 6m is too small camera_data.clip_start = 0.002 # 2mm is close to zero but allows any GPU-drawn lines to be visible. camera_data.clip_end = 10 # A slightly more reasonable default diff --git a/src/bonsai/bonsai/tool/loader.py b/src/bonsai/bonsai/tool/loader.py index 0af2d6316b..abac4ae622 100644 --- a/src/bonsai/bonsai/tool/loader.py +++ b/src/bonsai/bonsai/tool/loader.py @@ -830,9 +830,9 @@ class Loader(bonsai.core.tool.Loader): camera_type = "PERSP" camera = bpy.data.cameras.new(tool.Loader.get_mesh_name_from_shape(geometry)) - camera.type = camera_type - camera.show_limits = True props = tool.Drawing.get_camera_props(camera) + props.camera_type = camera_type + camera.show_limits = True if camera_type == "ORTHO": depth = ifcopenshell.util.shape.get_z(geometry) @@ -860,7 +860,6 @@ class Loader(bonsai.core.tool.Loader): camera.angle = fov tool.Drawing.import_camera_props(element, camera) - props = tool.Drawing.get_camera_props(camera) props.update_camera_resolution() # Only after all props are imported. mat = tool.Drawing.get_camera_shape_matrix(element, shape) props.update_representation(mat)