Fix bug where assigning a type did not use existing representation data in the scene if the context had changed

This commit is contained in:
Dion Moult
2021-11-06 20:56:53 +11:00
parent 4149292a13
commit 8e215382f7
9 changed files with 99 additions and 66 deletions
@@ -18,11 +18,11 @@ Scenario: Add representation
And I set "scene.BIMRootProperties.ifc_class" to "IfcWall"
And I press "bim.assign_class"
And the object "IfcWall/Cube" is selected
Then the object "IfcWall/Cube" has a "Tessellation" representation of "Model/Body/MODEL_VIEW"
Then the object "IfcWall/Cube" data is a "Tessellation" representation of "Model/Body/MODEL_VIEW"
When the variable "context" is "{ifc}.by_type('IfcGeometricRepresentationSubContext')[-1].id()"
And I set "scene.BIMProperties.contexts" to "{context}"
And I press "bim.add_representation"
Then the object "IfcWall/Cube" has a "Annotation2D" representation of "Plan/Annotation/PLAN_VIEW"
Then the object "IfcWall/Cube" data is a "Annotation2D" representation of "Plan/Annotation/PLAN_VIEW"
Scenario: Add representation - add a new representation to a typed instance
Given an empty IFC project
@@ -33,14 +33,14 @@ Scenario: Add representation - add a new representation to a typed instance
And I press "bim.assign_class"
And I press "bim.add_type_instance"
And I press "bim.add_type_instance"
Then the object "IfcWall/Instance" has a "MappedRepresentation" representation of "Model/Body/MODEL_VIEW"
And the object "IfcWall/Instance.001" has a "MappedRepresentation" representation of "Model/Body/MODEL_VIEW"
Then the object "IfcWall/Instance" data is a "Tessellation" representation of "Model/Body/MODEL_VIEW"
And the object "IfcWall/Instance.001" data is a "Tessellation" representation of "Model/Body/MODEL_VIEW"
When the object "IfcWall/Instance" is selected
And the variable "context" is "{ifc}.by_type('IfcGeometricRepresentationSubContext')[-1].id()"
And I set "scene.BIMProperties.contexts" to "{context}"
And I press "bim.add_representation"
Then the object "IfcWall/Instance" has a "MappedRepresentation" representation of "Plan/Annotation/PLAN_VIEW"
And the object "IfcWall/Instance.001" has a "MappedRepresentation" representation of "Plan/Annotation/PLAN_VIEW"
Then the object "IfcWall/Instance" data is a "Annotation2D" representation of "Plan/Annotation/PLAN_VIEW"
And the object "IfcWall/Instance.001" data is a "Annotation2D" representation of "Plan/Annotation/PLAN_VIEW"
Scenario: Switch representation
Given an empty IFC project
@@ -27,6 +27,27 @@ Scenario: Add type instance - add from an empty
When I press "bim.add_type_instance"
Then the object "IfcWall/Instance" exists
Scenario: Add type instance - add a mesh where existing instances have changed context
Given an empty IFC project
And I add a cube
And the object "Cube" is selected
And I set "scene.BIMRootProperties.ifc_product" to "IfcElementType"
And I set "scene.BIMRootProperties.ifc_class" to "IfcWallType"
And I press "bim.assign_class"
And I set "scene.BIMTypeProperties.ifc_class" to "IfcWallType"
And the variable "cube" is "{ifc}.by_type('IfcWallType')[0].id()"
And I set "scene.BIMTypeProperties.relating_type" to "{cube}"
And I press "bim.add_type_instance"
And the object "IfcWall/Instance" data is a "Tessellation" representation of "Model/Body/MODEL_VIEW"
And the object "IfcWall/Instance" is selected
And the variable "context" is "{ifc}.by_type('IfcGeometricRepresentationSubContext')[-1].id()"
And I set "scene.BIMProperties.contexts" to "{context}"
And I press "bim.add_representation"
And the object "IfcWall/Instance" data is a "Annotation2D" representation of "Plan/Annotation/PLAN_VIEW"
When I press "bim.add_type_instance"
Then the object "IfcWall/Instance" data is a "Annotation2D" representation of "Plan/Annotation/PLAN_VIEW"
And the object "IfcWall/Instance.001" data is a "Annotation2D" representation of "Plan/Annotation/PLAN_VIEW"
Scenario: Add grid
Given an empty IFC project
When I press "mesh.add_grid"
+14
View File
@@ -228,6 +228,7 @@ def the_object_name_has_a_body_of_value(name, value):
assert the_object_name_exists(name).data.body == value
@given(parsers.parse('the object "{name}" has a "{type}" representation of "{context}"'))
@then(parsers.parse('the object "{name}" has a "{type}" representation of "{context}"'))
def the_object_name_has_a_representation_type_of_context(name, type, context):
ifc = an_ifc_file_exists()
@@ -238,6 +239,19 @@ def the_object_name_has_a_representation_type_of_context(name, type, context):
assert rep.RepresentationType == type
@given(parsers.parse('the object "{name}" data is a "{type}" representation of "{context}"'))
@then(parsers.parse('the object "{name}" data is a "{type}" representation of "{context}"'))
def the_object_name_has_a_representation_type_of_context(name, type, context):
ifc = an_ifc_file_exists()
context, subcontext, target_view = context.split("/")
rep = ifc.by_id(the_object_name_exists(name).data.BIMMeshProperties.ifc_definition_id)
assert rep
assert rep.RepresentationType == type
assert rep.ContextOfItems.ContextType == context
assert rep.ContextOfItems.ContextIdentifier == subcontext
assert rep.ContextOfItems.TargetView == target_view
@then(parsers.parse('the material "{name}" exists'))
def the_material_name_exists(name) -> bpy.types.Material:
obj = bpy.data.materials.get(name)
+7 -22
View File
@@ -21,36 +21,21 @@ from test.core.bootstrap import ifc, type
class TestAssignType:
def test_assigning_and_switching_preferably_to_a_body_representation(self, ifc, type):
def test_assigning_and_switching_to_an_existing_type_data(self, ifc, type):
ifc.run("type.assign_type", related_object="element", relating_type="type").should_be_called()
type.has_material_usage("element").should_be_called().will_return(False)
type.get_body_representation("element").should_be_called().will_return("mapped_rep")
ifc.get_object("type").should_be_called().will_return("type_obj")
type.get_object_data("type_obj").should_be_called().will_return("type_obj_data")
type.change_object_data("obj", "type_obj_data", is_global=False).should_be_called()
ifc.get_object("element").should_be_called().will_return("obj")
type.has_dynamic_voids("obj").should_be_called().will_return(False)
type.run_geometry_switch_representation(
obj="obj", representation="mapped_rep", should_reload=False, enable_dynamic_voids=False, is_global=False
).should_be_called()
type.disable_editing("obj").should_be_called()
subject.assign_type(ifc, type, element="element", type="type")
def test_assigning_and_switching_to_any_representation_as_a_fallback(self, ifc, type):
def test_assigning_and_not_changing_data_if_the_type_has_no_data(self, ifc, type):
ifc.run("type.assign_type", related_object="element", relating_type="type").should_be_called()
type.has_material_usage("element").should_be_called().will_return(False)
type.get_body_representation("element").should_be_called().will_return(None)
type.get_any_representation("element").should_be_called().will_return("mapped_rep")
ifc.get_object("element").should_be_called().will_return("obj")
type.has_dynamic_voids("obj").should_be_called().will_return(False)
type.run_geometry_switch_representation(
obj="obj", representation="mapped_rep", should_reload=False, enable_dynamic_voids=False, is_global=False
).should_be_called()
type.disable_editing("obj").should_be_called()
subject.assign_type(ifc, type, element="element", type="type")
def test_assigning_and_not_changing_representation_if_there_is_no_representation_to_change_to(self, ifc, type):
ifc.run("type.assign_type", related_object="element", relating_type="type").should_be_called()
type.has_material_usage("element").should_be_called().will_return(False)
type.get_body_representation("element").should_be_called().will_return(None)
type.get_any_representation("element").should_be_called().will_return(None)
ifc.get_object("type").should_be_called().will_return("type_obj")
type.get_object_data("type_obj").should_be_called().will_return(None)
ifc.get_object("element").should_be_called().will_return("obj")
type.disable_editing("obj").should_be_called()
subject.assign_type(ifc, type, element="element", type="type")
+27 -16
View File
@@ -29,6 +29,26 @@ class TestImplementsTool(NewFile):
assert isinstance(subject(), blenderbim.core.tool.Type)
class TestChangeObjectData(NewFile):
def test_change_single_object_data(self):
data1 = bpy.data.meshes.new("Mesh")
data2 = bpy.data.meshes.new("Mesh")
obj1 = bpy.data.objects.new("Object", data1)
obj2 = bpy.data.objects.new("Object", data1)
subject.change_object_data(obj1, data2, is_global=False)
assert obj1.data == data2
assert obj2.data == data1
def test_change_object_data_globally(self):
data1 = bpy.data.meshes.new("Mesh")
data2 = bpy.data.meshes.new("Mesh")
obj1 = bpy.data.objects.new("Object", data1)
obj2 = bpy.data.objects.new("Object", data1)
subject.change_object_data(obj1, data2, is_global=True)
assert obj1.data == data2
assert obj2.data == data2
class TestDisableEditing(NewFile):
def test_run(self):
obj = bpy.data.objects.new("Object", None)
@@ -37,22 +57,6 @@ class TestDisableEditing(NewFile):
assert obj.BIMTypeProperties.is_editing_type is False
class TestGetAnyRepresentation(NewFile):
def test_get_product_representation(self):
ifc = ifcopenshell.file()
representation = ifc.createIfcShapeRepresentation()
element = ifc.createIfcWall(Representation=ifc.createIfcProductRepresentation(Representations=[representation]))
assert subject.get_any_representation(element) == representation
def test_get_type_product_representation(self):
ifc = ifcopenshell.file()
representation = ifc.createIfcShapeRepresentation()
element = ifc.createIfcWallType(
RepresentationMaps=[ifc.createIfcRepresentationMap(MappedRepresentation=representation)]
)
assert subject.get_any_representation(element) == representation
class TestGetBodyContext(NewFile):
def test_run(self):
ifc = ifcopenshell.file()
@@ -110,6 +114,13 @@ class TestGetIfcRepresentationClass(NewFile):
assert subject.get_ifc_representation_class(ifc.createIfcColumn()) is None
class TestGetObjectData(NewFile):
def test_run(self):
data = bpy.data.meshes.new("Mesh")
obj = bpy.data.objects.new("Object", data)
assert subject.get_object_data(obj) == obj.data
class TestGetProfileSetUsage(NewFile):
def test_getting_a_profile_set_usage(self):
ifc = ifcopenshell.file()