mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-27 18:57:17 +00:00
Fix bug where copying a type also copied its type relations which is invalid.
This commit is contained in:
@@ -508,6 +508,7 @@ class OverridePasteBuffer(bpy.types.Operator):
|
|||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
bpy.ops.view3d.pastebuffer()
|
bpy.ops.view3d.pastebuffer()
|
||||||
for obj in context.selected_objects:
|
if IfcStore.get_file():
|
||||||
blenderbim.core.root.copy_class(tool.Ifc, tool.Collector, tool.Geometry, tool.Root, obj=obj)
|
for obj in context.selected_objects:
|
||||||
|
blenderbim.core.root.copy_class(tool.Ifc, tool.Collector, tool.Geometry, tool.Root, obj=obj)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|||||||
@@ -170,10 +170,10 @@ class AssignClass(bpy.types.Operator):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if product.is_a("IfcElementType"):
|
if product.is_a("IfcElementType"):
|
||||||
self.place_in_types_collection(obj, context)
|
tool.Collector.assign(obj)
|
||||||
elif product.is_a("IfcOpeningElement"):
|
elif product.is_a("IfcOpeningElement"):
|
||||||
obj.display_type = "WIRE"
|
obj.display_type = "WIRE"
|
||||||
self.place_in_openings_collection(obj, context)
|
tool.Collector.assign(obj)
|
||||||
elif (
|
elif (
|
||||||
product.is_a("IfcSpatialElement")
|
product.is_a("IfcSpatialElement")
|
||||||
or product.is_a("IfcSpatialStructureElement")
|
or product.is_a("IfcSpatialStructureElement")
|
||||||
@@ -190,30 +190,6 @@ class AssignClass(bpy.types.Operator):
|
|||||||
self.assign_potential_spatial_container(obj)
|
self.assign_potential_spatial_container(obj)
|
||||||
context.view_layer.objects.active = obj
|
context.view_layer.objects.active = obj
|
||||||
|
|
||||||
def place_in_types_collection(self, obj, context):
|
|
||||||
for project in [c for c in context.view_layer.layer_collection.children if "IfcProject" in c.name]:
|
|
||||||
if not [c for c in project.children if "Types" in c.name]:
|
|
||||||
types = bpy.data.collections.new("Types")
|
|
||||||
project.collection.children.link(types)
|
|
||||||
for collection in [c for c in project.children if "Types" in c.name]:
|
|
||||||
for user_collection in obj.users_collection:
|
|
||||||
user_collection.objects.unlink(obj)
|
|
||||||
collection.collection.objects.link(obj)
|
|
||||||
break
|
|
||||||
break
|
|
||||||
|
|
||||||
def place_in_openings_collection(self, obj, context):
|
|
||||||
for project in [c for c in context.view_layer.layer_collection.children if "IfcProject" in c.name]:
|
|
||||||
if not [c for c in project.children if "IfcOpeningElements" in c.name]:
|
|
||||||
opening_elements = bpy.data.collections.new("IfcOpeningElements")
|
|
||||||
project.collection.children.link(opening_elements)
|
|
||||||
for collection in [c for c in project.children if "IfcOpeningElements" in c.name]:
|
|
||||||
for user_collection in obj.users_collection:
|
|
||||||
user_collection.objects.unlink(obj)
|
|
||||||
collection.collection.objects.link(obj)
|
|
||||||
break
|
|
||||||
break
|
|
||||||
|
|
||||||
def place_in_spatial_collection(self, obj, context):
|
def place_in_spatial_collection(self, obj, context):
|
||||||
for collection in obj.users_collection:
|
for collection in obj.users_collection:
|
||||||
if collection.name == obj.name:
|
if collection.name == obj.name:
|
||||||
@@ -229,7 +205,7 @@ class AssignClass(bpy.types.Operator):
|
|||||||
parent_collection.children.link(collection)
|
parent_collection.children.link(collection)
|
||||||
blenderbim.core.aggregate.assign_object(
|
blenderbim.core.aggregate.assign_object(
|
||||||
tool.Ifc,
|
tool.Ifc,
|
||||||
tool.Aggregator,
|
tool.Aggregate,
|
||||||
tool.Collector,
|
tool.Collector,
|
||||||
relating_obj=bpy.data.objects.get(parent_collection.name),
|
relating_obj=bpy.data.objects.get(parent_collection.name),
|
||||||
related_obj=obj,
|
related_obj=obj,
|
||||||
|
|||||||
@@ -79,6 +79,22 @@ class Collector(blenderbim.core.tool.Collector):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _get_collection(cls, element, obj):
|
def _get_collection(cls, element, obj):
|
||||||
|
if element.is_a("IfcTypeObject"):
|
||||||
|
collection = bpy.data.collections.get("Types")
|
||||||
|
if not collection:
|
||||||
|
collection = bpy.data.collections.new("Types")
|
||||||
|
project_obj = tool.Ifc.get_object(tool.Ifc.get().by_type("IfcProject")[0])
|
||||||
|
project_obj.users_collection[0].children.link(collection)
|
||||||
|
return collection
|
||||||
|
|
||||||
|
if element.is_a("IfcOpeningElement"):
|
||||||
|
collection = bpy.data.collections.get("IfcOpeningElements")
|
||||||
|
if not collection:
|
||||||
|
collection = bpy.data.collections.new("IfcOpeningElements")
|
||||||
|
project_obj = tool.Ifc.get_object(tool.Ifc.get().by_type("IfcProject")[0])
|
||||||
|
project_obj.users_collection[0].children.link(collection)
|
||||||
|
return collection
|
||||||
|
|
||||||
aggregate = ifcopenshell.util.element.get_aggregate(element)
|
aggregate = ifcopenshell.util.element.get_aggregate(element)
|
||||||
if aggregate:
|
if aggregate:
|
||||||
aggregate_obj = tool.Ifc.get_object(aggregate)
|
aggregate_obj = tool.Ifc.get_object(aggregate)
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ Scenario: Assign a type class to a cube
|
|||||||
Then the object "IfcWallType/Cube" is an "IfcWallType"
|
Then the object "IfcWallType/Cube" is an "IfcWallType"
|
||||||
And the object "IfcWallType/Cube" is in the collection "Types"
|
And the object "IfcWallType/Cube" is in the collection "Types"
|
||||||
And the object "IfcWallType/Cube" has a "Tessellation" representation of "Model/Body/MODEL_VIEW"
|
And the object "IfcWallType/Cube" has a "Tessellation" representation of "Model/Body/MODEL_VIEW"
|
||||||
|
|
||||||
Scenario: Assign a spatial class to a cube
|
Scenario: Assign a spatial class to a cube
|
||||||
Given an empty IFC project
|
Given an empty IFC project
|
||||||
And I add a cube
|
And I add a cube
|
||||||
@@ -56,6 +56,19 @@ Scenario: Assign a spatial class to a cube
|
|||||||
And the object "IfcBuilding/Cube" is in the collection "IfcBuilding/Cube"
|
And the object "IfcBuilding/Cube" is in the collection "IfcBuilding/Cube"
|
||||||
And the object "IfcBuilding/Cube" has a "Tessellation" representation of "Model/Body/MODEL_VIEW"
|
And the object "IfcBuilding/Cube" has a "Tessellation" representation of "Model/Body/MODEL_VIEW"
|
||||||
|
|
||||||
|
Scenario: Assign a spatial class to a cube already in a collection
|
||||||
|
Given an empty IFC project
|
||||||
|
And I add a cube
|
||||||
|
And the object "Cube" is placed in the collection "IfcBuildingStorey/My Storey"
|
||||||
|
When the object "Cube" is selected
|
||||||
|
And I set "scene.BIMRootProperties.ifc_product" to "IfcSpatialElement"
|
||||||
|
And I set "scene.BIMRootProperties.ifc_class" to "IfcSpace"
|
||||||
|
And I press "bim.assign_class"
|
||||||
|
Then the object "IfcSpace/Cube" is an "IfcSpace"
|
||||||
|
And the object "IfcSpace/Cube" is in the collection "IfcSpace/Cube"
|
||||||
|
And the collection "IfcSpace/Cube" is in the collection "IfcBuildingStorey/My Storey"
|
||||||
|
And the object "IfcSpace/Cube" has a "Tessellation" representation of "Model/Body/MODEL_VIEW"
|
||||||
|
|
||||||
Scenario: Assign an opening class to a cube
|
Scenario: Assign an opening class to a cube
|
||||||
Given an empty IFC project
|
Given an empty IFC project
|
||||||
And I add a cube
|
And I add a cube
|
||||||
|
|||||||
@@ -133,6 +133,7 @@ def the_object_name_is_selected(name):
|
|||||||
additionally_the_object_name_is_selected(name)
|
additionally_the_object_name_is_selected(name)
|
||||||
|
|
||||||
|
|
||||||
|
@given(parsers.parse('the object "{name}" is placed in the collection "{collection}"'))
|
||||||
@when(parsers.parse('the object "{name}" is placed in the collection "{collection}"'))
|
@when(parsers.parse('the object "{name}" is placed in the collection "{collection}"'))
|
||||||
def the_object_name_is_placed_in_the_collection_collection(name, collection):
|
def the_object_name_is_placed_in_the_collection_collection(name, collection):
|
||||||
obj = the_object_name_exists(name)
|
obj = the_object_name_exists(name)
|
||||||
|
|||||||
@@ -158,3 +158,23 @@ class TestAssign(NewFile):
|
|||||||
)
|
)
|
||||||
subject.assign(subelement_obj)
|
subject.assign(subelement_obj)
|
||||||
assert subelement_obj.users_collection[0].name == "IfcSite/My Site"
|
assert subelement_obj.users_collection[0].name == "IfcSite/My Site"
|
||||||
|
|
||||||
|
def test_in_decomposition_mode_types_are_placed_in_the_types_collection(self):
|
||||||
|
bpy.ops.bim.create_project()
|
||||||
|
element_obj = bpy.data.objects.new("IfcWallType/Name", None)
|
||||||
|
element = tool.Ifc.get().createIfcWallType()
|
||||||
|
tool.Ifc.link(element, element_obj)
|
||||||
|
bpy.context.scene.collection.objects.link(element_obj)
|
||||||
|
subject.assign(element_obj)
|
||||||
|
assert element_obj.users_collection[0].name == "Types"
|
||||||
|
assert bpy.data.collections.get("IfcProject/My Project").children.get("Types")
|
||||||
|
|
||||||
|
def test_in_decomposition_mode_openings_are_placed_in_the_openings_collection(self):
|
||||||
|
bpy.ops.bim.create_project()
|
||||||
|
element_obj = bpy.data.objects.new("IfcOpeningElement/Name", None)
|
||||||
|
element = tool.Ifc.get().createIfcOpeningElement()
|
||||||
|
tool.Ifc.link(element, element_obj)
|
||||||
|
bpy.context.scene.collection.objects.link(element_obj)
|
||||||
|
subject.assign(element_obj)
|
||||||
|
assert element_obj.users_collection[0].name == "IfcOpeningElements"
|
||||||
|
assert bpy.data.collections.get("IfcProject/My Project").children.get("IfcOpeningElements")
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ class Usecase:
|
|||||||
continue
|
continue
|
||||||
elif inverse.is_a("IfcRelContainedInSpatialStructure") and inverse.RelatingStructure == from_element:
|
elif inverse.is_a("IfcRelContainedInSpatialStructure") and inverse.RelatingStructure == from_element:
|
||||||
continue
|
continue
|
||||||
|
elif inverse.is_a("IfcRelDefinesByType") and inverse.RelatingType == from_element:
|
||||||
|
continue
|
||||||
elif inverse.is_a("IfcRelFillsElement"):
|
elif inverse.is_a("IfcRelFillsElement"):
|
||||||
continue
|
continue
|
||||||
elif inverse.is_a("IfcRelAssociatesMaterial") and "Usage" in inverse.RelatingMaterial.is_a():
|
elif inverse.is_a("IfcRelAssociatesMaterial") and "Usage" in inverse.RelatingMaterial.is_a():
|
||||||
|
|||||||
@@ -116,3 +116,10 @@ class TestCopyClass(test.bootstrap.IFC4):
|
|||||||
new = ifcopenshell.api.run("root.copy_class", self.file, product=element)
|
new = ifcopenshell.api.run("root.copy_class", self.file, product=element)
|
||||||
assert new.HasAssociations[0].RelatingMaterial != element.HasAssociations[0].RelatingMaterial
|
assert new.HasAssociations[0].RelatingMaterial != element.HasAssociations[0].RelatingMaterial
|
||||||
assert new.HasAssociations[0].RelatingMaterial.is_a("IfcMaterialLayerSetUsage")
|
assert new.HasAssociations[0].RelatingMaterial.is_a("IfcMaterialLayerSetUsage")
|
||||||
|
|
||||||
|
def test_copying_a_type_and_purging_type_relationships(self):
|
||||||
|
type = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWallType")
|
||||||
|
element = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall")
|
||||||
|
ifcopenshell.api.run("type.assign_type", self.file, related_object=element, relating_type=type)
|
||||||
|
new = ifcopenshell.api.run("root.copy_class", self.file, product=type)
|
||||||
|
assert not new.Types
|
||||||
|
|||||||
Reference in New Issue
Block a user