Fixes referent sorting

This commit is contained in:
Richard Brice
2025-08-29 14:37:17 -07:00
parent 34bf374047
commit a839183ac2
11 changed files with 29 additions and 33 deletions
@@ -179,7 +179,6 @@ def _add_segment_to_layout(file: ifcopenshell.file, layout: entity_instance, seg
referent = ifcopenshell.api.alignment.add_stationing_referent( referent = ifcopenshell.api.alignment.add_stationing_referent(
file, alignment, distance_along=dist_along, station=station, name=name, positioned_product=segment file, alignment, distance_along=dist_along, station=station, name=name, positioned_product=segment
) )
ifcopenshell.api.nest.reorder_nesting(file, referent, -1, -1)
if len(curve.Segments) == 2 and layout.is_a("IfcAlignmentHorizontal"): if len(curve.Segments) == 2 and layout.is_a("IfcAlignmentHorizontal"):
# this is the first real segment in the horizontal alignment # this is the first real segment in the horizontal alignment
@@ -105,15 +105,15 @@ def add_stationing_referent(
ay = float(p[1, 2]) ay = float(p[1, 2])
az = float(p[2, 2]) az = float(p[2, 2])
else: else:
x = 0. x = 0.0
y = 0. y = 0.0
z = 0. z = 0.0
rx = 1. rx = 1.0
ry = 0. ry = 0.0
rz = 0. rz = 0.0
ax = 0. ax = 0.0
ay = 0. ay = 0.0
az = 1. az = 1.0
object_placement.CartesianPosition = file.createIfcAxis2Placement3D( object_placement.CartesianPosition = file.createIfcAxis2Placement3D(
Location=file.createIfcCartesianPoint((x, y, z)), Location=file.createIfcCartesianPoint((x, y, z)),
@@ -146,7 +146,9 @@ def add_stationing_referent(
nest = ifcopenshell.api.alignment.get_referent_nest(file, alignment) nest = ifcopenshell.api.alignment.get_referent_nest(file, alignment)
nest.RelatedObjects += (referent,) nest.RelatedObjects += (referent,)
nest.RelatedObjects = sorted(nest.RelatedObjects,key=lambda x: ifcopenshell.util.element.get_pset(x, name="Pset_Stationing", prop="Station")) nest.RelatedObjects = sorted(
nest.RelatedObjects, key=lambda x: ifcopenshell.util.element.get_pset(x, name="Pset_Stationing", prop="Station")
)
if len(referent.Positions) == 0: if len(referent.Positions) == 0:
rel_positions = file.createIfcRelPositions( rel_positions = file.createIfcRelPositions(
@@ -54,18 +54,17 @@ def _move_vertical_layout_to_child_alignment(
ifcopenshell.api.aggregate.assign_object(file, products=[child_alignment], relating_object=parent_alignment) ifcopenshell.api.aggregate.assign_object(file, products=[child_alignment], relating_object=parent_alignment)
# move all referents positioning segments of the vertical layout to the referent nest of the child alignment # move all referents positioning segments of the vertical layout to the referent nest of the child alignment
child_referent_nest = ifcopenshell.api.alignment.get_referent_nest(file,child_alignment) child_referent_nest = ifcopenshell.api.alignment.get_referent_nest(file, child_alignment)
parent_referent_nest = ifcopenshell.api.alignment.get_referent_nest(file,parent_alignment) parent_referent_nest = ifcopenshell.api.alignment.get_referent_nest(file, parent_alignment)
for referent in parent_referent_nest.RelatedObjects: for referent in parent_referent_nest.RelatedObjects:
for product in referent.Positions[0].RelatedProducts: for product in referent.Positions[0].RelatedProducts:
if product.is_a("IfcAlignmentSegment") and product.Nests[0].RelatingObject == vertical_layout: if product.is_a("IfcAlignmentSegment") and product.Nests[0].RelatingObject == vertical_layout:
#ifcopenshell.api.nest.change_nest(file,referent,child_alignment) - this doesn't work because referent is assigned to child_alignment.IsNestedBy[0].RelatedObjects # ifcopenshell.api.nest.change_nest(file,referent,child_alignment) - this doesn't work because referent is assigned to child_alignment.IsNestedBy[0].RelatedObjects
# and it needs to be assigned to child_alignment.IsNestedBy[1].RelatedObjects # and it needs to be assigned to child_alignment.IsNestedBy[1].RelatedObjects
# move the referent manually - unassign it and add it to the child alignment's referent nest # move the referent manually - unassign it and add it to the child alignment's referent nest
ifcopenshell.api.nest.unassign_object(file,[referent]) ifcopenshell.api.nest.unassign_object(file, [referent])
child_referent_nest.RelatedObjects += (referent,) child_referent_nest.RelatedObjects += (referent,)
# if the parent alignment has a representation, move the Axis/Curve3D represention to the child alignment # if the parent alignment has a representation, move the Axis/Curve3D represention to the child alignment
base_curve = ifcopenshell.api.alignment.get_basis_curve(parent_alignment) base_curve = ifcopenshell.api.alignment.get_basis_curve(parent_alignment)
if base_curve: if base_curve:
@@ -233,7 +233,9 @@ def add_zero_length_segment(file: ifcopenshell.file, layout: entity_instance, in
alignment = ifcopenshell.api.alignment.get_alignment(layout) alignment = ifcopenshell.api.alignment.get_alignment(layout)
station = ifcopenshell.api.alignment.get_alignment_start_station(file, alignment) station = ifcopenshell.api.alignment.get_alignment_start_station(file, alignment)
name = f"{_get_segment_start_point_label(zero_length_curve_segment,None)} ({ifcopenshell.util.alignment.station_as_string(file,station)})" name = f"{_get_segment_start_point_label(zero_length_curve_segment,None)} ({ifcopenshell.util.alignment.station_as_string(file,station)})"
referent = ifcopenshell.api.alignment.add_stationing_referent(file, alignment, 0.0, station, name, zero_length_curve_segment) referent = ifcopenshell.api.alignment.add_stationing_referent(
file, alignment, 0.0, station, name, zero_length_curve_segment
)
referent.Description = f"Positions zero length segment {zero_length_curve_segment.id()}" referent.Description = f"Positions zero length segment {zero_length_curve_segment.id()}"
return True return True
@@ -142,7 +142,6 @@ def create_as_polyline(
# define stationing # define stationing
name = ifcopenshell.util.alignment.station_as_string(file, start_station) name = ifcopenshell.util.alignment.station_as_string(file, start_station)
referent = ifcopenshell.api.alignment.add_stationing_referent(file, alignment, 0.0, start_station, name, alignment) referent = ifcopenshell.api.alignment.add_stationing_referent(file, alignment, 0.0, start_station, name, alignment)
ifcopenshell.api.nest.reorder_nesting(file, referent, -1, 0)
# IFC 4.1.4.1.1 Alignment Aggregation To Project # IFC 4.1.4.1.1 Alignment Aggregation To Project
project = file.by_type("IfcProject")[0] project = file.by_type("IfcProject")[0]
@@ -29,9 +29,7 @@ def get_referent_nest(file: ifcopenshell.file, alignment: entity_instance) -> en
:return: Returns the IfcRelNests. :return: Returns the IfcRelNests.
""" """
if not alignment.is_a("IfcAlignment"): if not alignment.is_a("IfcAlignment"):
raise TypeError( raise TypeError(f"Expected IfcAlignment, instead received {alignment.is_a()}")
f"Expected IfcAlignment, instead received {alignment.is_a()}"
)
for nest in alignment.IsNestedBy: for nest in alignment.IsNestedBy:
for related_object in nest.RelatedObjects: for related_object in nest.RelatedObjects:
@@ -39,16 +39,13 @@ def test_add_stationing_to_alignment():
alignment = ifcopenshell.api.alignment.create(file, "TestAlignment", start_station=2000.0) alignment = ifcopenshell.api.alignment.create(file, "TestAlignment", start_station=2000.0)
referent_nest = ifcopenshell.api.alignment.get_referent_nest(file,alignment) referent_nest = ifcopenshell.api.alignment.get_referent_nest(file, alignment)
referent = referent_nest.RelatedObjects[0] referent = referent_nest.RelatedObjects[0]
assert referent.PredefinedType == "STATION" assert referent.PredefinedType == "STATION"
assert referent.Name == "2+000.000" assert referent.Name == "2+000.000"
assert ifcopenshell.util.element.get_pset(element=referent, name="Pset_Stationing") assert ifcopenshell.util.element.get_pset(element=referent, name="Pset_Stationing")
assert ( assert ifcopenshell.util.element.get_pset(element=referent, name="Pset_Stationing", prop="Station") == 2000.0
ifcopenshell.util.element.get_pset(element=referent, name="Pset_Stationing", prop="Station")
== 2000.0
)
assert referent.ObjectPlacement != None assert referent.ObjectPlacement != None
@@ -36,7 +36,7 @@ def test_add_vertical_alignment():
layout_nest = ifcopenshell.api.alignment.get_alignment_layout_nest(alignment) layout_nest = ifcopenshell.api.alignment.get_alignment_layout_nest(alignment)
assert len(layout_nest.RelatedObjects) == 1 assert len(layout_nest.RelatedObjects) == 1
assert layout_nest.RelatedObjects[0].is_a("IfcAlignmentHorizontal") assert layout_nest.RelatedObjects[0].is_a("IfcAlignmentHorizontal")
referent_nest = ifcopenshell.api.alignment.get_referent_nest(file,alignment) referent_nest = ifcopenshell.api.alignment.get_referent_nest(file, alignment)
assert len(referent_nest.RelatedObjects) == 2 assert len(referent_nest.RelatedObjects) == 2
assert referent_nest.RelatedObjects[0].is_a("IfcReferent") assert referent_nest.RelatedObjects[0].is_a("IfcReferent")
@@ -51,7 +51,7 @@ def test_create_by_pi_method():
layout_nest = ifcopenshell.api.alignment.get_alignment_layout_nest(alignment) layout_nest = ifcopenshell.api.alignment.get_alignment_layout_nest(alignment)
assert len(layout_nest.RelatedObjects) == 2 assert len(layout_nest.RelatedObjects) == 2
referent_nest = ifcopenshell.api.alignment.get_referent_nest(file,alignment) referent_nest = ifcopenshell.api.alignment.get_referent_nest(file, alignment)
assert len(referent_nest.RelatedObjects) == 19 assert len(referent_nest.RelatedObjects) == 19
horizontal_layout = ifcopenshell.api.alignment.get_horizontal_layout(alignment) horizontal_layout = ifcopenshell.api.alignment.get_horizontal_layout(alignment)
@@ -107,6 +107,6 @@ def test_with_default_names(default_names_alignment):
def test_with_callbacks(callback_alignment): def test_with_callbacks(callback_alignment):
referent_nest = ifcopenshell.api.alignment.get_referent_nest(None, callback_alignment) referent_nest = ifcopenshell.api.alignment.get_referent_nest(None, callback_alignment)
expected = ["A","Q","Z","a","q","z"] expected = ["A", "Q", "Z", "a", "q", "z"]
for r in referent_nest.RelatedObjects: for r in referent_nest.RelatedObjects:
assert [x in r.Name for x in expected] assert [x in r.Name for x in expected]