Fix #3973. Fix #4787. Clarify that you cannot have aggregated physical elements where the whole has a body representation.

This commit is contained in:
Dion Moult
2024-06-03 15:37:24 +10:00
parent 44d180007e
commit 6eb3c48144
4 changed files with 55 additions and 23 deletions
@@ -55,21 +55,24 @@ class BIM_OT_aggregate_assign_object(bpy.types.Operator, Operator):
if not relating_obj: if not relating_obj:
return return
for obj in bpy.context.selected_objects + [bpy.context.active_object]: for obj in tool.Blender.get_selected_objects():
if obj == relating_obj: if obj == relating_obj:
continue continue
element = tool.Ifc.get_entity(obj) element = tool.Ifc.get_entity(obj)
if not element: if not element:
continue continue
result = core.assign_object( try:
tool.Ifc, core.assign_object(
tool.Aggregate, tool.Ifc,
tool.Collector, tool.Aggregate,
relating_obj=relating_obj, tool.Collector,
related_obj=obj, relating_obj=relating_obj,
) related_obj=obj,
if not result: )
self.report({"ERROR"}, f" Cannot aggregate {obj.name} to {relating_obj.name}") except core.IncompatibleAggregateError:
self.report({"ERROR"}, f"Cannot aggregate {obj.name} to {relating_obj.name}")
except core.AggregateRepresentationError:
self.report({"ERROR"}, f"Cannot aggregate to {relating_obj.name} with a body representation")
class BIM_OT_aggregate_unassign_object(bpy.types.Operator, Operator): class BIM_OT_aggregate_unassign_object(bpy.types.Operator, Operator):
+13 -2
View File
@@ -41,9 +41,12 @@ def assign_object(
related_obj: Optional[bpy.types.Object] = None, related_obj: Optional[bpy.types.Object] = None,
) -> Union[ifcopenshell.entity_instance, None]: ) -> Union[ifcopenshell.entity_instance, None]:
if not aggregator.can_aggregate(relating_obj, related_obj): if not aggregator.can_aggregate(relating_obj, related_obj):
return raise IncompatibleAggregateError
relating_object = ifc.get_entity(relating_obj)
if aggregator.has_physical_body_representation(relating_object):
raise AggregateRepresentationError
rel = ifc.run( rel = ifc.run(
"aggregate.assign_object", products=[ifc.get_entity(related_obj)], relating_object=ifc.get_entity(relating_obj) "aggregate.assign_object", products=[ifc.get_entity(related_obj)], relating_object=relating_object
) )
collector.assign(relating_obj) collector.assign(relating_obj)
collector.assign(related_obj) collector.assign(related_obj)
@@ -84,3 +87,11 @@ def add_part_to_object(
part_obj = blender.create_ifc_object(ifc_class=part_class, name=part_name) part_obj = blender.create_ifc_object(ifc_class=part_class, name=part_name)
assign_object(ifc, aggregator, collector, relating_obj=obj, related_obj=part_obj) assign_object(ifc, aggregator, collector, relating_obj=obj, related_obj=part_obj)
blender.set_active_object(obj) blender.set_active_object(obj)
class IncompatibleAggregateError(Exception):
pass
class AggregateRepresentationError(Exception):
pass
+10 -3
View File
@@ -30,9 +30,9 @@ class Aggregate(blenderbim.core.tool.Aggregate):
related_object = tool.Ifc.get_entity(related_obj) related_object = tool.Ifc.get_entity(related_obj)
if not relating_object or not related_object: if not relating_object or not related_object:
return False return False
if (relating_object.is_a("IfcElement") or relating_object.is_a("IfcElementType")) and related_object.is_a("IfcElement"): if (relating_object.is_a("IfcElement") or relating_object.is_a("IfcElementType")) and related_object.is_a(
if relating_obj.data: # See #3973 "IfcElement"
return False ):
return True return True
if tool.Ifc.get_schema() == "IFC2X3": if tool.Ifc.get_schema() == "IFC2X3":
if relating_object.is_a("IfcSpatialStructureElement") and related_object.is_a("IfcSpatialStructureElement"): if relating_object.is_a("IfcSpatialStructureElement") and related_object.is_a("IfcSpatialStructureElement"):
@@ -46,6 +46,13 @@ class Aggregate(blenderbim.core.tool.Aggregate):
return True return True
return False return False
@classmethod
def has_physical_body_representation(cls, element: ifcopenshell.entity_instance) -> bool:
if element.is_a("IfcElement") or element.is_a("IfcElementType"): # See 3973
if ifcopenshell.util.representation.get_representation(element, "Model", "Body"):
return True
return False
@classmethod @classmethod
def disable_editing(cls, obj: bpy.types.Object) -> None: def disable_editing(cls, obj: bpy.types.Object) -> None:
obj.BIMObjectAggregateProperties.is_editing = False obj.BIMObjectAggregateProperties.is_editing = False
+19 -8
View File
@@ -18,6 +18,9 @@
import bpy import bpy
import ifcopenshell import ifcopenshell
import ifcopenshell.api.root
import ifcopenshell.api.unit
import ifcopenshell.api.context
import blenderbim.core.tool import blenderbim.core.tool
import blenderbim.tool as tool import blenderbim.tool as tool
from test.bim.bootstrap import NewFile from test.bim.bootstrap import NewFile
@@ -92,16 +95,24 @@ class TestCanAggregate(NewFile):
subelement_obj = bpy.data.objects.new("Object", None) subelement_obj = bpy.data.objects.new("Object", None)
assert subject.can_aggregate(element_obj, subelement_obj) is False assert subject.can_aggregate(element_obj, subelement_obj) is False
def test_aggregates_with_meshes_are_invalid(self):
class TestHasPhysicalBodyRepresentation(NewFile):
def test_run(self):
ifc = ifcopenshell.file() ifc = ifcopenshell.file()
tool.Ifc.set(ifc)
element = ifc.createIfcElementAssembly() element = ifc.createIfcElementAssembly()
element_obj = bpy.data.objects.new("Object", bpy.data.meshes.new("Mesh")) assert subject.has_physical_body_representation(element) is False
tool.Ifc.link(element, element_obj) ifcopenshell.api.root.create_entity(ifc, ifc_class="IfcProject")
subelement = ifc.createIfcBeam() ifcopenshell.api.unit.assign_unit(ifc)
subelement_obj = bpy.data.objects.new("Object", None) context = ifcopenshell.api.context.add_context(ifc, context_type="Model")
tool.Ifc.link(subelement, subelement_obj) body = ifcopenshell.api.context.add_context(
assert subject.can_aggregate(element_obj, subelement_obj) is False ifc, context_type="Model", context_identifier="Body", target_view="MODEL_VIEW", parent=context
)
builder = ifcopenshell.util.shape_builder.ShapeBuilder(ifc)
origin = builder.create_axis2_placement_3d()
block = ifc.createIfcCsgSolid(ifc.createIfcBlock(origin, 200, 200, 200))
rep = builder.get_representation(context=body, items=[block])
ifcopenshell.api.geometry.assign_representation(ifc, product=element, representation=rep)
assert subject.has_physical_body_representation(element) is True
class TestDisableEditing(NewFile): class TestDisableEditing(NewFile):