mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-19 14:41:25 +00:00
Allows key point referents to be nested to the parent alignment in the reusing horizontal scenario
This commit is contained in:
@@ -115,11 +115,19 @@ def update_key_point_referents(
|
|||||||
get_stationing_nest) -- key-point referents never belong in either of those.
|
get_stationing_nest) -- key-point referents never belong in either of those.
|
||||||
|
|
||||||
:param layout: IfcAlignmentHorizontal, IfcAlignmentVertical, or IfcAlignmentCant
|
:param layout: IfcAlignmentHorizontal, IfcAlignmentVertical, or IfcAlignmentCant
|
||||||
:param rel_nests: an existing IfcRelNests to (re)populate; its RelatingObject must be the
|
:param rel_nests: an existing IfcRelNests to (re)populate; its RelatingObject must be an
|
||||||
IfcAlignment that nests `layout` (TypeError is raised otherwise). If omitted, a new
|
IfcAlignment (TypeError is raised otherwise), but need not be the IfcAlignment that
|
||||||
IfcRelNests is always created and related to that IfcAlignment -- there is no implicit
|
directly nests `layout` -- passing an ancestor's own IfcRelNests is supported
|
||||||
search for or reuse of a previously created nest. Callers who want to regenerate into an
|
specifically so that a vertical/cant layout living under a child IfcAlignment (per CT
|
||||||
existing nest must pass it back in explicitly via `rel_nests`.
|
4.1.4.4.1.2, once a second vertical layout is added) can still have its key-point
|
||||||
|
referents named after and nested to the top-level parent alignment, matching how the
|
||||||
|
alignment's horizontal key points are named, rather than a generic "Child of X" name.
|
||||||
|
When `rel_nests` is given, `rel_nests.RelatingObject` -- not `layout`'s own direct
|
||||||
|
parent -- is used for both the created referents' Name and the returned IfcRelNests. If
|
||||||
|
omitted, a new IfcRelNests is always created and related to `layout`'s own direct
|
||||||
|
parent alignment -- there is no implicit search for or reuse of a previously created
|
||||||
|
nest. Callers who want to regenerate into an existing nest must pass it back in
|
||||||
|
explicitly via `rel_nests`.
|
||||||
:param clear: if True, deletes all IfcReferent currently in rel_nests.RelatedObjects (and their
|
:param clear: if True, deletes all IfcReferent currently in rel_nests.RelatedObjects (and their
|
||||||
Pset_Stationing) before regenerating. If False (default), new referents are appended to
|
Pset_Stationing) before regenerating. If False (default), new referents are appended to
|
||||||
whatever already exists -- no deduplication.
|
whatever already exists -- no deduplication.
|
||||||
@@ -155,17 +163,25 @@ def update_key_point_referents(
|
|||||||
f"Expected entity type to be one of {[_ for _ in expected_types]}, instead received {layout.is_a()}"
|
f"Expected entity type to be one of {[_ for _ in expected_types]}, instead received {layout.is_a()}"
|
||||||
)
|
)
|
||||||
|
|
||||||
alignment = ifcopenshell.api.alignment.get_alignment(layout)
|
layout_alignment = ifcopenshell.api.alignment.get_alignment(layout)
|
||||||
if alignment is None:
|
if layout_alignment is None:
|
||||||
raise ValueError(f"{layout.is_a()} #{layout.id()} is not nested under an IfcAlignment.")
|
raise ValueError(f"{layout.is_a()} #{layout.id()} is not nested under an IfcAlignment.")
|
||||||
|
|
||||||
|
# `alignment` is used below for referent naming (and as the fallback-placement basis) --
|
||||||
|
# it defaults to layout's own direct parent, but an explicitly passed rel_nests overrides
|
||||||
|
# it with rel_nests.RelatingObject instead (see the rel_nests docstring above). Station
|
||||||
|
# computation always uses layout_alignment, unaffected by this -- get_alignment_start_station
|
||||||
|
# already walks up to the true top-level alignment's own stationing referent regardless of
|
||||||
|
# which (possibly child) alignment it's given.
|
||||||
if rel_nests is not None:
|
if rel_nests is not None:
|
||||||
if not rel_nests.RelatingObject.is_a("IfcAlignment"):
|
if not rel_nests.RelatingObject.is_a("IfcAlignment"):
|
||||||
raise TypeError(
|
raise TypeError(
|
||||||
f"Expected rel_nests.RelatingObject to be IfcAlignment, instead received "
|
f"Expected rel_nests.RelatingObject to be IfcAlignment, instead received "
|
||||||
f"{rel_nests.RelatingObject.is_a()}"
|
f"{rel_nests.RelatingObject.is_a()}"
|
||||||
)
|
)
|
||||||
|
alignment = rel_nests.RelatingObject
|
||||||
else:
|
else:
|
||||||
|
alignment = layout_alignment
|
||||||
rel_nests = file.createIfcRelNests(
|
rel_nests = file.createIfcRelNests(
|
||||||
GlobalId=ifcopenshell.guid.new(), RelatingObject=alignment, RelatedObjects=()
|
GlobalId=ifcopenshell.guid.new(), RelatingObject=alignment, RelatedObjects=()
|
||||||
)
|
)
|
||||||
@@ -185,7 +201,7 @@ def update_key_point_referents(
|
|||||||
)
|
)
|
||||||
return rel_nests
|
return rel_nests
|
||||||
|
|
||||||
start_station = ifcopenshell.api.alignment.get_alignment_start_station(file, alignment)
|
start_station = ifcopenshell.api.alignment.get_alignment_start_station(file, layout_alignment)
|
||||||
curve = ifcopenshell.api.alignment.get_layout_curve(layout)
|
curve = ifcopenshell.api.alignment.get_layout_curve(layout)
|
||||||
is_horizontal = layout.is_a("IfcAlignmentHorizontal")
|
is_horizontal = layout.is_a("IfcAlignmentHorizontal")
|
||||||
|
|
||||||
|
|||||||
@@ -373,6 +373,41 @@ def test_start_station_composes_for_child_alignment():
|
|||||||
assert stations == pytest.approx([100.0, 600.0, 900.0])
|
assert stations == pytest.approx([100.0, 600.0, 900.0])
|
||||||
|
|
||||||
|
|
||||||
|
def test_rel_nests_from_ancestor_used_for_naming_and_nesting():
|
||||||
|
"""A vertical layout living under a child alignment (once a second vertical layout is
|
||||||
|
added, per CT 4.1.4.4.1.2) can still have its key-point referents named after and nested
|
||||||
|
to an ancestor alignment's own rel_nests -- e.g. the same one already holding that
|
||||||
|
ancestor's horizontal key points -- rather than the child's generic "Child of X" name."""
|
||||||
|
file = _new_file()
|
||||||
|
alignment = ifcopenshell.api.alignment.create(file, "A1", include_vertical=False, start_station=100.0)
|
||||||
|
horizontal = ifcopenshell.api.alignment.get_horizontal_layout(alignment)
|
||||||
|
horizontal_nest = ifcopenshell.api.alignment.update_key_point_referents(file, horizontal)
|
||||||
|
horizontal_count = len(horizontal_nest.RelatedObjects)
|
||||||
|
|
||||||
|
ifcopenshell.api.alignment.add_vertical_layout(file, alignment)
|
||||||
|
ifcopenshell.api.alignment.add_vertical_layout(file, alignment) # forces the child-alignment split
|
||||||
|
child_alignment = alignment.IsDecomposedBy[0].RelatedObjects[-1]
|
||||||
|
child_vertical = ifcopenshell.api.alignment.get_vertical_layout(child_alignment)
|
||||||
|
|
||||||
|
dp = file.createIfcAlignmentVerticalSegment(
|
||||||
|
StartDistAlong=0.0,
|
||||||
|
HorizontalLength=500.0,
|
||||||
|
StartHeight=10.0,
|
||||||
|
StartGradient=0.01,
|
||||||
|
EndGradient=0.01,
|
||||||
|
PredefinedType="CONSTANTGRADIENT",
|
||||||
|
)
|
||||||
|
ifcopenshell.api.alignment.create_layout_segment(file, child_vertical, dp)
|
||||||
|
|
||||||
|
result = ifcopenshell.api.alignment.update_key_point_referents(file, child_vertical, rel_nests=horizontal_nest)
|
||||||
|
|
||||||
|
assert result == horizontal_nest
|
||||||
|
assert result.RelatingObject == alignment
|
||||||
|
assert len(result.RelatedObjects) == horizontal_count + 2
|
||||||
|
assert all(r.Name.startswith("A1 ") for r in result.RelatedObjects)
|
||||||
|
assert not any("Child of" in r.Name for r in result.RelatedObjects)
|
||||||
|
|
||||||
|
|
||||||
def test_returns_ifc_rel_nests():
|
def test_returns_ifc_rel_nests():
|
||||||
file = _new_file()
|
file = _new_file()
|
||||||
alignment = _build_alignment(file)
|
alignment = _build_alignment(file)
|
||||||
@@ -399,4 +434,5 @@ test_cant_layout_boundary_labels()
|
|||||||
test_no_real_segments_produces_no_referents()
|
test_no_real_segments_produces_no_referents()
|
||||||
test_single_real_segment_produces_only_boundary_labels()
|
test_single_real_segment_produces_only_boundary_labels()
|
||||||
test_start_station_composes_for_child_alignment()
|
test_start_station_composes_for_child_alignment()
|
||||||
|
test_rel_nests_from_ancestor_used_for_naming_and_nesting()
|
||||||
test_returns_ifc_rel_nests()
|
test_returns_ifc_rel_nests()
|
||||||
|
|||||||
Reference in New Issue
Block a user