This commit is contained in:
Andrej730
2025-02-10 13:31:50 +05:00
parent 11c6b55f7c
commit 4c0a7e1ca9
41 changed files with 348 additions and 189 deletions
+3 -3
View File
@@ -117,7 +117,7 @@ def update_bim_tool_props():
if not representation: if not representation:
return return
props = bpy.context.scene.BIMModelProperties props = tool.Model.get_model_props()
if element.is_a("IfcElementType") or element.is_a("IfcElement"): if element.is_a("IfcElementType") or element.is_a("IfcElement"):
element_type = ifcopenshell.util.element.get_type(element) element_type = ifcopenshell.util.element.get_type(element)
if element_type: if element_type:
@@ -130,7 +130,7 @@ def update_bim_tool_props():
if not extrusion: if not extrusion:
return return
def get_x_angle(extrusion): def get_x_angle(extrusion: ifcopenshell.entity_instance) -> float:
x, y, z = extrusion.ExtrudedDirection.DirectionRatios x, y, z = extrusion.ExtrudedDirection.DirectionRatios
x_angle = Vector((0, 1)).angle_signed(Vector((y, z))) x_angle = Vector((0, 1)).angle_signed(Vector((y, z)))
return x_angle return x_angle
@@ -332,7 +332,7 @@ def load_post(scene):
georeference_props = bpy.context.scene.BIMGeoreferenceProperties georeference_props = bpy.context.scene.BIMGeoreferenceProperties
aggregate_props = bpy.context.scene.BIMAggregateProperties aggregate_props = bpy.context.scene.BIMAggregateProperties
nest_props = bpy.context.scene.BIMNestProperties nest_props = bpy.context.scene.BIMNestProperties
model_props = bpy.context.scene.BIMModelProperties model_props = tool.Model.get_model_props()
if georeference_props.should_visualise: if georeference_props.should_visualise:
GeoreferenceDecorator.install(bpy.context) GeoreferenceDecorator.install(bpy.context)
if aggregate_props.aggregate_decorator: if aggregate_props.aggregate_decorator:
@@ -660,6 +660,7 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
obj.select_set(True) obj.select_set(True)
def auto_generate_boundaries(self, space, space_obj): def auto_generate_boundaries(self, space, space_obj):
props = tool.Model.get_model_props()
# Identify all potential building elements # Identify all potential building elements
# TODO: don't select everything, use AABB culling in Blender # TODO: don't select everything, use AABB culling in Blender
building_elements = ( building_elements = (
@@ -775,9 +776,7 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
# we cheat by using the exterior boundary to mean "gross". # we cheat by using the exterior boundary to mean "gross".
exterior_boundary_polygon = shapely.Polygon(gross_boundary_polygon.exterior.coords) exterior_boundary_polygon = shapely.Polygon(gross_boundary_polygon.exterior.coords)
parent_boundary = tool.Ifc.run( parent_boundary = tool.Ifc.run("root.create_entity", ifc_class=props.boundary_class)
"root.create_entity", ifc_class=bpy.context.scene.BIMModelProperties.boundary_class
)
if building_element.is_a("IfcVirtualElement"): if building_element.is_a("IfcVirtualElement"):
parent_boundary.PhysicalOrVirtualBoundary = "VIRTUAL" parent_boundary.PhysicalOrVirtualBoundary = "VIRTUAL"
else: else:
@@ -854,9 +853,7 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
if opening_polygon.intersection(exterior_boundary_polygon).area == 0: if opening_polygon.intersection(exterior_boundary_polygon).area == 0:
continue continue
boundary = tool.Ifc.run( boundary = tool.Ifc.run("root.create_entity", ifc_class=props.boundary_class)
"root.create_entity", ifc_class=bpy.context.scene.BIMModelProperties.boundary_class
)
boundary.RelatingSpace = space boundary.RelatingSpace = space
boundary.RelatedBuildingElement = filling or opening boundary.RelatedBuildingElement = filling or opening
boundary.ConnectionGeometry = self.create_connection_geometry_from_polygon( boundary.ConnectionGeometry = self.create_connection_geometry_from_polygon(
@@ -877,6 +874,7 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
if not relating_space or not related_building_element: if not relating_space or not related_building_element:
return return
props = tool.Model.get_model_props()
# Find which face on space should be bounded to related building element # Find which face on space should be bounded to related building element
# TODO: Handle round wall where multiple faces need to be bound to the same related building element # TODO: Handle round wall where multiple faces need to be bound to the same related building element
bm = bmesh.new() bm = bmesh.new()
@@ -924,7 +922,7 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
): ):
return return
parent_boundary = tool.Ifc.run("root.create_entity", ifc_class=context.scene.BIMModelProperties.boundary_class) parent_boundary = tool.Ifc.run("root.create_entity", ifc_class=props.boundary_class)
parent_boundary.PhysicalOrVirtualBoundary = "PHYSICAL" parent_boundary.PhysicalOrVirtualBoundary = "PHYSICAL"
# Set to EXTERNAL by default and turn later to internal if there is a corresponding boundary relating to an # Set to EXTERNAL by default and turn later to internal if there is a corresponding boundary relating to an
# internal space # internal space
@@ -959,7 +957,7 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
continue continue
connection_geometry = self.create_connection_geometry_from_polygon(opening_polygon, target_face_matrix) connection_geometry = self.create_connection_geometry_from_polygon(opening_polygon, target_face_matrix)
boundary = tool.Ifc.run("root.create_entity", ifc_class=context.scene.BIMModelProperties.boundary_class) boundary = tool.Ifc.run("root.create_entity", ifc_class=props.boundary_class)
boundary.RelatingSpace = relating_space boundary.RelatingSpace = relating_space
boundary.RelatedBuildingElement = filling boundary.RelatedBuildingElement = filling
boundary.ConnectionGeometry = connection_geometry boundary.ConnectionGeometry = connection_geometry
@@ -54,7 +54,7 @@ class CoveringToolUI:
@classmethod @classmethod
def draw(cls, context, layout, ifc_element_type=None): def draw(cls, context, layout, ifc_element_type=None):
cls.layout = layout cls.layout = layout
cls.props = context.scene.BIMModelProperties cls.props = tool.Model.get_model_props()
cls.covering_props = context.scene.BIMCoveringProperties cls.covering_props = context.scene.BIMCoveringProperties
row = cls.layout.row(align=True) row = cls.layout.row(align=True)
@@ -37,7 +37,7 @@ class Annotator:
if related_element is None: if related_element is None:
location, _, _, _ = Annotator.get_placeholder_coords(bpy.context) location, _, _, _ = Annotator.get_placeholder_coords(bpy.context)
else: else:
obj.data.BIMAssignedProductProperties.related_element = related_element curve.BIMAssignedProductProperties.related_element = related_element
location = related_element.location location = related_element.location
obj.location = location obj.location = location
obj.hide_render = True obj.hide_render = True
@@ -47,8 +47,9 @@ class Annotator:
tool.Blender.get_data_dir_path(Path("fonts") / "OpenGost Type B TT.ttf").__str__() tool.Blender.get_data_dir_path(Path("fonts") / "OpenGost Type B TT.ttf").__str__()
) )
font.name = "OpenGost Type B TT" font.name = "OpenGost Type B TT"
obj.data.font = font curve.font = font
obj.data.BIMTextProperties.font_size = "2.5" props = tool.Drawing.get_text_props(obj)
props.font_size = "2.5"
collection = bpy.context.scene.camera.BIMObjectProperties.collection collection = bpy.context.scene.camera.BIMObjectProperties.collection
collection.objects.link(obj) collection.objects.link(obj)
Annotator.resize_text(obj) Annotator.resize_text(obj)
@@ -66,7 +67,8 @@ class Annotator:
return return
# This is a magic number for OpenGost # This is a magic number for OpenGost
font_size = 1.6 / 1000 font_size = 1.6 / 1000
font_size *= float(text_obj.data.BIMTextProperties.font_size) props = tool.Drawing.get_text_props(text_obj)
font_size *= float(props.font_size)
font_size /= tool.Drawing.get_scale_ratio(tool.Drawing.get_diagram_scale(camera)["Scale"]) font_size /= tool.Drawing.get_scale_ratio(tool.Drawing.get_diagram_scale(camera)["Scale"])
+2 -2
View File
@@ -303,7 +303,7 @@ class DecoratorData:
if not element or not tool.Drawing.is_annotation_object_type(element, ["TEXT", "TEXT_LEADER"]): if not element or not tool.Drawing.is_annotation_object_type(element, ["TEXT", "TEXT_LEADER"]):
return None return None
props = obj.BIMTextProperties props = tool.Drawing.get_text_props(obj)
# getting font size # getting font size
pset_data = ifcopenshell.util.element.get_pset(element, "EPset_Annotation") or {} pset_data = ifcopenshell.util.element.get_pset(element, "EPset_Annotation") or {}
# use `regular` as default # use `regular` as default
@@ -399,7 +399,7 @@ class AnnotationData:
@classmethod @classmethod
def load(cls): def load(cls):
cls.is_loaded = True cls.is_loaded = True
cls.props = bpy.context.scene.BIMAnnotationProperties cls.props = tool.Drawing.get_annotation_props()
cls.data["relating_type_id"] = cls.relating_type_id() cls.data["relating_type_id"] = cls.relating_type_id()
cls.data["relating_types"] = cls.relating_types() cls.data["relating_types"] = cls.relating_types()
@@ -589,7 +589,7 @@ class BaseDecorator:
text_dir = self.get_annotation_direction(context, obj) text_dir = self.get_annotation_direction(context, obj)
pos = location_3d_to_region_2d(region, region3d, text_world_position) pos = location_3d_to_region_2d(region, region3d, text_world_position)
props = obj.BIMTextProperties props = tool.Drawing.get_text_props(obj)
text_data = DecoratorData.get_ifc_text_data(obj) text_data = DecoratorData.get_ifc_text_data(obj)
if props.is_editing: if props.is_editing:
text_data = text_data | props.get_text_edited_data() text_data = text_data | props.get_text_edited_data()
@@ -416,7 +416,7 @@ def elevate_segment(bounds, segm):
return [Vector((x, ymin, zmin)), Vector((x, ymax, zmin))] return [Vector((x, ymin, zmin)), Vector((x, ymax, zmin))]
def add_newline_between_words(text, newline_at): def add_newline_between_words(text: str, newline_at: int) -> str:
result = [] result = []
start = 0 start = 0
@@ -84,7 +84,7 @@ class AddAnnotationType(bpy.types.Operator, tool.Ifc.Operator):
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def _execute(self, context): def _execute(self, context):
props = context.scene.BIMAnnotationProperties props = tool.Drawing.get_annotation_props()
object_type = props.object_type object_type = props.object_type
has_representation = props.create_representation_for_type has_representation = props.create_representation_for_type
drawing = tool.Ifc.get_entity(bpy.context.scene.camera) drawing = tool.Ifc.get_entity(bpy.context.scene.camera)
@@ -115,7 +115,7 @@ class EnableAddAnnotationType(bpy.types.Operator, tool.Ifc.Operator):
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def _execute(self, context): def _execute(self, context):
bpy.context.scene.BIMAnnotationProperties.is_adding_type = True tool.Drawing.get_annotation_props().is_adding_type = True
class DisableAddAnnotationType(bpy.types.Operator, tool.Ifc.Operator): class DisableAddAnnotationType(bpy.types.Operator, tool.Ifc.Operator):
@@ -124,7 +124,7 @@ class DisableAddAnnotationType(bpy.types.Operator, tool.Ifc.Operator):
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def _execute(self, context): def _execute(self, context):
bpy.context.scene.BIMAnnotationProperties.is_adding_type = False tool.Drawing.get_annotation_props().is_adding_type = False
class AddDrawing(bpy.types.Operator, tool.Ifc.Operator): class AddDrawing(bpy.types.Operator, tool.Ifc.Operator):
@@ -1433,7 +1433,7 @@ class AddAnnotation(bpy.types.Operator, tool.Ifc.Operator):
return operator.description or "" return operator.description or ""
def _execute(self, context): def _execute(self, context):
props = bpy.context.scene.BIMAnnotationProperties props = tool.Drawing.get_annotation_props()
if not (drawing := tool.Ifc.get_entity(context.scene.camera)): if not (drawing := tool.Ifc.get_entity(context.scene.camera)):
self.report({"WARNING"}, "Not a BIM camera") self.report({"WARNING"}, "Not a BIM camera")
return return
@@ -2725,7 +2725,9 @@ class EditTextPopup(bpy.types.Operator):
# need to keep them in sync or move to some common function # need to keep them in sync or move to some common function
# NOTE: that `popup_active_attribute` is used here when it's not used in `BIM_PT_text.draw()` # NOTE: that `popup_active_attribute` is used here when it's not used in `BIM_PT_text.draw()`
props = context.active_object.BIMTextProperties obj = context.active_object
assert obj
props = tool.Drawing.get_text_props(obj)
row = self.layout.row(align=True) row = self.layout.row(align=True)
row.operator("bim.add_text_literal", icon="ADD", text="Add Literal") row.operator("bim.add_text_literal", icon="ADD", text="Add Literal")
@@ -2826,9 +2828,11 @@ class AddTextLiteral(bpy.types.Operator):
def execute(self, context): def execute(self, context):
obj = context.active_object obj = context.active_object
assert obj
# similar to `tool.Drawing.import_text_attributes` # similar to `tool.Drawing.import_text_attributes`
literal_props = obj.BIMTextProperties.literals.add() props = tool.Drawing.get_text_props(obj)
literal_props = props.literals.add()
literal_attributes = literal_props.attributes literal_attributes = literal_props.attributes
literal_attr_values = { literal_attr_values = {
"Literal": "Literal", "Literal": "Literal",
@@ -2865,7 +2869,9 @@ class RemoveTextLiteral(bpy.types.Operator):
def execute(self, context): def execute(self, context):
obj = context.active_object obj = context.active_object
obj.BIMTextProperties.literals.remove(self.literal_prop_id) assert obj
props = tool.Drawing.get_text_props(obj)
props.literals.remove(self.literal_prop_id)
return {"FINISHED"} return {"FINISHED"}
@@ -2880,7 +2886,9 @@ class OrderTextLiteralUp(bpy.types.Operator):
def execute(self, context): def execute(self, context):
obj = context.active_object obj = context.active_object
obj.BIMTextProperties.literals.move(self.literal_prop_id, self.literal_prop_id - 1) assert obj
props = tool.Drawing.get_text_props(obj)
props.literals.move(self.literal_prop_id, self.literal_prop_id - 1)
return {"FINISHED"} return {"FINISHED"}
@@ -2895,7 +2903,9 @@ class OrderTextLiteralDown(bpy.types.Operator):
def execute(self, context): def execute(self, context):
obj = context.active_object obj = context.active_object
obj.BIMTextProperties.literals.move(self.literal_prop_id, self.literal_prop_id + 1) assert obj
props = tool.Drawing.get_text_props(obj)
props.literals.move(self.literal_prop_id, self.literal_prop_id + 1)
return {"FINISHED"} return {"FINISHED"}
+15 -2
View File
@@ -44,7 +44,7 @@ from bpy.props import (
CollectionProperty, CollectionProperty,
BoolVectorProperty, BoolVectorProperty,
) )
from typing import TYPE_CHECKING, Literal from typing import TYPE_CHECKING, Literal, Any
diagram_scales_enum = [] diagram_scales_enum = []
@@ -613,7 +613,13 @@ class BIMTextProperties(PropertyGroup):
) )
newline_at: IntProperty(name="Newline At") newline_at: IntProperty(name="Newline At")
def get_text_edited_data(self): if TYPE_CHECKING:
is_editing: bool
literals: bpy.types.bpy_prop_collection_idprop[LiteralProps]
font_size: str
newline_at: int
def get_text_edited_data(self) -> dict[str, Any]:
"""should be called only if `is_editing` """should be called only if `is_editing`
otherwise should use `DecoratorData.get_ifc_text_data(obj)` instead otherwise should use `DecoratorData.get_ifc_text_data(obj)` instead
because this data could be out of date because this data could be out of date
@@ -676,3 +682,10 @@ class BIMAnnotationProperties(PropertyGroup):
) )
is_adding_type: bpy.props.BoolProperty(default=False) is_adding_type: bpy.props.BoolProperty(default=False)
type_name: bpy.props.StringProperty(name="Name", default="TYPEX") type_name: bpy.props.StringProperty(name="Name", default="TYPEX")
if TYPE_CHECKING:
object_type: str
relating_type_id: str
create_representation_for_type: bool
is_adding_type: bool
type_name: str
+2 -1
View File
@@ -520,7 +520,8 @@ class BIM_PT_text(Panel):
def draw(self, context): def draw(self, context):
obj = context.active_object obj = context.active_object
props = obj.BIMTextProperties assert obj
props = tool.Drawing.get_text_props(obj)
if props.is_editing: if props.is_editing:
# shares most of the code with EditTextPopup.draw() # shares most of the code with EditTextPopup.draw()
@@ -45,7 +45,7 @@ class LaunchAnnotationTypeManager(bpy.types.Operator):
if not AnnotationData.is_loaded: if not AnnotationData.is_loaded:
AnnotationData.load() AnnotationData.load()
props = context.scene.BIMAnnotationProperties props = tool.Drawing.get_annotation_props()
columns = self.layout.column_flow(columns=3) columns = self.layout.column_flow(columns=3)
row = columns.row() row = columns.row()
@@ -155,7 +155,7 @@ def add_layout_hotkey_operator(
# TODO: move to operator # TODO: move to operator
def create_annotation_occurrence(context): def create_annotation_occurrence(context):
props = context.scene.BIMAnnotationProperties props = tool.Drawing.get_annotation_props()
relating_type = tool.Ifc.get().by_id(int(props.relating_type_id)) relating_type = tool.Ifc.get().by_id(int(props.relating_type_id))
object_type = props.object_type object_type = props.object_type
@@ -200,7 +200,7 @@ class AnnotationToolUI:
@classmethod @classmethod
def draw(cls, context, layout): def draw(cls, context, layout):
cls.layout = layout cls.layout = layout
cls.props = context.scene.BIMAnnotationProperties cls.props = tool.Drawing.get_annotation_props()
row = cls.layout.row(align=True) row = cls.layout.row(align=True)
if not tool.Ifc.get(): if not tool.Ifc.get():
@@ -279,19 +279,19 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator):
self.report({"ERROR"}, "No drawing active for annotation hotkeys.") self.report({"ERROR"}, "No drawing active for annotation hotkeys.")
return {"CANCELLED"} return {"CANCELLED"}
self.props = context.scene.BIMAnnotationProperties self.props = tool.Drawing.get_annotation_props()
getattr(self, f"hotkey_{self.hotkey}")() getattr(self, f"hotkey_{self.hotkey}")()
def invoke(self, context, event): def invoke(self, context, event):
# https://blender.stackexchange.com/questions/276035/how-do-i-make-operators-remember-their-property-values-when-called-from-a-hotkey # https://blender.stackexchange.com/questions/276035/how-do-i-make-operators-remember-their-property-values-when-called-from-a-hotkey
self.props = context.scene.BIMAnnotationProperties self.props = tool.Drawing.get_annotation_props()
return self.execute(context) return self.execute(context)
def draw(self, context): def draw(self, context):
pass pass
def hotkey_S_T(self): def hotkey_S_T(self):
props = bpy.context.scene.BIMAnnotationProperties props = tool.Drawing.get_annotation_props()
object_type = props.object_type object_type = props.object_type
if object_type not in tool.Drawing.ANNOTATION_TYPES_SUPPORT_SETUP: if object_type not in tool.Drawing.ANNOTATION_TYPES_SUPPORT_SETUP:
@@ -743,7 +743,7 @@ class OverrideDelete(bpy.types.Operator):
else: else:
bpy.data.objects.remove(obj) bpy.data.objects.remove(obj)
for opening in context.scene.BIMModelProperties.openings: for opening in tool.Model.get_model_props().openings:
if opening.obj is not None and not tool.Ifc.get_entity(opening.obj): if opening.obj is not None and not tool.Ifc.get_entity(opening.obj):
bpy.data.objects.remove(opening.obj) bpy.data.objects.remove(opening.obj)
tool.Model.purge_scene_openings() tool.Model.purge_scene_openings()
@@ -1874,7 +1874,7 @@ class OverrideEscape(bpy.types.Operator):
elif context.scene.BIMGeometryProperties.mode == "EDIT": elif context.scene.BIMGeometryProperties.mode == "EDIT":
bpy.ops.bim.override_mode_set_object("INVOKE_DEFAULT", should_save=False) bpy.ops.bim.override_mode_set_object("INVOKE_DEFAULT", should_save=False)
tool.Geometry.disable_item_mode() tool.Geometry.disable_item_mode()
elif context.scene.BIMModelProperties.openings: elif tool.Model.get_model_props().openings:
bpy.ops.bim.hide_all_openings() bpy.ops.bim.hide_all_openings()
elif context.scene.BIMAggregateProperties.in_aggregate_mode: elif context.scene.BIMAggregateProperties.in_aggregate_mode:
bpy.ops.bim.disable_aggregate_mode() bpy.ops.bim.disable_aggregate_mode()
+10 -4
View File
@@ -51,7 +51,7 @@ class AuthoringData:
@classmethod @classmethod
def load(cls, ifc_element_type=None): def load(cls, ifc_element_type=None):
cls.is_loaded = True cls.is_loaded = True
cls.props = bpy.context.scene.BIMModelProperties cls.props = tool.Model.get_model_props()
if ifc_element_type: if ifc_element_type:
cls.ifc_element_type = None if ifc_element_type == "all" else ifc_element_type cls.ifc_element_type = None if ifc_element_type == "all" else ifc_element_type
cls.data["default_container"] = cls.default_container() cls.data["default_container"] = cls.default_container()
@@ -535,7 +535,9 @@ class DoorData:
@classmethod @classmethod
def general_params(cls): def general_params(cls):
props = bpy.context.active_object.BIMDoorProperties obj = bpy.context.active_object
assert obj
props = tool.Model.get_door_props(obj)
data = cls.data["pset_data"]["data_dict"] data = cls.data["pset_data"]["data_dict"]
general_params = {} general_params = {}
general_props = props.get_general_kwargs() general_props = props.get_general_kwargs()
@@ -546,7 +548,9 @@ class DoorData:
@classmethod @classmethod
def lining_params(cls): def lining_params(cls):
props = bpy.context.active_object.BIMDoorProperties obj = bpy.context.active_object
assert obj
props = tool.Model.get_door_props(obj)
data = cls.data["pset_data"]["data_dict"] data = cls.data["pset_data"]["data_dict"]
lining_data = data["lining_properties"] lining_data = data["lining_properties"]
lining_params = {} lining_params = {}
@@ -558,7 +562,9 @@ class DoorData:
@classmethod @classmethod
def panel_params(cls): def panel_params(cls):
props = bpy.context.active_object.BIMDoorProperties obj = bpy.context.active_object
assert obj
props = tool.Model.get_door_props(obj)
data = cls.data["pset_data"]["data_dict"] data = cls.data["pset_data"]["data_dict"]
panel_data = cls.data["pset_data"]["data_dict"]["panel_properties"] panel_data = cls.data["pset_data"]["data_dict"]["panel_properties"]
panel_params = {} panel_params = {}
@@ -829,7 +829,7 @@ class ProductDecorator:
polyline_points = polyline_data[0].polyline_points if polyline_data else [] polyline_points = polyline_data[0].polyline_points if polyline_data else []
self.relating_type = None self.relating_type = None
props = context.scene.BIMModelProperties props = tool.Model.get_model_props()
relating_type_id = props.relating_type_id relating_type_id = props.relating_type_id
if relating_type_id: if relating_type_id:
self.relating_type = tool.Ifc.get().by_id(int(relating_type_id)) self.relating_type = tool.Ifc.get().by_id(int(relating_type_id))
+16 -9
View File
@@ -41,7 +41,7 @@ V_ = tool.Blender.V_
def update_door_modifier_representation(obj: bpy.types.Object) -> None: def update_door_modifier_representation(obj: bpy.types.Object) -> None:
props = obj.BIMDoorProperties props = tool.Model.get_door_props(obj)
element = tool.Ifc.get_entity(obj) element = tool.Ifc.get_entity(obj)
ifc_file = tool.Ifc.get() ifc_file = tool.Ifc.get()
sliding_door = "SLIDING" in props.door_type sliding_door = "SLIDING" in props.door_type
@@ -338,7 +338,8 @@ def create_bm_door_lining(
def update_door_modifier_bmesh(context: bpy.types.Context) -> None: def update_door_modifier_bmesh(context: bpy.types.Context) -> None:
obj = context.active_object obj = context.active_object
props = obj.BIMDoorProperties assert obj
props = tool.Model.get_door_props(obj)
overall_width = props.overall_width overall_width = props.overall_width
overall_height = props.overall_height overall_height = props.overall_height
@@ -572,9 +573,10 @@ class AddDoor(bpy.types.Operator, tool.Ifc.Operator):
bl_description = "Add a Parametric Door to the Selected IFC Door Elements" bl_description = "Add a Parametric Door to the Selected IFC Door Elements"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def add_door_on_object(self, obj): def add_door_on_object(self, obj: bpy.types.Object) -> None:
element = tool.Ifc.get_entity(obj) element = tool.Ifc.get_entity(obj)
props = obj.BIMDoorProperties assert element
props = tool.Model.get_door_props(obj)
door_data = props.get_general_kwargs(convert_to_project_units=True) door_data = props.get_general_kwargs(convert_to_project_units=True)
lining_props = props.get_lining_kwargs(convert_to_project_units=True) lining_props = props.get_lining_kwargs(convert_to_project_units=True)
@@ -608,11 +610,12 @@ class CancelEditingDoor(bpy.types.Operator, tool.Ifc.Operator):
bl_label = "Cancel Editing Door on Selected Objects" bl_label = "Cancel Editing Door on Selected Objects"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def cancel_editing_door_on_object(self, obj): def cancel_editing_door_on_object(self, obj: bpy.types.Object) -> None:
element = tool.Ifc.get_entity(obj) element = tool.Ifc.get_entity(obj)
assert element
if not tool.Blender.Modifier.is_door(element): if not tool.Blender.Modifier.is_door(element):
return return
props = obj.BIMDoorProperties props = tool.Model.get_door_props(obj)
data = json.loads(ifcopenshell.util.element.get_pset(element, "BBIM_Door", "Data")) data = json.loads(ifcopenshell.util.element.get_pset(element, "BBIM_Door", "Data"))
data.update(data.pop("lining_properties")) data.update(data.pop("lining_properties"))
data.update(data.pop("panel_properties")) data.update(data.pop("panel_properties"))
@@ -646,9 +649,10 @@ class FinishEditingDoor(bpy.types.Operator, tool.Ifc.Operator):
def finish_editing_door_on_object(self, obj): def finish_editing_door_on_object(self, obj):
element = tool.Ifc.get_entity(obj) element = tool.Ifc.get_entity(obj)
assert element
if not tool.Blender.Modifier.is_door(element): if not tool.Blender.Modifier.is_door(element):
return return
props = obj.BIMDoorProperties props = tool.Model.get_door_props(obj)
door_data = props.get_general_kwargs(convert_to_project_units=True) door_data = props.get_general_kwargs(convert_to_project_units=True)
lining_props = props.get_lining_kwargs(convert_to_project_units=True) lining_props = props.get_lining_kwargs(convert_to_project_units=True)
@@ -678,9 +682,10 @@ class EnableEditingDoor(bpy.types.Operator, tool.Ifc.Operator):
def edit_door_on_obj(self, obj): def edit_door_on_obj(self, obj):
element = tool.Ifc.get_entity(obj) element = tool.Ifc.get_entity(obj)
assert element
if not tool.Blender.Modifier.is_door(element): if not tool.Blender.Modifier.is_door(element):
return return
props = obj.BIMDoorProperties props = tool.Model.get_door_props(obj)
data = json.loads(ifcopenshell.util.element.get_pset(element, "BBIM_Door", "Data")) data = json.loads(ifcopenshell.util.element.get_pset(element, "BBIM_Door", "Data"))
data.update(data.pop("lining_properties")) data.update(data.pop("lining_properties"))
data.update(data.pop("panel_properties")) data.update(data.pop("panel_properties"))
@@ -702,9 +707,11 @@ class RemoveDoor(bpy.types.Operator, tool.Ifc.Operator):
def remove_door_on_object(self, obj): def remove_door_on_object(self, obj):
element = tool.Ifc.get_entity(obj) element = tool.Ifc.get_entity(obj)
assert element
if not tool.Blender.Modifier.is_door(element): if not tool.Blender.Modifier.is_door(element):
return return
obj.BIMDoorProperties.is_editing = False props = tool.Model.get_door_props(obj)
props.is_editing = False
pset = tool.Pset.get_element_pset(element, "BBIM_Door") pset = tool.Pset.get_element_pset(element, "BBIM_Door")
ifcopenshell.api.run("pset.remove_pset", tool.Ifc.get(), product=element, pset=pset) ifcopenshell.api.run("pset.remove_pset", tool.Ifc.get(), product=element, pset=pset)
+10 -7
View File
@@ -60,7 +60,7 @@ class FilledOpeningGenerator:
:param target: Target opening position. If ommited, cursor position is used. :param target: Target opening position. If ommited, cursor position is used.
:return: None if there was no errors, otherwise returns a string with error message. :return: None if there was no errors, otherwise returns a string with error message.
""" """
props = bpy.context.scene.BIMModelProperties props = tool.Model.get_model_props()
opening_thickness_si = 0.0 opening_thickness_si = 0.0
filling = tool.Ifc.get_entity(filling_obj) filling = tool.Ifc.get_entity(filling_obj)
@@ -531,7 +531,8 @@ class UpdateOpeningsFocus(Operator):
return {"FINISHED"} return {"FINISHED"}
openings = set() openings = set()
building_objects = set() building_objects = set()
for opening in context.scene.BIMModelProperties.openings: props = tool.Model.get_model_props()
for opening in props.openings:
if opening.obj: if opening.obj:
openings.add(opening.obj) openings.add(opening.obj)
opening_element = tool.Ifc.get_entity(opening.obj) opening_element = tool.Ifc.get_entity(opening.obj)
@@ -545,7 +546,7 @@ class UpdateOpeningsFocus(Operator):
obj.color[2], obj.color[2],
( (
1 1
if not context.scene.BIMModelProperties.openings if not props.openings
or not building_objects or not building_objects
or obj in openings or obj in openings
or obj in building_objects or obj in building_objects
@@ -558,7 +559,8 @@ class UpdateOpeningsFocus(Operator):
def hide_openings(context: bpy.types.Context, objects: Sequence[bpy.types.Object]) -> None: def hide_openings(context: bpy.types.Context, objects: Sequence[bpy.types.Object]) -> None:
objects_to_remove = set() objects_to_remove = set()
for opening_prop in context.scene.BIMModelProperties.openings: props = tool.Model.get_model_props()
for opening_prop in props.openings:
opening_obj = opening_prop.obj opening_obj = opening_prop.obj
if not opening_obj: if not opening_obj:
continue continue
@@ -623,7 +625,7 @@ class EditOpenings(Operator, tool.Ifc.Operator):
def get_buildings_and_openings( def get_buildings_and_openings(
self, context: bpy.types.Context self, context: bpy.types.Context
) -> tuple[set[bpy.types.Object], set[ifcopenshell.entity_instance]]: ) -> tuple[set[bpy.types.Object], set[ifcopenshell.entity_instance]]:
props = context.scene.BIMModelProperties props = tool.Model.get_model_props()
building_objs: set[bpy.types.Object] = set() building_objs: set[bpy.types.Object] = set()
opening_elements: set[ifcopenshell.entity_instance] = set() opening_elements: set[ifcopenshell.entity_instance] = set()
objects_to_remove = set() objects_to_remove = set()
@@ -892,7 +894,8 @@ class DecorationsHandler:
batch.draw(shader) batch.draw(shader)
def __call__(self, context): def __call__(self, context):
if not context.scene.BIMModelProperties.openings: props = tool.Model.get_model_props()
if not props.openings:
return return
self.addon_prefs = tool.Blender.get_addon_preferences() self.addon_prefs = tool.Blender.get_addon_preferences()
selected_elements_color = self.addon_prefs.decorator_color_selected selected_elements_color = self.addon_prefs.decorator_color_selected
@@ -907,7 +910,7 @@ class DecorationsHandler:
gpu.state.point_size_set(6) gpu.state.point_size_set(6)
gpu.state.blend_set("ALPHA") gpu.state.blend_set("ALPHA")
for opening in context.scene.BIMModelProperties.openings: for opening in props.openings:
obj = opening.obj obj = opening.obj
if context.scene.BIMGeometryProperties.representation_obj == obj: if context.scene.BIMGeometryProperties.representation_obj == obj:
# We are editing the representation of the opening : # We are editing the representation of the opening :
+12 -10
View File
@@ -23,6 +23,7 @@ import math
import bmesh import bmesh
import ifcopenshell import ifcopenshell
import ifcopenshell.api import ifcopenshell.api
import ifcopenshell.geom
import ifcopenshell.util.unit import ifcopenshell.util.unit
import ifcopenshell.util.element import ifcopenshell.util.element
import ifcopenshell.util.placement import ifcopenshell.util.placement
@@ -40,7 +41,7 @@ from mathutils import Vector, Matrix, Quaternion
from bonsai.bim.module.model.opening import FilledOpeningGenerator from bonsai.bim.module.model.opening import FilledOpeningGenerator
from bonsai.bim.module.model.decorator import PolylineDecorator from bonsai.bim.module.model.decorator import PolylineDecorator
from bonsai.bim.module.geometry.decorator import ItemDecorator from bonsai.bim.module.geometry.decorator import ItemDecorator
from typing import Optional, Union, Literal from typing import Optional, Union, Literal, Any
from lark import Lark, Transformer from lark import Lark, Transformer
@@ -63,7 +64,7 @@ def create_bmesh_from_vertices(vertices, is_closed=False):
def get_wall_preview_data(context, relating_type): def get_wall_preview_data(context, relating_type):
# Get properties from object type # Get properties from object type
model_props = context.scene.BIMModelProperties model_props = tool.Model.get_model_props()
direction_sense = model_props.direction_sense direction_sense = model_props.direction_sense
direction = 1 direction = 1
if direction_sense == "NEGATIVE": if direction_sense == "NEGATIVE":
@@ -190,9 +191,8 @@ def get_wall_preview_data(context, relating_type):
def get_slab_preview_data(context, relating_type): def get_slab_preview_data(context, relating_type):
props = context.scene.BIMModelProperties model_props = tool.Model.get_model_props()
x_angle = 0 if tool.Cad.is_x(props.x_angle, 0, tolerance=0.001) else props.x_angle x_angle = 0 if tool.Cad.is_x(model_props.x_angle, 0, tolerance=0.001) else model_props.x_angle
model_props = context.scene.BIMModelProperties
direction_sense = model_props.direction_sense direction_sense = model_props.direction_sense
direction = 1 direction = 1
if direction_sense == "NEGATIVE": if direction_sense == "NEGATIVE":
@@ -254,14 +254,16 @@ def get_slab_preview_data(context, relating_type):
return data return data
def get_vertical_profile_preview_data(context, relating_type): def get_vertical_profile_preview_data(
context: bpy.types.Context, relating_type: ifcopenshell.entity_instance
) -> dict[str, Any]:
material = ifcopenshell.util.element.get_material(relating_type) material = ifcopenshell.util.element.get_material(relating_type)
try: try:
profile = material.MaterialProfiles[0].Profile profile = material.MaterialProfiles[0].Profile
except: except:
return {} return {}
model_props = context.scene.BIMModelProperties model_props = tool.Model.get_model_props()
extrusion_depth = model_props.extrusion_depth extrusion_depth = model_props.extrusion_depth
cardinal_point = model_props.cardinal_point cardinal_point = model_props.cardinal_point
rot_mat = Quaternion() rot_mat = Quaternion()
@@ -373,7 +375,7 @@ def get_horizontal_profile_preview_data(context, relating_type):
except: except:
return {} return {}
model_props = context.scene.BIMModelProperties model_props = tool.Model.get_model_props()
cardinal_point = model_props.cardinal_point cardinal_point = model_props.cardinal_point
polyline_verts = [] polyline_verts = []
@@ -497,7 +499,7 @@ def get_horizontal_profile_preview_data(context, relating_type):
def get_generic_product_preview_data(context, relating_type): def get_generic_product_preview_data(context, relating_type):
model_props = context.scene.BIMModelProperties props = tool.Model.get_model_props()
if relating_type.is_a("IfcDoorType"): if relating_type.is_a("IfcDoorType"):
rl = float(model_props.rl1) rl = float(model_props.rl1)
elif relating_type.is_a("IfcWindowType"): elif relating_type.is_a("IfcWindowType"):
@@ -914,7 +916,7 @@ class PolylineOperator:
t.value_3d = tri t.value_3d = tri
def set_offset(self, context: bpy.types.Context, relating_type: ifcopenshell.entity_instance) -> None: def set_offset(self, context: bpy.types.Context, relating_type: ifcopenshell.entity_instance) -> None:
props = bpy.context.scene.BIMModelProperties props = tool.Model.get_model_props()
direction_sense = props.direction_sense direction_sense = props.direction_sense
if tool.Model.get_usage_type(relating_type) == "LAYER2": if tool.Model.get_usage_type(relating_type) == "LAYER2":
offset_type = "offset_type_vertical" offset_type = "offset_type_vertical"
@@ -200,7 +200,7 @@ class AddOccurrence(bpy.types.Operator, PolylineOperator):
def modal(self, context, event): def modal(self, context, event):
# Ensure state of BIM tool props is valid # Ensure state of BIM tool props is valid
props = bpy.context.scene.BIMModelProperties props = tool.Model.get_model_props()
relating_type_id = tool.Blender.get_enum_safe(props, "relating_type_id") relating_type_id = tool.Blender.get_enum_safe(props, "relating_type_id")
relating_type_id_data = AuthoringData.data["relating_type_id"] relating_type_id_data = AuthoringData.data["relating_type_id"]
if not relating_type_id and relating_type_id_data: if not relating_type_id and relating_type_id_data:
@@ -284,7 +284,7 @@ class AddConstrTypeInstance(bpy.types.Operator, tool.Ifc.Operator):
) )
def invoke(self, context, event): def invoke(self, context, event):
props = context.scene.BIMModelProperties props = tool.Model.get_model_props()
relating_type_id = self.relating_type_id or props.relating_type_id relating_type_id = self.relating_type_id or props.relating_type_id
if ( if (
relating_type_id relating_type_id
@@ -303,7 +303,7 @@ class AddConstrTypeInstance(bpy.types.Operator, tool.Ifc.Operator):
row.prop(self, "representation_template", text="") row.prop(self, "representation_template", text="")
def _execute(self, context): def _execute(self, context):
props = context.scene.BIMModelProperties props = tool.Model.get_model_props()
relating_type_id = self.relating_type_id or props.relating_type_id relating_type_id = self.relating_type_id or props.relating_type_id
if not relating_type_id: if not relating_type_id:
@@ -507,7 +507,8 @@ class AddConstrTypeInstance(bpy.types.Operator, tool.Ifc.Operator):
def set_flow_segment_rl(self, obj): def set_flow_segment_rl(self, obj):
if self.container_obj: if self.container_obj:
obj.location[2] = self.container_obj.location[2] + bpy.context.scene.BIMModelProperties.rl2 props = tool.Model.get_model_props()
obj.location[2] = self.container_obj.location[2] + props.rl2
@staticmethod @staticmethod
def generate_layered_element(ifc_class: str, relating_type: ifcopenshell.entity_instance) -> bool: def generate_layered_element(ifc_class: str, relating_type: ifcopenshell.entity_instance) -> bool:
@@ -535,7 +536,7 @@ class ChangeTypePage(bpy.types.Operator, tool.Ifc.Operator):
page: bpy.props.IntProperty() page: bpy.props.IntProperty()
def _execute(self, context): def _execute(self, context):
props = context.scene.BIMModelProperties props = tool.Model.get_model_props()
bpy.ops.bim.load_type_thumbnails(ifc_class=props.ifc_class, offset=9 * (self.page - 1), limit=9) bpy.ops.bim.load_type_thumbnails(ifc_class=props.ifc_class, offset=9 * (self.page - 1), limit=9)
props.type_page = self.page props.type_page = self.page
return {"FINISHED"} return {"FINISHED"}
@@ -548,7 +549,7 @@ class SetActiveType(bpy.types.Operator, tool.Ifc.Operator):
relating_type: bpy.props.IntProperty() relating_type: bpy.props.IntProperty()
def _execute(self, context): def _execute(self, context):
props = context.scene.BIMModelProperties props = tool.Model.get_model_props()
props.relating_type_id = str(self.relating_type) props.relating_type_id = str(self.relating_type)
@@ -623,7 +624,7 @@ class LoadTypeThumbnails(bpy.types.Operator, tool.Ifc.Operator):
if bpy.app.background: if bpy.app.background:
return return
props = bpy.context.scene.BIMModelProperties props = tool.Model.get_model_props()
# Only process at most one paginated class at a time. # Only process at most one paginated class at a time.
# Large projects have hundreds of types which can lead to unnecessary lag. # Large projects have hundreds of types which can lead to unnecessary lag.
if not AuthoringData.is_loaded: if not AuthoringData.is_loaded:
@@ -57,7 +57,7 @@ class DumbProfileGenerator:
self.body_context = ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Model", "Body", "MODEL_VIEW") self.body_context = ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Model", "Body", "MODEL_VIEW")
self.axis_context = ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Model", "Axis", "GRAPH_VIEW") self.axis_context = ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Model", "Axis", "GRAPH_VIEW")
props = bpy.context.scene.BIMModelProperties props = tool.Model.get_model_props()
self.container = None self.container = None
self.container_obj = None self.container_obj = None
@@ -68,7 +68,7 @@ class DumbProfileGenerator:
self.depth = props.extrusion_depth self.depth = props.extrusion_depth
self.rotation = 0 self.rotation = 0
self.location = Vector((0, 0, 0)) self.location = Vector((0, 0, 0))
self.cardinal_point = int(bpy.context.scene.BIMModelProperties.cardinal_point) self.cardinal_point = int(props.cardinal_point)
if insertion_type == "POLYLINE": if insertion_type == "POLYLINE":
return self.derive_from_polyline() return self.derive_from_polyline()
elif insertion_type == "CURSOR": elif insertion_type == "CURSOR":
@@ -1123,7 +1123,7 @@ class DrawPolylineProfile(bpy.types.Operator, PolylineOperator):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.relating_type = None self.relating_type = None
props = bpy.context.scene.BIMModelProperties props = tool.Model.get_model_props()
relating_type_id = props.relating_type_id relating_type_id = props.relating_type_id
if relating_type_id: if relating_type_id:
self.relating_type = tool.Ifc.get().by_id(int(relating_type_id)) self.relating_type = tool.Ifc.get().by_id(int(relating_type_id))
@@ -1132,7 +1132,7 @@ class DrawPolylineProfile(bpy.types.Operator, PolylineOperator):
if not self.relating_type: if not self.relating_type:
return {"FINISHED"} return {"FINISHED"}
model_props = context.scene.BIMModelProperties model_props = tool.Model.get_model_props()
direction_sense = model_props.direction_sense direction_sense = model_props.direction_sense
offset = model_props.offset offset = model_props.offset
+85 -12
View File
@@ -26,6 +26,7 @@ from bonsai.bim.module.model.data import AuthoringData
from bpy.types import PropertyGroup, NodeTree from bpy.types import PropertyGroup, NodeTree
from math import pi, radians from math import pi, radians
from bonsai.bim.module.model.decorator import WallAxisDecorator, SlabDirectionDecorator from bonsai.bim.module.model.decorator import WallAxisDecorator, SlabDirectionDecorator
from typing import TYPE_CHECKING, Literal, get_args
def get_ifc_class(self, context): def get_ifc_class(self, context):
@@ -230,6 +231,39 @@ class BIMModelProperties(PropertyGroup):
update=update_slab_direction_decorator, update=update_slab_direction_decorator,
) )
if TYPE_CHECKING:
ifc_class: str
relating_type_id: str
search_name: str
menu_relating_type_id: int
icon_id: int
updating: bool
occurrence_name_style: Literal["CLASS", "TYPE", "CUSTOM"]
occurrence_name_function: str
extrusion_depth: float
cardinal_point: Literal[
"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19"
]
length: float
openings: bpy.types.bpy_prop_collection_idprop[ObjProperty]
x: float
y: float
z: float
rl_mode: Literal["BOTTOM", "CONTAINER", "CURSOR"]
rl1: float
rl2: float
rl3: float
type_page: int
x_angle: float
type_name: str
boundary_class: str
direction_sense: Literal["POSITIVE", "NEGATIVE"]
offset_type_vertical: Literal["EXTERIOR", "CENTER", "INTERIOR"]
offset_type_horizontal: Literal["TOP", "CENTER", "BOTTOM"]
offset: float
show_wall_axis: bool
show_slab_direction: bool
class BIMArrayProperties(PropertyGroup): class BIMArrayProperties(PropertyGroup):
is_editing: bpy.props.IntProperty( is_editing: bpy.props.IntProperty(
@@ -550,21 +584,24 @@ class BIMWindowProperties(PropertyGroup):
setattr(self, prop_name, kwargs[prop_name]) setattr(self, prop_name, kwargs[prop_name])
DoorType = Literal[
"SINGLE_SWING_LEFT",
"SINGLE_SWING_RIGHT",
"DOUBLE_SWING_LEFT",
"DOUBLE_SWING_RIGHT",
"DOUBLE_DOOR_SINGLE_SWING",
"SLIDING_TO_LEFT",
"SLIDING_TO_RIGHT",
"DOUBLE_DOOR_SLIDING",
]
class BIMDoorProperties(PropertyGroup): class BIMDoorProperties(PropertyGroup):
non_si_units_props = ("is_editing", "door_type", "panel_width_ratio") non_si_units_props = ("is_editing", "door_type", "panel_width_ratio")
door_types = (
("SINGLE_SWING_LEFT", "SINGLE_SWING_LEFT", ""),
("SINGLE_SWING_RIGHT", "SINGLE_SWING_RIGHT", ""),
("DOUBLE_SWING_LEFT", "DOUBLE_SWING_LEFT", ""),
("DOUBLE_SWING_RIGHT", "DOUBLE_SWING_RIGHT", ""),
("DOUBLE_DOOR_SINGLE_SWING", "DOUBLE_DOOR_SINGLE_SWING", ""),
("SLIDING_TO_LEFT", "SLIDING_TO_LEFT", ""),
("SLIDING_TO_RIGHT", "SLIDING_TO_RIGHT", ""),
("DOUBLE_DOOR_SLIDING", "DOUBLE_DOOR_SLIDING", ""),
)
is_editing: bpy.props.BoolProperty(default=False) is_editing: bpy.props.BoolProperty(default=False)
door_type: bpy.props.EnumProperty(name="Door Operation Type", items=door_types, default="SINGLE_SWING_LEFT") door_type: bpy.props.EnumProperty(
name="Door Operation Type", items=tuple((i, i, "") for i in get_args(DoorType)), default="SINGLE_SWING_LEFT"
)
overall_height: bpy.props.FloatProperty(name="Overall Height", default=2.0, subtype="DISTANCE") overall_height: bpy.props.FloatProperty(name="Overall Height", default=2.0, subtype="DISTANCE")
overall_width: bpy.props.FloatProperty(name="Overall Width", default=0.9, subtype="DISTANCE") overall_width: bpy.props.FloatProperty(name="Overall Width", default=0.9, subtype="DISTANCE")
@@ -631,6 +668,42 @@ class BIMDoorProperties(PropertyGroup):
panel_material: bpy.props.EnumProperty(name="Panel Material", items=get_materials, options=set()) panel_material: bpy.props.EnumProperty(name="Panel Material", items=get_materials, options=set())
lining_material: bpy.props.EnumProperty(name="Lining Material", items=get_materials, options=set()) lining_material: bpy.props.EnumProperty(name="Lining Material", items=get_materials, options=set())
if TYPE_CHECKING:
is_editing: bool
door_type: DoorType
overall_height: float
overall_width: float
# Lining.
lining_depth: float
lining_thickness: float
lining_offset: float
lining_to_panel_offset_x: float
lining_to_panel_offset_y: float
# Transom.
transom_thickness: float
transom_offset: float
# Casing.
casing_thickness: float
casing_depth: float
# Threshold.
threshold_thickness: float
threshold_depth: float
threshold_offset: float
# Panel.
panel_depth: float
panel_width_ratio: float
frame_thickness: float
frame_depth: float
# Material.
panel_material: str
lining_material: str
def get_general_kwargs(self, convert_to_project_units=False): def get_general_kwargs(self, convert_to_project_units=False):
kwargs = { kwargs = {
"door_type": self.door_type, "door_type": self.door_type,
+9 -11
View File
@@ -62,7 +62,7 @@ class DumbSlabGenerator:
tool.Ifc.get(), "Plan", "FootPrint", "SKETCH_VIEW" tool.Ifc.get(), "Plan", "FootPrint", "SKETCH_VIEW"
) )
props = bpy.context.scene.BIMModelProperties props = tool.Model.get_model_props()
self.polyline = None self.polyline = None
self.container = None self.container = None
@@ -319,7 +319,7 @@ class DumbSlabPlaner:
extrusion.Position.Location.Coordinates = tuple(rot_offset) extrusion.Position.Location.Coordinates = tuple(rot_offset)
else: else:
props = bpy.context.scene.BIMModelProperties props = tool.Model.get_model_props()
x_angle = 0 if tool.Cad.is_x(props.x_angle, 0, tolerance=0.001) else props.x_angle x_angle = 0 if tool.Cad.is_x(props.x_angle, 0, tolerance=0.001) else props.x_angle
new_rep = ifcopenshell.api.run( new_rep = ifcopenshell.api.run(
"geometry.add_slab_representation", "geometry.add_slab_representation",
@@ -344,7 +344,7 @@ class DumbSlabPlaner:
) )
return return
else: else:
props = bpy.context.scene.BIMModelProperties props = tool.Model.get_model_props()
x_angle = 0 if tool.Cad.is_x(props.x_angle, 0, tolerance=0.001) else props.x_angle x_angle = 0 if tool.Cad.is_x(props.x_angle, 0, tolerance=0.001) else props.x_angle
representation = ifcopenshell.api.run( representation = ifcopenshell.api.run(
"geometry.add_slab_representation", "geometry.add_slab_representation",
@@ -844,7 +844,7 @@ class AddSlabFromWall(bpy.types.Operator, tool.Ifc.Operator):
def __init__(self): def __init__(self):
self.relating_type = None self.relating_type = None
props = bpy.context.scene.BIMModelProperties props = tool.Model.get_model_props()
relating_type_id = props.relating_type_id relating_type_id = props.relating_type_id
if relating_type_id: if relating_type_id:
self.relating_type = tool.Ifc.get().by_id(int(relating_type_id)) self.relating_type = tool.Ifc.get().by_id(int(relating_type_id))
@@ -876,7 +876,7 @@ class DrawPolylineSlab(bpy.types.Operator, PolylineOperator):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.relating_type = None self.relating_type = None
props = bpy.context.scene.BIMModelProperties props = tool.Model.get_model_props()
relating_type_id = props.relating_type_id relating_type_id = props.relating_type_id
if relating_type_id: if relating_type_id:
self.relating_type = tool.Ifc.get().by_id(int(relating_type_id)) self.relating_type = tool.Ifc.get().by_id(int(relating_type_id))
@@ -887,7 +887,7 @@ class DrawPolylineSlab(bpy.types.Operator, PolylineOperator):
slab = DumbSlabGenerator(self.relating_type).generate("POLYLINE") slab = DumbSlabGenerator(self.relating_type).generate("POLYLINE")
model_props = context.scene.BIMModelProperties model_props = tool.Model.get_model_props()
direction_sense = model_props.direction_sense direction_sense = model_props.direction_sense
offset = model_props.offset offset = model_props.offset
model = IfcStore.get_file() model = IfcStore.get_file()
@@ -920,13 +920,11 @@ class DrawPolylineSlab(bpy.types.Operator, PolylineOperator):
self.handle_mouse_move(context, event) self.handle_mouse_move(context, event)
return {"PASS_THROUGH"} return {"PASS_THROUGH"}
props = tool.Model.get_model_props()
if event.value == "RELEASE" and event.type == "F": if event.value == "RELEASE" and event.type == "F":
direction_sense = context.scene.BIMModelProperties.direction_sense direction_sense = props.direction_sense
context.scene.BIMModelProperties.direction_sense = ( props.direction_sense = "NEGATIVE" if direction_sense == "POSITIVE" else "POSITIVE"
"NEGATIVE" if direction_sense == "POSITIVE" else "POSITIVE"
)
props = bpy.context.scene.BIMModelProperties
if event.value == "RELEASE" and event.type == "O": if event.value == "RELEASE" and event.type == "O":
items = ["TOP", "CENTER", "BOTTOM"] items = ["TOP", "CENTER", "BOTTOM"]
index = items.index(props.offset_type_horizontal) index = items.index(props.offset_type_horizontal)
+7 -5
View File
@@ -55,7 +55,7 @@ class BIM_MT_type_menu(bpy.types.Menu):
relating_type_id: bpy.props.IntProperty(name="Relating Type Id") relating_type_id: bpy.props.IntProperty(name="Relating Type Id")
def draw(self, context): def draw(self, context):
props = context.scene.BIMModelProperties props = tool.Model.get_model_props()
layout = self.layout layout = self.layout
op = layout.operator("bim.launch_rename_type", icon="GREASEPENCIL", text="Rename Type") op = layout.operator("bim.launch_rename_type", icon="GREASEPENCIL", text="Rename Type")
op.element = props.menu_relating_type_id op.element = props.menu_relating_type_id
@@ -74,7 +74,7 @@ class LaunchTypeMenu(bpy.types.Operator):
relating_type_id: bpy.props.IntProperty(name="Relating Type Id") relating_type_id: bpy.props.IntProperty(name="Relating Type Id")
def execute(self, context): def execute(self, context):
props = context.scene.BIMModelProperties props = tool.Model.get_model_props()
props.menu_relating_type_id = self.relating_type_id props.menu_relating_type_id = self.relating_type_id
bpy.ops.wm.call_menu(name="BIM_MT_type_menu") bpy.ops.wm.call_menu(name="BIM_MT_type_menu")
return {"FINISHED"} return {"FINISHED"}
@@ -90,7 +90,7 @@ class LaunchTypeManager(bpy.types.Operator):
return {"FINISHED"} return {"FINISHED"}
def invoke(self, context, event): def invoke(self, context, event):
props = context.scene.BIMModelProperties props = tool.Model.get_model_props()
props.type_page = 1 props.type_page = 1
if get_ifc_class(None, context): if get_ifc_class(None, context):
ifc_class = AuthoringData.data["ifc_class_current"] or AuthoringData.data["ifc_element_type"] ifc_class = AuthoringData.data["ifc_class_current"] or AuthoringData.data["ifc_element_type"]
@@ -103,7 +103,7 @@ class LaunchTypeManager(bpy.types.Operator):
return context.window_manager.invoke_props_dialog(self, width=550, title="Type Manager", confirm_text="Close") return context.window_manager.invoke_props_dialog(self, width=550, title="Type Manager", confirm_text="Close")
def draw(self, context): def draw(self, context):
props = context.scene.BIMModelProperties props = tool.Model.get_model_props()
row = self.layout.row(align=True) row = self.layout.row(align=True)
text = f"{AuthoringData.data['total_types']} {AuthoringData.data['ifc_element_type'] or 'Types'}" text = f"{AuthoringData.data['total_types']} {AuthoringData.data['ifc_element_type'] or 'Types'}"
if AuthoringData.data["total_types"] > 1: if AuthoringData.data["total_types"] > 1:
@@ -518,7 +518,9 @@ class BIM_PT_door(bpy.types.Panel):
if not DoorData.is_loaded: if not DoorData.is_loaded:
DoorData.load() DoorData.load()
props = context.active_object.BIMDoorProperties obj = context.active_object
assert obj
props = tool.Model.get_door_props(obj)
if DoorData.data["pset_data"]: if DoorData.data["pset_data"]:
row = self.layout.row(align=True) row = self.layout.row(align=True)
+9 -11
View File
@@ -334,7 +334,7 @@ class AddWallsFromSlab(bpy.types.Operator, tool.Ifc.Operator):
def __init__(self): def __init__(self):
self.relating_type = None self.relating_type = None
props = bpy.context.scene.BIMModelProperties props = tool.Model.get_model_props()
relating_type_id = props.relating_type_id relating_type_id = props.relating_type_id
if relating_type_id: if relating_type_id:
self.relating_type = tool.Ifc.get().by_id(int(relating_type_id)) self.relating_type = tool.Ifc.get().by_id(int(relating_type_id))
@@ -368,7 +368,7 @@ class DrawPolylineWall(bpy.types.Operator, PolylineOperator):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.relating_type = None self.relating_type = None
props = bpy.context.scene.BIMModelProperties props = tool.Model.get_model_props()
relating_type_id = props.relating_type_id relating_type_id = props.relating_type_id
if relating_type_id: if relating_type_id:
self.relating_type = tool.Ifc.get().by_id(int(relating_type_id)) self.relating_type = tool.Ifc.get().by_id(int(relating_type_id))
@@ -377,7 +377,7 @@ class DrawPolylineWall(bpy.types.Operator, PolylineOperator):
if not self.relating_type: if not self.relating_type:
return {"FINISHED"} return {"FINISHED"}
model_props = context.scene.BIMModelProperties model_props = tool.Model.get_model_props()
direction_sense = model_props.direction_sense direction_sense = model_props.direction_sense
offset = model_props.offset offset = model_props.offset
@@ -420,17 +420,15 @@ class DrawPolylineWall(bpy.types.Operator, PolylineOperator):
self.handle_mouse_move(context, event) self.handle_mouse_move(context, event)
return {"PASS_THROUGH"} return {"PASS_THROUGH"}
props = tool.Model.get_model_props()
# Wall axis settings # Wall axis settings
if event.value == "RELEASE" and event.type == "F": if event.value == "RELEASE" and event.type == "F":
direction_sense = context.scene.BIMModelProperties.direction_sense direction_sense = props.direction_sense
context.scene.BIMModelProperties.direction_sense = ( props.direction_sense = "NEGATIVE" if direction_sense == "POSITIVE" else "POSITIVE"
"NEGATIVE" if direction_sense == "POSITIVE" else "POSITIVE"
)
self.set_offset(context, self.relating_type) self.set_offset(context, self.relating_type)
props = bpy.context.scene.BIMModelProperties
if event.value == "RELEASE" and event.type == "O": if event.value == "RELEASE" and event.type == "O":
items = ["EXTERIOR", "CENTER", "INTERIOR"] items = ("EXTERIOR", "CENTER", "INTERIOR")
index = items.index(props.offset_type_vertical) index = items.index(props.offset_type_vertical)
size = len(items) size = len(items)
props.offset_type_vertical = items[((index + 1) % size)] props.offset_type_vertical = items[((index + 1) % size)]
@@ -608,7 +606,7 @@ class DumbWallGenerator:
self.body_context = ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Model", "Body", "MODEL_VIEW") self.body_context = ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Model", "Body", "MODEL_VIEW")
self.axis_context = ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Plan", "Axis", "GRAPH_VIEW") self.axis_context = ifcopenshell.util.representation.get_context(tool.Ifc.get(), "Plan", "Axis", "GRAPH_VIEW")
props = bpy.context.scene.BIMModelProperties props = tool.Model.get_model_props()
self.container = None self.container = None
self.container_obj = None self.container_obj = None
@@ -800,7 +798,7 @@ class DumbWallGenerator:
return self.create_wall() return self.create_wall()
def create_wall(self) -> bpy.types.Object: def create_wall(self) -> bpy.types.Object:
props = bpy.context.scene.BIMModelProperties props = tool.Model.get_model_props()
ifc_class = self.get_relating_type_class(self.relating_type) ifc_class = self.get_relating_type_class(self.relating_type)
mesh = bpy.data.meshes.new("Dummy") mesh = bpy.data.meshes.new("Dummy")
obj = bpy.data.objects.new(tool.Model.generate_occurrence_name(self.relating_type, ifc_class), mesh) obj = bpy.data.objects.new(tool.Model.generate_occurrence_name(self.relating_type, ifc_class), mesh)
+3 -2
View File
@@ -21,6 +21,7 @@ import bpy
import json import json
import bmesh import bmesh
import collections import collections
import collections.abc
import ifcopenshell import ifcopenshell
import bonsai.tool as tool import bonsai.tool as tool
import bonsai.core.root import bonsai.core.root
@@ -33,7 +34,7 @@ import ifcopenshell.util.shape_builder
import ifcopenshell.util.unit import ifcopenshell.util.unit
from bmesh.types import BMVert from bmesh.types import BMVert
from mathutils import Vector from mathutils import Vector
from typing import Optional from typing import Optional, Union
V_ = tool.Blender.V_ V_ = tool.Blender.V_
@@ -132,7 +133,7 @@ def update_window_modifier_representation(context: bpy.types.Context) -> None:
def create_bm_window_frame( def create_bm_window_frame(
bm: bmesh.types.BMesh, size: Vector, thickness: list, position: Vector = V_(0, 0, 0).freeze() bm: bmesh.types.BMesh, size: Vector, thickness: Union[float, list[float]], position: Vector = V_(0, 0, 0).freeze()
) -> list[bmesh.types.BMVert]: ) -> list[bmesh.types.BMVert]:
"""`thickness` of the profile is defined as list in the following order: """`thickness` of the profile is defined as list in the following order:
`(LEFT, TOP, RIGHT, BOTTOM)` `(LEFT, TOP, RIGHT, BOTTOM)`
@@ -503,7 +503,7 @@ class CreateObjectUI:
cls, context: bpy.types.Context, layout: bpy.types.UILayout, ifc_element_type: Optional[str] = None cls, context: bpy.types.Context, layout: bpy.types.UILayout, ifc_element_type: Optional[str] = None
) -> None: ) -> None:
cls.layout = layout cls.layout = layout
cls.props = context.scene.BIMModelProperties cls.props = tool.Model.get_model_props()
row = cls.layout.row(align=True) row = cls.layout.row(align=True)
if not tool.Ifc.get(): if not tool.Ifc.get():
@@ -733,7 +733,7 @@ class EditObjectUI:
cls, context: bpy.types.Context, layout: bpy.types.UILayout, ifc_element_type: Optional[str] = None cls, context: bpy.types.Context, layout: bpy.types.UILayout, ifc_element_type: Optional[str] = None
) -> None: ) -> None:
cls.layout = layout cls.layout = layout
cls.props = context.scene.BIMModelProperties cls.props = tool.Model.get_model_props()
row = cls.layout.row(align=True) row = cls.layout.row(align=True)
row.separator() row.separator()
@@ -1099,7 +1099,7 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator):
return operator.description or "" return operator.description or ""
def _execute(self, context): def _execute(self, context):
self.props = context.scene.BIMModelProperties self.props = tool.Model.get_model_props()
self.has_ifc_class = True self.has_ifc_class = True
self.active_class = None self.active_class = None
@@ -1118,7 +1118,7 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator):
def invoke(self, context, event): def invoke(self, context, event):
# https://blender.stackexchange.com/questions/276035/how-do-i-make-operators-remember-their-property-values-when-called-from-a-hotkey # https://blender.stackexchange.com/questions/276035/how-do-i-make-operators-remember-their-property-values-when-called-from-a-hotkey
self.props = context.scene.BIMModelProperties self.props = tool.Model.get_model_props()
self.x = self.props.x self.x = self.props.x
self.y = self.props.y self.y = self.props.y
self.z = self.props.z self.z = self.props.z
@@ -1138,7 +1138,7 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator):
bpy.ops.wm.call_menu(name="BIM_MT_add_representation_item") bpy.ops.wm.call_menu(name="BIM_MT_add_representation_item")
return return
props = bpy.context.scene.BIMModelProperties props = tool.Model.get_model_props()
relating_type_class = AuthoringData.data["ifc_class_current"] relating_type_class = AuthoringData.data["ifc_class_current"]
if not (relating_type_id := tool.Blender.get_enum_safe(props, "relating_type_id")): if not (relating_type_id := tool.Blender.get_enum_safe(props, "relating_type_id")):
self.report({"ERROR"}, "No relating type selected") self.report({"ERROR"}, "No relating type selected")
@@ -1431,7 +1431,7 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator):
bpy.ops.bim.enable_editing_extrusion_axis() bpy.ops.bim.enable_editing_extrusion_axis()
def hotkey_A_O(self): def hotkey_A_O(self):
if bpy.context.scene.BIMModelProperties.openings: if tool.Model.get_model_props().openings:
bpy.ops.bim.edit_openings(apply_all=True) bpy.ops.bim.edit_openings(apply_all=True)
else: else:
bpy.ops.bim.show_openings() bpy.ops.bim.show_openings()
@@ -579,7 +579,7 @@ class AddElement(bpy.types.Operator, tool.Ifc.Operator):
if props.ifc_product == "IfcFeatureElement": if props.ifc_product == "IfcFeatureElement":
tool.Feature.add_feature(props.featured_obj, [obj]) tool.Feature.add_feature(props.featured_obj, [obj])
new = context.scene.BIMModelProperties.openings.add() new = tool.Model.get_model_props().openings.add()
new.obj = obj new.obj = obj
bpy.ops.bim.show_openings() bpy.ops.bim.show_openings()
tool.Model.purge_scene_openings() tool.Model.purge_scene_openings()
@@ -58,7 +58,7 @@ class SpatialToolUI:
@classmethod @classmethod
def draw(cls, context, layout): def draw(cls, context, layout):
cls.layout = layout cls.layout = layout
cls.model_props = context.scene.BIMModelProperties cls.model_props = tool.Model.get_model_props()
row = cls.layout.row(align=True) row = cls.layout.row(align=True)
if not tool.Ifc.get(): if not tool.Ifc.get():
@@ -48,7 +48,7 @@ class AssignType(bpy.types.Operator, tool.Ifc.Operator):
if self.related_object if self.related_object
else context.selected_objects or [context.active_object] else context.selected_objects or [context.active_object]
) )
model_props = context.scene.BIMModelProperties model_props = tool.Model.get_model_props()
for obj in related_objects: for obj in related_objects:
element = tool.Ifc.get_entity(obj) element = tool.Ifc.get_entity(obj)
core.assign_type(tool.Ifc, tool.Type, element=element, type=relating_type) core.assign_type(tool.Ifc, tool.Type, element=element, type=relating_type)
@@ -332,11 +332,11 @@ class DuplicateType(bpy.types.Operator, tool.Ifc.Operator):
else: else:
self.report({"INFO"}, "Type object can't be selected : It may be hidden or in an excluded collection.") self.report({"INFO"}, "Type object can't be selected : It may be hidden or in an excluded collection.")
props = context.scene.BIMModelProperties props = tool.Model.get_model_props()
ifc_class = new.is_a() ifc_class = new.is_a()
# Set duplicated type as active in current tool. # Set duplicated type as active in current tool.
if ifc_class in (i[0] for i in (bonsai.bim.helper.get_enum_items(props, "ifc_class", context) or ()) if i): if ifc_class in (i[0] for i in (bonsai.bim.helper.get_enum_items(props, "ifc_class", context) or ()) if i):
context.scene.BIMModelProperties.ifc_class = new.is_a() props.ifc_class = new.is_a()
context.scene.BIMModelProperties.relating_type_id = str(new_obj.BIMObjectProperties.ifc_definition_id) props.relating_type_id = str(new_obj.BIMObjectProperties.ifc_definition_id)
return {"FINISHED"} return {"FINISHED"}
+6 -5
View File
@@ -347,10 +347,11 @@ class BIM_ADDON_preferences(bpy.types.AddonPreferences):
layout.prop(context.scene.BIMProjectProperties, "should_disable_undo_on_save") layout.prop(context.scene.BIMProjectProperties, "should_disable_undo_on_save")
layout.prop(context.scene.BIMProjectProperties, "should_stream") layout.prop(context.scene.BIMProjectProperties, "should_stream")
def draw_model_settings(self, layout, context): def draw_model_settings(self, layout: bpy.types.UILayout, context: bpy.types.Context) -> None:
layout.prop(context.scene.BIMModelProperties, "occurrence_name_style") props = tool.Model.get_model_props()
if context.scene.BIMModelProperties == "CUSTOM": layout.prop(props, "occurrence_name_style")
layout.prop(context.scene.BIMModelProperties, "occurrence_name_function") if props == "CUSTOM":
layout.prop(props, "occurrence_name_function")
def draw_directories(self, layout, context): def draw_directories(self, layout, context):
row = layout.row(align=True) row = layout.row(align=True)
@@ -1221,7 +1222,7 @@ class BIM_PT_decorators_overlay(Panel):
georeference_props = bpy.context.scene.BIMGeoreferenceProperties georeference_props = bpy.context.scene.BIMGeoreferenceProperties
aggregate_props = bpy.context.scene.BIMAggregateProperties aggregate_props = bpy.context.scene.BIMAggregateProperties
nest_props = bpy.context.scene.BIMNestProperties nest_props = bpy.context.scene.BIMNestProperties
model_props = bpy.context.scene.BIMModelProperties model_props = tool.Model.get_model_props()
display_all = overlay.show_overlays display_all = overlay.show_overlays
col = layout.column() col = layout.column()
+2 -1
View File
@@ -1035,7 +1035,8 @@ class Blender(bonsai.core.tool.Blender):
@classmethod @classmethod
def is_editing_door_parameters(cls, obj: bpy.types.Object) -> bool: def is_editing_door_parameters(cls, obj: bpy.types.Object) -> bool:
return obj.BIMDoorProperties.is_editing props = tool.Model.get_door_props(obj)
return props.is_editing
@classmethod @classmethod
def is_editing_stair_parameters(cls, obj: bpy.types.Object) -> bool: def is_editing_stair_parameters(cls, obj: bpy.types.Object) -> bool:
+1 -1
View File
@@ -66,7 +66,7 @@ class Covering(bonsai.core.tool.Covering):
) -> bool: ) -> bool:
if not tool.Ifc.get(): if not tool.Ifc.get():
return False return False
props = context.scene.BIMModelProperties props = tool.Model.get_model_props()
relating_type_id = tool.Blender.get_enum_safe(props, "relating_type_id") relating_type_id = tool.Blender.get_enum_safe(props, "relating_type_id")
if relating_type_id is not None: if relating_type_id is not None:
relating_type = ifcopenshell.util.element.get_predefined_type(tool.Ifc.get().by_id(int(relating_type_id))) relating_type = ifcopenshell.util.element.get_predefined_type(tool.Ifc.get().by_id(int(relating_type_id)))
+21 -9
View File
@@ -55,7 +55,7 @@ from typing import Optional, Union, Iterable, Any, Literal, Sequence, TYPE_CHECK
from pathlib import Path from pathlib import Path
if TYPE_CHECKING: if TYPE_CHECKING:
from bonsai.bim.module.drawing.prop import DocProperties, Sheet from bonsai.bim.module.drawing.prop import DocProperties, Sheet, BIMAnnotationProperties, BIMTextProperties
from bonsai.bim.module.drawing.prop import Drawing as DrawingProperties from bonsai.bim.module.drawing.prop import Drawing as DrawingProperties
@@ -91,6 +91,14 @@ class Drawing(bonsai.core.tool.Drawing):
def get_document_props(cls) -> DocProperties: def get_document_props(cls) -> DocProperties:
return bpy.context.scene.DocProperties return bpy.context.scene.DocProperties
@classmethod
def get_annotation_props(cls) -> BIMAnnotationProperties:
return bpy.context.scene.BIMAnnotationProperties
@classmethod
def get_text_props(cls, obj: bpy.types.Object) -> BIMTextProperties:
return obj.BIMTextProperties
@classmethod @classmethod
def canonicalise_class_name(cls, name: str) -> str: def canonicalise_class_name(cls, name: str) -> str:
return re.sub("[^0-9a-zA-Z]+", "", name) return re.sub("[^0-9a-zA-Z]+", "", name)
@@ -349,7 +357,8 @@ class Drawing(bonsai.core.tool.Drawing):
@classmethod @classmethod
def disable_editing_text(cls, obj: bpy.types.Object) -> None: def disable_editing_text(cls, obj: bpy.types.Object) -> None:
obj.BIMTextProperties.is_editing = False props = tool.Drawing.get_text_props(obj)
props.is_editing = False
@classmethod @classmethod
def disable_editing_assigned_product(cls, obj: bpy.types.Object) -> None: def disable_editing_assigned_product(cls, obj: bpy.types.Object) -> None:
@@ -385,7 +394,8 @@ class Drawing(bonsai.core.tool.Drawing):
@classmethod @classmethod
def enable_editing_text(cls, obj: bpy.types.Object) -> None: def enable_editing_text(cls, obj: bpy.types.Object) -> None:
obj.BIMTextProperties.is_editing = True props = cls.get_text_props(obj)
props.is_editing = True
@classmethod @classmethod
def enable_editing_assigned_product(cls, obj: bpy.types.Object) -> None: def enable_editing_assigned_product(cls, obj: bpy.types.Object) -> None:
@@ -409,7 +419,8 @@ class Drawing(bonsai.core.tool.Drawing):
@classmethod @classmethod
def export_text_literal_attributes(cls, obj: bpy.types.Object) -> list[dict[str, Any]]: def export_text_literal_attributes(cls, obj: bpy.types.Object) -> list[dict[str, Any]]:
literals = [] literals = []
for literal_props in obj.BIMTextProperties.literals: props = tool.Drawing.get_text_props(obj)
for literal_props in props.literals:
literal_data = bonsai.bim.helper.export_attributes(literal_props.attributes) literal_data = bonsai.bim.helper.export_attributes(literal_props.attributes)
literals.append(literal_data) literals.append(literal_data)
return literals return literals
@@ -620,7 +631,8 @@ class Drawing(bonsai.core.tool.Drawing):
def synchronise_ifc_and_text_attributes(cls, obj: bpy.types.Object) -> None: def synchronise_ifc_and_text_attributes(cls, obj: bpy.types.Object) -> None:
literals = cls.get_text_literal(obj, return_list=True) literals = cls.get_text_literal(obj, return_list=True)
literals_attributes = cls.export_text_literal_attributes(obj) literals_attributes = cls.export_text_literal_attributes(obj)
defined_ifc_ids = [l.ifc_definition_id for l in obj.BIMTextProperties.literals] props = cls.get_text_props(obj)
defined_ifc_ids = [l.ifc_definition_id for l in props.literals]
ifc_file = tool.Ifc.get() ifc_file = tool.Ifc.get()
for ifc_definition_id, attributes in zip(defined_ifc_ids, literals_attributes): for ifc_definition_id, attributes in zip(defined_ifc_ids, literals_attributes):
@@ -921,7 +933,7 @@ class Drawing(bonsai.core.tool.Drawing):
def import_text_attributes(cls, obj: bpy.types.Object) -> None: def import_text_attributes(cls, obj: bpy.types.Object) -> None:
from bonsai.bim.module.drawing.prop import BOX_ALIGNMENT_POSITIONS from bonsai.bim.module.drawing.prop import BOX_ALIGNMENT_POSITIONS
props = obj.BIMTextProperties props = cls.get_text_props(obj)
props.literals.clear() props.literals.clear()
for ifc_literal in cls.get_text_literal(obj, return_list=True): for ifc_literal in cls.get_text_literal(obj, return_list=True):
@@ -1035,7 +1047,7 @@ class Drawing(bonsai.core.tool.Drawing):
@classmethod @classmethod
def update_text_value(cls, obj: bpy.types.Object) -> None: def update_text_value(cls, obj: bpy.types.Object) -> None:
props = obj.BIMTextProperties props = cls.get_text_props(obj)
literals = cls.get_text_literal(obj, return_list=True) literals = cls.get_text_literal(obj, return_list=True)
cls.import_text_attributes(obj) cls.import_text_attributes(obj)
for i, literal in enumerate(literals): for i, literal in enumerate(literals):
@@ -1049,7 +1061,7 @@ class Drawing(bonsai.core.tool.Drawing):
""" """
from bonsai.bim.module.drawing.data import FONT_SIZES from bonsai.bim.module.drawing.data import FONT_SIZES
props = obj.BIMTextProperties props = cls.get_text_props(obj)
element = tool.Ifc.get_entity(obj) element = tool.Ifc.get_entity(obj)
# updating text font size in EPset_Annotation.Classes # updating text font size in EPset_Annotation.Classes
font_size = float(props.font_size) font_size = float(props.font_size)
@@ -1080,7 +1092,7 @@ class Drawing(bonsai.core.tool.Drawing):
@classmethod @classmethod
def update_newline_at(cls, obj: bpy.types.Object) -> None: def update_newline_at(cls, obj: bpy.types.Object) -> None:
props = obj.BIMTextProperties props = cls.get_text_props(obj)
element = tool.Ifc.get_entity(obj) element = tool.Ifc.get_entity(obj)
newline_at = int(props.newline_at) newline_at = int(props.newline_at)
ifc_file = tool.Ifc.get() ifc_file = tool.Ifc.get()
+18 -4
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 json import json
import bmesh import bmesh
@@ -47,13 +48,24 @@ from bonsai.bim.module.geometry.helper import Helper
from bonsai.bim.module.model.data import AuthoringData, RailingData, RoofData, WindowData, DoorData from bonsai.bim.module.model.data import AuthoringData, RailingData, RoofData, WindowData, DoorData
from bonsai.bim.module.model.opening import FilledOpeningGenerator from bonsai.bim.module.model.opening import FilledOpeningGenerator
from ifcopenshell.util.shape_builder import ShapeBuilder from ifcopenshell.util.shape_builder import ShapeBuilder
from typing import Optional, Union, TypeVar, Any, Iterable, Literal from typing import Optional, Union, TypeVar, Any, Iterable, Literal, TYPE_CHECKING
T = TypeVar("T") T = TypeVar("T")
V_ = tool.Blender.V_ V_ = tool.Blender.V_
if TYPE_CHECKING:
from bonsai.bim.module.model.prop import BIMModelProperties, BIMDoorProperties
class Model(bonsai.core.tool.Model): class Model(bonsai.core.tool.Model):
@classmethod
def get_model_props(cls) -> BIMModelProperties:
return bpy.context.scene.BIMModelProperties
@classmethod
def get_door_props(cls, obj: bpy.types.Object) -> BIMDoorProperties:
return obj.BIMDoorProperties
@classmethod @classmethod
def convert_si_to_unit(cls, value: T) -> T: def convert_si_to_unit(cls, value: T) -> T:
if isinstance(value, (tuple, list)): if isinstance(value, (tuple, list)):
@@ -215,7 +227,7 @@ class Model(bonsai.core.tool.Model):
@classmethod @classmethod
def generate_occurrence_name(cls, element_type: ifcopenshell.entity_instance, ifc_class: str) -> str: def generate_occurrence_name(cls, element_type: ifcopenshell.entity_instance, ifc_class: str) -> str:
props = bpy.context.scene.BIMModelProperties props = cls.get_model_props()
if props.occurrence_name_style == "CLASS": if props.occurrence_name_style == "CLASS":
return ifc_class[3:] return ifc_class[3:]
elif props.occurrence_name_style == "TYPE": elif props.occurrence_name_style == "TYPE":
@@ -521,7 +533,8 @@ class Model(bonsai.core.tool.Model):
@classmethod @classmethod
def purge_scene_openings(cls) -> None: def purge_scene_openings(cls) -> None:
"""Purge removed scene openings.""" """Purge removed scene openings."""
openings = bpy.context.scene.BIMModelProperties.openings props = cls.get_model_props()
openings = props.openings
for i in range(len(openings) - 1, -1, -1): for i in range(len(openings) - 1, -1, -1):
if not openings[i].obj: if not openings[i].obj:
openings.remove(i) openings.remove(i)
@@ -1929,7 +1942,8 @@ class Model(bonsai.core.tool.Model):
@classmethod @classmethod
def get_tracked_opening_type(cls, obj: bpy.types.Object) -> Union[Literal["OPENING", "BOOLEAN"], None]: def get_tracked_opening_type(cls, obj: bpy.types.Object) -> Union[Literal["OPENING", "BOOLEAN"], None]:
"""Get tracked opening type, return `None` if object is not a tracked opening.""" """Get tracked opening type, return `None` if object is not a tracked opening."""
for opening in bpy.context.scene.BIMModelProperties.openings: props = cls.get_model_props()
for opening in props.openings:
if opening.obj == obj: if opening.obj == obj:
return opening.name return opening.name
return None return None
+1 -1
View File
@@ -143,7 +143,7 @@ class Project(bonsai.core.tool.Project):
@classmethod @classmethod
def set_default_modeling_dimensions(cls): def set_default_modeling_dimensions(cls):
props = bpy.context.scene.BIMModelProperties props = tool.Model.get_model_props()
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get()) unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
props.extrusion_depth = 3 props.extrusion_depth = 3
props.length = 1 props.length = 1
+2 -1
View File
@@ -35,7 +35,8 @@ class Root(bonsai.core.tool.Root):
@classmethod @classmethod
def add_tracked_opening(cls, obj: bpy.types.Object, opening_type: Literal["OPENING", "BOOLEAN"]) -> None: def add_tracked_opening(cls, obj: bpy.types.Object, opening_type: Literal["OPENING", "BOOLEAN"]) -> None:
"""Add tracked opening or boolean object.""" """Add tracked opening or boolean object."""
new = bpy.context.scene.BIMModelProperties.openings.add() props = tool.Model.get_model_props()
new = props.openings.add()
new.obj = obj new.obj = obj
new.name = opening_type new.name = opening_type
+5 -3
View File
@@ -688,7 +688,8 @@ class Spatial(bonsai.core.tool.Spatial):
@classmethod @classmethod
def get_boundary_lines_from_context_visible_objects(cls) -> list[shapely.LineString]: def get_boundary_lines_from_context_visible_objects(cls) -> list[shapely.LineString]:
calculation_rl = bpy.context.scene.BIMModelProperties.rl3 props = props = tool.Model.get_model_props()
calculation_rl = props.rl3
container = tool.Root.get_default_container() container = tool.Root.get_default_container()
container_obj = tool.Ifc.get_object(container) container_obj = tool.Ifc.get_object(container)
cut_point = container_obj.matrix_world.translation.copy() + Vector((0, 0, calculation_rl)) cut_point = container_obj.matrix_world.translation.copy() + Vector((0, 0, calculation_rl))
@@ -1054,7 +1055,7 @@ class Spatial(bonsai.core.tool.Spatial):
@classmethod @classmethod
def get_relating_type_id(cls) -> int: def get_relating_type_id(cls) -> int:
props = bpy.context.scene.BIMModelProperties props = tool.Model.get_model_props()
relating_type_id = props.relating_type_id relating_type_id = props.relating_type_id
return relating_type_id return relating_type_id
@@ -1110,7 +1111,8 @@ class Spatial(bonsai.core.tool.Spatial):
@classmethod @classmethod
def assign_type_to_obj(cls, obj: bpy.types.Object) -> None: def assign_type_to_obj(cls, obj: bpy.types.Object) -> None:
relating_type_id = bpy.context.scene.BIMModelProperties.relating_type_id props = tool.Model.get_model_props()
relating_type_id = props.relating_type_id
relating_type = tool.Ifc.get().by_id(int(relating_type_id)) relating_type = tool.Ifc.get().by_id(int(relating_type_id))
ifc_class = relating_type.is_a() ifc_class = relating_type.is_a()
instance_class = ifcopenshell.util.type.get_applicable_entities(ifc_class, tool.Ifc.get().schema)[0] instance_class = ifcopenshell.util.type.get_applicable_entities(ifc_class, tool.Ifc.get().schema)[0]
+5 -4
View File
@@ -360,7 +360,7 @@ def i_load_a_new_pset_template_file():
@given("I create default MEP types") @given("I create default MEP types")
def i_create_default_mep_types(): def i_create_default_mep_types():
model_props = bpy.context.scene.BIMModelProperties model_props = tool.Model.get_model_props()
# add couple segments types # add couple segments types
model_props.type_class = "IfcDuctSegmentType" model_props.type_class = "IfcDuctSegmentType"
@@ -1244,13 +1244,13 @@ def i_display_the_construction_type_browser():
@given("I add the construction type") @given("I add the construction type")
@when("I add the construction type") @when("I add the construction type")
def i_add_the_active_construction_type(): def i_add_the_active_construction_type():
props = bpy.context.scene.BIMModelProperties props = tool.Model.get_model_props()
bpy.ops.bim.add_constr_type_instance(relating_type_id=int(props.relating_type_id)) bpy.ops.bim.add_constr_type_instance(relating_type_id=int(props.relating_type_id))
@then(parsers.parse("construction type is {relating_type_name}")) @then(parsers.parse("construction type is {relating_type_name}"))
def construction_type(relating_type_name): def construction_type(relating_type_name):
props = bpy.context.scene.BIMModelProperties props = tool.Model.get_model_props()
relating_type = AuthoringData.relating_type_name_by_id(props.ifc_class, props.relating_type_id) relating_type = AuthoringData.relating_type_name_by_id(props.ifc_class, props.relating_type_id)
assert relating_type == relating_type_name, f"Construction Type is a {relating_type}, not a {relating_type_name}" assert relating_type == relating_type_name, f"Construction Type is a {relating_type}, not a {relating_type_name}"
@@ -1333,7 +1333,8 @@ def the_obj_layer_lenght_is_set_to(value):
print(50 * "@", bpy.context.selected_objects) print(50 * "@", bpy.context.selected_objects)
bpy.context.scene.BIMModelProperties.length = value props = tool.Model.get_model_props()
props.length = value
bpy.ops.bim.change_layer_length(length=value) bpy.ops.bim.change_layer_length(length=value)
+28 -19
View File
@@ -22,6 +22,7 @@ import bpy
import mathutils import mathutils
import ifcopenshell import ifcopenshell
import ifcopenshell.guid import ifcopenshell.guid
import ifcopenshell.util.element
import bonsai.core.tool import bonsai.core.tool
import bonsai.tool as tool import bonsai.tool as tool
from test.bim.bootstrap import NewFile from test.bim.bootstrap import NewFile
@@ -107,7 +108,7 @@ class TestDeleteDrawingElements(NewFile):
assert False assert False
except: except:
pass pass
assert not bpy.data.objects.get("Object") assert not bpy.data.objects["Object"]
class TestDisableEditingDrawings(NewFile): class TestDisableEditingDrawings(NewFile):
@@ -141,9 +142,10 @@ class TestDisableEditingSheets(NewFile):
class TestDisableEditingText(NewFile): class TestDisableEditingText(NewFile):
def test_run(self): def test_run(self):
obj = bpy.data.objects.new("Object", None) obj = bpy.data.objects.new("Object", None)
obj.BIMTextProperties.is_editing = True props = tool.Drawing.get_text_props(obj)
props.is_editing = True
subject.disable_editing_text(obj) subject.disable_editing_text(obj)
assert obj.BIMTextProperties.is_editing == False assert props.is_editing == False
class TestDisableEditingAssignedProduct(NewFile): class TestDisableEditingAssignedProduct(NewFile):
@@ -194,7 +196,8 @@ class TestEnableEditingText(NewFile):
def test_run(self): def test_run(self):
obj = bpy.data.objects.new("Object", None) obj = bpy.data.objects.new("Object", None)
subject.enable_editing_text(obj) subject.enable_editing_text(obj)
assert obj.BIMTextProperties.is_editing == True props = tool.Drawing.get_text_props(obj)
assert props.is_editing == True
class TestEnableEditingAssignedProduct(NewFile): class TestEnableEditingAssignedProduct(NewFile):
@@ -238,7 +241,7 @@ class TestEnsureUniqueIdentification(NewFile):
class TestExportTextLiteralAttributes(NewFile): class TestExportTextLiteralAttributes(NewFile):
def test_run(self): def test_run(self):
TestImportTextAttributes().test_run() TestImportTextAttributes().test_run()
assert subject.export_text_literal_attributes(bpy.data.objects.get("Object")) == [ assert subject.export_text_literal_attributes(bpy.data.objects["Object"]) == [
{ {
"Literal": "Literal", "Literal": "Literal",
"Path": "RIGHT", "Path": "RIGHT",
@@ -584,7 +587,8 @@ class TestImportTextAttributes(NewFile):
element.ObjectType = "TEXT" # TODO: double check if it's valid to set this element.ObjectType = "TEXT" # TODO: double check if it's valid to set this
tool.Ifc.link(element, obj) tool.Ifc.link(element, obj)
subject.import_text_attributes(obj) subject.import_text_attributes(obj)
literal_props = obj.BIMTextProperties.literals[0] props = tool.Drawing.get_text_props(obj)
literal_props = props.literals[0]
assert literal_props.attributes.get("Literal").string_value == "Literal" assert literal_props.attributes.get("Literal").string_value == "Literal"
assert literal_props.attributes.get("Path").enum_value == "RIGHT" assert literal_props.attributes.get("Path").enum_value == "RIGHT"
assert literal_props.attributes.get("BoxAlignment").string_value == "bottom-left" assert literal_props.attributes.get("BoxAlignment").string_value == "bottom-left"
@@ -733,11 +737,12 @@ class TestUpdateTextValue(NewFile):
TestGetTextLiteral().test_run() TestGetTextLiteral().test_run()
ifc = tool.Ifc.get() ifc = tool.Ifc.get()
obj = bpy.data.objects.get("Object") obj = bpy.data.objects["Object"]
subject.update_text_value(obj) subject.update_text_value(obj)
literal = obj.BIMTextProperties.literals[0] props = tool.Drawing.get_text_props(obj)
literal = props.literals[0]
assert obj.BIMTextProperties.font_size == "2.5" assert props.font_size == "2.5"
assert literal.value == "Literal" assert literal.value == "Literal"
assert literal.box_alignment[:] == tuple([False] * 6 + [True] + [False] * 2) assert literal.box_alignment[:] == tuple([False] * 6 + [True] + [False] * 2)
assert literal.ifc_definition_id == ifc.by_type("IfcTextLiteralWithExtent")[0].id() assert literal.ifc_definition_id == ifc.by_type("IfcTextLiteralWithExtent")[0].id()
@@ -745,7 +750,7 @@ class TestUpdateTextValue(NewFile):
def test_using_attribute_variables(self): def test_using_attribute_variables(self):
TestGetTextLiteral().test_run() TestGetTextLiteral().test_run()
obj = bpy.data.objects.get("Object") obj = bpy.data.objects["Object"]
ifc = tool.Ifc.get() ifc = tool.Ifc.get()
wall = ifc.createIfcWall(Name="Baz") wall = ifc.createIfcWall(Name="Baz")
label = ifc.by_type("IfcAnnotation")[0] label = ifc.by_type("IfcAnnotation")[0]
@@ -754,12 +759,13 @@ class TestUpdateTextValue(NewFile):
ifc.by_type("IfcTextLiteralWithExtent")[0].Literal = "Foo {{Name}} Bar" ifc.by_type("IfcTextLiteralWithExtent")[0].Literal = "Foo {{Name}} Bar"
subject.update_text_value(obj) subject.update_text_value(obj)
assert obj.BIMTextProperties.literals[0].value == "Foo Baz Bar" props = tool.Drawing.get_text_props(obj)
assert props.literals[0].value == "Foo Baz Bar"
def test_using_property_variables(self): def test_using_property_variables(self):
TestGetTextLiteral().test_run() TestGetTextLiteral().test_run()
obj = bpy.data.objects.get("Object") obj = bpy.data.objects["Object"]
ifc = tool.Ifc.get() ifc = tool.Ifc.get()
wall = ifc.createIfcWall() wall = ifc.createIfcWall()
pset = ifcopenshell.api.run("pset.add_pset", ifc, name="Custom_Pset", product=wall) pset = ifcopenshell.api.run("pset.add_pset", ifc, name="Custom_Pset", product=wall)
@@ -770,14 +776,16 @@ class TestUpdateTextValue(NewFile):
ifc.by_type("IfcTextLiteralWithExtent")[0].Literal = "Foo {{Custom_Pset.Key}} Bar" ifc.by_type("IfcTextLiteralWithExtent")[0].Literal = "Foo {{Custom_Pset.Key}} Bar"
subject.update_text_value(obj) subject.update_text_value(obj)
assert obj.BIMTextProperties.literals[0].value == "Foo Baz Bar" props = tool.Drawing.get_text_props(obj)
assert props.literals[0].value == "Foo Baz Bar"
def test_update_text_font_size(self): def test_update_text_font_size(self):
TestGetTextLiteral().test_run() TestGetTextLiteral().test_run()
obj = bpy.data.objects.get("Object") obj = bpy.data.objects["Object"]
with bpy.context.temp_override(active_object=obj): with bpy.context.temp_override(active_object=obj):
bpy.ops.bim.enable_editing_text() bpy.ops.bim.enable_editing_text()
obj.BIMTextProperties.font_size = "7.0" props = tool.Drawing.get_text_props(obj)
props.font_size = "7.0"
bpy.ops.bim.edit_text() bpy.ops.bim.edit_text()
annotation_classes = ifcopenshell.util.element.get_pset(tool.Ifc.get_entity(obj), "EPset_Annotation", "Classes") annotation_classes = ifcopenshell.util.element.get_pset(tool.Ifc.get_entity(obj), "EPset_Annotation", "Classes")
assert "title" in annotation_classes assert "title" in annotation_classes
@@ -786,11 +794,12 @@ class TestUpdateTextValue(NewFile):
def test_add_second_literal(self, setup=True): def test_add_second_literal(self, setup=True):
if setup: if setup:
TestGetTextLiteral().test_run() TestGetTextLiteral().test_run()
obj = bpy.data.objects.get("Object") obj = bpy.data.objects["Object"]
with bpy.context.temp_override(active_object=obj): with bpy.context.temp_override(active_object=obj):
bpy.ops.bim.enable_editing_text() bpy.ops.bim.enable_editing_text()
bpy.ops.bim.add_text_literal() bpy.ops.bim.add_text_literal()
literal = obj.BIMTextProperties.literals[1] props = tool.Drawing.get_text_props(obj)
literal = props.literals[1]
literal.attributes["Literal"].string_value = "test_value" literal.attributes["Literal"].string_value = "test_value"
bpy.ops.bim.edit_text() bpy.ops.bim.edit_text()
@@ -802,8 +811,8 @@ class TestUpdateTextValue(NewFile):
self.test_update_text_font_size() # sets font size to "7.0" self.test_update_text_font_size() # sets font size to "7.0"
self.test_add_second_literal(setup=False) self.test_add_second_literal(setup=False)
obj = bpy.data.objects.get("Object") obj = bpy.data.objects["Object"]
props = obj.BIMTextProperties props = tool.Drawing.get_text_props(obj)
assert obj is not None, obj assert obj is not None, obj
with bpy.context.temp_override(active_object=obj): with bpy.context.temp_override(active_object=obj):
bpy.ops.bim.enable_editing_text() bpy.ops.bim.enable_editing_text()
+7 -4
View File
@@ -41,13 +41,15 @@ class TestGenerateOccurrenceName(NewFile):
def test_generating_based_on_class(self): def test_generating_based_on_class(self):
ifc = ifcopenshell.file() ifc = ifcopenshell.file()
element_type = ifc.createIfcWallType(Name="Foobar") element_type = ifc.createIfcWallType(Name="Foobar")
bpy.context.scene.BIMModelProperties.occurrence_name_style = "CLASS" props = tool.Model.get_model_props()
props.occurrence_name_style = "CLASS"
assert subject.generate_occurrence_name(element_type, "IfcWall") == "Wall" assert subject.generate_occurrence_name(element_type, "IfcWall") == "Wall"
def test_generating_based_on_type_name(self): def test_generating_based_on_type_name(self):
ifc = ifcopenshell.file() ifc = ifcopenshell.file()
element_type = ifc.createIfcWallType() element_type = ifc.createIfcWallType()
bpy.context.scene.BIMModelProperties.occurrence_name_style = "TYPE" props = tool.Model.get_model_props()
props.occurrence_name_style = "TYPE"
assert subject.generate_occurrence_name(element_type, "IfcWall") == "Unnamed" assert subject.generate_occurrence_name(element_type, "IfcWall") == "Unnamed"
element_type.Name = "Foobar" element_type.Name = "Foobar"
assert subject.generate_occurrence_name(element_type, "IfcWall") == "Foobar" assert subject.generate_occurrence_name(element_type, "IfcWall") == "Foobar"
@@ -55,8 +57,9 @@ class TestGenerateOccurrenceName(NewFile):
def test_generating_based_on_a_custom_function(self): def test_generating_based_on_a_custom_function(self):
ifc = ifcopenshell.file() ifc = ifcopenshell.file()
element_type = ifc.createIfcWallType() element_type = ifc.createIfcWallType()
bpy.context.scene.BIMModelProperties.occurrence_name_style = "CUSTOM" props = tool.Model.get_model_props()
bpy.context.scene.BIMModelProperties.occurrence_name_function = '"Foobar"' props.occurrence_name_style = "CUSTOM"
props.occurrence_name_function = '"Foobar"'
assert subject.generate_occurrence_name(element_type, "IfcWall") == "Foobar" assert subject.generate_occurrence_name(element_type, "IfcWall") == "Foobar"
+1 -1
View File
@@ -125,7 +125,7 @@ class TestSetDefaultModelingDimensions(NewFile):
ifc.createIfcProject() ifc.createIfcProject()
ifcopenshell.api.run("unit.assign_unit", ifc) ifcopenshell.api.run("unit.assign_unit", ifc)
subject.set_default_modeling_dimensions() subject.set_default_modeling_dimensions()
props = bpy.context.scene.BIMModelProperties props = tool.Model.get_model_props()
assert props.extrusion_depth == 3 assert props.extrusion_depth == 3
assert props.length == 1 assert props.length == 1
assert props.rl1 == 0 assert props.rl1 == 0
+1 -1
View File
@@ -34,7 +34,7 @@ class TestAddTrackedOpening(NewFile):
def test_run(self): def test_run(self):
obj = bpy.data.objects.new("Object", None) obj = bpy.data.objects.new("Object", None)
subject.add_tracked_opening(obj, "OPENING") subject.add_tracked_opening(obj, "OPENING")
props = bpy.context.scene.BIMModelProperties props = tool.Model.get_model_props()
assert props.openings[0].obj == obj assert props.openings[0].obj == obj
assert props.openings[0].name == "OPENING" assert props.openings[0].name == "OPENING"