This commit is contained in:
Andrej730
2025-04-22 11:19:09 +05:00
parent 5c4f157624
commit 8d31d93531
5 changed files with 120 additions and 78 deletions
@@ -2408,6 +2408,7 @@ class SaveDrawingStyle(bpy.types.Operator, tool.Ifc.Operator):
def execute(self, context): def execute(self, context):
space = self.get_view_3d(context) # Do not remove. It is used later in eval space = self.get_view_3d(context) # Do not remove. It is used later in eval
scene = context.scene scene = context.scene
assert scene
style = {} style = {}
eval_namespace = {"context": context, "scene": scene, "space": space} eval_namespace = {"context": context, "scene": scene, "space": space}
@@ -2445,7 +2446,9 @@ class SaveDrawingStyle(bpy.types.Operator, tool.Ifc.Operator):
if self.index: if self.index:
index = int(self.index) index = int(self.index)
else: else:
index = context.scene.camera.data.BIMCameraProperties.active_drawing_style_index assert (camera := scene.camera)
props = tool.Drawing.get_camera_props(camera)
index = props.active_drawing_style_index
props = tool.Drawing.get_document_props() props = tool.Drawing.get_document_props()
props.drawing_styles[index].raster_style = json.dumps(style) props.drawing_styles[index].raster_style = json.dumps(style)
@@ -2520,8 +2523,10 @@ class ActivateDrawingStyle(bpy.types.Operator, tool.Ifc.Operator):
def execute(self, context): def execute(self, context):
scene = context.scene scene = context.scene
assert scene and (camera := scene.camera)
camera_props = tool.Drawing.get_camera_props(camera)
ifc_file = tool.Ifc.get() ifc_file = tool.Ifc.get()
active_drawing_style_index = scene.camera.data.BIMCameraProperties.active_drawing_style_index active_drawing_style_index = camera_props.active_drawing_style_index
props = tool.Drawing.get_document_props() props = tool.Drawing.get_document_props()
if active_drawing_style_index >= len(props.drawing_styles): if active_drawing_style_index >= len(props.drawing_styles):
@@ -2841,7 +2846,8 @@ class AddDrawingStyleAttribute(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def execute(self, context): def execute(self, context):
props = context.scene.camera.data.BIMCameraProperties assert context.scene and (camera := context.scene.camera)
props = tool.Drawing.get_camera_props(camera)
dprops = tool.Drawing.get_document_props() dprops = tool.Drawing.get_document_props()
dprops.drawing_styles[props.active_drawing_style_index].attributes.add() dprops.drawing_styles[props.active_drawing_style_index].attributes.add()
return {"FINISHED"} return {"FINISHED"}
@@ -2855,7 +2861,8 @@ class RemoveDrawingStyleAttribute(bpy.types.Operator):
index: bpy.props.IntProperty() index: bpy.props.IntProperty()
def execute(self, context): def execute(self, context):
props = context.scene.camera.data.BIMCameraProperties assert context.scene and (camera := context.scene.camera)
props = tool.Drawing.get_camera_props(camera)
dprops = tool.Drawing.get_document_props() dprops = tool.Drawing.get_document_props()
dprops.drawing_styles[props.active_drawing_style_index].attributes.remove(self.index) dprops.drawing_styles[props.active_drawing_style_index].attributes.remove(self.index)
return {"FINISHED"} return {"FINISHED"}
@@ -3402,11 +3409,15 @@ class EnableEditingElementFilter(bpy.types.Operator, tool.Ifc.Operator):
filter_mode: bpy.props.StringProperty() filter_mode: bpy.props.StringProperty()
def _execute(self, context): def _execute(self, context):
obj = bpy.context.scene.camera assert context.scene
obj = context.scene.camera
if not obj: if not obj:
return return
obj.data.BIMCameraProperties.filter_mode = self.filter_mode assert (camera := context.scene.camera)
props = tool.Drawing.get_camera_props(camera)
props.filter_mode = self.filter_mode
element = tool.Ifc.get_entity(obj) element = tool.Ifc.get_entity(obj)
assert element
if query := ifcopenshell.util.element.get_pset(element, "EPset_Drawing", self.filter_mode.title()): if query := ifcopenshell.util.element.get_pset(element, "EPset_Drawing", self.filter_mode.title()):
filter_groups = tool.Search.get_filter_groups(f"drawing_{self.filter_mode.lower()}") filter_groups = tool.Search.get_filter_groups(f"drawing_{self.filter_mode.lower()}")
try: try:
@@ -3422,10 +3433,12 @@ class EditElementFilter(bpy.types.Operator, tool.Ifc.Operator):
filter_mode: bpy.props.StringProperty() filter_mode: bpy.props.StringProperty()
def _execute(self, context): def _execute(self, context):
obj = bpy.context.scene.camera assert context.scene
obj = context.scene.camera
assert obj assert obj
props = obj.data.BIMCameraProperties props = tool.Drawing.get_camera_props(obj)
element = tool.Ifc.get_entity(obj) element = tool.Ifc.get_entity(obj)
assert element
pset = tool.Pset.get_element_pset(element, "EPset_Drawing") pset = tool.Pset.get_element_pset(element, "EPset_Drawing")
if self.filter_mode == "INCLUDE": if self.filter_mode == "INCLUDE":
query = tool.Search.export_filter_query(props.include_filter_groups) or None query = tool.Search.export_filter_query(props.include_filter_groups) or None
@@ -3433,7 +3446,7 @@ class EditElementFilter(bpy.types.Operator, tool.Ifc.Operator):
elif self.filter_mode == "EXCLUDE": elif self.filter_mode == "EXCLUDE":
query = tool.Search.export_filter_query(props.exclude_filter_groups) or None query = tool.Search.export_filter_query(props.exclude_filter_groups) or None
ifcopenshell.api.run("pset.edit_pset", tool.Ifc.get(), pset=pset, properties={"Exclude": query}) ifcopenshell.api.run("pset.edit_pset", tool.Ifc.get(), pset=pset, properties={"Exclude": query})
obj.data.BIMCameraProperties.filter_mode = "NONE" props.filter_mode = "NONE"
bpy.ops.bim.activate_drawing(drawing=element.id(), should_view_from_camera=False) bpy.ops.bim.activate_drawing(drawing=element.id(), should_view_from_camera=False)
+23 -14
View File
@@ -22,6 +22,7 @@ import json
import enum import enum
import ifcopenshell import ifcopenshell
import ifcopenshell.api import ifcopenshell.api
import ifcopenshell.api.pset
import ifcopenshell.util.element import ifcopenshell.util.element
import bonsai.tool as tool import bonsai.tool as tool
import bonsai.core.drawing as core import bonsai.core.drawing as core
@@ -65,9 +66,10 @@ def get_location_hint(self, context):
return DrawingsData.data["location_hint"] return DrawingsData.data["location_hint"]
def update_diagram_scale(self, context): def update_diagram_scale(self: "BIMCameraProperties", context: bpy.types.Context) -> None:
if not self.update_props: if not self.update_props:
return return
assert context.scene
if not context.scene.camera or context.scene.camera.data != self.id_data: if not context.scene.camera or context.scene.camera.data != self.id_data:
return return
element = tool.Ifc.get_entity(context.scene.camera) element = tool.Ifc.get_entity(context.scene.camera)
@@ -89,13 +91,14 @@ def update_diagram_scale(self, context):
if pset: if pset:
pset = tool.Ifc.get().by_id(pset["id"]) pset = tool.Ifc.get().by_id(pset["id"])
else: else:
pset = ifcopenshell.api.run("pset.add_pset", tool.Ifc.get(), product=element, name="EPset_Drawing") pset = ifcopenshell.api.pset.add_pset(tool.Ifc.get(), product=element, name="EPset_Drawing")
ifcopenshell.api.run("pset.edit_pset", tool.Ifc.get(), pset=pset, properties=diagram_scale) ifcopenshell.api.pset.edit_pset(tool.Ifc.get(), pset=pset, properties=diagram_scale)
def update_is_nts(self: "BIMCameraProperties", context: bpy.types.Context) -> None: def update_is_nts(self: "BIMCameraProperties", context: bpy.types.Context) -> None:
if not self.update_props: if not self.update_props:
return return
assert context.scene
if not context.scene.camera or context.scene.camera.data != self.id_data: if not context.scene.camera or context.scene.camera.data != self.id_data:
return return
element = tool.Ifc.get_entity(context.scene.camera) element = tool.Ifc.get_entity(context.scene.camera)
@@ -118,8 +121,9 @@ def update_is_nts(self: "BIMCameraProperties", context: bpy.types.Context) -> No
ifcopenshell.api.run("pset.edit_pset", tool.Ifc.get(), pset=pset, properties={"IsNTS": self.is_nts}) ifcopenshell.api.run("pset.edit_pset", tool.Ifc.get(), pset=pset, properties={"IsNTS": self.is_nts})
def get_diagram_scales(self, context): def get_diagram_scales(self: "BIMCameraProperties", context: bpy.types.Context) -> list[tuple[str, str, str]]:
global diagram_scales_enum global diagram_scales_enum
assert context.scene
if ( if (
len(diagram_scales_enum) < 1 len(diagram_scales_enum) < 1
or (context.scene.unit_settings.system == "IMPERIAL" and len(diagram_scales_enum) == 13) or (context.scene.unit_settings.system == "IMPERIAL" and len(diagram_scales_enum) == 13)
@@ -200,44 +204,45 @@ def set_drawing_style_name(self: "DrawingStyle", new_value: str) -> None:
bpy.ops.bim.save_drawing_styles_data(rename_style=True, rename_style_from=old_value, rename_style_to=new_value) bpy.ops.bim.save_drawing_styles_data(rename_style=True, rename_style_from=old_value, rename_style_to=new_value)
def update_document_name(self, context): def update_document_name(self: "Document", context: bpy.types.Context) -> None:
document = tool.Ifc.get().by_id(self.ifc_definition_id) document = tool.Ifc.get().by_id(self.ifc_definition_id)
core.update_document_name(tool.Ifc, tool.Drawing, document=document, name=self.name) core.update_document_name(tool.Ifc, tool.Drawing, document=document, name=self.name)
def update_has_underlay(self, context): def update_has_underlay(self: "BIMCameraProperties", context: bpy.types.Context) -> None:
update_layer(self, context, "HasUnderlay", self.has_underlay) update_layer(self, context, "HasUnderlay", self.has_underlay)
assert context.scene
# making sure that camera is active # making sure that camera is active
if self.has_underlay and (context.scene.camera and context.scene.camera.data == self.id_data): if self.has_underlay and (context.scene.camera and context.scene.camera.data == self.id_data):
bpy.ops.bim.reload_drawing_styles() bpy.ops.bim.reload_drawing_styles()
bpy.ops.bim.activate_drawing_style() bpy.ops.bim.activate_drawing_style()
def update_has_linework(self, context): def update_has_linework(self: "BIMCameraProperties", context: bpy.types.Context) -> None:
update_layer(self, context, "HasLinework", self.has_linework) update_layer(self, context, "HasLinework", self.has_linework)
def update_has_annotation(self, context): def update_has_annotation(self: "BIMCameraProperties", context: bpy.types.Context) -> None:
update_layer(self, context, "HasAnnotation", self.has_annotation) update_layer(self, context, "HasAnnotation", self.has_annotation)
def update_dpi(self, context): def update_dpi(self: "BIMCameraProperties", context: bpy.types.Context) -> None:
update_layer(self, context, "DPI", self.dpi) update_layer(self, context, "DPI", self.dpi)
def update_linework_mode(self, context): def update_linework_mode(self: "BIMCameraProperties", context: bpy.types.Context) -> None:
update_layer(self, context, "LineworkMode", self.linework_mode) update_layer(self, context, "LineworkMode", self.linework_mode)
def update_fill_mode(self, context): def update_fill_mode(self: "BIMCameraProperties", context: bpy.types.Context) -> None:
update_layer(self, context, "FillMode", self.fill_mode) update_layer(self, context, "FillMode", self.fill_mode)
def update_cut_mode(self, context): def update_cut_mode(self: "BIMCameraProperties", context: bpy.types.Context) -> None:
update_layer(self, context, "CutMode", self.cut_mode) update_layer(self, context, "CutMode", self.cut_mode)
def update_layer(self, context, name, value): def update_layer(self: "BIMCameraProperties", context: bpy.types.Context, name: str, value: Any) -> None:
if not self.update_props: if not self.update_props:
return return
if not context.scene.camera or context.scene.camera.data != self.id_data: if not context.scene.camera or context.scene.camera.data != self.id_data:
@@ -520,7 +525,11 @@ class BIMCameraProperties(PropertyGroup):
filter_mode: StringProperty(name="Filter Mode", default="NONE") filter_mode: StringProperty(name="Filter Mode", default="NONE")
include_filter_groups: CollectionProperty(type=BIMFilterGroup, name="Include Filter") include_filter_groups: CollectionProperty(type=BIMFilterGroup, name="Include Filter")
exclude_filter_groups: CollectionProperty(type=BIMFilterGroup, name="Exclude Filter") exclude_filter_groups: CollectionProperty(type=BIMFilterGroup, name="Exclude Filter")
update_props: BoolProperty(name="Enable Props Auto Update", default=True) update_props: BoolProperty(
name="Enable Props Auto Update",
description="Update related EPset_Drawing pset on any change in camera properties.",
default=True,
)
if TYPE_CHECKING: if TYPE_CHECKING:
linework_mode: Literal["OPENCASCADE", "FREESTYLE"] linework_mode: Literal["OPENCASCADE", "FREESTYLE"]
+17 -9
View File
@@ -16,6 +16,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>. # along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
import bpy import bpy
import bonsai.bim.helper import bonsai.bim.helper
import bonsai.tool as tool import bonsai.tool as tool
@@ -28,6 +29,10 @@ from bonsai.bim.module.drawing.data import (
ElementFiltersData, ElementFiltersData,
DecoratorData, DecoratorData,
) )
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from bonsai.bim.module.drawing.prop import DocProperties, Drawing
class BIM_PT_camera(Panel): class BIM_PT_camera(Panel):
@@ -39,18 +44,21 @@ class BIM_PT_camera(Panel):
bl_parent_id = "BIM_PT_tab_drawings" bl_parent_id = "BIM_PT_tab_drawings"
def draw(self, context): def draw(self, context):
if not (context.scene.camera and hasattr(context.scene.camera.data, "BIMCameraProperties")): assert context.scene and self.layout
camera = context.scene.camera
if not camera:
row = self.layout.row() row = self.layout.row()
row.label(text="No Active Drawing", icon="ERROR") row.label(text="No Active Drawing", icon="ERROR")
return return
if "/" not in context.scene.camera.name: if not tool.Ifc.get_entity(camera):
self.layout.label(text="This is not a BIM camera.") self.layout.label(text="This is not a BIM camera.")
return return
assert isinstance(camera_data := camera.data, bpy.types.Camera)
props = tool.Drawing.get_camera_props(camera)
self.layout.use_property_split = True self.layout.use_property_split = True
dprops = tool.Drawing.get_document_props() dprops = tool.Drawing.get_document_props()
props = context.scene.camera.data.BIMCameraProperties
col = self.layout.column(align=True) col = self.layout.column(align=True)
row = col.row(align=True) row = col.row(align=True)
@@ -77,7 +85,7 @@ class BIM_PT_camera(Panel):
row.prop(props, "height") row.prop(props, "height")
row = self.layout.row() row = self.layout.row()
row.prop(context.scene.camera.data, "clip_end", text="Depth") row.prop(camera_data, "clip_end", text="Depth")
row = self.layout.row(align=True) row = self.layout.row(align=True)
row.prop(props, "diagram_scale", text="Scale") row.prop(props, "diagram_scale", text="Scale")
@@ -110,7 +118,8 @@ class BIM_PT_element_filters(Panel):
if not ElementFiltersData.is_loaded: if not ElementFiltersData.is_loaded:
ElementFiltersData.load() ElementFiltersData.load()
props = context.scene.camera.data.BIMCameraProperties assert context.scene and (camera := context.scene.camera)
props = tool.Drawing.get_camera_props(camera)
if props.filter_mode == "INCLUDE": if props.filter_mode == "INCLUDE":
bonsai.bim.helper.draw_filter( bonsai.bim.helper.draw_filter(
@@ -159,10 +168,9 @@ class BIM_PT_drawing_underlay(Panel):
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
layout.use_property_split = True layout.use_property_split = True
camera = context.scene.camera assert context.scene and (camera := context.scene.camera)
assert camera
dprops = tool.Drawing.get_document_props() dprops = tool.Drawing.get_document_props()
props = camera.data.BIMCameraProperties props = tool.Drawing.get_camera_props(camera)
drawing_index_is_valid = props.active_drawing_style_index < len(dprops.drawing_styles) drawing_index_is_valid = props.active_drawing_style_index < len(dprops.drawing_styles)
if not DrawingsData.is_loaded: if not DrawingsData.is_loaded:
@@ -607,7 +615,7 @@ class BIM_PT_text(Panel):
class BIM_UL_drawinglist(bpy.types.UIList): class BIM_UL_drawinglist(bpy.types.UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname): def draw_item(self, context, layout, data: DocProperties, item: Drawing, icon, active_data, active_propname):
if not item: if not item:
layout.label(text="", translate=False) layout.label(text="", translate=False)
return return
+51 -43
View File
@@ -298,20 +298,21 @@ class Drawing(bonsai.core.tool.Drawing):
def create_camera( def create_camera(
cls, name: str, matrix: Matrix, location_hint: Literal["PERSPECTIVE", "ORTHOGRAPHIC"] cls, name: str, matrix: Matrix, location_hint: Literal["PERSPECTIVE", "ORTHOGRAPHIC"]
) -> bpy.types.Object: ) -> bpy.types.Object:
camera = bpy.data.objects.new(name, bpy.data.cameras.new(name)) camera = bpy.data.objects.new(name, (camera_data := bpy.data.cameras.new(name)))
props = cls.get_camera_props(camera_data)
camera.location = (0, 0, 1.5) # The view shall be 1.5m above the origin camera.location = (0, 0, 1.5) # The view shall be 1.5m above the origin
camera.data.show_limits = True camera_data.show_limits = True
if location_hint == "PERSPECTIVE": if location_hint == "PERSPECTIVE":
camera.data.type = "PERSP" camera_data.type = "PERSP"
else: else:
camera.data.type = "ORTHO" camera_data.type = "ORTHO"
camera.data.ortho_scale = 50 # The default of 6m is too small 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_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 camera_data.clip_end = 10 # A slightly more reasonable default
if bpy.context.scene.unit_settings.system == "IMPERIAL": if bpy.context.scene.unit_settings.system == "IMPERIAL":
camera.data.BIMCameraProperties.diagram_scale = '1/8"=1\'-0"|1/96' props.diagram_scale = '1/8"=1\'-0"|1/96'
else: else:
camera.data.BIMCameraProperties.diagram_scale = "1:100|1/100" props.diagram_scale = "1:100|1/100"
camera.matrix_world = matrix camera.matrix_world = matrix
return camera return camera
@@ -797,50 +798,50 @@ class Drawing(bonsai.core.tool.Drawing):
from bonsai.bim.module.drawing.prop import get_diagram_scales from bonsai.bim.module.drawing.prop import get_diagram_scales
# Temporarily clear the definition id to prevent prop update callbacks to IFC. # Temporarily clear the definition id to prevent prop update callbacks to IFC.
camera_props = tool.Drawing.get_camera_props(camera) camera_props = cls.get_camera_props(camera)
update_props = camera_props.update_props update_props = camera_props.update_props
camera_props.update_props = False camera_props.update_props = False
camera.BIMCameraProperties.has_underlay = False camera_props.has_underlay = False
camera.BIMCameraProperties.has_linework = True camera_props.has_linework = True
camera.BIMCameraProperties.has_annotation = True camera_props.has_annotation = True
camera.BIMCameraProperties.target_view = "PLAN_VIEW" camera_props.target_view = "PLAN_VIEW"
camera.BIMCameraProperties.is_nts = False camera_props.is_nts = False
pset = ifcopenshell.util.element.get_pset(drawing, "EPset_Drawing") pset = ifcopenshell.util.element.get_pset(drawing, "EPset_Drawing")
if pset: if pset:
if "TargetView" in pset: if "TargetView" in pset:
camera.BIMCameraProperties.target_view = pset["TargetView"] camera_props.target_view = pset["TargetView"]
if "Scale" in pset: if "Scale" in pset:
valid_scales = [ valid_scales = [
i[0] for i in get_diagram_scales(None, bpy.context) if pset["Scale"] == i[0].split("|")[-1] i[0] for i in get_diagram_scales(None, bpy.context) if pset["Scale"] == i[0].split("|")[-1]
] ]
if valid_scales: if valid_scales:
camera.BIMCameraProperties.diagram_scale = valid_scales[0] camera_props.diagram_scale = valid_scales[0]
else: else:
camera.BIMCameraProperties.diagram_scale = "CUSTOM" camera_props.diagram_scale = "CUSTOM"
if ":" in pset["HumanScale"]: if ":" in pset["HumanScale"]:
numerator, denominator = pset["HumanScale"].split(":") numerator, denominator = pset["HumanScale"].split(":")
else: else:
numerator, denominator = pset["HumanScale"].split("=") numerator, denominator = pset["HumanScale"].split("=")
camera.BIMCameraProperties.custom_scale_numerator = numerator camera_props.custom_scale_numerator = numerator
camera.BIMCameraProperties.custom_scale_denominator = denominator camera_props.custom_scale_denominator = denominator
if "HasUnderlay" in pset: if "HasUnderlay" in pset:
camera.BIMCameraProperties.has_underlay = bool(pset["HasUnderlay"]) camera_props.has_underlay = bool(pset["HasUnderlay"])
if "HasLinework" in pset: if "HasLinework" in pset:
camera.BIMCameraProperties.has_linework = bool(pset["HasLinework"]) camera_props.has_linework = bool(pset["HasLinework"])
if "HasAnnotation" in pset: if "HasAnnotation" in pset:
camera.BIMCameraProperties.has_annotation = bool(pset["HasAnnotation"]) camera_props.has_annotation = bool(pset["HasAnnotation"])
if "IsNTS" in pset: if "IsNTS" in pset:
camera.BIMCameraProperties.is_nts = bool(pset["IsNTS"]) camera_props.is_nts = bool(pset["IsNTS"])
if "DPI" in pset: if "DPI" in pset:
camera.BIMCameraProperties.dpi = int(pset["DPI"]) camera_props.dpi = int(pset["DPI"])
if "LineworkMode" in pset: if "LineworkMode" in pset:
camera.BIMCameraProperties.linework_mode = str(pset["LineworkMode"]) camera_props.linework_mode = str(pset["LineworkMode"])
if "FillMode" in pset: if "FillMode" in pset:
camera.BIMCameraProperties.fill_mode = str(pset["FillMode"]) camera_props.fill_mode = str(pset["FillMode"])
if "CutMode" in pset: if "CutMode" in pset:
camera.BIMCameraProperties.cut_mode = str(pset["CutMode"]) camera_props.cut_mode = str(pset["CutMode"])
camera_props.update_props = update_props camera_props.update_props = update_props
@@ -853,7 +854,7 @@ class Drawing(bonsai.core.tool.Drawing):
cls.drawing_selected_states.update({d.ifc_definition_id: d.is_selected for d in props.drawings if d.is_drawing}) cls.drawing_selected_states.update({d.ifc_definition_id: d.is_selected for d in props.drawings if d.is_drawing})
props.drawings.clear() props.drawings.clear()
drawings = [e for e in tool.Ifc.get().by_type("IfcAnnotation") if e.ObjectType == "DRAWING"] drawings = [e for e in tool.Ifc.get().by_type("IfcAnnotation") if e.ObjectType == "DRAWING"]
grouped_drawings = { grouped_drawings: dict[str, list[ifcopenshell.entity_instance]] = {
"MODEL_VIEW": [], "MODEL_VIEW": [],
"PLAN_VIEW": [], "PLAN_VIEW": [],
"SECTION_VIEW": [], "SECTION_VIEW": [],
@@ -1327,8 +1328,13 @@ class Drawing(bonsai.core.tool.Drawing):
import bonsai.bim.module.drawing.helper as helper import bonsai.bim.module.drawing.helper as helper
camera = tool.Ifc.get_object(drawing) camera = tool.Ifc.get_object(drawing)
bounds = helper.ortho_view_frame(camera.data) if camera.data.type == "ORTHO" else None assert isinstance(camera, bpy.types.Object)
assert isinstance((camera_data := camera.data), bpy.types.Camera)
props = tool.Drawing.get_camera_props(camera_data)
bounds = helper.ortho_view_frame(camera_data) if camera_data.type == "ORTHO" else None
reference_obj = tool.Ifc.get_object(reference_element) reference_obj = tool.Ifc.get_object(reference_element)
assert isinstance(reference_obj, bpy.types.Object)
def to_camera_coords(camera: bpy.types.Object, reference_obj: bpy.types.Object) -> Matrix: def to_camera_coords(camera: bpy.types.Object, reference_obj: bpy.types.Object) -> Matrix:
mat = reference_obj.matrix_world.copy() mat = reference_obj.matrix_world.copy()
@@ -1336,12 +1342,12 @@ class Drawing(bonsai.core.tool.Drawing):
xyz[2] = 0 xyz[2] = 0
xyz = camera.matrix_world @ xyz xyz = camera.matrix_world @ xyz
mat.translation = xyz mat.translation = xyz
annotation_offset = mathutils.Vector((0, 0, -camera.data.clip_start - 0.05)) annotation_offset = mathutils.Vector((0, 0, -camera_data.clip_start - 0.05))
annotation_offset = camera.matrix_world.to_quaternion() @ annotation_offset annotation_offset = camera.matrix_world.to_quaternion() @ annotation_offset
mat.translation += annotation_offset mat.translation += annotation_offset
return mat return mat
def project_point_onto_camera(point, camera): def project_point_onto_camera(point: Vector, camera: bpy.types.Object) -> Vector:
projection = camera.matrix_world.to_quaternion() @ mathutils.Vector((0, 0, -1)) projection = camera.matrix_world.to_quaternion() @ mathutils.Vector((0, 0, -1))
return camera.matrix_world.inverted() @ mathutils.geometry.intersect_line_plane( return camera.matrix_world.inverted() @ mathutils.geometry.intersect_line_plane(
point.xyz, point.xyz - projection, camera.location, projection point.xyz, point.xyz - projection, camera.location, projection
@@ -1349,12 +1355,12 @@ class Drawing(bonsai.core.tool.Drawing):
obj_matrix = to_camera_coords(camera, reference_obj) obj_matrix = to_camera_coords(camera, reference_obj)
if camera.data.BIMCameraProperties.raster_x > camera.data.BIMCameraProperties.raster_y: if props.raster_x > props.raster_y:
width = camera.data.ortho_scale width = camera_data.ortho_scale
height = width / camera.data.BIMCameraProperties.raster_x * camera.data.BIMCameraProperties.raster_y height = width / props.raster_x * props.raster_y
else: else:
height = camera.data.ortho_scale height = camera_data.ortho_scale
width = height / camera.data.BIMCameraProperties.raster_y * camera.data.BIMCameraProperties.raster_x width = height / props.raster_y * props.raster_x
projection = project_point_onto_camera(reference_obj.location, camera) projection = project_point_onto_camera(reference_obj.location, camera)
co1 = camera.matrix_world @ mathutils.Vector((width / 2, projection[1], -1)) co1 = camera.matrix_world @ mathutils.Vector((width / 2, projection[1], -1))
@@ -1618,16 +1624,18 @@ class Drawing(bonsai.core.tool.Drawing):
@classmethod @classmethod
def get_camera_block(cls, obj: bpy.types.Object) -> dict: def get_camera_block(cls, obj: bpy.types.Object) -> dict:
raster_x = obj.data.BIMCameraProperties.raster_x assert isinstance(camera := obj.data, bpy.types.Camera)
raster_y = obj.data.BIMCameraProperties.raster_y props = tool.Drawing.get_camera_props(camera)
raster_x = props.raster_x
raster_y = props.raster_y
if raster_x > raster_y: if raster_x > raster_y:
width = obj.data.ortho_scale width = camera.ortho_scale
height = width / raster_x * raster_y height = width / raster_x * raster_y
else: else:
height = obj.data.ortho_scale height = camera.ortho_scale
width = height / raster_y * raster_x width = height / raster_y * raster_x
depth = obj.data.clip_end depth = camera.clip_end
verts = ( verts = (
obj.matrix_world @ mathutils.Vector((-width / 2, -height / 2, -depth)), obj.matrix_world @ mathutils.Vector((-width / 2, -height / 2, -depth)),
@@ -2054,7 +2062,7 @@ class Drawing(bonsai.core.tool.Drawing):
def get_elements_in_camera_view( def get_elements_in_camera_view(
cls, camera: bpy.types.Object, objs: list[bpy.types.Object] cls, camera: bpy.types.Object, objs: list[bpy.types.Object]
) -> set[ifcopenshell.entity_instance]: ) -> set[ifcopenshell.entity_instance]:
props = camera.data.BIMCameraProperties props = tool.Drawing.get_camera_props(camera)
x = props.width x = props.width
y = props.height y = props.height
+7 -3
View File
@@ -726,8 +726,10 @@ class TestDrawingMaintainingSheetPosition(NewFile):
assert drawing_data["foreground"] == (30.0, 30.0, 500.0, 500.0) assert drawing_data["foreground"] == (30.0, 30.0, 500.0, 500.0)
assert drawing_data["view-title"] == (30.0, 535.0, 50.22, 10.0) assert drawing_data["view-title"] == (30.0, 535.0, 50.22, 10.0)
bpy.context.scene.camera.data.BIMCameraProperties.width = 25 assert (scene := bpy.context.scene) and (camera := scene.camera)
bpy.context.scene.camera.data.BIMCameraProperties.height = 25 props = tool.Drawing.get_camera_props(camera)
props.width = 25
props.height = 25
tool.Blender.force_depsgraph_update() tool.Blender.force_depsgraph_update()
bpy.ops.bim.create_drawing() bpy.ops.bim.create_drawing()
@@ -866,7 +868,9 @@ class TestDrawingStyles(NewFile):
def test_drawing_styles_loaded_on_underlay_enabled(self): def test_drawing_styles_loaded_on_underlay_enabled(self):
self.setup_project_with_drawing() self.setup_project_with_drawing()
bpy.context.scene.camera.data.BIMCameraProperties.has_underlay = True assert (scene := bpy.context.scene) and (camera := scene.camera)
props = tool.Drawing.get_camera_props(camera)
props.has_underlay = True
assert len(self.drawing_styles) == 3 assert len(self.drawing_styles) == 3
def test_drawing_styles_reload(self): def test_drawing_styles_reload(self):