mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 09:21:46 +00:00
Follow IfcRelAdheresToElement so IfcSurfaceFeature road markings import #8375
IfcSurfaceFeature (e.g. road markings) adheres to a host element through IfcRelAdheresToElement, a [1:1] cardinality hierarchical relationship in the same family as aggregation, containment and nesting since IFC4.3. The spatial traversal never followed it, so surface features had no resolvable parent or container: on import they landed in the Unsorted collection instead of the host's spatial collection, and were dropped entirely in DECOMPOSITION filter mode. Add get_adhered_element (feature to host) to the get_parent resolver chain and walk HasSurfaceFeatures in get_decomposition, plus a get_surface_features helper mirroring get_parts/get_contained. With get_parent resolving adherence, get_container now returns the host's spatial container, so tool.Collector places surface features under the host. Also follow HasSurfaceFeatures in the Bonsai DECOMPOSITION filter path so they load in that mode. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
committed by
Thomas Krijnen
parent
644b92263d
commit
e0a1988044
@@ -1125,7 +1125,8 @@ def get_decomposition(element: ifcopenshell.entity_instance, is_recursive=True)
|
||||
"""
|
||||
Retrieves all subelements of an element based on the spatial decomposition
|
||||
hierarchy. This includes all subspaces and elements contained in subspaces,
|
||||
parts of an aggregate, all openings, and all fills of any openings.
|
||||
parts of an aggregate, all openings, all fills of any openings, and any
|
||||
surface features adhering to an element (IFC4.3 and above).
|
||||
|
||||
:param element: The IFC element
|
||||
:return: The decomposition of the element
|
||||
@@ -1161,6 +1162,10 @@ def get_decomposition(element: ifcopenshell.entity_instance, is_recursive=True)
|
||||
related = rel.RelatedObjects
|
||||
queue.extend(related)
|
||||
results.update(related)
|
||||
for rel in getattr(element, "HasSurfaceFeatures", []):
|
||||
related = rel.RelatedSurfaceFeatures
|
||||
queue.extend(related)
|
||||
results.update(related)
|
||||
if not is_recursive:
|
||||
break
|
||||
return results
|
||||
@@ -1251,6 +1256,8 @@ def get_parent(
|
||||
- Nesting: components are attached to a host parent
|
||||
- Filling: the physical element fills an opening, such as a window filling a hole
|
||||
- Voiding: the opening voids another physical element, such as a hole in a wall
|
||||
- Adherence: a surface feature adheres to a host element, such as a road
|
||||
marking adhering to a road course (IFC4.3 and above)
|
||||
|
||||
:param element: Any physical or spatial element in the tree
|
||||
:param ifc_class: Optionally filter the type of parent you're after. For
|
||||
@@ -1270,6 +1277,7 @@ def get_parent(
|
||||
or get_nest(element)
|
||||
or get_filled_void(element)
|
||||
or get_voided_element(element)
|
||||
or get_adhered_element(element)
|
||||
)
|
||||
|
||||
if not ifc_class:
|
||||
@@ -1321,6 +1329,28 @@ def get_voided_element(element: ifcopenshell.entity_instance) -> Union[ifcopensh
|
||||
return rel[0].RelatingBuildingElement
|
||||
|
||||
|
||||
def get_adhered_element(element: ifcopenshell.entity_instance) -> Union[ifcopenshell.entity_instance, None]:
|
||||
"""If the element is a surface feature, get the element it adheres to
|
||||
|
||||
In IFC4.3 an IfcSurfaceFeature (such as a road marking) adheres to a host
|
||||
element through the IfcRelAdheresToElement relationship. This is a [1:1]
|
||||
cardinality hierarchical relationship, in the same family as aggregation,
|
||||
containment and nesting.
|
||||
|
||||
:param element: The IfcSurfaceFeature
|
||||
:return: The host element that the surface feature adheres to
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
marking = file.by_type("IfcSurfaceFeature")[0]
|
||||
host = ifcopenshell.util.element.get_adhered_element(marking)
|
||||
"""
|
||||
if rel := getattr(element, "AdheresToElement", None):
|
||||
return rel[0].RelatingElement
|
||||
|
||||
|
||||
def get_aggregate(element: ifcopenshell.entity_instance) -> Union[ifcopenshell.entity_instance, None]:
|
||||
"""
|
||||
Retrieves the aggregate parent of an element.
|
||||
@@ -1415,6 +1445,29 @@ def get_contained(element: ifcopenshell.entity_instance) -> list[ifcopenshell.en
|
||||
return objects
|
||||
|
||||
|
||||
def get_surface_features(element: ifcopenshell.entity_instance) -> list[ifcopenshell.entity_instance]:
|
||||
"""Retrieves the surface features that adhere to an element.
|
||||
|
||||
In IFC4.3 an IfcSurfaceFeature (such as a road marking) adheres to a host
|
||||
element through the IfcRelAdheresToElement relationship.
|
||||
|
||||
:param element: The IFC element
|
||||
:return: The surface features adhering to the element
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
element = file.by_type("IfcCourse")[0]
|
||||
markings = ifcopenshell.util.element.get_surface_features(element)
|
||||
"""
|
||||
objects: list[ifcopenshell.entity_instance] = []
|
||||
if has_surface_features := getattr(element, "HasSurfaceFeatures", ()):
|
||||
for rel in has_surface_features:
|
||||
objects.extend(rel.RelatedSurfaceFeatures)
|
||||
return objects
|
||||
|
||||
|
||||
def get_components(
|
||||
element: ifcopenshell.entity_instance, include_ports: bool = False
|
||||
) -> list[ifcopenshell.entity_instance]:
|
||||
|
||||
Reference in New Issue
Block a user