mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 02:02:22 +00:00
See #2140. You can now bulk unassign aggregates, and they are auto directly contained in any previous indirect containers.
This commit is contained in:
@@ -34,7 +34,6 @@ class AggregateData:
|
||||
cls.data = {
|
||||
"has_relating_object": cls.has_relating_object(),
|
||||
"relating_object_label": cls.get_relating_object_label(),
|
||||
"relating_object_id": cls.get_relating_object_id(),
|
||||
"has_related_objects": cls.has_related_objects(),
|
||||
"related_objects_amount": cls.get_related_objects_amount(),
|
||||
"ifc_class": cls.ifc_class(),
|
||||
@@ -55,12 +54,6 @@ class AggregateData:
|
||||
if aggregate:
|
||||
return f"{aggregate.is_a()}/{aggregate.Name or ''}"
|
||||
|
||||
@classmethod
|
||||
def get_relating_object_id(cls) -> int:
|
||||
aggregate = cls.get_relating_object()
|
||||
if aggregate:
|
||||
return aggregate.id()
|
||||
|
||||
@classmethod
|
||||
def get_related_objects(cls):
|
||||
return ifcopenshell.util.element.get_parts(tool.Ifc.get_entity(bpy.context.active_object))
|
||||
|
||||
@@ -58,16 +58,22 @@ class BIM_OT_unassign_object(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.unassign_object"
|
||||
bl_label = "Unassign Object"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
relating_object: bpy.props.IntProperty()
|
||||
related_object: bpy.props.IntProperty()
|
||||
|
||||
def _execute(self, context):
|
||||
core.unassign_object(
|
||||
tool.Ifc,
|
||||
tool.Collector,
|
||||
relating_obj=tool.Ifc.get_object(tool.Ifc.get().by_id(self.relating_object)),
|
||||
related_obj=tool.Ifc.get_object(tool.Ifc.get().by_id(self.related_object)),
|
||||
)
|
||||
for obj in bpy.context.selected_objects:
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
if not element:
|
||||
continue
|
||||
aggregate = ifcopenshell.util.element.get_aggregate(element)
|
||||
if not aggregate:
|
||||
continue
|
||||
core.unassign_object(
|
||||
tool.Ifc,
|
||||
tool.Aggregate,
|
||||
tool.Collector,
|
||||
relating_obj=tool.Ifc.get_object(aggregate),
|
||||
related_obj=tool.Ifc.get_object(element),
|
||||
)
|
||||
|
||||
|
||||
class BIM_OT_enable_editing_aggregate(bpy.types.Operator, Operator):
|
||||
|
||||
@@ -67,8 +67,6 @@ class BIM_PT_aggregate(Panel):
|
||||
row.operator("bim.enable_editing_aggregate", icon="GREASEPENCIL", text="")
|
||||
row.operator("bim.add_aggregate", icon="ADD", text="")
|
||||
op = row.operator("bim.unassign_object", icon="X", text="")
|
||||
op.relating_object = AggregateData.data["relating_object_id"]
|
||||
op.related_object = context.active_object.BIMObjectProperties.ifc_definition_id
|
||||
else:
|
||||
row.label(text="No Aggregate", icon="TRIA_UP")
|
||||
row.operator("bim.enable_editing_aggregate", icon="GREASEPENCIL", text="")
|
||||
|
||||
@@ -53,7 +53,7 @@ class AddFilledOpening(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
|
||||
class FilledOpeningGenerator:
|
||||
def generate(self, filling_obj, voided_obj):
|
||||
def generate(self, filling_obj, voided_obj, target=None):
|
||||
props = bpy.context.scene.BIMModelProperties
|
||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||
|
||||
@@ -62,8 +62,14 @@ class FilledOpeningGenerator:
|
||||
if not voided_obj or not filling_obj:
|
||||
return
|
||||
|
||||
if filling.FillsVoids:
|
||||
ifcopenshell.api.run(
|
||||
"void.remove_opening", tool.Ifc.get(), opening=filling.FillsVoids[0].RelatingOpeningElement
|
||||
)
|
||||
|
||||
if target is None:
|
||||
target = bpy.context.scene.cursor.location
|
||||
element = tool.Ifc.get_entity(voided_obj)
|
||||
target = bpy.context.scene.cursor.location
|
||||
raycast = voided_obj.closest_point_on_mesh(voided_obj.matrix_world.inverted() @ target, distance=0.01)
|
||||
if not raycast[0]:
|
||||
target = filling_obj.matrix_world.col[3].to_3d().copy()
|
||||
|
||||
@@ -37,11 +37,14 @@ def assign_object(ifc, aggregator, collector, relating_obj=None, related_obj=Non
|
||||
return rel
|
||||
|
||||
|
||||
def unassign_object(ifc, collector, relating_obj=None, related_obj=None):
|
||||
rel = ifc.run("aggregate.unassign_object", product=ifc.get_entity(related_obj))
|
||||
def unassign_object(ifc, aggregate, collector, relating_obj=None, related_obj=None):
|
||||
related_element = ifc.get_entity(related_obj)
|
||||
container = aggregate.get_container(related_element)
|
||||
ifc.run("aggregate.unassign_object", product=related_element)
|
||||
if container:
|
||||
ifc.run("spatial.assign_container", product=related_element, relating_structure=container)
|
||||
collector.assign(relating_obj)
|
||||
collector.assign(related_obj)
|
||||
return rel
|
||||
|
||||
|
||||
def add_part_to_object(ifc, aggregator, collector, blender, obj, part_class, part_name=None):
|
||||
|
||||
@@ -67,6 +67,7 @@ class Aggregate:
|
||||
def can_aggregate(cls, relating_object, related_object): pass
|
||||
def disable_editing(cls, obj): pass
|
||||
def enable_editing(cls, obj): pass
|
||||
def get_container(cls, element): pass
|
||||
|
||||
|
||||
@interface
|
||||
|
||||
@@ -18,17 +18,10 @@
|
||||
|
||||
import blenderbim.core.tool
|
||||
import blenderbim.tool as tool
|
||||
import ifcopenshell.util.element
|
||||
|
||||
|
||||
class Aggregate(blenderbim.core.tool.Aggregate):
|
||||
@classmethod
|
||||
def enable_editing(cls, obj):
|
||||
obj.BIMObjectAggregateProperties.is_editing = True
|
||||
|
||||
@classmethod
|
||||
def disable_editing(cls, obj):
|
||||
obj.BIMObjectAggregateProperties.is_editing = False
|
||||
|
||||
@classmethod
|
||||
def can_aggregate(cls, relating_obj, related_obj):
|
||||
relating_object = tool.Ifc.get_entity(relating_obj)
|
||||
@@ -50,3 +43,15 @@ class Aggregate(blenderbim.core.tool.Aggregate):
|
||||
if relating_object.is_a("IfcProject") and related_object.is_a("IfcSpatialElement"):
|
||||
return True
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def disable_editing(cls, obj):
|
||||
obj.BIMObjectAggregateProperties.is_editing = False
|
||||
|
||||
@classmethod
|
||||
def enable_editing(cls, obj):
|
||||
obj.BIMObjectAggregateProperties.is_editing = True
|
||||
|
||||
@classmethod
|
||||
def get_container(cls, element):
|
||||
return ifcopenshell.util.element.get_container(element)
|
||||
|
||||
@@ -34,7 +34,7 @@ Scenario: Unassign object
|
||||
And the variable "related_object" is "tool.Ifc.get().by_type('IfcBuildingStorey')[0].id()"
|
||||
And I press "bim.assign_object(relating_object={relating_object}, related_object={related_object})"
|
||||
And the object "IfcBuildingStorey/My Storey" is selected
|
||||
When I press "bim.unassign_object(relating_object={relating_object}, related_object={related_object})"
|
||||
When I press "bim.unassign_object"
|
||||
Then the object "IfcSite/My Site" is in the collection "IfcSite/My Site"
|
||||
And the object "IfcBuildingStorey/My Storey" is in the collection "IfcBuildingStorey/My Storey"
|
||||
And the collection "IfcBuildingStorey/My Storey" is in the collection "IfcProject/My Project"
|
||||
|
||||
@@ -50,9 +50,11 @@ class TestAssignObject:
|
||||
|
||||
|
||||
class TestUnassignObject:
|
||||
def test_run(self, ifc, collector):
|
||||
ifc.get_entity("related_obj").should_be_called().will_return("related_object")
|
||||
ifc.run("aggregate.unassign_object", product="related_object").should_be_called().will_return("rel")
|
||||
def test_run(self, ifc, aggregate, collector):
|
||||
ifc.get_entity("related_obj").should_be_called().will_return("element")
|
||||
aggregate.get_container("element").should_be_called().will_return("container")
|
||||
ifc.run("spatial.assign_container", product="element", relating_structure="container").should_be_called()
|
||||
ifc.run("aggregate.unassign_object", product="element").should_be_called().will_return("rel")
|
||||
collector.assign("relating_obj").should_be_called()
|
||||
collector.assign("related_obj").should_be_called()
|
||||
assert subject.unassign_object(ifc, collector, relating_obj="relating_obj", related_obj="related_obj") == "rel"
|
||||
subject.unassign_object(ifc, aggregate, collector, relating_obj="relating_obj", related_obj="related_obj")
|
||||
|
||||
@@ -29,19 +29,8 @@ class TestImplementsTool(NewFile):
|
||||
assert isinstance(subject(), blenderbim.core.tool.Aggregate)
|
||||
|
||||
|
||||
class TestEnableEditing(NewFile):
|
||||
def test_run(self):
|
||||
obj = bpy.data.objects.new("Object", None)
|
||||
subject.enable_editing(obj)
|
||||
assert obj.BIMObjectAggregateProperties.is_editing is True
|
||||
|
||||
|
||||
class TestDisableEditing(NewFile):
|
||||
def test_run(self):
|
||||
obj = bpy.data.objects.new("Object", None)
|
||||
subject.enable_editing(obj)
|
||||
subject.disable_editing(obj)
|
||||
assert obj.BIMObjectAggregateProperties.is_editing is False
|
||||
|
||||
|
||||
class TestCanAggregate(NewFile):
|
||||
@@ -117,3 +106,27 @@ class TestCanAggregate(NewFile):
|
||||
subelement_obj = bpy.data.objects.new("Object", None)
|
||||
tool.Ifc.link(subelement, subelement_obj)
|
||||
assert subject.can_aggregate(element_obj, subelement_obj) is False
|
||||
|
||||
class TestDisableEditing(NewFile):
|
||||
def test_run(self):
|
||||
obj = bpy.data.objects.new("Object", None)
|
||||
subject.enable_editing(obj)
|
||||
subject.disable_editing(obj)
|
||||
assert obj.BIMObjectAggregateProperties.is_editing is False
|
||||
|
||||
|
||||
class TestEnableEditing(NewFile):
|
||||
def test_run(self):
|
||||
obj = bpy.data.objects.new("Object", None)
|
||||
subject.enable_editing(obj)
|
||||
assert obj.BIMObjectAggregateProperties.is_editing is True
|
||||
|
||||
|
||||
class TestGetContainer(NewFile):
|
||||
def test_run(self):
|
||||
ifc = ifcopenshell.file()
|
||||
tool.Ifc.set(ifc)
|
||||
element = ifc.createIfcWall()
|
||||
container = ifc.createIfcBuildingStorey()
|
||||
ifcopenshell.api.run("spatial.assign_container", ifc, product=element, relating_structure=container)
|
||||
assert subject.get_container(element) == container
|
||||
|
||||
Reference in New Issue
Block a user