diff --git a/src/blenderbim/blenderbim/bim/module/spatial/operator.py b/src/blenderbim/blenderbim/bim/module/spatial/operator.py index a20e314f54..f705b2cf84 100644 --- a/src/blenderbim/blenderbim/bim/module/spatial/operator.py +++ b/src/blenderbim/blenderbim/bim/module/spatial/operator.py @@ -29,11 +29,21 @@ import blenderbim.bim.handler class ReferenceStructure(bpy.types.Operator, tool.Ifc.Operator): bl_idname = "bim.reference_structure" bl_label = "Reference Structure" + bl_description = ( + "Reference selected objects from all selected structures.\n\n" + "Currently we do not support referencing structures in other structures " + "though it is allowed in IFC4X3" + ) bl_options = {"REGISTER", "UNDO"} def _execute(self, context): + objs = tool.Spatial.get_selected_objects_without_containers() + if not objs: + self.report({"INFO"}, "No non-spatial objects are selected.") + return + containers = tool.Spatial.get_selected_containers() - for obj in context.selected_objects: + for obj in objs: element = tool.Ifc.get_entity(obj) if not element: continue @@ -44,11 +54,21 @@ class ReferenceStructure(bpy.types.Operator, tool.Ifc.Operator): class DereferenceStructure(bpy.types.Operator, tool.Ifc.Operator): bl_idname = "bim.dereference_structure" bl_label = "Dereference Structure" + bl_description = ( + "Dereference selected objects from all selected structures.\n\n" + "Currently we do not support referencing structures in other structures " + "though it is allowed in IFC4X3" + ) bl_options = {"REGISTER", "UNDO"} def _execute(self, context): + objs = tool.Spatial.get_selected_objects_without_containers() + if not objs: + self.report({"INFO"}, "No non-spatial objects are selected.") + return + containers = tool.Spatial.get_selected_containers() - for obj in context.selected_objects: + for obj in objs: element = tool.Ifc.get_entity(obj) if not element: continue @@ -100,29 +120,36 @@ class RemoveContainer(bpy.types.Operator, tool.Ifc.Operator): class CopyToContainer(bpy.types.Operator, tool.Ifc.Operator): """ - Copies selected 3D elements in the viewport to checkmarked spatial containers + Copies selected 3D elements in the viewport to the selected spatial containers Example: bulk copy a wall to multiple storeys 1. Select one or more 3D elements in the viewport - 2. Enable the checkmark next to one or more containers in the container list below to select it + 2. Select one or more spatial containers in the viewport 3. Press this button 4. The copied elements will have a new position relative to the destination containers - """ + + Copying containers to other containers currently is not supported.""" bl_idname = "bim.copy_to_container" bl_label = "Copy To Container" bl_options = {"REGISTER", "UNDO"} def _execute(self, context): - # Track decompositions so they can be recreated after the operation - relationships = tool.Root.get_decomposition_relationships(context.selected_objects) - old_to_new = {} + objs = tool.Spatial.get_selected_objects_without_containers() + if not objs: + self.report({"INFO"}, "No non-spatial objects are selected.") + return + containers = tool.Spatial.get_selected_containers() - for obj in context.selected_objects: + # Track decompositions so they can be recreated after the operation + relationships = tool.Root.get_decomposition_relationships(objs) + old_to_new = {} + for obj in objs: result_objs = core.copy_to_container(tool.Ifc, tool.Collector, tool.Spatial, obj=obj, containers=containers) if result_objs: old_to_new[tool.Ifc.get_entity(obj)] = result_objs + # Recreate decompositions tool.Root.recreate_decompositions(relationships, old_to_new) blenderbim.bim.handler.refresh_ui_data() diff --git a/src/blenderbim/blenderbim/tool/spatial.py b/src/blenderbim/blenderbim/tool/spatial.py index 1344e51091..21b417acdb 100644 --- a/src/blenderbim/blenderbim/tool/spatial.py +++ b/src/blenderbim/blenderbim/tool/spatial.py @@ -866,3 +866,18 @@ class Spatial(blenderbim.core.tool.Spatial): if (element := tool.Ifc.get_entity(obj)) and tool.Root.is_spatial_element(element): results.append(element) return results + + @classmethod + def get_selected_objects_without_containers(cls) -> list[bpy.types.Object]: + """Get selected objects skipping spatial elements. + + Useful for operators that are using selected objects to identify selected containers. + Note that those operators are typically have a limitation since they can't tell + objects to operate on from containers that should be used in the operation. + + E.g. we cannot bim.copy_to_container containers to other containers.""" + results: list[bpy.types.Object] = [] + for obj in tool.Blender.get_selected_objects(): + if (element := tool.Ifc.get_entity(obj)) and not tool.Root.is_spatial_element(element): + results.append(obj) + return results diff --git a/src/blenderbim/test/bim/feature/spatial.feature b/src/blenderbim/test/bim/feature/spatial.feature index 6672a525f1..0b3718f511 100644 --- a/src/blenderbim/test/bim/feature/spatial.feature +++ b/src/blenderbim/test/bim/feature/spatial.feature @@ -38,10 +38,10 @@ Scenario: Copy to container And I set "scene.BIMRootProperties.ifc_product" to "IfcElement" And I set "scene.BIMRootProperties.ifc_class" to "IfcWall" And I press "bim.assign_class" - And the object "IfcWall/Cube" is selected + And the object "IfcSite/My Site" is selected + And additionally the object "IfcWall/Cube" is selected And I press "bim.enable_editing_container" - When I set "scene.BIMSpatialProperties.containers[0].is_selected" to "True" - And I press "bim.copy_to_container" + When I press "bim.copy_to_container" Then the object "IfcWall/Cube.001" is in the collection "IfcSite/My Site" Scenario: Reference structure