Fix #6640. Fix invalid association of annotations to grids.

There was already some half written code with this intent it seems, so I
just finished it up.
This commit is contained in:
Dion Moult
2025-05-26 13:49:06 +10:00
parent d6cc1ff9e9
commit 810e8df6fe
5 changed files with 76 additions and 36 deletions
+23 -8
View File
@@ -1342,17 +1342,32 @@ class Drawing(bonsai.core.tool.Drawing):
) -> Union[ifcopenshell.entity_instance, bool, None]:
if drawing == reference_element:
return True
if reference_element.is_a("IfcGridAxis"):
# We cannot associate IfcGridAxis directly, so we establish a convention:
# IfcRelAssignsToProduct.RelatingProduct = IfcGrid
# IfcRelAssignsToProduct.Name = IfcGridAxis.AxisTag
grid = None
for attribute in ("PartOfW", "PartOfV", "PartOfU"):
if getattr(reference_element, attribute, None):
grid = getattr(reference_element, attribute)[0]
break
for element in cls.get_group_elements(cls.get_drawing_group(drawing)):
if not element.is_a("IfcAnnotation"):
continue
for rel in element.HasAssignments:
if (
rel.is_a("IfcRelAssignsToProduct")
and rel.RelatingProduct == grid
and rel.Name == reference_element.AxisTag
):
return element
return
for element in cls.get_group_elements(cls.get_drawing_group(drawing)):
if element.is_a("IfcAnnotation"):
for rel in element.HasAssignments:
if rel.is_a("IfcRelAssignsToProduct"):
if rel.RelatingProduct == reference_element:
return element
# We cannot associate IfcGridAxis directly, so we establish a convention:
# IfcRelAssignsToProduct.RelatingProduct = IfcGrid
# IfcRelAssignsToProduct.Name = IfcGridAxis.AxisTag
elif reference_element.is_a("IfcGridAxis") and rel.Name == reference_element.AxisTag:
return element
if rel.is_a("IfcRelAssignsToProduct") and rel.RelatingProduct == reference_element:
return element
@classmethod
def generate_reference_annotation(
@@ -59,49 +59,47 @@ def assign_product(
ifcopenshell.api.drawing.assign_product(model,
relating_product=furniture, related_object=annotation)
"""
is_grid_axis = relating_product.is_a("IfcGridAxis")
if is_grid_axis:
if related_object.HasAssignments:
for rel in related_object.HasAssignments:
if rel.is_a("IfcRelAssignsToProduct") and rel.Name == relating_product.AxisTag:
return
elif related_object.HasAssignments:
for rel in related_object.HasAssignments:
if rel.is_a("IfcRelAssignsToProduct") and rel.RelatingProduct == relating_product:
return
referenced_by = None
if is_grid_axis:
if relating_product.is_a("IfcGridAxis"):
axis = relating_product
grid = None
for attribute in ("PartOfW", "PartOfV", "PartOfU"):
if getattr(axis, attribute, None):
grid = getattr(axis, attribute)[0]
for rel in grid.ReferencedBy:
if rel.Name == axis.AxisTag:
referenced_by = rel
break
elif relating_product.ReferencedBy:
for rel in grid.ReferencedBy or []:
if rel.Name == axis.AxisTag and related_object in rel.RelatedObjects:
return
return file.create_entity(
"IfcRelAssignsToProduct",
GlobalId=ifcopenshell.guid.new(),
Name=axis.AxisTag,
OwnerHistory=ifcopenshell.api.owner.create_owner_history(file),
RelatedObjects=[related_object],
RelatingProduct=grid,
)
if related_object.HasAssignments:
for rel in related_object.HasAssignments:
if rel.is_a("IfcRelAssignsToProduct") and rel.RelatingProduct == relating_product:
return
referenced_by = None
if relating_product.ReferencedBy:
referenced_by = relating_product.ReferencedBy[0]
if referenced_by:
related_objects = list(referenced_by.RelatedObjects)
related_objects.append(related_object)
referenced_by.RelatedObjects = related_objects
ifcopenshell.api.owner.update_owner_history(file, **{"element": referenced_by})
ifcopenshell.api.owner.update_owner_history(file, element=referenced_by)
else:
referenced_by = file.create_entity(
"IfcRelAssignsToProduct",
**{
"GlobalId": ifcopenshell.guid.new(),
"OwnerHistory": ifcopenshell.api.owner.create_owner_history(file),
"RelatedObjects": [related_object],
"RelatingProduct": relating_product,
},
GlobalId=ifcopenshell.guid.new(),
OwnerHistory=ifcopenshell.api.owner.create_owner_history(file),
RelatedObjects=[related_object],
RelatingProduct=relating_product,
)
if is_grid_axis:
referenced_by.Name = axis.AxisTag
return referenced_by
@@ -51,6 +51,14 @@ def unassign_product(
ifcopenshell.api.drawing.unassign_product(model,
relating_product=furniture, related_object=annotation)
"""
if relating_product.is_a("IfcGridAxis"):
grid = None
for attribute in ("PartOfW", "PartOfV", "PartOfU"):
if getattr(relating_product, attribute, None):
grid = getattr(relating_product, attribute)[0]
break
relating_product = grid
for rel in related_object.HasAssignments or []:
if not rel.is_a("IfcRelAssignsToProduct") or rel.RelatingProduct != relating_product:
continue
@@ -38,6 +38,17 @@ class TestAssignProduct(test.bootstrap.IFC4):
assert len(wall.ReferencedBy) == 1
assert wall.ReferencedBy[0].RelatedObjects == (label,)
def test_assigning_a_grid_axis(self):
axis = self.file.createIfcGridAxis(AxisTag="A")
grid = self.file.createIfcGrid(UAxes=[axis])
line = self.file.createIfcAnnotation()
ifcopenshell.api.drawing.assign_product(self.file, relating_product=axis, related_object=line)
assert grid.ReferencedBy[0].RelatedObjects == (line,)
assert grid.ReferencedBy[0].Name == "A"
assert len(self.file.by_type("IfcRelAssignsToProduct")) == 1
ifcopenshell.api.drawing.assign_product(self.file, relating_product=axis, related_object=line)
assert len(self.file.by_type("IfcRelAssignsToProduct")) == 1
class TestAssignProductIFC2X3(test.bootstrap.IFC2X3, TestAssignProduct):
pass
@@ -28,6 +28,14 @@ class TestUnassignProduct(test.bootstrap.IFC4):
ifcopenshell.api.drawing.unassign_product(self.file, relating_product=wall, related_object=label)
assert len(self.file.by_type("IfcRelAssignsToProduct")) == 0
def test_unassigning_a_grid_axis(self):
axis = self.file.createIfcGridAxis(AxisTag="A")
grid = self.file.createIfcGrid(UAxes=[axis])
line = self.file.createIfcAnnotation()
ifcopenshell.api.drawing.assign_product(self.file, relating_product=axis, related_object=line)
ifcopenshell.api.drawing.unassign_product(self.file, relating_product=axis, related_object=line)
assert len(self.file.by_type("IfcRelAssignsToProduct")) == 0
class TestUnassignProductIFC2X3(test.bootstrap.IFC2X3, TestUnassignProduct):
pass