diff --git a/src/ifcopenshell-python/ifcopenshell/api/alignment/_get_cant_segment.py b/src/ifcopenshell-python/ifcopenshell/api/alignment/_get_cant_segment.py new file mode 100644 index 0000000000..fe88d33c61 --- /dev/null +++ b/src/ifcopenshell-python/ifcopenshell/api/alignment/_get_cant_segment.py @@ -0,0 +1,77 @@ +# IfcOpenShell - IFC toolkit and geometry engine +# Copyright (C) 2025 Thomas Krijnen +# +# This file is part of IfcOpenShell. +# +# IfcOpenShell is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# IfcOpenShell is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with IfcOpenShell. If not, see . + +import ifcopenshell +import ifcopenshell.api.alignment +import ifcopenshell.api.geometry +from ifcopenshell import entity_instance + +import math +from collections.abc import Sequence + + +def _get_cant_segment(horizontal_segment: entity_instance) -> entity_instance: + """ + Returns the IfcAlignmentSegment from the cant layout that corresponds to horizontal_segment. + Returns None if the cant segment cannot be found + """ + + expected_type = "IfcAlignmentSegment" + if not horizontal_segment.is_a(expected_type): + raise TypeError(f"Expected {expected_type} but got {horizontal_segment.is_a()}") + + if not horizontal_segment.DesignParameters.is_a("IfcAlignmentHorizontalSegment"): + raise TypeError(f"Expect DesignParameter to be IfcAlignmentHorizontal but got {horizontal_segment.DesignParameters.is_a()}") + + # get the index of horizontal_segment in the horizontal_layout + horizontal_layout = horizontal_segment.Nests[0].RelatingObject + index = 0 + for segment in horizontal_layout.IsNestedBy[0].RelatedObjects: + if segment == horizontal_segment: + break + else: + index += 1 + + cant_segment = None + + # first check CT 4.1.4.4.1.1 Alignment Layout - Horizontal, Vertical and Cant + nests_layouts = horizontal_layout.Nests[0] + for layout in nests_layouts.RelatedObjects: + if layout.is_a("IfcAlignmentCant"): + cant_segment = layout.IsNestedBy[0].RelatedObjects[index] + break + + # if a cant_segment wasn't found, check CT 4.1.4.4.1.2 Alignment Layout - Reusing Horizontal Layout + # Note that nothing forbids multiple child alignments to have cant layouts. However, this would not make + # sense for Viennese Bend because the Viennese Bend cant segment influences the geometry of the horizontal + # Viennese Bend transition curve segment. The horizontal geometry would not be unique if there are + # multiple child alignments with cant layouts. + # For this reason, use the first cant layout found + if cant_segment == None: + alignment = ifcopenshell.api.alignment.get_alignment(horizontal_layout) + for child_alignment in alignment.IsDecomposedBy[0].RelatedObjects: + for layout in child_alignment.Nests[0].RelatedObjects: + if layout.is_a("IfcAlignmentCant"): + cant_segment = layout.IsNestedBy[0].RelatedObjects[index] + break + if cant_segment: + break + + + return cant_segment + diff --git a/src/ifcopenshell-python/ifcopenshell/api/alignment/_map_alignment_cant_segment.py b/src/ifcopenshell-python/ifcopenshell/api/alignment/_map_alignment_cant_segment.py index 1e5481f9ea..d24a6d9135 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/alignment/_map_alignment_cant_segment.py +++ b/src/ifcopenshell-python/ifcopenshell/api/alignment/_map_alignment_cant_segment.py @@ -377,7 +377,66 @@ def _map_sine_curve( def _map_viennese_bend( file: ifcopenshell.file, design_parameters: entity_instance, rail_head_distance: float ) -> Sequence[entity_instance]: - raise NotImplementedError("VIENNESEBEND not implemented") + dist_along = design_parameters.StartDistAlong + length = design_parameters.HorizontalLength + Dsl = design_parameters.StartCantLeft + Del = design_parameters.EndCantLeft + Dsr = design_parameters.StartCantRight + Der = design_parameters.EndCantRight + + Ds = 0.5 * (Dsl + Dsr) + De = 0.5 * (Del + Der) + f = De - Ds + + a0 = Ds # constant term + a1 = 0.0 # linear term + a2 = 0.0 * f # quadratic term + a3 = 0.0 * f # cubic term + a4 = 35. * f # quartic term + a5 = -84.*f # quintic term + a6 = 70.*f # sextic term + a7 = -20.*f # septic term + + transition = "DISCONTINUOUS" + + A0 = math.pow(length, 2.0 / 1.0) * math.pow(math.fabs(a0), -1.0 / 1.0) * (a0 / math.fabs(a0)) if a0 != 0.0 else 0.0 + A1 = math.pow(length, 3.0 / 2.0) * math.pow(math.fabs(a1), -1.0 / 2.0) * (a1 / math.fabs(a1)) if a1 != 0.0 else 0.0 + A2 = math.pow(length, 4.0 / 3.0) * math.pow(math.fabs(a2), -1.0 / 3.0) * (a2 / math.fabs(a2)) if a2 != 0.0 else 0.0 + A3 = math.pow(length, 5.0 / 4.0) * math.pow(math.fabs(a3), -1.0 / 4.0) * (a3 / math.fabs(a3)) if a3 != 0.0 else 0.0 + A4 = math.pow(length, 6.0 / 5.0) * math.pow(math.fabs(a4), -1.0 / 5.0) * (a4 / math.fabs(a4)) if a4 != 0.0 else 0.0 + A5 = math.pow(length, 7.0 / 6.0) * math.pow(math.fabs(a5), -1.0 / 6.0) * (a5 / math.fabs(a5)) if a5 != 0.0 else 0.0 + A6 = math.pow(length, 8.0 / 7.0) * math.pow(math.fabs(a6), -1.0 / 7.0) * (a6 / math.fabs(a6)) if a6 != 0.0 else 0.0 + A7 = math.pow(length, 9.0 / 8.0) * math.pow(math.fabs(a7), -1.0 / 8.0) * (a7 / math.fabs(a7)) if a7 != 0.0 else 0.0 + + parent_curve = file.createIfcSeventhOrderPolynomialSpiral( + Position=file.createIfcAxis2Placement2D( + Location=file.createIfcCartesianPoint((0.0, 0.0)), RefDirection=file.createIfcDirection((1.0, 0.0)) + ), + SepticTerm=A7, + SexticTerm=A6 if A6 != 0.0 else None, + QuinticTerm=A5 if A5 != 0.0 else None, + QuarticTerm=A4 if A4 != 0.0 else None, + CubicTerm=A3 if A3 != 0.0 else None, + QuadraticTerm=A2 if A2 != 0.0 else None, + LinearTerm=A1 if A1 != 0.0 else None, + ConstantTerm=A0 if A0 != 0.0 else None, + ) + + start_point = file.createIfcCartesianPoint((dist_along, Ds, 0.0)) + start_direction = 0.0 + + curve_segment = file.createIfcCurveSegment( + Transition=transition, + Placement=file.createIfcAxis2Placement3D( + Location=start_point, + Axis=_get_axis(file, Ds, rail_head_distance), + RefDirection=file.createIfcDirection((math.cos(start_direction), math.sin(start_direction), 0.0)), + ), + SegmentStart=file.createIfcLengthMeasure(0.0), + SegmentLength=file.createIfcLengthMeasure(length), + ParentCurve=parent_curve, + ) + return (curve_segment, None) def _map_alignment_cant_segment( diff --git a/src/ifcopenshell-python/ifcopenshell/api/alignment/_map_alignment_horizontal_segment.py b/src/ifcopenshell-python/ifcopenshell/api/alignment/_map_alignment_horizontal_segment.py index 297d628031..64b2a64b0d 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/alignment/_map_alignment_horizontal_segment.py +++ b/src/ifcopenshell-python/ifcopenshell/api/alignment/_map_alignment_horizontal_segment.py @@ -22,6 +22,8 @@ import ifcopenshell.ifcopenshell_wrapper as ifcopenshell_wrapper from collections.abc import Sequence import math +from ifcopenshell.api.alignment._get_cant_segment import _get_cant_segment + def _get_curve_factor(design_parameters: entity_instance) -> float: start_radius = design_parameters.StartRadiusOfCurvature @@ -290,22 +292,6 @@ def _map_helmert_curve(file: ifcopenshell.file, design_parameters: entity_instan ParentCurve=parent_curve2, ) - """ - import numpy as np - settings = ifcopenshell.geom.settings() - prev_segment_fn = ifcopenshell_wrapper.map_shape(settings, curve_segment1.wrapped_data) - prev_segment_evaluator = ifcopenshell_wrapper.function_item_evaluator(settings, prev_segment_fn) - e = prev_segment_evaluator.evaluate(prev_segment_fn.end()) - end = np.array(e) - - segment_fn = ifcopenshell_wrapper.map_shape(settings, curve_segment2.wrapped_data) - segment_evaluator = ifcopenshell_wrapper.function_item_evaluator(settings, segment_fn) - s = segment_evaluator.evaluate(segment_fn.start()) - start = np.array(s) - - assert(np.allclose(end[:3,3],start[:3,3])) - """ - return curve_segment1, curve_segment2 @@ -444,8 +430,87 @@ def _map_sine_curve(file: ifcopenshell.file, design_parameters: entity_instance) return (curve_segment, None) -def _map_viennese_bend(file: ifcopenshell.file, design_parameters: entity_instance) -> Sequence[entity_instance]: - raise NotImplementedError("VIENNESEBEND not implemented") +def _map_viennese_bend(file: ifcopenshell.file, segment: entity_instance) -> Sequence[entity_instance]: + design_parameters = segment.DesignParameters + + start_point = design_parameters.StartPoint + start_direction = design_parameters.StartDirection + start_radius = design_parameters.StartRadiusOfCurvature + length = design_parameters.SegmentLength + gravity_centerline_height = design_parameters.GravityCenterLineHeight if design_parameters.GravityCenterLineHeight != None else 0.0 + + angle_unit_scale = ifcopenshell.util.unit.calculate_unit_scale(file, "PLANEANGLEUNIT") + start_direction *= angle_unit_scale + + transition = "DISCONTINUOUS" + + cant_segment = _get_cant_segment(segment) + if cant_segment: + start_cant_left = cant_segment.DesignParameters.StartCantLeft + end_cant_left = cant_segment.DesignParameters.EndCantLeft if cant_segment.DesignParameters.EndCantLeft else 0.0 + start_cant_right = cant_segment.DesignParameters.StartCantRight + end_cant_right = cant_segment.DesignParameters.EndCantRight if cant_segment.DesignParameters.EndCantRight else 0.0 + cant_layout = cant_segment.Nests[0].RelatingObject + rail_head_distance = cant_layout.RailHeadDistance + else: + start_cant_left = 0. + end_cant_left = 0. + start_cant_right = 0. + end_cant_right = 0. + rail_head_distance = 1. + + cant_angle_start = (start_cant_right - start_cant_left)/rail_head_distance if rail_head_distance else 0. + cant_angle_end = (end_cant_right - end_cant_left)/rail_head_distance if rail_head_distance else 0. + + cant_factor = -420.*(gravity_centerline_height/length)*(cant_angle_end - cant_angle_start) + + f = _get_curve_factor(design_parameters) + + a0 = length / start_radius if start_radius != 0.0 else 0.0 # constant term + a1 = 0. # linear term + a2 = 1.*cant_factor # quadratic term + a3 = -4.*cant_factor # cubic term + a4 = 5.*cant_factor + 35.*f # quartic term + a5 = -2.*cant_factor - 84.*f # quintic term + a6 = 70.*f # sextic term + a7 = -20.0*f # septic term + + A0 = length*math.pow(math.fabs(a0),-1.0 / 1.0) * (a0 / math.fabs(a0)) if a0 != 0.0 else 0.0 + A1 = length*math.pow(math.fabs(a1),-1.0 / 2.0) * (a1 / math.fabs(a1)) if a1 != 0.0 else 0.0 + A2 = length*math.pow(math.fabs(a2),-1.0 / 3.0) * (a2 / math.fabs(a2)) if a2 != 0.0 else 0.0 + A3 = length*math.pow(math.fabs(a3),-1.0 / 4.0) * (a3 / math.fabs(a3)) if a3 != 0.0 else 0.0 + A4 = length*math.pow(math.fabs(a4),-1.0 / 5.0) * (a4 / math.fabs(a4)) if a4 != 0.0 else 0.0 + A5 = length*math.pow(math.fabs(a5),-1.0 / 6.0) * (a5 / math.fabs(a5)) if a5 != 0.0 else 0.0 + A6 = length*math.pow(math.fabs(a6),-1.0 / 7.0) * (a6 / math.fabs(a6)) if a6 != 0.0 else 0.0 + A7 = length*math.pow(math.fabs(a7),-1.0 / 8.0) * (a7 / math.fabs(a7)) if a7 != 0.0 else 0.0 + + parent_curve = file.createIfcSeventhOrderPolynomialSpiral( + Position=file.createIfcAxis2Placement2D( + Location=file.createIfcCartesianPoint((0.0, 0.0)), RefDirection=file.createIfcDirection((1.0, 0.0)) + ), + SepticTerm=A7, + SexticTerm=A6 if A6 != 0.0 else None, + QuinticTerm=A5 if A5 != 0.0 else None, + QuarticTerm=A4 if A4 != 0.0 else None, + CubicTerm=A3 if A3 != 0.0 else None, + QuadraticTerm=A2 if A2 != 0.0 else None, + LinearTerm=A1 if A1 != 0.0 else None, + ConstantTerm=A0 if A0 != 0.0 else None, + ) + + curve_segment = file.create_entity( + type="IfcCurveSegment", + Transition=transition, + Placement=file.create_entity( + type="IfcAxis2Placement2D", + Location=start_point, + RefDirection=file.createIfcDirection((math.cos(start_direction), math.sin(start_direction))), + ), + SegmentStart=file.createIfcLengthMeasure(0.0), + SegmentLength=file.createIfcLengthMeasure(length), + ParentCurve=parent_curve, + ) + return (curve_segment, None) def _map_alignment_horizontal_segment(file: ifcopenshell.file, segment: entity_instance) -> Sequence[entity_instance]: @@ -477,7 +542,7 @@ def _map_alignment_horizontal_segment(file: ifcopenshell.file, segment: entity_i elif predefined_type == "SINECURVE": result = _map_sine_curve(file, segment.DesignParameters) elif predefined_type == "VIENNESEBEND": - result = _map_viennese_bend(file, segment.DesignParameters) + result = _map_viennese_bend(file, segment) else: raise TypeError(f"Unexpected predefined type: '{predefined_type}'.") diff --git a/src/ifcopenshell-python/ifcopenshell/api/alignment/create.py b/src/ifcopenshell-python/ifcopenshell/api/alignment/create.py index 04a7ebb582..7abb768174 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/alignment/create.py +++ b/src/ifcopenshell-python/ifcopenshell/api/alignment/create.py @@ -46,6 +46,9 @@ def create( Use get_horizontal_layout(alignment) to get the IfcAlignmentHorizontal layout. + If the alignment has Viennese Bend transition curves, create the cant layout before the horizontal layout. This is because the horizontal layout + in the Viennese Bend transition curves depends on the Viennese Bend cant parameters. + :param file: :param name: name assigned to IfcAlignment.Name :param include_vertical: If True, IfcAlignmentVertical and IfcGradientCurve are created diff --git a/src/ifcopenshell-python/test/api/alignment/test_map_alignment_cant_segment.py b/src/ifcopenshell-python/test/api/alignment/test_map_alignment_cant_segment.py index 483e7b977c..46e0a871e7 100644 --- a/src/ifcopenshell-python/test/api/alignment/test_map_alignment_cant_segment.py +++ b/src/ifcopenshell-python/test/api/alignment/test_map_alignment_cant_segment.py @@ -1605,6 +1605,277 @@ def _SineCurve_100_0__inf__300_1_Meter(file): assert mapped_segment.ParentCurve.LinearTerm == pytest.approx(3535.53390593274) assert mapped_segment.ParentCurve.ConstantTerm == pytest.approx(None) +def _VienneseBend_100_0_300_1000_1_Meter(file): + design_parameters = file.createIfcAlignmentCantSegment( + StartDistAlong=0.0, + HorizontalLength=100.0, + StartCantLeft=0.0, + EndCantLeft=0.0, + StartCantRight=0.1, + EndCantRight=0.03, + PredefinedType="VIENNESEBEND") + + alignment_segment = file.createIfcAlignmentSegment( + GlobalId=ifcopenshell.guid.new(), + DesignParameters=design_parameters) + + mapped_segments = _map_alignment_cant_segment(file,alignment_segment, 1.5) + mapped_segment = mapped_segments[0] + assert len(mapped_segments) == 2 + assert "DISCONTINUOUS" == mapped_segment.Transition + assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 0.05, 0.0)) + assert mapped_segment.Placement.RefDirection.DirectionRatios == pytest.approx((1.0, 0.0, 0.0)) + assert mapped_segment.SegmentStart.wrappedValue == pytest.approx(0.0) + assert mapped_segment.SegmentLength.wrappedValue == pytest.approx(100.0) + assert mapped_segment.ParentCurve.is_a("IfcSeventhOrderPolynomialSpiral") + assert mapped_segment.ParentCurve.Position.Location.Coordinates == pytest.approx((0.0, 0.0)) + assert mapped_segment.ParentCurve.Position.RefDirection.DirectionRatios == pytest.approx((1.0,0.0)) + assert mapped_segment.ParentCurve.SepticTerm == pytest.approx(185.93568367635672) + assert mapped_segment.ParentCurve.SexticTerm == pytest.approx(-169.87095595653895) + assert mapped_segment.ParentCurve.QuinticTerm == pytest.approx(180.0012184608678) + assert mapped_segment.ParentCurve.QuarticTerm == pytest.approx(-241.1974890085123) + assert mapped_segment.ParentCurve.CubicTerm == pytest.approx(None) + assert mapped_segment.ParentCurve.QuadraticTerm == pytest.approx(None) + assert mapped_segment.ParentCurve.LinearTerm == pytest.approx(None) + assert mapped_segment.ParentCurve.ConstantTerm == pytest.approx(200000.0) + +def _VienneseBend_100_0__300__1000_1_Meter(file): + design_parameters = file.createIfcAlignmentCantSegment( + StartDistAlong=0.0, + HorizontalLength=100.0, + StartCantLeft=0.1, + EndCantLeft=0.03, + StartCantRight=0.0, + EndCantRight=0.0, + PredefinedType="VIENNESEBEND") + + alignment_segment = file.createIfcAlignmentSegment( + GlobalId=ifcopenshell.guid.new(), + DesignParameters=design_parameters) + + mapped_segments = _map_alignment_cant_segment(file,alignment_segment, 1.5) + mapped_segment = mapped_segments[0] + assert len(mapped_segments) == 2 + assert "DISCONTINUOUS" == mapped_segment.Transition + assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 0.05, 0.0)) + assert mapped_segment.Placement.RefDirection.DirectionRatios == pytest.approx((1.0, 0.0, 0.0)) + assert mapped_segment.SegmentStart.wrappedValue == pytest.approx(0.0) + assert mapped_segment.SegmentLength.wrappedValue == pytest.approx(100.0) + assert mapped_segment.ParentCurve.is_a("IfcSeventhOrderPolynomialSpiral") + assert mapped_segment.ParentCurve.Position.Location.Coordinates == pytest.approx((0.0, 0.0)) + assert mapped_segment.ParentCurve.Position.RefDirection.DirectionRatios == pytest.approx((1.0,0.0)) + assert mapped_segment.ParentCurve.SepticTerm == pytest.approx(185.93568367635672) + assert mapped_segment.ParentCurve.SexticTerm == pytest.approx(-169.87095595653895) + assert mapped_segment.ParentCurve.QuinticTerm == pytest.approx(180.0012184608678) + assert mapped_segment.ParentCurve.QuarticTerm == pytest.approx(-241.1974890085123) + assert mapped_segment.ParentCurve.CubicTerm == pytest.approx(None) + assert mapped_segment.ParentCurve.QuadraticTerm == pytest.approx(None) + assert mapped_segment.ParentCurve.LinearTerm == pytest.approx(None) + assert mapped_segment.ParentCurve.ConstantTerm == pytest.approx(200000.0) + +def _VienneseBend_100_0_300_inf_1_Meter(file): + design_parameters = file.createIfcAlignmentCantSegment( + StartDistAlong=0.0, + HorizontalLength=100.0, + StartCantLeft=0.0, + EndCantLeft=0.0, + StartCantRight=0.1, + EndCantRight=0.0, + PredefinedType="VIENNESEBEND") + + alignment_segment = file.createIfcAlignmentSegment( + GlobalId=ifcopenshell.guid.new(), + DesignParameters=design_parameters) + + mapped_segments = _map_alignment_cant_segment(file,alignment_segment, 1.5) + mapped_segment = mapped_segments[0] + assert len(mapped_segments) == 2 + assert "DISCONTINUOUS" == mapped_segment.Transition + assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 0.05, 0.0)) + assert mapped_segment.Placement.RefDirection.DirectionRatios == pytest.approx((1.0, 0.0, 0.0)) + assert mapped_segment.SegmentStart.wrappedValue == pytest.approx(0.0) + assert mapped_segment.SegmentLength.wrappedValue == pytest.approx(100.0) + assert mapped_segment.ParentCurve.is_a("IfcSeventhOrderPolynomialSpiral") + assert mapped_segment.ParentCurve.Position.Location.Coordinates == pytest.approx((0.0, 0.0)) + assert mapped_segment.ParentCurve.Position.RefDirection.DirectionRatios == pytest.approx((1.0,0.0)) + assert mapped_segment.ParentCurve.SepticTerm == pytest.approx(177.82794100389228) + assert mapped_segment.ParentCurve.SexticTerm == pytest.approx(-161.4322423756691) + assert mapped_segment.ParentCurve.QuinticTerm == pytest.approx(169.6127328157867) + assert mapped_segment.ParentCurve.QuarticTerm == pytest.approx(-224.5910214113641) + assert mapped_segment.ParentCurve.CubicTerm == pytest.approx(None) + assert mapped_segment.ParentCurve.QuadraticTerm == pytest.approx(None) + assert mapped_segment.ParentCurve.LinearTerm == pytest.approx(None) + assert mapped_segment.ParentCurve.ConstantTerm == pytest.approx(200000.0) + +def _VienneseBend_100_0__300__inf_1_Meter(file): + design_parameters = file.createIfcAlignmentCantSegment( + StartDistAlong=0.0, + HorizontalLength=100.0, + StartCantLeft=0.1, + EndCantLeft=0.0, + StartCantRight=0.0, + EndCantRight=0.0, + PredefinedType="VIENNESEBEND") + + alignment_segment = file.createIfcAlignmentSegment( + GlobalId=ifcopenshell.guid.new(), + DesignParameters=design_parameters) + + mapped_segments = _map_alignment_cant_segment(file,alignment_segment, 1.5) + mapped_segment = mapped_segments[0] + assert len(mapped_segments) == 2 + assert "DISCONTINUOUS" == mapped_segment.Transition + assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 0.05, 0.0)) + assert mapped_segment.Placement.RefDirection.DirectionRatios == pytest.approx((1.0, 0.0, 0.0)) + assert mapped_segment.SegmentStart.wrappedValue == pytest.approx(0.0) + assert mapped_segment.SegmentLength.wrappedValue == pytest.approx(100.0) + assert mapped_segment.ParentCurve.is_a("IfcSeventhOrderPolynomialSpiral") + assert mapped_segment.ParentCurve.Position.Location.Coordinates == pytest.approx((0.0, 0.0)) + assert mapped_segment.ParentCurve.Position.RefDirection.DirectionRatios == pytest.approx((1.0,0.0)) + assert mapped_segment.ParentCurve.SepticTerm == pytest.approx(177.82794100389228) + assert mapped_segment.ParentCurve.SexticTerm == pytest.approx(-161.4322423756691) + assert mapped_segment.ParentCurve.QuinticTerm == pytest.approx(169.6127328157867) + assert mapped_segment.ParentCurve.QuarticTerm == pytest.approx(-224.5910214113641) + assert mapped_segment.ParentCurve.CubicTerm == pytest.approx(None) + assert mapped_segment.ParentCurve.QuadraticTerm == pytest.approx(None) + assert mapped_segment.ParentCurve.LinearTerm == pytest.approx(None) + assert mapped_segment.ParentCurve.ConstantTerm == pytest.approx(200000.0) + +def _VienneseBend_100_0_1000_300_1_Meter(file): + design_parameters = file.createIfcAlignmentCantSegment( + StartDistAlong=0.0, + HorizontalLength=100.0, + StartCantLeft=0.0, + EndCantLeft=0.0, + StartCantRight=0.03, + EndCantRight=0.1, + PredefinedType="VIENNESEBEND") + + alignment_segment = file.createIfcAlignmentSegment( + GlobalId=ifcopenshell.guid.new(), + DesignParameters=design_parameters) + + mapped_segments = _map_alignment_cant_segment(file,alignment_segment, 1.5) + mapped_segment = mapped_segments[0] + assert len(mapped_segments) == 2 + assert "DISCONTINUOUS" == mapped_segment.Transition + assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 0.015, 0.0)) + assert mapped_segment.Placement.RefDirection.DirectionRatios == pytest.approx((1.0, 0.0, 0.0)) + assert mapped_segment.SegmentStart.wrappedValue == pytest.approx(0.0) + assert mapped_segment.SegmentLength.wrappedValue == pytest.approx(100.0) + assert mapped_segment.ParentCurve.is_a("IfcSeventhOrderPolynomialSpiral") + assert mapped_segment.ParentCurve.Position.Location.Coordinates == pytest.approx((0.0, 0.0)) + assert mapped_segment.ParentCurve.Position.RefDirection.DirectionRatios == pytest.approx((1.0,0.0)) + assert mapped_segment.ParentCurve.SepticTerm == pytest.approx(-185.93568367635672) + assert mapped_segment.ParentCurve.SexticTerm == pytest.approx(169.87095595653895) + assert mapped_segment.ParentCurve.QuinticTerm == pytest.approx(-180.0012184608678) + assert mapped_segment.ParentCurve.QuarticTerm == pytest.approx(241.1974890085123) + assert mapped_segment.ParentCurve.CubicTerm == pytest.approx(None) + assert mapped_segment.ParentCurve.QuadraticTerm == pytest.approx(None) + assert mapped_segment.ParentCurve.LinearTerm == pytest.approx(None) + assert mapped_segment.ParentCurve.ConstantTerm == pytest.approx(666666.666666667) + +def _VienneseBend_100_0__1000__300_1_Meter(file): + design_parameters = file.createIfcAlignmentCantSegment( + StartDistAlong=0.0, + HorizontalLength=100.0, + StartCantLeft=0.03, + EndCantLeft=0.1, + StartCantRight=0.0, + EndCantRight=0.0, + PredefinedType="VIENNESEBEND") + + alignment_segment = file.createIfcAlignmentSegment( + GlobalId=ifcopenshell.guid.new(), + DesignParameters=design_parameters) + + mapped_segments = _map_alignment_cant_segment(file,alignment_segment, 1.5) + mapped_segment = mapped_segments[0] + assert len(mapped_segments) == 2 + assert "DISCONTINUOUS" == mapped_segment.Transition + assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 0.015, 0.0)) + assert mapped_segment.Placement.RefDirection.DirectionRatios == pytest.approx((1.0, 0.0, 0.0)) + assert mapped_segment.SegmentStart.wrappedValue == pytest.approx(0.0) + assert mapped_segment.SegmentLength.wrappedValue == pytest.approx(100.0) + assert mapped_segment.ParentCurve.is_a("IfcSeventhOrderPolynomialSpiral") + assert mapped_segment.ParentCurve.Position.Location.Coordinates == pytest.approx((0.0, 0.0)) + assert mapped_segment.ParentCurve.Position.RefDirection.DirectionRatios == pytest.approx((1.0,0.0)) + assert mapped_segment.ParentCurve.SepticTerm == pytest.approx(-185.93568367635672) + assert mapped_segment.ParentCurve.SexticTerm == pytest.approx(169.87095595653895) + assert mapped_segment.ParentCurve.QuinticTerm == pytest.approx(-180.0012184608678) + assert mapped_segment.ParentCurve.QuarticTerm == pytest.approx(241.1974890085123) + assert mapped_segment.ParentCurve.CubicTerm == pytest.approx(None) + assert mapped_segment.ParentCurve.QuadraticTerm == pytest.approx(None) + assert mapped_segment.ParentCurve.LinearTerm == pytest.approx(None) + assert mapped_segment.ParentCurve.ConstantTerm == pytest.approx(666666.666666667) + +def _VienneseBend_100_0_inf_300_1_Meter(file): + design_parameters = file.createIfcAlignmentCantSegment( + StartDistAlong=0.0, + HorizontalLength=100.0, + StartCantLeft=0.0, + EndCantLeft=0.0, + StartCantRight=0.0, + EndCantRight=0.1, + PredefinedType="VIENNESEBEND") + + alignment_segment = file.createIfcAlignmentSegment( + GlobalId=ifcopenshell.guid.new(), + DesignParameters=design_parameters) + + mapped_segments = _map_alignment_cant_segment(file,alignment_segment, 1.5) + mapped_segment = mapped_segments[0] + assert len(mapped_segments) == 2 + assert "DISCONTINUOUS" == mapped_segment.Transition + assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 0.0, 0.0)) + assert mapped_segment.Placement.RefDirection.DirectionRatios == pytest.approx((1.0, 0.0, 0.0)) + assert mapped_segment.SegmentStart.wrappedValue == pytest.approx(0.0) + assert mapped_segment.SegmentLength.wrappedValue == pytest.approx(100.0) + assert mapped_segment.ParentCurve.is_a("IfcSeventhOrderPolynomialSpiral") + assert mapped_segment.ParentCurve.Position.Location.Coordinates == pytest.approx((0.0, 0.0)) + assert mapped_segment.ParentCurve.Position.RefDirection.DirectionRatios == pytest.approx((1.0,0.0)) + assert mapped_segment.ParentCurve.SepticTerm == pytest.approx(-177.82794100389228) + assert mapped_segment.ParentCurve.SexticTerm == pytest.approx(161.4322423756691) + assert mapped_segment.ParentCurve.QuinticTerm == pytest.approx(-169.6127328157867) + assert mapped_segment.ParentCurve.QuarticTerm == pytest.approx(224.5910214113641) + assert mapped_segment.ParentCurve.CubicTerm == pytest.approx(None) + assert mapped_segment.ParentCurve.QuadraticTerm == pytest.approx(None) + assert mapped_segment.ParentCurve.LinearTerm == pytest.approx(None) + assert mapped_segment.ParentCurve.ConstantTerm == pytest.approx(None) + +def _VienneseBend_100_0__inf__300_1_Meter(file): + design_parameters = file.createIfcAlignmentCantSegment( + StartDistAlong=0.0, + HorizontalLength=100.0, + StartCantLeft=0.0, + EndCantLeft=0.1, + StartCantRight=0.0, + EndCantRight=0.0, + PredefinedType="VIENNESEBEND") + + alignment_segment = file.createIfcAlignmentSegment( + GlobalId=ifcopenshell.guid.new(), + DesignParameters=design_parameters) + + mapped_segments = _map_alignment_cant_segment(file,alignment_segment, 1.5) + mapped_segment = mapped_segments[0] + assert len(mapped_segments) == 2 + assert "DISCONTINUOUS" == mapped_segment.Transition + assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 0.0, 0.0)) + assert mapped_segment.Placement.RefDirection.DirectionRatios == pytest.approx((1.0, 0.0, 0.0)) + assert mapped_segment.SegmentStart.wrappedValue == pytest.approx(0.0) + assert mapped_segment.SegmentLength.wrappedValue == pytest.approx(100.0) + assert mapped_segment.ParentCurve.is_a("IfcSeventhOrderPolynomialSpiral") + assert mapped_segment.ParentCurve.Position.Location.Coordinates == pytest.approx((0.0, 0.0)) + assert mapped_segment.ParentCurve.Position.RefDirection.DirectionRatios == pytest.approx((1.0,0.0)) + assert mapped_segment.ParentCurve.SepticTerm == pytest.approx(-177.82794100389228) + assert mapped_segment.ParentCurve.SexticTerm == pytest.approx(161.4322423756691) + assert mapped_segment.ParentCurve.QuinticTerm == pytest.approx(-169.6127328157867) + assert mapped_segment.ParentCurve.QuarticTerm == pytest.approx(224.5910214113641) + assert mapped_segment.ParentCurve.CubicTerm == pytest.approx(None) + assert mapped_segment.ParentCurve.QuadraticTerm == pytest.approx(None) + assert mapped_segment.ParentCurve.LinearTerm == pytest.approx(None) + assert mapped_segment.ParentCurve.ConstantTerm == pytest.approx(None) def test_map_alignment_cant_segment(): file = ifcopenshell.file(schema="IFC4X3") @@ -1656,5 +1927,14 @@ def test_map_alignment_cant_segment(): _SineCurve_100_0__1000__300_1_Meter(file) _SineCurve_100_0_inf_300_1_Meter(file) _SineCurve_100_0__inf__300_1_Meter(file) + _VienneseBend_100_0_300_1000_1_Meter(file) + _VienneseBend_100_0__300__1000_1_Meter(file) + _VienneseBend_100_0_300_inf_1_Meter(file) + _VienneseBend_100_0__300__inf_1_Meter(file) + _VienneseBend_100_0_1000_300_1_Meter(file) + _VienneseBend_100_0__1000__300_1_Meter(file) + _VienneseBend_100_0_inf_300_1_Meter(file) + _VienneseBend_100_0__inf__300_1_Meter(file) - # VIENESSE BEND NOT IMPLEMENTED + +test_map_alignment_cant_segment() diff --git a/src/ifcopenshell-python/test/api/alignment/test_map_alignment_horizontal_segment.py b/src/ifcopenshell-python/test/api/alignment/test_map_alignment_horizontal_segment.py index 1d48fc1561..e3ef4cac20 100644 --- a/src/ifcopenshell-python/test/api/alignment/test_map_alignment_horizontal_segment.py +++ b/src/ifcopenshell-python/test/api/alignment/test_map_alignment_horizontal_segment.py @@ -2031,6 +2031,516 @@ def _SineCurve_100_0__inf__300_1_Meter(file): assert mapped_segment.ParentCurve.LinearTerm == pytest.approx(-173.205080756888) assert mapped_segment.ParentCurve.ConstantTerm == pytest.approx(None) +def _VienneseBend_100_0_300_1000_1_Meter(file): + project = file.createIfcProject(GlobalId=ifcopenshell.guid.new()) + length = ifcopenshell.api.unit.add_si_unit(file,unit_type="LENGTHUNIT") + ifcopenshell.api.unit.assign_unit(file,units=[length]) + + alignment = ifcopenshell.api.alignment.create(file,"",include_vertical=True,include_cant=True) + + # for viennese bends, the horizontal layout depends on the cant layout + # for this reason, define the cant segment before the horizontal segment + cant_layout = ifcopenshell.api.alignment.get_cant_layout(alignment) + cant_layout.RailHeadDistance=1.5 + design_parameters = file.createIfcAlignmentCantSegment( + StartDistAlong=0., + HorizontalLength=100., + StartCantLeft=0., + EndCantLeft=0., + StartCantRight=0.1, + EndCantRight=0.03, + PredefinedType="VIENNESEBEND" + + ) + ifcopenshell.api.alignment.create_layout_segment(file,cant_layout,design_parameters) + + horizontal_layout = ifcopenshell.api.alignment.get_horizontal_layout(alignment) + design_parameters = file.createIfcAlignmentHorizontalSegment( + StartPoint=file.createIfcCartesianPoint((0.0, 0.0)), + StartDirection=0.0, + StartRadiusOfCurvature=300.0, + EndRadiusOfCurvature=1000.0, + SegmentLength=100.0, + GravityCenterLineHeight=1.8, + PredefinedType="VIENNESEBEND") + ifcopenshell.api.alignment.create_layout_segment(file,horizontal_layout,design_parameters) + + vertical_layout = ifcopenshell.api.alignment.get_vertical_layout(alignment) + design_parameters = file.createIfcAlignmentVerticalSegment( + StartDistAlong=0., + HorizontalLength=100., + StartHeight=0., + StartGradient=0., + EndGradient=0., + PredefinedType = "CONSTANTGRADIENT" + ) + ifcopenshell.api.alignment.create_layout_segment(file,vertical_layout,design_parameters) + + alignment_segment = horizontal_layout.IsNestedBy[0].RelatedObjects[0] + mapped_segments = _map_alignment_horizontal_segment(file,alignment_segment) + mapped_segment = mapped_segments[0] + assert len(mapped_segments) == 2 + assert "DISCONTINUOUS" == mapped_segment.Transition + assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 0.0)) + assert mapped_segment.Placement.RefDirection.DirectionRatios == pytest.approx((1.0, 0.0)) + assert mapped_segment.SegmentStart.wrappedValue == pytest.approx(0.0) + assert mapped_segment.SegmentLength.wrappedValue == pytest.approx(100.0) + assert mapped_segment.ParentCurve.is_a("IfcSeventhOrderPolynomialSpiral") + assert mapped_segment.ParentCurve.Position.Location.Coordinates == pytest.approx((0.0, 0.0)) + assert mapped_segment.ParentCurve.Position.RefDirection.DirectionRatios == pytest.approx((1.0,0.0)) + assert mapped_segment.ParentCurve.SepticTerm == pytest.approx(82.48484305114) + assert mapped_segment.ParentCurve.SexticTerm == pytest.approx(-67.097076273516) + assert mapped_segment.ParentCurve.QuinticTerm == pytest.approx(61.2742234216927) + assert mapped_segment.ParentCurve.QuarticTerm == pytest.approx(-68.9807356362507) + assert mapped_segment.ParentCurve.CubicTerm == pytest.approx(-91.7493208218373) + assert mapped_segment.ParentCurve.QuadraticTerm == pytest.approx(141.521951256265) + assert mapped_segment.ParentCurve.LinearTerm == pytest.approx(None) + assert mapped_segment.ParentCurve.ConstantTerm == pytest.approx(300.0) + +def _VienneseBend_100_0__300__1000_1_Meter(file): + project = file.createIfcProject(GlobalId=ifcopenshell.guid.new()) + length = ifcopenshell.api.unit.add_si_unit(file,unit_type="LENGTHUNIT") + ifcopenshell.api.unit.assign_unit(file,units=[length]) + + alignment = ifcopenshell.api.alignment.create(file,"",include_vertical=True,include_cant=True) + + cant_layout = ifcopenshell.api.alignment.get_cant_layout(alignment) + cant_layout.RailHeadDistance=1.5 + design_parameters = file.createIfcAlignmentCantSegment( + StartDistAlong=0., + HorizontalLength=100., + StartCantLeft=0.1, + EndCantLeft=0.03, + StartCantRight=0., + EndCantRight=0., + PredefinedType="VIENNESEBEND" + + ) + ifcopenshell.api.alignment.create_layout_segment(file,cant_layout,design_parameters) + + horizontal_layout = ifcopenshell.api.alignment.get_horizontal_layout(alignment) + design_parameters = file.createIfcAlignmentHorizontalSegment( + StartPoint=file.createIfcCartesianPoint((0.0, 0.0)), + StartDirection=0.0, + StartRadiusOfCurvature=-300.0, + EndRadiusOfCurvature=-1000.0, + SegmentLength=100.0, + GravityCenterLineHeight=1.8, + PredefinedType="VIENNESEBEND") + ifcopenshell.api.alignment.create_layout_segment(file,horizontal_layout,design_parameters) + + vertical_layout = ifcopenshell.api.alignment.get_vertical_layout(alignment) + design_parameters = file.createIfcAlignmentVerticalSegment( + StartDistAlong=0., + HorizontalLength=100., + StartHeight=0., + StartGradient=0., + EndGradient=0., + PredefinedType = "CONSTANTGRADIENT" + ) + ifcopenshell.api.alignment.create_layout_segment(file,vertical_layout,design_parameters) + + alignment_segment = horizontal_layout.IsNestedBy[0].RelatedObjects[0] + mapped_segments = _map_alignment_horizontal_segment(file,alignment_segment) + mapped_segment = mapped_segments[0] + assert len(mapped_segments) == 2 + assert "DISCONTINUOUS" == mapped_segment.Transition + assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 0.0)) + assert mapped_segment.Placement.RefDirection.DirectionRatios == pytest.approx((1.0, 0.0)) + assert mapped_segment.SegmentStart.wrappedValue == pytest.approx(0.0) + assert mapped_segment.SegmentLength.wrappedValue == pytest.approx(100.0) + assert mapped_segment.ParentCurve.is_a("IfcSeventhOrderPolynomialSpiral") + assert mapped_segment.ParentCurve.Position.Location.Coordinates == pytest.approx((0.0, 0.0)) + assert mapped_segment.ParentCurve.Position.RefDirection.DirectionRatios == pytest.approx((1.0,0.0)) + assert mapped_segment.ParentCurve.SepticTerm == pytest.approx(-82.48484305114) + assert mapped_segment.ParentCurve.SexticTerm == pytest.approx(67.097076273516) + assert mapped_segment.ParentCurve.QuinticTerm == pytest.approx(-61.2742234216927) + assert mapped_segment.ParentCurve.QuarticTerm == pytest.approx(68.9807356362507) + assert mapped_segment.ParentCurve.CubicTerm == pytest.approx(91.7493208218373) + assert mapped_segment.ParentCurve.QuadraticTerm == pytest.approx(-141.521951256265) + assert mapped_segment.ParentCurve.LinearTerm == pytest.approx(None) + assert mapped_segment.ParentCurve.ConstantTerm == pytest.approx(-300.0) + +def _VienneseBend_100_0_300_inf_1_Meter(file): + project = file.createIfcProject(GlobalId=ifcopenshell.guid.new()) + length = ifcopenshell.api.unit.add_si_unit(file,unit_type="LENGTHUNIT") + ifcopenshell.api.unit.assign_unit(file,units=[length]) + + alignment = ifcopenshell.api.alignment.create(file,"",include_vertical=True,include_cant=True) + + cant_layout = ifcopenshell.api.alignment.get_cant_layout(alignment) + cant_layout.RailHeadDistance=1.5 + design_parameters = file.createIfcAlignmentCantSegment( + StartDistAlong=0., + HorizontalLength=100., + StartCantLeft=0., + EndCantLeft=0., + StartCantRight=0.1, + EndCantRight=0., + PredefinedType="VIENNESEBEND" + + ) + ifcopenshell.api.alignment.create_layout_segment(file,cant_layout,design_parameters) + + horizontal_layout = ifcopenshell.api.alignment.get_horizontal_layout(alignment) + design_parameters = file.createIfcAlignmentHorizontalSegment( + StartPoint=file.createIfcCartesianPoint((0.0, 0.0)), + StartDirection=0.0, + StartRadiusOfCurvature=300.0, + EndRadiusOfCurvature=0.0, + SegmentLength=100.0, + GravityCenterLineHeight=1.8, + PredefinedType="VIENNESEBEND") + ifcopenshell.api.alignment.create_layout_segment(file,horizontal_layout,design_parameters) + + vertical_layout = ifcopenshell.api.alignment.get_vertical_layout(alignment) + design_parameters = file.createIfcAlignmentVerticalSegment( + StartDistAlong=0., + HorizontalLength=100., + StartHeight=0., + StartGradient=0., + EndGradient=0., + PredefinedType = "CONSTANTGRADIENT" + ) + ifcopenshell.api.alignment.create_layout_segment(file,vertical_layout,design_parameters) + + alignment_segment = horizontal_layout.IsNestedBy[0].RelatedObjects[0] + mapped_segments = _map_alignment_horizontal_segment(file,alignment_segment) + mapped_segment = mapped_segments[0] + assert len(mapped_segments) == 2 + assert "DISCONTINUOUS" == mapped_segment.Transition + assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 0.0)) + assert mapped_segment.Placement.RefDirection.DirectionRatios == pytest.approx((1.0, 0.0)) + assert mapped_segment.SegmentStart.wrappedValue == pytest.approx(0.0) + assert mapped_segment.SegmentLength.wrappedValue == pytest.approx(100.0) + assert mapped_segment.ParentCurve.is_a("IfcSeventhOrderPolynomialSpiral") + assert mapped_segment.ParentCurve.Position.Location.Coordinates == pytest.approx((0.0, 0.0)) + assert mapped_segment.ParentCurve.Position.RefDirection.DirectionRatios == pytest.approx((1.0,0.0)) + assert mapped_segment.ParentCurve.SepticTerm == pytest.approx(78.8880838459446) + assert mapped_segment.ParentCurve.SexticTerm == pytest.approx(-63.7638813456506) + assert mapped_segment.ParentCurve.QuinticTerm == pytest.approx(57.7378785242934) + assert mapped_segment.ParentCurve.QuarticTerm == pytest.approx(-64.2314061308743) + assert mapped_segment.ParentCurve.CubicTerm == pytest.approx(-83.922298125931) + assert mapped_segment.ParentCurve.QuadraticTerm == pytest.approx(125.657906854859) + assert mapped_segment.ParentCurve.LinearTerm == pytest.approx(None) + assert mapped_segment.ParentCurve.ConstantTerm == pytest.approx(300.0) + +def _VienneseBend_100_0__300__inf_1_Meter(file): + project = file.createIfcProject(GlobalId=ifcopenshell.guid.new()) + length = ifcopenshell.api.unit.add_si_unit(file,unit_type="LENGTHUNIT") + ifcopenshell.api.unit.assign_unit(file,units=[length]) + + alignment = ifcopenshell.api.alignment.create(file,"",include_vertical=True,include_cant=True) + + cant_layout = ifcopenshell.api.alignment.get_cant_layout(alignment) + cant_layout.RailHeadDistance=1.5 + design_parameters = file.createIfcAlignmentCantSegment( + StartDistAlong=0., + HorizontalLength=100., + StartCantLeft=0.1, + EndCantLeft=0., + StartCantRight=0., + EndCantRight=0., + PredefinedType="VIENNESEBEND" + + ) + ifcopenshell.api.alignment.create_layout_segment(file,cant_layout,design_parameters) + + horizontal_layout = ifcopenshell.api.alignment.get_horizontal_layout(alignment) + design_parameters = file.createIfcAlignmentHorizontalSegment( + StartPoint=file.createIfcCartesianPoint((0.0, 0.0)), + StartDirection=0.0, + StartRadiusOfCurvature=-300.0, + EndRadiusOfCurvature=0.0, + SegmentLength=100.0, + GravityCenterLineHeight=1.8, + PredefinedType="VIENNESEBEND") + ifcopenshell.api.alignment.create_layout_segment(file,horizontal_layout,design_parameters) + + vertical_layout = ifcopenshell.api.alignment.get_vertical_layout(alignment) + design_parameters = file.createIfcAlignmentVerticalSegment( + StartDistAlong=0., + HorizontalLength=100., + StartHeight=0., + StartGradient=0., + EndGradient=0., + PredefinedType = "CONSTANTGRADIENT" + ) + ifcopenshell.api.alignment.create_layout_segment(file,vertical_layout,design_parameters) + + alignment_segment = horizontal_layout.IsNestedBy[0].RelatedObjects[0] + mapped_segments = _map_alignment_horizontal_segment(file,alignment_segment) + mapped_segment = mapped_segments[0] + assert len(mapped_segments) == 2 + assert "DISCONTINUOUS" == mapped_segment.Transition + assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 0.0)) + assert mapped_segment.Placement.RefDirection.DirectionRatios == pytest.approx((1.0, 0.0)) + assert mapped_segment.SegmentStart.wrappedValue == pytest.approx(0.0) + assert mapped_segment.SegmentLength.wrappedValue == pytest.approx(100.0) + assert mapped_segment.ParentCurve.is_a("IfcSeventhOrderPolynomialSpiral") + assert mapped_segment.ParentCurve.Position.Location.Coordinates == pytest.approx((0.0, 0.0)) + assert mapped_segment.ParentCurve.Position.RefDirection.DirectionRatios == pytest.approx((1.0,0.0)) + assert mapped_segment.ParentCurve.SepticTerm == pytest.approx(-78.8880838459446) + assert mapped_segment.ParentCurve.SexticTerm == pytest.approx(63.7638813456506) + assert mapped_segment.ParentCurve.QuinticTerm == pytest.approx(-57.7378785242934) + assert mapped_segment.ParentCurve.QuarticTerm == pytest.approx(64.2314061308743) + assert mapped_segment.ParentCurve.CubicTerm == pytest.approx(83.922298125931) + assert mapped_segment.ParentCurve.QuadraticTerm == pytest.approx(-125.657906854859) + assert mapped_segment.ParentCurve.LinearTerm == pytest.approx(None) + assert mapped_segment.ParentCurve.ConstantTerm == pytest.approx(-300.0) + +def _VienneseBend_100_0_1000_300_1_Meter(file): + project = file.createIfcProject(GlobalId=ifcopenshell.guid.new()) + length = ifcopenshell.api.unit.add_si_unit(file,unit_type="LENGTHUNIT") + ifcopenshell.api.unit.assign_unit(file,units=[length]) + + alignment = ifcopenshell.api.alignment.create(file,"",include_vertical=True,include_cant=True) + + cant_layout = ifcopenshell.api.alignment.get_cant_layout(alignment) + cant_layout.RailHeadDistance=1.5 + design_parameters = file.createIfcAlignmentCantSegment( + StartDistAlong=0., + HorizontalLength=100., + StartCantLeft=0., + EndCantLeft=0., + StartCantRight=0.03, + EndCantRight=0.1, + PredefinedType="VIENNESEBEND" + ) + ifcopenshell.api.alignment.create_layout_segment(file,cant_layout,design_parameters) + + horizontal_layout = ifcopenshell.api.alignment.get_horizontal_layout(alignment) + design_parameters = file.createIfcAlignmentHorizontalSegment( + StartPoint=file.createIfcCartesianPoint((0.0, 0.0)), + StartDirection=0.0, + StartRadiusOfCurvature=1000.0, + EndRadiusOfCurvature=300.0, + SegmentLength=100.0, + GravityCenterLineHeight=1.8, + PredefinedType="VIENNESEBEND") + ifcopenshell.api.alignment.create_layout_segment(file,horizontal_layout,design_parameters) + + vertical_layout = ifcopenshell.api.alignment.get_vertical_layout(alignment) + design_parameters = file.createIfcAlignmentVerticalSegment( + StartDistAlong=0., + HorizontalLength=100., + StartHeight=0., + StartGradient=0., + EndGradient=0., + PredefinedType = "CONSTANTGRADIENT" + ) + ifcopenshell.api.alignment.create_layout_segment(file,vertical_layout,design_parameters) + + alignment_segment = horizontal_layout.IsNestedBy[0].RelatedObjects[0] + mapped_segments = _map_alignment_horizontal_segment(file,alignment_segment) + mapped_segment = mapped_segments[0] + assert len(mapped_segments) == 2 + assert "DISCONTINUOUS" == mapped_segment.Transition + assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 0.0)) + assert mapped_segment.Placement.RefDirection.DirectionRatios == pytest.approx((1.0, 0.0)) + assert mapped_segment.SegmentStart.wrappedValue == pytest.approx(0.0) + assert mapped_segment.SegmentLength.wrappedValue == pytest.approx(100.0) + assert mapped_segment.ParentCurve.is_a("IfcSeventhOrderPolynomialSpiral") + assert mapped_segment.ParentCurve.Position.Location.Coordinates == pytest.approx((0.0, 0.0)) + assert mapped_segment.ParentCurve.Position.RefDirection.DirectionRatios == pytest.approx((1.0,0.0)) + assert mapped_segment.ParentCurve.SepticTerm == pytest.approx(-82.48484305114) + assert mapped_segment.ParentCurve.SexticTerm == pytest.approx(67.097076273516) + assert mapped_segment.ParentCurve.QuinticTerm == pytest.approx(-61.2742234216927) + assert mapped_segment.ParentCurve.QuarticTerm == pytest.approx(68.9807356362507) + assert mapped_segment.ParentCurve.CubicTerm == pytest.approx(91.7493208218373) + assert mapped_segment.ParentCurve.QuadraticTerm == pytest.approx(-141.521951256265) + assert mapped_segment.ParentCurve.LinearTerm == pytest.approx(None) + assert mapped_segment.ParentCurve.ConstantTerm == pytest.approx(1000.0) + +def _VienneseBend_100_0__1000__300_1_Meter(file): + project = file.createIfcProject(GlobalId=ifcopenshell.guid.new()) + length = ifcopenshell.api.unit.add_si_unit(file,unit_type="LENGTHUNIT") + ifcopenshell.api.unit.assign_unit(file,units=[length]) + + alignment = ifcopenshell.api.alignment.create(file,"",include_vertical=True,include_cant=True) + + cant_layout = ifcopenshell.api.alignment.get_cant_layout(alignment) + cant_layout.RailHeadDistance=1.5 + design_parameters = file.createIfcAlignmentCantSegment( + StartDistAlong=0., + HorizontalLength=100., + StartCantLeft=0.03, + EndCantLeft=0.1, + StartCantRight=0., + EndCantRight=0., + PredefinedType="VIENNESEBEND" + ) + ifcopenshell.api.alignment.create_layout_segment(file,cant_layout,design_parameters) + + horizontal_layout = ifcopenshell.api.alignment.get_horizontal_layout(alignment) + design_parameters = file.createIfcAlignmentHorizontalSegment( + StartPoint=file.createIfcCartesianPoint((0.0, 0.0)), + StartDirection=0.0, + StartRadiusOfCurvature=-1000.0, + EndRadiusOfCurvature=-300.0, + SegmentLength=100.0, + GravityCenterLineHeight=1.8, + PredefinedType="VIENNESEBEND") + ifcopenshell.api.alignment.create_layout_segment(file,horizontal_layout,design_parameters) + + vertical_layout = ifcopenshell.api.alignment.get_vertical_layout(alignment) + design_parameters = file.createIfcAlignmentVerticalSegment( + StartDistAlong=0., + HorizontalLength=100., + StartHeight=0., + StartGradient=0., + EndGradient=0., + PredefinedType = "CONSTANTGRADIENT" + ) + ifcopenshell.api.alignment.create_layout_segment(file,vertical_layout,design_parameters) + + alignment_segment = horizontal_layout.IsNestedBy[0].RelatedObjects[0] + mapped_segments = _map_alignment_horizontal_segment(file,alignment_segment) + mapped_segment = mapped_segments[0] + assert len(mapped_segments) == 2 + assert "DISCONTINUOUS" == mapped_segment.Transition + assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 0.0)) + assert mapped_segment.Placement.RefDirection.DirectionRatios == pytest.approx((1.0, 0.0)) + assert mapped_segment.SegmentStart.wrappedValue == pytest.approx(0.0) + assert mapped_segment.SegmentLength.wrappedValue == pytest.approx(100.0) + assert mapped_segment.ParentCurve.is_a("IfcSeventhOrderPolynomialSpiral") + assert mapped_segment.ParentCurve.Position.Location.Coordinates == pytest.approx((0.0, 0.0)) + assert mapped_segment.ParentCurve.Position.RefDirection.DirectionRatios == pytest.approx((1.0,0.0)) + assert mapped_segment.ParentCurve.SepticTerm == pytest.approx(82.48484305114) + assert mapped_segment.ParentCurve.SexticTerm == pytest.approx(-67.097076273516) + assert mapped_segment.ParentCurve.QuinticTerm == pytest.approx(61.2742234216927) + assert mapped_segment.ParentCurve.QuarticTerm == pytest.approx(-68.9807356362507) + assert mapped_segment.ParentCurve.CubicTerm == pytest.approx(-91.7493208218373) + assert mapped_segment.ParentCurve.QuadraticTerm == pytest.approx(141.521951256265) + assert mapped_segment.ParentCurve.LinearTerm == pytest.approx(None) + assert mapped_segment.ParentCurve.ConstantTerm == pytest.approx(-1000.0) + +def _VienneseBend_100_0_inf_300_1_Meter(file): + project = file.createIfcProject(GlobalId=ifcopenshell.guid.new()) + length = ifcopenshell.api.unit.add_si_unit(file,unit_type="LENGTHUNIT") + ifcopenshell.api.unit.assign_unit(file,units=[length]) + + alignment = ifcopenshell.api.alignment.create(file,"",include_vertical=True,include_cant=True) + + cant_layout = ifcopenshell.api.alignment.get_cant_layout(alignment) + cant_layout.RailHeadDistance=1.5 + design_parameters = file.createIfcAlignmentCantSegment( + StartDistAlong=0., + HorizontalLength=100., + StartCantLeft=0., + EndCantLeft=0., + StartCantRight=0., + EndCantRight=0.1, + PredefinedType="VIENNESEBEND" + ) + ifcopenshell.api.alignment.create_layout_segment(file,cant_layout,design_parameters) + + horizontal_layout = ifcopenshell.api.alignment.get_horizontal_layout(alignment) + design_parameters = file.createIfcAlignmentHorizontalSegment( + StartPoint=file.createIfcCartesianPoint((0.0, 0.0)), + StartDirection=0.0, + StartRadiusOfCurvature=0.0, + EndRadiusOfCurvature=300.0, + SegmentLength=100.0, + GravityCenterLineHeight=1.8, + PredefinedType="VIENNESEBEND") + ifcopenshell.api.alignment.create_layout_segment(file,horizontal_layout,design_parameters) + + vertical_layout = ifcopenshell.api.alignment.get_vertical_layout(alignment) + design_parameters = file.createIfcAlignmentVerticalSegment( + StartDistAlong=0., + HorizontalLength=100., + StartHeight=0., + StartGradient=0., + EndGradient=0., + PredefinedType = "CONSTANTGRADIENT" + ) + ifcopenshell.api.alignment.create_layout_segment(file,vertical_layout,design_parameters) + + alignment_segment = horizontal_layout.IsNestedBy[0].RelatedObjects[0] + mapped_segments = _map_alignment_horizontal_segment(file,alignment_segment) + mapped_segment = mapped_segments[0] + assert len(mapped_segments) == 2 + assert "DISCONTINUOUS" == mapped_segment.Transition + assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 0.0)) + assert mapped_segment.Placement.RefDirection.DirectionRatios == pytest.approx((1.0, 0.0)) + assert mapped_segment.SegmentStart.wrappedValue == pytest.approx(0.0) + assert mapped_segment.SegmentLength.wrappedValue == pytest.approx(100.0) + assert mapped_segment.ParentCurve.is_a("IfcSeventhOrderPolynomialSpiral") + assert mapped_segment.ParentCurve.Position.Location.Coordinates == pytest.approx((0.0, 0.0)) + assert mapped_segment.ParentCurve.Position.RefDirection.DirectionRatios == pytest.approx((1.0,0.0)) + assert mapped_segment.ParentCurve.SepticTerm == pytest.approx(-78.8880838459446) + assert mapped_segment.ParentCurve.SexticTerm == pytest.approx(63.7638813456506) + assert mapped_segment.ParentCurve.QuinticTerm == pytest.approx(-57.7378785242934) + assert mapped_segment.ParentCurve.QuarticTerm == pytest.approx(64.2314061308743) + assert mapped_segment.ParentCurve.CubicTerm == pytest.approx(83.922298125931) + assert mapped_segment.ParentCurve.QuadraticTerm == pytest.approx(-125.657906854859) + assert mapped_segment.ParentCurve.LinearTerm == pytest.approx(None) + assert mapped_segment.ParentCurve.ConstantTerm == pytest.approx(None) + +def _VienneseBend_100_0__inf__300_1_Meter(file): + project = file.createIfcProject(GlobalId=ifcopenshell.guid.new()) + length = ifcopenshell.api.unit.add_si_unit(file,unit_type="LENGTHUNIT") + ifcopenshell.api.unit.assign_unit(file,units=[length]) + + alignment = ifcopenshell.api.alignment.create(file,"",include_vertical=True,include_cant=True) + + cant_layout = ifcopenshell.api.alignment.get_cant_layout(alignment) + cant_layout.RailHeadDistance=1.5 + design_parameters = file.createIfcAlignmentCantSegment( + StartDistAlong=0., + HorizontalLength=100., + StartCantLeft=0., + EndCantLeft=0.1, + StartCantRight=0., + EndCantRight=0., + PredefinedType="VIENNESEBEND" + ) + ifcopenshell.api.alignment.create_layout_segment(file,cant_layout,design_parameters) + + horizontal_layout = ifcopenshell.api.alignment.get_horizontal_layout(alignment) + design_parameters = file.createIfcAlignmentHorizontalSegment( + StartPoint=file.createIfcCartesianPoint((0.0, 0.0)), + StartDirection=0.0, + StartRadiusOfCurvature=0.0, + EndRadiusOfCurvature=-300.0, + SegmentLength=100.0, + GravityCenterLineHeight=1.8, + PredefinedType="VIENNESEBEND") + ifcopenshell.api.alignment.create_layout_segment(file,horizontal_layout,design_parameters) + + vertical_layout = ifcopenshell.api.alignment.get_vertical_layout(alignment) + design_parameters = file.createIfcAlignmentVerticalSegment( + StartDistAlong=0., + HorizontalLength=100., + StartHeight=0., + StartGradient=0., + EndGradient=0., + PredefinedType = "CONSTANTGRADIENT" + ) + ifcopenshell.api.alignment.create_layout_segment(file,vertical_layout,design_parameters) + + alignment_segment = horizontal_layout.IsNestedBy[0].RelatedObjects[0] + mapped_segments = _map_alignment_horizontal_segment(file,alignment_segment) + mapped_segment = mapped_segments[0] + assert len(mapped_segments) == 2 + assert "DISCONTINUOUS" == mapped_segment.Transition + assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 0.0)) + assert mapped_segment.Placement.RefDirection.DirectionRatios == pytest.approx((1.0, 0.0)) + assert mapped_segment.SegmentStart.wrappedValue == pytest.approx(0.0) + assert mapped_segment.SegmentLength.wrappedValue == pytest.approx(100.0) + assert mapped_segment.ParentCurve.is_a("IfcSeventhOrderPolynomialSpiral") + assert mapped_segment.ParentCurve.Position.Location.Coordinates == pytest.approx((0.0, 0.0)) + assert mapped_segment.ParentCurve.Position.RefDirection.DirectionRatios == pytest.approx((1.0,0.0)) + assert mapped_segment.ParentCurve.SepticTerm == pytest.approx(78.8880838459446) + assert mapped_segment.ParentCurve.SexticTerm == pytest.approx(-63.7638813456506) + assert mapped_segment.ParentCurve.QuinticTerm == pytest.approx(57.7378785242934) + assert mapped_segment.ParentCurve.QuarticTerm == pytest.approx(-64.2314061308743) + assert mapped_segment.ParentCurve.CubicTerm == pytest.approx(-83.922298125931) + assert mapped_segment.ParentCurve.QuadraticTerm == pytest.approx(125.657906854859) + assert mapped_segment.ParentCurve.LinearTerm == pytest.approx(None) + assert mapped_segment.ParentCurve.ConstantTerm == pytest.approx(None) + def test_map_alignment_horizontal_segment(): file = ifcopenshell.file(schema="IFC4X3") @@ -2098,8 +2608,14 @@ def test_map_alignment_horizontal_segment(): _SineCurve_100_0__1000__300_1_Meter(file) _SineCurve_100_0_inf_300_1_Meter(file) _SineCurve_100_0__inf__300_1_Meter(file) - - # VIENESSE BEND NOT IMPLEMENTED + _VienneseBend_100_0_300_1000_1_Meter(file) + _VienneseBend_100_0__300__1000_1_Meter(file) + _VienneseBend_100_0_300_inf_1_Meter(file) + _VienneseBend_100_0__300__inf_1_Meter(file) + _VienneseBend_100_0_1000_300_1_Meter(file) + _VienneseBend_100_0__1000__300_1_Meter(file) + _VienneseBend_100_0_inf_300_1_Meter(file) + _VienneseBend_100_0__inf__300_1_Meter(file) test_map_alignment_horizontal_segment()