Fix regression where changing assigned types didn't update the materials.

This commit is contained in:
Dion Moult
2023-02-04 22:12:28 +11:00
parent 42c4a68108
commit 207093fe99
6 changed files with 120 additions and 17 deletions
@@ -169,7 +169,9 @@ class UnassignMaterial(bpy.types.Operator, tool.Ifc.Operator):
for obj in objects:
element = tool.Ifc.get_entity(obj)
if element:
ifcopenshell.api.run("material.unassign_material", tool.Ifc.get(), product=element)
material = ifcopenshell.util.element.get_material(element, should_inherit=False)
if "Usage" not in material.is_a():
ifcopenshell.api.run("material.unassign_material", tool.Ifc.get(), product=element)
class AddConstituent(bpy.types.Operator, tool.Ifc.Operator):
@@ -418,7 +418,9 @@ class DumbProfileJoiner:
self.body = copy.deepcopy(body)
material = ifcopenshell.util.element.get_material(element, should_skip_usage=False)
usage = None
if not material or (not material.is_a("IfcMaterialProfileSet") and not material.is_a("IfcMaterialProfileSetUsage")):
if not material:
return
if "ProfileSet" not in material.is_a():
return
if material.is_a("IfcMaterialProfileSetUsage"):
usage = material
@@ -141,6 +141,7 @@ Scenario: Assign material - material layer set
When I set "active_object.BIMObjectMaterialProperties.material_type" to "IfcMaterialLayerSet"
And I press "bim.assign_material"
Then the object "IfcWallType/Empty" does not have the material "Default"
And the object "IfcWallType/Empty" has a "0.1" thick layered material containing the material "Default"
Scenario: Unassign material - material layer set
Given an empty IFC project
@@ -155,6 +156,27 @@ Scenario: Unassign material - material layer set
When I press "bim.unassign_material"
Then nothing happens
Scenario: Unassign material - material layer set usages will not be removed
Given an empty IFC project
And I add a cube
And the object "Cube" is selected
And I set "scene.BIMRootProperties.ifc_class" to "IfcWall"
And I press "bim.assign_class"
And I add an empty
And the object "Empty" 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 press "bim.add_material(obj='')"
And I set "active_object.BIMObjectMaterialProperties.material_type" to "IfcMaterialLayerSet"
And I press "bim.assign_material"
And the object "IfcWall/Cube" is selected
When the variable "type" is "{ifc}.by_type('IfcWallType')[0].id()"
And I press "bim.assign_type(relating_type={type}, related_object='IfcWall/Cube')"
Then the object "IfcWall/Cube" has a "0.1" thick layered material containing the material "Default"
When I press "bim.unassign_material"
Then the object "IfcWall/Cube" has a "0.1" thick layered material containing the material "Default"
Scenario: Enable editing assigned material - material layer set
Given an empty IFC project
And I add a cube
+61 -9
View File
@@ -1,6 +1,25 @@
@type
Feature: Type
Scenario: Enable editing type
Given an empty IFC project
And I add a cube
And the object "Cube" is selected
And I set "scene.BIMRootProperties.ifc_class" to "IfcWall"
And I press "bim.assign_class"
When I press "bim.enable_editing_type"
Then nothing happens
Scenario: Disable editing type
Given an empty IFC project
And I add a cube
And the object "Cube" is selected
And I set "scene.BIMRootProperties.ifc_class" to "IfcWall"
And I press "bim.assign_class"
And I press "bim.enable_editing_type"
When I press "bim.disable_editing_type"
Then nothing happens
Scenario: Assign type - assign to an empty type
Given an empty IFC project
And I add a cube
@@ -31,7 +50,7 @@ Scenario: Assign type - assign to a type with representation maps
And I press "bim.assign_type(relating_type={type}, related_object='IfcWall/Cube')"
Then the object "IfcWall/Cube" has a "MappedRepresentation" representation of "Model/Body/MODEL_VIEW"
Scenario: Assign type - assign to a type with a material layer set
Scenario: Assign type - assign to a type with a material layer set, which automatically recreates the shape
Given an empty IFC project
And I add a cube
And the object "Cube" is selected
@@ -45,17 +64,50 @@ Scenario: Assign type - assign to a type with a material layer set
And I press "bim.add_material(obj='')"
And I set "active_object.BIMObjectMaterialProperties.material_type" to "IfcMaterialLayerSet"
And I press "bim.assign_material"
And I press "bim.enable_editing_assigned_material"
And the variable "layer_set" is "{ifc}.by_type("IfcMaterialLayerSet")[0].id()"
And I press "bim.add_layer(layer_set={layer_set})"
And the variable "layer" is "{ifc}.by_type("IfcMaterialLayer")[0].id()"
And I press "bim.enable_editing_material_set_item(material_set_item={layer})"
And I set "active_object.BIMObjectMaterialProperties.material_set_item_attributes[0].float_value" to "0.1"
And I press "bim.edit_material_set_item(material_set_item={layer})"
And I press "bim.edit_assigned_material(material_set={layer_set})"
When the variable "type" is "{ifc}.by_type('IfcWallType')[0].id()"
And I press "bim.assign_type(relating_type={type}, related_object='IfcWall/Cube')"
Then the object "IfcWall/Cube" has a "SweptSolid" representation of "Model/Body/MODEL_VIEW"
And the object "IfcWall/Cube" has the material "Default"
And the object "IfcWall/Cube" has a "0.1" thick layered material containing the material "Default"
And the object "IfcWall/Cube" dimensions are "2,.1,3"
Scenario: Assign type - assign to a dfferent type with a material layer set
Given an empty IFC project
And I add a cube
And the object "Cube" is selected
And I set "scene.BIMRootProperties.ifc_class" to "IfcWall"
And I press "bim.assign_class"
And I add an empty
And the object "Empty" 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 the variable "type" is "{ifc}.by_type('IfcWallType')[-1].id()"
And I press "bim.add_material(obj='')"
And I set "active_object.BIMObjectMaterialProperties.material_type" to "IfcMaterialLayerSet"
And I press "bim.assign_material"
And I add an empty
And the object "Empty" 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 "active_object.BIMObjectMaterialProperties.material_type" to "IfcMaterialLayerSet"
And I press "bim.assign_material"
And the variable "type2" is "[w for w in {ifc}.by_type('IfcWallType') if w.id() != {type}][0].id()"
And the variable "layer_set" is "ifcopenshell.util.element.get_material({ifc}.by_id({type2})).id()"
And the variable "layer" is "{ifc}.by_id({layer_set}).MaterialLayers[0].id()"
And I press "bim.enable_editing_material_set_item(material_set_item={layer})"
And I set "active_object.BIMObjectMaterialProperties.material_set_item_attributes[0].float_value" to "0.2"
And I press "bim.edit_material_set_item(material_set_item={layer})"
And I press "bim.edit_assigned_material(material_set={layer_set})"
When I press "bim.assign_type(relating_type={type}, related_object='IfcWall/Cube')"
Then the object "IfcWall/Cube" has a "SweptSolid" representation of "Model/Body/MODEL_VIEW"
And the object "IfcWall/Cube" has the material "Default"
And the object "IfcWall/Cube" has a "0.1" thick layered material containing the material "Default"
And the object "IfcWall/Cube" dimensions are "2,.1,3"
When I press "bim.assign_type(relating_type={type2}, related_object='IfcWall/Cube')"
Then the object "IfcWall/Cube" has a "0.2" thick layered material containing the material "Default"
And the object "IfcWall/Cube" dimensions are "2,.2,3"
Scenario: Assign type - assign to a type with a material profile set
Given an empty IFC project
+29 -1
View File
@@ -48,6 +48,10 @@ def replace_variables(value):
return value
def is_x(number, x):
return abs(number - x) < 1e-6
@given("an untestable scenario")
def an_untestable_scenario():
pass
@@ -498,6 +502,27 @@ def the_object_name_has_the_material_material(name, material):
assert material in [ms.material.name for ms in the_object_name_exists(name).material_slots]
@then(
parsers.parse('the object "{name}" has a "{thickness}" thick layered material containing the material "{material}"')
)
def the_object_name_has_the_thickness_thick_layered_material_containing_the_material_material(
name, thickness, material
):
material_name = material
element = tool.Ifc.get_entity(the_object_name_exists(name))
material = ifcopenshell.util.element.get_material(element)
assert material and "LayerSet" in material.is_a()
if material.is_a("IfcMaterialLayerSetUsage"):
material = material.ForLayerSet
total_thickness = 0
material_names = []
for layer in material.MaterialLayers or []:
total_thickness += layer.LayerThickness
material_names.append(layer.Material.Name)
assert is_x(total_thickness, float(thickness))
assert material_name in material_names
@then(parsers.parse('the object "{name}" does not have the material "{material}"'))
def the_object_name_does_not_have_the_material_material(name, material):
assert material not in [ms.material.name for ms in the_object_name_exists(name).material_slots]
@@ -548,7 +573,10 @@ def the_object_name_has_no_scale(name):
@then(parsers.parse('the object "{name}" dimensions are "{dimensions}"'))
def the_object_name_dimensions_are_dimensions(name, dimensions):
assert list(the_object_name_exists(name).dimensions) == [float(co) for co in dimensions.split(",")]
actual_dimensions = list(the_object_name_exists(name).dimensions)
expected_dimensions = [float(co) for co in dimensions.split(",")]
for i, number in enumerate(actual_dimensions):
assert is_x(number, expected_dimensions[i])
@then(parsers.parse('the object "{name}" bottom left corner is at "{location}"'))
@@ -75,11 +75,8 @@ class Usecase:
for rel in self.settings["product"].HasAssociations:
if rel.is_a("IfcRelAssociatesMaterial"):
if rel.RelatingMaterial.is_a() in ["IfcMaterialLayerSetUsage", "IfcMaterialProfileSetUsage"]:
# Usages cannot be unassigned, as all occurrences of a type
# which has a parametric material must use the parametric
# material. Instead, unassign the parametric material from
# the type.
continue
# Warning: this may leave the model in a non-compliant state.
self.file.remove(rel.RelatingMaterial)
if len(rel.RelatedObjects) == 1:
self.file.remove(rel)
continue