mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 01:41:57 +00:00
typing
This commit is contained in:
@@ -137,7 +137,7 @@ class IfcExporter:
|
||||
return checksum != tool.Geometry.get_material_checksum(obj)
|
||||
|
||||
def sync_object_placement(self, obj: bpy.types.Object) -> Union[ifcopenshell.entity_instance, None]:
|
||||
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
element = self.file.by_id(tool.Blender.get_object_bim_props(obj).ifc_definition_id)
|
||||
if tool.Geometry.is_scaled(obj):
|
||||
bpy.ops.bim.update_representation(obj=obj.name)
|
||||
# update_representation might not apply scale if the object has openings
|
||||
|
||||
@@ -64,14 +64,15 @@ def name_callback(obj: Union[bpy.types.Object, bpy.types.Material], data: str) -
|
||||
refresh_ui_data()
|
||||
return
|
||||
|
||||
if not obj.BIMObjectProperties.ifc_definition_id:
|
||||
props = tool.Blender.get_object_bim_props(obj)
|
||||
if not props.ifc_definition_id:
|
||||
return
|
||||
|
||||
if obj.BIMObjectProperties.is_renaming:
|
||||
obj.BIMObjectProperties.is_renaming = False
|
||||
if props.is_renaming:
|
||||
props.is_renaming = False
|
||||
return
|
||||
|
||||
element = tool.Ifc.get().by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
element = tool.Ifc.get().by_id(props.ifc_definition_id)
|
||||
if "/" in obj.name:
|
||||
object_name = obj.name
|
||||
element_name = obj.name.split("/", 1)[1]
|
||||
@@ -87,8 +88,8 @@ def name_callback(obj: Union[bpy.types.Object, bpy.types.Material], data: str) -
|
||||
if not element.is_a("IfcRoot"):
|
||||
return
|
||||
element.Name = element_name
|
||||
if obj.BIMObjectProperties.collection:
|
||||
obj.BIMObjectProperties.collection.name = object_name
|
||||
if props.collection:
|
||||
props.collection.name = object_name
|
||||
refresh_ui_data()
|
||||
|
||||
|
||||
|
||||
@@ -267,7 +267,8 @@ class IfcStore:
|
||||
if element.is_a("IfcSurfaceStyle"):
|
||||
obj.BIMStyleProperties.ifc_definition_id = element.id()
|
||||
else:
|
||||
obj.BIMObjectProperties.ifc_definition_id = element.id()
|
||||
props = tool.Blender.get_object_bim_props(obj)
|
||||
props.ifc_definition_id = element.id()
|
||||
|
||||
tool.Ifc.setup_listeners(obj)
|
||||
|
||||
@@ -407,7 +408,8 @@ class IfcStore:
|
||||
if isinstance(obj, bpy.types.Material):
|
||||
obj.BIMStyleProperties.ifc_definition_id = 0
|
||||
else: # bpy.types.Object
|
||||
obj.BIMObjectProperties.ifc_definition_id = 0
|
||||
props = tool.Blender.get_object_bim_props(obj)
|
||||
props.ifc_definition_id = 0
|
||||
|
||||
@staticmethod
|
||||
def execute_ifc_operator(
|
||||
|
||||
@@ -933,7 +933,8 @@ class IfcImporter:
|
||||
self.project = {"ifc": project}
|
||||
obj = tool.Ifc.get_object(project)
|
||||
if obj:
|
||||
self.project["blender"] = obj.BIMObjectProperties.collection
|
||||
props = tool.Blender.get_object_bim_props(obj)
|
||||
self.project["blender"] = props.collection
|
||||
self.has_existing_project = True
|
||||
return
|
||||
self.project["blender"] = bpy.data.collections.new(
|
||||
@@ -943,7 +944,8 @@ class IfcImporter:
|
||||
obj.hide_select = True
|
||||
self.project["blender"].objects.link(obj)
|
||||
self.project["blender"].BIMCollectionProperties.obj = obj
|
||||
obj.BIMObjectProperties.collection = self.collections[project.GlobalId] = self.project["blender"]
|
||||
props = tool.Blender.get_object_bim_props(obj)
|
||||
props.collection = self.collections[project.GlobalId] = self.project["blender"]
|
||||
|
||||
def create_styles(self) -> None:
|
||||
for style in self.file.by_type("IfcSurfaceStyle"):
|
||||
|
||||
@@ -34,9 +34,9 @@ class BIM_PT_aggregate(Panel):
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not context.active_object:
|
||||
if not (obj := context.active_object):
|
||||
return False
|
||||
props = context.active_object.BIMObjectProperties
|
||||
props = tool.Blender.get_object_bim_props(obj)
|
||||
if not props.ifc_definition_id:
|
||||
return False
|
||||
if not tool.Ifc.get_object_by_identifier(props.ifc_definition_id):
|
||||
@@ -66,9 +66,9 @@ class BIM_PT_aggregate(Panel):
|
||||
col.enabled = False
|
||||
op = col.operator("bim.aggregate_assign_object", icon="CHECKMARK")
|
||||
if props.relating_object:
|
||||
op.relating_object = props.relating_object.BIMObjectProperties.ifc_definition_id
|
||||
op.relating_object = tool.Blender.get_object_bim_props(props.relating_object).ifc_definition_id
|
||||
elif props.related_object:
|
||||
op.related_object = props.related_object.BIMObjectProperties.ifc_definition_id
|
||||
op.related_object = tool.Blender.get_object_bim_props(props.related_object).ifc_definition_id
|
||||
row.operator("bim.disable_editing_aggregate", icon="CANCEL", text="")
|
||||
return
|
||||
else:
|
||||
@@ -115,9 +115,9 @@ class BIM_PT_linked_aggregate(Panel):
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not context.active_object:
|
||||
if not (obj := context.active_object):
|
||||
return False
|
||||
props = context.active_object.BIMObjectProperties
|
||||
props = tool.Blender.get_object_bim_props(obj)
|
||||
if not props.ifc_definition_id:
|
||||
return False
|
||||
if not tool.Ifc.get_object_by_identifier(props.ifc_definition_id):
|
||||
|
||||
@@ -316,7 +316,8 @@ class ColourByRelatedBuildingElement(bpy.types.Operator):
|
||||
|
||||
def _execute(self, context):
|
||||
for obj in context.visible_objects:
|
||||
if not obj.BIMObjectProperties.ifc_definition_id:
|
||||
props = tool.Blender.get_object_bim_props(obj)
|
||||
if not props.ifc_definition_id:
|
||||
continue
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
if not element.is_a("IfcRelSpaceBoundary"):
|
||||
|
||||
@@ -52,9 +52,9 @@ class BIM_PT_Boundary(Panel):
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not context.active_object:
|
||||
if not (obj := context.active_object):
|
||||
return False
|
||||
props = context.active_object.BIMObjectProperties
|
||||
props = tool.Blender.get_object_bim_props(obj)
|
||||
if not props.ifc_definition_id:
|
||||
return False
|
||||
if not tool.Ifc.get_object_by_identifier(props.ifc_definition_id):
|
||||
@@ -65,7 +65,7 @@ class BIM_PT_Boundary(Panel):
|
||||
def draw(self, context):
|
||||
obj = context.active_object
|
||||
assert obj
|
||||
props = obj.BIMObjectProperties
|
||||
props = tool.Blender.get_object_bim_props(obj)
|
||||
ifc_file = tool.Ifc.get()
|
||||
boundary = ifc_file.by_id(props.ifc_definition_id)
|
||||
self.bprops = tool.Boundary.get_object_boundary_props(obj)
|
||||
@@ -128,9 +128,9 @@ class BIM_PT_SpaceBoundaries(Panel):
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not context.active_object:
|
||||
if not (obj := context.active_object):
|
||||
return False
|
||||
props = context.active_object.BIMObjectProperties
|
||||
props = tool.Blender.get_object_bim_props(obj)
|
||||
if not props.ifc_definition_id:
|
||||
return False
|
||||
if not tool.Ifc.get_object_by_identifier(props.ifc_definition_id):
|
||||
@@ -145,7 +145,9 @@ class BIM_PT_SpaceBoundaries(Panel):
|
||||
if not SpaceBoundariesData.is_loaded:
|
||||
SpaceBoundariesData.load()
|
||||
|
||||
self.props = context.active_object.BIMObjectProperties
|
||||
obj = context.active_object
|
||||
assert obj
|
||||
self.props = tool.Blender.get_object_bim_props(obj)
|
||||
self.ifc_file = tool.Ifc.get()
|
||||
row = self.layout.row()
|
||||
row.operator("bim.load_space_boundaries")
|
||||
|
||||
@@ -20,6 +20,7 @@ import bpy
|
||||
from bonsai.bim.module.model.data import AuthoringData
|
||||
from bpy.types import PropertyGroup
|
||||
from math import pi
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
|
||||
class BIMCadProperties(PropertyGroup):
|
||||
@@ -31,3 +32,11 @@ class BIMCadProperties(PropertyGroup):
|
||||
gable_roof_edge_angle: bpy.props.FloatProperty(
|
||||
name="Gable Roof Edge Angle", default=pi / 2, soft_min=0, soft_max=pi / 2, subtype="ANGLE"
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
resolution: int
|
||||
radius: float
|
||||
distance: float
|
||||
x: float
|
||||
y: float
|
||||
gable_roof_edge_angle: float
|
||||
|
||||
@@ -146,7 +146,7 @@ class CadTool(WorkSpaceTool):
|
||||
if (
|
||||
(RailingData.is_loaded or not RailingData.load())
|
||||
and RailingData.data["pset_data"]
|
||||
and obj.BIMRailingProperties.is_editing_path
|
||||
and tool.Model.get_railing_props(obj).is_editing_path
|
||||
):
|
||||
add_header_apply_button(
|
||||
layout,
|
||||
@@ -159,7 +159,7 @@ class CadTool(WorkSpaceTool):
|
||||
elif (
|
||||
(RoofData.is_loaded or not RoofData.load())
|
||||
and RoofData.data["pset_data"]
|
||||
and obj.BIMRoofProperties.is_editing_path
|
||||
and tool.Model.get_roof_props(obj).is_editing_path
|
||||
):
|
||||
add_header_apply_button(
|
||||
layout, "Edit Roof Path", "bim.finish_editing_roof_path", "bim.cancel_editing_roof_path", ui_context
|
||||
@@ -195,12 +195,14 @@ class CadHotkey(bpy.types.Operator):
|
||||
return operator.description or ""
|
||||
|
||||
def execute(self, context):
|
||||
self.props = context.scene.BIMCadProperties
|
||||
self.props = tool.Cad.get_cad_props()
|
||||
getattr(self, f"hotkey_{self.hotkey}")()
|
||||
return {"FINISHED"}
|
||||
|
||||
def draw(self, context):
|
||||
props = context.scene.BIMCadProperties
|
||||
props = tool.Cad.get_cad_props()
|
||||
obj = context.active_object
|
||||
|
||||
if self.hotkey == "S_C":
|
||||
if tool.Geometry.is_profile_object_active():
|
||||
row = self.layout.row()
|
||||
@@ -226,7 +228,7 @@ class CadHotkey(bpy.types.Operator):
|
||||
elif (
|
||||
(RoofData.is_loaded or not RoofData.load())
|
||||
and RoofData.data["pset_data"]
|
||||
and bpy.context.active_object.BIMRoofProperties.is_editing_path
|
||||
and tool.Model.get_roof_props(obj).is_editing_path
|
||||
):
|
||||
self.layout.row().prop(props, "gable_roof_edge_angle")
|
||||
|
||||
@@ -281,13 +283,17 @@ class CadHotkey(bpy.types.Operator):
|
||||
bpy.ops.bim.edit_extrusion_axis()
|
||||
|
||||
def hotkey_S_R(self):
|
||||
obj = bpy.context.active_object
|
||||
if not obj:
|
||||
return
|
||||
|
||||
if tool.Geometry.is_profile_object_active():
|
||||
si_conversion = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||
bpy.ops.bim.add_rectangle(x=self.props.x / si_conversion, y=self.props.y / si_conversion)
|
||||
elif (
|
||||
(RoofData.is_loaded or not RoofData.load())
|
||||
and RoofData.data["pset_data"]
|
||||
and bpy.context.active_object.BIMRoofProperties.is_editing_path
|
||||
and tool.Model.get_roof_props(obj).is_editing_path
|
||||
):
|
||||
bpy.ops.bim.set_gable_roof_edge_angle(angle=self.props.gable_roof_edge_angle)
|
||||
|
||||
|
||||
@@ -316,7 +316,8 @@ class SelectIfcClashResults(bpy.types.Operator):
|
||||
global_ids.extend([clash["a_global_id"], clash["b_global_id"]])
|
||||
|
||||
for obj in context.visible_objects:
|
||||
if not obj.BIMObjectProperties.ifc_definition_id:
|
||||
props = tool.Blender.get_object_bim_props(obj)
|
||||
if not props.ifc_definition_id:
|
||||
continue
|
||||
|
||||
ifc_file = ""
|
||||
@@ -335,7 +336,7 @@ class SelectIfcClashResults(bpy.types.Operator):
|
||||
element_file = self.file
|
||||
|
||||
try:
|
||||
element = element_file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
element = element_file.by_id(props.ifc_definition_id)
|
||||
except:
|
||||
continue
|
||||
|
||||
|
||||
@@ -161,8 +161,12 @@ class AssignConstraint(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
def _execute(self, context):
|
||||
self.file = tool.Ifc.get()
|
||||
objs = [bpy.data.objects.get(self.obj)] if self.obj else context.selected_objects
|
||||
products = [self.file.by_id(obj_id) for obj in objs if (obj_id := obj.BIMObjectProperties.ifc_definition_id)]
|
||||
objs = [bpy.data.objects[self.obj]] if self.obj else context.selected_objects
|
||||
products = [
|
||||
self.file.by_id(obj_id)
|
||||
for obj in objs
|
||||
if (obj_id := tool.Blender.get_object_bim_props(obj).ifc_definition_id)
|
||||
]
|
||||
if products:
|
||||
ifcopenshell.api.run(
|
||||
"constraint.assign_constraint",
|
||||
@@ -184,8 +188,12 @@ class UnassignConstraint(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
def _execute(self, context):
|
||||
self.file = tool.Ifc.get()
|
||||
objs = [bpy.data.objects.get(self.obj)] if self.obj else context.selected_objects
|
||||
products = [self.file.by_id(obj_id) for obj in objs if (obj_id := obj.BIMObjectProperties.ifc_definition_id)]
|
||||
objs = [bpy.data.objects[self.obj]] if self.obj else context.selected_objects
|
||||
products = [
|
||||
self.file.by_id(obj_id)
|
||||
for obj in objs
|
||||
if (obj_id := tool.Blender.get_object_bim_props(obj).ifc_definition_id)
|
||||
]
|
||||
if products:
|
||||
ifcopenshell.api.run(
|
||||
"constraint.unassign_constraint",
|
||||
|
||||
@@ -79,18 +79,18 @@ class BIM_PT_object_constraints(Panel):
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not context.active_object:
|
||||
if not (obj := context.active_object):
|
||||
return False
|
||||
if not tool.Ifc.get_object_by_identifier(context.active_object.BIMObjectProperties.ifc_definition_id):
|
||||
return False
|
||||
return bool(context.active_object.BIMObjectProperties.ifc_definition_id)
|
||||
props = tool.Blender.get_object_bim_props(obj)
|
||||
return bool(tool.Ifc.get_object_by_identifier(props.ifc_definition_id))
|
||||
|
||||
def draw(self, context):
|
||||
if not ObjectConstraintsData.is_loaded:
|
||||
ObjectConstraintsData.load()
|
||||
|
||||
obj = context.active_object
|
||||
self.oprops = obj.BIMObjectProperties
|
||||
assert obj
|
||||
self.oprops = tool.Blender.get_object_bim_props(obj)
|
||||
self.sprops = context.scene.BIMConstraintProperties
|
||||
self.props = obj.BIMObjectConstraintProperties
|
||||
self.file = tool.Ifc.get()
|
||||
|
||||
@@ -740,15 +740,14 @@ class LoadProductCostItems(bpy.types.Operator):
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not tool.Ifc.get() or not (obj := context.active_object) or not (obj.BIMObjectProperties.ifc_definition_id):
|
||||
if not tool.Ifc.get() or not (obj := context.active_object) or not (tool.Blender.get_ifc_definition_id(obj)):
|
||||
cls.poll_message_set("No IFC object is active.")
|
||||
return False
|
||||
return True
|
||||
|
||||
def execute(self, context):
|
||||
core.load_product_cost_items(
|
||||
tool.Cost, product=tool.Ifc.get().by_id(context.active_object.BIMObjectProperties.ifc_definition_id)
|
||||
)
|
||||
obj = context.active_object
|
||||
core.load_product_cost_items(tool.Cost, product=tool.Ifc.get_entity(obj))
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
|
||||
@@ -18,9 +18,13 @@
|
||||
|
||||
import bpy
|
||||
from bpy.types import PropertyGroup
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
|
||||
class BIMCoveringProperties(PropertyGroup):
|
||||
ceiling_height: bpy.props.FloatProperty(
|
||||
name="ceiling_height", default=2.7, subtype="DISTANCE", description="Ceiling height"
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
ceiling_height: float
|
||||
|
||||
@@ -55,7 +55,7 @@ class CoveringToolUI:
|
||||
def draw(cls, context, layout, ifc_element_type=None):
|
||||
cls.layout = layout
|
||||
cls.props = tool.Model.get_model_props()
|
||||
cls.covering_props = context.scene.BIMCoveringProperties
|
||||
cls.covering_props = tool.Covering.get_covering_props()
|
||||
|
||||
row = cls.layout.row(align=True)
|
||||
if not tool.Ifc.get():
|
||||
@@ -159,12 +159,11 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator):
|
||||
return operator.description or ""
|
||||
|
||||
def _execute(self, context):
|
||||
# self.props = context.scene.BIMCoveringProperties
|
||||
self.props = tool.Covering.get_covering_props()
|
||||
getattr(self, f"hotkey_{self.hotkey}")()
|
||||
|
||||
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
|
||||
# self.props = context.scene.BIMSpatialProperties
|
||||
return self.execute(context)
|
||||
|
||||
def draw(self, context):
|
||||
|
||||
@@ -181,12 +181,12 @@ class RunAnalysis(bpy.types.Operator):
|
||||
if modifier.type == "TRIANGULATE":
|
||||
return True
|
||||
|
||||
def get_covetool_category(self, obj):
|
||||
def get_covetool_category(self, obj: bpy.types.Object):
|
||||
if not hasattr(obj, "data") or not isinstance(obj.data, bpy.types.Mesh):
|
||||
return
|
||||
if not obj.BIMObjectProperties.ifc_definition_id:
|
||||
if not (ifc_id := tool.Blender.get_ifc_definition_id(obj)):
|
||||
return
|
||||
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
element = self.file.by_id(ifc_id)
|
||||
ifc_class = element.is_a()
|
||||
if "IfcSlab" in ifc_class:
|
||||
return "floors"
|
||||
|
||||
@@ -382,7 +382,7 @@ class InspectFromObject(bpy.types.Operator):
|
||||
def get_active_object_ifc_definition(cls, context: bpy.types.Context) -> Union[int, None]:
|
||||
obj = context.active_object
|
||||
assert obj
|
||||
if ifc_id := obj.BIMObjectProperties.ifc_definition_id:
|
||||
if ifc_id := tool.Blender.get_ifc_definition_id(obj):
|
||||
return ifc_id
|
||||
if (
|
||||
(data := obj.data)
|
||||
|
||||
@@ -65,7 +65,7 @@ class VisualiseDiff(bpy.types.Operator):
|
||||
obj.color = (0.0, 0.0, 0.7, 1.0)
|
||||
continue
|
||||
|
||||
if not obj.BIMObjectProperties.ifc_definition_id:
|
||||
if not (ifc_id := tool.Blender.get_ifc_definition_id(obj)):
|
||||
continue
|
||||
|
||||
ifc_file = ""
|
||||
@@ -84,7 +84,7 @@ class VisualiseDiff(bpy.types.Operator):
|
||||
element_file = ifc_file
|
||||
|
||||
try:
|
||||
element = element_file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
element = element_file.by_id(ifc_id)
|
||||
except:
|
||||
continue
|
||||
global_id = getattr(element, "GlobalId", None)
|
||||
@@ -253,7 +253,7 @@ class SelectDiffObjects(bpy.types.Operator):
|
||||
obj.select_set(True)
|
||||
continue
|
||||
|
||||
if not obj.BIMObjectProperties.ifc_definition_id:
|
||||
if not (ifc_id := tool.Blender.get_ifc_definition_id(obj)):
|
||||
continue
|
||||
|
||||
ifc_file = ""
|
||||
@@ -272,7 +272,7 @@ class SelectDiffObjects(bpy.types.Operator):
|
||||
element_file = ifc_file
|
||||
|
||||
try:
|
||||
element = element_file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
element = element_file.by_id(ifc_id)
|
||||
except:
|
||||
continue
|
||||
global_id = getattr(element, "GlobalId", None)
|
||||
|
||||
@@ -90,18 +90,20 @@ class BIM_PT_object_documents(Panel):
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not context.active_object:
|
||||
if not (obj := context.active_object):
|
||||
return False
|
||||
if not tool.Ifc.get_object_by_identifier(context.active_object.BIMObjectProperties.ifc_definition_id):
|
||||
if not (ifc_id := tool.Blender.get_ifc_definition_id(obj)):
|
||||
return False
|
||||
return bool(context.active_object.BIMObjectProperties.ifc_definition_id)
|
||||
if not tool.Ifc.get_object_by_identifier(ifc_id):
|
||||
return False
|
||||
return True
|
||||
|
||||
def draw(self, context):
|
||||
if not ObjectDocumentData.is_loaded:
|
||||
ObjectDocumentData.load()
|
||||
|
||||
obj = context.active_object
|
||||
self.oprops = obj.BIMObjectProperties
|
||||
self.oprops = tool.Blender.get_object_bim_props(obj)
|
||||
self.props = tool.Document.get_document_props()
|
||||
self.file = tool.Ifc.get()
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ class Annotator:
|
||||
curve.font = font
|
||||
props = tool.Drawing.get_text_props(obj)
|
||||
props.font_size = "2.5"
|
||||
collection = bpy.context.scene.camera.BIMObjectProperties.collection
|
||||
collection = tool.Blender.get_object_bim_props(bpy.context.scene.camera).collection
|
||||
collection.objects.link(obj)
|
||||
Annotator.resize_text(obj)
|
||||
return obj
|
||||
@@ -133,7 +133,7 @@ class Annotator:
|
||||
co1, _, _, _ = Annotator.get_placeholder_coords(camera)
|
||||
matrix_world = tool.Drawing.get_camera_matrix(camera)
|
||||
matrix_world.translation = co1
|
||||
collection = camera.BIMObjectProperties.collection
|
||||
collection = tool.Blender.get_object_bim_props(camera).collection
|
||||
|
||||
if object_type == "TEXT":
|
||||
obj = bpy.data.objects.new(object_type, None)
|
||||
|
||||
@@ -343,7 +343,7 @@ def get_active_drawing(
|
||||
props = tool.Drawing.get_document_props()
|
||||
try:
|
||||
camera = tool.Ifc.get_object(tool.Ifc.get().by_id(props.active_drawing_id))
|
||||
return camera.BIMObjectProperties.collection, camera
|
||||
return tool.Blender.get_object_bim_props(camera).collection, camera
|
||||
except:
|
||||
return None, None
|
||||
|
||||
|
||||
@@ -246,7 +246,7 @@ class CreateDrawing(bpy.types.Operator):
|
||||
def execute(self, context):
|
||||
self.props = tool.Drawing.get_document_props()
|
||||
|
||||
active_drawing_id = context.scene.camera.BIMObjectProperties.ifc_definition_id
|
||||
active_drawing_id = tool.Blender.get_ifc_definition_id(context.scene.camera)
|
||||
if self.print_all:
|
||||
original_drawing_id = active_drawing_id
|
||||
drawings_to_print = [d.ifc_definition_id for d in self.props.drawings if d.is_selected and d.is_drawing]
|
||||
@@ -391,7 +391,7 @@ class CreateDrawing(bpy.types.Operator):
|
||||
bpy.ops.render.render(write_still=True)
|
||||
else:
|
||||
previous_visibility = {}
|
||||
for obj in self.camera.BIMObjectProperties.collection.objects:
|
||||
for obj in tool.Blender.get_object_bim_props(self.camera).collection.objects:
|
||||
if bpy.context.view_layer.objects.get(obj.name):
|
||||
previous_visibility[obj.name] = obj.hide_get()
|
||||
obj.hide_set(True)
|
||||
@@ -2095,7 +2095,7 @@ class ResizeText(bpy.types.Operator):
|
||||
# TODO: check undo redo
|
||||
|
||||
def execute(self, context):
|
||||
for obj in context.scene.camera.BIMObjectProperties.collection.objects:
|
||||
for obj in tool.Blender.get_object_bim_props(context.scene.camera).collection.objects:
|
||||
if isinstance(obj.data, bpy.types.TextCurve):
|
||||
annotation.Annotator.resize_text(obj)
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -266,7 +266,7 @@ def update_titleblocks(self, context):
|
||||
def update_should_draw_decorations(self, context: bpy.types.Context) -> None:
|
||||
if self.should_draw_decorations:
|
||||
# TODO: design a proper text variable templating renderer
|
||||
collection = context.scene.camera.BIMObjectProperties.collection
|
||||
collection = tool.Blender.get_object_bim_props(context.scene.camera).collection
|
||||
for obj in collection.objects:
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
if not element or not tool.Drawing.is_annotation_object_type(element, ["TEXT", "TEXT_LEADER"]):
|
||||
|
||||
@@ -102,7 +102,7 @@ def block_scale(scene: bpy.types.Scene) -> None:
|
||||
import bonsai.tool as tool
|
||||
|
||||
if obj := (getattr(bpy.context, "active_object", None) or bpy.context.view_layer.objects.active):
|
||||
if isinstance(obj, bpy.types.Object) and obj.BIMObjectProperties.ifc_definition_id:
|
||||
if isinstance(obj, bpy.types.Object) and tool.Blender.get_ifc_definition_id(obj):
|
||||
if obj.scale != (1, 1, 1):
|
||||
obj.scale = (1, 1, 1)
|
||||
elif isinstance(obj, bpy.types.Mesh) and tool.Geometry.get_mesh_props(obj).ifc_definition_id:
|
||||
|
||||
@@ -464,7 +464,8 @@ class UpdateRepresentation(bpy.types.Operator, tool.Ifc.Operator):
|
||||
assert tool.Geometry.is_data_supported_for_adding_representation(data)
|
||||
mprops = tool.Geometry.get_mesh_props(data)
|
||||
|
||||
product = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
product = tool.Ifc.get_entity(obj)
|
||||
assert product
|
||||
material = ifcopenshell.util.element.get_material(product, should_skip_usage=True)
|
||||
|
||||
# NOTE: Currently iterator doesn't detect whether opening is actually affected the representation
|
||||
@@ -903,7 +904,7 @@ class OverrideOutlinerDelete(bpy.types.Operator):
|
||||
if element := tool.Ifc.get_entity(obj):
|
||||
if tool.Geometry.is_locked(element):
|
||||
self.report({"ERROR"}, lock_error_message(obj.name))
|
||||
if collection := obj.BIMObjectProperties.collection:
|
||||
if collection := tool.Blender.get_object_bim_props(obj).collection:
|
||||
collections_to_delete.discard(collection)
|
||||
continue
|
||||
tool.Geometry.delete_ifc_object(obj)
|
||||
@@ -1067,7 +1068,7 @@ class OverrideDuplicateMove(bpy.types.Operator):
|
||||
continue
|
||||
|
||||
# clear object's collection so it will be able to have it's own
|
||||
new_obj.BIMObjectProperties.collection = None
|
||||
tool.Blender.get_object_bim_props(new_obj).collection = None
|
||||
# copy the actual class
|
||||
new = bonsai.core.root.copy_class(tool.Ifc, tool.Collector, tool.Geometry, tool.Root, obj=new_obj)
|
||||
|
||||
|
||||
@@ -334,9 +334,9 @@ class BIM_PT_connections(Panel):
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not context.active_object:
|
||||
if not (obj := context.active_object):
|
||||
return False
|
||||
if not tool.Ifc.get_object_by_identifier(context.active_object.BIMObjectProperties.ifc_definition_id):
|
||||
if not tool.Ifc.get_object_by_identifier(tool.Blender.get_ifc_definition_id(obj)):
|
||||
return False
|
||||
return tool.Ifc.get()
|
||||
|
||||
@@ -345,7 +345,6 @@ class BIM_PT_connections(Panel):
|
||||
ConnectionsData.load()
|
||||
|
||||
layout = self.layout
|
||||
props = context.active_object.BIMObjectProperties
|
||||
|
||||
if not ConnectionsData.data["connections"] and not ConnectionsData.data["is_connection_realization"]:
|
||||
layout.label(text="No connections found")
|
||||
@@ -480,12 +479,16 @@ class BIM_PT_placement(Panel):
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return (obj := context.active_object) and obj.BIMObjectProperties.ifc_definition_id
|
||||
return (obj := context.active_object) and tool.Blender.get_ifc_definition_id(obj)
|
||||
|
||||
def draw(self, context):
|
||||
if not PlacementData.is_loaded:
|
||||
PlacementData.load()
|
||||
|
||||
obj = context.active_object
|
||||
assert obj
|
||||
props = tool.Blender.get_object_bim_props(obj)
|
||||
|
||||
if not PlacementData.data["has_placement"]:
|
||||
row = self.layout.row()
|
||||
row.label(text="No Object Placement Found")
|
||||
@@ -496,12 +499,12 @@ class BIM_PT_placement(Panel):
|
||||
row = self.layout.row()
|
||||
row.prop(context.active_object, "rotation_euler", text="Rotation")
|
||||
|
||||
if context.active_object.BIMObjectProperties.blender_offset_type != "NONE":
|
||||
if props.blender_offset_type != "NONE":
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="Blender Offset", icon="TRACKING_REFINE_FORWARDS")
|
||||
row.label(text=context.active_object.BIMObjectProperties.blender_offset_type)
|
||||
row.label(text=props.blender_offset_type)
|
||||
|
||||
if context.active_object.BIMObjectProperties.blender_offset_type != "NOT_APPLICABLE":
|
||||
if props.blender_offset_type != "NOT_APPLICABLE":
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text=PlacementData.data["original_x"], icon="EMPTY_AXIS")
|
||||
row.label(text=PlacementData.data["original_y"])
|
||||
|
||||
@@ -91,9 +91,10 @@ class BIM_PT_object_groups(Panel):
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not context.active_object:
|
||||
if not (obj := context.active_object):
|
||||
return False
|
||||
return tool.Ifc.get() and context.active_object.BIMObjectProperties.ifc_definition_id
|
||||
props = tool.Blender.get_object_bim_props(obj)
|
||||
return tool.Ifc.get() and props.ifc_definition_id
|
||||
|
||||
def draw(self, context):
|
||||
if not ObjectGroupsData.is_loaded:
|
||||
|
||||
@@ -374,16 +374,17 @@ class ObjectLog(bpy.types.Operator):
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not context.active_object:
|
||||
if not (obj := context.active_object):
|
||||
cls.poll_message_set("No Active Object")
|
||||
elif not context.active_object.BIMObjectProperties.ifc_definition_id:
|
||||
elif not tool.Blender.get_ifc_definition_id(obj):
|
||||
cls.poll_message_set("Active Object doesn't have an IFC definition")
|
||||
else:
|
||||
return True
|
||||
|
||||
def execute(self, context):
|
||||
|
||||
step_id = context.active_object.BIMObjectProperties.ifc_definition_id
|
||||
obj = context.active_object
|
||||
assert obj
|
||||
step_id = tool.Blender.get_ifc_definition_id(obj)
|
||||
core.entity_log(tool.IfcGit, tool.Ifc, step_id, self)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -137,14 +137,14 @@ class BIM_PT_object_material(Panel):
|
||||
def poll(cls, context):
|
||||
if not tool.Blender.is_tab(context, "GEOMETRY"):
|
||||
return False
|
||||
if not context.active_object:
|
||||
if not (obj := context.active_object):
|
||||
return False
|
||||
props = context.active_object.BIMObjectProperties
|
||||
if not props.ifc_definition_id:
|
||||
ifc_id = tool.Blender.get_ifc_definition_id(obj)
|
||||
if not ifc_id:
|
||||
return False
|
||||
if not tool.Ifc.get_object_by_identifier(props.ifc_definition_id):
|
||||
if not tool.Ifc.get_object_by_identifier(ifc_id):
|
||||
return False
|
||||
if not hasattr(tool.Ifc.get().by_id(props.ifc_definition_id), "HasAssociations"):
|
||||
if not hasattr(tool.Ifc.get().by_id(ifc_id), "HasAssociations"):
|
||||
return False
|
||||
return True
|
||||
|
||||
@@ -152,9 +152,11 @@ class BIM_PT_object_material(Panel):
|
||||
if not ObjectMaterialData.is_loaded:
|
||||
ObjectMaterialData.load()
|
||||
|
||||
obj = context.active_object
|
||||
assert obj
|
||||
self.file = tool.Ifc.get()
|
||||
self.oprops = context.active_object.BIMObjectProperties
|
||||
self.props = context.active_object.BIMObjectMaterialProperties
|
||||
self.oprops = tool.Blender.get_object_bim_props(obj)
|
||||
self.props = obj.BIMObjectMaterialProperties
|
||||
self.mprops = tool.Material.get_material_props()
|
||||
|
||||
if not ObjectMaterialData.data["materials"]:
|
||||
|
||||
@@ -257,7 +257,7 @@ class DrawSystemArrows(bpy.types.Operator, tool.Ifc.Operator):
|
||||
sources = []
|
||||
|
||||
for obj in bpy.context.selected_objects:
|
||||
if not obj.BIMObjectProperties.ifc_definition_id:
|
||||
if not tool.Blender.get_ifc_definition_id(obj):
|
||||
continue
|
||||
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
|
||||
@@ -72,7 +72,9 @@ class DisableEditingArray(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def _execute(self, context):
|
||||
context.active_object.BIMArrayProperties.is_editing = -1
|
||||
obj = context.active_object
|
||||
assert obj
|
||||
tool.Model.get_array_props(obj).is_editing = -1
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -84,8 +86,9 @@ class EnableEditingArray(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
assert obj
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
props = obj.BIMArrayProperties
|
||||
props = tool.Model.get_array_props(obj)
|
||||
|
||||
relating_obj = props.relating_array_object
|
||||
|
||||
@@ -119,7 +122,7 @@ class EditArray(bpy.types.Operator, tool.Ifc.Operator):
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
props = obj.BIMArrayProperties
|
||||
props = tool.Model.get_array_props(obj)
|
||||
si_conversion = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||
|
||||
pset = ifcopenshell.util.element.get_pset(element, "BBIM_Array")
|
||||
@@ -182,7 +185,7 @@ class RemoveArray(bpy.types.Operator, tool.Ifc.Operator):
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
props = obj.BIMArrayProperties
|
||||
props = tool.Model.get_array_props(obj)
|
||||
|
||||
pset = ifcopenshell.util.element.get_pset(element, "BBIM_Array")
|
||||
data = json.loads(pset["Data"])
|
||||
@@ -302,7 +305,8 @@ class Input3DCursorXArray(bpy.types.Operator):
|
||||
|
||||
def execute(self, context):
|
||||
obj = context.active_object
|
||||
props = obj.BIMArrayProperties
|
||||
assert obj
|
||||
props = tool.Model.get_array_props(obj)
|
||||
cursor = context.scene.cursor
|
||||
if props.use_local_space:
|
||||
props.x = (Matrix.inverted(obj.matrix_world) @ cursor.matrix.translation).x
|
||||
@@ -318,7 +322,8 @@ class Input3DCursorYArray(bpy.types.Operator):
|
||||
|
||||
def execute(self, context):
|
||||
obj = context.active_object
|
||||
props = obj.BIMArrayProperties
|
||||
assert obj
|
||||
props = tool.Model.get_array_props(obj)
|
||||
cursor = context.scene.cursor
|
||||
if props.use_local_space:
|
||||
props.y = (Matrix.inverted(obj.matrix_world) @ cursor.matrix.translation).y
|
||||
@@ -334,7 +339,8 @@ class Input3DCursorZArray(bpy.types.Operator):
|
||||
|
||||
def execute(self, context):
|
||||
obj = context.active_object
|
||||
props = obj.BIMArrayProperties
|
||||
assert obj
|
||||
props = tool.Model.get_array_props(obj)
|
||||
cursor = context.scene.cursor
|
||||
if props.use_local_space:
|
||||
props.z = (Matrix.inverted(obj.matrix_world) @ cursor.matrix.translation).z
|
||||
|
||||
@@ -385,7 +385,9 @@ class StairData:
|
||||
|
||||
@classmethod
|
||||
def general_params(cls):
|
||||
props = bpy.context.active_object.BIMStairProperties
|
||||
obj = bpy.context.active_object
|
||||
assert obj
|
||||
props = tool.Model.get_stair_props(obj)
|
||||
data = cls.data["pset_data"]["data_dict"]
|
||||
general_params = {}
|
||||
general_props = props.get_props_kwargs(stair_type=data["stair_type"])
|
||||
@@ -451,7 +453,9 @@ class WindowData:
|
||||
|
||||
@classmethod
|
||||
def general_params(cls):
|
||||
props = bpy.context.active_object.BIMWindowProperties
|
||||
obj = bpy.context.active_object
|
||||
assert obj
|
||||
props = tool.Model.get_window_props(obj)
|
||||
data = cls.data["pset_data"]["data_dict"]
|
||||
general_params = {}
|
||||
general_props = props.get_general_kwargs()
|
||||
@@ -462,7 +466,9 @@ class WindowData:
|
||||
|
||||
@classmethod
|
||||
def lining_params(cls):
|
||||
props = bpy.context.active_object.BIMWindowProperties
|
||||
obj = bpy.context.active_object
|
||||
assert obj
|
||||
props = tool.Model.get_window_props(obj)
|
||||
data = cls.data["pset_data"]["data_dict"]
|
||||
lining_data = data["lining_properties"]
|
||||
lining_params = {}
|
||||
@@ -474,7 +480,9 @@ class WindowData:
|
||||
|
||||
@classmethod
|
||||
def panel_params(cls):
|
||||
props = bpy.context.active_object.BIMWindowProperties
|
||||
obj = bpy.context.active_object
|
||||
assert obj
|
||||
props = tool.Model.get_window_props(obj)
|
||||
panel_data = cls.data["pset_data"]["data_dict"]["panel_properties"]
|
||||
panel_params = {}
|
||||
panel_props = props.get_panel_kwargs()
|
||||
@@ -565,7 +573,9 @@ class RailingData:
|
||||
|
||||
@classmethod
|
||||
def general_params(cls):
|
||||
props = bpy.context.active_object.BIMRailingProperties
|
||||
obj = bpy.context.active_object
|
||||
assert obj
|
||||
props = tool.Model.get_railing_props(obj)
|
||||
data = cls.data["pset_data"]["data_dict"]
|
||||
general_params = {}
|
||||
general_props = props.get_general_kwargs(railing_type=data["railing_type"])
|
||||
@@ -599,7 +609,9 @@ class RoofData:
|
||||
|
||||
@classmethod
|
||||
def general_params(cls):
|
||||
props = bpy.context.active_object.BIMRoofProperties
|
||||
obj = bpy.context.active_object
|
||||
assert obj
|
||||
props = tool.Model.get_roof_props(obj)
|
||||
data = cls.data["pset_data"]["data_dict"]
|
||||
general_params = {}
|
||||
general_props = props.get_general_kwargs(generation_method=data["generation_method"])
|
||||
|
||||
@@ -718,14 +718,15 @@ class MirrorElements(bpy.types.Operator, tool.Ifc.Operator):
|
||||
obj.matrix_world = newmat
|
||||
|
||||
|
||||
def generate_box(usecase_path, ifc_file, settings):
|
||||
def generate_box(usecase_path: str, ifc_file: ifcopenshell.file, settings: dict[str, Any]) -> None:
|
||||
box_context = ifcopenshell.util.representation.get_context(ifc_file, "Model", "Box", "MODEL_VIEW")
|
||||
if not box_context:
|
||||
return
|
||||
obj = settings["blender_object"]
|
||||
if 0 in list(obj.dimensions):
|
||||
return
|
||||
product = ifc_file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
product = tool.Ifc.get_entity(obj)
|
||||
assert product
|
||||
old_box = ifcopenshell.util.representation.get_representation(product, "Model", "Box", "MODEL_VIEW")
|
||||
if settings["context"].ContextType == "Model" and getattr(settings["context"], "ContextIdentifier") == "Body":
|
||||
if old_box:
|
||||
|
||||
@@ -28,34 +28,36 @@ from math import pi, radians
|
||||
from bonsai.bim.module.model.decorator import WallAxisDecorator, SlabDirectionDecorator
|
||||
from bonsai.bim.module.model.door import update_door_modifier_bmesh
|
||||
from bonsai.bim.module.model.window import update_window_modifier_bmesh
|
||||
from typing import TYPE_CHECKING, Literal, get_args
|
||||
from typing import TYPE_CHECKING, Literal, get_args, Union, get_args
|
||||
|
||||
|
||||
def get_ifc_class(self, context):
|
||||
def get_ifc_class(self: "BIMModelProperties", context: bpy.types.Context) -> list[tuple[str, str, str]]:
|
||||
if not AuthoringData.is_loaded:
|
||||
AuthoringData.load()
|
||||
return AuthoringData.data["ifc_classes"]
|
||||
|
||||
|
||||
def get_boundary_class(self, context):
|
||||
def get_boundary_class(self: "BIMModelProperties", context: bpy.types.Context) -> list[tuple[str, str, str]]:
|
||||
if not AuthoringData.is_loaded:
|
||||
AuthoringData.load()
|
||||
return AuthoringData.data["boundary_class"]
|
||||
|
||||
|
||||
def get_relating_type_id(self, context):
|
||||
def get_relating_type_id(self: "BIMModelProperties", context: bpy.types.Context) -> list[tuple[str, str, str]]:
|
||||
if not AuthoringData.is_loaded:
|
||||
AuthoringData.load()
|
||||
return AuthoringData.data["relating_type_id"]
|
||||
|
||||
|
||||
def get_materials(self, context):
|
||||
def get_materials(
|
||||
self: Union["BIMWindowProperties", "BIMDoorProperties"], context: bpy.types.Context
|
||||
) -> list[tuple[str, str, str]]:
|
||||
if not AuthoringData.is_loaded:
|
||||
AuthoringData.load()
|
||||
return AuthoringData.data["materials"]
|
||||
|
||||
|
||||
def update_ifc_class(self, context):
|
||||
def update_ifc_class(self: "BIMModelProperties", context: bpy.types.Context) -> None:
|
||||
bpy.ops.bim.load_type_thumbnails(ifc_class=self.ifc_class)
|
||||
AuthoringData.data["ifc_class_current"] = self.ifc_class
|
||||
AuthoringData.data["type_elements"] = AuthoringData.type_elements()
|
||||
@@ -72,46 +74,46 @@ def update_ifc_class(self, context):
|
||||
AuthoringData.data["paginated_relating_types"] = AuthoringData.paginated_relating_types()
|
||||
|
||||
|
||||
def update_relating_type_id(self, context):
|
||||
def update_relating_type_id(self: "BIMModelProperties", context: bpy.types.Context) -> None:
|
||||
AuthoringData.data["relating_type_id"] = AuthoringData.relating_type_id()
|
||||
AuthoringData.data["relating_type_data"] = AuthoringData.relating_type_data()
|
||||
self.type_page = [e[0] for e in AuthoringData.data["relating_type_id"]].index(self.relating_type_id) // 9 + 1
|
||||
|
||||
|
||||
def update_type_page(self, context):
|
||||
def update_type_page(self: "BIMModelProperties", context: bpy.types.Context) -> None:
|
||||
AuthoringData.data["paginated_relating_types"] = AuthoringData.paginated_relating_types()
|
||||
bpy.ops.bim.load_type_thumbnails(ifc_class=self.ifc_class, offset=9 * (self.type_page - 1), limit=9)
|
||||
self["type_page"] = min(self["type_page"], AuthoringData.data["total_pages"])
|
||||
self["type_page"] = max(self["type_page"], 1)
|
||||
|
||||
|
||||
def update_relating_array_from_object(self, context):
|
||||
def update_relating_array_from_object(self: "BIMArrayProperties", context: bpy.types.Context) -> None:
|
||||
bpy.ops.bim.enable_editing_array(item=self.is_editing)
|
||||
return
|
||||
|
||||
|
||||
def is_object_array_applicable(self, obj):
|
||||
def is_object_array_applicable(self: "BIMArrayProperties", obj: bpy.types.Object) -> bool:
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
if not element:
|
||||
return False
|
||||
return ifcopenshell.util.element.get_pset(element, "BBIM_Array")
|
||||
|
||||
|
||||
def update_wall_axis_decorator(self, context):
|
||||
def update_wall_axis_decorator(self: "BIMModelProperties", context: bpy.types.Context) -> None:
|
||||
if self.show_wall_axis:
|
||||
WallAxisDecorator.install(bpy.context)
|
||||
else:
|
||||
WallAxisDecorator.uninstall()
|
||||
|
||||
|
||||
def update_slab_direction_decorator(self, context):
|
||||
def update_slab_direction_decorator(self: "BIMModelProperties", context: bpy.types.Context) -> None:
|
||||
if self.show_slab_direction:
|
||||
SlabDirectionDecorator.install(bpy.context)
|
||||
else:
|
||||
SlabDirectionDecorator.uninstall()
|
||||
|
||||
|
||||
def update_search_name(self, context):
|
||||
def update_search_name(self: "BIMModelProperties", context: bpy.types.Context) -> None:
|
||||
AuthoringData.load()
|
||||
# Total number of pages may decrease when using the search bar :
|
||||
if self.type_page > AuthoringData.data["total_pages"]:
|
||||
@@ -119,17 +121,17 @@ def update_search_name(self, context):
|
||||
bpy.ops.bim.load_type_thumbnails(ifc_class=self.ifc_class)
|
||||
|
||||
|
||||
def update_x_angle(self, context):
|
||||
def update_x_angle(self: "BIMModelProperties", context: bpy.types.Context) -> None:
|
||||
angle_deg = math.degrees(self.x_angle)
|
||||
if tool.Cad.is_x(angle_deg, -90, 0.5) or tool.Cad.is_x(angle_deg, 90, 0.5):
|
||||
self.x_angle = 0
|
||||
|
||||
|
||||
def update_door(self, context):
|
||||
def update_door(self: "BIMDoorProperties", context: bpy.types.Context) -> None:
|
||||
update_door_modifier_bmesh(context)
|
||||
|
||||
|
||||
def update_window(self, context):
|
||||
def update_window(self: "BIMWindowProperties", context: bpy.types.Context) -> None:
|
||||
update_window_modifier_bmesh(context)
|
||||
|
||||
|
||||
@@ -303,36 +305,45 @@ class BIMArrayProperties(PropertyGroup):
|
||||
poll=is_object_array_applicable,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
is_editing: int
|
||||
count: int
|
||||
x: float
|
||||
y: float
|
||||
z: float
|
||||
use_local_space: bool
|
||||
method: Literal["OFFSET", "DISTRIBUTE"]
|
||||
sync_children: bool
|
||||
relating_array_object: Union[bpy.types.Object, None]
|
||||
|
||||
def update_total_length_target(self, context):
|
||||
|
||||
def update_total_length_target(self: "BIMStairProperties", context: bpy.types.Context) -> None:
|
||||
self["tread_run"] = self.total_length_target / (self.number_of_treads + 1)
|
||||
|
||||
|
||||
def update_tread_run(self, context):
|
||||
def update_tread_run(self: "BIMStairProperties", context: bpy.types.Context) -> None:
|
||||
if self.total_length_lock:
|
||||
self["number_of_treads"] = int((self.total_length_target / self.tread_run) - 1)
|
||||
else:
|
||||
self["total_length_target"] = (self.number_of_treads + 1) * self.tread_run
|
||||
|
||||
|
||||
def update_number_of_treads(self, context):
|
||||
def update_number_of_treads(self: "BIMStairProperties", context: bpy.types.Context) -> None:
|
||||
if self.total_length_lock:
|
||||
self["tread_run"] = self.total_length_target / (self.number_of_treads + 1)
|
||||
else:
|
||||
self["total_length_target"] = (self.number_of_treads + 1) * self.tread_run
|
||||
|
||||
|
||||
StairType = Literal["CONCRETE", "WOOD/STEEL", "GENERIC"]
|
||||
|
||||
|
||||
class BIMStairProperties(PropertyGroup):
|
||||
def validate_nosing_value(self, context):
|
||||
def validate_nosing_value(self, context: bpy.types.Context) -> None:
|
||||
if self.stair_type != "WOOD/STEEL" and self.nosing_length < 0:
|
||||
self["nosing_length"] = 0
|
||||
|
||||
non_si_units_props = ("is_editing", "number_of_treads", "has_top_nib", "stair_type")
|
||||
stair_types = (
|
||||
("CONCRETE", "Concrete", ""),
|
||||
("WOOD/STEEL", "Wood / Steel", ""),
|
||||
("GENERIC", "Generic", ""),
|
||||
)
|
||||
|
||||
is_editing: bpy.props.BoolProperty(default=False)
|
||||
width: bpy.props.FloatProperty(name="Width", default=1.2, soft_min=0.01, subtype="DISTANCE")
|
||||
@@ -361,7 +372,10 @@ class BIMStairProperties(PropertyGroup):
|
||||
top_slab_depth: bpy.props.FloatProperty(name="Top Slab Depth", default=0.25, soft_min=0, subtype="DISTANCE")
|
||||
has_top_nib: bpy.props.BoolProperty(name="Has Top Nib", default=True)
|
||||
stair_type: bpy.props.EnumProperty(
|
||||
name="Stair Type", items=stair_types, default="CONCRETE", update=validate_nosing_value
|
||||
name="Stair Type",
|
||||
items=[(i, i.replace("/", " / ").title(), "") for i in get_args(StairType)],
|
||||
default="CONCRETE",
|
||||
update=validate_nosing_value,
|
||||
)
|
||||
custom_first_last_tread_run: bpy.props.FloatVectorProperty(
|
||||
name="Custom First / Last Treads Widths",
|
||||
@@ -385,6 +399,23 @@ class BIMStairProperties(PropertyGroup):
|
||||
name="Nosing Depth", description="Depth of the tread's nosing", min=0, default=0, unit="LENGTH"
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
is_editing: bool
|
||||
width: float
|
||||
height: float
|
||||
number_of_treads: int
|
||||
total_length_target: float
|
||||
total_length_lock: bool
|
||||
tread_depth: float
|
||||
tread_run: float
|
||||
base_slab_depth: float
|
||||
top_slab_depth: float
|
||||
has_top_nib: bool
|
||||
stair_type: str
|
||||
custom_first_last_tread_run: tuple[float, float]
|
||||
nosing_length: float
|
||||
nosing_depth: float
|
||||
|
||||
def get_props_kwargs(self, convert_to_project_units=False, stair_type=None):
|
||||
if not stair_type:
|
||||
stair_type = self.stair_type
|
||||
@@ -445,20 +476,22 @@ def window_type_prop_update(self, context):
|
||||
update_window(self, context)
|
||||
|
||||
|
||||
WindowType = Literal[
|
||||
"SINGLE_PANEL",
|
||||
"DOUBLE_PANEL_HORIZONTAL",
|
||||
"DOUBLE_PANEL_VERTICAL",
|
||||
"TRIPLE_PANEL_BOTTOM",
|
||||
"TRIPLE_PANEL_TOP",
|
||||
"TRIPLE_PANEL_LEFT",
|
||||
"TRIPLE_PANEL_RIGHT",
|
||||
"TRIPLE_PANEL_HORIZONTAL",
|
||||
"TRIPLE_PANEL_VERTICAL",
|
||||
]
|
||||
|
||||
|
||||
# default prop values are in mm and converted later
|
||||
class BIMWindowProperties(PropertyGroup):
|
||||
non_si_units_props = ("is_editing", "window_type")
|
||||
window_types = (
|
||||
("SINGLE_PANEL", "SINGLE_PANEL", ""),
|
||||
("DOUBLE_PANEL_HORIZONTAL", "DOUBLE_PANEL_HORIZONTAL", ""),
|
||||
("DOUBLE_PANEL_VERTICAL", "DOUBLE_PANEL_VERTICAL", ""),
|
||||
("TRIPLE_PANEL_BOTTOM", "TRIPLE_PANEL_BOTTOM", ""),
|
||||
("TRIPLE_PANEL_TOP", "TRIPLE_PANEL_TOP", ""),
|
||||
("TRIPLE_PANEL_LEFT", "TRIPLE_PANEL_LEFT", ""),
|
||||
("TRIPLE_PANEL_RIGHT", "TRIPLE_PANEL_RIGHT", ""),
|
||||
("TRIPLE_PANEL_HORIZONTAL", "TRIPLE_PANEL_HORIZONTAL", ""),
|
||||
("TRIPLE_PANEL_VERTICAL", "TRIPLE_PANEL_VERTICAL", ""),
|
||||
)
|
||||
|
||||
# number of panels and default mullion/transom values
|
||||
# fmt: off
|
||||
@@ -477,7 +510,10 @@ class BIMWindowProperties(PropertyGroup):
|
||||
|
||||
is_editing: bpy.props.BoolProperty(default=False)
|
||||
window_type: bpy.props.EnumProperty(
|
||||
name="Window Type", items=window_types, default="SINGLE_PANEL", update=window_type_prop_update
|
||||
name="Window Type",
|
||||
items=[(i, i, "") for i in get_args(WindowType)],
|
||||
default="SINGLE_PANEL",
|
||||
update=window_type_prop_update,
|
||||
)
|
||||
overall_height: bpy.props.FloatProperty(
|
||||
name="Overall Height", default=0.9, subtype="DISTANCE", update=update_window
|
||||
@@ -546,6 +582,31 @@ class BIMWindowProperties(PropertyGroup):
|
||||
framing_material: bpy.props.EnumProperty(name="Framing Material", items=get_materials, options=set())
|
||||
glazing_material: bpy.props.EnumProperty(name="Glazing Material", items=get_materials, options=set())
|
||||
|
||||
if TYPE_CHECKING:
|
||||
is_editing: bool
|
||||
window_type: WindowType
|
||||
overall_height: float
|
||||
overall_width: float
|
||||
lining_depth: float
|
||||
lining_thickness: float
|
||||
lining_offset: float
|
||||
lining_to_panel_offset_x: float
|
||||
lining_to_panel_offset_y: float
|
||||
mullion_thickness: float
|
||||
first_mullion_offset: float
|
||||
second_mullion_offset: float
|
||||
first_transom_offset: float
|
||||
second_transom_offset: float
|
||||
|
||||
# Panel properties.
|
||||
frame_depth: tuple[float, float, float]
|
||||
frame_thickness: tuple[float, float, float]
|
||||
|
||||
# Material properties.
|
||||
lining_material: str
|
||||
framing_material: str
|
||||
glazing_material: str
|
||||
|
||||
def get_general_kwargs(self, convert_to_project_units=False):
|
||||
kwargs = {
|
||||
"window_type": self.window_type,
|
||||
@@ -824,6 +885,10 @@ class BIMDoorProperties(PropertyGroup):
|
||||
setattr(self, prop_name, kwargs[prop_name])
|
||||
|
||||
|
||||
RailingType = Literal["FRAMELESS_PANEL", "WALL_MOUNTED_HANDRAIL"]
|
||||
CapType = Literal["TO_END_POST_AND_FLOOR", "TO_END_POST", "TO_FLOOR", "TO_WALL", "180", "NONE"]
|
||||
|
||||
|
||||
class BIMRailingProperties(PropertyGroup):
|
||||
non_si_units_props = (
|
||||
"is_editing",
|
||||
@@ -833,23 +898,12 @@ class BIMRailingProperties(PropertyGroup):
|
||||
"path_data",
|
||||
)
|
||||
|
||||
railing_types = (
|
||||
("FRAMELESS_PANEL", "FRAMELESS_PANEL", ""),
|
||||
("WALL_MOUNTED_HANDRAIL", "WALL_MOUNTED_HANDRAIL", ""),
|
||||
)
|
||||
cap_types = (
|
||||
("TO_END_POST_AND_FLOOR", "TO_END_POST_AND_FLOOR", ""),
|
||||
("TO_END_POST", "TO_END_POST", ""),
|
||||
("TO_FLOOR", "TO_FLOOR", ""),
|
||||
("TO_WALL", "TO_WALL", ""),
|
||||
("180", "180", ""),
|
||||
("NONE", "NONE", ""),
|
||||
)
|
||||
|
||||
is_editing: bpy.props.BoolProperty(default=False)
|
||||
is_editing_path: bpy.props.BoolProperty(default=False)
|
||||
|
||||
railing_type: bpy.props.EnumProperty(name="Railing Type", items=railing_types, default="FRAMELESS_PANEL")
|
||||
railing_type: bpy.props.EnumProperty(
|
||||
name="Railing Type", items=[(i, i, "") for i in get_args(RailingType)], default="FRAMELESS_PANEL"
|
||||
)
|
||||
height: bpy.props.FloatProperty(name="Height", default=1.0, subtype="DISTANCE")
|
||||
thickness: bpy.props.FloatProperty(name="Thickness", default=0.050, subtype="DISTANCE")
|
||||
spacing: bpy.props.FloatProperty(name="Spacing", default=0.050, subtype="DISTANCE")
|
||||
@@ -875,7 +929,24 @@ class BIMRailingProperties(PropertyGroup):
|
||||
description="Clear width between the railing and the wall",
|
||||
subtype="DISTANCE",
|
||||
)
|
||||
terminal_type: bpy.props.EnumProperty(name="Terminal Type", items=cap_types, default="180")
|
||||
terminal_type: bpy.props.EnumProperty(
|
||||
name="Terminal Type", items=[(i, i, "") for i in get_args(CapType)], default="180"
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
is_editing: bool
|
||||
is_editing_path: bool
|
||||
|
||||
railing_type: RailingType
|
||||
height: float
|
||||
thickness: float
|
||||
spacing: float
|
||||
|
||||
use_manual_supports: bool
|
||||
support_spacing: float
|
||||
railing_diameter: float
|
||||
clear_width: float
|
||||
terminal_type: CapType
|
||||
|
||||
def get_general_kwargs(self, railing_type=None, convert_to_project_units=False):
|
||||
if railing_type is None:
|
||||
@@ -921,11 +992,15 @@ def to_percentage(angle: float) -> float:
|
||||
return math.tan(angle) * 100
|
||||
|
||||
|
||||
RoofType = Literal["HIP/GABLE ROOF"]
|
||||
RoofGenerationMethod = Literal["HEIGHT", "ANGLE"]
|
||||
|
||||
|
||||
class BIMRoofProperties(PropertyGroup):
|
||||
def update_angle(self, context) -> None:
|
||||
def update_angle(self, context: bpy.types.Context) -> None:
|
||||
self["angle"] = to_angle(self.percentage)
|
||||
|
||||
def update_percentage(self, context) -> None:
|
||||
def update_percentage(self, context: bpy.types.Context) -> None:
|
||||
self["percentage"] = to_percentage(self.angle)
|
||||
|
||||
non_si_units_props = (
|
||||
@@ -937,18 +1012,15 @@ class BIMRoofProperties(PropertyGroup):
|
||||
"percentage",
|
||||
"rafter_edge_angle",
|
||||
)
|
||||
roof_types = (("HIP/GABLE ROOF", "HIP/GABLE ROOF", ""),)
|
||||
roof_generation_methods = (
|
||||
("HEIGHT", "HEIGHT", ""),
|
||||
("ANGLE", "ANGLE", ""),
|
||||
)
|
||||
|
||||
is_editing: bpy.props.BoolProperty(default=False)
|
||||
is_editing_path: bpy.props.BoolProperty(default=False)
|
||||
|
||||
roof_type: bpy.props.EnumProperty(name="Roof Type", items=roof_types, default="HIP/GABLE ROOF")
|
||||
roof_type: bpy.props.EnumProperty(
|
||||
name="Roof Type", items=[(i, i, "") for i in get_args(RoofType)], default="HIP/GABLE ROOF"
|
||||
)
|
||||
generation_method: bpy.props.EnumProperty(
|
||||
name="Roof Generation Method", items=roof_generation_methods, default="ANGLE"
|
||||
name="Roof Generation Method", items=[(i, i, "") for i in get_args(RoofGenerationMethod)], default="ANGLE"
|
||||
)
|
||||
height: bpy.props.FloatProperty(
|
||||
name="Height", default=1.0, description="Maximum height of the roof to be generated.", subtype="DISTANCE"
|
||||
@@ -978,6 +1050,17 @@ class BIMRoofProperties(PropertyGroup):
|
||||
name="Rafter Edge Angle", min=0, max=pi / 2, default=pi / 2, subtype="ANGLE"
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
is_editing: bool
|
||||
is_editing_path: bool
|
||||
roof_type: Literal["HIP/GABLE ROOF"]
|
||||
generation_method: Literal["HEIGHT", "ANGLE"]
|
||||
height: float
|
||||
angle: float
|
||||
percentage: float
|
||||
roof_thickness: float
|
||||
rafter_edge_angle: float
|
||||
|
||||
def get_general_kwargs(self, generation_method=None, convert_to_project_units=False):
|
||||
if generation_method is None:
|
||||
generation_method = self.generation_method
|
||||
|
||||
@@ -55,8 +55,10 @@ def update_railing_modifier_ifc_data(context: bpy.types.Context) -> None:
|
||||
since it's going to update ifc representation
|
||||
"""
|
||||
obj = context.active_object
|
||||
props = obj.BIMRailingProperties
|
||||
assert obj
|
||||
props = tool.Model.get_railing_props(obj)
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
assert element
|
||||
ifc_file = tool.Ifc.get()
|
||||
|
||||
# type attributes
|
||||
@@ -122,7 +124,8 @@ def update_railing_modifier_bmesh(context: bpy.types.Context) -> None:
|
||||
If BBIM Pset just changed should call refresh() before updating bmesh
|
||||
"""
|
||||
obj = context.active_object
|
||||
props = obj.BIMRailingProperties
|
||||
assert obj
|
||||
props = tool.Model.get_railing_props(obj)
|
||||
V_ = tool.Blender.V_
|
||||
|
||||
# NOTE: using Data since bmesh update will hapen very often
|
||||
@@ -327,8 +330,10 @@ class AddRailing(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
assert obj
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
props = obj.BIMRailingProperties
|
||||
assert element
|
||||
props = tool.Model.get_railing_props(obj)
|
||||
si_conversion = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||
|
||||
railing_data = props.get_general_kwargs(convert_to_project_units=True)
|
||||
@@ -367,7 +372,8 @@ class CopyRailingParameters(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
def _execute(self, context):
|
||||
source_obj = context.active_object
|
||||
source_props = source_obj.BIMRailingProperties
|
||||
assert source_obj
|
||||
source_props = tool.Model.get_railing_props(source_obj)
|
||||
railing_data = source_props.get_general_kwargs(convert_to_project_units=True)
|
||||
|
||||
for target_obj in context.selected_objects:
|
||||
@@ -379,7 +385,8 @@ class CopyRailingParameters(bpy.types.Operator, tool.Ifc.Operator):
|
||||
continue
|
||||
railing_data["path_data"] = RailingData.data["path_data"]
|
||||
target_element = tool.Ifc.get_entity(target_obj)
|
||||
target_props = target_obj.BIMRailingProperties
|
||||
assert target_element
|
||||
target_props = tool.Model.get_railing_props(target_obj)
|
||||
|
||||
target_props.set_props_kwargs_from_ifc_data(railing_data)
|
||||
update_bbim_railing_pset(target_element, railing_data)
|
||||
@@ -398,7 +405,8 @@ class EnableEditingRailing(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
props = obj.BIMRailingProperties
|
||||
assert obj
|
||||
props = tool.Model.get_railing_props(obj)
|
||||
data = tool.Model.get_modeling_bbim_pset_data(obj, "BBIM_Railing")["data_dict"]
|
||||
data["path_data"] = json.dumps(data["path_data"])
|
||||
|
||||
@@ -416,8 +424,9 @@ class CancelEditingRailing(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
assert obj
|
||||
data = tool.Model.get_modeling_bbim_pset_data(obj, "BBIM_Railing")["data_dict"]
|
||||
props = obj.BIMRailingProperties
|
||||
props = tool.Model.get_railing_props(obj)
|
||||
|
||||
# restore previous settings since editing was canceled
|
||||
props.set_props_kwargs_from_ifc_data(data)
|
||||
@@ -434,8 +443,10 @@ class FinishEditingRailing(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
assert obj
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
props = obj.BIMRailingProperties
|
||||
assert element
|
||||
props = tool.Model.get_railing_props(obj)
|
||||
|
||||
pset_data = tool.Model.get_modeling_bbim_pset_data(bpy.context.active_object, "BBIM_Railing")
|
||||
path_data = pset_data["data_dict"]["path_data"]
|
||||
@@ -457,8 +468,10 @@ class FlipRailingPathOrder(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
assert obj
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
props = obj.BIMRailingProperties
|
||||
assert element
|
||||
props = tool.Model.get_railing_props(obj)
|
||||
|
||||
pset_data = tool.Model.get_modeling_bbim_pset_data(bpy.context.active_object, "BBIM_Railing")
|
||||
path_data = pset_data["data_dict"]["path_data"]
|
||||
@@ -488,7 +501,8 @@ class EnableEditingRailingPath(bpy.types.Operator, tool.Ifc.Operator):
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
[o.select_set(False) for o in context.selected_objects if o != obj]
|
||||
props = obj.BIMRailingProperties
|
||||
assert obj
|
||||
props = tool.Model.get_railing_props(obj)
|
||||
data = tool.Model.get_modeling_bbim_pset_data(obj, "BBIM_Railing")["data_dict"]
|
||||
# required since we could load pset from .ifc and BIMRoofProperties won't be set
|
||||
props.set_props_kwargs_from_ifc_data(data)
|
||||
@@ -505,7 +519,8 @@ class EnableEditingRailingPath(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
def cancel_editing_railing_path(context: bpy.types.Context) -> set[str]:
|
||||
obj = context.active_object
|
||||
props = obj.BIMRailingProperties
|
||||
assert obj
|
||||
props = tool.Model.get_railing_props(obj)
|
||||
|
||||
ProfileDecorator.uninstall()
|
||||
props.is_editing_path = False
|
||||
@@ -517,6 +532,7 @@ def cancel_editing_railing_path(context: bpy.types.Context) -> set[str]:
|
||||
update_railing_modifier_bmesh(context)
|
||||
else:
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
assert element
|
||||
body = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
|
||||
bonsai.core.geometry.switch_representation(
|
||||
tool.Ifc,
|
||||
@@ -547,8 +563,9 @@ class FinishEditingRailingPath(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
assert obj
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
props = obj.BIMRailingProperties
|
||||
props = tool.Model.get_railing_props(obj)
|
||||
|
||||
railing_data = props.get_general_kwargs(convert_to_project_units=True)
|
||||
path_data = get_path_data(obj)
|
||||
@@ -574,8 +591,11 @@ class RemoveRailing(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
assert obj
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
obj.BIMRailingProperties.is_editing = False
|
||||
assert element
|
||||
props = tool.Model.get_railing_props(obj)
|
||||
props.is_editing = False
|
||||
|
||||
pset = tool.Pset.get_element_pset(element, "BBIM_Railing")
|
||||
ifcopenshell.api.run("pset.remove_pset", tool.Ifc.get(), product=element, pset=pset)
|
||||
|
||||
@@ -409,7 +409,8 @@ def update_roof_modifier_ifc_data(context: bpy.types.Context) -> None:
|
||||
since it's going to update ifc representation
|
||||
"""
|
||||
obj = context.active_object
|
||||
props = obj.BIMRoofProperties
|
||||
assert obj
|
||||
props = tool.Model.get_roof_props(obj)
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
|
||||
def roof_is_gabled() -> bool:
|
||||
@@ -442,7 +443,7 @@ def update_roof_modifier_bmesh(obj: bpy.types.Object) -> None:
|
||||
"""before using should make sure that Data contains up-to-date information.
|
||||
If BBIM Pset just changed should call refresh() before updating bmesh
|
||||
"""
|
||||
props = obj.BIMRoofProperties
|
||||
props = tool.Model.get_roof_props(obj)
|
||||
assert isinstance(obj.data, bpy.types.Mesh)
|
||||
|
||||
# NOTE: using Data since bmesh update will hapen very often
|
||||
@@ -559,7 +560,7 @@ class AddRoof(bpy.types.Operator, tool.Ifc.Operator):
|
||||
obj = context.active_object
|
||||
assert obj
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
props = obj.BIMRoofProperties
|
||||
props = tool.Model.get_roof_props(obj)
|
||||
si_conversion = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||
|
||||
# rejecting original roof shape to be safe
|
||||
@@ -607,7 +608,8 @@ class EnableEditingRoof(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
props = obj.BIMRoofProperties
|
||||
assert obj
|
||||
props = tool.Model.get_roof_props(obj)
|
||||
data = tool.Model.get_modeling_bbim_pset_data(obj, "BBIM_Roof")["data_dict"]
|
||||
# required since we could load pset from .ifc and BIMRoofProperties won't be set
|
||||
props.set_props_kwargs_from_ifc_data(data)
|
||||
@@ -624,7 +626,7 @@ class CancelEditingRoof(bpy.types.Operator, tool.Ifc.Operator):
|
||||
obj = context.active_object
|
||||
assert obj
|
||||
data = tool.Model.get_modeling_bbim_pset_data(obj, "BBIM_Roof")["data_dict"]
|
||||
props = obj.BIMRoofProperties
|
||||
props = tool.Model.get_roof_props(obj)
|
||||
|
||||
# restore previous settings since editing was canceled
|
||||
props.set_props_kwargs_from_ifc_data(data)
|
||||
@@ -642,7 +644,7 @@ class FinishEditingRoof(bpy.types.Operator, tool.Ifc.Operator):
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
props = obj.BIMRoofProperties
|
||||
props = tool.Model.get_roof_props(obj)
|
||||
|
||||
pset_data = tool.Model.get_modeling_bbim_pset_data(obj, "BBIM_Roof")
|
||||
path_data = pset_data["data_dict"]["path_data"]
|
||||
@@ -666,7 +668,7 @@ class EnableEditingRoofPath(bpy.types.Operator, tool.Ifc.Operator):
|
||||
obj = context.active_object
|
||||
assert obj
|
||||
[o.select_set(False) for o in context.selected_objects if o != obj]
|
||||
props = obj.BIMRoofProperties
|
||||
props = tool.Model.get_roof_props(obj)
|
||||
data = tool.Model.get_modeling_bbim_pset_data(obj, "BBIM_Roof")["data_dict"]
|
||||
# required since we could load pset from .ifc and BIMRoofProperties won't be set
|
||||
props.set_props_kwargs_from_ifc_data(data)
|
||||
@@ -720,7 +722,7 @@ class EnableEditingRoofPath(bpy.types.Operator, tool.Ifc.Operator):
|
||||
def cancel_editing_roof_path(context: bpy.types.Context) -> set[str]:
|
||||
obj = context.active_object
|
||||
assert obj
|
||||
props = obj.BIMRoofProperties
|
||||
props = tool.Model.get_roof_props(obj)
|
||||
|
||||
ProfileDecorator.uninstall()
|
||||
props.is_editing_path = False
|
||||
@@ -751,7 +753,8 @@ class CopyRoofParameters(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
def _execute(self, context):
|
||||
source_obj = context.active_object
|
||||
source_props = source_obj.BIMRoofProperties
|
||||
assert source_obj
|
||||
source_props = tool.Model.get_roof_props(source_obj)
|
||||
data = source_props.get_general_kwargs(convert_to_project_units=True)
|
||||
|
||||
for target_obj in context.selected_objects:
|
||||
@@ -763,7 +766,7 @@ class CopyRoofParameters(bpy.types.Operator, tool.Ifc.Operator):
|
||||
continue
|
||||
data["path_data"] = RoofData.data["path_data"]
|
||||
target_element = tool.Ifc.get_entity(target_obj)
|
||||
target_props = target_obj.BIMRoofProperties
|
||||
target_props = tool.Model.get_roof_props(target_obj)
|
||||
|
||||
target_props.set_props_kwargs_from_ifc_data(data)
|
||||
update_bbim_roof_pset(target_element, data)
|
||||
@@ -783,7 +786,7 @@ class FinishEditingRoofPath(bpy.types.Operator, tool.Ifc.Operator):
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
props = obj.BIMRoofProperties
|
||||
props = tool.Model.get_roof_props(obj)
|
||||
|
||||
bm = tool.Blender.get_bmesh_for_mesh(obj.data)
|
||||
op_status, error_message = is_valid_roof_footprint(bm)
|
||||
@@ -815,9 +818,12 @@ class RemoveRoof(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
assert obj
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
obj.BIMRoofProperties.is_editing = False
|
||||
props = tool.Model.get_roof_props(obj)
|
||||
props.is_editing = False
|
||||
|
||||
assert element
|
||||
pset = tool.Pset.get_element_pset(element, "BBIM_Roof")
|
||||
ifcopenshell.api.run("pset.remove_pset", tool.Ifc.get(), product=element, pset=pset)
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -34,7 +34,8 @@ from bpy_extras.object_utils import AddObjectHelper, object_data_add
|
||||
|
||||
|
||||
def regenerate_stair_mesh(obj: bpy.types.Object) -> None:
|
||||
props_kwargs = obj.BIMStairProperties.get_props_kwargs()
|
||||
props = tool.Model.get_stair_props(obj)
|
||||
props_kwargs = props.get_props_kwargs()
|
||||
vertices, edges, faces = tool.Model.generate_stair_2d_profile(**props_kwargs)
|
||||
|
||||
bm = bmesh.new()
|
||||
@@ -69,7 +70,8 @@ def update_ifc_stair_props(obj: bpy.types.Object) -> None:
|
||||
since it's going to update ifc representation
|
||||
"""
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
props = obj.BIMStairProperties
|
||||
assert element
|
||||
props = tool.Model.get_stair_props(obj)
|
||||
ifc_file = tool.Ifc.get()
|
||||
|
||||
if tool.Ifc.get_schema() != "IFC2X3" and element.is_a("IfcStairFlight"):
|
||||
@@ -183,7 +185,8 @@ class AddStair(bpy.types.Operator, tool.Ifc.Operator):
|
||||
obj = context.active_object
|
||||
assert obj
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
props = obj.BIMStairProperties
|
||||
assert element
|
||||
props = tool.Model.get_stair_props(obj)
|
||||
ifc_file = tool.Ifc.get()
|
||||
|
||||
stair_data = props.get_props_kwargs(convert_to_project_units=True)
|
||||
@@ -214,9 +217,11 @@ class CancelEditingStair(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
assert obj
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
assert element
|
||||
data = json.loads(ifcopenshell.util.element.get_pset(element, "BBIM_Stair", "Data"))
|
||||
props = obj.BIMStairProperties
|
||||
props = tool.Model.get_stair_props(obj)
|
||||
# restore previous settings since editing was canceled
|
||||
props.set_props_kwargs_from_ifc_data(data)
|
||||
regenerate_stair_mesh(obj)
|
||||
@@ -233,8 +238,10 @@ class FinishEditingStair(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
assert obj
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
props = obj.BIMStairProperties
|
||||
assert element
|
||||
props = tool.Model.get_stair_props(obj)
|
||||
|
||||
data = props.get_props_kwargs(convert_to_project_units=True)
|
||||
props.is_editing = False
|
||||
@@ -257,7 +264,8 @@ class EnableEditingStair(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
props = obj.BIMStairProperties
|
||||
assert obj
|
||||
props = tool.Model.get_stair_props(obj)
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
data = json.loads(ifcopenshell.util.element.get_pset(element, "BBIM_Stair", "Data"))
|
||||
# required since we could load pset from .ifc and BIMStairProperties won't be set
|
||||
@@ -273,9 +281,11 @@ class RemoveStair(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
props = obj.BIMStairProperties
|
||||
assert obj
|
||||
props = tool.Model.get_stair_props(obj)
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
obj.BIMStairProperties.is_editing = False
|
||||
assert element
|
||||
props.is_editing = False
|
||||
|
||||
pset = tool.Pset.get_element_pset(element, "BBIM_Stair")
|
||||
ifcopenshell.api.run("pset.remove_pset", tool.Ifc.get(), product=element, pset=pset)
|
||||
|
||||
@@ -217,7 +217,9 @@ class BIM_PT_array(bpy.types.Panel):
|
||||
if not ArrayData.is_loaded:
|
||||
ArrayData.load()
|
||||
|
||||
props = context.active_object.BIMArrayProperties
|
||||
obj = context.active_object
|
||||
assert obj
|
||||
props = tool.Model.get_array_props(obj)
|
||||
|
||||
if ArrayData.data["parameters"]:
|
||||
row = self.layout.row(align=True)
|
||||
@@ -291,7 +293,7 @@ class BIM_PT_stair(bpy.types.Panel):
|
||||
|
||||
obj = context.active_object
|
||||
assert obj
|
||||
props = obj.BIMStairProperties
|
||||
props = tool.Model.get_stair_props(obj)
|
||||
|
||||
if StairData.data["pset_data"]:
|
||||
row = self.layout.row(align=True)
|
||||
@@ -404,7 +406,9 @@ class BIM_PT_window(bpy.types.Panel):
|
||||
if not WindowData.is_loaded:
|
||||
WindowData.load()
|
||||
|
||||
props = context.active_object.BIMWindowProperties
|
||||
obj = context.active_object
|
||||
assert obj
|
||||
props = tool.Model.get_window_props(obj)
|
||||
|
||||
if WindowData.data["pset_data"]:
|
||||
row = self.layout.row(align=True)
|
||||
@@ -594,7 +598,9 @@ class BIM_PT_railing(bpy.types.Panel):
|
||||
if not RailingData.is_loaded:
|
||||
RailingData.load()
|
||||
|
||||
props = context.active_object.BIMRailingProperties
|
||||
obj = context.active_object
|
||||
assert obj
|
||||
props = tool.Model.get_railing_props(obj)
|
||||
|
||||
if RailingData.data["pset_data"]:
|
||||
row = self.layout.row(align=True)
|
||||
@@ -659,7 +665,7 @@ class BIM_PT_roof(bpy.types.Panel):
|
||||
|
||||
obj = context.active_object
|
||||
assert obj
|
||||
props = obj.BIMRoofProperties
|
||||
props = tool.Model.get_roof_props(obj)
|
||||
|
||||
if RoofData.data["pset_data"]:
|
||||
row = self.layout.row(align=True)
|
||||
|
||||
@@ -41,8 +41,10 @@ V_ = tool.Blender.V_
|
||||
|
||||
def update_window_modifier_representation(context: bpy.types.Context) -> None:
|
||||
obj = context.active_object
|
||||
assert obj
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
props = obj.BIMWindowProperties
|
||||
assert element
|
||||
props = tool.Model.get_window_props(obj)
|
||||
ifc_file = tool.Ifc.get()
|
||||
si_conversion = ifcopenshell.util.unit.calculate_unit_scale(ifc_file)
|
||||
|
||||
@@ -258,7 +260,8 @@ def create_bm_window(
|
||||
|
||||
def update_window_modifier_bmesh(context: bpy.types.Context) -> None:
|
||||
obj = context.active_object
|
||||
props = obj.BIMWindowProperties
|
||||
assert obj
|
||||
props = tool.Model.get_window_props(obj)
|
||||
panel_schema = DEFAULT_PANEL_SCHEMAS[props.window_type]
|
||||
accumulated_height = [0] * len(panel_schema[0])
|
||||
built_panels = []
|
||||
@@ -447,8 +450,10 @@ class AddWindow(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
assert obj
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
props = obj.BIMWindowProperties
|
||||
assert element
|
||||
props = tool.Model.get_window_props(obj)
|
||||
|
||||
window_data = props.get_general_kwargs(convert_to_project_units=True)
|
||||
lining_props = props.get_lining_kwargs(convert_to_project_units=True)
|
||||
@@ -477,11 +482,13 @@ class CancelEditingWindow(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
assert obj
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
assert element
|
||||
data = json.loads(ifcopenshell.util.element.get_pset(element, "BBIM_Window", "Data"))
|
||||
data.update(data.pop("lining_properties"))
|
||||
data.update(data.pop("panel_properties"))
|
||||
props = obj.BIMWindowProperties
|
||||
props = tool.Model.get_window_props(obj)
|
||||
props.set_props_kwargs_from_ifc_data(data)
|
||||
|
||||
body = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
|
||||
@@ -506,8 +513,10 @@ class FinishEditingWindow(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
assert obj
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
props = obj.BIMWindowProperties
|
||||
assert element
|
||||
props = tool.Model.get_window_props(obj)
|
||||
|
||||
window_data = props.get_general_kwargs(convert_to_project_units=True)
|
||||
lining_props = props.get_lining_kwargs(convert_to_project_units=True)
|
||||
@@ -533,8 +542,10 @@ class EnableEditingWindow(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
props = obj.BIMWindowProperties
|
||||
assert obj
|
||||
props = tool.Model.get_window_props(obj)
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
assert element
|
||||
data = json.loads(ifcopenshell.util.element.get_pset(element, "BBIM_Window", "Data"))
|
||||
data.update(data.pop("lining_properties"))
|
||||
data.update(data.pop("panel_properties"))
|
||||
@@ -553,9 +564,11 @@ class RemoveWindow(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
props = obj.BIMWindowProperties
|
||||
assert obj
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
obj.BIMWindowProperties.is_editing = False
|
||||
assert element
|
||||
props = tool.Model.get_window_props(obj)
|
||||
props.is_editing = False
|
||||
|
||||
pset = tool.Pset.get_element_pset(element, "BBIM_Window")
|
||||
ifcopenshell.api.run("pset.remove_pset", tool.Ifc.get(), product=element, pset=pset)
|
||||
|
||||
@@ -1046,6 +1046,7 @@ class EditObjectUI:
|
||||
|
||||
@classmethod
|
||||
def draw_modes(cls, context: bpy.types.Context) -> None:
|
||||
obj = context.active_object
|
||||
ui_context = str(context.region.type)
|
||||
row = cls.layout.row(align=True)
|
||||
row.separator()
|
||||
@@ -1055,9 +1056,7 @@ class EditObjectUI:
|
||||
if len(context.selected_objects) == 1 and AuthoringData.data["has_extrusion"]:
|
||||
row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row
|
||||
add_layout_hotkey_operator(row, "Edit Profile", "S_E", "", ui_context)
|
||||
elif (
|
||||
tool.Model.is_parametric_railing_active() and not context.active_object.BIMRailingProperties.is_editing_path
|
||||
):
|
||||
elif tool.Model.is_parametric_railing_active() and not tool.Model.get_railing_props(obj).is_editing_path:
|
||||
row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row
|
||||
row.operator(
|
||||
"bim.enable_editing_railing_path",
|
||||
@@ -1208,12 +1207,12 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator):
|
||||
# and it might conflict with one of the conditions below
|
||||
if (
|
||||
tool.Model.is_parametric_railing_active()
|
||||
and not bpy.context.active_object.BIMRailingProperties.is_editing_path
|
||||
and not tool.Model.get_railing_props(active_object).is_editing_path
|
||||
):
|
||||
bpy.ops.bim.enable_editing_railing_path()
|
||||
return
|
||||
|
||||
elif tool.Model.is_parametric_roof_active() and not bpy.context.active_object.BIMRoofProperties.is_editing_path:
|
||||
elif tool.Model.is_parametric_roof_active() and not tool.Model.get_roof_props(active_object).is_editing_path:
|
||||
# undo the unselection done above because roof has no usage type
|
||||
bpy.ops.bim.enable_editing_roof_path()
|
||||
return
|
||||
|
||||
@@ -40,7 +40,7 @@ def update_relating_object(self, context):
|
||||
|
||||
if self.relating_object is None:
|
||||
return
|
||||
if not self.relating_object.BIMObjectProperties.ifc_definition_id:
|
||||
if not tool.Blender.get_ifc_definition_id(self.relating_object):
|
||||
context.window_manager.popup_menu(message, title="Invalid Element Selected", icon="INFO")
|
||||
self.relating_object = None
|
||||
|
||||
|
||||
@@ -32,14 +32,14 @@ class BIM_PT_nest(Panel):
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not context.active_object:
|
||||
if not (obj := context.active_object):
|
||||
return False
|
||||
props = context.active_object.BIMObjectProperties
|
||||
if not props.ifc_definition_id:
|
||||
ifc_id = tool.Blender.get_ifc_definition_id(obj)
|
||||
if not ifc_id:
|
||||
return False
|
||||
if not tool.Ifc.get_object_by_identifier(props.ifc_definition_id):
|
||||
if not tool.Ifc.get_object_by_identifier(ifc_id):
|
||||
return False
|
||||
if not tool.Ifc.get().by_id(props.ifc_definition_id).is_a("IfcObjectDefinition"):
|
||||
if not tool.Ifc.get().by_id(ifc_id).is_a("IfcObjectDefinition"):
|
||||
return False
|
||||
return True
|
||||
|
||||
@@ -55,7 +55,7 @@ class BIM_PT_nest(Panel):
|
||||
row.prop(props, "relating_object", text="")
|
||||
if props.relating_object:
|
||||
op = row.operator("bim.nest_assign_object", icon="CHECKMARK", text="")
|
||||
op.relating_object = props.relating_object.BIMObjectProperties.ifc_definition_id
|
||||
op.relating_object = tool.Blender.get_ifc_definition_id(props.relating_object)
|
||||
row.operator("bim.disable_editing_nest", icon="CANCEL", text="")
|
||||
else:
|
||||
row = layout.row(align=True)
|
||||
|
||||
@@ -2327,11 +2327,12 @@ class RefreshClippingPlanes(bpy.types.Operator):
|
||||
else:
|
||||
break
|
||||
|
||||
def is_moved(self, obj):
|
||||
if not obj.BIMObjectProperties.location_checksum:
|
||||
def is_moved(self, obj: bpy.types.Object) -> bool:
|
||||
props = tool.Blender.get_object_bim_props(obj)
|
||||
if not props.location_checksum:
|
||||
return True # Let's be conservative
|
||||
loc_check = np.frombuffer(eval(obj.BIMObjectProperties.location_checksum))
|
||||
rot_check = np.frombuffer(eval(obj.BIMObjectProperties.rotation_checksum))
|
||||
loc_check = np.frombuffer(eval(props.location_checksum))
|
||||
rot_check = np.frombuffer(eval(props.rotation_checksum))
|
||||
loc_real = np.array(obj.matrix_world.translation).flatten()
|
||||
rot_real = np.array(obj.matrix_world.to_3x3()).flatten()
|
||||
if np.allclose(loc_check, loc_real, atol=1e-4) and np.allclose(rot_check, rot_real, atol=1e-2):
|
||||
|
||||
@@ -351,10 +351,9 @@ class BIM_OT_add_edit_custom_property(bpy.types.Operator, tool.Ifc.Operator):
|
||||
props = context.scene.AddEditProperties
|
||||
|
||||
for obj in tool.Blender.get_selected_objects():
|
||||
ifc_definition_id = obj.BIMObjectProperties.ifc_definition_id
|
||||
if not ifc_definition_id:
|
||||
ifc_element = tool.Ifc.get_entity(obj)
|
||||
if not ifc_element:
|
||||
continue
|
||||
ifc_element = tool.Ifc.get().by_id(ifc_definition_id)
|
||||
|
||||
for prop in props:
|
||||
value = getattr(prop, prop.get_value_name())
|
||||
@@ -406,23 +405,19 @@ class BIM_OT_bulk_remove_psets(bpy.types.Operator, tool.Ifc.Operator):
|
||||
props = context.scene.DeletePsets
|
||||
|
||||
for obj in tool.Blender.get_selected_objects():
|
||||
ifc_definition_id = obj.BIMObjectProperties.ifc_definition_id
|
||||
if not ifc_definition_id:
|
||||
ifc_element = tool.Ifc.get_entity(obj)
|
||||
if not ifc_element:
|
||||
continue
|
||||
ifc_element = tool.Ifc.get().by_id(ifc_definition_id)
|
||||
psets = ifcopenshell.util.element.get_psets(ifc_element)
|
||||
|
||||
for prop in props:
|
||||
pset = prop.pset_name
|
||||
if pset in psets:
|
||||
try:
|
||||
ifcopenshell.api.run(
|
||||
"pset.remove_pset",
|
||||
ifcopenshell.api.pset.remove_pset(
|
||||
self.file,
|
||||
**{
|
||||
"product": self.file.by_id(ifc_definition_id),
|
||||
"pset": self.file.by_id(psets[pset]["id"]),
|
||||
},
|
||||
product=ifc_element,
|
||||
pset=self.file.by_id(psets[pset]["id"]),
|
||||
)
|
||||
except KeyError:
|
||||
pass # Sometimes the pset id is not found, I'm not sure why this happens though. - vulevukusej
|
||||
|
||||
@@ -241,12 +241,12 @@ class BIM_PT_object_psets(Panel):
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not context.active_object:
|
||||
if not (obj := context.active_object):
|
||||
return False
|
||||
props = context.active_object.BIMObjectProperties
|
||||
if not props.ifc_definition_id:
|
||||
ifc_id = tool.Blender.get_ifc_definition_id(obj)
|
||||
if not ifc_id:
|
||||
return False
|
||||
if not tool.Ifc.get_object_by_identifier(props.ifc_definition_id):
|
||||
if not tool.Ifc.get_object_by_identifier(ifc_id):
|
||||
return False
|
||||
return True
|
||||
|
||||
@@ -319,12 +319,12 @@ class BIM_PT_object_qtos(Panel):
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not context.active_object:
|
||||
if not (obj := context.active_object):
|
||||
return False
|
||||
props = context.active_object.BIMObjectProperties
|
||||
if not props.ifc_definition_id:
|
||||
ifc_id = tool.Blender.get_ifc_definition_id(obj)
|
||||
if not ifc_id:
|
||||
return False
|
||||
if not tool.Ifc.get_object_by_identifier(props.ifc_definition_id):
|
||||
if not tool.Ifc.get_object_by_identifier(ifc_id):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
@@ -648,7 +648,8 @@ def get_opening_area(
|
||||
"""
|
||||
total_opening_area = 0
|
||||
ifc = tool.Ifc.get()
|
||||
ifc_element = ifc.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
ifc_element = tool.Ifc.get_entity(obj)
|
||||
assert ifc_element
|
||||
if len(openings := ifc_element.HasOpenings) != 0:
|
||||
for opening in openings:
|
||||
opening_id = opening.RelatedOpeningElement.GlobalId
|
||||
@@ -887,7 +888,7 @@ def get_OBB_object(obj: bpy.types.Object) -> bpy.types.Object:
|
||||
:param blender-object obj: Blender Object
|
||||
:return blender-object: OBB of the Object
|
||||
"""
|
||||
ifc_id = obj.BIMObjectProperties.ifc_definition_id
|
||||
ifc_id = tool.Blender.get_ifc_definition_id(obj)
|
||||
bbox = obj.bound_box
|
||||
# matrix transformation to go from obj coordinates to world coordinates:
|
||||
obb = [Vector(v) for v in bbox]
|
||||
@@ -929,7 +930,7 @@ def get_AABB_object(obj: bpy.types.Object) -> bpy.types.Object:
|
||||
:param blender-object obj: Blender Object
|
||||
:return blender-object: AABB of the Object
|
||||
"""
|
||||
ifc_id = obj.BIMObjectProperties.ifc_definition_id
|
||||
ifc_id = tool.Blender.get_ifc_definition_id(obj)
|
||||
aabb_mesh = bpy.data.meshes.new(f"OBB_{ifc_id}")
|
||||
|
||||
x = [v.co.x for v in obj.data.vertices]
|
||||
@@ -994,7 +995,7 @@ def get_bisected_obj(
|
||||
:param tuple(x,y,z) plane_no_neg: Tuple describing the normal vector of the lower bisection plane. Example: (0,0,-1)
|
||||
:return _type_: _description_
|
||||
"""
|
||||
ifc_id = obj.BIMObjectProperties.ifc_definition_id
|
||||
ifc_id = tool.Blender.get_ifc_definition_id(obj)
|
||||
|
||||
bis_obj = obj.copy()
|
||||
bis_obj.data = obj.data.copy()
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
import bpy
|
||||
import bmesh
|
||||
import bonsai.tool as tool
|
||||
from typing import Callable
|
||||
|
||||
|
||||
@@ -86,7 +87,7 @@ def calculate_formwork_area(objs: list[bpy.types.Object], context: bpy.types.Con
|
||||
bpy.ops.object.modifier_apply(modifier="Boolean")
|
||||
|
||||
copied_obj.name = "Formwork"
|
||||
copied_obj.BIMObjectProperties.ifc_definition_id = 0
|
||||
tool.Blender.get_object_bim_props(copied_obj).ifc_definition_id = 0
|
||||
modifier = copied_obj.modifiers.new("Formwork", "REMESH")
|
||||
assert isinstance(modifier, bpy.types.RemeshModifier)
|
||||
modifier.mode = "SHARP"
|
||||
|
||||
@@ -48,7 +48,8 @@ class EnableReassignClass(bpy.types.Operator):
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
assert element
|
||||
ifc_class = element.is_a()
|
||||
context.active_object.BIMObjectProperties.is_reassigning_class = True
|
||||
props = tool.Blender.get_object_bim_props(obj)
|
||||
props.is_reassigning_class = True
|
||||
ifc_products = tool.Root.get_ifc_products()
|
||||
schema = tool.Ifc.schema()
|
||||
declaration = schema.declaration_by_name(ifc_class)
|
||||
@@ -58,10 +59,10 @@ class EnableReassignClass(bpy.types.Operator):
|
||||
break
|
||||
else:
|
||||
self.report({"ERROR"}, f"Couldn't find matching IFC product for the selected object: '{element}'.")
|
||||
obj.BIMObjectProperties.is_reassigning_class = False
|
||||
props.is_reassigning_class = False
|
||||
return {"CANCELLED"}
|
||||
|
||||
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
element = self.file.by_id(tool.Blender.get_ifc_definition_id(obj))
|
||||
rprops.ifc_class = element.is_a()
|
||||
rprops.relating_class_object = None
|
||||
if hasattr(element, "PredefinedType"):
|
||||
@@ -78,7 +79,8 @@ class DisableReassignClass(bpy.types.Operator):
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
context.active_object.BIMObjectProperties.is_reassigning_class = False
|
||||
props = tool.Blender.get_object_bim_props(context.active_object)
|
||||
props.is_reassigning_class = False
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -127,7 +129,8 @@ class ReassignClass(bpy.types.Operator, tool.Ifc.Operator):
|
||||
)
|
||||
return {"CANCELLED"}
|
||||
|
||||
obj.BIMObjectProperties.is_reassigning_class = False
|
||||
props = tool.Blender.get_object_bim_props(obj)
|
||||
props.is_reassigning_class = False
|
||||
if element.is_a("IfcTypeObject"):
|
||||
elements_to_reassign[element] = ifc_class
|
||||
elements_to_update.update(ifcopenshell.util.element.get_types(element))
|
||||
|
||||
@@ -43,7 +43,9 @@ class BIM_PT_class(Panel):
|
||||
def draw(self, context):
|
||||
if not IfcClassData.is_loaded:
|
||||
IfcClassData.load()
|
||||
props = context.active_object.BIMObjectProperties
|
||||
obj = context.active_object
|
||||
assert obj
|
||||
props = tool.Blender.get_object_bim_props(obj)
|
||||
rprops = tool.Root.get_root_props()
|
||||
if props.ifc_definition_id:
|
||||
if not IfcClassData.data["has_entity"]:
|
||||
|
||||
@@ -1449,15 +1449,17 @@ class LoadProductTasks(bpy.types.Operator):
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not tool.Ifc.get() or not (obj := context.active_object) or not (obj.BIMObjectProperties.ifc_definition_id):
|
||||
if not tool.Ifc.get() or not (obj := context.active_object) or not (tool.Blender.get_ifc_definition_id(obj)):
|
||||
cls.poll_message_set("No IFC object is active.")
|
||||
return False
|
||||
return True
|
||||
|
||||
def execute(self, context):
|
||||
result = core.load_product_related_tasks(
|
||||
tool.Sequence, product=tool.Ifc.get().by_id(context.active_object.BIMObjectProperties.ifc_definition_id)
|
||||
)
|
||||
obj = context.active_object
|
||||
assert obj
|
||||
product = tool.Ifc.get_entity(obj)
|
||||
assert product
|
||||
result = core.load_product_related_tasks(tool.Sequence, product=product)
|
||||
if isinstance(result, str):
|
||||
self.report({"INFO"}, result)
|
||||
else:
|
||||
|
||||
@@ -271,10 +271,10 @@ def update_sort_reversed(self, context):
|
||||
|
||||
|
||||
def update_filter_by_active_schedule(self, context):
|
||||
if context.active_object:
|
||||
core.load_product_related_tasks(
|
||||
tool.Sequence, product=tool.Ifc.get().by_id(context.active_object.BIMObjectProperties.ifc_definition_id)
|
||||
)
|
||||
if obj := context.active_object:
|
||||
product = tool.Ifc.get_entity(obj)
|
||||
assert product
|
||||
core.load_product_related_tasks(tool.Sequence, product=product)
|
||||
|
||||
|
||||
def switch_options(self, context):
|
||||
|
||||
@@ -75,11 +75,13 @@ class AddStructuralMemberConnection(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
oprops = obj.BIMObjectProperties
|
||||
assert obj
|
||||
oprops = tool.Blender.get_object_bim_props(obj)
|
||||
props = obj.BIMStructuralProperties
|
||||
file = tool.Ifc.get()
|
||||
related_structural_connection = file.by_id(oprops.ifc_definition_id)
|
||||
relating_structural_member = file.by_id(props.relating_structural_member.BIMObjectProperties.ifc_definition_id)
|
||||
relating_structural_member = tool.Ifc.get_entity(props.relating_structural_member)
|
||||
assert relating_structural_member
|
||||
if not relating_structural_member.is_a("IfcStructuralMember"):
|
||||
return {"FINISHED"}
|
||||
ifcopenshell.api.structural.add_structural_member_connection(
|
||||
@@ -99,7 +101,6 @@ class EnableEditingStructuralConnectionCondition(bpy.types.Operator):
|
||||
|
||||
def execute(self, context):
|
||||
obj = context.active_object
|
||||
oprops = obj.BIMObjectProperties
|
||||
props = obj.BIMStructuralProperties
|
||||
props.active_connects_structural_member = self.connects_structural_member
|
||||
return {"FINISHED"}
|
||||
@@ -350,7 +351,8 @@ class EnableEditingStructuralItemAxis(bpy.types.Operator):
|
||||
|
||||
def execute(self, context):
|
||||
obj = context.active_object
|
||||
oprops = obj.BIMObjectProperties
|
||||
assert obj
|
||||
oprops = tool.Blender.get_object_bim_props(obj)
|
||||
props = obj.BIMStructuralProperties
|
||||
|
||||
self.file = tool.Ifc.get()
|
||||
@@ -403,7 +405,8 @@ class EditStructuralItemAxis(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
oprops = obj.BIMObjectProperties
|
||||
assert obj
|
||||
oprops = tool.Blender.get_object_bim_props(obj)
|
||||
props = obj.BIMStructuralProperties
|
||||
relative_matrix = props.axis_empty.matrix_world @ obj.matrix_world.inverted()
|
||||
z_axis = relative_matrix.col[2][0:3]
|
||||
@@ -425,11 +428,12 @@ class EnableEditingStructuralConnectionCS(bpy.types.Operator):
|
||||
|
||||
def execute(self, context):
|
||||
obj = context.active_object
|
||||
oprops = obj.BIMObjectProperties
|
||||
assert obj
|
||||
props = obj.BIMStructuralProperties
|
||||
|
||||
self.file = tool.Ifc.get()
|
||||
item = self.file.by_id(oprops.ifc_definition_id)
|
||||
item = tool.Ifc.get_entity(obj)
|
||||
assert item
|
||||
|
||||
location = obj.data.vertices[0].co
|
||||
empty = bpy.data.objects.new("Item Connection CS", None)
|
||||
@@ -491,16 +495,17 @@ class EditStructuralConnectionCS(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
oprops = obj.BIMObjectProperties
|
||||
assert obj
|
||||
item = tool.Ifc.get_entity(obj)
|
||||
assert item
|
||||
props = obj.BIMStructuralProperties
|
||||
relative_matrix = props.ccs_empty.matrix_world @ obj.matrix_world.inverted()
|
||||
x_axis = relative_matrix.col[0][0:3]
|
||||
z_axis = relative_matrix.col[2][0:3]
|
||||
self.file = tool.Ifc.get()
|
||||
ifcopenshell.api.run(
|
||||
"structural.edit_structural_connection_cs",
|
||||
ifcopenshell.api.structural.edit_structural_connection_cs(
|
||||
self.file,
|
||||
structural_item=self.file.by_id(oprops.ifc_definition_id),
|
||||
structural_item=item,
|
||||
axis=z_axis,
|
||||
ref_direction=x_axis,
|
||||
)
|
||||
@@ -695,9 +700,9 @@ class AddStructuralActivity(bpy.types.Operator, tool.Ifc.Operator):
|
||||
self.props = context.scene.BIMStructuralProperties
|
||||
self.file = tool.Ifc.get()
|
||||
for obj in context.selected_objects:
|
||||
if not obj.BIMObjectProperties.ifc_definition_id:
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
if not element:
|
||||
continue
|
||||
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
applied_load_class = self.props.applicable_structural_load_types
|
||||
|
||||
allowed_load_classes = {
|
||||
|
||||
@@ -85,14 +85,14 @@ class BIM_PT_structural_boundary_conditions(Panel):
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not context.active_object:
|
||||
if not (obj := context.active_object):
|
||||
return False
|
||||
props = context.active_object.BIMObjectProperties
|
||||
if not props.ifc_definition_id:
|
||||
ifc_id = tool.Blender.get_ifc_definition_id(obj)
|
||||
if not ifc_id:
|
||||
return False
|
||||
if not tool.Ifc.get_object_by_identifier(props.ifc_definition_id):
|
||||
if not (tool.Ifc.get_object_by_identifier(ifc_id)):
|
||||
return False
|
||||
if not tool.Ifc.get().by_id(props.ifc_definition_id).is_a("IfcStructuralConnection"):
|
||||
if not tool.Ifc.get().by_id(ifc_id).is_a("IfcStructuralConnection"):
|
||||
return False
|
||||
return True
|
||||
|
||||
@@ -120,14 +120,14 @@ class BIM_PT_connected_structural_members(Panel):
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not context.active_object:
|
||||
if not (obj := context.active_object):
|
||||
return False
|
||||
props = context.active_object.BIMObjectProperties
|
||||
if not props.ifc_definition_id:
|
||||
ifc_id = tool.Blender.get_ifc_definition_id(obj)
|
||||
if not ifc_id:
|
||||
return False
|
||||
if not tool.Ifc.get_object_by_identifier(props.ifc_definition_id):
|
||||
if not (tool.Ifc.get_object_by_identifier(ifc_id)):
|
||||
return False
|
||||
if not tool.Ifc.get().by_id(props.ifc_definition_id).is_a("IfcStructuralConnection"):
|
||||
if not tool.Ifc.get().by_id(ifc_id).is_a("IfcStructuralConnection"):
|
||||
return False
|
||||
return True
|
||||
|
||||
@@ -173,14 +173,14 @@ class BIM_PT_structural_member(Panel):
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not context.active_object:
|
||||
if not (obj := context.active_object):
|
||||
return False
|
||||
props = context.active_object.BIMObjectProperties
|
||||
if not props.ifc_definition_id:
|
||||
ifc_id = tool.Blender.get_ifc_definition_id(obj)
|
||||
if not ifc_id:
|
||||
return False
|
||||
if not tool.Ifc.get_object_by_identifier(props.ifc_definition_id):
|
||||
if not tool.Ifc.get_object_by_identifier(ifc_id):
|
||||
return False
|
||||
if not tool.Ifc.get().by_id(props.ifc_definition_id).is_a("IfcStructuralMember"):
|
||||
if not tool.Ifc.get().by_id(ifc_id).is_a("IfcStructuralMember"):
|
||||
return False
|
||||
return True
|
||||
|
||||
@@ -216,14 +216,14 @@ class BIM_PT_structural_connection(Panel):
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not context.active_object:
|
||||
if not (obj := context.active_object):
|
||||
return False
|
||||
props = context.active_object.BIMObjectProperties
|
||||
if not props.ifc_definition_id:
|
||||
ifc_id = tool.Blender.get_ifc_definition_id(obj)
|
||||
if not ifc_id:
|
||||
return False
|
||||
if not tool.Ifc.get_object_by_identifier(props.ifc_definition_id):
|
||||
if not tool.Ifc.get_object_by_identifier(ifc_id):
|
||||
return False
|
||||
if not tool.Ifc.get().by_id(props.ifc_definition_id).is_a("IfcStructuralConnection"):
|
||||
if not tool.Ifc.get().by_id(ifc_id).is_a("IfcStructuralConnection"):
|
||||
return False
|
||||
return True
|
||||
|
||||
@@ -315,7 +315,6 @@ class BIM_UL_structural_analysis_models(UIList):
|
||||
row.label(text=item.name)
|
||||
|
||||
if context.active_object:
|
||||
oprops = context.active_object.BIMObjectProperties
|
||||
if item.ifc_definition_id in StructuralAnalysisModelsData.data["active_model_ids"]:
|
||||
op = row.operator(
|
||||
"bim.unassign_structural_analysis_model", text="", icon="KEYFRAME_HLT", emboss=False
|
||||
|
||||
@@ -187,9 +187,8 @@ class BIM_PT_ports(Panel):
|
||||
if connected_obj_name:
|
||||
connected_obj = bpy.data.objects[connected_obj_name]
|
||||
cols[3].operator("bim.disconnect_port", text="", icon="UNLINKED").element_id = port.id()
|
||||
cols[4].operator("bim.select_entity", text="", icon="RESTRICT_SELECT_OFF").ifc_id = (
|
||||
connected_obj.BIMObjectProperties.ifc_definition_id
|
||||
)
|
||||
ifc_id = tool.Blender.get_ifc_definition_id(connected_obj)
|
||||
cols[4].operator("bim.select_entity", text="", icon="RESTRICT_SELECT_OFF").ifc_id = ifc_id
|
||||
cols[5].label(text=connected_obj_name)
|
||||
else:
|
||||
cols[3].label(text="", icon="UNLINKED")
|
||||
@@ -244,9 +243,8 @@ class BIM_PT_port(Panel):
|
||||
relating_object = bpy.data.objects[relating_object_name]
|
||||
row.label(text="Port located on:")
|
||||
row.label(text=relating_object_name)
|
||||
row.operator("bim.select_entity", text="", icon="RESTRICT_SELECT_OFF").ifc_id = (
|
||||
relating_object.BIMObjectProperties.ifc_definition_id
|
||||
)
|
||||
ifc_id = tool.Blender.get_ifc_definition_id(relating_object)
|
||||
row.operator("bim.select_entity", text="", icon="RESTRICT_SELECT_OFF").ifc_id = ifc_id
|
||||
|
||||
# object connected to the port
|
||||
row = layout.row(align=True)
|
||||
@@ -255,9 +253,8 @@ class BIM_PT_port(Panel):
|
||||
connected_object = bpy.data.objects[connected_object_name]
|
||||
row.label(text="Port connected to:")
|
||||
row.label(text=connected_object_name)
|
||||
row.operator("bim.select_entity", text="", icon="RESTRICT_SELECT_OFF").ifc_id = (
|
||||
connected_object.BIMObjectProperties.ifc_definition_id
|
||||
)
|
||||
ifc_id = tool.Blender.get_ifc_definition_id(connected_object)
|
||||
row.operator("bim.select_entity", text="", icon="RESTRICT_SELECT_OFF").ifc_id = ifc_id
|
||||
else:
|
||||
row.label(text="Port is not connected to any element")
|
||||
|
||||
@@ -304,9 +301,8 @@ class BIM_PT_flow_controls(Panel):
|
||||
op.flow_control = control_id
|
||||
op.flow_element = flow_element_id
|
||||
op.assign = False
|
||||
row.operator("bim.select_entity", text="", icon="RESTRICT_SELECT_OFF").ifc_id = (
|
||||
displayed_object.BIMObjectProperties.ifc_definition_id
|
||||
)
|
||||
ifc_id = tool.Blender.get_ifc_definition_id(displayed_object)
|
||||
row.operator("bim.select_entity", text="", icon="RESTRICT_SELECT_OFF").ifc_id = ifc_id
|
||||
row.label(text=f"{displayed_object_name}")
|
||||
|
||||
element = tool.Ifc.get_entity(context.active_object)
|
||||
|
||||
@@ -150,7 +150,8 @@ class SelectRequirement(bpy.types.Operator):
|
||||
area.spaces[0].shading.show_xray = True
|
||||
failed_ids = [e["id"] for e in failed_entities]
|
||||
for obj in context.scene.objects:
|
||||
if obj.BIMObjectProperties.ifc_definition_id in failed_ids:
|
||||
ifc_id = tool.Blender.get_ifc_definition_id(obj)
|
||||
if ifc_id in failed_ids:
|
||||
obj.color = (1, 0, 0, 1)
|
||||
else:
|
||||
obj.color = (1, 1, 1, 1)
|
||||
@@ -175,7 +176,8 @@ class SelectFailedEntities(bpy.types.Operator):
|
||||
|
||||
failed_ids = [e["id"] for e in failed_entities]
|
||||
for obj in context.scene.objects:
|
||||
if obj.BIMObjectProperties.ifc_definition_id in failed_ids:
|
||||
ifc_id = tool.Blender.get_ifc_definition_id(obj)
|
||||
if ifc_id in failed_ids:
|
||||
obj.select_set(True)
|
||||
else:
|
||||
obj.select_set(False)
|
||||
|
||||
@@ -337,5 +337,5 @@ class DuplicateType(bpy.types.Operator, tool.Ifc.Operator):
|
||||
# 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):
|
||||
props.ifc_class = new.is_a()
|
||||
props.relating_type_id = str(new_obj.BIMObjectProperties.ifc_definition_id)
|
||||
props.relating_type_id = str(tool.Blender.get_ifc_definition_id(new_obj))
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -46,7 +46,9 @@ class BIM_PT_type(Panel):
|
||||
if not TypeData.is_loaded:
|
||||
TypeData.load()
|
||||
|
||||
oprops = context.active_object.BIMObjectProperties
|
||||
obj = context.active_object
|
||||
assert obj
|
||||
oprops = tool.Blender.get_object_bim_props(obj)
|
||||
|
||||
if TypeData.data["is_product"]:
|
||||
self.draw_product_ui(context)
|
||||
@@ -54,21 +56,19 @@ class BIM_PT_type(Panel):
|
||||
self.draw_type_ui(context)
|
||||
|
||||
def draw_type_ui(self, context):
|
||||
props = context.active_object.BIMTypeProperties
|
||||
oprops = context.active_object.BIMObjectProperties
|
||||
oprops = tool.Blender.get_object_bim_props(context.active_object)
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text=f"{TypeData.data['total_instances']} Typed Objects")
|
||||
select_type_objects_row = row.row(align=True)
|
||||
select_type_objects_row.operator("bim.select_type_objects", icon="RESTRICT_SELECT_OFF", text="")
|
||||
select_type_objects_row.enabled = int(TypeData.data["total_instances"]) > 0
|
||||
op = row.operator("bim.duplicate_type", icon="DUPLICATE", text="")
|
||||
op.element = context.active_object.BIMObjectProperties.ifc_definition_id
|
||||
op.element = oprops.ifc_definition_id
|
||||
row.operator("bim.auto_rename_occurrences", icon="ITALIC", text="")
|
||||
|
||||
def draw_product_ui(self, context):
|
||||
layout = self.layout
|
||||
props = context.active_object.BIMTypeProperties
|
||||
oprops = context.active_object.BIMObjectProperties
|
||||
|
||||
if props.is_editing_type:
|
||||
row = layout.row(align=True)
|
||||
|
||||
@@ -215,8 +215,8 @@ class AddFilling(bpy.types.Operator, tool.Ifc.Operator):
|
||||
if opening is None:
|
||||
return {"FINISHED"}
|
||||
self.file = tool.Ifc.get()
|
||||
element_id = obj.BIMObjectProperties.ifc_definition_id
|
||||
opening_id = opening.BIMObjectProperties.ifc_definition_id
|
||||
element_id = tool.Blender.get_object_bim_props(obj).ifc_definition_id
|
||||
opening_id = tool.Blender.get_object_bim_props(opening).ifc_definition_id
|
||||
if not element_id or not opening_id or element_id == opening_id:
|
||||
return {"FINISHED"}
|
||||
ifcopenshell.api.run(
|
||||
|
||||
@@ -52,8 +52,6 @@ class BIM_PT_voids(Panel):
|
||||
if not VoidsData.is_loaded:
|
||||
VoidsData.load()
|
||||
|
||||
props = context.active_object.BIMObjectProperties
|
||||
|
||||
if len(context.selected_objects) >= 2:
|
||||
row = self.layout.row(align=True)
|
||||
op = row.operator("bim.add_opening", icon="ADD", text="Add Opening")
|
||||
|
||||
@@ -857,7 +857,9 @@ class FetchObjectPassport(bpy.types.Operator):
|
||||
|
||||
def execute(self, context):
|
||||
# TODO: this is dead code, awaiting reimplementation. See #1222.
|
||||
for reference in context.active_object.BIMObjectProperties.document_references:
|
||||
obj = context.active_object
|
||||
props = tool.Blender.get_object_bim_props(obj)
|
||||
for reference in props.document_references:
|
||||
bim_props = tool.Blender.get_bim_props()
|
||||
reference = bim_props.document_references[reference.name]
|
||||
if reference.location[-6:] == ".blend":
|
||||
|
||||
@@ -41,7 +41,7 @@ from typing import Any, Optional, Union, Literal, Iterable, Callable, TypeVar, G
|
||||
from typing_extensions import assert_never
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bonsai.bim.prop import BIMProperties
|
||||
from bonsai.bim.prop import BIMProperties, BIMObjectProperties
|
||||
|
||||
|
||||
VIEWPORT_ATTRIBUTES = [
|
||||
@@ -192,7 +192,8 @@ class Blender(bonsai.core.tool.Blender):
|
||||
if context is None:
|
||||
context = bpy.context
|
||||
if obj_type == "Object":
|
||||
return bpy.data.objects.get(obj).BIMObjectProperties.ifc_definition_id
|
||||
props = tool.Blender.get_object_bim_props(bpy.data.objects[obj])
|
||||
return props.ifc_definition_id
|
||||
elif obj_type == "Material":
|
||||
props = tool.Material.get_material_props()
|
||||
return props.materials[props.active_material_index].ifc_definition_id
|
||||
@@ -221,7 +222,8 @@ class Blender(bonsai.core.tool.Blender):
|
||||
|
||||
@classmethod
|
||||
def is_ifc_object(cls, obj: bpy.types.Object) -> bool:
|
||||
return bool(obj.BIMObjectProperties.ifc_definition_id)
|
||||
props = tool.Blender.get_object_bim_props(obj)
|
||||
return bool(props.ifc_definition_id)
|
||||
|
||||
@classmethod
|
||||
def is_ifc_class_active(cls, ifc_class: str) -> bool:
|
||||
@@ -880,7 +882,7 @@ class Blender(bonsai.core.tool.Blender):
|
||||
@classmethod
|
||||
def get_layer_collection(cls, collection: bpy.types.Collection) -> Union[bpy.types.LayerCollection, None]:
|
||||
project = tool.Ifc.get_object(tool.Ifc.get().by_type("IfcProject")[0])
|
||||
project_collection = project.BIMObjectProperties.collection
|
||||
project_collection = tool.Blender.get_object_bim_props(project).collection
|
||||
for layer_collection in bpy.context.view_layer.layer_collection.children:
|
||||
if layer_collection.collection == project_collection:
|
||||
for layer_collection2 in layer_collection.children:
|
||||
@@ -1019,23 +1021,28 @@ class Blender(bonsai.core.tool.Blender):
|
||||
|
||||
@classmethod
|
||||
def is_editing_railing_path(cls, obj: bpy.types.Object):
|
||||
return obj.BIMRailingProperties.is_editing_path
|
||||
props = tool.Model.get_railing_props(obj)
|
||||
return props.is_editing_path
|
||||
|
||||
@classmethod
|
||||
def is_editing_roof_path(cls, obj: bpy.types.Object) -> bool:
|
||||
return obj.BIMRoofProperties.is_editing_path
|
||||
props = tool.Model.get_roof_props(obj)
|
||||
return props.is_editing_path
|
||||
|
||||
@classmethod
|
||||
def is_editing_railing_parameters(cls, obj: bpy.types.Object) -> bool:
|
||||
return obj.BIMRailingProperties.is_editing
|
||||
props = tool.Model.get_railing_props(obj)
|
||||
return props.is_editing
|
||||
|
||||
@classmethod
|
||||
def is_editing_roof_parameters(cls, obj: bpy.types.Object) -> bool:
|
||||
return obj.BIMRoofProperties.is_editing
|
||||
props = tool.Model.get_roof_props(obj)
|
||||
return props.is_editing
|
||||
|
||||
@classmethod
|
||||
def is_editing_window_parameters(cls, obj: bpy.types.Object) -> bool:
|
||||
return obj.BIMWindowProperties.is_editing
|
||||
props = tool.Model.get_window_props(obj)
|
||||
return props.is_editing
|
||||
|
||||
@classmethod
|
||||
def is_editing_door_parameters(cls, obj: bpy.types.Object) -> bool:
|
||||
@@ -1044,7 +1051,8 @@ class Blender(bonsai.core.tool.Blender):
|
||||
|
||||
@classmethod
|
||||
def is_editing_stair_parameters(cls, obj: bpy.types.Object) -> bool:
|
||||
return obj.BIMStairProperties.is_editing
|
||||
props = tool.Model.get_stair_props(obj)
|
||||
return props.is_editing
|
||||
|
||||
@classmethod
|
||||
def is_modifier_with_non_editable_path(cls, element: entity_instance) -> bool:
|
||||
@@ -1545,3 +1553,11 @@ class Blender(bonsai.core.tool.Blender):
|
||||
if scene is None:
|
||||
scene = bpy.context.scene
|
||||
return scene.BIMProperties
|
||||
|
||||
@classmethod
|
||||
def get_object_bim_props(cls, obj: bpy.types.Object) -> BIMObjectProperties:
|
||||
return obj.BIMObjectProperties
|
||||
|
||||
@classmethod
|
||||
def get_ifc_definition_id(cls, obj: bpy.types.Object) -> int:
|
||||
return tool.Blender.get_object_bim_props(obj).ifc_definition_id
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
# - An arc is reconstructed from 3 points instead of a full circle
|
||||
# - You can now derive the center from an arc without generating geometry
|
||||
|
||||
|
||||
from __future__ import annotations
|
||||
import sys
|
||||
import bpy
|
||||
import math
|
||||
@@ -36,12 +36,20 @@ import bmesh
|
||||
import mathutils.geometry
|
||||
from mathutils import Vector, Matrix, geometry
|
||||
import itertools
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bonsai.bim.module.cad.prop import BIMCadProperties
|
||||
|
||||
|
||||
VTX_PRECISION = 1.0e-5
|
||||
|
||||
|
||||
class Cad:
|
||||
@classmethod
|
||||
def get_cad_props(cls) -> BIMCadProperties:
|
||||
return bpy.context.scene.BIMCadProperties
|
||||
|
||||
@classmethod
|
||||
def is_point_on_edge(cls, p, edge):
|
||||
"""
|
||||
|
||||
@@ -29,7 +29,7 @@ class Collector(bonsai.core.tool.Collector):
|
||||
"""Links an object to an appropriate Blender collection."""
|
||||
if should_clean_users_collection:
|
||||
for users_collection in obj.users_collection:
|
||||
if obj.BIMObjectProperties.collection == users_collection:
|
||||
if tool.Blender.get_object_bim_props(obj).collection == users_collection:
|
||||
continue
|
||||
# Users are free to use extra collections for their own
|
||||
# purposes except for the reserved keyword "Ifc" and
|
||||
@@ -87,7 +87,7 @@ class Collector(bonsai.core.tool.Collector):
|
||||
if collection := cls._create_own_collection(obj):
|
||||
cls.link_collection_object_safe(collection, obj)
|
||||
project_obj = tool.Ifc.get_object(tool.Ifc.get().by_type("IfcProject")[0])
|
||||
cls.link_collection_child_safe(project_obj.BIMObjectProperties.collection, collection)
|
||||
cls.link_collection_child_safe(tool.Blender.get_object_bim_props(project_obj).collection, collection)
|
||||
elif (
|
||||
tool.Ifc.get_schema() != "IFC2X3"
|
||||
and element.is_a("IfcSpatialElement")
|
||||
@@ -98,21 +98,21 @@ class Collector(bonsai.core.tool.Collector):
|
||||
if collection := cls._create_own_collection(obj):
|
||||
cls.link_collection_object_safe(collection, obj)
|
||||
project_obj = tool.Ifc.get_object(tool.Ifc.get().by_type("IfcProject")[0])
|
||||
cls.link_collection_child_safe(project_obj.BIMObjectProperties.collection, collection)
|
||||
cls.link_collection_child_safe(tool.Blender.get_object_bim_props(project_obj).collection, collection)
|
||||
elif element.is_a("IfcAnnotation") and element.ObjectType == "DRAWING":
|
||||
if collection := cls._create_own_collection(obj):
|
||||
cls.link_collection_object_safe(collection, obj)
|
||||
project_obj = tool.Ifc.get_object(tool.Ifc.get().by_type("IfcProject")[0])
|
||||
cls.link_collection_child_safe(project_obj.BIMObjectProperties.collection, collection)
|
||||
cls.link_collection_child_safe(tool.Blender.get_object_bim_props(project_obj).collection, collection)
|
||||
elif element.is_a("IfcAnnotation") and (drawing_obj := cls.get_annotation_drawing_obj(element)):
|
||||
cls.link_collection_object_safe(drawing_obj.BIMObjectProperties.collection, obj)
|
||||
cls.link_collection_object_safe(tool.Blender.get_object_bim_props(drawing_obj).collection, obj)
|
||||
elif container := ifcopenshell.util.element.get_container(element):
|
||||
while container.is_a("IfcSpace"):
|
||||
container = ifcopenshell.util.element.get_aggregate(container)
|
||||
container_obj = tool.Ifc.get_object(container)
|
||||
if not (collection := container_obj.BIMObjectProperties.collection):
|
||||
if not (collection := tool.Blender.get_object_bim_props(container_obj).collection):
|
||||
cls.assign(container_obj)
|
||||
collection = container_obj.BIMObjectProperties.collection
|
||||
collection = tool.Blender.get_object_bim_props(container_obj).collection
|
||||
cls.link_collection_object_safe(collection, obj)
|
||||
else:
|
||||
collection = cls._create_project_child_collection("Unsorted")
|
||||
@@ -128,7 +128,7 @@ class Collector(bonsai.core.tool.Collector):
|
||||
return collection
|
||||
collection = bpy.data.collections.new(name)
|
||||
project_obj = tool.Ifc.get_object(tool.Ifc.get().by_type("IfcProject")[0])
|
||||
project_obj.BIMObjectProperties.collection.children.link(collection)
|
||||
tool.Blender.get_object_bim_props(project_obj).collection.children.link(collection)
|
||||
if layer_collection := tool.Blender.get_layer_collection(collection):
|
||||
cls.set_layer_collection_visibility(layer_collection)
|
||||
return collection
|
||||
@@ -136,11 +136,12 @@ class Collector(bonsai.core.tool.Collector):
|
||||
@classmethod
|
||||
def _create_own_collection(cls, obj: bpy.types.Object) -> bpy.types.Collection:
|
||||
"""get or create own collection for the element"""
|
||||
if obj.BIMObjectProperties.collection:
|
||||
obj.BIMObjectProperties.collection.name = obj.name
|
||||
props = tool.Blender.get_object_bim_props(obj)
|
||||
if props.collection:
|
||||
props.collection.name = obj.name
|
||||
return
|
||||
collection = bpy.data.collections.new(obj.name)
|
||||
obj.BIMObjectProperties.collection = collection
|
||||
props.collection = collection
|
||||
collection.BIMCollectionProperties.obj = obj
|
||||
return collection
|
||||
|
||||
@@ -184,7 +185,8 @@ class Collector(bonsai.core.tool.Collector):
|
||||
@classmethod
|
||||
def reset_default_visibility(cls) -> None:
|
||||
project = tool.Ifc.get_object(tool.Ifc.get().by_type("IfcProject")[0])
|
||||
project_collection = project.BIMObjectProperties.collection
|
||||
assert project
|
||||
project_collection = tool.Blender.get_object_bim_props(project).collection
|
||||
for layer_collection in bpy.context.view_layer.layer_collection.children:
|
||||
if layer_collection.collection == project_collection:
|
||||
for layer_collection2 in layer_collection.children:
|
||||
|
||||
@@ -16,17 +16,26 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import annotations
|
||||
import bpy
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.element
|
||||
import bonsai.core.tool
|
||||
import bonsai.tool as tool
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bonsai.bim.module.covering.prop import BIMCoveringProperties
|
||||
|
||||
|
||||
class Covering(bonsai.core.tool.Covering):
|
||||
@classmethod
|
||||
def get_covering_props(cls) -> BIMCoveringProperties:
|
||||
return bpy.context.scene.BIMCoveringProperties
|
||||
|
||||
@classmethod
|
||||
def get_z_from_ceiling_height(cls) -> float:
|
||||
props = bpy.context.scene.BIMCoveringProperties
|
||||
props = cls.get_covering_props()
|
||||
return props.ceiling_height
|
||||
|
||||
# def toggle_spaces_visibility_wired_and_textured(cls, spaces):
|
||||
|
||||
@@ -524,7 +524,7 @@ class Drawing(bonsai.core.tool.Drawing):
|
||||
def get_drawing_collection(cls, drawing: ifcopenshell.entity_instance) -> Union[bpy.types.Collection, None]:
|
||||
obj = tool.Ifc.get_object(drawing)
|
||||
if obj:
|
||||
return obj.BIMObjectProperties.collection
|
||||
return tool.Blender.get_object_bim_props(obj).collection
|
||||
|
||||
@classmethod
|
||||
def get_drawing_group(cls, drawing: ifcopenshell.entity_instance) -> ifcopenshell.entity_instance:
|
||||
@@ -1516,8 +1516,8 @@ class Drawing(bonsai.core.tool.Drawing):
|
||||
dst = src.copy()
|
||||
dst.data = dst.data.copy()
|
||||
dst.name = dst.name.replace("IfcGridAxis/", "")
|
||||
dst.BIMObjectProperties.ifc_definition_id = 0
|
||||
tool.Geometry.get_geometry_props(dst).ifc_definition_id = 0
|
||||
tool.Blender.get_object_bim_props(dst).ifc_definition_id = 0
|
||||
tool.Geometry.get_geometry_props(dst.data).ifc_definition_id = 0
|
||||
return dst
|
||||
|
||||
def disassemble(obj: bpy.types.Object) -> tuple[bpy.types.Object, bmesh.types.BMesh]:
|
||||
@@ -1888,7 +1888,7 @@ class Drawing(bonsai.core.tool.Drawing):
|
||||
return bool(
|
||||
camera is not None
|
||||
and camera.type == "CAMERA"
|
||||
and camera.BIMObjectProperties.ifc_definition_id
|
||||
and tool.Blender.get_ifc_definition_id(camera)
|
||||
and area is not None
|
||||
)
|
||||
|
||||
@@ -1910,11 +1910,12 @@ class Drawing(bonsai.core.tool.Drawing):
|
||||
def isolate_camera_collection(cls, camera: bpy.types.Object) -> None:
|
||||
drawings = [e for e in tool.Ifc.get().by_type("IfcAnnotation") if e.ObjectType == "DRAWING"]
|
||||
drawing_collections = []
|
||||
camera_collection = camera.BIMObjectProperties.collection
|
||||
camera_collection = tool.Blender.get_object_bim_props(camera).collection
|
||||
for drawing in drawings:
|
||||
if not (drawing_obj := tool.Ifc.get_object(drawing)):
|
||||
continue
|
||||
if not (drawing_collection := drawing_obj.BIMObjectProperties.collection):
|
||||
oprops = tool.Blender.get_object_bim_props(drawing_obj)
|
||||
if not (drawing_collection := oprops.collection):
|
||||
continue
|
||||
if drawing_obj == camera:
|
||||
drawing_collection.hide_render = False
|
||||
@@ -1922,7 +1923,7 @@ class Drawing(bonsai.core.tool.Drawing):
|
||||
drawing_collection.hide_render = True
|
||||
|
||||
project = tool.Ifc.get_object(tool.Ifc.get().by_type("IfcProject")[0])
|
||||
project_collection = project.BIMObjectProperties.collection
|
||||
project_collection = tool.Blender.get_object_bim_props(project).collection
|
||||
for layer_collection in bpy.context.view_layer.layer_collection.children:
|
||||
if layer_collection.collection == project_collection:
|
||||
for layer_collection2 in layer_collection.children:
|
||||
|
||||
@@ -235,7 +235,7 @@ class Geometry(bonsai.core.tool.Geometry):
|
||||
bpy.data.objects.remove(axis_obj)
|
||||
ifcopenshell.api.grid.remove_grid_axis(tool.Ifc.get(), axis=axis)
|
||||
|
||||
collection = obj.BIMObjectProperties.collection
|
||||
collection = tool.Blender.get_object_bim_props(obj).collection
|
||||
if collection:
|
||||
parent = ifcopenshell.util.element.get_aggregate(element)
|
||||
if not parent:
|
||||
@@ -243,7 +243,7 @@ class Geometry(bonsai.core.tool.Geometry):
|
||||
if parent:
|
||||
parent_obj = tool.Ifc.get_object(parent)
|
||||
if parent_obj:
|
||||
parent_collection = parent_obj.BIMObjectProperties.collection
|
||||
parent_collection = tool.Blender.get_object_bim_props(parent_obj).collection
|
||||
for child in collection.children:
|
||||
parent_collection.children.link(child)
|
||||
for child_object in collection.objects:
|
||||
@@ -557,11 +557,9 @@ class Geometry(bonsai.core.tool.Geometry):
|
||||
|
||||
@classmethod
|
||||
def get_cartesian_point_offset(cls, obj: bpy.types.Object) -> npt.NDArray[np.float64] | None:
|
||||
if (
|
||||
obj.BIMObjectProperties.blender_offset_type == "CARTESIAN_POINT"
|
||||
and obj.BIMObjectProperties.cartesian_point_offset
|
||||
):
|
||||
return np.array(tuple(map(float, obj.BIMObjectProperties.cartesian_point_offset.split(","))))
|
||||
props = tool.Blender.get_object_bim_props(obj)
|
||||
if props.blender_offset_type == "CARTESIAN_POINT" and props.cartesian_point_offset:
|
||||
return np.array(tuple(map(float, props.cartesian_point_offset.split(","))))
|
||||
|
||||
@classmethod
|
||||
def get_element_type(cls, element: ifcopenshell.entity_instance) -> Union[ifcopenshell.entity_instance, None]:
|
||||
@@ -1084,8 +1082,9 @@ class Geometry(bonsai.core.tool.Geometry):
|
||||
@classmethod
|
||||
def record_object_position(cls, obj: bpy.types.Object) -> None:
|
||||
# These are recorded separately because they have different numerical tolerances
|
||||
obj.BIMObjectProperties.location_checksum = repr(np.array(obj.matrix_world.translation).tobytes())
|
||||
obj.BIMObjectProperties.rotation_checksum = repr(np.array(obj.matrix_world.to_3x3()).tobytes())
|
||||
props = tool.Blender.get_object_bim_props(obj)
|
||||
props.location_checksum = repr(np.array(obj.matrix_world.translation).tobytes())
|
||||
props.rotation_checksum = repr(np.array(obj.matrix_world.to_3x3()).tobytes())
|
||||
|
||||
@classmethod
|
||||
def remove_connection(cls, connection: ifcopenshell.entity_instance) -> None:
|
||||
@@ -1570,8 +1569,9 @@ class Geometry(bonsai.core.tool.Geometry):
|
||||
def get_blender_offset_type(cls, obj: bpy.types.Object) -> Optional[str]:
|
||||
props = tool.Georeference.get_georeference_props()
|
||||
if props.has_blender_offset:
|
||||
if (result := obj.BIMObjectProperties.blender_offset_type) == "NONE":
|
||||
result = obj.BIMObjectProperties.blender_offset_type = "OBJECT_PLACEMENT"
|
||||
props = tool.Blender.get_object_bim_props(obj)
|
||||
if (result := props.blender_offset_type) == "NONE":
|
||||
result = props.blender_offset_type = "OBJECT_PLACEMENT"
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -77,13 +77,14 @@ class Ifc(bonsai.core.tool.Ifc):
|
||||
return False
|
||||
if element and (element.is_a("IfcTypeProduct") or element.is_a("IfcProject")):
|
||||
return False
|
||||
if not obj.BIMObjectProperties.location_checksum:
|
||||
oprops = tool.Blender.get_object_bim_props(obj)
|
||||
if not oprops.location_checksum:
|
||||
return True # Let's be conservative
|
||||
loc_check = np.frombuffer(eval(obj.BIMObjectProperties.location_checksum))
|
||||
loc_check = np.frombuffer(eval(oprops.location_checksum))
|
||||
loc_real = np.array(obj.matrix_world.translation).flatten()
|
||||
if not np.allclose(loc_check, loc_real, atol=1e-4): # 0.1 mm
|
||||
return True
|
||||
rot_check = np.frombuffer(eval(obj.BIMObjectProperties.rotation_checksum)).reshape(3, 3)
|
||||
rot_check = np.frombuffer(eval(oprops.rotation_checksum)).reshape(3, 3)
|
||||
rot_real = np.array(obj.matrix_world.to_3x3())
|
||||
rot_dot = np.dot(rot_check, rot_real.T)
|
||||
angle_rad = np.arccos(np.clip((np.trace(rot_dot) - 1) / 2, -1, 1))
|
||||
@@ -107,7 +108,7 @@ class Ifc(bonsai.core.tool.Ifc):
|
||||
|
||||
props = None
|
||||
if isinstance(obj, bpy.types.Object):
|
||||
props = obj.BIMObjectProperties
|
||||
props = tool.Blender.get_object_bim_props(obj)
|
||||
elif isinstance(obj, bpy.types.Material):
|
||||
props = obj.BIMStyleProperties
|
||||
else:
|
||||
|
||||
@@ -397,9 +397,9 @@ class IfcGit:
|
||||
bpy.ops.object.select_all(action="DESELECT")
|
||||
|
||||
for obj in bpy.context.visible_objects:
|
||||
if not obj.BIMObjectProperties.ifc_definition_id:
|
||||
props = tool.Blender.get_object_bim_props(obj)
|
||||
if not (step_id := props.ifc_definition_id):
|
||||
continue
|
||||
step_id = obj.BIMObjectProperties.ifc_definition_id
|
||||
if step_id in step_ids["modified"]:
|
||||
obj.color = (0.3, 0.3, 1.0, 1)
|
||||
obj.select_set(True)
|
||||
|
||||
@@ -929,6 +929,7 @@ class Loader(bonsai.core.tool.Loader):
|
||||
|
||||
@classmethod
|
||||
def apply_blender_offset_to_matrix_world(cls, obj: bpy.types.Object, matrix: np.ndarray) -> Matrix:
|
||||
oprops = tool.Blender.get_object_bim_props(obj)
|
||||
if (
|
||||
not obj.data
|
||||
and tool.Cad.is_x(matrix[0][3], 0)
|
||||
@@ -939,13 +940,13 @@ class Loader(bonsai.core.tool.Loader):
|
||||
# positionally significant and is left alone. This handles
|
||||
# scenarios where often spatial elements are left at 0,0,0 and
|
||||
# everything else is at map coordinates.
|
||||
obj.BIMObjectProperties.blender_offset_type = "NOT_APPLICABLE"
|
||||
oprops.blender_offset_type = "NOT_APPLICABLE"
|
||||
return Matrix(matrix.tolist())
|
||||
|
||||
if obj.data and obj.data.get("has_cartesian_point_offset", None):
|
||||
obj.BIMObjectProperties.blender_offset_type = "CARTESIAN_POINT"
|
||||
oprops.blender_offset_type = "CARTESIAN_POINT"
|
||||
if cartesian_point_offset := obj.data.get("cartesian_point_offset", None):
|
||||
obj.BIMObjectProperties.cartesian_point_offset = cartesian_point_offset
|
||||
oprops.cartesian_point_offset = cartesian_point_offset
|
||||
offset_xyz = list(map(float, cartesian_point_offset.split(","))) + [1.0]
|
||||
offset_xyz = matrix @ offset_xyz
|
||||
matrix[0][3] = offset_xyz[0]
|
||||
@@ -954,8 +955,8 @@ class Loader(bonsai.core.tool.Loader):
|
||||
|
||||
props = tool.Georeference.get_georeference_props()
|
||||
if props.has_blender_offset:
|
||||
if obj.BIMObjectProperties.blender_offset_type == "NONE":
|
||||
obj.BIMObjectProperties.blender_offset_type = "OBJECT_PLACEMENT"
|
||||
if oprops.blender_offset_type == "NONE":
|
||||
oprops.blender_offset_type = "OBJECT_PLACEMENT"
|
||||
matrix = ifcopenshell.util.geolocation.global2local(
|
||||
matrix,
|
||||
float(props.blender_offset_x) * cls.unit_scale,
|
||||
|
||||
@@ -55,7 +55,15 @@ T = TypeVar("T")
|
||||
V_ = tool.Blender.V_
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bonsai.bim.module.model.prop import BIMModelProperties, BIMDoorProperties
|
||||
from bonsai.bim.module.model.prop import (
|
||||
BIMModelProperties,
|
||||
BIMDoorProperties,
|
||||
BIMArrayProperties,
|
||||
BIMRoofProperties,
|
||||
BIMWindowProperties,
|
||||
BIMStairProperties,
|
||||
BIMRailingProperties,
|
||||
)
|
||||
|
||||
|
||||
class Model(bonsai.core.tool.Model):
|
||||
@@ -67,6 +75,26 @@ class Model(bonsai.core.tool.Model):
|
||||
def get_door_props(cls, obj: bpy.types.Object) -> BIMDoorProperties:
|
||||
return obj.BIMDoorProperties
|
||||
|
||||
@classmethod
|
||||
def get_window_props(cls, obj: bpy.types.Object) -> BIMWindowProperties:
|
||||
return obj.BIMWindowProperties
|
||||
|
||||
@classmethod
|
||||
def get_stair_props(cls, obj: bpy.types.Object) -> BIMStairProperties:
|
||||
return obj.BIMStairProperties
|
||||
|
||||
@classmethod
|
||||
def get_roof_props(cls, obj: bpy.types.Object) -> BIMRoofProperties:
|
||||
return obj.BIMRoofProperties
|
||||
|
||||
@classmethod
|
||||
def get_railing_props(cls, obj: bpy.types.Object) -> BIMRailingProperties:
|
||||
return obj.BIMRailingProperties
|
||||
|
||||
@classmethod
|
||||
def get_array_props(cls, obj: bpy.types.Object) -> BIMArrayProperties:
|
||||
return obj.BIMArrayProperties
|
||||
|
||||
@classmethod
|
||||
def convert_si_to_unit(cls, value: T) -> T:
|
||||
if isinstance(value, (tuple, list)):
|
||||
@@ -1989,9 +2017,9 @@ class Model(bonsai.core.tool.Model):
|
||||
if z < 0 and y < 0:
|
||||
y = abs(y)
|
||||
z = abs(z)
|
||||
if z < 0 and y >=0:
|
||||
if z < 0 and y >= 0:
|
||||
vector = Vector((0, -1))
|
||||
|
||||
|
||||
x_angle = vector.angle_signed(Vector((y, z)))
|
||||
|
||||
return x_angle
|
||||
|
||||
@@ -409,7 +409,8 @@ class Root(bonsai.core.tool.Root):
|
||||
def set_object_name(cls, obj: bpy.types.Object, element: ifcopenshell.entity_instance) -> None:
|
||||
name = tool.Loader.get_name(element)
|
||||
if obj.name != name:
|
||||
obj.BIMObjectProperties.is_renaming = True
|
||||
props = tool.Blender.get_object_bim_props(obj)
|
||||
props.is_renaming = True
|
||||
obj.name = name # The handler will trigger, and reset is_renaming to False
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -1158,7 +1158,7 @@ class Sequence(bonsai.core.tool.Sequence):
|
||||
bpy.context.scene.frame_start = 1
|
||||
bpy.context.scene.frame_end = 2
|
||||
for obj in bpy.data.objects:
|
||||
if not obj.BIMObjectProperties.ifc_definition_id:
|
||||
if not (ifc_id := tool.Blender.get_ifc_definition_id(obj)):
|
||||
continue
|
||||
obj.color = (1.0, 1.0, 1.0, 1)
|
||||
obj.hide_viewport = False
|
||||
@@ -1317,7 +1317,7 @@ class Sequence(bonsai.core.tool.Sequence):
|
||||
@classmethod
|
||||
def clear_objects_animation(cls, include_blender_objects=True):
|
||||
for obj in bpy.data.objects:
|
||||
if not include_blender_objects and not obj.BIMObjectProperties.ifc_definition_id:
|
||||
if not include_blender_objects and not (ifc_id := tool.Blender.get_ifc_definition_id(obj)):
|
||||
continue
|
||||
cls.clear_object_animation(obj)
|
||||
cls.clear_object_color(obj)
|
||||
@@ -1326,13 +1326,14 @@ class Sequence(bonsai.core.tool.Sequence):
|
||||
@classmethod
|
||||
def animate_objects(cls, settings, frames, animation_type=""):
|
||||
for obj in bpy.data.objects:
|
||||
if not obj.BIMObjectProperties.ifc_definition_id:
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
if not element:
|
||||
continue
|
||||
if tool.Ifc.get().by_id(obj.BIMObjectProperties.ifc_definition_id).is_a("IfcSpace"):
|
||||
if element.is_a("IfcSpace"):
|
||||
cls.hide_object(obj)
|
||||
continue
|
||||
cls.earliest_frame = None
|
||||
product_frames = frames.get(obj.BIMObjectProperties.ifc_definition_id, [])
|
||||
product_frames = frames.get(element.id(), [])
|
||||
for product_frame in product_frames:
|
||||
if product_frame["relationship"] == "input":
|
||||
cls.animate_input(obj, settings["start_frame"], product_frame, animation_type)
|
||||
|
||||
@@ -1180,9 +1180,9 @@ class Spatial(bonsai.core.tool.Spatial):
|
||||
SpatialDecompositionData.data["default_container"] = SpatialDecompositionData.default_container()
|
||||
|
||||
project = tool.Ifc.get_object(tool.Ifc.get().by_type("IfcProject")[0])
|
||||
project_collection = project.BIMObjectProperties.collection
|
||||
project_collection = tool.Blender.get_object_bim_props(project).collection
|
||||
obj = tool.Ifc.get_object(container)
|
||||
if obj and (collection := obj.BIMObjectProperties.collection):
|
||||
if obj and (collection := tool.Blender.get_object_bim_props(obj).collection):
|
||||
for layer_collection in bpy.context.view_layer.layer_collection.children:
|
||||
if layer_collection.collection == project_collection:
|
||||
for layer_collection2 in layer_collection.children:
|
||||
|
||||
@@ -110,7 +110,8 @@ class Structural(bonsai.core.tool.Structural):
|
||||
def get_product_or_active_object(cls, product: str) -> Union[bpy.types.Object, None]:
|
||||
product = bpy.data.objects.get(product) if product else bpy.context.active_object
|
||||
try:
|
||||
if product.BIMObjectProperties.ifc_definition_id:
|
||||
props = tool.Blender.get_object_bim_props(product)
|
||||
if props.ifc_definition_id:
|
||||
return product
|
||||
else:
|
||||
return None
|
||||
|
||||
@@ -33,7 +33,7 @@ class Surveyor(bonsai.core.tool.Surveyor):
|
||||
M_TRANSLATION = (slice(0, 3), 3)
|
||||
matrix = np.array(obj.matrix_world)
|
||||
props = tool.Georeference.get_georeference_props()
|
||||
if props.has_blender_offset and obj.BIMObjectProperties.blender_offset_type != "NOT_APPLICABLE":
|
||||
if props.has_blender_offset and tool.Blender.get_object_bim_props(obj).blender_offset_type != "NOT_APPLICABLE":
|
||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||
coordinate_offset = tool.Geometry.get_cartesian_point_offset(obj)
|
||||
if coordinate_offset is not None:
|
||||
|
||||
@@ -189,7 +189,7 @@ class System(bonsai.core.tool.System):
|
||||
|
||||
container = ifcopenshell.util.element.get_container(element)
|
||||
if container:
|
||||
collection = tool.Ifc.get_object(container).BIMObjectProperties.collection
|
||||
collection = tool.Blender.get_object_bim_props(tool.Ifc.get_object(container)).collection
|
||||
ifc_importer.collections[container.GlobalId] = collection
|
||||
ifc_importer.place_objects_in_collections()
|
||||
|
||||
|
||||
@@ -192,12 +192,12 @@ def the_object_name_does_not_exist(name):
|
||||
|
||||
def the_object_name_is_an_ifc_class(name, ifc_class):
|
||||
ifc = an_ifc_file_exists()
|
||||
element = ifc.by_id(the_object_name_exists(name).BIMObjectProperties.ifc_definition_id)
|
||||
element = ifc.by_id(tool.Blender.get_ifc_definition_id(the_object_name_exists(name)))
|
||||
assert element.is_a(ifc_class), f'Object "{name}" is an {element.is_a()}'
|
||||
|
||||
|
||||
def the_object_name_is_not_an_ifc_element(name):
|
||||
id = the_object_name_exists(name).BIMObjectProperties.ifc_definition_id
|
||||
id = tool.Blender.get_ifc_definition_id(the_object_name_exists(name))
|
||||
assert id == 0, f"The ID is {id}"
|
||||
|
||||
|
||||
@@ -229,7 +229,7 @@ def the_object_name_is_placed_in_the_collection_collection(name, collection):
|
||||
|
||||
def the_object_name_has_a_type_representation_of_context(name, type, context):
|
||||
ifc = an_ifc_file_exists()
|
||||
element = ifc.by_id(the_object_name_exists(name).BIMObjectProperties.ifc_definition_id)
|
||||
element = ifc.by_id(tool.Blender.get_ifc_definition_id(the_object_name_exists(name)))
|
||||
context, subcontext, target_view = context.split("/")
|
||||
assert ifcopenshell.util.representation.get_representation(
|
||||
element, context, subcontext or None, target_view or None
|
||||
@@ -238,7 +238,7 @@ def the_object_name_has_a_type_representation_of_context(name, type, context):
|
||||
|
||||
def the_object_name_is_contained_in_container_name(name, container_name):
|
||||
ifc = an_ifc_file_exists()
|
||||
element = ifc.by_id(the_object_name_exists(name).BIMObjectProperties.ifc_definition_id)
|
||||
element = ifc.by_id(tool.Blender.get_ifc_definition_id(the_object_name_exists(name)))
|
||||
container = ifcopenshell.util.element.get_container(element)
|
||||
if not container:
|
||||
assert False, f'Object "{name}" is not in any container'
|
||||
@@ -257,8 +257,8 @@ def i_delete_the_selected_objects():
|
||||
|
||||
def the_object_name1_and_name2_are_different_elements(name1, name2):
|
||||
ifc = an_ifc_file_exists()
|
||||
element1 = ifc.by_id(the_object_name_exists(name1).BIMObjectProperties.ifc_definition_id)
|
||||
element2 = ifc.by_id(the_object_name_exists(name2).BIMObjectProperties.ifc_definition_id)
|
||||
element1 = ifc.by_id(tool.Blender.get_ifc_definition_id(the_object_name_exists(name1)))
|
||||
element2 = ifc.by_id(tool.Blender.get_ifc_definition_id(the_object_name_exists(name2)))
|
||||
assert element1 != element2, f"Objects {name1} and {name2} have same elements {element1} and {element2}"
|
||||
|
||||
|
||||
@@ -284,7 +284,7 @@ def the_object_name1_has_no_boolean_difference_by_name2(name1, name2):
|
||||
|
||||
def the_object_name_is_voided_by_void(name, void):
|
||||
ifc = tool.Ifc.get()
|
||||
element = ifc.by_id(the_object_name_exists(name).BIMObjectProperties.ifc_definition_id)
|
||||
element = ifc.by_id(tool.Blender.get_ifc_definition_id(the_object_name_exists(name)))
|
||||
for rel in element.HasOpenings:
|
||||
if rel.RelatedOpeningElement.Name == void:
|
||||
return True
|
||||
@@ -293,7 +293,7 @@ def the_object_name_is_voided_by_void(name, void):
|
||||
|
||||
def the_object_name_is_not_voided_by_void(name, void):
|
||||
ifc = tool.Ifc.get()
|
||||
element = ifc.by_id(the_object_name_exists(name).BIMObjectProperties.ifc_definition_id)
|
||||
element = ifc.by_id(tool.Blender.get_ifc_definition_id(the_object_name_exists(name)))
|
||||
for rel in element.HasOpenings:
|
||||
if rel.RelatedOpeningElement.Name == void:
|
||||
assert False, "A void was found"
|
||||
@@ -301,21 +301,21 @@ def the_object_name_is_not_voided_by_void(name, void):
|
||||
|
||||
def the_object_name_is_not_voided(name):
|
||||
ifc = tool.Ifc.get()
|
||||
element = ifc.by_id(the_object_name_exists(name).BIMObjectProperties.ifc_definition_id)
|
||||
element = ifc.by_id(tool.Blender.get_ifc_definition_id(the_object_name_exists(name)))
|
||||
if any(element.HasOpenings):
|
||||
assert False, "An opening was found"
|
||||
|
||||
|
||||
def the_object_name_is_not_a_void(name):
|
||||
ifc = tool.Ifc.get()
|
||||
element = ifc.by_id(the_object_name_exists(name).BIMObjectProperties.ifc_definition_id)
|
||||
element = ifc.by_id(tool.Blender.get_ifc_definition_id(the_object_name_exists(name)))
|
||||
if any(element.VoidsElements):
|
||||
assert False, "A void was found"
|
||||
|
||||
|
||||
def the_void_name_is_filled_by_filling(name, filling):
|
||||
ifc = tool.Ifc.get()
|
||||
element = ifc.by_id(the_object_name_exists(name).BIMObjectProperties.ifc_definition_id)
|
||||
element = ifc.by_id(tool.Blender.get_ifc_definition_id(the_object_name_exists(name)))
|
||||
if any(rel.RelatedBuildingElement.Name == filling for rel in element.HasFillings):
|
||||
return True
|
||||
assert False, "No filling found"
|
||||
@@ -323,14 +323,14 @@ def the_void_name_is_filled_by_filling(name, filling):
|
||||
|
||||
def the_void_name_is_not_filled_by_filling(name, filling):
|
||||
ifc = tool.Ifc.get()
|
||||
element = ifc.by_id(the_object_name_exists(name).BIMObjectProperties.ifc_definition_id)
|
||||
element = ifc.by_id(tool.Blender.get_ifc_definition_id(the_object_name_exists(name)))
|
||||
if any(rel.RelatedBuildingElement.Name == filling for rel in element.HasFillings):
|
||||
assert False, "A filling was found"
|
||||
|
||||
|
||||
def the_object_name_is_not_a_filling(name):
|
||||
ifc = tool.Ifc.get()
|
||||
element = ifc.by_id(the_object_name_exists(name).BIMObjectProperties.ifc_definition_id)
|
||||
element = ifc.by_id(tool.Blender.get_ifc_definition_id(the_object_name_exists(name)))
|
||||
if any(element.FillsVoids):
|
||||
assert False, "A filling was found"
|
||||
|
||||
|
||||
@@ -718,8 +718,8 @@ def the_collection_exclude_status_is(name: str, exclude: str) -> None:
|
||||
@then(parsers.parse('the object "{name1}" and "{name2}" are different elements'))
|
||||
def the_object_name1_and_name2_are_different_elements(name1, name2):
|
||||
ifc = an_ifc_file_exists()
|
||||
element1 = ifc.by_id(the_object_name_exists(name1).BIMObjectProperties.ifc_definition_id)
|
||||
element2 = ifc.by_id(the_object_name_exists(name2).BIMObjectProperties.ifc_definition_id)
|
||||
element1 = ifc.by_id(tool.Blender.get_ifc_definition_id(the_object_name_exists(name1)))
|
||||
element2 = ifc.by_id(tool.Blender.get_ifc_definition_id(the_object_name_exists(name2)))
|
||||
assert element1 != element2, f"Objects {name1} and {name2} have same elements {element1} and {element2}"
|
||||
|
||||
|
||||
@@ -732,7 +732,7 @@ def the_object_name_has_a_body_of_value(name, value):
|
||||
@then(parsers.parse('the object "{name}" has a "{type}" representation of "{context}"'))
|
||||
def the_object_name_has_a_representation_type_of_context(name, type, context):
|
||||
ifc = an_ifc_file_exists()
|
||||
element = ifc.by_id(the_object_name_exists(name).BIMObjectProperties.ifc_definition_id)
|
||||
element = ifc.by_id(tool.Blender.get_ifc_definition_id(the_object_name_exists(name)))
|
||||
context, subcontext, target_view = context.split("/")
|
||||
rep = ifcopenshell.util.representation.get_representation(element, context, subcontext or None, target_view or None)
|
||||
assert rep
|
||||
@@ -808,7 +808,7 @@ def the_object_name_should_display_as_mode(name, mode):
|
||||
@then(parsers.parse('the object "{name}" is voided by "{void}"'))
|
||||
def the_object_name_is_voided_by_void(name, void):
|
||||
ifc = tool.Ifc.get()
|
||||
element = ifc.by_id(the_object_name_exists(name).BIMObjectProperties.ifc_definition_id)
|
||||
element = ifc.by_id(tool.Blender.get_ifc_definition_id(the_object_name_exists(name)))
|
||||
assert any((rel for rel in element.HasOpenings if rel.RelatedOpeningElement.Name == void)), "No void found"
|
||||
|
||||
|
||||
@@ -824,7 +824,7 @@ def the_object_name_is_not_voided_by_void(name, void):
|
||||
@then(parsers.parse('the object "{name}" is not voided'))
|
||||
def the_object_name_is_not_voided(name):
|
||||
ifc = tool.Ifc.get()
|
||||
element = ifc.by_id(the_object_name_exists(name).BIMObjectProperties.ifc_definition_id)
|
||||
element = ifc.by_id(tool.Blender.get_ifc_definition_id(the_object_name_exists(name)))
|
||||
assert not element.HasOpenings, "A void was found"
|
||||
|
||||
|
||||
@@ -832,7 +832,7 @@ def the_object_name_is_not_voided(name):
|
||||
def the_object_name_is_a_void(name):
|
||||
ifc = tool.Ifc.get()
|
||||
obj = the_object_name_exists(name)
|
||||
element = ifc.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
element = ifc.by_id(tool.Blender.get_ifc_definition_id(obj))
|
||||
assert any((element.VoidsElements)), "No void was found"
|
||||
|
||||
|
||||
@@ -872,14 +872,14 @@ def the_object_name_is_not_visible(name):
|
||||
@then(parsers.parse('the object "{name}" is an "{ifc_class}"'))
|
||||
def the_object_name_is_an_ifc_class(name, ifc_class):
|
||||
ifc = an_ifc_file_exists()
|
||||
element = ifc.by_id(the_object_name_exists(name).BIMObjectProperties.ifc_definition_id)
|
||||
element = ifc.by_id(tool.Blender.get_ifc_definition_id(the_object_name_exists(name)))
|
||||
assert element.is_a(ifc_class), f'Object "{name}" is an {element.is_a()}'
|
||||
|
||||
|
||||
@then(parsers.parse('the object "{name}" is not an IFC element'))
|
||||
def the_object_name_is_not_an_ifc_element(name):
|
||||
obj = the_object_name_exists(name)
|
||||
ifc_definition_id = obj.BIMObjectProperties.ifc_definition_id
|
||||
ifc_definition_id = tool.Blender.get_ifc_definition_id(obj)
|
||||
assert ifc_definition_id == 0, f"The object {obj} has an ID of {ifc_definition_id}"
|
||||
|
||||
|
||||
@@ -897,14 +897,14 @@ def the_object_name_has_ifc_representation_data(name):
|
||||
@then(parsers.parse('the material "{name}" is an IFC material'))
|
||||
def the_material_name_is_an_ifc_material(name):
|
||||
obj = the_material_name_exists(name)
|
||||
ifc_definition_id = obj.BIMObjectProperties.ifc_definition_id
|
||||
ifc_definition_id = tool.Blender.get_ifc_definition_id(obj)
|
||||
assert ifc_definition_id != 0, f"The material {obj} has no ID: {ifc_definition_id}"
|
||||
|
||||
|
||||
@then(parsers.parse('the material "{name}" is not an IFC material'))
|
||||
def the_material_name_is_not_an_ifc_material(name):
|
||||
obj = the_material_name_exists(name)
|
||||
ifc_definition_id = obj.BIMObjectProperties.ifc_definition_id
|
||||
ifc_definition_id = tool.Blender.get_ifc_definition_id(obj)
|
||||
assert ifc_definition_id == 0, f"The material {obj} has an ID of {ifc_definition_id}"
|
||||
|
||||
|
||||
@@ -937,7 +937,7 @@ def the_object_name_has_number_vertices(name, number):
|
||||
@then(parsers.parse('the void "{name}" is filled by "{filling}"'))
|
||||
def the_void_name_is_filled_by_filling(name, filling):
|
||||
ifc = tool.Ifc.get()
|
||||
element = ifc.by_id(the_object_name_exists(name).BIMObjectProperties.ifc_definition_id)
|
||||
element = ifc.by_id(tool.Blender.get_ifc_definition_id(the_object_name_exists(name)))
|
||||
assert any((rel.RelatedBuildingElement.Name == filling for rel in element.HasFillings)), "No filling found"
|
||||
|
||||
|
||||
@@ -954,7 +954,7 @@ def the_void_name_is_not_filled_by_filling(name, filling):
|
||||
@then(parsers.parse('the object "{name}" is not a filling'))
|
||||
def the_object_name_is_not_a_filling(name):
|
||||
ifc = tool.Ifc.get()
|
||||
element = ifc.by_id(the_object_name_exists(name).BIMObjectProperties.ifc_definition_id)
|
||||
element = ifc.by_id(tool.Blender.get_ifc_definition_id(the_object_name_exists(name)))
|
||||
assert not any(element.FillsVoids), "A filling was found"
|
||||
|
||||
|
||||
@@ -1010,8 +1010,9 @@ def prop_is_roughly_value(prop, value):
|
||||
def the_object_name_has_a_cartesian_point_offset_of_offset(name: str, offset: str) -> None:
|
||||
offset = replace_variables(offset)
|
||||
obj = the_object_name_exists(name)
|
||||
assert obj.BIMObjectProperties.blender_offset_type == "CARTESIAN_POINT"
|
||||
obj_offset = np.array(tuple(map(float, obj.BIMObjectProperties.cartesian_point_offset.split(","))))
|
||||
props = tool.Blender.get_object_props(obj)
|
||||
assert props.blender_offset_type == "CARTESIAN_POINT"
|
||||
obj_offset = np.array(tuple(map(float, props.cartesian_point_offset.split(","))))
|
||||
offset = np.array(tuple(map(float, offset.split(","))))
|
||||
assert np.allclose(obj_offset, offset)
|
||||
|
||||
@@ -1169,7 +1170,7 @@ def the_object_name_bottom_left_corner_is_at_location(name, location):
|
||||
@then(parsers.parse('the object "{name}" is contained in "{container_name}"'))
|
||||
def the_object_name_is_contained_in_container_name(name, container_name):
|
||||
ifc = an_ifc_file_exists()
|
||||
element = ifc.by_id(the_object_name_exists(name).BIMObjectProperties.ifc_definition_id)
|
||||
element = ifc.by_id(tool.Blender.get_ifc_definition_id(the_object_name_exists(name)))
|
||||
container = ifcopenshell.util.element.get_container(element)
|
||||
if not container:
|
||||
assert False, f'Object "{name}" is not in any container'
|
||||
@@ -1179,7 +1180,7 @@ def the_object_name_is_contained_in_container_name(name, container_name):
|
||||
@then(parsers.parse('the object "{name}" is contained in object "{container_name}"'))
|
||||
def the_object_name_is_contained_in_object_container_name(name: str, container_name: str) -> None:
|
||||
ifc = an_ifc_file_exists()
|
||||
element = ifc.by_id(the_object_name_exists(name).BIMObjectProperties.ifc_definition_id)
|
||||
element = ifc.by_id(tool.Blender.get_ifc_definition_id(the_object_name_exists(name)))
|
||||
container = ifcopenshell.util.element.get_container(element)
|
||||
if not container:
|
||||
assert False, f'Object "{name}" is not in any container'
|
||||
@@ -1190,7 +1191,7 @@ def the_object_name_is_contained_in_object_container_name(name: str, container_n
|
||||
@then(parsers.parse('the object "{name}" is aggregated by object "{aggregate_name}"'))
|
||||
def the_object_name_is_aggregated_by_object_aggregate_name(name: str, aggregate_name: str) -> None:
|
||||
ifc = an_ifc_file_exists()
|
||||
element = ifc.by_id(the_object_name_exists(name).BIMObjectProperties.ifc_definition_id)
|
||||
element = ifc.by_id(tool.Blender.get_ifc_definition_id(the_object_name_exists(name)))
|
||||
aggregate = ifcopenshell.util.element.get_aggregate(element)
|
||||
if not aggregate:
|
||||
assert False, f'Object "{name}" is not aggregated by any element'
|
||||
@@ -1201,7 +1202,7 @@ def the_object_name_is_aggregated_by_object_aggregate_name(name: str, aggregate_
|
||||
@then(parsers.parse('the object "{name}" has no aggregate'))
|
||||
def the_object_name_has_no_aggregate(name: str) -> None:
|
||||
ifc = an_ifc_file_exists()
|
||||
element = ifc.by_id(the_object_name_exists(name).BIMObjectProperties.ifc_definition_id)
|
||||
element = ifc.by_id(tool.Blender.get_ifc_definition_id(the_object_name_exists(name)))
|
||||
aggregate = ifcopenshell.util.element.get_aggregate(element)
|
||||
if aggregate:
|
||||
assert False, f'Object "{name}" is aggregated by element "{aggregate}"'
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
import bpy
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.api.aggregate
|
||||
import ifcopenshell.util.element
|
||||
import bonsai.core.tool
|
||||
import bonsai.tool as tool
|
||||
@@ -167,7 +168,8 @@ class TestAssign(NewIfc):
|
||||
tool.Ifc.link(building_element, building_obj)
|
||||
building_collection = bpy.data.collections.new("Foobar")
|
||||
bpy.context.scene.collection.children.link(building_collection)
|
||||
building_obj.BIMObjectProperties.collection = building_collection
|
||||
props = tool.Blender.get_object_bim_props(building_obj)
|
||||
props.collection = building_collection
|
||||
building_collection.objects.link(building_obj)
|
||||
ifcopenshell.api.aggregate.assign_object(
|
||||
tool.Ifc.get(),
|
||||
|
||||
@@ -319,7 +319,8 @@ class TestGetDrawingCollection(NewFile):
|
||||
collection = bpy.data.collections.new("Collection")
|
||||
bpy.context.scene.collection.children.link(collection)
|
||||
collection.objects.link(obj)
|
||||
obj.BIMObjectProperties.collection = collection
|
||||
props = tool.Blender.get_object_bim_props(obj)
|
||||
props.collection = collection
|
||||
collection.BIMCollectionProperties.obj = obj
|
||||
|
||||
element = ifc.createIfcAnnotation()
|
||||
|
||||
@@ -170,22 +170,25 @@ class TestGetTextLiteral(NewFile):
|
||||
class TestGetCartesianPointCoordinateOffset(NewFile):
|
||||
def test_run(self):
|
||||
obj = bpy.data.objects.new("Object", None)
|
||||
obj.BIMObjectProperties.blender_offset_type = "CARTESIAN_POINT"
|
||||
oprops = tool.Blender.get_object_bim_props(obj)
|
||||
oprops.blender_offset_type = "CARTESIAN_POINT"
|
||||
props = tool.Georeference.get_georeference_props()
|
||||
props.has_blender_offset = True
|
||||
obj.BIMObjectProperties.cartesian_point_offset = "1,2,3"
|
||||
oprops.cartesian_point_offset = "1,2,3"
|
||||
assert np.allclose(subject.get_cartesian_point_offset(obj), np.array((1.0, 2.0, 3.0)))
|
||||
|
||||
def test_get_null_if_not_a_cartesian_point_offset_type(self):
|
||||
obj = bpy.data.objects.new("Object", None)
|
||||
props = tool.Georeference.get_georeference_props()
|
||||
props.has_blender_offset = True
|
||||
obj.BIMObjectProperties.cartesian_point_offset = "1,2,3"
|
||||
oprops = tool.Blender.get_object_bim_props(obj)
|
||||
oprops.cartesian_point_offset = "1,2,3"
|
||||
assert subject.get_cartesian_point_offset(obj) is None
|
||||
|
||||
def test_get_null_if_no_blender_offset(self):
|
||||
obj = bpy.data.objects.new("Object", None)
|
||||
obj.BIMObjectProperties.blender_offset_type = "CARTESIAN_POINT"
|
||||
oprops = tool.Blender.get_object_bim_props(obj)
|
||||
oprops.blender_offset_type = "CARTESIAN_POINT"
|
||||
props = tool.Georeference.get_georeference_props()
|
||||
props.has_blender_offset = False
|
||||
assert subject.get_cartesian_point_offset(obj) is None
|
||||
@@ -307,15 +310,16 @@ class TestRecordObjectMaterials(NewFile):
|
||||
material.BIMStyleProperties.ifc_definition_id = style.id()
|
||||
obj.data.materials.append(material)
|
||||
subject.record_object_materials(obj)
|
||||
assert tool.Geometry.get_mesh_props(obj).material_checksum == str([style.id()])
|
||||
assert tool.Geometry.get_mesh_props(obj.data).material_checksum == str([style.id()])
|
||||
|
||||
|
||||
class TestRecordObjectPosition(NewFile):
|
||||
def test_run(self):
|
||||
obj = bpy.data.objects.new("Object", None)
|
||||
props = tool.Blender.get_object_bim_props(obj)
|
||||
subject.record_object_position(obj)
|
||||
assert obj.BIMObjectProperties.location_checksum == repr(np.array(obj.matrix_world.translation).tobytes())
|
||||
assert obj.BIMObjectProperties.rotation_checksum == repr(np.array(obj.matrix_world.to_3x3()).tobytes())
|
||||
assert props.location_checksum == repr(np.array(obj.matrix_world.translation).tobytes())
|
||||
assert props.rotation_checksum == repr(np.array(obj.matrix_world.to_3x3()).tobytes())
|
||||
|
||||
|
||||
class TestRemoveConnection(NewFile):
|
||||
|
||||
@@ -129,14 +129,16 @@ class TestGetEntity(test.bim.bootstrap.NewFile):
|
||||
|
||||
def test_attempting_without_a_file(self):
|
||||
obj = bpy.data.objects.new("Object", None)
|
||||
obj.BIMObjectProperties.ifc_definition_id = 1
|
||||
props = tool.Blender.get_object_bim_props(obj)
|
||||
props.ifc_definition_id = 1
|
||||
assert subject.get_entity(obj) is None
|
||||
|
||||
def test_attempting_to_get_an_invalidly_linked_object(self):
|
||||
ifc = ifcopenshell.file()
|
||||
subject.set(ifc)
|
||||
obj = bpy.data.objects.new("Object", None)
|
||||
obj.BIMObjectProperties.ifc_definition_id = 1
|
||||
props = tool.Blender.get_object_bim_props(obj)
|
||||
props.ifc_definition_id = 1
|
||||
assert subject.get_entity(obj) is None
|
||||
|
||||
|
||||
|
||||
@@ -383,23 +383,26 @@ class TestUsingArrays(NewFile):
|
||||
|
||||
bpy.ops.mesh.primitive_cube_add()
|
||||
obj = bpy.context.active_object
|
||||
assert obj
|
||||
rprops = tool.Root.get_root_props()
|
||||
rprops.ifc_product = "IfcElement"
|
||||
bpy.ops.bim.assign_class(ifc_class="IfcActuator", predefined_type="ELECTRICACTUATOR", userdefined_type="")
|
||||
|
||||
bpy.ops.bim.add_array()
|
||||
bpy.ops.bim.enable_editing_array(item=0)
|
||||
obj.BIMArrayProperties.count = 4
|
||||
obj.BIMArrayProperties.x = 4
|
||||
obj.BIMArrayProperties.sync_children = sync_children
|
||||
props = tool.Model.get_array_props(obj)
|
||||
props.count = 4
|
||||
props.x = 4
|
||||
props.sync_children = sync_children
|
||||
bpy.ops.bim.edit_array(item=0)
|
||||
|
||||
if add_second_layer:
|
||||
bpy.ops.bim.add_array()
|
||||
bpy.ops.bim.enable_editing_array(item=1)
|
||||
obj.BIMArrayProperties.count = 3
|
||||
obj.BIMArrayProperties.y = 4
|
||||
obj.BIMArrayProperties.sync_children = sync_children
|
||||
props = tool.Model.get_array_props(obj)
|
||||
props.count = 3
|
||||
props.y = 4
|
||||
props.sync_children = sync_children
|
||||
bpy.ops.bim.edit_array(item=1)
|
||||
|
||||
def test_remove_array_last_to_first(self):
|
||||
|
||||
@@ -54,6 +54,7 @@ class TestGetGlobalMatrix(test.bim.bootstrap.NewFile):
|
||||
props.blender_x_axis_abscissa = "0"
|
||||
props.blender_x_axis_ordinate = "1"
|
||||
obj = bpy.data.objects.new("Object", None)
|
||||
obj.BIMObjectProperties.blender_offset_type = "OBJECT_PLACEMENT"
|
||||
props = tool.Blender.get_object_bim_props(obj)
|
||||
props.blender_offset_type = "OBJECT_PLACEMENT"
|
||||
matrix = ifcopenshell.util.geolocation.local2global(np.array(obj.matrix_world), 1.0, 2.0, 3.0, 0.0, 1.0)
|
||||
assert (subject.get_absolute_matrix(obj) == matrix).all()
|
||||
|
||||
@@ -240,7 +240,7 @@ class TestImportUnitAttributes(NewFile):
|
||||
assert props.unit_attributes["UnitType"].enum_value == "ABSORBEDDOSEUNIT"
|
||||
assert props.unit_attributes["Prefix"].enum_value == "EXA"
|
||||
assert props.unit_attributes["Name"].enum_value == "AMPERE"
|
||||
assert props.unit_attributes["Dimensions"] is None
|
||||
assert "Dimensions" not in props.unit_attributes
|
||||
|
||||
|
||||
class TestImportUnits(NewFile):
|
||||
|
||||
@@ -442,7 +442,7 @@ class Usecase:
|
||||
|
||||
panel_schema: list[list[int]] = self.settings["panel_schema"]
|
||||
panels: list[dict[str, Any]] = self.settings["panel_properties"]
|
||||
accumulated_height = [0] * len(panel_schema[0])
|
||||
accumulated_height: list[float] = [0] * len(panel_schema[0])
|
||||
built_panels: list[int] = []
|
||||
window_items: list[ifcopenshell.entity_instance] = []
|
||||
lining_items: list[ifcopenshell.entity_instance] = []
|
||||
|
||||
@@ -96,7 +96,8 @@ class Patcher:
|
||||
angle_threshold = 0.3
|
||||
|
||||
for obj in bpy.data.objects:
|
||||
if not obj.BIMObjectProperties.ifc_definition_id or not obj.data:
|
||||
ifc_id = tool.Blender.get_ifc_definition_id(obj)
|
||||
if not ifc_id or not obj.data:
|
||||
continue
|
||||
if not obj.data.polygons:
|
||||
continue
|
||||
|
||||
Reference in New Issue
Block a user