Alignment api update (#6817)

* Some basic COGO survey points functions

* Update alignment api

Includes defining alignment segment by segment, automatic geometry definitions, and automatric stationing and referents

* Fixes bonsai import alignment from csv

* Adds DMS angle conversion functions to COGO api

* Updated per @civilx64 review comments

* Fixes problem with segment representations

* Fixes problem with segment transition codes

* Allows for compound vertical and horizontal curves

* Implements callbacks for referent naming

* Renames angle_from_bearing to bearing2dd for consistency with ifcopenshell.util.geolocation.dms2dd. Removes angle_from_dms because it duplicates dms2dd

* Documents register_referent_name_callback

* Fixes all sorts of problems with Cant/SegRefCurve implementation

* refactor referent unit tests to use a fixture for test setup

* lint with black

---------

Co-authored-by: Scott Lecher <civilx64@gmail.com>
This commit is contained in:
Richard Brice
2025-07-08 10:09:14 -07:00
committed by GitHub
parent ad8d02bfed
commit 40f92d15c3
76 changed files with 3645 additions and 1839 deletions
@@ -22,40 +22,29 @@ import ifcopenshell.util.element
from ifcopenshell import entity_instance
def has_zero_length_segment(entity: entity_instance) -> bool:
def has_zero_length_segment(layout: entity_instance) -> bool:
"""
Returns true if the entity ends with a zero length segment. If the entity is an IfcCompositeCurve the IfcCurveSegment.Transition must be DISCONTINUOUS
Returns true if the layout ends with a zero length segment.
:param entity: An IfcAlignmentHorizontal, IfcAlignmentVertical, IfcAlignmentCant or IfcCompositeCurve
:param layout: An IfcAlignmentHorizontal, IfcAlignmentVertical, or IfcAlignmentCant
:return: True if the zero length segment is present
"""
expected_types = [
"IfcAlignmentHorizontal",
"IfcAlignmentVertical",
"IfcAlignmentCant",
"IfcCompositeCurve",
"IfcGradientCurve",
"IfcSegmentedReferenceCurve",
]
if not entity.is_a() in expected_types:
expected_types = ["IfcAlignmentHorizontal", "IfcAlignmentVertical", "IfcAlignmentCant"]
if not layout.is_a() in expected_types:
raise TypeError(
f"Expected entity type to be one of {[_ for _ in expected_types]}, instead received '{entity.is_a()}"
f"Expected entity type to be one of {[_ for _ in expected_types]}, instead received '{layout.is_a()}"
)
if entity.is_a("IfcCompositeCurve"):
last_segment = entity.Segments[-1]
return last_segment.Transition == "DISCONTINUOUS" and last_segment.SegmentLength.wrappedValue == 0.0
else:
segments = ifcopenshell.util.element.get_components(entity)
for rel in entity.IsNestedBy:
if 0 < len(rel.RelatedObjects):
last_segment = rel.RelatedObjects[-1]
if last_segment.is_a("IfcAlignmentSegment"):
if last_segment.DesignParameters.is_a("IfcAlignmentHorizontalSegment"):
return last_segment.DesignParameters.SegmentLength == 0.0
elif last_segment.DesignParameters.is_a("IfcAlignmentVerticalSegment"):
return last_segment.DesignParameters.HorizontalLength == 0.0
elif last_segment.DesignParameters.is_a("IfcAlignmentCantSegment"):
return last_segment.DesignParameters.HorizontalLength == 0.0
result = False
for rel in layout.IsNestedBy:
if 0 < len(rel.RelatedObjects):
last_segment = rel.RelatedObjects[-1]
if last_segment.is_a("IfcAlignmentSegment"):
if last_segment.DesignParameters.is_a("IfcAlignmentHorizontalSegment"):
result = last_segment.DesignParameters.SegmentLength == 0.0
elif last_segment.DesignParameters.is_a("IfcAlignmentVerticalSegment"):
result = last_segment.DesignParameters.HorizontalLength == 0.0
elif last_segment.DesignParameters.is_a("IfcAlignmentCantSegment"):
result = last_segment.DesignParameters.HorizontalLength == 0.0
return False
return result