mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 02:02:22 +00:00
Linked aggregate preserve names (#4135)
* added simples linked aggregate test * small fix in remove_old_connections function * added test for refresh linked aggregate * refresh linked aggregates now preserves the objects original name * small fix in recreate_connections function * tests for Refresh Linked Aggregate * test for Refresh Linked Aggregate after copying an object * small deletion * added custom incremental naming * small fix in tests * small fix on the number for renaming
This commit is contained in:
@@ -21,6 +21,7 @@ import bmesh
|
|||||||
import logging
|
import logging
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import json
|
import json
|
||||||
|
import re
|
||||||
import ifcopenshell
|
import ifcopenshell
|
||||||
import ifcopenshell.util.unit
|
import ifcopenshell.util.unit
|
||||||
import ifcopenshell.util.element
|
import ifcopenshell.util.element
|
||||||
@@ -840,6 +841,7 @@ class OverrideDuplicateMove(bpy.types.Operator):
|
|||||||
|
|
||||||
# Recreate decompositions
|
# Recreate decompositions
|
||||||
tool.Root.recreate_decompositions(decomposition_relationships, old_to_new)
|
tool.Root.recreate_decompositions(decomposition_relationships, old_to_new)
|
||||||
|
OverrideDuplicateMove.handle_linked_aggregates(old_to_new)
|
||||||
blenderbim.bim.handler.refresh_ui_data()
|
blenderbim.bim.handler.refresh_ui_data()
|
||||||
return old_to_new
|
return old_to_new
|
||||||
|
|
||||||
@@ -892,6 +894,26 @@ class OverrideDuplicateMove(bpy.types.Operator):
|
|||||||
if entity in old_to_new.keys():
|
if entity in old_to_new.keys():
|
||||||
core.remove_connection(tool.Geometry, connection=connection)
|
core.remove_connection(tool.Geometry, connection=connection)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def handle_linked_aggregates(old_to_new):
|
||||||
|
for old, new in old_to_new.items():
|
||||||
|
pset = ifcopenshell.util.element.get_pset(new[0], "BBIM_Linked_Aggregate")
|
||||||
|
if pset:
|
||||||
|
old_aggregate = ifcopenshell.util.element.get_aggregate(old)
|
||||||
|
new_aggregate = ifcopenshell.util.element.get_aggregate(new[0])
|
||||||
|
if old_aggregate == new_aggregate:
|
||||||
|
parts = ifcopenshell.util.element.get_parts(new_aggregate)
|
||||||
|
if parts:
|
||||||
|
index = DuplicateMoveLinkedAggregate.get_max_index(parts)
|
||||||
|
index += 1
|
||||||
|
pset = tool.Ifc.get().by_id(pset['id'])
|
||||||
|
ifcopenshell.api.run(
|
||||||
|
"pset.edit_pset",
|
||||||
|
tool.Ifc.get(),
|
||||||
|
pset=pset,
|
||||||
|
properties={"Index": index},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class OverrideDuplicateMoveLinkedMacro(bpy.types.Macro):
|
class OverrideDuplicateMoveLinkedMacro(bpy.types.Macro):
|
||||||
bl_idname = "bim.override_object_duplicate_move_linked_macro"
|
bl_idname = "bim.override_object_duplicate_move_linked_macro"
|
||||||
@@ -950,17 +972,39 @@ class DuplicateMoveLinkedAggregate(bpy.types.Operator):
|
|||||||
obj.select_set(True)
|
obj.select_set(True)
|
||||||
parts = ifcopenshell.util.element.get_parts(element)
|
parts = ifcopenshell.util.element.get_parts(element)
|
||||||
if parts:
|
if parts:
|
||||||
index = 0
|
index = DuplicateMoveLinkedAggregate.get_max_index(parts)
|
||||||
|
add_linked_aggregate_pset(element, index)
|
||||||
|
index +=1
|
||||||
for part in parts:
|
for part in parts:
|
||||||
if part.is_a("IfcElementAssembly"):
|
if part.is_a("IfcElementAssembly"):
|
||||||
select_objects_and_add_data(part)
|
select_objects_and_add_data(part)
|
||||||
|
else:
|
||||||
add_linked_aggregate_pset(part, index)
|
add_linked_aggregate_pset(part, index)
|
||||||
index += 1
|
index += 1
|
||||||
|
|
||||||
obj = tool.Ifc.get_object(part)
|
obj = tool.Ifc.get_object(part)
|
||||||
obj.select_set(True)
|
obj.select_set(True)
|
||||||
|
|
||||||
|
|
||||||
|
def add_linked_aggregate_pset(part, index):
|
||||||
|
pset = ifcopenshell.util.element.get_pset(part, self.pset_name)
|
||||||
|
|
||||||
|
if not pset:
|
||||||
|
pset = ifcopenshell.api.run(
|
||||||
|
"pset.add_pset", tool.Ifc.get(), product=part, name=self.pset_name
|
||||||
|
)
|
||||||
|
|
||||||
|
ifcopenshell.api.run(
|
||||||
|
"pset.edit_pset",
|
||||||
|
tool.Ifc.get(),
|
||||||
|
pset=pset,
|
||||||
|
properties={"Index": index},
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return index
|
||||||
|
|
||||||
def add_linked_aggregate_group(element):
|
def add_linked_aggregate_group(element):
|
||||||
linked_aggregate_group = None
|
linked_aggregate_group = None
|
||||||
product_groups_name = [
|
product_groups_name = [
|
||||||
@@ -974,22 +1018,29 @@ class DuplicateMoveLinkedAggregate(bpy.types.Operator):
|
|||||||
linked_aggregate_group = ifcopenshell.api.run("group.add_group", tool.Ifc.get(), Name=self.group_name)
|
linked_aggregate_group = ifcopenshell.api.run("group.add_group", tool.Ifc.get(), Name=self.group_name)
|
||||||
ifcopenshell.api.run("group.assign_group", tool.Ifc.get(), products=[element], group=linked_aggregate_group)
|
ifcopenshell.api.run("group.assign_group", tool.Ifc.get(), products=[element], group=linked_aggregate_group)
|
||||||
|
|
||||||
def add_linked_aggregate_pset(part, index):
|
def custom_incremental_naming_for_element_assembly(old_to_new):
|
||||||
pset = ifcopenshell.util.element.get_pset(part, self.pset_name)
|
for new in old_to_new.values():
|
||||||
|
if new[0].is_a("IfcElementAssembly"):
|
||||||
|
group_elements = [
|
||||||
|
r.RelatedObjects
|
||||||
|
for r in getattr(new[0], "HasAssignments", []) or []
|
||||||
|
if r.is_a("IfcRelAssignsToGroup")
|
||||||
|
if "BBIM_Linked_Aggregate" in r.RelatingGroup.Name
|
||||||
|
][0]
|
||||||
|
|
||||||
if not pset:
|
number = len(group_elements) - 1
|
||||||
pset = ifcopenshell.api.run("pset.add_pset", tool.Ifc.get(), product=part, name=self.pset_name)
|
number = f"{number:02d}"
|
||||||
else:
|
new_obj = tool.Ifc.get_object(new[0])
|
||||||
pset = tool.Ifc.get().by_id(pset["id"])
|
pattern1 = r'_\d'
|
||||||
|
if re.findall(pattern1, new_obj.name):
|
||||||
|
split_name = new_obj.name.split("_")
|
||||||
|
new_obj.name = split_name[0] + "_" + number
|
||||||
|
continue
|
||||||
|
pattern2 = r'\.\d{3}'
|
||||||
|
if re.findall(pattern2, new_obj.name):
|
||||||
|
split_name = new_obj.name.split(".")
|
||||||
|
new_obj.name = split_name[0] + "_" + number
|
||||||
|
|
||||||
ifcopenshell.api.run(
|
|
||||||
"pset.edit_pset",
|
|
||||||
tool.Ifc.get(),
|
|
||||||
pset=pset,
|
|
||||||
properties={"Index": index},
|
|
||||||
)
|
|
||||||
|
|
||||||
return index
|
|
||||||
|
|
||||||
if len(context.selected_objects) != 1:
|
if len(context.selected_objects) != 1:
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
@@ -1011,6 +1062,8 @@ class DuplicateMoveLinkedAggregate(bpy.types.Operator):
|
|||||||
|
|
||||||
old_to_new = OverrideDuplicateMove.execute_ifc_duplicate_operator(self, context, linked=True)
|
old_to_new = OverrideDuplicateMove.execute_ifc_duplicate_operator(self, context, linked=True)
|
||||||
|
|
||||||
|
custom_incremental_naming_for_element_assembly(old_to_new)
|
||||||
|
|
||||||
# Recreate aggregate relationship
|
# Recreate aggregate relationship
|
||||||
for old in old_to_new.keys():
|
for old in old_to_new.keys():
|
||||||
if old.is_a("IfcElementAssembly"):
|
if old.is_a("IfcElementAssembly"):
|
||||||
@@ -1021,6 +1074,18 @@ class DuplicateMoveLinkedAggregate(bpy.types.Operator):
|
|||||||
return old_to_new
|
return old_to_new
|
||||||
|
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_max_index(parts):
|
||||||
|
psets = [ifcopenshell.util.element.get_pset(p, "BBIM_Linked_Aggregate") for p in parts]
|
||||||
|
index = [i['Index'] for i in psets if i]
|
||||||
|
if len(index) > 0:
|
||||||
|
index = max(index)
|
||||||
|
return index
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class RefreshLinkedAggregate(bpy.types.Operator):
|
class RefreshLinkedAggregate(bpy.types.Operator):
|
||||||
bl_idname = "bim.refresh_linked_aggregate"
|
bl_idname = "bim.refresh_linked_aggregate"
|
||||||
bl_label = "IFC Refresh Linked Aggregate"
|
bl_label = "IFC Refresh Linked Aggregate"
|
||||||
@@ -1044,6 +1109,7 @@ class RefreshLinkedAggregate(bpy.types.Operator):
|
|||||||
self.pset_name = "BBIM_Linked_Aggregate"
|
self.pset_name = "BBIM_Linked_Aggregate"
|
||||||
refresh_start_time = time()
|
refresh_start_time = time()
|
||||||
old_to_new = {}
|
old_to_new = {}
|
||||||
|
original_names = {}
|
||||||
|
|
||||||
def delete_objects(element):
|
def delete_objects(element):
|
||||||
parts = ifcopenshell.util.element.get_parts(element)
|
parts = ifcopenshell.util.element.get_parts(element)
|
||||||
@@ -1056,6 +1122,61 @@ class RefreshLinkedAggregate(bpy.types.Operator):
|
|||||||
|
|
||||||
tool.Geometry.delete_ifc_object(tool.Ifc.get_object(element))
|
tool.Geometry.delete_ifc_object(tool.Ifc.get_object(element))
|
||||||
|
|
||||||
|
def get_original_names(element):
|
||||||
|
group = [
|
||||||
|
r.RelatingGroup
|
||||||
|
for r in getattr(element, "HasAssignments", []) or []
|
||||||
|
if r.is_a("IfcRelAssignsToGroup")
|
||||||
|
if self.group_name in r.RelatingGroup.Name
|
||||||
|
][0].id()
|
||||||
|
original_names[group] = {}
|
||||||
|
|
||||||
|
pset = ifcopenshell.util.element.get_pset(element, self.pset_name)
|
||||||
|
index = pset['Index']
|
||||||
|
original_names[group][index] = tool.Ifc.get_object(element).name
|
||||||
|
|
||||||
|
parts = ifcopenshell.util.element.get_parts(element)
|
||||||
|
if parts:
|
||||||
|
for part in parts:
|
||||||
|
if part.is_a("IfcElementAssembly"):
|
||||||
|
original_names | get_original_names(part)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
pset = ifcopenshell.util.element.get_pset(part, self.pset_name)
|
||||||
|
except:
|
||||||
|
continue
|
||||||
|
index = pset['Index']
|
||||||
|
original_names[group][index] = tool.Ifc.get_object(part).name
|
||||||
|
|
||||||
|
return original_names
|
||||||
|
|
||||||
|
def set_original_name(obj, original_names):
|
||||||
|
element = tool.Ifc.get_entity(obj)
|
||||||
|
aggregate = ifcopenshell.util.element.get_aggregate(element)
|
||||||
|
if ifcopenshell.util.element.get_parts(element): # if element has parts it means it is the base of and aggregate or sub-aggregate
|
||||||
|
aggregate = element
|
||||||
|
|
||||||
|
group = [
|
||||||
|
r.RelatingGroup
|
||||||
|
for r in getattr(aggregate, "HasAssignments", []) or []
|
||||||
|
if r.is_a("IfcRelAssignsToGroup")
|
||||||
|
if self.group_name in r.RelatingGroup.Name
|
||||||
|
]
|
||||||
|
if not group:
|
||||||
|
return
|
||||||
|
|
||||||
|
group = group[0].id()
|
||||||
|
|
||||||
|
pset = ifcopenshell.util.element.get_pset(element, self.pset_name)
|
||||||
|
index = pset['Index']
|
||||||
|
|
||||||
|
try:
|
||||||
|
obj.name = original_names[group][index]
|
||||||
|
except:
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_element_assembly(element):
|
def get_element_assembly(element):
|
||||||
if element.is_a("IfcElementAssembly"):
|
if element.is_a("IfcElementAssembly"):
|
||||||
return element
|
return element
|
||||||
@@ -1141,6 +1262,8 @@ class RefreshLinkedAggregate(bpy.types.Operator):
|
|||||||
object_duplicate = tool.Ifc.get_object(element)
|
object_duplicate = tool.Ifc.get_object(element)
|
||||||
duplicate_matrix = object_duplicate.matrix_world.decompose()
|
duplicate_matrix = object_duplicate.matrix_world.decompose()
|
||||||
|
|
||||||
|
original_names = get_original_names(element)
|
||||||
|
|
||||||
delete_objects(element)
|
delete_objects(element)
|
||||||
|
|
||||||
for obj in context.selected_objects:
|
for obj in context.selected_objects:
|
||||||
@@ -1156,17 +1279,22 @@ class RefreshLinkedAggregate(bpy.types.Operator):
|
|||||||
new_obj_matrix = new_base_matrix @ matrix_diff
|
new_obj_matrix = new_base_matrix @ matrix_diff
|
||||||
new_obj.matrix_world = new_obj_matrix
|
new_obj.matrix_world = new_obj_matrix
|
||||||
|
|
||||||
|
for old, new in old_to_new.items():
|
||||||
if element_aggregate and new[0].is_a("IfcElementAssembly"):
|
if element_aggregate and new[0].is_a("IfcElementAssembly"):
|
||||||
new_aggregate = ifcopenshell.util.element.get_aggregate(new[0])
|
new_aggregate = ifcopenshell.util.element.get_aggregate(new[0])
|
||||||
|
|
||||||
if not new_aggregate:
|
if not new_aggregate:
|
||||||
blenderbim.core.aggregate.assign_object(
|
blenderbim.core.aggregate.assign_object(
|
||||||
tool.Ifc,
|
tool.Ifc,
|
||||||
tool.Aggregate,
|
tool.Aggregate,
|
||||||
tool.Collector,
|
tool.Collector,
|
||||||
relating_obj=tool.Ifc.get_object(element_aggregate),
|
relating_obj=tool.Ifc.get_object(element_aggregate),
|
||||||
related_obj=tool.Ifc.get_object(new[0]),
|
related_obj=tool.Ifc.get_object(new[0]),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
for old, new in old_to_new.items():
|
||||||
|
new_obj = tool.Ifc.get_object(new[0])
|
||||||
|
set_original_name(new_obj, original_names)
|
||||||
|
|
||||||
blenderbim.bim.handler.refresh_ui_data()
|
blenderbim.bim.handler.refresh_ui_data()
|
||||||
|
|
||||||
|
|||||||
@@ -220,8 +220,11 @@ class Root(blenderbim.core.tool.Root):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def recreate_connections(cls, relationship, old_to_new):
|
def recreate_connections(cls, relationship, old_to_new):
|
||||||
for element, data in relationship.items():
|
for element, data in relationship.items():
|
||||||
new_relating_element = old_to_new.get(data["relating_element"])[0]
|
try:
|
||||||
new_related_element = old_to_new.get(data["related_element"])[0]
|
new_relating_element = old_to_new.get(data["relating_element"])[0]
|
||||||
|
new_related_element = old_to_new.get(data["related_element"])[0]
|
||||||
|
except:
|
||||||
|
continue
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"geometry.connect_path",
|
"geometry.connect_path",
|
||||||
tool.Ifc.get(),
|
tool.Ifc.get(),
|
||||||
|
|||||||
@@ -552,3 +552,58 @@ Scenario: Override paste buffer - with active IFC data
|
|||||||
And the object "IfcWall/Cube.001" has a "Tessellation" representation of "Model/Body/MODEL_VIEW"
|
And the object "IfcWall/Cube.001" has a "Tessellation" representation of "Model/Body/MODEL_VIEW"
|
||||||
And the object "IfcBuildingStorey/My Storey.001" exists
|
And the object "IfcBuildingStorey/My Storey.001" exists
|
||||||
And the object "IfcBuildingStorey/My Storey.001" is an "IfcBuildingStorey"
|
And the object "IfcBuildingStorey/My Storey.001" is an "IfcBuildingStorey"
|
||||||
|
|
||||||
|
Scenario: Duplicate linked aggregate
|
||||||
|
Given I load the IFC test file "/test/files/linked-aggregates.ifc"
|
||||||
|
And the object "IfcWall/Wall_01" is selected
|
||||||
|
When I duplicate linked aggregate the selected objects
|
||||||
|
Then the object "IfcWall/Wall_01.001" exists
|
||||||
|
And the object "IfcWall/Wall_02.001" exists
|
||||||
|
And the object "IfcElementAssembly/Assembly_02" exists
|
||||||
|
Then the object "IfcElementAssembly/Assembly" and "IfcElementAssembly/Assembly_02" belong to the same Linked Aggregate Group
|
||||||
|
|
||||||
|
Scenario: Refresh linked aggregate
|
||||||
|
Given I load the IFC test file "/test/files/linked-aggregates.ifc"
|
||||||
|
And the object "IfcWall/Wall_01" is selected
|
||||||
|
When I duplicate linked aggregate the selected objects
|
||||||
|
Then the object "IfcWall/Wall_01.001" exists
|
||||||
|
When I deselect all objects
|
||||||
|
And the object "IfcWall/Wall_01.001" is selected
|
||||||
|
When the object layer length is set to "3"
|
||||||
|
Then the object "IfcWall/Wall_01.001" dimensions are "3,0.1,3"
|
||||||
|
When I refresh linked aggregate the selected object
|
||||||
|
Then the object "IfcWall/Wall_01" exists
|
||||||
|
And the object "IfcWall/Wall_01" dimensions are "3,0.1,3"
|
||||||
|
|
||||||
|
Scenario: Refresh linked aggregate - after deleting an object
|
||||||
|
Given I load the IFC test file "/test/files/linked-aggregates.ifc"
|
||||||
|
And the object "IfcWall/Wall_01" is selected
|
||||||
|
When I duplicate linked aggregate the selected objects
|
||||||
|
Then the object "IfcWall/Wall_01.001" exists
|
||||||
|
When I deselect all objects
|
||||||
|
And the object "IfcWall/Wall_01.001" is selected
|
||||||
|
And I delete the selected objects
|
||||||
|
When I deselect all objects
|
||||||
|
And the object "IfcWall/Wall_02.001" is selected
|
||||||
|
When I refresh linked aggregate the selected object
|
||||||
|
Then the object "IfcWall/Wall_01" does not exist
|
||||||
|
And the object "IfcWall/Wall_02" exists
|
||||||
|
|
||||||
|
Scenario: Refresh linked aggregate - after duplicating an object
|
||||||
|
Given I load the IFC test file "/test/files/linked-aggregates.ifc"
|
||||||
|
And the object "IfcWall/Wall_01" is selected
|
||||||
|
When I duplicate linked aggregate the selected objects
|
||||||
|
Then the object "IfcWall/Wall_01.001" exists
|
||||||
|
And the object "IfcWall/Wall_02.001" exists
|
||||||
|
When I deselect all objects
|
||||||
|
And the object "IfcWall/Wall_01" is selected
|
||||||
|
When I duplicate the selected objects
|
||||||
|
Then the object "IfcWall/Wall_01.002" exists
|
||||||
|
When I rename the object "IfcWall/Wall_01.002" to "IfcWall/Wall_03"
|
||||||
|
And I deselect all objects
|
||||||
|
And the object "IfcWall/Wall_03" is selected
|
||||||
|
When I refresh linked aggregate the selected object
|
||||||
|
Then the object "IfcWall/Wall_01.001" exists
|
||||||
|
And the object "IfcWall/Wall_02.001" exists
|
||||||
|
And the object "IfcWall/Wall_03.001" exists
|
||||||
|
|
||||||
|
|||||||
@@ -234,6 +234,16 @@ def i_duplicate_the_selected_objects():
|
|||||||
bpy.ops.bim.override_object_duplicate_move()
|
bpy.ops.bim.override_object_duplicate_move()
|
||||||
blenderbim.bim.handler.active_object_callback()
|
blenderbim.bim.handler.active_object_callback()
|
||||||
|
|
||||||
|
@when("I duplicate linked aggregate the selected objects")
|
||||||
|
def i_duplicate_the_selected_objects():
|
||||||
|
bpy.ops.bim.object_duplicate_move_linked_aggregate()
|
||||||
|
blenderbim.bim.handler.active_object_callback()
|
||||||
|
|
||||||
|
@when("I refresh linked aggregate the selected object")
|
||||||
|
def i_refresh_the_selected_objects():
|
||||||
|
bpy.ops.bim.refresh_linked_aggregate()
|
||||||
|
blenderbim.bim.handler.active_object_callback()
|
||||||
|
|
||||||
|
|
||||||
@when("I deselect all objects")
|
@when("I deselect all objects")
|
||||||
def i_deselect_all_objects():
|
def i_deselect_all_objects():
|
||||||
@@ -360,6 +370,13 @@ def the_object_name_exists(name) -> bpy.types.Object:
|
|||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
|
||||||
|
@then(parsers.parse('the object "{name}" does not exist'))
|
||||||
|
def the_object_name_does_not_exist(name) -> bpy.types.Object:
|
||||||
|
obj = bpy.data.objects.get(name)
|
||||||
|
if not obj:
|
||||||
|
assert True, f'The object "{name}" exists'
|
||||||
|
return obj
|
||||||
|
|
||||||
@given(parsers.parse('the collection "{name}" exists'))
|
@given(parsers.parse('the collection "{name}" exists'))
|
||||||
@when(parsers.parse('the collection "{name}" exists'))
|
@when(parsers.parse('the collection "{name}" exists'))
|
||||||
@then(parsers.parse('the collection "{name}" exists'))
|
@then(parsers.parse('the collection "{name}" exists'))
|
||||||
@@ -774,6 +791,10 @@ def the_file_name_should_contain_value(name, value):
|
|||||||
def the_object_name_has_no_modifiers(name):
|
def the_object_name_has_no_modifiers(name):
|
||||||
assert len(the_object_name_exists(name).modifiers) == 0
|
assert len(the_object_name_exists(name).modifiers) == 0
|
||||||
|
|
||||||
|
@given(parsers.parse('I load the IFC test file "{filepath}"'))
|
||||||
|
def i_load_the_ifc_test_file(filepath):
|
||||||
|
filepath = f"{variables['cwd']}{filepath}"
|
||||||
|
bpy.ops.bim.load_project(filepath=filepath, use_relative_path=True)
|
||||||
|
|
||||||
@given("I load the demo construction library")
|
@given("I load the demo construction library")
|
||||||
@when("I load the demo construction library")
|
@when("I load the demo construction library")
|
||||||
@@ -826,6 +847,64 @@ def hit_undo():
|
|||||||
bpy.ops.ed.undo_push(message="UNDO STEP")
|
bpy.ops.ed.undo_push(message="UNDO STEP")
|
||||||
bpy.ops.ed.undo()
|
bpy.ops.ed.undo()
|
||||||
|
|
||||||
|
@then(parsers.parse('the object "{obj_name1}" has a connection with "{obj_name2}"'))
|
||||||
|
def the_obj1_has_a_connection_with_obj2(obj_name1, obj_name2):
|
||||||
|
element1 = replace_variables(obj_name1)
|
||||||
|
element1 = tool.Ifc.get_entity(the_object_name_exists(element1))
|
||||||
|
element2 = replace_variables(obj_name2)
|
||||||
|
element2 = tool.Ifc.get_entity(the_object_name_exists(element2))
|
||||||
|
connections = []
|
||||||
|
if hasattr(element1, "ConnectedTo") and element1.ConnectedTo:
|
||||||
|
connections = [connection for connection in element1.ConnectedTo]
|
||||||
|
elif hasattr(element1, "ConnectedFrom") and element1.ConnectedFrom:
|
||||||
|
connections = [connection for connection in element1.ConnectedFrom]
|
||||||
|
else:
|
||||||
|
assert False, f'Object "{obj_name1}" has no connections'
|
||||||
|
|
||||||
|
relationships = {}
|
||||||
|
for conn in connections:
|
||||||
|
relationships[conn.RelatedElement] = conn.RelatingElement
|
||||||
|
|
||||||
|
for key, value in relationships.items():
|
||||||
|
assert (key.id() == element1.id() and value.id() == element2.id()) or (key.id() == element2.id() and value.id() == element1.id()), f"The object {obj_name1} is connected to {obj_name2}"
|
||||||
|
|
||||||
|
|
||||||
|
@then(parsers.parse('the object "{obj_name1}" and "{obj_name2}" belong to the same Linked Aggregate Group'))
|
||||||
|
def the_obj1_and_obj2_belong_the_same_linked_aggregate_group(obj_name1, obj_name2):
|
||||||
|
element1 = replace_variables(obj_name1)
|
||||||
|
element1 = tool.Ifc.get_entity(the_object_name_exists(element1))
|
||||||
|
element2 = replace_variables(obj_name2)
|
||||||
|
element2 = tool.Ifc.get_entity(the_object_name_exists(element2))
|
||||||
|
|
||||||
|
elements = [element1, element2]
|
||||||
|
groups = []
|
||||||
|
for element in elements:
|
||||||
|
product_linked_agg_group = [
|
||||||
|
r.RelatingGroup
|
||||||
|
for r in getattr(element, "HasAssignments", []) or []
|
||||||
|
if r.is_a("IfcRelAssignsToGroup")
|
||||||
|
if "BBIM_Linked_Aggregate" in r.RelatingGroup.Name
|
||||||
|
]
|
||||||
|
try:
|
||||||
|
groups.append(product_linked_agg_group[0].id())
|
||||||
|
except:
|
||||||
|
assert False, "Object is not part of a Linked Aggregate."
|
||||||
|
|
||||||
|
assert groups[0] == groups[1], "Objects do not belong to the same Linked Aggregate group"
|
||||||
|
|
||||||
|
@when(parsers.parse('the object layer length is set to "{value}"'))
|
||||||
|
def the_obj_layer_lenght_is_set_to(value):
|
||||||
|
value = float(value)
|
||||||
|
try:
|
||||||
|
eval(f"bpy.context.scene.BIMModelProperties.length")
|
||||||
|
except:
|
||||||
|
assert False, f"Property BIMModelProperties.length does not exist when trying to set to value {value}"
|
||||||
|
|
||||||
|
print(50*"@", bpy.context.selected_objects)
|
||||||
|
|
||||||
|
bpy.context.scene.BIMModelProperties.length = value
|
||||||
|
bpy.ops.bim.change_layer_length(length=value)
|
||||||
|
|
||||||
|
|
||||||
# These definitions are not to be used in tests but simply in debugging failing tests
|
# These definitions are not to be used in tests but simply in debugging failing tests
|
||||||
|
|
||||||
@@ -875,27 +954,4 @@ def run_pdb():
|
|||||||
|
|
||||||
pdb.set_trace()
|
pdb.set_trace()
|
||||||
|
|
||||||
@then(parsers.parse('the object "{obj_name1}" has a connection with "{obj_name2}"'))
|
|
||||||
def the_obj1_has_a_connection_with_obj2(obj_name1, obj_name2):
|
|
||||||
element1 = replace_variables(obj_name1)
|
|
||||||
element1 = tool.Ifc.get_entity(the_object_name_exists(element1))
|
|
||||||
element2 = replace_variables(obj_name2)
|
|
||||||
element2 = tool.Ifc.get_entity(the_object_name_exists(element2))
|
|
||||||
connections = []
|
|
||||||
if hasattr(element1, "ConnectedTo") and element1.ConnectedTo:
|
|
||||||
connections = [connection for connection in element1.ConnectedTo]
|
|
||||||
elif hasattr(element1, "ConnectedFrom") and element1.ConnectedFrom:
|
|
||||||
connections = [connection for connection in element1.ConnectedFrom]
|
|
||||||
else:
|
|
||||||
assert False, f'Object "{obj_name1}" has no connections'
|
|
||||||
|
|
||||||
|
|
||||||
relationships = {}
|
|
||||||
for conn in connections:
|
|
||||||
relationships[conn.RelatedElement] = conn.RelatingElement
|
|
||||||
|
|
||||||
for key, value in relationships.items():
|
|
||||||
print(key, value)
|
|
||||||
# assert False, f"1-{key} and {element1.id()} and {key.id()}"
|
|
||||||
assert (key.id() == element1.id() and value.id() == element2.id()) or (key.id() == element2.id() and value.id() == element1.id()), f"The object {obj_name1} is connected to {obj_name2}"
|
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user