Expose camera type to UI and automatically update IFC camera type on drawing activation

Noticed fixing #6670 that though example project in this issue had camera named "PERSPECTIVE" but it was saved to IFC as orthogonal and there is no straightforward way to change it, besides changing Blender camera props and updating representation.

Example - https://imgur.com/a/GQ9A3EK

It's kind of exposed to UI now, but there's still bunch of issues with it to address.
This commit is contained in:
Andrej730
2025-05-07 12:47:14 +05:00
parent 41eadf735e
commit 1619ae8543
5 changed files with 43 additions and 9 deletions
@@ -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(
+31 -4
View File
@@ -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,
@@ -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":
+2 -2
View File
@@ -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
+2 -3
View File
@@ -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)