Corrects nesting of referents

This commit is contained in:
Richard Brice
2025-08-29 12:48:03 -07:00
parent 43c35eaf24
commit 34bf374047
17 changed files with 125 additions and 120 deletions
@@ -62,7 +62,7 @@ from .distance_along_from_station import distance_along_from_station
from .get_alignment import get_alignment from .get_alignment import get_alignment
from .get_alignment_layout_nest import get_alignment_layout_nest from .get_alignment_layout_nest import get_alignment_layout_nest
from .get_alignment_segment_nest import get_alignment_segment_nest from .get_alignment_segment_nest import get_alignment_segment_nest
from .get_alignment_station import get_alignment_station from .get_alignment_start_station import get_alignment_start_station
from .get_curve_segment_transition_code import get_curve_segment_transition_code from .get_curve_segment_transition_code import get_curve_segment_transition_code
from .get_layout_segments import get_layout_segments from .get_layout_segments import get_layout_segments
from .get_horizontal_layout import get_horizontal_layout from .get_horizontal_layout import get_horizontal_layout
@@ -103,7 +103,7 @@ __all__ = [
"get_alignment_layout_nest", "get_alignment_layout_nest",
"get_alignment_layouts", "get_alignment_layouts",
"get_alignment_segment_nest", "get_alignment_segment_nest",
"get_alignment_station", "get_alignment_start_station",
"get_axis_subcontext", "get_axis_subcontext",
"get_basis_curve", "get_basis_curve",
"get_cant_layout", "get_cant_layout",
@@ -83,7 +83,7 @@ def _add_segment_to_layout(file: ifcopenshell.file, layout: entity_instance, seg
# get the station of the start of the segment # get the station of the start of the segment
alignment = ifcopenshell.api.alignment.get_alignment(layout) alignment = ifcopenshell.api.alignment.get_alignment(layout)
start_station = ifcopenshell.api.alignment.get_alignment_station(file, alignment) start_station = ifcopenshell.api.alignment.get_alignment_start_station(file, alignment)
station = start_station + dist_along station = start_station + dist_along
# update the zero length layout segment # update the zero length layout segment
@@ -137,8 +137,7 @@ def _add_segment_to_layout(file: ifcopenshell.file, layout: entity_instance, seg
start_dist_along = segment.DesignParameters.StartDistAlong + segment.DesignParameters.HorizontalLength start_dist_along = segment.DesignParameters.StartDistAlong + segment.DesignParameters.HorizontalLength
zero_length_segment.DesignParameters.StartDistAlong = start_dist_along zero_length_segment.DesignParameters.StartDistAlong = start_dist_along
referent_nest = ifcopenshell.api.alignment.get_referent_nest(file, layout) end_referent = zero_length_segment.PositionedRelativeTo[0].RelatingPositioningElement
end_referent = referent_nest.RelatedObjects[-1]
end_referent.Name = f"{_get_segment_start_point_label(zero_length_segment,None)} ({ifcopenshell.util.alignment.station_as_string(file,start_station+start_dist_along)})" end_referent.Name = f"{_get_segment_start_point_label(zero_length_segment,None)} ({ifcopenshell.util.alignment.station_as_string(file,start_station+start_dist_along)})"
# update the referent's geometric representation's location # update the referent's geometric representation's location
@@ -166,7 +165,7 @@ def _add_segment_to_layout(file: ifcopenshell.file, layout: entity_instance, seg
end_referent.ObjectPlacement.CartesianPosition.Axis.DirectionRatios = (ax, ay, az) end_referent.ObjectPlacement.CartesianPosition.Axis.DirectionRatios = (ax, ay, az)
end_referent.ObjectPlacement.CartesianPosition.RefDirection.DirectionRatios = (rx, ry, rz) end_referent.ObjectPlacement.CartesianPosition.RefDirection.DirectionRatios = (rx, ry, rz)
start_station = ifcopenshell.api.alignment.get_alignment_station(file, alignment) start_station = ifcopenshell.api.alignment.get_alignment_start_station(file, alignment)
end_referent_station = start_station + start_dist_along end_referent_station = start_station + start_dist_along
pset_stationing = ifcopenshell.api.pset.add_pset(file, product=end_referent, name="Pset_Stationing") pset_stationing = ifcopenshell.api.pset.add_pset(file, product=end_referent, name="Pset_Stationing")
ifcopenshell.api.pset.edit_pset(file, pset=pset_stationing, properties={"Station": end_referent_station}) ifcopenshell.api.pset.edit_pset(file, pset=pset_stationing, properties={"Station": end_referent_station})
@@ -178,7 +177,7 @@ def _add_segment_to_layout(file: ifcopenshell.file, layout: entity_instance, seg
prev_segment = segment_nest.RelatedObjects[-3] if 2 < len(segment_nest.RelatedObjects) else None prev_segment = segment_nest.RelatedObjects[-3] if 2 < len(segment_nest.RelatedObjects) else None
name = f"{_get_segment_start_point_label(prev_segment,segment)} ({ifcopenshell.util.alignment.station_as_string(file,station)})" name = f"{_get_segment_start_point_label(prev_segment,segment)} ({ifcopenshell.util.alignment.station_as_string(file,station)})"
referent = ifcopenshell.api.alignment.add_stationing_referent( referent = ifcopenshell.api.alignment.add_stationing_referent(
file, layout, 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) ifcopenshell.api.nest.reorder_nesting(file, referent, -1, -1)
@@ -51,6 +51,6 @@ def _add_zero_length_segment(file: ifcopenshell.file, layout: entity_instance) -
segment_nest = ifcopenshell.api.alignment.get_alignment_segment_nest(layout) segment_nest = ifcopenshell.api.alignment.get_alignment_segment_nest(layout)
segment = segment_nest.RelatedObjects[-1] segment = segment_nest.RelatedObjects[-1]
alignment = ifcopenshell.api.alignment.get_alignment(layout) alignment = ifcopenshell.api.alignment.get_alignment(layout)
station = ifcopenshell.api.alignment.get_alignment_station(file, alignment) station = ifcopenshell.api.alignment.get_alignment_start_station(file, alignment)
name = f"{_get_segment_start_point_label(segment,None)} ({ifcopenshell.util.alignment.station_as_string(file,station)})" name = f"{_get_segment_start_point_label(segment,None)} ({ifcopenshell.util.alignment.station_as_string(file,station)})"
ifcopenshell.api.alignment.add_stationing_referent(file, layout, 0.0, station, name, segment) referent = ifcopenshell.api.alignment.add_stationing_referent(file, alignment, 0.0, station, name, segment)
@@ -30,18 +30,17 @@ import numpy as np
def add_stationing_referent( def add_stationing_referent(
file: ifcopenshell.file, file: ifcopenshell.file,
element: entity_instance, alignment: entity_instance,
distance_along: float, distance_along: float,
station: float, station: float,
name: str, name: str,
positioned_product: entity_instance, positioned_product: entity_instance,
) -> entity_instance: ) -> entity_instance:
""" """
Adds an IfcReferent to the element with the Pset_Stationing property set. Adds an IfcReferent to the alignment with the Pset_Stationing property set.
If element is an IfcAlignment, IfcReferent.PredefinedType is set to "STATION", otherwise "POSITION"
:param element: the element to receive the referent, expected to be an IfcAlignment or IfcAlignmentSegment :param alignment: the alignment to receive the referent
:param distance_along: distance along the alignment curve :param distance_along: distance along the alignment basis curve
:param station: station value :param station: station value
:param name: name to assign to IfcReferent.Name, typically a stringized version of the station value :param name: name to assign to IfcReferent.Name, typically a stringized version of the station value
:param positioned_product: the product whose position is informed by the referent :param positioned_product: the product whose position is informed by the referent
@@ -52,21 +51,8 @@ def add_stationing_referent(
.. code:: python .. code:: python
alignment = model.by_type("IfcAlignment")[0] alignment = model.by_type("IfcAlignment")[0]
ifcopenshell.api.alignment.add_stationing_referent(model,entity=alignment,distance_along=0.0,station=100.0) ifcopenshell.api.alignment.add_stationing_referent(model,alignment=alignment,distance_along=0.0,station=100.0)
""" """
alignment = element
layout_types = [
"IfcAlignmentHorizontal",
"IfcAlignmentVertical",
"IfcAlignmentCant",
]
if element.is_a("IfcAlignmentSegment"):
layout = element.Nests[0].RelatingObject
alignment = ifcopenshell.api.alignment.get_alignment(layout)
elif element.is_a() in layout_types:
alignment = ifcopenshell.api.alignment.get_alignment(element)
basis_curve = ifcopenshell.api.alignment.get_basis_curve(alignment) basis_curve = ifcopenshell.api.alignment.get_basis_curve(alignment)
@@ -86,6 +72,8 @@ def add_stationing_referent(
) )
is_valid_curve = True is_valid_curve = True
if basis_curve.is_a("IfcCompositeCurve") and len(basis_curve.Segments) == 0:
is_valid_curve = False
if basis_curve.is_a("IfcPolyline") and len(basis_curve.Points) < 2: if basis_curve.is_a("IfcPolyline") and len(basis_curve.Points) < 2:
is_valid_curve = False is_valid_curve = False
elif basis_curve.is_a("IfcIndexedPolyCurve") and len(basis_curve.Points.CoordList) < 2: elif basis_curve.is_a("IfcIndexedPolyCurve") and len(basis_curve.Points.CoordList) < 2:
@@ -101,6 +89,7 @@ def add_stationing_referent(
fn = ifcopenshell_wrapper.convert_loop_to_function_item(fn) fn = ifcopenshell_wrapper.convert_loop_to_function_item(fn)
evaluator = ifcopenshell_wrapper.function_item_evaluator(settings, fn) evaluator = ifcopenshell_wrapper.function_item_evaluator(settings, fn)
p = evaluator.evaluate(distance_along * unit_scale) p = evaluator.evaluate(distance_along * unit_scale)
p = np.array(p) p = np.array(p)
@@ -115,12 +104,23 @@ def add_stationing_referent(
ax = float(p[0, 2]) ax = float(p[0, 2])
ay = float(p[1, 2]) ay = float(p[1, 2])
az = float(p[2, 2]) az = float(p[2, 2])
else:
x = 0.
y = 0.
z = 0.
rx = 1.
ry = 0.
rz = 0.
ax = 0.
ay = 0.
az = 1.
object_placement.CartesianPosition = file.createIfcAxis2Placement3D( object_placement.CartesianPosition = file.createIfcAxis2Placement3D(
Location=file.createIfcCartesianPoint((x, y, z)), Location=file.createIfcCartesianPoint((x, y, z)),
Axis=file.createIfcDirection((ax, ay, az)), Axis=file.createIfcDirection((ax, ay, az)),
RefDirection=file.createIfcDirection((rx, ry, rz)), RefDirection=file.createIfcDirection((rx, ry, rz)),
) )
# this commented out code is what you would do to add a geometric representation of the referent # this commented out code is what you would do to add a geometric representation of the referent
# the example is a circle. a better way would be to pass a representation into the function # the example is a circle. a better way would be to pass a representation into the function
# representation = file.create_entity( # representation = file.create_entity(
@@ -130,7 +130,6 @@ def add_stationing_referent(
# ) # )
# create referent for the station # create referent for the station
predefined_type = "STATION" if element.is_a("IfcAlignment") else "POSITION"
referent = file.createIfcReferent( referent = file.createIfcReferent(
GlobalId=ifcopenshell.guid.new(), GlobalId=ifcopenshell.guid.new(),
OwnerHistory=None, OwnerHistory=None,
@@ -139,14 +138,16 @@ def add_stationing_referent(
ObjectType=None, ObjectType=None,
ObjectPlacement=object_placement, ObjectPlacement=object_placement,
Representation=representation, Representation=representation,
PredefinedType=predefined_type, PredefinedType="STATION",
) )
pset_stationing = ifcopenshell.api.pset.add_pset(file, product=referent, name="Pset_Stationing") pset_stationing = ifcopenshell.api.pset.add_pset(file, product=referent, name="Pset_Stationing")
ifcopenshell.api.pset.edit_pset(file, pset=pset_stationing, properties={"Station": station}) ifcopenshell.api.pset.edit_pset(file, pset=pset_stationing, properties={"Station": station})
nest = ifcopenshell.api.alignment.get_referent_nest(file, element) 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"))
if len(referent.Positions) == 0: if len(referent.Positions) == 0:
rel_positions = file.createIfcRelPositions( rel_positions = file.createIfcRelPositions(
GlobalId=ifcopenshell.guid.new(), GlobalId=ifcopenshell.guid.new(),
@@ -50,9 +50,22 @@ def _move_vertical_layout_to_child_alignment(
# nest the vertical layout onto the child alignment # nest the vertical layout onto the child alignment
ifcopenshell.api.nest.assign_object(file, related_objects=[vertical_layout], relating_object=child_alignment) ifcopenshell.api.nest.assign_object(file, related_objects=[vertical_layout], relating_object=child_alignment)
# aggreage the child alignment to the parent alignment # aggregate the child alignment to the parent 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
child_referent_nest = ifcopenshell.api.alignment.get_referent_nest(file,child_alignment)
parent_referent_nest = ifcopenshell.api.alignment.get_referent_nest(file,parent_alignment)
for referent in parent_referent_nest.RelatedObjects:
for product in referent.Positions[0].RelatedProducts:
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
# 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
ifcopenshell.api.nest.unassign_object(file,[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:
@@ -231,8 +231,9 @@ def add_zero_length_segment(file: ifcopenshell.file, layout: entity_instance, in
if include_referent: if include_referent:
alignment = ifcopenshell.api.alignment.get_alignment(layout) alignment = ifcopenshell.api.alignment.get_alignment(layout)
station = ifcopenshell.api.alignment.get_alignment_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)})"
ifcopenshell.api.alignment.add_stationing_referent(file, zero_length_curve_segment, 0.0, station, name=name) 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()}"
return True return True
@@ -79,17 +79,15 @@ def create(
if include_geometry: if include_geometry:
_create_geometric_representation(file, alignment) _create_geometric_representation(file, alignment)
for layout in alignment_layouts:
_add_zero_length_segment(file, layout)
if include_geometry:
# 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( referent = ifcopenshell.api.alignment.add_stationing_referent(
file, alignment, 0.0, start_station, name, alignment file, alignment, 0.0, start_station, name, alignment
) )
for layout in alignment_layouts:
_add_zero_length_segment(file, layout)
# 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]
if project: if project:
@@ -53,11 +53,6 @@ def create_as_offset_curve(
_create_offset_curve_representation(file, alignment, offsets) _create_offset_curve_representation(file, alignment, offsets)
# define stationing
# name = ifcopenshell.util.alignment.station_as_string(file, start_station)
# referent = ifcopenshell.api.alignment.add_stationing_referent(file, alignment, 0.0, start_station, name)
# 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]
if project: if project:
@@ -43,6 +43,6 @@ def distance_along_from_station(file: ifcopenshell.file, alignment: entity_insta
print(dist_along) # 100.00 print(dist_along) # 100.00
""" """
start_station = ifcopenshell.api.alignment.get_alignment_station(file, alignment) start_station = ifcopenshell.api.alignment.get_alignment_start_station(file, alignment)
dist_along = station - start_station dist_along = station - start_station
return dist_along return dist_along
@@ -22,10 +22,10 @@ import ifcopenshell.util.element
from ifcopenshell import entity_instance from ifcopenshell import entity_instance
def get_alignment_station(file: ifcopenshell.file, alignment: entity_instance) -> float: def get_alignment_start_station(file: ifcopenshell.file, alignment: entity_instance) -> float:
""" """
Returns the start station of the alignment. If the alignment is nested by an IfcReferent Returns the start station of the alignment. The starting station is defined by the first nested IfcReferent.
the referent is checked for PredefinedType of STATION and an occurance of Pset_Stationing.Station, This is interpreted to mean the first IfcReferent with an occurance of Pset_Stationing.Station,
otherwise returns 0.0. otherwise returns 0.0.
""" """
@@ -36,12 +36,13 @@ def get_alignment_station(file: ifcopenshell.file, alignment: entity_instance) -
parent_alignment = ifcopenshell.api.alignment.get_parent_alignment(alignment) parent_alignment = ifcopenshell.api.alignment.get_parent_alignment(alignment)
if parent_alignment: if parent_alignment:
start_station = ifcopenshell.api.alignment.get_alignment_station(file, parent_alignment) start_station = ifcopenshell.api.alignment.get_alignment_start_station(file, parent_alignment)
else: else:
components = ifcopenshell.util.element.get_components(alignment) components = ifcopenshell.util.element.get_components(alignment)
for c in components: for c in components:
if c.is_a("IfcReferent") and ifcopenshell.util.element.get_predefined_type(c) == "STATION": if c.is_a("IfcReferent"):
start_station = ifcopenshell.util.element.get_pset(c, name="Pset_Stationing", prop="Station") start_station = ifcopenshell.util.element.get_pset(c, name="Pset_Stationing", prop="Station")
break if not start_station == None:
break
return start_station return start_station
@@ -20,18 +20,23 @@ import ifcopenshell
from ifcopenshell import entity_instance from ifcopenshell import entity_instance
def get_referent_nest(file: ifcopenshell.file, entity: entity_instance) -> entity_instance: def get_referent_nest(file: ifcopenshell.file, alignment: entity_instance) -> entity_instance:
""" """
Searches for the IfcRelNest that contains IfcReferent. If one is not found, a empty IfcRelNests is created. Searches for the IfcRelNest that contains IfcReferent. If one is not found, a empty IfcRelNests is created.
:param file: :param file:
:param entity: any entity that is the parent in a nesting relationship, but intended to be IfcAlignment, IfcAlignmentHorizontal, IfcAlignmentVertical, or IfcAlignmentCant :param alignment: The IfcAlignment which hosts IfcReferent
:return: Returns the IfcRelNests. :return: Returns the IfcRelNests.
""" """
for nest in entity.IsNestedBy: if not alignment.is_a("IfcAlignment"):
raise TypeError(
f"Expected IfcAlignment, instead received {alignment.is_a()}"
)
for nest in alignment.IsNestedBy:
for related_object in nest.RelatedObjects: for related_object in nest.RelatedObjects:
if related_object.is_a("IfcReferent"): if related_object.is_a("IfcReferent"):
return nest return nest
nest = file.createIfcRelNests(GlobalId=ifcopenshell.guid.new(), RelatingObject=entity, RelatedObjects=[]) nest = file.createIfcRelNests(GlobalId=ifcopenshell.guid.new(), RelatingObject=alignment, RelatedObjects=[])
return nest return nest
@@ -67,11 +67,11 @@ def test_add_segment_to_layout():
_add_segment_to_layout(file, horizontal_alignment, alignment_segment) _add_segment_to_layout(file, horizontal_alignment, alignment_segment)
assert len(horizontal_alignment.IsNestedBy) == 2 assert len(horizontal_alignment.IsNestedBy) == 1
referent_nest = ifcopenshell.api.alignment.get_referent_nest(file, horizontal_alignment)
segment_nest = ifcopenshell.api.alignment.get_alignment_segment_nest(horizontal_alignment) segment_nest = ifcopenshell.api.alignment.get_alignment_segment_nest(horizontal_alignment)
assert len(segment_nest.RelatedObjects) == 2 assert len(segment_nest.RelatedObjects) == 2
assert len(referent_nest.RelatedObjects) == 2 referent_nest = ifcopenshell.api.alignment.get_referent_nest(file, alignment)
assert len(referent_nest.RelatedObjects) == 3
test_add_segment_to_layout() test_add_segment_to_layout()
@@ -39,14 +39,17 @@ 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)
for rel in alignment.IsNestedBy: referent_nest = ifcopenshell.api.alignment.get_referent_nest(file,alignment)
for referent in rel.RelatedObjects: referent = referent_nest.RelatedObjects[0]
if referent.is_a("IfcReferent"):
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") ifcopenshell.util.element.get_pset(element=referent, name="Pset_Stationing", prop="Station")
== 2000.0 == 2000.0
) )
assert referent.ObjectPlacement != None assert referent.ObjectPlacement != None
test_add_stationing_to_alignment()
@@ -33,9 +33,13 @@ def test_add_vertical_alignment():
assert len(alignment.IsDecomposedBy) == 0 # no child alignments assert len(alignment.IsDecomposedBy) == 0 # no child alignments
assert len(alignment.IsNestedBy) == 2 # nests for layout and referents assert len(alignment.IsNestedBy) == 2 # nests for layout and referents
assert len(alignment.IsNestedBy[0].RelatedObjects) == 1 layout_nest = ifcopenshell.api.alignment.get_alignment_layout_nest(alignment)
assert ifcopenshell.api.alignment.get_referent_nest(file, alignment).RelatedObjects[0].is_a("IfcReferent") assert len(layout_nest.RelatedObjects) == 1
assert alignment.IsNestedBy[0].RelatedObjects[0].is_a("IfcAlignmentHorizontal") assert layout_nest.RelatedObjects[0].is_a("IfcAlignmentHorizontal")
referent_nest = ifcopenshell.api.alignment.get_referent_nest(file,alignment)
assert len(referent_nest.RelatedObjects) == 2
assert referent_nest.RelatedObjects[0].is_a("IfcReferent")
curve = ifcopenshell.api.alignment.get_curve(alignment) curve = ifcopenshell.api.alignment.get_curve(alignment)
assert curve.is_a("IfcCompositeCurve") assert curve.is_a("IfcCompositeCurve")
@@ -43,9 +47,10 @@ def test_add_vertical_alignment():
assert len(alignment.IsDecomposedBy) == 0 # no child alignments assert len(alignment.IsDecomposedBy) == 0 # no child alignments
assert len(alignment.IsNestedBy) == 2 assert len(alignment.IsNestedBy) == 2
assert len(alignment.IsNestedBy[0].RelatedObjects) == 2 assert len(layout_nest.RelatedObjects) == 2
assert alignment.IsNestedBy[0].RelatedObjects[0].is_a("IfcAlignmentHorizontal") assert layout_nest.RelatedObjects[0].is_a("IfcAlignmentHorizontal")
assert alignment.IsNestedBy[0].RelatedObjects[1].is_a("IfcAlignmentVertical") assert layout_nest.RelatedObjects[1].is_a("IfcAlignmentVertical")
curve = ifcopenshell.api.alignment.get_curve(alignment) curve = ifcopenshell.api.alignment.get_curve(alignment)
assert curve.is_a("IfcGradientCurve") assert curve.is_a("IfcGradientCurve")
@@ -57,13 +62,14 @@ def test_add_vertical_alignment():
for child_alignment in alignment.IsDecomposedBy[0].RelatedObjects: for child_alignment in alignment.IsDecomposedBy[0].RelatedObjects:
assert child_alignment.is_a("IfcAlignment") assert child_alignment.is_a("IfcAlignment")
assert len(child_alignment.IsNestedBy) == 1 # one nesting relationship for the IfcAlignmentVertical assert len(child_alignment.IsNestedBy) == 2
assert len(child_alignment.IsNestedBy[0].RelatedObjects) == 1 # The IfcAlignmentVertical child_layout_nest = ifcopenshell.api.alignment.get_alignment_layout_nest(child_alignment)
assert child_alignment.IsNestedBy[0].RelatedObjects[0].is_a("IfcAlignmentVertical") assert len(child_layout_nest.RelatedObjects) == 1 # The IfcAlignmentVertical
assert child_layout_nest.RelatedObjects[0].is_a("IfcAlignmentVertical")
assert len(alignment.IsNestedBy) == 2 assert len(alignment.IsNestedBy) == 2
assert len(alignment.IsNestedBy[0].RelatedObjects) == 1 assert len(layout_nest.RelatedObjects) == 1
assert alignment.IsNestedBy[0].RelatedObjects[0].is_a("IfcAlignmentHorizontal") assert layout_nest.RelatedObjects[0].is_a("IfcAlignmentHorizontal")
test_add_vertical_alignment() test_add_vertical_alignment()
@@ -51,17 +51,16 @@ 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)
assert len(referent_nest.RelatedObjects) == 19
horizontal_layout = ifcopenshell.api.alignment.get_horizontal_layout(alignment) horizontal_layout = ifcopenshell.api.alignment.get_horizontal_layout(alignment)
horizontal_segment_nest = ifcopenshell.api.alignment.get_alignment_segment_nest(horizontal_layout) horizontal_segment_nest = ifcopenshell.api.alignment.get_alignment_segment_nest(horizontal_layout)
assert len(horizontal_segment_nest.RelatedObjects) == 8 assert len(horizontal_segment_nest.RelatedObjects) == 8
horizontal_referent_nest = ifcopenshell.api.alignment.get_referent_nest(file, horizontal_layout)
assert len(horizontal_referent_nest.RelatedObjects) == 8
vertical_layout = ifcopenshell.api.alignment.get_vertical_layout(alignment) vertical_layout = ifcopenshell.api.alignment.get_vertical_layout(alignment)
vertical_segment_nest = ifcopenshell.api.alignment.get_alignment_segment_nest(vertical_layout) vertical_segment_nest = ifcopenshell.api.alignment.get_alignment_segment_nest(vertical_layout)
assert len(vertical_segment_nest.RelatedObjects) == 10 assert len(vertical_segment_nest.RelatedObjects) == 10
vertical_referent_nest = ifcopenshell.api.alignment.get_referent_nest(file, vertical_layout)
assert len(vertical_referent_nest.RelatedObjects) == 10
test_create_by_pi_method() test_create_by_pi_method()
@@ -97,36 +97,16 @@ def callback_alignment():
def test_with_default_names(default_names_alignment): def test_with_default_names(default_names_alignment):
hlayout = ifcopenshell.api.alignment.get_horizontal_layout(default_names_alignment) referent_nest = ifcopenshell.api.alignment.get_referent_nest(None, default_names_alignment)
referent_nest = ifcopenshell.api.alignment.get_referent_nest(None, hlayout)
assert "P.O.B." in referent_nest.RelatedObjects[0].Name expected = ["P.O.B", "P.C.", "P.T.", "P.O.E.", "V.P.O.B.", "P.V.C.", "P.V.T.", "V.P.O.E"]
assert "P.C." in referent_nest.RelatedObjects[1].Name for r in referent_nest.RelatedObjects:
assert "P.T." in referent_nest.RelatedObjects[2].Name assert [x in r.Name for x in expected]
assert "P.O.E." in referent_nest.RelatedObjects[-1].Name
vlayout = ifcopenshell.api.alignment.get_vertical_layout(default_names_alignment)
referent_nest = ifcopenshell.api.alignment.get_referent_nest(None, vlayout)
assert "V.P.O.B." in referent_nest.RelatedObjects[0].Name
assert "P.V.C." in referent_nest.RelatedObjects[1].Name
assert "P.V.T." in referent_nest.RelatedObjects[2].Name
assert "V.P.O.E." in referent_nest.RelatedObjects[-1].Name
def test_with_callbacks(callback_alignment): def test_with_callbacks(callback_alignment):
hlayout = ifcopenshell.api.alignment.get_horizontal_layout(callback_alignment) referent_nest = ifcopenshell.api.alignment.get_referent_nest(None, callback_alignment)
referent_nest = ifcopenshell.api.alignment.get_referent_nest(None, hlayout)
assert "A" in referent_nest.RelatedObjects[0].Name expected = ["A","Q","Z","a","q","z"]
assert "Q" in referent_nest.RelatedObjects[1].Name for r in referent_nest.RelatedObjects:
assert "Q" in referent_nest.RelatedObjects[2].Name assert [x in r.Name for x in expected]
assert "Z" in referent_nest.RelatedObjects[-1].Name
vlayout = ifcopenshell.api.alignment.get_vertical_layout(callback_alignment)
referent_nest = ifcopenshell.api.alignment.get_referent_nest(None, vlayout)
assert "a" in referent_nest.RelatedObjects[0].Name
assert "q" in referent_nest.RelatedObjects[1].Name
assert "q" in referent_nest.RelatedObjects[2].Name
assert "z" in referent_nest.RelatedObjects[-1].Name
@@ -58,11 +58,15 @@ def test_vertical_layout_by_pi_method():
ifcopenshell.api.alignment.layout_vertical_alignment_by_pi_method(file, vlayout, vpoints, lengths) ifcopenshell.api.alignment.layout_vertical_alignment_by_pi_method(file, vlayout, vpoints, lengths)
assert len(alignment.IsDecomposedBy) == 0 # no child alignments assert len(alignment.IsDecomposedBy) == 0 # no child alignments
assert len(alignment.IsNestedBy) == 2 assert len(alignment.IsNestedBy) == 2
referent_nest = ifcopenshell.api.alignment.get_referent_nest(file, alignment)
layout_nest = ifcopenshell.api.alignment.get_alignment_layout_nest(alignment) layout_nest = ifcopenshell.api.alignment.get_alignment_layout_nest(alignment)
assert len(referent_nest.RelatedObjects) == 1
assert len(layout_nest.RelatedObjects) == 2 assert len(layout_nest.RelatedObjects) == 2
referent_nest = ifcopenshell.api.alignment.get_referent_nest(file, alignment)
assert len(referent_nest.RelatedObjects) == 6
segment_nest = ifcopenshell.api.alignment.get_alignment_segment_nest(vlayout) segment_nest = ifcopenshell.api.alignment.get_alignment_segment_nest(vlayout)
assert len(segment_nest.RelatedObjects) == 3 assert len(segment_nest.RelatedObjects) == 3