Import alignment from csv (#6234)

* Start of the official alignment API

* Import alignment into bonsai model using CSV file
This commit is contained in:
Richard Brice
2025-03-14 07:31:50 -07:00
committed by GitHub
parent eed47c8c87
commit 04e07db0a3
59 changed files with 7369 additions and 1311 deletions
@@ -0,0 +1,72 @@
# IfcOpenShell - IFC toolkit and geometry engine
# Copyright (C) 2025 Thomas Krijnen <thomas@aecgeeks.com>
#
# 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 <http://www.gnu.org/licenses/>.
import pytest
import ifcopenshell.api.alignment
import ifcopenshell.api.context
def test_add_segment_to_curve():
file = ifcopenshell.file(schema="IFC4X3_ADD2")
project = file.createIfcProject(Name="Test")
geometric_representation_context = ifcopenshell.api.context.add_context(file, context_type="Model")
axis_model_representation_subcontext = ifcopenshell.api.context.add_context(
file,
context_type="Model",
context_identifier="Axis",
target_view="MODEL_VIEW",
parent=geometric_representation_context,
)
circular_arc = file.createIfcCurveSegment(
Placement=file.createIfcAxis2Placement2d(
file.createIfcCartesianPoint((4084.115884, 3889.462938)),
file.createIfcDirection((0.224530986099614, 0.974466949814685)),
),
SegmentStart=file.createIfcLengthMeasure(0.0),
SegmentLength=file.createIfcLengthMeasure(-1848.115835),
ParentCurve=file.createIfcCircle(
Position=file.createIfcAxis2Placement2d(
file.createIfcCartesianPoint((0.0, 0.0)), file.createIfcDirection((1.0, 0.0))
),
Radius=1250.0,
),
)
line = file.createIfcCurveSegment(
Placement=file.createIfcAxis2Placement2d(
file.createIfcCartesianPoint((5469.395067, 4847.56631)),
file.createIfcDirection((0.991014275066766, -0.133756146078947)),
),
SegmentStart=file.createIfcLengthMeasure(0.0),
SegmentLength=file.createIfcLengthMeasure(1564.635765),
ParentCurve=file.createIfcLine(
Pnt=file.createIfcCartesianPoint((0.0, 0.0)),
Dir=file.createIfcVector(Orientation=file.createIfcDirection((1.0, 0.0)), Magnitude=1.0),
),
)
composite_curve = file.createIfcCompositeCurve(SelfIntersect=False)
ifcopenshell.api.alignment.add_segment_to_curve(file, circular_arc, composite_curve)
assert circular_arc.UsingCurves[0] == composite_curve
assert composite_curve.Segments[-1] == circular_arc
ifcopenshell.api.alignment.add_segment_to_curve(file, line, composite_curve)
assert line.UsingCurves[0] == composite_curve
assert composite_curve.Segments[-1] == line
@@ -0,0 +1,75 @@
# IfcOpenShell - IFC toolkit and geometry engine
# Copyright (C) 2025 Thomas Krijnen <thomas@aecgeeks.com>
#
# 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 <http://www.gnu.org/licenses/>.
import pytest
import ifcopenshell.api.alignment
import ifcopenshell.api.context
def test_add_segment_to_layout():
file = ifcopenshell.file(schema="IFC4X3_ADD2")
project = file.createIfcProject(Name="Test")
geometric_representation_context = ifcopenshell.api.context.add_context(file, context_type="Model")
axis_model_representation_subcontext = ifcopenshell.api.context.add_context(
file,
context_type="Model",
context_identifier="Axis",
target_view="MODEL_VIEW",
parent=geometric_representation_context,
)
horizontal_alignment = file.create_entity(
type="IfcAlignmentHorizontal",
GlobalId=ifcopenshell.guid.new(),
OwnerHistory=None,
Name=None,
Description=None,
ObjectType=None,
ObjectPlacement=None,
Representation=None,
)
design_parameters = file.create_entity(
type="IfcAlignmentHorizontalSegment",
StartTag=None,
EndTag=None,
StartPoint=file.createIfcCartesianPoint(Coordinates=((0.0, 0.0))),
StartDirection=0.0,
StartRadiusOfCurvature=0.0,
EndRadiusOfCurvature=0.0,
SegmentLength=100.0,
GravityCenterLineHeight=None,
PredefinedType="LINE",
)
alignment_segment = file.create_entity(
type="IfcAlignmentSegment",
GlobalId=ifcopenshell.guid.new(),
OwnerHistory=None,
Name=None,
Description=None,
ObjectType=None,
ObjectPlacement=None,
Representation=None,
DesignParameters=design_parameters,
)
ifcopenshell.api.alignment.add_segment_to_layout(file, horizontal_alignment, alignment_segment)
assert len(horizontal_alignment.IsNestedBy) == 1
assert len(horizontal_alignment.IsNestedBy[0].RelatedObjects) == 1
assert horizontal_alignment.IsNestedBy[0].RelatedObjects[0] == alignment_segment
@@ -0,0 +1,56 @@
# IfcOpenShell - IFC toolkit and geometry engine
# Copyright (C) 2025 Thomas Krijnen <thomas@aecgeeks.com>
#
# 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 <http://www.gnu.org/licenses/>.
import pytest
import ifcopenshell.api.alignment
import ifcopenshell.api.context
def test_add_stationing_to_alignment():
file = ifcopenshell.file(schema="IFC4X3_ADD2")
project = file.createIfcProject(Name="Test")
geometric_representation_context = ifcopenshell.api.context.add_context(file, context_type="Model")
axis_model_representation_subcontext = ifcopenshell.api.context.add_context(
file,
context_type="Model",
context_identifier="Axis",
target_view="MODEL_VIEW",
parent=geometric_representation_context,
)
coordinates = [(500.0, 2500.0), (3340.0, 660.0), (4340.0, 5000.0), (7600.0, 4560.0), (8480.0, 2010.0)]
radii = [(1000.0), (1250.0), (950.0)]
vpoints = [(0.0, 100.0), (2000.0, 135.0), (5000.0, 105.0), (7400.0, 153.0), (9800.0, 105.0), (12800.0, 90.0)]
lengths = [(1600.0), (1200.0), (2000.0), (800.0)]
alignment = ifcopenshell.api.alignment.create_alignment_by_pi_method(
file, "TestAlignment", coordinates, radii, vpoints, lengths
)
ifcopenshell.api.alignment.add_stationing_to_alignment(file, alignment, 2000.0)
for rel in alignment.IsNestedBy:
for referent in rel.RelatedObjects:
if referent.is_a("IfcReferent"):
assert referent.PredefinedType == "STATION"
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", prop="Station")
== 2000.0
)
@@ -0,0 +1,74 @@
# IfcOpenShell - IFC toolkit and geometry engine
# Copyright (C) 2025 Thomas Krijnen <thomas@aecgeeks.com>
#
# 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 <http://www.gnu.org/licenses/>.
import pytest
import ifcopenshell.api.alignment
import ifcopenshell.api.context
def test_add_vertical_by_pi_method():
file = ifcopenshell.file(schema="IFC4X3_ADD2")
project = file.createIfcProject(Name="Test")
geometric_representation_context = ifcopenshell.api.context.add_context(file, context_type="Model")
axis_model_representation_subcontext = ifcopenshell.api.context.add_context(
file,
context_type="Model",
context_identifier="Axis",
target_view="MODEL_VIEW",
parent=geometric_representation_context,
)
coordinates = [(500.0, 2500.0), (3340.0, 660.0), (4340.0, 5000.0), (7600.0, 4560.0), (8480.0, 2010.0)]
radii = [(1000.0), (1250.0), (950.0)]
vpoints = [(0.0, 100.0), (2000.0, 135.0), (5000.0, 105.0), (7400.0, 153.0), (9800.0, 105.0), (12800.0, 90.0)]
lengths = [(1600.0), (1200.0), (2000.0), (800.0)]
# single horizontal alignment
alignment = ifcopenshell.api.alignment.create_alignment_by_pi_method(file, "TestAlignment", coordinates, radii)
assert len(alignment.IsDecomposedBy) == 0 # no child alignments
assert len(alignment.IsNestedBy) == 1 # nesting IfcAlignemtHorizontal
assert len(alignment.IsNestedBy[0].RelatedObjects) == 1 # nesting one IfcAlignmentHorizontal
assert alignment.IsNestedBy[0].RelatedObjects[0].is_a("IfcAlignmentHorizontal")
assert (
len(alignment.IsNestedBy[0].RelatedObjects[0].IsNestedBy) == 1
) # nesting of segments beneath IfcAlignmentHorizontal
assert len(alignment.IsNestedBy[0].RelatedObjects[0].IsNestedBy[0].RelatedObjects) == 8 # segments
# add first vertical
ifcopenshell.api.alignment.add_vertical_alignment_by_pi_method(file, alignment, vpoints, lengths)
assert len(alignment.IsDecomposedBy) == 0 # no child alignments
assert len(alignment.IsNestedBy) == 1 # 1 nesting relationsip for the alignments
assert len(alignment.IsNestedBy[0].RelatedObjects) == 2 # nesting IfcAlignmentHorizontal and IfcAlignmentVertical
assert alignment.IsNestedBy[0].RelatedObjects[0].is_a("IfcAlignmentHorizontal")
assert alignment.IsNestedBy[0].RelatedObjects[1].is_a("IfcAlignmentVertical")
# add second vertical
ifcopenshell.api.alignment.add_vertical_alignment_by_pi_method(file, alignment, vpoints, lengths)
assert len(alignment.IsDecomposedBy) == 1 # 1 IfcRelAggreates relationship for the child algiments
assert (
len(alignment.IsDecomposedBy[0].RelatedObjects) == 2
) # two child alignments, one for the first vertical and one for the vertical just added
for child_alignment in alignment.IsDecomposedBy[0].RelatedObjects:
assert child_alignment.is_a("IfcAlignment")
assert len(child_alignment.IsNestedBy) == 1 # one nesting relationship for the IfcAlignmentVertical
assert len(child_alignment.IsNestedBy[0].RelatedObjects) == 1 # The IfcAlignmentVertical
assert child_alignment.IsNestedBy[0].RelatedObjects[0].is_a("IfcAlignmentVertical")
assert len(alignment.IsNestedBy) == 1 # 1 nesting relationsip for the alignments
assert len(alignment.IsNestedBy[0].RelatedObjects) == 1 # nesting one IfcAlignmentHorizontal
assert alignment.IsNestedBy[0].RelatedObjects[0].is_a("IfcAlignmentHorizontal")
@@ -0,0 +1,70 @@
# IfcOpenShell - IFC toolkit and geometry engine
# Copyright (C) 2025 Thomas Krijnen <thomas@aecgeeks.com>
#
# 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 <http://www.gnu.org/licenses/>.
import pytest
# import test.bootstrap
import ifcopenshell.api.alignment
import ifcopenshell.api.context
# class TestGetBasisCurve(test.bootstrap.IFC4X3):
def test_horizontal():
file = ifcopenshell.file(schema="IFC4X3_ADD2")
project = file.createIfcProject(Name="Test")
geometric_representation_context = ifcopenshell.api.context.add_context(file, context_type="Model")
axis_model_representation_subcontext = ifcopenshell.api.context.add_context(
file,
context_type="Model",
context_identifier="Axis",
target_view="MODEL_VIEW",
parent=geometric_representation_context,
)
coordinates = [(500.0, 2500.0), (3340.0, 660.0), (4340.0, 5000.0), (7600.0, 4560.0), (8480.0, 2010.0)]
radii = [(1000.0), (1250.0), (950.0)]
alignment = ifcopenshell.api.alignment.create_alignment_by_pi_method(file, "TestAlignment", coordinates, radii)
ifcopenshell.api.alignment.create_geometric_representation(file, alignment)
basis_curve = ifcopenshell.api.alignment.get_basis_curve(alignment)
assert basis_curve.is_a("IfcCompositeCurve")
def test_horizontal_and_vertical():
file = ifcopenshell.file(schema="IFC4X3_ADD2")
project = file.createIfcProject(Name="Test")
geometric_representation_context = ifcopenshell.api.context.add_context(file, context_type="Model")
axis_model_representation_subcontext = ifcopenshell.api.context.add_context(
file,
context_type="Model",
context_identifier="Axis",
target_view="MODEL_VIEW",
parent=geometric_representation_context,
)
coordinates = [(500.0, 2500.0), (3340.0, 660.0), (4340.0, 5000.0), (7600.0, 4560.0), (8480.0, 2010.0)]
radii = [(1000.0), (1250.0), (950.0)]
vpoints = [(0.0, 100.0), (2000.0, 135.0), (5000.0, 105.0), (7400.0, 153.0), (9800.0, 105.0), (12800.0, 90.0)]
lengths = [(1600.0), (1200.0), (2000.0), (800.0)]
alignment = ifcopenshell.api.alignment.create_alignment_by_pi_method(
file, "TestAlignment", coordinates, radii, vpoints, lengths
)
ifcopenshell.api.alignment.create_geometric_representation(file, alignment)
basis_curve = ifcopenshell.api.alignment.get_basis_curve(alignment)
assert basis_curve.is_a("IfcCompositeCurve")
@@ -0,0 +1,70 @@
# IfcOpenShell - IFC toolkit and geometry engine
# Copyright (C) 2025 Thomas Krijnen <thomas@aecgeeks.com>
#
# 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 <http://www.gnu.org/licenses/>.
import pytest
# import test.bootstrap
import ifcopenshell.api.alignment
import ifcopenshell.api.context
# class TestGetCurve(test.bootstrap.IFC4X3):
def test_horizontal():
file = ifcopenshell.file(schema="IFC4X3_ADD2")
project = file.createIfcProject(Name="Test")
geometric_representation_context = ifcopenshell.api.context.add_context(file, context_type="Model")
axis_model_representation_subcontext = ifcopenshell.api.context.add_context(
file,
context_type="Model",
context_identifier="Axis",
target_view="MODEL_VIEW",
parent=geometric_representation_context,
)
coordinates = [(500.0, 2500.0), (3340.0, 660.0), (4340.0, 5000.0), (7600.0, 4560.0), (8480.0, 2010.0)]
radii = [(1000.0), (1250.0), (950.0)]
alignment = ifcopenshell.api.alignment.create_alignment_by_pi_method(file, "TestAlignment", coordinates, radii)
ifcopenshell.api.alignment.create_geometric_representation(file, alignment)
curve = ifcopenshell.api.alignment.get_curve(alignment)
assert curve.is_a("IfcCompositeCurve")
def test_horizontal_and_vertical():
file = ifcopenshell.file(schema="IFC4X3_ADD2")
project = file.createIfcProject(Name="Test")
geometric_representation_context = ifcopenshell.api.context.add_context(file, context_type="Model")
axis_model_representation_subcontext = ifcopenshell.api.context.add_context(
file,
context_type="Model",
context_identifier="Axis",
target_view="MODEL_VIEW",
parent=geometric_representation_context,
)
coordinates = [(500.0, 2500.0), (3340.0, 660.0), (4340.0, 5000.0), (7600.0, 4560.0), (8480.0, 2010.0)]
radii = [(1000.0), (1250.0), (950.0)]
vpoints = [(0.0, 100.0), (2000.0, 135.0), (5000.0, 105.0), (7400.0, 153.0), (9800.0, 105.0), (12800.0, 90.0)]
lengths = [(1600.0), (1200.0), (2000.0), (800.0)]
alignment = ifcopenshell.api.alignment.create_alignment_by_pi_method(
file, "TestAlignment", coordinates, radii, vpoints, lengths
)
ifcopenshell.api.alignment.create_geometric_representation(file, alignment)
curve = ifcopenshell.api.alignment.get_curve(alignment)
assert curve.is_a("IfcGradientCurve")
@@ -0,0 +1,123 @@
# IfcOpenShell - IFC toolkit and geometry engine
# Copyright (C) 2025 Thomas Krijnen <thomas@aecgeeks.com>
#
# 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 <http://www.gnu.org/licenses/>.
import pytest
import ifcopenshell.api.alignment
import ifcopenshell.api.alignment.has_zero_length_segment
import ifcopenshell.api.alignment.remove_zero_length_segment
import ifcopenshell.api.context
import ifcopenshell.guid
import ifcopenshell.api.nest
def _test_business_definition():
file = ifcopenshell.file(schema="IFC4X3_ADD2")
project = file.createIfcProject(Name="Test")
geometric_representation_context = ifcopenshell.api.context.add_context(file, context_type="Model")
axis_model_representation_subcontext = ifcopenshell.api.context.add_context(
file,
context_type="Model",
context_identifier="Axis",
target_view="MODEL_VIEW",
parent=geometric_representation_context,
)
horizontal = file.createIfcAlignmentHorizontal("Horizontal Alignment")
design_parameters = file.createIfcAlignmentHorizontalSegment(
StartPoint=file.createIfcCartesianPoint((0.0, 0.0)),
StartDirection=0.0,
SegmentLength=100.0,
PredefinedType="LINE",
)
segment = file.createIfcAlignmentSegment(GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters)
ifcopenshell.api.nest.assign_object(
file,
related_objects=[
segment,
],
relating_object=horizontal,
)
assert False == ifcopenshell.api.alignment.has_zero_length_segment(horizontal)
ifcopenshell.api.alignment.add_zero_length_segment(file, horizontal)
assert len(horizontal.IsNestedBy[0].RelatedObjects) == 2
assert True == ifcopenshell.api.alignment.has_zero_length_segment(horizontal)
zero_length_segment = ifcopenshell.api.alignment.remove_zero_length_segment(file, horizontal)
assert len(horizontal.IsNestedBy[0].RelatedObjects) == 1
assert False == ifcopenshell.api.alignment.has_zero_length_segment(horizontal)
ifcopenshell.api.alignment.add_segment_to_layout(file, horizontal, zero_length_segment)
assert len(horizontal.IsNestedBy[0].RelatedObjects) == 2
assert True == ifcopenshell.api.alignment.has_zero_length_segment(horizontal)
def _test_geometric_definition():
file = ifcopenshell.file(schema="IFC4X3_ADD2")
project = file.createIfcProject(Name="Test")
geometric_representation_context = ifcopenshell.api.context.add_context(file, context_type="Model")
axis_model_representation_subcontext = ifcopenshell.api.context.add_context(
file,
context_type="Model",
context_identifier="Axis",
target_view="MODEL_VIEW",
parent=geometric_representation_context,
)
circular_arc = file.createIfcCurveSegment(
Placement=file.createIfcAxis2Placement2d(
file.createIfcCartesianPoint((4084.115884, 3889.462938)),
file.createIfcDirection((0.224530986099614, 0.974466949814685)),
),
SegmentStart=file.createIfcLengthMeasure(0.0),
SegmentLength=file.createIfcLengthMeasure(-1848.115835),
ParentCurve=file.createIfcCircle(
Position=file.createIfcAxis2Placement2d(
file.createIfcCartesianPoint((0.0, 0.0)), file.createIfcDirection((1.0, 0.0))
),
Radius=1250.0,
),
)
composite_curve = file.createIfcCompositeCurve(Segments=(circular_arc,), SelfIntersect=False)
assert False == ifcopenshell.api.alignment.has_zero_length_segment(composite_curve)
ifcopenshell.api.alignment.add_zero_length_segment(file, composite_curve)
assert True == ifcopenshell.api.alignment.has_zero_length_segment(composite_curve)
assert len(composite_curve.Segments) == 2
zero_length_segment = ifcopenshell.api.alignment.remove_zero_length_segment(file, composite_curve)
assert len(composite_curve.Segments) == 1
assert False == ifcopenshell.api.alignment.has_zero_length_segment(composite_curve)
ifcopenshell.api.alignment.add_segment_to_curve(file, zero_length_segment, composite_curve)
assert len(composite_curve.Segments) == 2
assert True == ifcopenshell.api.alignment.has_zero_length_segment(composite_curve)
segment = composite_curve.Segments[-1]
assert segment.Placement.Location.Coordinates == (5469.394535876198, 4847.567078630914)
assert segment.Placement.RefDirection.DirectionRatios == (0.9910142986043448, -0.13375597168627318)
def test_has_zero_length_segment():
_test_business_definition()
_test_geometric_definition()
@@ -0,0 +1,26 @@
# IfcOpenShell - IFC toolkit and geometry engine
# Copyright (C) 2025 Thomas Krijnen <thomas@aecgeeks.com>
#
# 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 <http://www.gnu.org/licenses/>.
import pytest
import ifcopenshell.api.alignment
import ifcopenshell.api.context
def test_map_alignment_cant_segment():
file = ifcopenshell.file(schema="IFC4X3_ADD2")
# create tests as the mapping functions are implemented
@@ -0,0 +1,102 @@
# IfcOpenShell - IFC toolkit and geometry engine
# Copyright (C) 2025 Thomas Krijnen <thomas@aecgeeks.com>
#
# 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 <http://www.gnu.org/licenses/>.
import pytest
import ifcopenshell.api.alignment
import ifcopenshell.api.context
def test_map_alignment_horizontal_segment():
file = ifcopenshell.file(schema="IFC4X3_ADD2")
project = file.createIfcProject(Name="Test")
geometric_representation_context = ifcopenshell.api.context.add_context(file, context_type="Model")
axis_model_representation_subcontext = ifcopenshell.api.context.add_context(
file,
context_type="Model",
context_identifier="Axis",
target_view="MODEL_VIEW",
parent=geometric_representation_context,
)
coordinates = [(500.0, 2500.0), (3340.0, 660.0), (4340.0, 5000.0), (7600.0, 4560.0), (8480.0, 2010.0)]
radii = [(1000.0), (1250.0), (950.0)]
vpoints = [(0.0, 100.0), (2000.0, 135.0), (5000.0, 105.0), (7400.0, 153.0), (9800.0, 105.0), (12800.0, 90.0)]
lengths = [(1600.0), (1200.0), (2000.0), (800.0)]
alignment = ifcopenshell.api.alignment.create_alignment_by_pi_method(
file, "TestAlignment", coordinates, radii, vpoints, lengths
)
horizontal_alignment = alignment.IsNestedBy[0].RelatedObjects[0]
assert horizontal_alignment.is_a("IfcAlignmentHorizontal")
composite_curve = file.create_entity(
type="IfcCompositeCurve",
Segments=[],
SelfIntersect=False,
)
ifcopenshell.api.alignment.map_alignment_segments(file, horizontal_alignment, composite_curve)
assert len(composite_curve.Segments) == 8
assert composite_curve.Segments[0].ParentCurve.is_a("IfcLine")
assert composite_curve.Segments[0].Transition == "CONTSAMEGRADIENT"
assert composite_curve.Segments[1].ParentCurve.is_a("IfcCircle")
assert composite_curve.Segments[1].Transition == "CONTSAMEGRADIENT"
assert composite_curve.Segments[2].ParentCurve.is_a("IfcLine")
assert composite_curve.Segments[2].Transition == "CONTSAMEGRADIENT"
assert composite_curve.Segments[3].ParentCurve.is_a("IfcCircle")
assert composite_curve.Segments[3].Transition == "CONTSAMEGRADIENT"
assert composite_curve.Segments[4].ParentCurve.is_a("IfcLine")
assert composite_curve.Segments[4].Transition == "CONTSAMEGRADIENT"
assert composite_curve.Segments[5].ParentCurve.is_a("IfcCircle")
assert composite_curve.Segments[5].Transition == "CONTSAMEGRADIENT"
assert composite_curve.Segments[6].ParentCurve.is_a("IfcLine")
assert composite_curve.Segments[6].Transition == "CONTSAMEGRADIENTSAMECURVATURE"
assert composite_curve.Segments[7].ParentCurve.is_a("IfcLine")
assert composite_curve.Segments[7].Transition == "DISCONTINUOUS"
vertical_alignment = alignment.IsNestedBy[0].RelatedObjects[1]
assert vertical_alignment.is_a("IfcAlignmentVertical")
gradient_curve = file.create_entity(
type="IfcGradientCurve", Segments=[], SelfIntersect=False, BaseCurve=composite_curve, EndPoint=None
)
ifcopenshell.api.alignment.map_alignment_segments(file, vertical_alignment, gradient_curve)
assert len(gradient_curve.Segments) == 10
assert gradient_curve.Segments[0].ParentCurve.is_a("IfcLine")
assert gradient_curve.Segments[0].Transition == "CONTSAMEGRADIENT"
assert gradient_curve.Segments[1].ParentCurve.is_a("IfcPolynomialCurve")
assert gradient_curve.Segments[1].Transition == "CONTSAMEGRADIENT"
assert gradient_curve.Segments[2].ParentCurve.is_a("IfcLine")
assert gradient_curve.Segments[2].Transition == "CONTSAMEGRADIENT"
assert gradient_curve.Segments[3].ParentCurve.is_a("IfcPolynomialCurve")
assert gradient_curve.Segments[3].Transition == "CONTSAMEGRADIENT"
assert gradient_curve.Segments[4].ParentCurve.is_a("IfcLine")
assert gradient_curve.Segments[4].Transition == "CONTSAMEGRADIENT"
assert gradient_curve.Segments[5].ParentCurve.is_a("IfcPolynomialCurve")
assert gradient_curve.Segments[5].Transition == "CONTSAMEGRADIENT"
assert gradient_curve.Segments[6].ParentCurve.is_a("IfcLine")
assert gradient_curve.Segments[6].Transition == "CONTSAMEGRADIENT"
assert gradient_curve.Segments[7].ParentCurve.is_a("IfcPolynomialCurve")
assert gradient_curve.Segments[7].Transition == "CONTSAMEGRADIENT"
assert gradient_curve.Segments[8].ParentCurve.is_a("IfcLine")
assert gradient_curve.Segments[8].Transition == "CONTSAMEGRADIENTSAMECURVATURE"
assert gradient_curve.Segments[9].ParentCurve.is_a("IfcLine")
assert gradient_curve.Segments[9].Transition == "DISCONTINUOUS"
@@ -0,0 +1,795 @@
# IfcOpenShell - IFC toolkit and geometry engine
# Copyright (C) 2025 Thomas Krijnen <thomas@aecgeeks.com>
#
# 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 <http://www.gnu.org/licenses/>.
# These are test cases generated from https://github.com/bSI-RailwayRoom/IFC-Rail-Unit-Test-Reference-Code/tree/master/alignment_testset/IFC-WithGeneratedGeometry
# for vertical alignment.
import pytest
import ifcopenshell.api.alignment
def _CircularArc_100_0_10_0_0_0_0_5_1_Meter(file):
design_parameters = file.createIfcAlignmentVerticalSegment(
StartDistAlong=0.0,
HorizontalLength=100.0,
StartHeight=10.0,
StartGradient=0.0,
EndGradient=0.5,
PredefinedType="CIRCULARARC",
)
alignment_segment = file.createIfcAlignmentSegment(
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
)
mapped_segments = ifcopenshell.api.alignment.map_alignment_segment(file, alignment_segment)
mapped_segment = mapped_segments[0]
assert len(mapped_segments) == 2
assert mapped_segments[1] == None
assert "DISCONTINUOUS" == mapped_segment.Transition
assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 10.0))
assert mapped_segment.Placement.RefDirection.DirectionRatios == pytest.approx((1.0, 0.0))
assert mapped_segment.SegmentStart.wrappedValue == pytest.approx(1053.72220965611)
assert mapped_segment.SegmentLength.wrappedValue == pytest.approx(103.674757133105)
assert mapped_segment.ParentCurve.is_a("IfcCircle")
assert mapped_segment.ParentCurve.Position.Location.Coordinates == pytest.approx((-0.0, 223.606797749979))
assert mapped_segment.ParentCurve.Position.RefDirection.DirectionRatios == pytest.approx((1.0, 0.0))
assert mapped_segment.ParentCurve.Radius == pytest.approx(223.606797749979)
def _CircularArc_100_0_10_0_0_0__0_5_1_Meter(file):
design_parameters = file.createIfcAlignmentVerticalSegment(
StartDistAlong=0.0,
HorizontalLength=100.0,
StartHeight=10.0,
StartGradient=0.0,
EndGradient=-0.5,
PredefinedType="CIRCULARARC",
)
alignment_segment = file.createIfcAlignmentSegment(
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
)
mapped_segments = ifcopenshell.api.alignment.map_alignment_segment(file, alignment_segment)
mapped_segment = mapped_segments[0]
assert len(mapped_segments) == 2
assert mapped_segments[1] == None
assert "DISCONTINUOUS" == mapped_segment.Transition
assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 10.0))
assert mapped_segment.Placement.RefDirection.DirectionRatios == pytest.approx((1.0, 0.0))
assert mapped_segment.SegmentStart.wrappedValue == pytest.approx(351.240736552036)
assert mapped_segment.SegmentLength.wrappedValue == pytest.approx(-103.674757133105)
assert mapped_segment.ParentCurve.is_a("IfcCircle")
assert mapped_segment.ParentCurve.Position.Location.Coordinates == pytest.approx(
(-1.36919674566051e-14, -223.606797749979)
)
assert mapped_segment.ParentCurve.Position.RefDirection.DirectionRatios == pytest.approx((1.0, 0.0))
assert mapped_segment.ParentCurve.Radius == pytest.approx(223.606797749979)
def _CircularArc_100_0_10_0_0_5_0_0_1_Meter(file):
design_parameters = file.createIfcAlignmentVerticalSegment(
StartDistAlong=0.0,
HorizontalLength=100.0,
StartHeight=10.0,
StartGradient=0.5,
EndGradient=0.0,
PredefinedType="CIRCULARARC",
)
alignment_segment = file.createIfcAlignmentSegment(
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
)
mapped_segments = ifcopenshell.api.alignment.map_alignment_segment(file, alignment_segment)
mapped_segment = mapped_segments[0]
assert len(mapped_segments) == 2
assert mapped_segments[1] == None
assert "DISCONTINUOUS" == mapped_segment.Transition
assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 10.0))
assert mapped_segment.Placement.RefDirection.DirectionRatios == pytest.approx(
(0.894427190999916, 0.447213595499958)
)
assert mapped_segment.SegmentStart.wrappedValue == pytest.approx(454.915493685141)
assert mapped_segment.SegmentLength.wrappedValue == pytest.approx(-103.674757133105)
assert mapped_segment.ParentCurve.is_a("IfcCircle")
assert mapped_segment.ParentCurve.Position.Location.Coordinates == pytest.approx((100.0, -200.0))
assert mapped_segment.ParentCurve.Position.RefDirection.DirectionRatios == pytest.approx((1.0, 0.0))
assert mapped_segment.ParentCurve.Radius == pytest.approx(223.606797749979)
def _CircularArc_100_0_10_0__0_5_0_0_1_Meter(file):
design_parameters = file.createIfcAlignmentVerticalSegment(
StartDistAlong=0.0,
HorizontalLength=100.0,
StartHeight=10.0,
StartGradient=-0.5,
EndGradient=0.0,
PredefinedType="CIRCULARARC",
)
alignment_segment = file.createIfcAlignmentSegment(
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
)
mapped_segments = ifcopenshell.api.alignment.map_alignment_segment(file, alignment_segment)
mapped_segment = mapped_segments[0]
assert len(mapped_segments) == 2
assert mapped_segments[1] == None
assert "DISCONTINUOUS" == mapped_segment.Transition
assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 10.0))
assert mapped_segment.Placement.RefDirection.DirectionRatios == pytest.approx(
(0.894427190999916, -0.447213595499958)
)
assert mapped_segment.SegmentStart.wrappedValue == pytest.approx(950.047452523004)
assert mapped_segment.SegmentLength.wrappedValue == pytest.approx(103.674757133105)
assert mapped_segment.ParentCurve.is_a("IfcCircle")
assert mapped_segment.ParentCurve.Position.Location.Coordinates == pytest.approx((100.0, 200.0))
assert mapped_segment.ParentCurve.Position.RefDirection.DirectionRatios == pytest.approx((1.0, 0.0))
assert mapped_segment.ParentCurve.Radius == pytest.approx(223.606797749979)
def _CircularArc_100_0_10_0_0_5_1_0_1_Meter(file):
design_parameters = file.createIfcAlignmentVerticalSegment(
StartDistAlong=0.0,
HorizontalLength=100.0,
StartHeight=10.0,
StartGradient=0.5,
EndGradient=1.0,
PredefinedType="CIRCULARARC",
)
alignment_segment = file.createIfcAlignmentSegment(
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
)
mapped_segments = ifcopenshell.api.alignment.map_alignment_segment(file, alignment_segment)
mapped_segment = mapped_segments[0]
assert len(mapped_segments) == 2
assert mapped_segments[1] == None
assert "DISCONTINUOUS" == mapped_segment.Transition
assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 10.0))
assert mapped_segment.Placement.RefDirection.DirectionRatios == pytest.approx(
(0.894427190999916, 0.447213595499958)
)
assert mapped_segment.SegmentStart.wrappedValue == pytest.approx(1991.60150186753)
assert mapped_segment.SegmentLength.wrappedValue == pytest.approx(123.801073716741)
assert mapped_segment.ParentCurve.is_a("IfcCircle")
assert mapped_segment.ParentCurve.Position.Location.Coordinates == pytest.approx(
(-172.075922005613, 344.151844011225)
)
assert mapped_segment.ParentCurve.Position.RefDirection.DirectionRatios == pytest.approx((1.0, 0.0))
assert mapped_segment.ParentCurve.Radius == pytest.approx(384.773458895502)
def _CircularArc_100_0_10_0__0_5__1_0_1_Meter(file):
design_parameters = file.createIfcAlignmentVerticalSegment(
StartDistAlong=0.0,
HorizontalLength=100.0,
StartHeight=10.0,
StartGradient=-0.5,
EndGradient=-1.0,
PredefinedType="CIRCULARARC",
)
alignment_segment = file.createIfcAlignmentSegment(
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
)
mapped_segments = ifcopenshell.api.alignment.map_alignment_segment(file, alignment_segment)
mapped_segment = mapped_segments[0]
assert len(mapped_segments) == 2
assert mapped_segments[1] == None
assert "DISCONTINUOUS" == mapped_segment.Transition
assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 10.0))
assert mapped_segment.Placement.RefDirection.DirectionRatios == pytest.approx(
(0.894427190999916, -0.447213595499958)
)
assert mapped_segment.SegmentStart.wrappedValue == pytest.approx(426.001441657352)
assert mapped_segment.SegmentLength.wrappedValue == pytest.approx(-123.801073716741)
assert mapped_segment.ParentCurve.is_a("IfcCircle")
assert mapped_segment.ParentCurve.Position.Location.Coordinates == pytest.approx(
(-172.075922005613, -344.151844011225)
)
assert mapped_segment.ParentCurve.Position.RefDirection.DirectionRatios == pytest.approx((1.0, 0.0))
assert mapped_segment.ParentCurve.Radius == pytest.approx(384.773458895502)
def _CircularArc_100_0_10_0_1_0_0_5_1_Meter(file):
design_parameters = file.createIfcAlignmentVerticalSegment(
StartDistAlong=0.0,
HorizontalLength=100.0,
StartHeight=10.0,
StartGradient=1.0,
EndGradient=0.5,
PredefinedType="CIRCULARARC",
)
alignment_segment = file.createIfcAlignmentSegment(
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
)
mapped_segments = ifcopenshell.api.alignment.map_alignment_segment(file, alignment_segment)
mapped_segment = mapped_segments[0]
assert len(mapped_segments) == 2
assert mapped_segments[1] == None
assert "DISCONTINUOUS" == mapped_segment.Transition
assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 10.0))
assert mapped_segment.Placement.RefDirection.DirectionRatios == pytest.approx(
(0.707106781186547, 0.707106781186547)
)
assert mapped_segment.SegmentStart.wrappedValue == pytest.approx(906.601103821832)
assert mapped_segment.SegmentLength.wrappedValue == pytest.approx(-123.801073716741)
assert mapped_segment.ParentCurve.is_a("IfcCircle")
assert mapped_segment.ParentCurve.Position.Location.Coordinates == pytest.approx(
(272.075922005613, -272.075922005613)
)
assert mapped_segment.ParentCurve.Position.RefDirection.DirectionRatios == pytest.approx((1.0, 0.0))
assert mapped_segment.ParentCurve.Radius == pytest.approx(384.773458895502)
def _CircularArc_100_0_10_0__1_0__0_5_1_Meter(file):
design_parameters = file.createIfcAlignmentVerticalSegment(
StartDistAlong=0.0,
HorizontalLength=100.0,
StartHeight=10.0,
StartGradient=-1.0,
EndGradient=-0.5,
PredefinedType="CIRCULARARC",
)
alignment_segment = file.createIfcAlignmentSegment(
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
)
mapped_segments = ifcopenshell.api.alignment.map_alignment_segment(file, alignment_segment)
mapped_segment = mapped_segments[0]
assert len(mapped_segments) == 2
assert mapped_segments[1] == None
assert "DISCONTINUOUS" == mapped_segment.Transition
assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 10.0))
assert mapped_segment.Placement.RefDirection.DirectionRatios == pytest.approx(
(0.707106781186547, -0.707106781186547)
)
assert mapped_segment.SegmentStart.wrappedValue == pytest.approx(1511.00183970305)
assert mapped_segment.SegmentLength.wrappedValue == pytest.approx(123.801073716741)
assert mapped_segment.ParentCurve.is_a("IfcCircle")
assert mapped_segment.ParentCurve.Position.Location.Coordinates == pytest.approx(
(272.075922005613, 272.075922005613)
)
assert mapped_segment.ParentCurve.Position.RefDirection.DirectionRatios == pytest.approx((1.0, 0.0))
assert mapped_segment.ParentCurve.Radius == pytest.approx(384.773458895502)
def _ConstantGradient_100_0_10_0_0_0_0_5_1_Meter(file):
design_parameters = file.createIfcAlignmentVerticalSegment(
StartDistAlong=0.0,
HorizontalLength=100.0,
StartHeight=10.0,
StartGradient=0.0,
EndGradient=0.5,
PredefinedType="CONSTANTGRADIENT",
)
alignment_segment = file.createIfcAlignmentSegment(
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
)
mapped_segments = ifcopenshell.api.alignment.map_alignment_segment(file, alignment_segment)
mapped_segment = mapped_segments[0]
assert len(mapped_segments) == 2
assert mapped_segments[1] == None
assert "DISCONTINUOUS" == mapped_segment.Transition
assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 10.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("IfcLine")
assert mapped_segment.ParentCurve.Pnt.Coordinates == pytest.approx((0.0, 0.0))
assert mapped_segment.ParentCurve.Dir.Orientation.DirectionRatios == pytest.approx((1.0, 0.0))
assert mapped_segment.ParentCurve.Dir.Magnitude == pytest.approx(1.0)
def _ConstantGradient_100_0_10_0_0_0__0_5_1_Meter(file):
design_parameters = file.createIfcAlignmentVerticalSegment(
StartDistAlong=0.0,
HorizontalLength=100.0,
StartHeight=10.0,
StartGradient=0.0,
EndGradient=-0.5,
PredefinedType="CONSTANTGRADIENT",
)
alignment_segment = file.createIfcAlignmentSegment(
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
)
mapped_segments = ifcopenshell.api.alignment.map_alignment_segment(file, alignment_segment)
mapped_segment = mapped_segments[0]
assert len(mapped_segments) == 2
assert mapped_segments[1] == None
assert "DISCONTINUOUS" == mapped_segment.Transition
assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 10.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("IfcLine")
assert mapped_segment.ParentCurve.Pnt.Coordinates == pytest.approx((0.0, 0.0))
assert mapped_segment.ParentCurve.Dir.Orientation.DirectionRatios == pytest.approx((1.0, 0.0))
assert mapped_segment.ParentCurve.Dir.Magnitude == pytest.approx(1.0)
def _ConstantGradient_100_0_10_0_0_5_0_0_1_Meter(file):
design_parameters = file.createIfcAlignmentVerticalSegment(
StartDistAlong=0.0,
HorizontalLength=100.0,
StartHeight=10.0,
StartGradient=0.5,
EndGradient=0.0,
PredefinedType="CONSTANTGRADIENT",
)
alignment_segment = file.createIfcAlignmentSegment(
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
)
mapped_segments = ifcopenshell.api.alignment.map_alignment_segment(file, alignment_segment)
mapped_segment = mapped_segments[0]
assert len(mapped_segments) == 2
assert mapped_segments[1] == None
assert "DISCONTINUOUS" == mapped_segment.Transition
assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 10.0))
assert mapped_segment.Placement.RefDirection.DirectionRatios == pytest.approx(
(0.894427190999916, 0.447213595499958)
)
assert mapped_segment.SegmentStart.wrappedValue == pytest.approx(0.0)
assert mapped_segment.SegmentLength.wrappedValue == pytest.approx(111.803398874989)
assert mapped_segment.ParentCurve.is_a("IfcLine")
assert mapped_segment.ParentCurve.Pnt.Coordinates == pytest.approx((0.0, 0.0))
assert mapped_segment.ParentCurve.Dir.Orientation.DirectionRatios == pytest.approx((1.0, 0.0))
assert mapped_segment.ParentCurve.Dir.Magnitude == pytest.approx(1.0)
def _ConstantGradient_100_0_10_0__0_5_0_0_1_Meter(file):
design_parameters = file.createIfcAlignmentVerticalSegment(
StartDistAlong=0.0,
HorizontalLength=100.0,
StartHeight=10.0,
StartGradient=-0.5,
EndGradient=0.0,
PredefinedType="CONSTANTGRADIENT",
)
alignment_segment = file.createIfcAlignmentSegment(
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
)
mapped_segments = ifcopenshell.api.alignment.map_alignment_segment(file, alignment_segment)
mapped_segment = mapped_segments[0]
assert len(mapped_segments) == 2
assert mapped_segments[1] == None
assert "DISCONTINUOUS" == mapped_segment.Transition
assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 10.0))
assert mapped_segment.Placement.RefDirection.DirectionRatios == pytest.approx(
(0.894427190999916, -0.447213595499958)
)
assert mapped_segment.SegmentStart.wrappedValue == pytest.approx(0.0)
assert mapped_segment.SegmentLength.wrappedValue == pytest.approx(111.803398874989)
assert mapped_segment.ParentCurve.is_a("IfcLine")
assert mapped_segment.ParentCurve.Pnt.Coordinates == pytest.approx((0.0, 0.0))
assert mapped_segment.ParentCurve.Dir.Orientation.DirectionRatios == pytest.approx((1.0, 0.0))
assert mapped_segment.ParentCurve.Dir.Magnitude == pytest.approx(1.0)
def _ConstantGradient_100_0_10_0_0_5_1_0_1_Meter(file):
design_parameters = file.createIfcAlignmentVerticalSegment(
StartDistAlong=0.0,
HorizontalLength=100.0,
StartHeight=10.0,
StartGradient=0.5,
EndGradient=1.0,
PredefinedType="CONSTANTGRADIENT",
)
alignment_segment = file.createIfcAlignmentSegment(
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
)
mapped_segments = ifcopenshell.api.alignment.map_alignment_segment(file, alignment_segment)
mapped_segment = mapped_segments[0]
assert len(mapped_segments) == 2
assert mapped_segments[1] == None
assert "DISCONTINUOUS" == mapped_segment.Transition
assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 10.0))
assert mapped_segment.Placement.RefDirection.DirectionRatios == pytest.approx(
(0.894427190999916, 0.447213595499958)
)
assert mapped_segment.SegmentStart.wrappedValue == pytest.approx(0.0)
assert mapped_segment.SegmentLength.wrappedValue == pytest.approx(111.803398874989)
assert mapped_segment.ParentCurve.is_a("IfcLine")
assert mapped_segment.ParentCurve.Pnt.Coordinates == pytest.approx((0.0, 0.0))
assert mapped_segment.ParentCurve.Dir.Orientation.DirectionRatios == pytest.approx((1.0, 0.0))
assert mapped_segment.ParentCurve.Dir.Magnitude == pytest.approx(1.0)
def _ConstantGradient_100_0_10_0__0_5__1_0_1_Meter(file):
design_parameters = file.createIfcAlignmentVerticalSegment(
StartDistAlong=0.0,
HorizontalLength=100.0,
StartHeight=10.0,
StartGradient=-0.5,
EndGradient=-1.0,
PredefinedType="CONSTANTGRADIENT",
)
alignment_segment = file.createIfcAlignmentSegment(
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
)
mapped_segments = ifcopenshell.api.alignment.map_alignment_segment(file, alignment_segment)
mapped_segment = mapped_segments[0]
assert len(mapped_segments) == 2
assert mapped_segments[1] == None
assert "DISCONTINUOUS" == mapped_segment.Transition
assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 10.0))
assert mapped_segment.Placement.RefDirection.DirectionRatios == pytest.approx(
(0.894427190999916, -0.447213595499958)
)
assert mapped_segment.SegmentStart.wrappedValue == pytest.approx(0.0)
assert mapped_segment.SegmentLength.wrappedValue == pytest.approx(111.803398874989)
assert mapped_segment.ParentCurve.is_a("IfcLine")
assert mapped_segment.ParentCurve.Pnt.Coordinates == pytest.approx((0.0, 0.0))
assert mapped_segment.ParentCurve.Dir.Orientation.DirectionRatios == pytest.approx((1.0, 0.0))
assert mapped_segment.ParentCurve.Dir.Magnitude == pytest.approx(1.0)
def _ConstantGradient_100_0_10_0_1_0_0_5_1_Meter(file):
design_parameters = file.createIfcAlignmentVerticalSegment(
StartDistAlong=0.0,
HorizontalLength=100.0,
StartHeight=10.0,
StartGradient=1.0,
EndGradient=0.5,
PredefinedType="CONSTANTGRADIENT",
)
alignment_segment = file.createIfcAlignmentSegment(
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
)
mapped_segments = ifcopenshell.api.alignment.map_alignment_segment(file, alignment_segment)
mapped_segment = mapped_segments[0]
assert len(mapped_segments) == 2
assert mapped_segments[1] == None
assert "DISCONTINUOUS" == mapped_segment.Transition
assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 10.0))
assert mapped_segment.Placement.RefDirection.DirectionRatios == pytest.approx(
(0.707106781186547, 0.707106781186547)
)
assert mapped_segment.SegmentStart.wrappedValue == pytest.approx(0.0)
assert mapped_segment.SegmentLength.wrappedValue == pytest.approx(141.42135623731)
assert mapped_segment.ParentCurve.is_a("IfcLine")
assert mapped_segment.ParentCurve.Pnt.Coordinates == pytest.approx((0.0, 0.0))
assert mapped_segment.ParentCurve.Dir.Orientation.DirectionRatios == pytest.approx((1.0, 0.0))
assert mapped_segment.ParentCurve.Dir.Magnitude == pytest.approx(1.0)
def _ConstantGradient_100_0_10_0__1_0__0_5_1_Meter(file):
design_parameters = file.createIfcAlignmentVerticalSegment(
StartDistAlong=0.0,
HorizontalLength=100.0,
StartHeight=10.0,
StartGradient=-1.0,
EndGradient=-0.5,
PredefinedType="CONSTANTGRADIENT",
)
alignment_segment = file.createIfcAlignmentSegment(
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
)
mapped_segments = ifcopenshell.api.alignment.map_alignment_segment(file, alignment_segment)
mapped_segment = mapped_segments[0]
assert len(mapped_segments) == 2
assert mapped_segments[1] == None
assert "DISCONTINUOUS" == mapped_segment.Transition
assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 10.0))
assert mapped_segment.Placement.RefDirection.DirectionRatios == pytest.approx(
(0.707106781186547, -0.707106781186547)
)
assert mapped_segment.SegmentStart.wrappedValue == pytest.approx(0.0)
assert mapped_segment.SegmentLength.wrappedValue == pytest.approx(141.42135623731)
assert mapped_segment.ParentCurve.is_a("IfcLine")
assert mapped_segment.ParentCurve.Pnt.Coordinates == pytest.approx((0.0, 0.0))
assert mapped_segment.ParentCurve.Dir.Orientation.DirectionRatios == pytest.approx((1.0, 0.0))
assert mapped_segment.ParentCurve.Dir.Magnitude == pytest.approx(1.0)
def _ParabolicArc_100_0_10_0_0_0_0_5_1_Meter(file):
design_parameters = file.createIfcAlignmentVerticalSegment(
StartDistAlong=0.0,
HorizontalLength=100.0,
StartHeight=10.0,
StartGradient=0.0,
EndGradient=0.5,
PredefinedType="PARABOLICARC",
)
alignment_segment = file.createIfcAlignmentSegment(
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
)
mapped_segments = ifcopenshell.api.alignment.map_alignment_segment(file, alignment_segment)
mapped_segment = mapped_segments[0]
assert len(mapped_segments) == 2
assert mapped_segments[1] == None
assert "DISCONTINUOUS" == mapped_segment.Transition
assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 10.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(104.02288238772185)
assert mapped_segment.ParentCurve.is_a("IfcPolynomialCurve")
assert mapped_segment.ParentCurve.Position.Location.Coordinates == pytest.approx((0.0, 0.0))
assert mapped_segment.ParentCurve.CoefficientsX == pytest.approx((0.0, 1.0))
assert mapped_segment.ParentCurve.CoefficientsY == pytest.approx((10.0, 0.0, 0.0025))
def _ParabolicArc_100_0_10_0_0_0__0_5_1_Meter(file):
design_parameters = file.createIfcAlignmentVerticalSegment(
StartDistAlong=0.0,
HorizontalLength=100.0,
StartHeight=10.0,
StartGradient=0.0,
EndGradient=-0.5,
PredefinedType="PARABOLICARC",
)
alignment_segment = file.createIfcAlignmentSegment(
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
)
mapped_segments = ifcopenshell.api.alignment.map_alignment_segment(file, alignment_segment)
mapped_segment = mapped_segments[0]
assert len(mapped_segments) == 2
assert mapped_segments[1] == None
assert "DISCONTINUOUS" == mapped_segment.Transition
assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 10.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(104.02288238772185)
assert mapped_segment.ParentCurve.is_a("IfcPolynomialCurve")
assert mapped_segment.ParentCurve.Position.Location.Coordinates == pytest.approx((0.0, 0.0))
assert mapped_segment.ParentCurve.CoefficientsX == pytest.approx((0.0, 1.0))
assert mapped_segment.ParentCurve.CoefficientsY == pytest.approx((10.0, 0.0, -0.0025))
def _ParabolicArc_100_0_10_0_0_5_0_0_1_Meter(file):
design_parameters = file.createIfcAlignmentVerticalSegment(
StartDistAlong=0.0,
HorizontalLength=100.0,
StartHeight=10.0,
StartGradient=0.5,
EndGradient=0.0,
PredefinedType="PARABOLICARC",
)
alignment_segment = file.createIfcAlignmentSegment(
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
)
mapped_segments = ifcopenshell.api.alignment.map_alignment_segment(file, alignment_segment)
mapped_segment = mapped_segments[0]
assert len(mapped_segments) == 2
assert mapped_segments[1] == None
assert "DISCONTINUOUS" == mapped_segment.Transition
assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 10.0))
assert mapped_segment.Placement.RefDirection.DirectionRatios == pytest.approx(
(0.894427190999916, 0.447213595499958)
)
assert mapped_segment.SegmentStart.wrappedValue == pytest.approx(0.0)
assert mapped_segment.SegmentLength.wrappedValue == pytest.approx(104.02288238772185)
assert mapped_segment.ParentCurve.is_a("IfcPolynomialCurve")
assert mapped_segment.ParentCurve.Position.Location.Coordinates == pytest.approx((0.0, 0.0))
assert mapped_segment.ParentCurve.CoefficientsX == pytest.approx((0.0, 1.0))
assert mapped_segment.ParentCurve.CoefficientsY == pytest.approx((10.0, 0.5, -0.0025))
def _ParabolicArc_100_0_10_0__0_5_0_0_1_Meter(file):
design_parameters = file.createIfcAlignmentVerticalSegment(
StartDistAlong=0.0,
HorizontalLength=100.0,
StartHeight=10.0,
StartGradient=-0.5,
EndGradient=0.0,
PredefinedType="PARABOLICARC",
)
alignment_segment = file.createIfcAlignmentSegment(
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
)
mapped_segments = ifcopenshell.api.alignment.map_alignment_segment(file, alignment_segment)
mapped_segment = mapped_segments[0]
assert len(mapped_segments) == 2
assert mapped_segments[1] == None
assert "DISCONTINUOUS" == mapped_segment.Transition
assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 10.0))
assert mapped_segment.Placement.RefDirection.DirectionRatios == pytest.approx(
(0.894427190999916, -0.447213595499958)
)
assert mapped_segment.SegmentStart.wrappedValue == pytest.approx(0.0)
assert mapped_segment.SegmentLength.wrappedValue == pytest.approx(104.02288238772185)
assert mapped_segment.ParentCurve.is_a("IfcPolynomialCurve")
assert mapped_segment.ParentCurve.Position.Location.Coordinates == pytest.approx((0.0, 0.0))
assert mapped_segment.ParentCurve.CoefficientsX == pytest.approx((0.0, 1.0))
assert mapped_segment.ParentCurve.CoefficientsY == pytest.approx((10.0, -0.5, 0.0025))
def _ParabolicArc_100_0_10_0_0_5_1_0_1_Meter(file):
design_parameters = file.createIfcAlignmentVerticalSegment(
StartDistAlong=0.0,
HorizontalLength=100.0,
StartHeight=10.0,
StartGradient=0.5,
EndGradient=1.0,
PredefinedType="PARABOLICARC",
)
alignment_segment = file.createIfcAlignmentSegment(
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
)
mapped_segments = ifcopenshell.api.alignment.map_alignment_segment(file, alignment_segment)
mapped_segment = mapped_segments[0]
assert len(mapped_segments) == 2
assert mapped_segments[1] == None
assert "DISCONTINUOUS" == mapped_segment.Transition
assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 10.0))
assert mapped_segment.Placement.RefDirection.DirectionRatios == pytest.approx(
(0.894427190999916, 0.447213595499958)
)
assert mapped_segment.SegmentStart.wrappedValue == pytest.approx(0.0)
assert mapped_segment.SegmentLength.wrappedValue == pytest.approx(125.53583325398947)
assert mapped_segment.ParentCurve.is_a("IfcPolynomialCurve")
assert mapped_segment.ParentCurve.Position.Location.Coordinates == pytest.approx((0.0, 0.0))
assert mapped_segment.ParentCurve.CoefficientsX == pytest.approx((0.0, 1.0))
assert mapped_segment.ParentCurve.CoefficientsY == pytest.approx((10.0, 0.5, 0.0025))
def _ParabolicArc_100_0_10_0__0_5__1_0_1_Meter(file):
design_parameters = file.createIfcAlignmentVerticalSegment(
StartDistAlong=0.0,
HorizontalLength=100.0,
StartHeight=10.0,
StartGradient=-0.5,
EndGradient=-1.0,
PredefinedType="PARABOLICARC",
)
alignment_segment = file.createIfcAlignmentSegment(
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
)
mapped_segments = ifcopenshell.api.alignment.map_alignment_segment(file, alignment_segment)
mapped_segment = mapped_segments[0]
assert len(mapped_segments) == 2
assert mapped_segments[1] == None
assert "DISCONTINUOUS" == mapped_segment.Transition
assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 10.0))
assert mapped_segment.Placement.RefDirection.DirectionRatios == pytest.approx(
(0.894427190999916, -0.447213595499958)
)
assert mapped_segment.SegmentStart.wrappedValue == pytest.approx(0.0)
assert mapped_segment.SegmentLength.wrappedValue == pytest.approx(125.53583325398947)
assert mapped_segment.ParentCurve.is_a("IfcPolynomialCurve")
assert mapped_segment.ParentCurve.Position.Location.Coordinates == pytest.approx((0.0, 0.0))
assert mapped_segment.ParentCurve.CoefficientsX == pytest.approx((0.0, 1.0))
assert mapped_segment.ParentCurve.CoefficientsY == pytest.approx((10.0, -0.5, -0.0025))
def _ParabolicArc_100_0_10_0_1_0_0_5_1_Meter(file):
design_parameters = file.createIfcAlignmentVerticalSegment(
StartDistAlong=0.0,
HorizontalLength=100.0,
StartHeight=10.0,
StartGradient=1.0,
EndGradient=0.5,
PredefinedType="PARABOLICARC",
)
alignment_segment = file.createIfcAlignmentSegment(
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
)
mapped_segments = ifcopenshell.api.alignment.map_alignment_segment(file, alignment_segment)
mapped_segment = mapped_segments[0]
assert len(mapped_segments) == 2
assert mapped_segments[1] == None
assert "DISCONTINUOUS" == mapped_segment.Transition
assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 10.0))
assert mapped_segment.Placement.RefDirection.DirectionRatios == pytest.approx(
(0.707106781186547, 0.707106781186547)
)
assert mapped_segment.SegmentStart.wrappedValue == pytest.approx(0.0)
assert mapped_segment.SegmentLength.wrappedValue == pytest.approx(125.53583325398947)
assert mapped_segment.ParentCurve.is_a("IfcPolynomialCurve")
assert mapped_segment.ParentCurve.Position.Location.Coordinates == pytest.approx((0.0, 0.0))
assert mapped_segment.ParentCurve.CoefficientsX == pytest.approx((0.0, 1.0))
assert mapped_segment.ParentCurve.CoefficientsY == pytest.approx((10.0, 1.0, -0.0025))
def _ParabolicArc_100_0_10_0__1_0__0_5_1_Meter(file):
design_parameters = file.createIfcAlignmentVerticalSegment(
StartDistAlong=0.0,
HorizontalLength=100.0,
StartHeight=10.0,
StartGradient=-1.0,
EndGradient=-0.5,
PredefinedType="PARABOLICARC",
)
alignment_segment = file.createIfcAlignmentSegment(
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
)
mapped_segments = ifcopenshell.api.alignment.map_alignment_segment(file, alignment_segment)
mapped_segment = mapped_segments[0]
assert len(mapped_segments) == 2
assert mapped_segments[1] == None
assert "DISCONTINUOUS" == mapped_segment.Transition
assert mapped_segment.Placement.Location.Coordinates == pytest.approx((0.0, 10.0))
assert mapped_segment.Placement.RefDirection.DirectionRatios == pytest.approx(
(0.707106781186547, -0.707106781186547)
)
assert mapped_segment.SegmentStart.wrappedValue == pytest.approx(0.0)
assert mapped_segment.SegmentLength.wrappedValue == pytest.approx(125.53583325398947)
assert mapped_segment.ParentCurve.is_a("IfcPolynomialCurve")
assert mapped_segment.ParentCurve.Position.Location.Coordinates == pytest.approx((0.0, 0.0))
assert mapped_segment.ParentCurve.CoefficientsX == pytest.approx((0.0, 1.0))
assert mapped_segment.ParentCurve.CoefficientsY == pytest.approx((10.0, -1.0, 0.0025))
def test_map_alignment_vertical_segment():
file = ifcopenshell.file(schema="IFC4X3_ADD2")
_CircularArc_100_0_10_0_0_0_0_5_1_Meter(file)
_CircularArc_100_0_10_0_0_0__0_5_1_Meter(file)
_CircularArc_100_0_10_0_0_5_0_0_1_Meter(file)
_CircularArc_100_0_10_0__0_5_0_0_1_Meter(file)
_CircularArc_100_0_10_0_0_5_1_0_1_Meter(file)
_CircularArc_100_0_10_0__0_5__1_0_1_Meter(file)
_CircularArc_100_0_10_0_1_0_0_5_1_Meter(file)
_CircularArc_100_0_10_0__1_0__0_5_1_Meter(file)
_ConstantGradient_100_0_10_0_0_0_0_5_1_Meter(file)
_ConstantGradient_100_0_10_0_0_0__0_5_1_Meter(file)
_ConstantGradient_100_0_10_0_0_5_0_0_1_Meter(file)
_ConstantGradient_100_0_10_0__0_5_0_0_1_Meter(file)
_ConstantGradient_100_0_10_0_0_5_1_0_1_Meter(file)
_ConstantGradient_100_0_10_0__0_5__1_0_1_Meter(file)
_ConstantGradient_100_0_10_0_1_0_0_5_1_Meter(file)
_ConstantGradient_100_0_10_0__1_0__0_5_1_Meter(file)
_ParabolicArc_100_0_10_0_0_0_0_5_1_Meter(file)
_ParabolicArc_100_0_10_0_0_0__0_5_1_Meter(file)
_ParabolicArc_100_0_10_0_0_5_0_0_1_Meter(file)
_ParabolicArc_100_0_10_0__0_5_0_0_1_Meter(file)
_ParabolicArc_100_0_10_0_0_5_1_0_1_Meter(file)
_ParabolicArc_100_0_10_0__0_5__1_0_1_Meter(file)
_ParabolicArc_100_0_10_0_1_0_0_5_1_Meter(file)
_ParabolicArc_100_0_10_0__1_0__0_5_1_Meter(file)
# VERTICAL CLOTHOID NOT IMPLEMENTED
@@ -0,0 +1,53 @@
# IfcOpenShell - IFC toolkit and geometry engine
# Copyright (C) 2025 Thomas Krijnen <thomas@aecgeeks.com>
#
# 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 <http://www.gnu.org/licenses/>.
import pytest
import ifcopenshell.api.alignment
import ifcopenshell.api.context
def test_name_segments():
file = ifcopenshell.file(schema="IFC4X3_ADD2")
project = file.createIfcProject(Name="Test")
geometric_representation_context = ifcopenshell.api.context.add_context(file, context_type="Model")
axis_model_representation_subcontext = ifcopenshell.api.context.add_context(
file,
context_type="Model",
context_identifier="Axis",
target_view="MODEL_VIEW",
parent=geometric_representation_context,
)
coordinates = [(500.0, 2500.0), (3340.0, 660.0), (4340.0, 5000.0), (7600.0, 4560.0), (8480.0, 2010.0)]
radii = [(1000.0), (1250.0), (950.0)]
vpoints = [(0.0, 100.0), (2000.0, 135.0), (5000.0, 105.0), (7400.0, 153.0), (9800.0, 105.0), (12800.0, 90.0)]
lengths = [(1600.0), (1200.0), (2000.0), (800.0)]
alignment = ifcopenshell.api.alignment.create_alignment_by_pi_method(
file, "TestAlignment", coordinates, radii, vpoints, lengths
)
for rel in alignment.IsNestedBy:
for a in rel.RelatedObjects:
if a.is_a("IfcLinearElement"):
ifcopenshell.api.alignment.name_segments("Q", a)
i = 1
for sr in a.IsNestedBy:
for s in sr.RelatedObjects:
assert f"Q{i}" == s.Name
i += 1
@@ -0,0 +1,248 @@
# IfcOpenShell - IFC toolkit and geometry engine
# Copyright (C) 2025 Thomas Krijnen <thomas@aecgeeks.com>
#
# 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 <http://www.gnu.org/licenses/>.
import pytest
import ifcopenshell.api.alignment
import ifcopenshell.api.context
def _test1():
file = ifcopenshell.file(schema="IFC4X3_ADD2")
project = file.createIfcProject(Name="Test")
geometric_representation_context = ifcopenshell.api.context.add_context(file, context_type="Model")
axis_model_representation_subcontext = ifcopenshell.api.context.add_context(
file,
context_type="Model",
context_identifier="Axis",
target_view="MODEL_VIEW",
parent=geometric_representation_context,
)
# 26=IFCCARTESIANPOINT((4084.115884,3889.462938));
# 70=IFCDIRECTION((0.224530986099614,0.974466949814685));
# 71=IFCAXIS2PLACEMENT2D(#26,#70);
# 72=IFCCARTESIANPOINT((0.,0.));
# 73=IFCDIRECTION((1.,0.));
# 74=IFCAXIS2PLACEMENT2D(#72,#73);
# 75=IFCCIRCLE(#74,1250.);
# 76=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#71,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(-1848.115835),#75);
circular_arc = file.createIfcCurveSegment(
Placement=file.createIfcAxis2Placement2d(
file.createIfcCartesianPoint((4084.115884, 3889.462938)),
file.createIfcDirection((0.224530986099614, 0.974466949814685)),
),
SegmentStart=file.createIfcLengthMeasure(0.0),
SegmentLength=file.createIfcLengthMeasure(-1848.115835),
ParentCurve=file.createIfcCircle(
Position=file.createIfcAxis2Placement2d(
file.createIfcCartesianPoint((0.0, 0.0)), file.createIfcDirection((1.0, 0.0))
),
Radius=1250.0,
),
)
# 27=IFCCARTESIANPOINT((5469.395067,4847.56631));
# 77=IFCDIRECTION((0.991014275066766,-0.133756146078947));
# 78=IFCAXIS2PLACEMENT2D(#27,#77);
# 79=IFCCARTESIANPOINT((0.,0.));
# 80=IFCDIRECTION((1.,0.));
# 81=IFCVECTOR(#80,1.);
# 82=IFCLINE(#79,#81);
# 83=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#78,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(1564.635765),#82);
line = file.createIfcCurveSegment(
Placement=file.createIfcAxis2Placement2d(
file.createIfcCartesianPoint((5469.395067, 4847.56631)),
file.createIfcDirection((0.991014275066766, -0.133756146078947)),
),
SegmentStart=file.createIfcLengthMeasure(0.0),
SegmentLength=file.createIfcLengthMeasure(1564.635765),
ParentCurve=file.createIfcLine(
Pnt=file.createIfcCartesianPoint((0.0, 0.0)),
Dir=file.createIfcVector(Orientation=file.createIfcDirection((1.0, 0.0)), Magnitude=1.0),
),
)
composite_curve = file.createIfcCompositeCurve(Segments=(circular_arc, line), SelfIntersect=False)
ifcopenshell.api.alignment.update_curve_segment_transition_code(circular_arc, line)
assert circular_arc.Transition == "CONTSAMEGRADIENT"
def _test2():
file = ifcopenshell.file(schema="IFC4X3_ADD2")
project = file.createIfcProject(Name="Test")
geometric_representation_context = ifcopenshell.api.context.add_context(file, context_type="Model")
axis_model_representation_subcontext = ifcopenshell.api.context.add_context(
file,
context_type="Model",
context_identifier="Axis",
target_view="MODEL_VIEW",
parent=geometric_representation_context,
)
# 30=IFCCARTESIANPOINT((0.,0.));
# 31=IFCALIGNMENTHORIZONTALSEGMENT($,$,#30,0.523598775598299,0.,0.,27.8843513637174,$,.LINE.);
# 32=IFCALIGNMENTSEGMENT('3$jiMaOgfAoujgvRyMLw0X',$,'H1',$,$,#111,#113,#31);
# 33=IFCDIRECTION((0.866025403784439,0.5));
# 34=IFCAXIS2PLACEMENT2D(#30,#33);
# 35=IFCCARTESIANPOINT((0.,0.));
# 36=IFCDIRECTION((1.,0.));
# 37=IFCVECTOR(#36,1.);
# 38=IFCLINE(#35,#37);
# 39=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#34,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(27.8843513637174),#38);
line1 = file.createIfcCurveSegment(
Placement=file.createIfcAxis2Placement2d(
file.createIfcCartesianPoint((0.0, 0.0)),
file.createIfcDirection((0.866025403784439, 0.5)),
),
SegmentStart=file.createIfcLengthMeasure(0.0),
SegmentLength=file.createIfcLengthMeasure(27.8843513637174),
ParentCurve=file.createIfcLine(
Pnt=file.createIfcCartesianPoint((0.0, 0.0)),
Dir=file.createIfcVector(Orientation=file.createIfcDirection((1.0, 0.0)), Magnitude=1.0),
),
)
# 40=IFCCARTESIANPOINT((24.1485566490305,13.9421756818587));
# 41=IFCALIGNMENTHORIZONTALSEGMENT($,$,#40,0.523598775598299,0.,1524.,152.4,$,.CLOTHOID.);
# 42=IFCALIGNMENTSEGMENT('0Rd38fCkHF1Q11ppiqdMP6',$,'H2',$,$,#111,#115,#41);
# 43=IFCDIRECTION((0.866025403784439,0.5));
# 44=IFCAXIS2PLACEMENT2D(#40,#43);
# 45=IFCCARTESIANPOINT((0.,0.));
# 46=IFCDIRECTION((1.,0.));
# 47=IFCAXIS2PLACEMENT2D(#45,#46);
# 48=IFCCLOTHOID(#47,481.931115409661);
# 49=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#44,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(152.4),#48);
clothoid1 = file.createIfcCurveSegment(
Placement=file.createIfcAxis2Placement2d(
file.createIfcCartesianPoint((24.1485566490305, 13.9421756818587)),
file.createIfcDirection((0.866025403784439, 0.5)),
),
SegmentStart=file.createIfcLengthMeasure(0.0),
SegmentLength=file.createIfcLengthMeasure(152.4),
ParentCurve=file.createIfcClothoid(
Position=file.createIfcAxis2Placement2d(
file.createIfcCartesianPoint((0.0, 0.0)), RefDirection=file.createIfcDirection((1.0, 0.0))
),
ClothoidConstant=481.931115409661,
),
)
# 50=IFCCARTESIANPOINT((154.828063204281,92.32243963907));
# 51=IFCALIGNMENTHORIZONTALSEGMENT($,$,#50,0.573598775598299,1524.,1524.,246.582267005904,$,.CIRCULARARC.);
# 52=IFCALIGNMENTSEGMENT('2OGYY2lQjCnRlzxKU9vtdu',$,'H3',$,$,#111,#117,#51);
# 53=IFCDIRECTION((0.839953512903025,0.542658360445933));
# 54=IFCAXIS2PLACEMENT2D(#50,#53);
# 55=IFCCARTESIANPOINT((0.,0.));
# 56=IFCDIRECTION((1.,0.));
# 57=IFCAXIS2PLACEMENT2D(#55,#56);
# 58=IFCCIRCLE(#57,1524.);
# 59=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#54,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(246.582267005904),#58);
circular_arc = file.createIfcCurveSegment(
Placement=file.createIfcAxis2Placement2d(
file.createIfcCartesianPoint((154.828063204281, 92.32243963907)),
file.createIfcDirection((0.839953512903025, 0.542658360445933)),
),
SegmentStart=file.createIfcLengthMeasure(0.0),
SegmentLength=file.createIfcLengthMeasure(246.582267005904),
ParentCurve=file.createIfcCircle(
Position=file.createIfcAxis2Placement2d(
file.createIfcCartesianPoint((0.0, 0.0)), file.createIfcDirection((1.0, 0.0))
),
Radius=1524.0,
),
)
# 60=IFCCARTESIANPOINT((350.24160971216,242.268527691248));
# 61=IFCALIGNMENTHORIZONTALSEGMENT($,$,#60,0.735398163397447,1524.,0.,152.4,$,.CLOTHOID.);
# 62=IFCALIGNMENTSEGMENT('13CGRzUN9CAfNVKnf0Pxza',$,'H4',$,$,#111,#119,#61);
# 63=IFCDIRECTION((0.741563691346478,0.670882472327743));
# 64=IFCAXIS2PLACEMENT2D(#60,#63);
# 65=IFCCARTESIANPOINT((0.,0.));
# 66=IFCDIRECTION((1.,0.));
# 67=IFCAXIS2PLACEMENT2D(#65,#66);
# 68=IFCCLOTHOID(#67,-481.931115409661);
# 69=IFCCURVESEGMENT(.CONTSAMEGRADIENT.,#64,IFCLENGTHMEASURE(-152.4),IFCLENGTHMEASURE(152.4),#68);
clothoid2 = file.createIfcCurveSegment(
Placement=file.createIfcAxis2Placement2d(
file.createIfcCartesianPoint((350.24160971216, 242.268527691248)),
file.createIfcDirection((0.741563691346478, 0.670882472327743)),
),
SegmentStart=file.createIfcLengthMeasure(-152.4),
SegmentLength=file.createIfcLengthMeasure(152.4),
ParentCurve=file.createIfcClothoid(
Position=file.createIfcAxis2Placement2d(
file.createIfcCartesianPoint((0.0, 0.0)), RefDirection=file.createIfcDirection((1.0, 0.0))
),
ClothoidConstant=-481.931115409661,
),
)
# 70=IFCCARTESIANPOINT((459.773476040884,348.208932967387));
# 71=IFCALIGNMENTHORIZONTALSEGMENT($,$,#70,0.785398163397448,0.,0.,0.,$,.LINE.);
# 72=IFCALIGNMENTSEGMENT('0FlcTrOfT5YBi0fqVhTMyc',$,'H5',$,$,#111,#121,#71);
# 73=IFCDIRECTION((0.707106781186548,0.707106781186548));
# 74=IFCAXIS2PLACEMENT2D(#70,#73);
# 75=IFCCARTESIANPOINT((0.,0.));
# 76=IFCDIRECTION((1.,0.));
# 77=IFCVECTOR(#76,1.);
# 78=IFCLINE(#75,#77);
# 79=IFCCURVESEGMENT(.DISCONTINUOUS.,#74,IFCLENGTHMEASURE(0.),IFCLENGTHMEASURE(0.),#78);
line2 = file.createIfcCurveSegment(
Placement=file.createIfcAxis2Placement2d(
file.createIfcCartesianPoint((459.773476040884, 348.208932967387)),
file.createIfcDirection((0.707106781186548, 0.707106781186548)),
),
SegmentStart=file.createIfcLengthMeasure(0.0),
SegmentLength=file.createIfcLengthMeasure(0.0),
ParentCurve=file.createIfcLine(
Pnt=file.createIfcCartesianPoint((0.0, 0.0)),
Dir=file.createIfcVector(Orientation=file.createIfcDirection((1.0, 0.0)), Magnitude=1.0),
),
)
composite_curve = file.createIfcCompositeCurve(Segments=[], SelfIntersect=False)
# add_segment_to_curve calls update_curve_segment_transition_code
ifcopenshell.api.alignment.add_segment_to_curve(file, line1, composite_curve)
assert line1.Transition == "DISCONTINUOUS"
ifcopenshell.api.alignment.add_segment_to_curve(file, clothoid1, composite_curve)
assert line1.Transition == "CONTSAMEGRADIENTSAMECURVATURE"
assert clothoid1.Transition == "DISCONTINUOUS"
ifcopenshell.api.alignment.add_segment_to_curve(file, circular_arc, composite_curve)
assert clothoid1.Transition == "CONTSAMEGRADIENTSAMECURVATURE"
assert circular_arc.Transition == "DISCONTINUOUS"
ifcopenshell.api.alignment.add_segment_to_curve(file, clothoid2, composite_curve)
assert circular_arc.Transition == "CONTSAMEGRADIENTSAMECURVATURE"
assert clothoid2.Transition == "DISCONTINUOUS"
ifcopenshell.api.alignment.add_segment_to_curve(file, line2, composite_curve)
assert clothoid2.Transition == "CONTSAMEGRADIENTSAMECURVATURE"
assert line2.Transition == "DISCONTINUOUS"
def test_update_curve_segment_transition_code():
_test1()
_test2()