mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 01:41:57 +00:00
material.remove_material_set to remove usages
To prevent them from being invalidated. Noticed this as a possible issue investigating https://community.osarch.org/discussion/2820/error-message-in-bonsai-bim
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api.material
|
||||
import ifcopenshell.util.element
|
||||
|
||||
|
||||
@@ -24,7 +25,9 @@ def remove_material_set(file: ifcopenshell.file, material: ifcopenshell.entity_i
|
||||
"""Removes a material set
|
||||
|
||||
All set items, such as layers, profiles, or constituents will also be
|
||||
removed. However, the materials and profile curves used by the layers,
|
||||
removed. All set usages are also removed.
|
||||
|
||||
However, the materials and profile curves used by the layers,
|
||||
profiles and constituents will not be removed.
|
||||
|
||||
:param material: The IfcMaterialLayerSet, IfcMaterialConstituentSet,
|
||||
@@ -53,7 +56,15 @@ def remove_material_set(file: ifcopenshell.file, material: ifcopenshell.entity_i
|
||||
ifcopenshell.api.material.remove_material_set(model, material=material_set)
|
||||
"""
|
||||
|
||||
inverse_elements = file.get_inverse(material)
|
||||
# Remove all usages for sets.
|
||||
has_usages = material.is_a("IfcMaterialLayerSet") or material.is_a("IfcMaterialProfileSet")
|
||||
if has_usages:
|
||||
# Usage is invalid if it is not associated with some element,
|
||||
# so we can remove usages through unassignment.
|
||||
elements = ifcopenshell.util.element.get_elements_by_material(file, material)
|
||||
if elements:
|
||||
ifcopenshell.api.material.unassign_material(file, products=list(elements))
|
||||
|
||||
if material.is_a("IfcMaterialLayerSet"):
|
||||
set_items = material.MaterialLayers or []
|
||||
elif material.is_a("IfcMaterialProfileSet"):
|
||||
@@ -66,9 +77,13 @@ def remove_material_set(file: ifcopenshell.file, material: ifcopenshell.entity_i
|
||||
raise ValueError(f"Unknown material set type: {material.is_a()}")
|
||||
for set_item in set_items:
|
||||
file.remove(set_item)
|
||||
|
||||
inverse_elements = file.get_inverse(material)
|
||||
file.remove(material)
|
||||
|
||||
for inverse in inverse_elements:
|
||||
if inverse.is_a("IfcRelAssociatesMaterial"):
|
||||
# NOTE: for has_usages already handled by unassign_material.
|
||||
history = inverse.OwnerHistory
|
||||
file.remove(inverse)
|
||||
if history:
|
||||
|
||||
@@ -31,6 +31,9 @@ def unassign_material(file: ifcopenshell.file, products: list[ifcopenshell.entit
|
||||
|
||||
If the product does not have a material, nothing happens.
|
||||
|
||||
Unassigning a LayerSet or ProfileSet from the product type will also
|
||||
remove all Usages of the set.
|
||||
|
||||
:param products: The list IfcProducts that may or may not have a material
|
||||
:return: None
|
||||
|
||||
@@ -76,6 +79,8 @@ class Usecase:
|
||||
continue
|
||||
if material.is_a() in ["IfcMaterialLayerSet", "IfcMaterialProfileSet"]:
|
||||
# Remove set usages
|
||||
# TODO: be more considerate and remove only usages
|
||||
# associated with the set + product type, not all usages?
|
||||
for inverse in self.file.get_inverse(material):
|
||||
if self.file.schema == "IFC2X3":
|
||||
if not inverse.is_a("IfcMaterialLayerSetUsage"):
|
||||
|
||||
@@ -17,9 +17,10 @@
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import test.bootstrap
|
||||
import ifcopenshell.api.material
|
||||
import ifcopenshell.api.pset
|
||||
import ifcopenshell.api.root
|
||||
import ifcopenshell.api.material
|
||||
import ifcopenshell.api.type
|
||||
|
||||
|
||||
class TestRemoveMaterialSetIFC2X3(test.bootstrap.IFC2X3):
|
||||
@@ -45,6 +46,19 @@ class TestRemoveMaterialSetIFC2X3(test.bootstrap.IFC2X3):
|
||||
assert len(self.file.by_type("IfcMaterialLayer")) == 0
|
||||
assert len(self.file.by_type("IfcMaterial")) == 1
|
||||
|
||||
def test_removing_a_material_set_with_usages(self):
|
||||
material = ifcopenshell.api.material.add_material_set(self.file, set_type="IfcMaterialLayerSet")
|
||||
element_type = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcWallType")
|
||||
element = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcWall")
|
||||
ifcopenshell.api.type.assign_type(self.file, related_objects=[element], relating_type=element_type)
|
||||
ifcopenshell.api.material.assign_material(self.file, products=[element_type], material=material)
|
||||
ifcopenshell.api.material.assign_material(
|
||||
self.file, products=[element], material=material, type="IfcMaterialLayerSetUsage"
|
||||
)
|
||||
ifcopenshell.api.material.remove_material_set(self.file, material=material)
|
||||
assert len(self.file.by_type("IfcMaterialLayerSet")) == 0
|
||||
assert len(self.file.by_type("IfcMaterialLayerSetUsage")) == 0
|
||||
|
||||
|
||||
class TestRemoveMaterialSetIFC4(test.bootstrap.IFC4, TestRemoveMaterialSetIFC2X3):
|
||||
# IFC2X3 doesn't support adding a pset to IfcMaterialLayerSet
|
||||
|
||||
Reference in New Issue
Block a user