mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-08 17:01:40 +00:00
Alignment api update (#6817)
* Some basic COGO survey points functions * Update alignment api Includes defining alignment segment by segment, automatic geometry definitions, and automatric stationing and referents * Fixes bonsai import alignment from csv * Adds DMS angle conversion functions to COGO api * Updated per @civilx64 review comments * Fixes problem with segment representations * Fixes problem with segment transition codes * Allows for compound vertical and horizontal curves * Implements callbacks for referent naming * Renames angle_from_bearing to bearing2dd for consistency with ifcopenshell.util.geolocation.dms2dd. Removes angle_from_dms because it duplicates dms2dd * Documents register_referent_name_callback * Fixes all sorts of problems with Cant/SegRefCurve implementation * refactor referent unit tests to use a fixture for test setup * lint with black --------- Co-authored-by: Scott Lecher <civilx64@gmail.com>
This commit is contained in:
@@ -21,7 +21,6 @@
|
||||
import os
|
||||
|
||||
import ifcopenshell.api.alignment
|
||||
import ifcopenshell.api.alignment.add_stationing_to_alignment
|
||||
|
||||
import bpy
|
||||
import json
|
||||
@@ -62,9 +61,7 @@ class ImportAlignmentCSV(bpy.types.Operator, tool.Ifc.Operator, ImportHelper):
|
||||
def _execute(self, context):
|
||||
self.file = tool.Ifc.get()
|
||||
start = time.time()
|
||||
alignment = ifcopenshell.api.alignment.create_alignment_from_csv(self.file, self.filepath)
|
||||
ifcopenshell.api.alignment.create_geometric_representation(self.file, alignment)
|
||||
ifcopenshell.api.alignment.add_stationing_to_alignment(self.file, alignment=alignment, start_station=0.0)
|
||||
alignment = ifcopenshell.api.alignment.create_from_csv(self.file, self.filepath)
|
||||
|
||||
# IFC 4.1.5.1 alignments cannot be contained in spatial structures, but can be referenced into them
|
||||
sites = self.file.by_type("IfcSite")
|
||||
|
||||
@@ -17,7 +17,15 @@
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""
|
||||
Manages alignment layout (business logical) and alignment geometry (geometric representations).
|
||||
Manages alignment layout (semantic definition) and alignment geometry (geometric definition).
|
||||
|
||||
This API is defined in terms of the semantic definition of an alignment. The corresponding geometric definition
|
||||
is created and maintained automatically. The manditory zero length segment for the semantic and geometric definitions
|
||||
are automatically created and maintained.
|
||||
|
||||
Alignments are created with stationing referents. Each layout segment is assigned a position referent that informs about
|
||||
the start point of the segment. An example is the point of curvature of a horizontal circular curve. The referent is
|
||||
nested to the segment representing the circular arc and is named with a indicator of the position and the station, e.g. "P.C. (145+98.32)"
|
||||
|
||||
This API does not determine alignment parameters based on rules, such as minimum curve radius as a function of design speed or sight distance.
|
||||
|
||||
@@ -25,14 +33,13 @@ This API is under development and subject to code breaking changes in the future
|
||||
|
||||
Presently, this API supports:
|
||||
1. Creating alignments, both horizontal and vertical, using the PI method. Alignment definition can be read from a CSV file.
|
||||
2. Adding business logic and geometric segments to the end of an alignment
|
||||
3. Adding and removing the zero length segment at the end of alignments
|
||||
4. Creating geometric representations from a business logical definition
|
||||
5. Mapping individual business logical segments to geometric segments (complete for horizontal, missing clothoid for vertical, not implemented for cant)
|
||||
6. Using curve geometry to determine IfcCurveSegment.Transition transition code.
|
||||
7. Utility functions for printing business logical and geometric representations, as well as minimal geometry evaluations
|
||||
2. Creating alignments segment by segment.
|
||||
3. Automatic creation of geometric definitions (IfcCompositeCurve, IfcGradientCurve, IfcSegmentedReferenceCurve)
|
||||
4. Automatic definition of stationing
|
||||
5. Automatic definition of alignment transition point referents
|
||||
6. Utility functions for printing business logical and geometric representations, as well as minimal geometry evaluations
|
||||
|
||||
Future versions of this API will support:
|
||||
Future versions of this API may support:
|
||||
1. Defining alignments using the PI method, including transition spirals
|
||||
2. Updating horizontal curve definitions by revising transition spiral parameters and circular curve radii
|
||||
3. Updating vertical curve definitions by revising horizontal length of curves
|
||||
@@ -40,61 +47,59 @@ Future versions of this API will support:
|
||||
5. Adding a segment at any location along a curve
|
||||
"""
|
||||
|
||||
from .add_segment_to_curve import add_segment_to_curve
|
||||
from .add_segment_to_layout import add_segment_to_layout
|
||||
from .add_stationing_to_alignment import add_stationing_to_alignment
|
||||
from .add_vertical_alignment_by_pi_method import add_vertical_alignment_by_pi_method
|
||||
from .add_vertical_alignment import add_vertical_alignment
|
||||
from .add_zero_length_segment import add_zero_length_segment
|
||||
from .create_alignment_by_pi_method import create_alignment_by_pi_method
|
||||
from .create_alignment_from_csv import create_alignment_from_csv
|
||||
from .create_horizontal_alignment_by_pi_method import create_horizontal_alignment_by_pi_method
|
||||
from .create_geometric_representation import create_geometric_representation
|
||||
from .create_vertical_alignment_by_pi_method import create_vertical_alignment_by_pi_method
|
||||
from .add_stationing_referent import add_stationing_referent
|
||||
from .add_vertical_layout import add_vertical_layout
|
||||
from .create_layout_segment import create_layout_segment
|
||||
from .create_alignment import create
|
||||
from .create_by_pi_method import create_by_pi_method
|
||||
from .create_from_csv import create_from_csv
|
||||
from .create_segment_representations import create_segment_representations
|
||||
from .distance_along_from_station import distance_along_from_station
|
||||
from .get_alignment import get_alignment
|
||||
from .get_alignment_station import get_alignment_station
|
||||
from .get_layout_segments import get_layout_segments
|
||||
from .get_horizontal_layout import get_horizontal_layout
|
||||
from .get_vertical_layout import get_vertical_layout
|
||||
from .get_cant_layout import get_cant_layout
|
||||
from .get_alignment_layouts import get_alignment_layouts
|
||||
from .get_axis_subcontext import get_axis_subcontext
|
||||
from .get_basis_curve import get_basis_curve
|
||||
from .get_child_alignments import get_child_alignments
|
||||
from .get_curve import get_curve
|
||||
from .get_layout_curve import get_layout_curve
|
||||
from .get_parent_alignment import get_parent_alignment
|
||||
from .has_zero_length_segment import has_zero_length_segment
|
||||
from .map_alignment_segments import map_alignment_segments
|
||||
from .map_alignment_horizontal_segment import map_alignment_horizontal_segment
|
||||
from .map_alignment_vertical_segment import map_alignment_vertical_segment
|
||||
from .map_alignment_cant_segment import map_alignment_cant_segment
|
||||
from .layout_horizontal_alignment_by_pi_method import layout_horizontal_alignment_by_pi_method
|
||||
from .layout_vertical_alignment_by_pi_method import layout_vertical_alignment_by_pi_method
|
||||
from .name_segments import name_segments
|
||||
from .remove_last_segment import remove_last_segment
|
||||
from .remove_zero_length_segment import remove_zero_length_segment
|
||||
from .update_curve_segment_transition_code import update_curve_segment_transition_code
|
||||
from .util import *
|
||||
|
||||
from ._get_segment_start_point_label import register_referent_name_callback
|
||||
|
||||
__all__ = [
|
||||
"add_segment_to_curve",
|
||||
"add_segment_to_layout",
|
||||
"add_stationing_to_alignment",
|
||||
"add_vertical_alignment_by_pi_method",
|
||||
"add_vertical_alignment",
|
||||
"add_zero_length_segment",
|
||||
"create_alignment_by_pi_method",
|
||||
"create_alignment_from_csv",
|
||||
"create_horizontal_alignment_by_pi_method",
|
||||
"create_geometric_representation",
|
||||
"create_vertical_alignment_by_pi_method",
|
||||
"add_stationing_referent",
|
||||
"add_vertical_layout",
|
||||
"create_layout_segment",
|
||||
"create",
|
||||
"create_by_pi_method",
|
||||
"create_from_csv",
|
||||
"distance_along_from_station",
|
||||
"get_alignment",
|
||||
"get_alignment_station",
|
||||
"get_layout_segments",
|
||||
"get_horizontal_layout",
|
||||
"get_vertical_layout",
|
||||
"get_cant_layout",
|
||||
"get_alignment_layouts",
|
||||
"get_axis_subcontext",
|
||||
"get_basis_curve",
|
||||
"get_child_alignments",
|
||||
"get_curve",
|
||||
"get_layout_curve",
|
||||
"get_parent_alignment",
|
||||
"has_zero_length_segment",
|
||||
"map_alignment_segments",
|
||||
"map_alignment_horizontal_segment",
|
||||
"map_alignment_vertical_segment",
|
||||
"map_alignment_cant_segment",
|
||||
"layout_horizontal_alignment_by_pi_method",
|
||||
"layout_vertical_alignment_by_pi_method",
|
||||
"name_segments",
|
||||
"remove_last_segment",
|
||||
"remove_zero_length_segment",
|
||||
"update_curve_segment_transition_code",
|
||||
"register_referent_name_callback",
|
||||
]
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
# 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 ifcopenshell
|
||||
import ifcopenshell.geom
|
||||
import ifcopenshell.ifcopenshell_wrapper as ifcopenshell_wrapper
|
||||
import numpy as np
|
||||
from ifcopenshell import entity_instance
|
||||
|
||||
from ifcopenshell.api.alignment._update_curve_segment_transition_code import _update_curve_segment_transition_code
|
||||
from ifcopenshell.api.alignment._map_alignment_horizontal_segment import __map_alignment_horizontal_segment
|
||||
from ifcopenshell.api.alignment._map_alignment_vertical_segment import _map_alignment_vertical_segment
|
||||
from ifcopenshell.api.alignment._map_alignment_cant_segment import _map_alignment_cant_segment
|
||||
|
||||
|
||||
def _add_curve_segment_to_composite_curve(
|
||||
file: ifcopenshell.file, curve_segment: entity_instance, composite_curve: entity_instance
|
||||
):
|
||||
if 0 < len(curve_segment.UsingCurves):
|
||||
raise TypeError("IfcCurveSegment cannot belong to other curves")
|
||||
|
||||
settings = ifcopenshell.geom.settings()
|
||||
if composite_curve.Segments == None or 0 == len(composite_curve.Segments):
|
||||
# this is the first segment so just add it
|
||||
if composite_curve.Segments == None:
|
||||
composite_curve.Segments = []
|
||||
|
||||
# the last segment is always discontinuous
|
||||
curve_segment.Transition = "DISCONTINUOUS"
|
||||
|
||||
composite_curve.Segments += (curve_segment,)
|
||||
assert len(curve_segment.UsingCurves) == 1
|
||||
else:
|
||||
# get the segment before the zero length segment
|
||||
prev_segment = (
|
||||
composite_curve.Segments[-2]
|
||||
if composite_curve.Segments != None and 1 < len(composite_curve.Segments)
|
||||
else None
|
||||
)
|
||||
|
||||
curve_segment.Transition = "CONTINUOUS"
|
||||
|
||||
# must add the new segment to the curve before updating the transition code
|
||||
# add the new segment before the zero length segment
|
||||
zero_length_segment = composite_curve.Segments[-1]
|
||||
|
||||
if prev_segment:
|
||||
segments = composite_curve.Segments[0:-1]
|
||||
segments += (
|
||||
curve_segment,
|
||||
zero_length_segment,
|
||||
)
|
||||
composite_curve.Segments = []
|
||||
composite_curve.Segments += segments
|
||||
_update_curve_segment_transition_code(prev_segment, curve_segment)
|
||||
else:
|
||||
composite_curve.Segments = (curve_segment, zero_length_segment)
|
||||
|
||||
settings = ifcopenshell.geom.settings()
|
||||
segment_fn = ifcopenshell_wrapper.map_shape(settings, curve_segment.wrapped_data)
|
||||
segment_evaluator = ifcopenshell_wrapper.function_item_evaluator(settings, segment_fn)
|
||||
e = segment_evaluator.evaluate(segment_fn.end())
|
||||
end = np.array(e)
|
||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(file)
|
||||
x = float(end[0, 3]) / unit_scale
|
||||
y = float(end[1, 3]) / unit_scale
|
||||
dx = float(end[0, 0])
|
||||
dy = float(end[1, 0])
|
||||
|
||||
# assume IfcAxis2Placement2D
|
||||
zero_length_segment.Placement.Location.Coordinates = (x, y)
|
||||
zero_length_segment.Placement.RefDirection.DirectionRatios = (dx, dy)
|
||||
|
||||
_update_curve_segment_transition_code(curve_segment, zero_length_segment)
|
||||
|
||||
|
||||
def _add_segment_to_curve(file: ifcopenshell.file, segment: entity_instance, curve: entity_instance) -> None:
|
||||
"""
|
||||
Creates an IfcCurveSegment from the IfcAlignmentSegment and adds it to the representation curve. The IfcCurveSegment is added
|
||||
at the end of the curve, but before the manditory zero length segment. The IfcCurveSegment.Transition for the segment
|
||||
that preceeds the new segment is updated.
|
||||
|
||||
:param segment: The segment to be added to the curve
|
||||
:param curve: The representation curve receiving the segment
|
||||
:return: None
|
||||
"""
|
||||
expected_types = ["IfcAlignmentSegment"]
|
||||
if not segment.is_a() in expected_types:
|
||||
raise TypeError(
|
||||
f"Expected entity type to be one of {[_ for _ in expected_types]}, instead received '{segment.is_a()}"
|
||||
)
|
||||
|
||||
if segment.DesignParameters.is_a("IfcAlignmentHorizontalSegment") and not curve.is_a("IfcCompositeCurve"):
|
||||
raise TypeError(f"Expected to see IfcCompositeCurve, instead received '{curve.is_a()}'.")
|
||||
elif segment.DesignParameters.is_a("IfcAlignmentVerticalSegment") and not curve.is_a("IfcGradientCurve"):
|
||||
raise TypeError(f"Expected to see IfcGradientCurve, instead received '{curve.is_a()}'.")
|
||||
elif segment.DesignParameters.is_a("IfcAlignmentCantSegment") and not curve.is_a("IfcSegmentedReferenceCurve"):
|
||||
raise TypeError(f"Expected to see IfcSegmentedReferenceCurve, instead received '{curve.is_a()}'.")
|
||||
|
||||
expected_type = "IfcCompositeCurve"
|
||||
if not curve.is_a(expected_type):
|
||||
raise TypeError(f"Expected to see {expected_type}, instead received {curve.is_a()}.")
|
||||
|
||||
# map the IfcAlignmentSegment to an IfcCurveSegment (or two in the case of helmert curves)
|
||||
if segment.DesignParameters.is_a("IfcAlignmentHorizontalSegment"):
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, segment)
|
||||
elif segment.DesignParameters.is_a("IfcAlignmentVerticalSegment"):
|
||||
mapped_segments = _map_alignment_vertical_segment(file, segment)
|
||||
elif segment.DesignParameters.is_a("IfcAlignmentCantSegment"):
|
||||
cant_layout = segment.Nests[0].RelatingObject
|
||||
mapped_segments = _map_alignment_cant_segment(file, segment, cant_layout.RailHeadDistance)
|
||||
else:
|
||||
assert False
|
||||
|
||||
for mapped_segment in mapped_segments:
|
||||
if mapped_segment:
|
||||
_add_curve_segment_to_composite_curve(file, mapped_segment, curve)
|
||||
@@ -0,0 +1,198 @@
|
||||
# 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 ifcopenshell
|
||||
import ifcopenshell.api.alignment
|
||||
import ifcopenshell.api.nest
|
||||
from ifcopenshell import ifcopenshell_wrapper
|
||||
import numpy as np
|
||||
import math
|
||||
from ifcopenshell import entity_instance
|
||||
from typing import Sequence
|
||||
|
||||
from ifcopenshell.api.alignment._add_segment_to_curve import _add_segment_to_curve
|
||||
from ifcopenshell.api.alignment._get_mapped_segments import _get_mapped_segments
|
||||
from ifcopenshell.api.alignment._get_segment_start_point_label import _get_segment_start_point_label
|
||||
|
||||
|
||||
def _add_segment_to_layout(file: ifcopenshell.file, layout: entity_instance, segment: entity_instance) -> None:
|
||||
"""
|
||||
Adds an IfcAlignmentSegment to a layout alignment (IfcAlignmentHorizontal/Vertical/Cant). This segment is added at the end
|
||||
of the layout, before the manditory zero length segment. An IfcCurveSegment is created for the corresponding geometric representation.
|
||||
|
||||
:param layout: The layout alignment
|
||||
:param segment: The segment to be appended
|
||||
:return: None
|
||||
"""
|
||||
|
||||
expected_types = ["IfcAlignmentHorizontal", "IfcAlignmentVertical", "IfcAlignmentCant"]
|
||||
if not layout.is_a() in expected_types:
|
||||
raise TypeError(
|
||||
f"Expected entity type to be one of {[_ for _ in expected_types]}, instead received {layout.is_a()}"
|
||||
)
|
||||
|
||||
if not (segment.is_a("IfcAlignmentSegment")):
|
||||
raise TypeError(f"Expected to see IfcAlignmentSegment, instead received {segment.is_a()}.")
|
||||
|
||||
curve = ifcopenshell.api.alignment.get_layout_curve(layout)
|
||||
|
||||
# add the new segment to the layout
|
||||
ifcopenshell.api.nest.assign_object(file, related_objects=[segment], relating_object=layout)
|
||||
|
||||
# segment is attached at the end, but this is after the zero length segment
|
||||
# swap the last two segments
|
||||
ifcopenshell.api.nest.reorder_nesting(file, segment, -1, -1)
|
||||
|
||||
# add the new segment to the geometric representation curve
|
||||
_add_segment_to_curve(file, segment, curve)
|
||||
|
||||
# gather information to:
|
||||
# (1) add a referent at the start of this segment
|
||||
# (2) update the name of the zero length segment's referent
|
||||
|
||||
# get the distance along the alignment to the start of the new segment
|
||||
dist_along = 0.0
|
||||
if layout.is_a("IfcAlignmentHorizontal"):
|
||||
for nest in layout.IsNestedBy:
|
||||
for seg in nest.RelatedObjects:
|
||||
if seg.is_a("IfcAlignmentSegment"):
|
||||
dist_along += seg.DesignParameters.SegmentLength
|
||||
|
||||
# the length of the current segment is in dist_along, so subtract it out
|
||||
dist_along -= segment.DesignParameters.SegmentLength
|
||||
else:
|
||||
dist_along = segment.DesignParameters.StartDistAlong
|
||||
|
||||
# get the station of the start of the segment
|
||||
alignment = ifcopenshell.api.alignment.get_alignment(layout)
|
||||
start_station = ifcopenshell.api.alignment.get_alignment_station(file, alignment)
|
||||
station = start_station + dist_along
|
||||
|
||||
# update the zero length layout segment
|
||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(file)
|
||||
|
||||
zero_length_segment = layout.IsNestedBy[0].RelatedObjects[-1]
|
||||
# DesignParameters.StartPoint for IfcAlignmentHorizontalSegment is automatically updated when the
|
||||
# geometric representation is updated because the semantic and geometric data use the same IfcPoint.
|
||||
# This is not the case of IfcAlignmentVerticalSegment and IfcAlignmentCantSegment. For these
|
||||
# segment types, the design parameters of the zero length segment must be updated explicitly.
|
||||
if zero_length_segment.DesignParameters.is_a(
|
||||
"IfcAlignmentVerticalSegment"
|
||||
) or zero_length_segment.DesignParameters.is_a("IfcAlignmentCantSegment"):
|
||||
# get the geometric representation for the new segment
|
||||
mapped_segments = _get_mapped_segments(file, segment)
|
||||
mapped_segment = mapped_segments[0] if mapped_segments[1] == None else mapped_segments[1]
|
||||
|
||||
# compute the end point matrix
|
||||
settings = ifcopenshell.geom.settings()
|
||||
segment_fn = ifcopenshell_wrapper.map_shape(settings, mapped_segment.wrapped_data)
|
||||
segment_evaluator = ifcopenshell_wrapper.function_item_evaluator(settings, segment_fn)
|
||||
e = segment_evaluator.evaluate(segment_fn.end())
|
||||
end = np.array(e)
|
||||
|
||||
# update the zero length segment semantic representation parameters
|
||||
if zero_length_segment.DesignParameters.is_a("IfcAlignmentVerticalSegment"):
|
||||
y = float(end[1, 3]) / unit_scale
|
||||
zero_length_segment.DesignParameters.StartHeight = y
|
||||
dx = float(end[0, 0])
|
||||
dy = float(end[1, 0])
|
||||
zero_length_segment.DesignParameters.StartGradient = dy / dx
|
||||
zero_length_segment.DesignParameters.EndGradient = zero_length_segment.DesignParameters.StartGradient
|
||||
else:
|
||||
z = float(end[2, 3]) / unit_scale
|
||||
dx = float(end[0, 1])
|
||||
dy = float(end[1, 1])
|
||||
dz = float(end[2, 1])
|
||||
ds = math.sqrt(dx * dx + dy * dy)
|
||||
slope = dz / ds
|
||||
railhead = layout.RailHeadDistance
|
||||
|
||||
zero_length_segment.DesignParameters.StartCantLeft = z + slope * railhead / 2.0
|
||||
zero_length_segment.DesignParameters.StartCantRight = z - slope * railhead / 2.0
|
||||
|
||||
# updated the referent's name because the referent is now at a new station
|
||||
start_dist_along = 0.0
|
||||
if segment.DesignParameters.is_a("IfcAlignmentHorizontalSegment"):
|
||||
start_dist_along = dist_along + segment.DesignParameters.SegmentLength
|
||||
else:
|
||||
start_dist_along = segment.DesignParameters.StartDistAlong + segment.DesignParameters.HorizontalLength
|
||||
zero_length_segment.DesignParameters.StartDistAlong = start_dist_along
|
||||
|
||||
end_referent = zero_length_segment.IsNestedBy[0].RelatedObjects[0]
|
||||
end_referent.Name = f"{_get_segment_start_point_label(zero_length_segment,None)} ({ifcopenshell.util.stationing.station_as_string(file,start_station+start_dist_along)})"
|
||||
|
||||
# update the referent's geometric representation's location
|
||||
end_referent.ObjectPlacement.RelativePlacement.Location.DistanceAlong.wrappedValue = start_dist_along
|
||||
settings = ifcopenshell.geom.settings()
|
||||
basis_curve = ifcopenshell.api.alignment.get_basis_curve(alignment)
|
||||
curve_fn = ifcopenshell_wrapper.map_shape(settings, basis_curve.wrapped_data)
|
||||
curve_evaluator = ifcopenshell_wrapper.function_item_evaluator(settings, curve_fn)
|
||||
p = curve_evaluator.evaluate(start_dist_along * unit_scale)
|
||||
p = np.array(p)
|
||||
|
||||
x = float(p[0, 3]) / unit_scale
|
||||
y = float(p[1, 3]) / unit_scale
|
||||
z = float(p[2, 3]) / unit_scale
|
||||
|
||||
rx = float(p[0, 0])
|
||||
ry = float(p[1, 0])
|
||||
rz = float(p[2, 0])
|
||||
|
||||
ax = float(p[0, 2])
|
||||
ay = float(p[1, 2])
|
||||
az = float(p[2, 2])
|
||||
|
||||
end_referent.ObjectPlacement.CartesianPosition.Location.Coordinates = (x, y, z)
|
||||
end_referent.ObjectPlacement.CartesianPosition.Axis.DirectionRatios = (ax, ay, az)
|
||||
end_referent.ObjectPlacement.CartesianPosition.RefDirection.DirectionRatios = (rx, ry, rz)
|
||||
|
||||
# create the start of segment referent
|
||||
|
||||
# get the previous segment. Working from the end of the basis curve, -1 is zero length segment
|
||||
# -2 is the newly added segment, so -3 is the segment occuring just before the newly added segment
|
||||
prev_segment = layout.IsNestedBy[0].RelatedObjects[-3] if 2 < len(layout.IsNestedBy[0].RelatedObjects) else None
|
||||
name = f"{_get_segment_start_point_label(prev_segment,segment)} ({ifcopenshell.util.stationing.station_as_string(file,station)})"
|
||||
referent = ifcopenshell.api.alignment.add_stationing_referent(
|
||||
file, segment, basis_curve=basis_curve, distance_along=dist_along, station=station, name=name
|
||||
)
|
||||
|
||||
if len(curve.Segments) == 2 and layout.is_a("IfcAlignmentHorizontal"):
|
||||
# this is the first real segment in the horizontal alignment
|
||||
# update the location of the alignment's stationing referent
|
||||
alignment = ifcopenshell.api.alignment.get_alignment(layout)
|
||||
stationing_referent = alignment.IsNestedBy[0].RelatedObjects[0]
|
||||
p = curve_evaluator.evaluate(
|
||||
stationing_referent.ObjectPlacement.RelativePlacement.Location.DistanceAlong.wrappedValue
|
||||
)
|
||||
p = np.array(p)
|
||||
|
||||
x = float(p[0, 3]) / unit_scale
|
||||
y = float(p[1, 3]) / unit_scale
|
||||
z = float(p[2, 3]) / unit_scale
|
||||
|
||||
rx = float(p[0, 0])
|
||||
ry = float(p[1, 0])
|
||||
rz = float(p[2, 0])
|
||||
|
||||
ax = float(p[0, 2])
|
||||
ay = float(p[1, 2])
|
||||
az = float(p[2, 2])
|
||||
|
||||
stationing_referent.ObjectPlacement.CartesianPosition.Location.Coordinates = (x, y, z)
|
||||
stationing_referent.ObjectPlacement.CartesianPosition.Axis.DirectionRatios = (ax, ay, az)
|
||||
stationing_referent.ObjectPlacement.CartesianPosition.RefDirection.DirectionRatios = (rx, ry, rz)
|
||||
@@ -0,0 +1,144 @@
|
||||
# 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 ifcopenshell
|
||||
import ifcopenshell.api.alignment
|
||||
import ifcopenshell.api.nest
|
||||
from ifcopenshell import entity_instance
|
||||
|
||||
from ifcopenshell.api.alignment._get_segment_start_point_label import _get_segment_start_point_label
|
||||
|
||||
|
||||
def _add_zero_length_segment(file: ifcopenshell.file, layout: entity_instance) -> None:
|
||||
"""
|
||||
Adds a zero length segment to the end of a layout. Also adds a zero length segment to the end of the corresponding geometric curve.
|
||||
|
||||
If the layout already has a zero length segment, nothing is changed
|
||||
|
||||
:param layout: An IfcAlignmentHorizontal, IfcAlignmentVertical, or IfcAlignmentCant
|
||||
:return: None
|
||||
"""
|
||||
expected_types = ["IfcAlignmentHorizontal", "IfcAlignmentVertical", "IfcAlignmentCant"]
|
||||
if not layout.is_a() in expected_types:
|
||||
raise TypeError(
|
||||
f"Expected layout type to be one of {[_ for _ in expected_types]}, instead received {layout.is_a()}"
|
||||
)
|
||||
|
||||
if ifcopenshell.api.alignment.has_zero_length_segment(layout):
|
||||
return
|
||||
|
||||
segment = None
|
||||
if layout.is_a("IfcAlignmentHorizontal"):
|
||||
design_parameters = file.createIfcAlignmentHorizontalSegment(
|
||||
StartPoint=file.createIfcCartesianPoint(
|
||||
(0.0, 0.0)
|
||||
), # this is a little problematic. need to know the end point and tangent
|
||||
StartDirection=0.0, # of the previous segment, which requires geometry mapping
|
||||
StartRadiusOfCurvature=0.0,
|
||||
EndRadiusOfCurvature=0.0,
|
||||
SegmentLength=0.0,
|
||||
PredefinedType="LINE",
|
||||
)
|
||||
segment = file.createIfcAlignmentSegment(GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters)
|
||||
elif layout.is_a("IfcAlignmentVertical"):
|
||||
last_segment_dist_along = 0.0
|
||||
last_segment_end_gradient = 0.0
|
||||
for rel in layout.IsNestedBy:
|
||||
if 0 < len(rel.RelatedObjects):
|
||||
last_segment = rel.RelatedObjects[1]
|
||||
last_segment_dist_along = (
|
||||
last_segment.DesignParameters.StartDistAlong + last_segment.DesignParameters.HorizontalLength
|
||||
)
|
||||
last_segment_end_gradient = last_segment.DesignParameters.EndGradient
|
||||
|
||||
design_parameters = file.createIfcAlignmentVerticalSegment(
|
||||
StartDistAlong=last_segment_dist_along,
|
||||
HorizontalLength=0.0,
|
||||
StartHeight=0.0,
|
||||
StartGradient=last_segment_end_gradient,
|
||||
EndGradient=last_segment_end_gradient,
|
||||
PredefinedType="CONSTANTGRADIENT",
|
||||
)
|
||||
segment = file.createIfcAlignmentSegment(GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters)
|
||||
elif layout.is_a("IfcAlignmentCant"):
|
||||
last_segment_dist_along = 0.0
|
||||
last_segment_cant_left = 0.0
|
||||
last_segment_cant_right = 0.0
|
||||
for rel in layout.IsNestedBy:
|
||||
if 0 < len(rel.RelatedObjects):
|
||||
last_segment = rel.RelatedObjects[1]
|
||||
last_segment_dist_along = (
|
||||
last_segment.DesignParameters.StartDistAlong + last_segment.DesignParameters.HorizontalLength
|
||||
)
|
||||
last_segment_cant_left = (
|
||||
last_segment.DesignParameters.EndCantLeft
|
||||
if last_segment.DesignParameters.EndCantLeft != None
|
||||
else last_segment.DesignParameters.StartCantLeft
|
||||
)
|
||||
last_segment_cant_right = (
|
||||
last_segment.DesignParameters.EndCantRight
|
||||
if last_segment.DesignParameters.EndCantRight != None
|
||||
else last_segment.DesignParameters.StartCantRight
|
||||
)
|
||||
|
||||
design_parameters = file.createIfcAlignmentCantSegment(
|
||||
StartDistAlong=last_segment_dist_along,
|
||||
HorizontalLength=0.0,
|
||||
StartCantLeft=last_segment_cant_left,
|
||||
StartCantRight=last_segment_cant_right,
|
||||
PredefinedType="CONSTANTCANT",
|
||||
)
|
||||
segment = file.createIfcAlignmentSegment(GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters)
|
||||
|
||||
ifcopenshell.api.nest.assign_object(file, related_objects=[segment], relating_object=layout)
|
||||
|
||||
curve = ifcopenshell.api.alignment.get_layout_curve(layout)
|
||||
|
||||
has_zero_length_segment = False
|
||||
if curve.Segments != None and 0 < len(curve.Segments):
|
||||
last_segment = curve.Segments[-1]
|
||||
has_zero_length_segment = (
|
||||
True
|
||||
if last_segment.Transition == "DISCONTINUOUS" and last_segment.SegmentLength.wrappedValue == 0.0
|
||||
else False
|
||||
)
|
||||
|
||||
if not has_zero_length_segment:
|
||||
parent_curve = file.createIfcLine(
|
||||
Pnt=file.createIfcCartesianPoint(Coordinates=((0.0, 0.0))),
|
||||
Dir=file.createIfcVector(
|
||||
Orientation=file.createIfcDirection(DirectionRatios=((1.0, 0.0))),
|
||||
Magnitude=1.0,
|
||||
),
|
||||
)
|
||||
curve_segment = file.createIfcCurveSegment(
|
||||
Transition="DISCONTINUOUS",
|
||||
Placement=file.createIfcAxis2Placement2D(
|
||||
Location=file.createIfcCartesianPoint((0.0, 0.0)),
|
||||
RefDirection=file.createIfcDirection((1.0, 0.0)),
|
||||
),
|
||||
SegmentStart=file.createIfcLengthMeasure(0.0),
|
||||
SegmentLength=file.createIfcLengthMeasure(0.0),
|
||||
ParentCurve=parent_curve,
|
||||
)
|
||||
curve.Segments = [
|
||||
curve_segment,
|
||||
]
|
||||
|
||||
name = f"{_get_segment_start_point_label(segment,None)} {ifcopenshell.util.stationing.station_as_string(file,0.0)}"
|
||||
ifcopenshell.api.alignment.add_stationing_referent(file, segment, curve, 0.0, 0.0, name=name)
|
||||
+30
-53
@@ -25,17 +25,17 @@ import math
|
||||
from collections.abc import Sequence
|
||||
|
||||
|
||||
def create_geometric_representation(file: ifcopenshell.file, alignment: entity_instance) -> None:
|
||||
def _create_geometric_representation(file: ifcopenshell.file, alignment: entity_instance) -> None:
|
||||
"""
|
||||
Create geometric representation for the alignment.
|
||||
Create geometric representation for the alignment and its nested layouts.
|
||||
|
||||
There are 5 different cases:
|
||||
There are 5 different cases (the IfcCurve created is indicated):
|
||||
|
||||
1) Horizontal only
|
||||
2) Horizontal + Vertical
|
||||
3) Horizontal + Vertical + Cant
|
||||
4) Vertical only (this occurs when horizontal is reused from a parent alignment)
|
||||
5) Vertical + Cant (this occurs when horizontal is reused from a parent alignment)
|
||||
1) Horizontal only -> IfcCompositeCurve
|
||||
2) Horizontal + Vertical -> IfcCompositeCurve and IfcGradientCurve
|
||||
3) Horizontal + Vertical + Cant -> IfcCompositeCurve and IfcSegmentedReferentCurve
|
||||
4) Vertical only (this occurs when horizontal is reused from a parent alignment) -> IfcGradientCurve
|
||||
5) Vertical + Cant (this occurs when horizontal is reused from a parent alignment) -> IfcSegmentedReferenceCurve
|
||||
|
||||
:param alignment: The alignment for which the representation is being created
|
||||
:return: None
|
||||
@@ -43,7 +43,7 @@ def create_geometric_representation(file: ifcopenshell.file, alignment: entity_i
|
||||
|
||||
expected_type = "IfcAlignment"
|
||||
if not alignment.is_a(expected_type):
|
||||
raise TypeError("Expected '{expected_type}' but got '{alignment.is_a()}'")
|
||||
raise TypeError(f"Expected {expected_type} but got {alignment.is_a()}")
|
||||
|
||||
placement = file.createIfcLocalPlacement(
|
||||
PlacementRelTo=None,
|
||||
@@ -60,11 +60,8 @@ def create_geometric_representation(file: ifcopenshell.file, alignment: entity_i
|
||||
if len(layouts) == 1 and len(children) == 0:
|
||||
assert layouts[0].is_a("IfcAlignmentHorizontal")
|
||||
# Horizontal only - IFC CT 4.1.7.1.1.1
|
||||
ifcopenshell.api.alignment.add_zero_length_segment(file, layouts[0])
|
||||
composite_curve = file.createIfcCompositeCurve()
|
||||
ifcopenshell.api.alignment.map_alignment_segments(file, layouts[0], composite_curve)
|
||||
representation = file.create_entity(
|
||||
type="IfcShapeRepresentation",
|
||||
composite_curve = file.createIfcCompositeCurve(Segments=[], SelfIntersect=False)
|
||||
representation = file.createIfcShapeRepresentation(
|
||||
ContextOfItems=axis_geom_subcontext,
|
||||
RepresentationIdentifier="Axis",
|
||||
RepresentationType="Curve2D",
|
||||
@@ -75,12 +72,8 @@ def create_geometric_representation(file: ifcopenshell.file, alignment: entity_i
|
||||
# Horizontal and Vertical - IFC CT 4.1.7.1.1.1
|
||||
assert layouts[0].is_a("IfcAlignmentHorizontal")
|
||||
assert layouts[1].is_a("IfcAlignmentVertical")
|
||||
ifcopenshell.api.alignment.add_zero_length_segment(file, layouts[0])
|
||||
ifcopenshell.api.alignment.add_zero_length_segment(file, layouts[1])
|
||||
composite_curve = file.createIfcCompositeCurve()
|
||||
ifcopenshell.api.alignment.map_alignment_segments(file, layouts[0], composite_curve)
|
||||
representation = file.create_entity(
|
||||
type="IfcShapeRepresentation",
|
||||
composite_curve = file.createIfcCompositeCurve(Segments=[], SelfIntersect=False)
|
||||
representation = file.createIfcShapeRepresentation(
|
||||
ContextOfItems=axis_geom_subcontext,
|
||||
RepresentationIdentifier="FootPrint",
|
||||
RepresentationType="Curve2D",
|
||||
@@ -88,10 +81,8 @@ def create_geometric_representation(file: ifcopenshell.file, alignment: entity_i
|
||||
)
|
||||
ifcopenshell.api.geometry.assign_representation(file, alignment, representation)
|
||||
|
||||
gradient_curve = file.createIfcGradientCurve(BaseCurve=composite_curve)
|
||||
ifcopenshell.api.alignment.map_alignment_segments(file, layouts[1], gradient_curve)
|
||||
representation = file.create_entity(
|
||||
type="IfcShapeRepresentation",
|
||||
gradient_curve = file.createIfcGradientCurve(Segments=[], BaseCurve=composite_curve, SelfIntersect=False)
|
||||
representation = file.createIfcShapeRepresentation(
|
||||
ContextOfItems=axis_geom_subcontext,
|
||||
RepresentationIdentifier="Axis",
|
||||
RepresentationType="Curve3D",
|
||||
@@ -103,13 +94,8 @@ def create_geometric_representation(file: ifcopenshell.file, alignment: entity_i
|
||||
assert layouts[0].is_a("IfcAlignmentHorizontal")
|
||||
assert layouts[1].is_a("IfcAlignmentVertical")
|
||||
assert layouts[2].is_a("IfcAlignmentCant")
|
||||
ifcopenshell.api.alignment.add_zero_length_segment(file, layouts[0])
|
||||
ifcopenshell.api.alignment.add_zero_length_segment(file, layouts[1])
|
||||
ifcopenshell.api.alignment.add_zero_length_segment(file, layouts[2])
|
||||
composite_curve = file.createIfcCompositeCurve()
|
||||
ifcopenshell.api.alignment.map_alignment_segments(file, layouts[0], composite_curve)
|
||||
representation = file.create_entity(
|
||||
type="IfcShapeRepresentation",
|
||||
composite_curve = file.createIfcCompositeCurve(Segments=[], SelfIntersect=False)
|
||||
representation = file.createIfcShapeRepresentation(
|
||||
ContextOfItems=axis_geom_subcontext,
|
||||
RepresentationIdentifier="FootPrint",
|
||||
RepresentationType="Curve2D",
|
||||
@@ -117,10 +103,10 @@ def create_geometric_representation(file: ifcopenshell.file, alignment: entity_i
|
||||
)
|
||||
ifcopenshell.api.geometry.assign_representation(file, alignment, representation)
|
||||
|
||||
gradient_curve = file.createIfcGradientCurve(BaseCurve=composite_curve)
|
||||
ifcopenshell.api.alignment.map_alignment_segments(file, layouts[1], gradient_curve)
|
||||
segmented_reference_curve = file.createIfcSegmentedReferenceCurve(BaseCurve=gradient_curve)
|
||||
ifcopenshell.api.alignment.map_alignment_segments(file, layouts[2], segmented_reference_curve)
|
||||
gradient_curve = file.createIfcGradientCurve(Segments=[], BaseCurve=composite_curve, SelfIntersect=False)
|
||||
segmented_reference_curve = file.createIfcSegmentedReferenceCurve(
|
||||
Segments=[], BaseCurve=gradient_curve, SelfIntersect=False
|
||||
)
|
||||
representation = file.create_entity(
|
||||
type="IfcShapeRepresentation",
|
||||
ContextOfItems=axis_geom_subcontext,
|
||||
@@ -132,11 +118,8 @@ def create_geometric_representation(file: ifcopenshell.file, alignment: entity_i
|
||||
else:
|
||||
# Reusing Horizontal - CT 4.1.4.4.1.2
|
||||
# Create a representation on the parent alignment
|
||||
ifcopenshell.api.alignment.add_zero_length_segment(file, layouts[0])
|
||||
composite_curve = file.createIfcCompositeCurve()
|
||||
ifcopenshell.api.alignment.map_alignment_segments(file, layouts[0], composite_curve)
|
||||
representation = file.create_entity(
|
||||
type="IfcShapeRepresentation",
|
||||
composite_curve = file.createIfcCompositeCurve(Segments=[], SelfIntersect=False)
|
||||
representation = file.createIfcShapeRepresentation(
|
||||
ContextOfItems=axis_geom_subcontext,
|
||||
RepresentationIdentifier="FootPrint",
|
||||
RepresentationType="Curve2D",
|
||||
@@ -149,12 +132,9 @@ def create_geometric_representation(file: ifcopenshell.file, alignment: entity_i
|
||||
child_layouts = ifcopenshell.api.alignment.get_alignment_layouts(child_alignment)
|
||||
if len(child_layouts) == 1:
|
||||
assert child_layouts[0].is_a("IfcAlignmentVertical")
|
||||
ifcopenshell.api.alignment.add_zero_length_segment(file, child_layouts[0])
|
||||
base_curve = ifcopenshell.api.alignment.get_basis_curve(alignment)
|
||||
gradient_curve = file.createIfcGradientCurve(BaseCurve=base_curve)
|
||||
ifcopenshell.api.alignment.map_alignment_segments(file, child_layouts[0], gradient_curve)
|
||||
representation = file.create_entity(
|
||||
type="IfcShapeRepresentation",
|
||||
gradient_curve = file.createIfcGradientCurve(Segments=[], BaseCurve=base_curve, SelfIntersect=False)
|
||||
representation = file.createIfcShapeRepresentation(
|
||||
ContextOfItems=axis_geom_subcontext,
|
||||
RepresentationIdentifier="Axis",
|
||||
RepresentationType="Curve3D",
|
||||
@@ -164,15 +144,12 @@ def create_geometric_representation(file: ifcopenshell.file, alignment: entity_i
|
||||
elif len(child_layouts) == 2:
|
||||
assert child_layouts[0].is_a("IfcAlignmentVertical")
|
||||
assert child_layouts[1].is_a("IfcAlignmentCant")
|
||||
ifcopenshell.api.alignment.add_zero_length_segment(file, child_layouts[0])
|
||||
ifcopenshell.api.alignment.add_zero_length_segment(file, child_layouts[1])
|
||||
base_curve = ifcopenshell.api.alignment.get_basis_curve(alignment)
|
||||
gradient_curve = file.createIfcGradientCurve(BaseCurve=base_curve)
|
||||
ifcopenshell.api.alignment.map_alignment_segments(file, child_layouts[0], gradient_curve)
|
||||
segmented_reference_curve = file.createIfcSegmentedReferenceCurve(BaseCurve=gradient_curve)
|
||||
ifcopenshell.api.alignment.map_alignment_segments(file, child_layouts[1], segmented_reference_curve)
|
||||
representation = file.create_entity(
|
||||
type="IfcShapeRepresentation",
|
||||
gradient_curve = file.createIfcGradientCurve(Segments=[], BaseCurve=base_curve, SelfIntersect=False)
|
||||
segmented_reference_curve = file.createIfcSegmentedReferenceCurve(
|
||||
Segments=[], BaseCurve=gradient_curve, SelfIntersect=False
|
||||
)
|
||||
representation = file.creatIfcShapeRepresentation(
|
||||
ContextOfItems=axis_geom_subcontext,
|
||||
RepresentationIdentifier="Axis",
|
||||
RepresentationType="Curve3D",
|
||||
@@ -0,0 +1,60 @@
|
||||
# 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 ifcopenshell
|
||||
import ifcopenshell.api.alignment
|
||||
from ifcopenshell import entity_instance
|
||||
from typing import Sequence
|
||||
|
||||
|
||||
def __get_curve_segment_count(segment: entity_instance) -> int:
|
||||
"""
|
||||
returns the number of IfcCurveSegment that an IfcAlignmentSegment maps to.
|
||||
generally this is a 1 to 1 mapping, with helmert curve being the exception
|
||||
"""
|
||||
if segment.DesignParameters.is_a("IfcAlignmentHorizontalSegment"):
|
||||
return 2 if segment.DesignParameters.PredefinedType == "HELMERTCURVE" else 1
|
||||
elif segment.DesignParameters.is_a("IfcAlignmentVerticalSegment"):
|
||||
return 1
|
||||
elif segment.DesignParameters.is_a("IfcAlignmentCantSegment"):
|
||||
return 2 if segment.DesignParameters.PredefinedType == "HELMERTCURVE" else 1
|
||||
|
||||
|
||||
def _get_mapped_segments(file: ifcopenshell.file, layout_segment: entity_instance) -> Sequence[entity_instance]:
|
||||
"""
|
||||
Finds the IfcCurveSegment related to segment
|
||||
"""
|
||||
expected_type = "IfcAlignmentSegment"
|
||||
if not layout_segment.is_a(expected_type):
|
||||
raise TypeError(f"Expected to see type '{expected_type}', instead received '{layout_segment.is_a()}'.")
|
||||
|
||||
layout = layout_segment.Nests[0].RelatingObject
|
||||
alignment = ifcopenshell.api.alignment.get_alignment(layout)
|
||||
curve = ifcopenshell.api.alignment.get_curve(alignment)
|
||||
|
||||
index = 0
|
||||
for seg in layout.IsNestedBy[0].RelatedObjects:
|
||||
index += __get_curve_segment_count(seg)
|
||||
if seg == layout_segment:
|
||||
break
|
||||
|
||||
segment_count = __get_curve_segment_count(layout_segment)
|
||||
if segment_count == 1:
|
||||
return (curve.Segments[index - segment_count], None)
|
||||
else:
|
||||
return (curve.Segments[index - segment_count], curve.Segment[index])
|
||||
@@ -0,0 +1,314 @@
|
||||
# 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 ifcopenshell
|
||||
from ifcopenshell import entity_instance
|
||||
from typing import Sequence
|
||||
|
||||
|
||||
_horizontal_callback = None
|
||||
_vertical_callback = None
|
||||
_cant_callback = None
|
||||
|
||||
|
||||
def register_referent_name_callback(horizontal=None, vertical=None, cant=None):
|
||||
"""
|
||||
Referents are automatically created at the start of each horizontal, vertical, and cant segment.
|
||||
The referents represent key points in the alignment layout such as Point of Curvature, Point of Tangent, and others.
|
||||
Different juristicions use different naming systems for these key points.
|
||||
|
||||
The referent name callback functions provide a customizable method for naming these referents. If a callback is registered,
|
||||
it is called when creating the referent name, otherwise the default naming is used.
|
||||
|
||||
The callback function signature is
|
||||
|
||||
def mycallback(prev_segment : entity_instance, segment : entity_instance) -> str:
|
||||
|
||||
The callback function returns a string that is used in the referent name for the referent at the start of `segment`.
|
||||
The callback must accomodate the following cases:
|
||||
* prev_segment = None and segment != None - this indicates the last segment so the "End of Alignment" name is returned
|
||||
* prev_segment != None and segment == None - this indicates the first segment so the "Beginning of Alignment" name is returned
|
||||
* prev_segment != None and segment != None - this indicates an intermediate segment so a name representitive of the transition is returned
|
||||
|
||||
Setting any or all of the callbacks to None causes the default naming to be used.
|
||||
"""
|
||||
global _horizontal_callback
|
||||
_horizontal_callback = horizontal
|
||||
|
||||
global _vertical_callback
|
||||
_vertical_callback = vertical
|
||||
|
||||
global _cant_callback
|
||||
_cant_callback = cant
|
||||
|
||||
|
||||
def _horizontal_label(prev_segment: entity_instance, segment: entity_instance) -> str:
|
||||
if prev_segment == None and segment != None:
|
||||
label = "P.O.B."
|
||||
elif prev_segment != None and segment == None:
|
||||
label = "P.O.E."
|
||||
else:
|
||||
lookup_table = {
|
||||
"BLOSSCURVE": {
|
||||
"BLOSSCURVE": "xx",
|
||||
"CIRCULARARC": "S.C.",
|
||||
"CLOTHOID": "xx",
|
||||
"COSINECURVE": "xx",
|
||||
"CUBIC": "xx",
|
||||
"HELMERTCURVE": "xx",
|
||||
"LINE": "S.T.",
|
||||
"SINECURVE": "xx",
|
||||
"VIENNESEBEND": "xx",
|
||||
},
|
||||
"CIRCULARARC": {
|
||||
"BLOSSCURVE": "C.S.",
|
||||
"CIRCULARARC": "P.C.C.",
|
||||
"CLOTHOID": "C.S.",
|
||||
"COSINECURVE": "C.S.",
|
||||
"CUBIC": "C.S.",
|
||||
"HELMERTCURVE": "C.S.",
|
||||
"LINE": "P.T.",
|
||||
"SINECURVE": "C.S.",
|
||||
"VIENNESEBEND": "C.S.",
|
||||
},
|
||||
"CLOTHOID": {
|
||||
"BLOSSCURVE": "xx",
|
||||
"CIRCULARARC": "S.C.",
|
||||
"CLOTHOID": "xx",
|
||||
"COSINECURVE": "xx",
|
||||
"CUBIC": "xx",
|
||||
"HELMERTCURVE": "xx",
|
||||
"LINE": "S.T.",
|
||||
"SINECURVE": "xx",
|
||||
"VIENNESEBEND": "xx",
|
||||
},
|
||||
"COSINECURVE": {
|
||||
"BLOSSCURVE": "xx",
|
||||
"CIRCULARARC": "S.C.",
|
||||
"CLOTHOID": "xx",
|
||||
"COSINECURVE": "xx",
|
||||
"CUBIC": "xx",
|
||||
"HELMERTCURVE": "xx",
|
||||
"LINE": "S.T.",
|
||||
"SINECURVE": "xx",
|
||||
"VIENNESEBEND": "xx",
|
||||
},
|
||||
"CUBIC": {
|
||||
"BLOSSCURVE": "xx",
|
||||
"CIRCULARARC": "S.C.",
|
||||
"CLOTHOID": "xx",
|
||||
"COSINECURVE": "xx",
|
||||
"CUBIC": "xx",
|
||||
"HELMERTCURVE": "xx",
|
||||
"LINE": "S.T.",
|
||||
"SINECURVE": "xx",
|
||||
"VIENNESEBEND": "xx",
|
||||
},
|
||||
"HELMERTCURVE": {
|
||||
"BLOSSCURVE": "xx",
|
||||
"CIRCULARARC": "S.C.",
|
||||
"CLOTHOID": "xx",
|
||||
"COSINECURVE": "xx",
|
||||
"CUBIC": "xx",
|
||||
"HELMERTCURVE": "xx",
|
||||
"LINE": "S.T.",
|
||||
"SINECURVE": "xx",
|
||||
"VIENNESEBEND": "xx",
|
||||
},
|
||||
"LINE": {
|
||||
"BLOSSCURVE": "T.S.",
|
||||
"CIRCULARARC": "P.C.",
|
||||
"CLOTHOID": "T.S.",
|
||||
"COSINECURVE": "T.S.",
|
||||
"CUBIC": "T.S.",
|
||||
"HELMERTCURVE": "T.S.",
|
||||
"LINE": "P.I.",
|
||||
"SINECURVE": "T.S.",
|
||||
"VIENNESEBEND": "T.S.",
|
||||
},
|
||||
"SINECURVE": {
|
||||
"BLOSSCURVE": "xx",
|
||||
"CIRCULARARC": "S.C.",
|
||||
"CLOTHOID": "xx",
|
||||
"COSINECURVE": "xx",
|
||||
"CUBIC": "xx",
|
||||
"HELMERTCURVE": "xx",
|
||||
"LINE": "S.T.",
|
||||
"SINECURVE": "xx",
|
||||
"VIENNESEBEND": "xx",
|
||||
},
|
||||
"VIENNESEBEND": {
|
||||
"BLOSSCURVE": "xx",
|
||||
"CIRCULARARC": "S.C.",
|
||||
"CLOTHOID": "xx",
|
||||
"COSINECURVE": "xx",
|
||||
"CUBIC": "xx",
|
||||
"HELMERTCURVE": "xx",
|
||||
"LINE": "S.T.",
|
||||
"SINECURVE": "xx",
|
||||
"VIENNESEBEND": "xx",
|
||||
},
|
||||
}
|
||||
label = lookup_table[prev_segment.DesignParameters.PredefinedType][segment.DesignParameters.PredefinedType]
|
||||
|
||||
return label
|
||||
|
||||
|
||||
def _vertical_label(prev_segment: entity_instance, segment: entity_instance) -> str:
|
||||
if prev_segment == None and segment != None:
|
||||
label = "V.P.O.B."
|
||||
elif prev_segment != None and segment == None:
|
||||
label = "V.P.O.E."
|
||||
else:
|
||||
lookup_table = {
|
||||
"CIRCULARARC": {"CIRCULARARC": "xx", "CLOTHOID": "xx", "CONSTANTGRADIENT": "xx", "PARABOLICARC": "xx"},
|
||||
"CLOTHOID": {"CIRCULARARC": "xx", "CLOTHOID": "xx", "CONSTANTGRADIENT": "xx", "PARABOLICARC": "xx"},
|
||||
"CONSTANTGRADIENT": {
|
||||
"CIRCULARARC": "xx",
|
||||
"CLOTHOID": "xx",
|
||||
"CONSTANTGRADIENT": "P.V.I",
|
||||
"PARABOLICARC": "P.V.C.",
|
||||
},
|
||||
"PARABOLICARC": {
|
||||
"CIRCULARARC": "xx",
|
||||
"CLOTHOID": "xx",
|
||||
"CONSTANTGRADIENT": "P.V.T.",
|
||||
"PARABOLICARC": "V.C.C.",
|
||||
},
|
||||
}
|
||||
label = lookup_table[prev_segment.DesignParameters.PredefinedType][segment.DesignParameters.PredefinedType]
|
||||
|
||||
return label
|
||||
|
||||
|
||||
def _cant_label(prev_segment: entity_instance, segment: entity_instance) -> str:
|
||||
if prev_segment == None and segment != None:
|
||||
label = "C.P.O.B."
|
||||
elif prev_segment != None and segment == None:
|
||||
label = "C.P.O.E."
|
||||
else:
|
||||
lookup_table = {
|
||||
"BLOSSCURVE": {
|
||||
"BLOSSCURVE": "xx",
|
||||
"CONSTANTCANT": "xx",
|
||||
"COSINECURVE": "xx",
|
||||
"HELMERTCURVE": "xx",
|
||||
"LINEARTRANSITION": "xx",
|
||||
"SINECURVE": "xx",
|
||||
"VIENNESEBEND": "xx",
|
||||
},
|
||||
"CONSTANTCANT": {
|
||||
"BLOSSCURVE": "xx",
|
||||
"CONSTANTCANT": "xx",
|
||||
"COSINECURVE": "xx",
|
||||
"HELMERTCURVE": "xx",
|
||||
"LINEARTRANSITION": "xx",
|
||||
"SINECURVE": "xx",
|
||||
"VIENNESEBEND": "xx",
|
||||
},
|
||||
"COSINECURVE": {
|
||||
"BLOSSCURVE": "xx",
|
||||
"CONSTANTCANT": "xx",
|
||||
"COSINECURVE": "xx",
|
||||
"HELMERTCURVE": "xx",
|
||||
"LINEARTRANSITION": "xx",
|
||||
"SINECURVE": "xx",
|
||||
"VIENNESEBEND": "xx",
|
||||
},
|
||||
"HELMERTCURVE": {
|
||||
"BLOSSCURVE": "xx",
|
||||
"CONSTANTCANT": "xx",
|
||||
"COSINECURVE": "xx",
|
||||
"HELMERTCURVE": "xx",
|
||||
"LINEARTRANSITION": "xx",
|
||||
"SINECURVE": "xx",
|
||||
"VIENNESEBEND": "xx",
|
||||
},
|
||||
"LINEARTRANSITION": {
|
||||
"BLOSSCURVE": "xx",
|
||||
"CONSTANTCANT": "xx",
|
||||
"COSINECURVE": "xx",
|
||||
"HELMERTCURVE": "xx",
|
||||
"LINEARTRANSITION": "xx",
|
||||
"SINECURVE": "xx",
|
||||
"VIENNESEBEND": "xx",
|
||||
},
|
||||
"SINECURVE": {
|
||||
"BLOSSCURVE": "xx",
|
||||
"CONSTANTCANT": "xx",
|
||||
"COSINECURVE": "xx",
|
||||
"HELMERTCURVE": "xx",
|
||||
"LINEARTRANSITION": "xx",
|
||||
"SINECURVE": "xx",
|
||||
"VIENNESEBEND": "xx",
|
||||
},
|
||||
"VIENNESEBEND": {
|
||||
"BLOSSCURVE": "xx",
|
||||
"CONSTANTCANT": "xx",
|
||||
"COSINECURVE": "xx",
|
||||
"HELMERTCURVE": "xx",
|
||||
"LINEARTRANSITION": "xx",
|
||||
"SINECURVE": "xx",
|
||||
"VIENNESEBEND": "xx",
|
||||
},
|
||||
}
|
||||
label = lookup_table[prev_segment.DesignParameters.PredefinedType][segment.DesignParameters.PredefinedType]
|
||||
|
||||
return label
|
||||
|
||||
|
||||
def _get_segment_start_point_label(prev_segment: entity_instance, segment: entity_instance) -> str:
|
||||
"""
|
||||
Returns the label for the start point of a segment. Typically used in the name of an IfcReferent
|
||||
"""
|
||||
if prev_segment != None and segment != None and prev_segment.is_a() != segment.is_a():
|
||||
raise TypeError(
|
||||
f"Expected entity type to be the same type, instead received {prev_segment.is_a()} and {segment.is_a()}"
|
||||
)
|
||||
|
||||
expected_types = ["IfcAlignmentHorizontalSegment", "IfcAlignmentVerticalSegment", "IfcAlignmentCantSegment"]
|
||||
if prev_segment != None and not prev_segment.DesignParameters.is_a() in expected_types:
|
||||
raise TypeError(
|
||||
f"Expected prev_segment.DesignParameters type to be one of {[_ for _ in expected_types]}, instead received {prev_segment.DesignParameters.is_a()}"
|
||||
)
|
||||
if segment != None and not segment.DesignParameters.is_a() in expected_types:
|
||||
raise TypeError(
|
||||
f"Expected segment.DesignParameters type to be one of {[_ for _ in expected_types]}, instead received {segment.DesignParameters.is_a()}"
|
||||
)
|
||||
|
||||
s = segment if segment != None else prev_segment
|
||||
if s.DesignParameters.is_a("IfcAlignmentHorizontalSegment"):
|
||||
global _horizontal_callback
|
||||
if _horizontal_callback:
|
||||
label = _horizontal_callback(prev_segment, segment)
|
||||
else:
|
||||
label = _horizontal_label(prev_segment, segment)
|
||||
elif s.DesignParameters.is_a("IfcAlignmentVerticalSegment"):
|
||||
global _vertical_callback
|
||||
if _vertical_callback:
|
||||
label = _vertical_callback(prev_segment, segment)
|
||||
else:
|
||||
label = _vertical_label(prev_segment, segment)
|
||||
elif s.DesignParameters.is_a("IfcAlignmentCantSegment"):
|
||||
global _cant_callback
|
||||
if _cant_callback:
|
||||
label = _cant_callback(prev_segment, segment)
|
||||
else:
|
||||
label = _cant_label(prev_segment, segment)
|
||||
|
||||
return label
|
||||
+1
-1
@@ -380,7 +380,7 @@ def _map_viennese_bend(
|
||||
raise NotImplementedError("VIENNESEBEND not implemented")
|
||||
|
||||
|
||||
def map_alignment_cant_segment(
|
||||
def _map_alignment_cant_segment(
|
||||
file: ifcopenshell.file, segment: entity_instance, rail_head_distance: float
|
||||
) -> Sequence[entity_instance]:
|
||||
"""
|
||||
+1
-1
@@ -401,7 +401,7 @@ def _map_viennese_bend(file: ifcopenshell.file, design_parameters: entity_instan
|
||||
raise NotImplementedError("VIENNESEBEND not implemented")
|
||||
|
||||
|
||||
def map_alignment_horizontal_segment(file: ifcopenshell.file, segment: entity_instance) -> Sequence[entity_instance]:
|
||||
def __map_alignment_horizontal_segment(file: ifcopenshell.file, segment: entity_instance) -> Sequence[entity_instance]:
|
||||
"""
|
||||
Creates IfcCurveSegment entities for the represention of the supplied IfcAlignmentHorizontalSegment business logic entity instance.
|
||||
A pair of entities is returned because a single business logic segment of type HELMERTCURVE maps to two representaiton entities.
|
||||
+1
-1
@@ -189,7 +189,7 @@ def _map_clothoid(file: ifcopenshell.file, design_parameters: entity_instance) -
|
||||
raise NotImplementedError("mapping for IfcVerticalSegment.CLOTHOID not implemented")
|
||||
|
||||
|
||||
def map_alignment_vertical_segment(file: ifcopenshell.file, segment: entity_instance) -> Sequence[entity_instance]:
|
||||
def _map_alignment_vertical_segment(file: ifcopenshell.file, segment: entity_instance) -> Sequence[entity_instance]:
|
||||
"""
|
||||
Creates IfcCurveSegment entities for the represention of the supplied IfcAlignmentVerticalSegment business logic entity instance.
|
||||
A pair of entities is returned for consistency with map_alignment_horizontal_segment and map_alignment_cant_segment.
|
||||
+4
-4
@@ -25,7 +25,7 @@ import numpy as np
|
||||
import math
|
||||
|
||||
|
||||
def update_curve_segment_transition_code(prev_segment: entity_instance, segment: entity_instance) -> None:
|
||||
def _update_curve_segment_transition_code(prev_segment: entity_instance, segment: entity_instance) -> None:
|
||||
"""
|
||||
Updates IfcCurveSegment.Transition of prev_segment based on a comparison of
|
||||
the position, ref. direction, and curvature at the end of the prev_segment and the start of segment.
|
||||
@@ -62,9 +62,9 @@ def update_curve_segment_transition_code(prev_segment: entity_instance, segment:
|
||||
s = segment_evaluator.evaluate(segment_fn.start())
|
||||
start = np.array(s)
|
||||
|
||||
same_position = True if np.allclose(end[:3], start[:3]) else False
|
||||
same_gradient = True if np.allclose(end[:0], start[:0]) else False
|
||||
same_curvature = True if np.allclose(end[3:], start[3:]) else False
|
||||
same_position = True if np.allclose(end[:3, 3], start[:3, 3]) else False
|
||||
same_gradient = True if np.allclose(end[:3, 0], start[:3, 0]) else False
|
||||
same_curvature = True if np.allclose(end[3:, :3], start[3:, :3]) else False
|
||||
|
||||
if same_position:
|
||||
prev_segment.Transition = "CONTINUOUS"
|
||||
@@ -1,76 +0,0 @@
|
||||
# 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 ifcopenshell
|
||||
import ifcopenshell.api.alignment
|
||||
import ifcopenshell.geom
|
||||
from ifcopenshell import entity_instance
|
||||
|
||||
|
||||
def add_segment_to_curve(file: ifcopenshell.file, segment: entity_instance, composite_curve: entity_instance) -> None:
|
||||
"""
|
||||
Adds a segment to a composite curve. The segment must not belong to another composite curve (len(segment.UsingCurves) == 0).
|
||||
If the composite curve does not have any segments, the segment is simply appended to the curve.
|
||||
If the composite curve has segments, the position, ref. direction, and curvature at the end of the last segment is
|
||||
compared to the position, ref. direction and curvature at the start of the new segment. The IfcCurveSegment.Transition of the last curve segment is updated.
|
||||
|
||||
:param segment: The segment to be added to the curve
|
||||
:param composite_curve: The curve receiving the segment
|
||||
:return: None
|
||||
"""
|
||||
expected_type = "IfcCurveSegment"
|
||||
if not segment.is_a(expected_type):
|
||||
raise TypeError(f"Expected to see '{expected_type}', instead received '{segment.is_a()}'.")
|
||||
|
||||
if 0 < len(segment.UsingCurves):
|
||||
raise TypeError("IfcCurveSegment cannot belong to other curves")
|
||||
|
||||
expected_type = "IfcCompositeCurve"
|
||||
if not composite_curve.is_a(expected_type):
|
||||
raise TypeError(f"Expected to see '{expected_type}', instead received '{composite_curve.is_a()}'.")
|
||||
|
||||
settings = ifcopenshell.geom.settings()
|
||||
if composite_curve.Segments == None or 0 == len(composite_curve.Segments):
|
||||
# this is the first segment so just add it
|
||||
if composite_curve.Segments == None:
|
||||
composite_curve.Segments = []
|
||||
|
||||
# the last segment is always discontinuous
|
||||
segment.Transition = "DISCONTINUOUS"
|
||||
|
||||
composite_curve.Segments += (segment,)
|
||||
assert len(segment.UsingCurves) == 1
|
||||
else:
|
||||
zero_length_segment = (
|
||||
ifcopenshell.api.alignment.remove_zero_length_segment(file, composite_curve)
|
||||
if ifcopenshell.api.alignment.has_zero_length_segment(composite_curve)
|
||||
else None
|
||||
)
|
||||
|
||||
prev_segment = composite_curve.Segments[-1]
|
||||
|
||||
# the last segment is always discontinuous
|
||||
segment.Transition = "DISCONTINUOUS"
|
||||
|
||||
# must add the new segment to the curve before updating the transition code
|
||||
composite_curve.Segments += (segment,)
|
||||
|
||||
ifcopenshell.api.alignment.update_curve_segment_transition_code(prev_segment, segment)
|
||||
|
||||
if zero_length_segment:
|
||||
ifcopenshell.api.alignment.add_segment_to_curve(zero_length_segment, composite_curve)
|
||||
@@ -1,51 +0,0 @@
|
||||
# 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 ifcopenshell
|
||||
import ifcopenshell.api.alignment
|
||||
import ifcopenshell.api.nest
|
||||
from ifcopenshell import entity_instance
|
||||
|
||||
|
||||
def add_segment_to_layout(file: ifcopenshell.file, alignment: entity_instance, segment: entity_instance) -> None:
|
||||
"""
|
||||
Adds a segment to a layout alignment (horizontal, vertical, or cant)
|
||||
|
||||
:param alignment: The alignment
|
||||
:param segment: The segment to be appended
|
||||
:return: None
|
||||
"""
|
||||
expected_types = ["IfcAlignmentHorizontal", "IfcAlignmentVertical", "IfcAlignmentCant"]
|
||||
if not alignment.is_a() in expected_types:
|
||||
raise TypeError(
|
||||
f"Expected entity type to be one of {[_ for _ in expected_types]}, instead received '{alignment.is_a()}"
|
||||
)
|
||||
|
||||
if not (segment.is_a("IfcAlignmentSegment")):
|
||||
raise TypeError(f"Expected to see IfcAlignmentSegment, instead received '{segment.is_a()}.")
|
||||
|
||||
zero_length_segment = (
|
||||
ifcopenshell.api.alignment.remove_zero_length_segment(file, alignment)
|
||||
if ifcopenshell.api.alignment.has_zero_length_segment(alignment)
|
||||
else None
|
||||
)
|
||||
|
||||
ifcopenshell.api.nest.assign_object(file, related_objects=[segment], relating_object=alignment)
|
||||
|
||||
if zero_length_segment:
|
||||
ifcopenshell.api.nest.assign_object(file, related_objects=[zero_length_segment], relating_object=alignment)
|
||||
@@ -0,0 +1,137 @@
|
||||
# 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 ifcopenshell
|
||||
import ifcopenshell.api.alignment
|
||||
import ifcopenshell.api.nest
|
||||
import ifcopenshell.api.pset
|
||||
import ifcopenshell.util.stationing
|
||||
import ifcopenshell.guid
|
||||
from ifcopenshell import entity_instance
|
||||
from ifcopenshell import ifcopenshell_wrapper
|
||||
import numpy as np
|
||||
|
||||
|
||||
def add_stationing_referent(
|
||||
file: ifcopenshell.file,
|
||||
element: entity_instance,
|
||||
basis_curve: entity_instance,
|
||||
distance_along: float,
|
||||
station: float,
|
||||
name: str,
|
||||
) -> entity_instance:
|
||||
"""
|
||||
Adds an IfcReferent to the element with the Pset_Stationing property set.
|
||||
If element is an IfcAlignment, IfcReferent.PredefinedType is set to "STATION", otherwise "POSITION"
|
||||
|
||||
:param element: the element to receive the referent, expected to be an IfcAlignment or IfcAlignmentSegment
|
||||
:param basis_curve: the basis curve for positining
|
||||
:param distance_along: distance along the basis curve
|
||||
:param station: station value
|
||||
:param name: name to assign to IfcReferent.Name, typically a stringized version of the station value
|
||||
:return: referent
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
alignment = model.by_type("IfcAlignment")[0]
|
||||
basis_curve = ifcopenshell.api.alignment.get_basis_curve(alignment)
|
||||
ifcopenshell.api.alignment.add_stationing_referent(model,entity=alignment,basis_curve=basis_curve,distance_along=0.0,station=100.0)
|
||||
"""
|
||||
object_placement = None
|
||||
representation = None
|
||||
if basis_curve:
|
||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(file)
|
||||
|
||||
settings = ifcopenshell.geom.settings()
|
||||
fn = ifcopenshell_wrapper.map_shape(settings, basis_curve.wrapped_data)
|
||||
evaluator = ifcopenshell_wrapper.function_item_evaluator(settings, fn)
|
||||
p = evaluator.evaluate(distance_along * unit_scale)
|
||||
p = np.array(p)
|
||||
|
||||
x = float(p[0, 3]) / unit_scale
|
||||
y = float(p[1, 3]) / unit_scale
|
||||
z = float(p[2, 3]) / unit_scale
|
||||
|
||||
rx = float(p[0, 0])
|
||||
ry = float(p[1, 0])
|
||||
rz = float(p[2, 0])
|
||||
|
||||
ax = float(p[0, 2])
|
||||
ay = float(p[1, 2])
|
||||
az = float(p[2, 2])
|
||||
|
||||
object_placement = file.createIfcLinearPlacement(
|
||||
RelativePlacement=file.createIfcAxis2PlacementLinear(
|
||||
Location=file.createIfcPointByDistanceExpression(
|
||||
DistanceAlong=file.createIfcLengthMeasure(distance_along),
|
||||
OffsetLateral=None,
|
||||
OffsetVertical=None,
|
||||
OffsetLongitudinal=None,
|
||||
BasisCurve=basis_curve,
|
||||
)
|
||||
),
|
||||
CartesianPosition=file.createIfcAxis2Placement3D(
|
||||
Location=file.createIfcCartesianPoint(((x, y, z))),
|
||||
Axis=file.createIfcDirection((ax, ay, az)),
|
||||
RefDirection=file.createIfcDirection((rx, ry, rz)),
|
||||
),
|
||||
)
|
||||
# this commented out code is what you would do to add a geometric representation of the referent
|
||||
# the example is a circle. a better way would be to pass a representation into the function
|
||||
# representation = file.create_entity(
|
||||
# name="IfcCircle",
|
||||
# position=file.createIfcAxis2Placement2D(Location=file.createIfcCartesianPoint(Coordinates=(0.0, 0.0)),
|
||||
# radius=1.0)
|
||||
# )
|
||||
|
||||
# create referent for the station
|
||||
predefined_type = "STATION" if element.is_a("IfcAlignment") else "POSITION"
|
||||
referent = file.createIfcReferent(
|
||||
GlobalId=ifcopenshell.guid.new(),
|
||||
OwnerHistory=None,
|
||||
Name=name,
|
||||
Description=None,
|
||||
ObjectType=None,
|
||||
ObjectPlacement=object_placement,
|
||||
Representation=representation,
|
||||
PredefinedType=predefined_type,
|
||||
)
|
||||
pset_stationing = ifcopenshell.api.pset.add_pset(file, product=referent, name="Pset_Stationing")
|
||||
ifcopenshell.api.pset.edit_pset(file, pset=pset_stationing, properties={"Station": station})
|
||||
ifcopenshell.api.nest.assign_object(file, related_objects=[referent], relating_object=element)
|
||||
|
||||
alignment = element
|
||||
|
||||
if element.is_a("IfcAlignmentSegment"):
|
||||
layout = element.Nests[0].RelatingObject
|
||||
alignment = ifcopenshell.api.alignment.get_alignment(layout)
|
||||
|
||||
if len(alignment.Positions) == 0:
|
||||
rel_positions = file.createIfcRelPositions(
|
||||
GlobalId=ifcopenshell.guid.new(),
|
||||
RelatingPositioningElement=alignment,
|
||||
RelatedProducts=[
|
||||
referent,
|
||||
],
|
||||
)
|
||||
else:
|
||||
alignment.Positions[0].RelatedProducts += (referent,)
|
||||
|
||||
return referent
|
||||
@@ -1,83 +0,0 @@
|
||||
# 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 ifcopenshell
|
||||
import ifcopenshell.api.alignment
|
||||
import ifcopenshell.api.nest
|
||||
import ifcopenshell.api.pset
|
||||
import ifcopenshell.util.stationing
|
||||
import ifcopenshell.guid
|
||||
from ifcopenshell import entity_instance
|
||||
|
||||
|
||||
def add_stationing_to_alignment(
|
||||
file: ifcopenshell.file, alignment: entity_instance, start_station: float, plus_seperator=3, accuracy=3
|
||||
) -> None:
|
||||
"""
|
||||
Adds stationing to an alignment by creating an IfcReferent with the Pset_Stationing property set to establish the stationing at the start of the alignment.
|
||||
Note - this function assumes the stationing has not been previously defined
|
||||
|
||||
:param alignment: the alignment to be stationed
|
||||
:param start_station: station value at the start of the alignment
|
||||
:return: None
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
alignment = model.by_type("IfcAlignment")[0]
|
||||
ifcopenshell.api.alignment.add_stationing_to_alignment(model,alignment=alignment,start_station=100.0)
|
||||
"""
|
||||
# this commented out code is what you would do to add a geometric representation of the referent
|
||||
# the example is a circle. a better way would be to pass a representation into the function
|
||||
object_placement = None
|
||||
representation = None
|
||||
basis_curve = ifcopenshell.api.alignment.get_basis_curve(alignment)
|
||||
if basis_curve:
|
||||
object_placement = file.createIfcLinearPlacement(
|
||||
RelativePlacement=file.createIfcAxis2PlacementLinear(
|
||||
Location=file.createIfcPointByDistanceExpression(
|
||||
DistanceAlong=file.createIfcLengthMeasure(0.0),
|
||||
OffsetLateral=None,
|
||||
OffsetVertical=None,
|
||||
OffsetLongitudinal=None,
|
||||
BasisCurve=basis_curve,
|
||||
)
|
||||
),
|
||||
CartesianPosition=None,
|
||||
)
|
||||
# representation = file.create_entity(
|
||||
# name="IfcCircle",
|
||||
# position=file.createIfcAxis2Placement2D(Location=file.createIfcCartesianPoint(Coordinates=(0.0, 0.0)),
|
||||
# radius=1.0)
|
||||
# )
|
||||
|
||||
# create referent for start station
|
||||
start_referent = file.createIfcReferent(
|
||||
GlobalId=ifcopenshell.guid.new(),
|
||||
OwnerHistory=None,
|
||||
Name=ifcopenshell.util.stationing.station_as_string(start_station, plus_seperator, accuracy),
|
||||
Description=None,
|
||||
ObjectType=None,
|
||||
ObjectPlacement=object_placement,
|
||||
Representation=representation,
|
||||
PredefinedType="STATION",
|
||||
)
|
||||
pset_stationing = ifcopenshell.api.pset.add_pset(file, product=start_referent, name="Pset_Stationing")
|
||||
ifcopenshell.api.pset.edit_pset(file, pset=pset_stationing, properties={"Station": start_station})
|
||||
ifcopenshell.api.nest.assign_object(file, related_objects=[start_referent], relating_object=alignment)
|
||||
@@ -1,199 +0,0 @@
|
||||
# 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 ifcopenshell
|
||||
import ifcopenshell.api.aggregate
|
||||
import ifcopenshell.api.alignment
|
||||
import ifcopenshell.api.geometry
|
||||
import ifcopenshell.api.nest
|
||||
import ifcopenshell.api.root
|
||||
import ifcopenshell.guid
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.representation
|
||||
import ifcopenshell.util.stationing
|
||||
import ifcopenshell.api
|
||||
from ifcopenshell import entity_instance
|
||||
|
||||
|
||||
def _move_vertical_to_child_alignment(
|
||||
file: ifcopenshell.file, parent_alignment: entity_instance, vertical_alignment: entity_instance
|
||||
):
|
||||
"""
|
||||
Creates a new child alignment and aggregates it to the parent alignment. Moves the vertical alignment from the parent
|
||||
alignment to the child alignment. Also moves the "Axis/Curve3D" representation to the child alignment, if present.
|
||||
This function supports the transition of vertical alignment between CT 4.1.4.4.1.1 and 4.1.4.4.1.2 because a subsequent
|
||||
vertical alignment is being added and the Alignment Layout - Reusing Horizontal Layout concept applies.
|
||||
"""
|
||||
# unhook the vertical alignment from the parent alignment
|
||||
ifcopenshell.api.nest.unassign_object(file, related_objects=[vertical_alignment])
|
||||
|
||||
# create the child alignment
|
||||
child_alignment = ifcopenshell.api.root.create_entity(
|
||||
file, ifc_class="IfcAlignment", name=f"Child of {parent_alignment.Name}"
|
||||
)
|
||||
|
||||
# nest the vertical alignment onto the child alignment
|
||||
ifcopenshell.api.nest.assign_object(file, related_objects=[vertical_alignment], relating_object=child_alignment)
|
||||
|
||||
# aggreage the child alignment to the parent alignment
|
||||
ifcopenshell.api.aggregate.assign_object(file, products=[child_alignment], relating_object=parent_alignment)
|
||||
|
||||
# if the parent alignment has a representation, move the Axis/Curve3D represention to the child alignment
|
||||
base_curve = ifcopenshell.api.alignment.get_basis_curve(parent_alignment)
|
||||
if base_curve:
|
||||
representations = ifcopenshell.util.representation.get_representations_iter(parent_alignment)
|
||||
for representation in representations:
|
||||
if representation.RepresentationIdentifier == "Axis" and representation.RepresentationType == "Curve3D":
|
||||
ifcopenshell.api.geometry.unassign_representation(file, parent_alignment, representation)
|
||||
ifcopenshell.api.geometry.assign_representation(file, child_alignment, representation)
|
||||
break
|
||||
|
||||
|
||||
def add_vertical_alignment(
|
||||
file: ifcopenshell.file, parent_alignment: entity_instance, vertical_alignment: entity_instance
|
||||
) -> None:
|
||||
"""
|
||||
Adds a vertical alignment to a previously created alignment.
|
||||
|
||||
If this is the first vertical alignment assigned to the parent_alignment the IFC CT 4.1.4.4.1.1 Alignment Layout - Horizontal, Vertical and Cant
|
||||
is followed. If this is the second or subsequent vertical alignment assigned to the parent_alignment the
|
||||
IFC CT 4.1.4.4.1.2 Alignment Layout - Reusing Horizontal Layout is followed.
|
||||
|
||||
When the second vertical alignment is added, the structure of the IFC model must transition from one concept template to the other.
|
||||
Specifically, the following occurs:
|
||||
|
||||
1) The first child IfcAlignment is created and is IfcRelAggregates with the parent alignment.
|
||||
2) The first vertical alignment is unassigned from the IfcRelNests of the parent alignment and assigned to the new child alignment IfcRelNests
|
||||
3) A second child IfcAlignment is created ant is is IfcRelAggregates with the parent alignment.
|
||||
4) The vertical_alignment is assigned to the second child alignment
|
||||
|
||||
For the third and subsequent vertical alignments, a new child alignment is created and aggregated to the parent alignment and an IfcAlignmentVertical is created
|
||||
from vpoints and lengths and assigned to the new child alignment.
|
||||
|
||||
If the parent_alignment has a geometric representation, a geometric representation will be created for the vertical alignment.
|
||||
|
||||
:param parent_alignment: The parent alignment
|
||||
:param vertical_alignment: The vertical alignment to be added
|
||||
:return: None
|
||||
"""
|
||||
|
||||
# get all the child alignments under alignment
|
||||
child_alignments = [
|
||||
c for c in ifcopenshell.util.element.get_decomposition(parent_alignment) if c.is_a("IfcAlignment")
|
||||
]
|
||||
|
||||
# Get all the IfcAlignmentVertical that are nesting alignment (there should be 0 or 1)
|
||||
# if 0, alignment is just horizontal and we are adding the first vertical so it will nest to the alignment,
|
||||
# or there are multiple vertical and they nest to the aggregated child alignments
|
||||
# if 1, there is one vertical alignments. Move it to a child alignment
|
||||
vertical_alignments_nesting_alignment = [
|
||||
c for c in ifcopenshell.util.element.get_components(parent_alignment) if c.is_a("IfcAlignmentVertical")
|
||||
]
|
||||
|
||||
# move the vertical alignment to a child alignment because there is going to be more than one vertical
|
||||
assert len(vertical_alignments_nesting_alignment) == 0 or len(vertical_alignments_nesting_alignment) == 1
|
||||
for vertical_alignment_nesting_alignment in vertical_alignments_nesting_alignment:
|
||||
_move_vertical_to_child_alignment(file, parent_alignment, vertical_alignment_nesting_alignment)
|
||||
|
||||
if len(child_alignments) == 0 and len(vertical_alignments_nesting_alignment) == 0:
|
||||
# this is the first vertical alignment so nest it into the parent alignment (IFC CT 4.1.4.4.1.1)
|
||||
ifcopenshell.api.nest.assign_object(
|
||||
file, related_objects=[vertical_alignment], relating_object=parent_alignment
|
||||
)
|
||||
|
||||
base_curve = ifcopenshell.api.alignment.get_basis_curve(parent_alignment)
|
||||
if base_curve:
|
||||
# the parent alignment has a Representation so create a representation for the vertical
|
||||
gradient_curve = file.create_entity(
|
||||
type="IfcGradientCurve", Segments=[], SelfIntersect=False, BaseCurve=base_curve, EndPoint=None
|
||||
)
|
||||
|
||||
# using the business logic definition of vertical_alignment, create the curve segments and assign to gradient_curve
|
||||
ifcopenshell.api.alignment.map_alignment_segments(file, vertical_alignment, gradient_curve)
|
||||
|
||||
# Per IFC CT 4.1.7.1.1.1, the shape representation for Horizontal geometry only is
|
||||
# RepresentationIdentifier="Axis" and RepresentationType="Curve2D".
|
||||
# However, per IFC CT 4.1.7.1.1.2 and 3 the shape represenation with Horizontal, Vertical and Cant
|
||||
# is RepresentationIdentifier="FootPrint" and RepresentationType="Curve2D" for the horizontal and
|
||||
# RepresentationIdentifier="Axis" and RepresentationType="Curve3D" for the 2.5D curve.
|
||||
# Since the alignment is transitioning from horizontal only to horizontal+vertical, the
|
||||
# RepresentationIdentifier must change from "Axis" to "FootPrint"
|
||||
representations = ifcopenshell.util.representation.get_representations_iter(parent_alignment)
|
||||
for representation in representations:
|
||||
if representation.RepresentationIdentifier == "Axis" and representation.RepresentationType == "Curve2D":
|
||||
representation.RepresentationIdentifier = "FootPrint"
|
||||
break
|
||||
|
||||
# create the Axis,Curve3D representation
|
||||
axis_geom_subcontext = ifcopenshell.api.alignment.get_axis_subcontext(file)
|
||||
axis3d_shape_representation = file.create_entity(
|
||||
type="IfcShapeRepresentation",
|
||||
ContextOfItems=axis_geom_subcontext,
|
||||
RepresentationIdentifier="Axis",
|
||||
RepresentationType="Curve3D",
|
||||
Items=(gradient_curve,),
|
||||
)
|
||||
|
||||
ifcopenshell.api.geometry.assign_representation(file, parent_alignment, axis3d_shape_representation)
|
||||
else:
|
||||
# there are multiple vertical reusing the horizontal (IFC CT 4.1.4.4.1.2)
|
||||
# this is the second or subsequent vertical reusing the horizontal
|
||||
|
||||
# create a new child alignment for the new vertical
|
||||
child_alignment = file.create_entity(
|
||||
type="IfcAlignment",
|
||||
GlobalId=ifcopenshell.guid.new(),
|
||||
OwnerHistory=None,
|
||||
Name=f"Child of {parent_alignment.Name}",
|
||||
Description=None,
|
||||
ObjectType=None,
|
||||
ObjectPlacement=None,
|
||||
Representation=None,
|
||||
PredefinedType=None,
|
||||
)
|
||||
|
||||
# Aggregate the child alignment to the parent alignment
|
||||
ifcopenshell.api.aggregate.assign_object(file, (child_alignment,), parent_alignment)
|
||||
|
||||
# nest the vertical under the child alignment
|
||||
ifcopenshell.api.nest.assign_object(file, related_objects=[vertical_alignment], relating_object=child_alignment)
|
||||
|
||||
base_curve = ifcopenshell.api.alignment.get_basis_curve(parent_alignment)
|
||||
if base_curve:
|
||||
child_alignment.ObjectPlacement = parent_alignment.ObjectPlacement
|
||||
|
||||
# the parent alignment has a Representation so create a representation for the vertical
|
||||
gradient_curve = file.create_entity(
|
||||
type="IfcGradientCurve", Segments=[], SelfIntersect=False, BaseCurve=base_curve, EndPoint=None
|
||||
)
|
||||
|
||||
ifcopenshell.api.alignment.map_alignment_segments(file, vertical_alignment, gradient_curve)
|
||||
|
||||
axis_geom_subcontext = ifcopenshell.api.alignment.get_axis_subcontext(file)
|
||||
|
||||
# create the Curve3D representation
|
||||
axis3d_shape_representation = file.create_entity(
|
||||
type="IfcShapeRepresentation",
|
||||
ContextOfItems=axis_geom_subcontext,
|
||||
RepresentationIdentifier="Axis",
|
||||
RepresentationType="Curve3D",
|
||||
Items=(gradient_curve,),
|
||||
)
|
||||
|
||||
# add the representation to the child alignment
|
||||
ifcopenshell.api.geometry.assign_representation(file, child_alignment, axis3d_shape_representation)
|
||||
-59
@@ -1,59 +0,0 @@
|
||||
# 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 ifcopenshell
|
||||
import ifcopenshell.api.alignment.add_vertical_alignment
|
||||
from ifcopenshell import entity_instance
|
||||
from collections.abc import Sequence
|
||||
|
||||
|
||||
def add_vertical_alignment_by_pi_method(
|
||||
file: ifcopenshell.file,
|
||||
parent_alignment: entity_instance,
|
||||
vpoints: Sequence[Sequence[float]],
|
||||
lengths: Sequence[float],
|
||||
) -> None:
|
||||
"""
|
||||
Adds a vertical alignment to a previously created alignment using the PI method.
|
||||
|
||||
If this is the first vertical alignment assigned to the parent_alignment the IFC CT 4.1.4.4.1.1 Alignment Layout - Horizontal, Vertical and Cant
|
||||
is followed. If this is the second or subsequent vertical alignment assigned to the parent_alignment the
|
||||
IFC CT 4.1.4.4.1.2 Alignment Layout - Reusing Horizontal Layout is followed.
|
||||
|
||||
When the second vertical alignment is added, the structure of the IFC model must transition from one concept template to the other.
|
||||
Specifically, the following occurs:
|
||||
|
||||
1) The first child IfcAlignment is created and is IfcRelAggregates with the parent alignment.
|
||||
2) The first vertical alignment is unassigned from the IfcRelNests of the parent alignment and assigned to the new child alignment IfcRelNests
|
||||
3) A second child IfcAlignment is created and it is IfcRelAggregates with the parent alignment.
|
||||
4) An IfcAlignmentVertical is created from vpoints and lengths and it is assigned to the second child alignment
|
||||
|
||||
For the third and subsequent vertical alignments, a new child alignment is created and aggregated to the parent alignment and an IfcAlignmentVertical is created
|
||||
from vpoints and lengths and assigned to the new child alignment.
|
||||
|
||||
If the parent_alignment has a geometric representation, a geometric representation will be created for the vertical alignment.
|
||||
|
||||
:param parent_alignment: The parent alignment
|
||||
:param vpoints: A sequence of (D,Z) points where D is distance along horizontal and Z is elevation
|
||||
:param: lengths: Lengths of parabolic vertical curves occuring at each VPI
|
||||
:return: None
|
||||
"""
|
||||
vertical_alignment = ifcopenshell.api.alignment.create_vertical_alignment_by_pi_method(
|
||||
file, parent_alignment.Name, vpoints, lengths
|
||||
)
|
||||
ifcopenshell.api.alignment.add_vertical_alignment(file, parent_alignment, vertical_alignment)
|
||||
@@ -0,0 +1,192 @@
|
||||
# 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 ifcopenshell
|
||||
import ifcopenshell.api.aggregate
|
||||
import ifcopenshell.api.alignment
|
||||
import ifcopenshell.api.geometry
|
||||
import ifcopenshell.api.nest
|
||||
import ifcopenshell.guid
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.representation
|
||||
import ifcopenshell.api
|
||||
from ifcopenshell import entity_instance
|
||||
|
||||
from ifcopenshell.api.alignment._add_zero_length_segment import _add_zero_length_segment
|
||||
|
||||
|
||||
def _move_vertical_layout_to_child_alignment(
|
||||
file: ifcopenshell.file, parent_alignment: entity_instance, vertical_layout: entity_instance
|
||||
):
|
||||
"""
|
||||
Creates a new child alignment and aggregates it to the parent alignment. Moves the vertical alignment from the parent
|
||||
alignment to the child alignment. Also moves the "Axis/Curve3D" representation to the child alignment, if present.
|
||||
This function supports the transition of vertical alignment between CT 4.1.4.4.1.1 and 4.1.4.4.1.2 because a subsequent
|
||||
vertical alignment is being added and the Alignment Layout - Reusing Horizontal Layout concept applies.
|
||||
"""
|
||||
# unhook the vertical layout from the parent alignment
|
||||
ifcopenshell.api.nest.unassign_object(file, related_objects=[vertical_layout])
|
||||
|
||||
# create the child alignment
|
||||
child_alignment = file.createIfcAlignment(
|
||||
GlobalId=ifcopenshell.guid.new(), Name=f"Child of {parent_alignment.Name}"
|
||||
)
|
||||
|
||||
# nest the vertical layout onto the child alignment
|
||||
ifcopenshell.api.nest.assign_object(file, related_objects=[vertical_layout], relating_object=child_alignment)
|
||||
|
||||
# aggreage the child alignment to the parent alignment
|
||||
ifcopenshell.api.aggregate.assign_object(file, products=[child_alignment], relating_object=parent_alignment)
|
||||
|
||||
# if the parent alignment has a representation, move the Axis/Curve3D represention to the child alignment
|
||||
base_curve = ifcopenshell.api.alignment.get_basis_curve(parent_alignment)
|
||||
if base_curve:
|
||||
representations = ifcopenshell.util.representation.get_representations_iter(parent_alignment)
|
||||
for representation in representations:
|
||||
if representation.RepresentationIdentifier == "Axis" and representation.RepresentationType == "Curve3D":
|
||||
ifcopenshell.api.geometry.unassign_representation(file, parent_alignment, representation)
|
||||
ifcopenshell.api.geometry.assign_representation(file, child_alignment, representation)
|
||||
break
|
||||
|
||||
|
||||
def add_vertical_layout(file: ifcopenshell.file, parent_alignment: entity_instance) -> entity_instance:
|
||||
"""
|
||||
Adds a vertical layout to a previously created alignment.
|
||||
|
||||
If this is the first vertical layout assigned to the parent_alignment the IFC CT 4.1.4.4.1.1 Alignment Layout - Horizontal, Vertical and Cant
|
||||
is followed. If this is the second or subsequent vertical layout assigned to the parent_alignment the
|
||||
IFC CT 4.1.4.4.1.2 Alignment Layout - Reusing Horizontal Layout is followed.
|
||||
|
||||
When the second vertical layout is added, the structure of the IFC model must transition from one concept template to the other.
|
||||
Specifically, the following occurs:
|
||||
|
||||
1) The first child IfcAlignment is created and is IfcRelAggregates with the parent alignment.
|
||||
2) The first vertical layout is unassigned from the IfcRelNests of the parent alignment and is IfcRelNests to the new child alignment.
|
||||
3) A second child IfcAlignment is created and it is IfcRelAggregates with the parent alignment.
|
||||
4) The vertical layout is IfcRelNests to the second child alignment
|
||||
|
||||
For the third and subsequent vertical layouts, a new child alignment is created and aggregated to the parent alignment.
|
||||
|
||||
A zero segment length terminated IfcGradientCurve is created for the new vertical layout
|
||||
|
||||
:param parent_alignment: The parent alignment
|
||||
:return: The new vertical layout, including the manditory zero length segment
|
||||
"""
|
||||
|
||||
vertical_layout = file.createIfcAlignmentVertical(GlobalId=ifcopenshell.guid.new())
|
||||
|
||||
# get all the child alignments under alignment
|
||||
child_alignments = [
|
||||
c for c in ifcopenshell.util.element.get_decomposition(parent_alignment) if c.is_a("IfcAlignment")
|
||||
]
|
||||
|
||||
# Get all the IfcAlignmentVertical that are nesting alignment (there should be 0 or 1)
|
||||
# if 0, alignment is just horizontal and we are adding the first vertical so it will nest to the alignment,
|
||||
# or there are multiple vertical and they nest to the aggregated child alignments
|
||||
# if 1, there is one vertical alignments. Move it to a child alignment
|
||||
vertical_layouts_nesting_alignment = [
|
||||
c for c in ifcopenshell.util.element.get_components(parent_alignment) if c.is_a("IfcAlignmentVertical")
|
||||
]
|
||||
|
||||
# move the vertical layout to a child alignment because there is going to be more than one vertical
|
||||
assert len(vertical_layouts_nesting_alignment) == 0 or len(vertical_layouts_nesting_alignment) == 1
|
||||
for vertical_layout_nesting_alignment in vertical_layouts_nesting_alignment:
|
||||
_move_vertical_layout_to_child_alignment(file, parent_alignment, vertical_layout_nesting_alignment)
|
||||
|
||||
if len(child_alignments) == 0 and len(vertical_layouts_nesting_alignment) == 0:
|
||||
# this is the first vertical layout so nest it into the parent alignment (IFC CT 4.1.4.4.1.1)
|
||||
ifcopenshell.api.nest.assign_object(file, related_objects=[vertical_layout], relating_object=parent_alignment)
|
||||
|
||||
base_curve = ifcopenshell.api.alignment.get_basis_curve(parent_alignment)
|
||||
|
||||
# the parent alignment has a Representation so create a representation for the vertical
|
||||
gradient_curve = file.createIfcGradientCurve(
|
||||
Segments=[], SelfIntersect=False, BaseCurve=base_curve, EndPoint=None
|
||||
)
|
||||
|
||||
# Per IFC CT 4.1.7.1.1.1, the shape representation for Horizontal geometry only is
|
||||
# RepresentationIdentifier="Axis" and RepresentationType="Curve2D".
|
||||
# However, per IFC CT 4.1.7.1.1.2 and 3 the shape represenation with Horizontal, Vertical and Cant
|
||||
# is RepresentationIdentifier="FootPrint" and RepresentationType="Curve2D" for the horizontal and
|
||||
# RepresentationIdentifier="Axis" and RepresentationType="Curve3D" for the 2.5D curve.
|
||||
# Since the alignment is transitioning from horizontal only to horizontal+vertical, the
|
||||
# RepresentationIdentifier must change from "Axis" to "FootPrint"
|
||||
representations = ifcopenshell.util.representation.get_representations_iter(parent_alignment)
|
||||
for representation in representations:
|
||||
if representation.RepresentationIdentifier == "Axis" and representation.RepresentationType == "Curve2D":
|
||||
representation.RepresentationIdentifier = "FootPrint"
|
||||
break
|
||||
|
||||
# create the Axis,Curve3D representation
|
||||
axis_geom_subcontext = ifcopenshell.api.alignment.get_axis_subcontext(file)
|
||||
axis3d_shape_representation = file.createIfcShapeRepresentation(
|
||||
ContextOfItems=axis_geom_subcontext,
|
||||
RepresentationIdentifier="Axis",
|
||||
RepresentationType="Curve3D",
|
||||
Items=(gradient_curve,),
|
||||
)
|
||||
|
||||
ifcopenshell.api.geometry.assign_representation(file, parent_alignment, axis3d_shape_representation)
|
||||
else:
|
||||
# there are multiple vertical reusing the horizontal (IFC CT 4.1.4.4.1.2)
|
||||
# this is the second or subsequent vertical reusing the horizontal
|
||||
|
||||
# create a new child alignment for the new vertical
|
||||
child_alignment = file.createIfcAlignment(
|
||||
GlobalId=ifcopenshell.guid.new(),
|
||||
OwnerHistory=None,
|
||||
Name=f"Child of {parent_alignment.Name}",
|
||||
Description=None,
|
||||
ObjectType=None,
|
||||
ObjectPlacement=None,
|
||||
Representation=None,
|
||||
PredefinedType=None,
|
||||
)
|
||||
|
||||
# Aggregate the child alignment to the parent alignment
|
||||
ifcopenshell.api.aggregate.assign_object(file, (child_alignment,), parent_alignment)
|
||||
|
||||
# nest the vertical under the child alignment
|
||||
ifcopenshell.api.nest.assign_object(file, related_objects=[vertical_layout], relating_object=child_alignment)
|
||||
|
||||
child_alignment.ObjectPlacement = parent_alignment.ObjectPlacement
|
||||
|
||||
# the parent alignment has a Representation so create a representation for the vertical
|
||||
base_curve = ifcopenshell.api.alignment.get_basis_curve(parent_alignment)
|
||||
gradient_curve = file.createIfcGradientCurve(
|
||||
Segments=[], SelfIntersect=False, BaseCurve=base_curve, EndPoint=None
|
||||
)
|
||||
|
||||
axis_geom_subcontext = ifcopenshell.api.alignment.get_axis_subcontext(file)
|
||||
|
||||
# create the Curve3D representation
|
||||
axis3d_shape_representation = file.createIfcShapeRepresentation(
|
||||
ContextOfItems=axis_geom_subcontext,
|
||||
RepresentationIdentifier="Axis",
|
||||
RepresentationType="Curve3D",
|
||||
Items=(gradient_curve,),
|
||||
)
|
||||
|
||||
# add the representation to the child alignment
|
||||
ifcopenshell.api.geometry.assign_representation(file, child_alignment, axis3d_shape_representation)
|
||||
|
||||
# All alignment layouts must end with a zero length segment. Their geometric representations must also end with a zero length segment.
|
||||
# Now that all the geometry is setup, add the zero length segment to the layout, which also adds a zero length segment to the representation
|
||||
_add_zero_length_segment(file, vertical_layout)
|
||||
|
||||
return vertical_layout
|
||||
@@ -1,154 +0,0 @@
|
||||
# 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 ifcopenshell
|
||||
import ifcopenshell.api.alignment
|
||||
import ifcopenshell.api.nest
|
||||
import ifcopenshell.geom
|
||||
import ifcopenshell.ifcopenshell_wrapper as ifcopenshell_wrapper
|
||||
import numpy as np
|
||||
from ifcopenshell import entity_instance
|
||||
|
||||
|
||||
def add_zero_length_segment(file: ifcopenshell.file, entity: entity_instance) -> None:
|
||||
"""
|
||||
Adds a zero length segment to the end of entity.
|
||||
|
||||
:param entity: An IfcAlignmentHorizontal, IfcAlignmentVertical, IfcAlignmentCant or IfcCompositeCurve (or subtype)
|
||||
:return: None
|
||||
"""
|
||||
expected_types = [
|
||||
"IfcAlignmentHorizontal",
|
||||
"IfcAlignmentVertical",
|
||||
"IfcAlignmentCant",
|
||||
"IfcCompositeCurve",
|
||||
"IfcGradientCurve",
|
||||
"IfcSegmentedReferenceCurve",
|
||||
]
|
||||
if not entity.is_a() in expected_types:
|
||||
raise TypeError(
|
||||
f"Expected entity type to be one of {[_ for _ in expected_types]}, instead received '{entity.is_a()}"
|
||||
)
|
||||
|
||||
if ifcopenshell.api.alignment.has_zero_length_segment(entity):
|
||||
return # do nothing if the entity already has a zero length segment
|
||||
|
||||
if entity.is_a("IfcCompositeCurve"):
|
||||
last_segment = entity.Segments[-1]
|
||||
settings = ifcopenshell.geom.settings()
|
||||
segment_fn = ifcopenshell_wrapper.map_shape(settings, last_segment.wrapped_data)
|
||||
segment_evaluator = ifcopenshell_wrapper.function_item_evaluator(settings, segment_fn)
|
||||
e = segment_evaluator.evaluate(segment_fn.end())
|
||||
end = np.array(e)
|
||||
x = float(end[0, 3])
|
||||
y = float(end[1, 3])
|
||||
dx = float(end[0, 0])
|
||||
dy = float(end[1, 0])
|
||||
|
||||
parent_curve = file.createIfcLine(
|
||||
Pnt=file.createIfcCartesianPoint(Coordinates=((0.0, 0.0))),
|
||||
Dir=file.createIfcVector(
|
||||
Orientation=file.createIfcDirection(DirectionRatios=((1.0, 0.0))),
|
||||
Magnitude=1.0,
|
||||
),
|
||||
)
|
||||
curve_segment = file.createIfcCurveSegment(
|
||||
Transition="DISCONTINUOUS",
|
||||
Placement=file.createIfcAxis2Placement2D(
|
||||
Location=file.createIfcCartesianPoint((x, y)),
|
||||
RefDirection=file.createIfcDirection((dx, dy)),
|
||||
),
|
||||
SegmentStart=file.createIfcLengthMeasure(0.0),
|
||||
SegmentLength=file.createIfcLengthMeasure(0.0),
|
||||
ParentCurve=parent_curve,
|
||||
)
|
||||
ifcopenshell.api.alignment.add_segment_to_curve(file, curve_segment, entity)
|
||||
else:
|
||||
for rel in entity.IsNestedBy:
|
||||
if 0 < len(rel.RelatedObjects):
|
||||
last_segment = rel.RelatedObjects[-1]
|
||||
if last_segment.is_a("IfcAlignmentSegment"):
|
||||
if entity.is_a("IfcAlignmentHorizontal"):
|
||||
design_parameters = file.createIfcAlignmentHorizontalSegment(
|
||||
StartPoint=file.createIfcCartesianPoint(
|
||||
(0.0, 0.0)
|
||||
), # this is a little problematic. need to know the end point and tangent
|
||||
StartDirection=0.0, # of the previous segment, which requires geometry mapping
|
||||
SegmentLength=0.0,
|
||||
PredefinedType="LINE",
|
||||
)
|
||||
segment = file.createIfcAlignmentSegment(
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
ifcopenshell.api.nest.assign_object(
|
||||
file,
|
||||
related_objects=[
|
||||
segment,
|
||||
],
|
||||
relating_object=entity,
|
||||
)
|
||||
break
|
||||
elif entity.is_a("IfcAlignmentVertical"):
|
||||
design_parameters = file.createIfcAlignmentVerticalSegment(
|
||||
StartDistAlong=last_segment.DesignParameters.StartDistAlong
|
||||
+ last_segment.DesignParameters.HorizontalLength,
|
||||
HorizontalLength=0.0,
|
||||
StartHeight=0.0,
|
||||
StartGradient=last_segment.DesignParameters.EndGradient,
|
||||
EndGradient=last_segment.DesignParameters.EndGradient,
|
||||
PredefinedType="CONSTANTGRADIENT",
|
||||
)
|
||||
segment = file.createIfcAlignmentSegment(
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
ifcopenshell.api.nest.assign_object(
|
||||
file,
|
||||
related_objects=[
|
||||
segment,
|
||||
],
|
||||
relating_object=entity,
|
||||
)
|
||||
break
|
||||
elif entity.is_a("IfcAlignmentCant"):
|
||||
design_parameters = file.createIfcAlignmentCantSegment(
|
||||
StartDistAlong=last_segment.DesignParameters.StartDistAlong
|
||||
+ last_segment.DesignParameters.HorizontalLength,
|
||||
HorizontalLength=0.0,
|
||||
StartCantLeft=(
|
||||
last_segment.DesignParameters.EndCantLeft
|
||||
if last_segment.DesignParameters.EndCantLeft != None
|
||||
else last_segment.DesignParameters.StartCantLeft
|
||||
),
|
||||
StartCantRight=(
|
||||
last_segment.DesignParameters.EndCantRight
|
||||
if last_segment.DesignParameters.EndCantRight != None
|
||||
else last_segment.DesignParameters.StartCantRight
|
||||
),
|
||||
PredefinedType="CONSTANTCANT",
|
||||
)
|
||||
segment = file.createIfcAlignmentSegment(
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
ifcopenshell.api.nest.assign_object(
|
||||
file,
|
||||
related_objects=[
|
||||
segment,
|
||||
],
|
||||
relating_object=entity,
|
||||
)
|
||||
break
|
||||
@@ -0,0 +1,87 @@
|
||||
# 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 ifcopenshell
|
||||
import ifcopenshell.api.alignment
|
||||
from ifcopenshell import entity_instance
|
||||
|
||||
from ifcopenshell.api.alignment._create_geometric_representation import _create_geometric_representation
|
||||
from ifcopenshell.api.alignment._add_zero_length_segment import _add_zero_length_segment
|
||||
|
||||
|
||||
def create(
|
||||
file: ifcopenshell.file,
|
||||
name: str,
|
||||
include_vertical: bool = False,
|
||||
include_cant: bool = False,
|
||||
start_station: float = 0.0,
|
||||
) -> entity_instance:
|
||||
"""
|
||||
Creates a new IfcAlignment with an IfcRelNests nesting an IfcReferent (for stationing) and IfcAlignmentHorizontal. The nest relationship can optionally
|
||||
include IfcAlignmentVertical and IfcAlignmentCant. Geometric representations for the alignment layouts (IfcCompositeCurve,
|
||||
IfcGradientCurve, IfcSegmentedReferenceCurve) are created as well.
|
||||
|
||||
Zero length segments are added at the end.
|
||||
|
||||
The IfcAlignment is aggreated to IfcProject
|
||||
|
||||
Use get_horizontal_layout(alignment) to get the IfcAlignmentHorizontal layout.
|
||||
|
||||
:param file:
|
||||
:param name: name assigned to IfcAlignment.Name
|
||||
:param include_vertical: If True, IfcAlignmentVertical and IfcGradientCurve are created
|
||||
:param include_cant: If True, IfcAlignmentCant and IfcSegmentedReferenceCurve are created
|
||||
:param start_station: station value at the start of the alignment
|
||||
:return: Returns an IfcAlignment
|
||||
"""
|
||||
alignment = file.createIfcAlignment(
|
||||
GlobalId=ifcopenshell.guid.new(),
|
||||
Name=name,
|
||||
)
|
||||
|
||||
alignment_layouts = []
|
||||
|
||||
alignment_layouts.append(file.createIfcAlignmentHorizontal(GlobalId=ifcopenshell.guid.new()))
|
||||
|
||||
if include_vertical:
|
||||
alignment_layouts.append(file.createIfcAlignmentVertical(GlobalId=ifcopenshell.guid.new()))
|
||||
|
||||
if include_cant:
|
||||
alignment_layouts.append(file.createIfcAlignmentCant(GlobalId=ifcopenshell.guid.new(), RailHeadDistance=1.0))
|
||||
|
||||
ifcopenshell.api.nest.assign_object(file, related_objects=alignment_layouts, relating_object=alignment)
|
||||
|
||||
_create_geometric_representation(file, alignment)
|
||||
|
||||
for layout in alignment_layouts:
|
||||
_add_zero_length_segment(file, layout)
|
||||
|
||||
# define stationing
|
||||
basis_curve = ifcopenshell.api.alignment.get_basis_curve(alignment)
|
||||
name = ifcopenshell.util.stationing.station_as_string(file, start_station)
|
||||
referent = ifcopenshell.api.alignment.add_stationing_referent(
|
||||
file, alignment, basis_curve, 0.0, start_station, name
|
||||
)
|
||||
ifcopenshell.api.nest.reorder_nesting(file, referent, -1, 0)
|
||||
|
||||
# IFC 4.1.4.1.1 Alignment Aggregation To Project
|
||||
project = file.by_type("IfcProject")[0]
|
||||
if project:
|
||||
ifcopenshell.api.aggregate.assign_object(file, products=[alignment], relating_object=project)
|
||||
|
||||
return alignment
|
||||
+13
-38
@@ -24,59 +24,34 @@ from ifcopenshell import entity_instance
|
||||
from collections.abc import Sequence
|
||||
|
||||
|
||||
def create_alignment_by_pi_method(
|
||||
def create_by_pi_method(
|
||||
file: ifcopenshell.file,
|
||||
alignment_name: str,
|
||||
name: str,
|
||||
hpoints: Sequence[Sequence[float]],
|
||||
radii: Sequence[float],
|
||||
vpoints: Sequence[Sequence[float]] = None,
|
||||
lengths: Sequence[float] = None,
|
||||
alignment_description: str = None,
|
||||
start_station: float = 0.0,
|
||||
) -> entity_instance:
|
||||
"""
|
||||
Create an alignment using the PI layout method for both horizontal and vertical alignments.
|
||||
If vpoints and lengths are omitted, only a horizontal alignment is created. Only the business logic
|
||||
entities are creaed. Use create_geometric_representation() to create the geometric entities.
|
||||
If vpoints and lengths are omitted, only a horizontal alignment is created.
|
||||
|
||||
:param alignment_name: value for Name attribute
|
||||
:param name: value for Name attribute
|
||||
:param points: (X,Y) pairs denoting the location of the horizontal PIs, including start and end
|
||||
:param radii: radii values to use for transition
|
||||
:param vpoints: (distance_along, Z_height) pairs denoting the location of the vertical PIs, including start and end.
|
||||
:param lengths: parabolic vertical curve horizontal length values to use for transition
|
||||
:param alignment_description: value for Description attribute
|
||||
:return: Returns an IfcAlignment
|
||||
"""
|
||||
alignments = []
|
||||
|
||||
horizontal_alignment = ifcopenshell.api.alignment.create_horizontal_alignment_by_pi_method(
|
||||
file, alignment_name, hpoints, radii
|
||||
include_vertical = True if vpoints and lengths else False
|
||||
alignment = ifcopenshell.api.alignment.create(
|
||||
file, name, include_vertical=include_vertical, start_station=start_station
|
||||
)
|
||||
alignments.append(horizontal_alignment)
|
||||
|
||||
if vpoints and lengths:
|
||||
vertical_alignment = ifcopenshell.api.alignment.create_vertical_alignment_by_pi_method(
|
||||
file, alignment_name, vpoints, lengths
|
||||
)
|
||||
alignments.append(vertical_alignment)
|
||||
|
||||
# create the alignment
|
||||
alignment = file.create_entity(
|
||||
type="IfcAlignment",
|
||||
GlobalId=ifcopenshell.guid.new(),
|
||||
OwnerHistory=None,
|
||||
Name=alignment_name,
|
||||
Description=alignment_description,
|
||||
ObjectType=None,
|
||||
ObjectPlacement=None,
|
||||
Representation=None,
|
||||
PredefinedType=None,
|
||||
)
|
||||
|
||||
# nest the horizontal and vertical under the alignment
|
||||
ifcopenshell.api.nest.assign_object(file, related_objects=alignments, relating_object=alignment)
|
||||
|
||||
# IFC 4.1.4.1.1 Alignment Aggregation To Project
|
||||
project = file.by_type("IfcProject")[0]
|
||||
ifcopenshell.api.aggregate.assign_object(file, products=[alignment], relating_object=project)
|
||||
horizontal_layout = ifcopenshell.api.alignment.get_horizontal_layout(alignment)
|
||||
ifcopenshell.api.alignment.layout_horizontal_alignment_by_pi_method(file, horizontal_layout, hpoints, radii)
|
||||
if include_vertical:
|
||||
vertical_layout = ifcopenshell.api.alignment.get_vertical_layout(alignment)
|
||||
ifcopenshell.api.alignment.layout_vertical_alignment_by_pi_method(file, vertical_layout, vpoints, lengths)
|
||||
|
||||
return alignment
|
||||
+11
-25
@@ -17,27 +17,19 @@
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api.aggregate
|
||||
import ifcopenshell.api.alignment
|
||||
import ifcopenshell.api.geometry
|
||||
import ifcopenshell.api.nest
|
||||
import ifcopenshell.guid
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.representation
|
||||
import ifcopenshell.util.stationing
|
||||
import ifcopenshell.api
|
||||
from ifcopenshell import entity_instance
|
||||
from ifcopenshell.api.alignment import get_axis_subcontext
|
||||
|
||||
import math
|
||||
from typing import Sequence
|
||||
|
||||
import csv
|
||||
|
||||
|
||||
def create_alignment_from_csv(file: ifcopenshell.file, filepath: str) -> entity_instance:
|
||||
def create_from_csv(file: ifcopenshell.file, filepath: str) -> entity_instance:
|
||||
"""
|
||||
Creates an alignment from PI data stored in a CSV file. Only the business logic
|
||||
entities are creaed. Use create_geometric_representation() to create the geometric entities.
|
||||
Creates an alignment from PI data stored in a CSV file.
|
||||
|
||||
The format of the file is:
|
||||
|
||||
@@ -94,22 +86,16 @@ def create_alignment_from_csv(file: ifcopenshell.file, filepath: str) -> entity_
|
||||
radii = radii[1:-1] # The first radius value is a placeholder, remove it
|
||||
|
||||
if row_count == 1:
|
||||
# create the alignment
|
||||
alignment = file.createIfcAlignment(GlobalId=ifcopenshell.guid.new())
|
||||
# create the horizontal alignment
|
||||
horizontal_alignment = ifcopenshell.api.alignment.create_horizontal_alignment_by_pi_method(
|
||||
file, "Alignment_from_CSV", coordinates, radii
|
||||
)
|
||||
# nest them together
|
||||
ifcopenshell.api.nest.assign_object(
|
||||
file, related_objects=(horizontal_alignment,), relating_object=alignment
|
||||
alignment = ifcopenshell.api.alignment.create(file, "Alignment_from_CSV")
|
||||
horizontal_layout = ifcopenshell.api.alignment.get_horizontal_layout(alignment)
|
||||
ifcopenshell.api.alignment.layout_horizontal_alignment_by_pi_method(
|
||||
file, horizontal_layout, coordinates, radii
|
||||
)
|
||||
else:
|
||||
# add all subsequent vertical alignments
|
||||
ifcopenshell.api.alignment.add_vertical_alignment_by_pi_method(file, alignment, coordinates, radii)
|
||||
|
||||
# IFC 4.1.4.1.1 Alignment Aggregation To Project
|
||||
project = file.by_type("IfcProject")[0]
|
||||
ifcopenshell.api.aggregate.assign_object(file, products=[alignment], relating_object=project)
|
||||
vertical_layout = ifcopenshell.api.alignment.add_vertical_layout(file, alignment)
|
||||
ifcopenshell.api.alignment.layout_vertical_alignment_by_pi_method(
|
||||
file, vertical_layout, coordinates, radii
|
||||
)
|
||||
|
||||
return alignment
|
||||
-216
@@ -1,216 +0,0 @@
|
||||
# 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 ifcopenshell
|
||||
import ifcopenshell.api.alignment
|
||||
from ifcopenshell import entity_instance
|
||||
|
||||
import math
|
||||
from collections.abc import Sequence
|
||||
|
||||
|
||||
def create_horizontal_alignment_by_pi_method(
|
||||
file: ifcopenshell.file, name: str, hpoints: Sequence[Sequence[float]], radii: Sequence[float]
|
||||
) -> entity_instance:
|
||||
"""
|
||||
Create a horizontal alignment using the PI layout method.
|
||||
|
||||
:param name: value for Name attribute
|
||||
:param hpoints: (X, Y) pairs denoting the location of the horizontal PIs, including start (POB) and end (POE).
|
||||
:param radii: radius values to use for transition
|
||||
:return: Returns a IfcAlignmentHorizontal
|
||||
"""
|
||||
if not (len(hpoints) - 2 == len(radii)):
|
||||
raise ValueError("radii should have two fewer elements that hpoints")
|
||||
|
||||
# Create the horizontal alignment (IfcAlignmentHorizontal) and nest alignment segments
|
||||
horizontal_alignment = file.create_entity(
|
||||
type="IfcAlignmentHorizontal",
|
||||
GlobalId=ifcopenshell.guid.new(),
|
||||
OwnerHistory=None,
|
||||
Name=f"{name} - Horizontal",
|
||||
Description=None,
|
||||
ObjectType=None,
|
||||
ObjectPlacement=None,
|
||||
Representation=None,
|
||||
)
|
||||
|
||||
xBT, yBT = hpoints[0]
|
||||
xPI, yPI = hpoints[1]
|
||||
|
||||
i = 1
|
||||
|
||||
for radius in radii:
|
||||
# back tangent
|
||||
dxBT = xPI - xBT
|
||||
dyBT = yPI - yBT
|
||||
angleBT = math.atan2(dyBT, dxBT)
|
||||
lengthBT = math.sqrt(dxBT * dxBT + dyBT * dyBT)
|
||||
|
||||
# forward tangent
|
||||
i += 1
|
||||
xFT, yFT = hpoints[i]
|
||||
dxFT = xFT - xPI
|
||||
dyFT = yFT - yPI
|
||||
angleFT = math.atan2(dyFT, dxFT)
|
||||
|
||||
delta = angleFT - angleBT
|
||||
|
||||
tangent = abs(radius * math.tan(delta / 2))
|
||||
|
||||
lc = abs(radius * delta)
|
||||
|
||||
radius *= delta / abs(delta)
|
||||
|
||||
xPC = xPI - tangent * math.cos(angleBT)
|
||||
yPC = yPI - tangent * math.sin(angleBT)
|
||||
|
||||
xPT = xPI + tangent * math.cos(angleFT)
|
||||
yPT = yPI + tangent * math.sin(angleFT)
|
||||
|
||||
tangent_run = lengthBT - tangent
|
||||
|
||||
# create back tangent run
|
||||
pt = file.create_entity(
|
||||
type="IfcCartesianPoint",
|
||||
Coordinates=(xBT, yBT),
|
||||
)
|
||||
design_parameters = file.create_entity(
|
||||
type="IfcAlignmentHorizontalSegment",
|
||||
StartTag=None,
|
||||
EndTag=None,
|
||||
StartPoint=pt,
|
||||
StartDirection=angleBT,
|
||||
StartRadiusOfCurvature=0.0,
|
||||
EndRadiusOfCurvature=0.0,
|
||||
SegmentLength=tangent_run,
|
||||
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)
|
||||
|
||||
# create circular curve
|
||||
if radius != 0.0:
|
||||
pc = file.create_entity(
|
||||
type="IfcCartesianPoint",
|
||||
Coordinates=(xPC, yPC),
|
||||
)
|
||||
design_parameters = file.create_entity(
|
||||
type="IfcAlignmentHorizontalSegment",
|
||||
StartTag=None,
|
||||
EndTag=None,
|
||||
StartPoint=pc,
|
||||
StartDirection=angleBT,
|
||||
StartRadiusOfCurvature=float(radius),
|
||||
EndRadiusOfCurvature=float(radius),
|
||||
SegmentLength=lc,
|
||||
GravityCenterLineHeight=None,
|
||||
PredefinedType="CIRCULARARC",
|
||||
)
|
||||
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)
|
||||
|
||||
xBT = xPT
|
||||
yBT = yPT
|
||||
xPI = xFT
|
||||
yPI = yFT
|
||||
|
||||
# done processing radii
|
||||
# create last tangent run
|
||||
dx = xPI - xBT
|
||||
dy = yPI - yBT
|
||||
angleBT = math.atan2(dy, dx)
|
||||
tangent_run = math.sqrt(dx * dx + dy * dy)
|
||||
pt = file.create_entity(type="IfcCartesianPoint", Coordinates=(xBT, yBT))
|
||||
|
||||
design_parameters = file.create_entity(
|
||||
type="IfcAlignmentHorizontalSegment",
|
||||
StartTag=None,
|
||||
EndTag=None,
|
||||
StartPoint=pt,
|
||||
StartDirection=angleBT,
|
||||
StartRadiusOfCurvature=0.0,
|
||||
EndRadiusOfCurvature=0.0,
|
||||
SegmentLength=tangent_run,
|
||||
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)
|
||||
|
||||
# create zero length terminator segment
|
||||
poe = file.create_entity(type="IfcCartesianPoint", Coordinates=(xPI, yPI))
|
||||
|
||||
design_parameters = file.create_entity(
|
||||
type="IfcAlignmentHorizontalSegment",
|
||||
StartTag="POE",
|
||||
EndTag="POE",
|
||||
StartPoint=poe,
|
||||
StartDirection=angleBT,
|
||||
StartRadiusOfCurvature=0.0,
|
||||
EndRadiusOfCurvature=0.0,
|
||||
SegmentLength=0.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)
|
||||
|
||||
return horizontal_alignment
|
||||
@@ -0,0 +1,85 @@
|
||||
# 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 ifcopenshell
|
||||
import ifcopenshell.api.alignment
|
||||
import ifcopenshell.api.alignment.get_alignment
|
||||
import ifcopenshell.geom
|
||||
from ifcopenshell import entity_instance
|
||||
import math
|
||||
from ifcopenshell import ifcopenshell_wrapper
|
||||
import numpy as np
|
||||
|
||||
from ifcopenshell.api.alignment._add_segment_to_layout import _add_segment_to_layout
|
||||
|
||||
|
||||
def create_layout_segment(
|
||||
file: ifcopenshell.file, layout: entity_instance, design_parameters: entity_instance
|
||||
) -> np.array:
|
||||
"""
|
||||
Creates a new IfcAlignmentSegment using the IfcAlignmentParameterSegment design parameters.
|
||||
The new segment is appended to the layout alignment and the corresponding IfcCurveSegment is created in the geometric representation
|
||||
|
||||
:param layout: The layout to receive the new layout segment. This parameter is expected to be IfcAlignmentHorizontal, IfcAlignmentVertical or IfcAlignmentCant
|
||||
:param design_parameters: The parameters defining the segment. Expected to be the appropreate subclass of IfcAlignmentParameterSegment
|
||||
:return: 4x4 matrix at end of segment as np.array intended to be used as the start point geometry for the next segment.
|
||||
"""
|
||||
expected_types = ["IfcAlignmentHorizontal", "IfcAlignmentVertical", "IfcAlignmentCant"]
|
||||
if not layout.is_a() in expected_types:
|
||||
raise TypeError(
|
||||
f"Expected entity type to be one of {[_ for _ in expected_types]}, instead received {layout.is_a()}"
|
||||
)
|
||||
|
||||
if layout.is_a("IfcAlignmentHorizontal") and not design_parameters.is_a("IfcAlignmentHorizontalSegment"):
|
||||
raise TypeError("Expected design_parameters to be IfcAlignmentHorizontalSegment")
|
||||
elif layout.is_a("IfcAlignmentVertical") and not design_parameters.is_a("IfcAlignmentVerticalSegment"):
|
||||
raise TypeError("Expected design_parameters to be IfcAlignmentVerticalSegment")
|
||||
elif layout.is_a("IfcAlignmentCant") and not design_parameters.is_a("IfcAlignmentCantSegment"):
|
||||
raise TypeError("Expected design_parameters to be IfcAlignmentCantSegment")
|
||||
|
||||
# create the segment and add it to the layout.
|
||||
segment = file.createIfcAlignmentSegment(GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters)
|
||||
_add_segment_to_layout(file, layout, segment) # adds to layout and geometric representation
|
||||
|
||||
# compute the 4x4 matrix at the end of the segment so this information can be
|
||||
# returned and used when defining the next segment
|
||||
alignment = ifcopenshell.api.alignment.get_alignment(layout)
|
||||
curve = ifcopenshell.api.alignment.get_curve(alignment)
|
||||
|
||||
if layout.is_a("IfcAlignmentHorizontal"):
|
||||
if curve.is_a("IfcGradientCurve"):
|
||||
curve = curve.BaseCurve
|
||||
elif curve.is_a("IfcSegmentedReferenceCurve"):
|
||||
curve = (
|
||||
curve.BaseCurve.BaseCurve
|
||||
) # layout is horizontal and curve is segmented ref ... we want the curve's base curve
|
||||
elif layout.is_a("IfcAlignmentVertical"):
|
||||
if curve.is_a("IfcSegmentedReferenceCurve"):
|
||||
curve = curve.BaseCurve
|
||||
|
||||
# the new segment is two from the end... the end segment is zero length
|
||||
curve_segment = curve.Segments[-2]
|
||||
|
||||
settings = ifcopenshell.geom.settings()
|
||||
|
||||
segment_fn = ifcopenshell_wrapper.map_shape(settings, curve_segment.wrapped_data)
|
||||
segment_evaluator = ifcopenshell_wrapper.function_item_evaluator(settings, segment_fn)
|
||||
e = segment_evaluator.evaluate(segment_fn.end())
|
||||
end = np.array(e)
|
||||
|
||||
return end
|
||||
+1
-1
@@ -58,7 +58,7 @@ def create_segment_representations(
|
||||
)
|
||||
|
||||
curve_segments = curve.Segments
|
||||
segments = nested_alignment.IsNestedBy[0].RelatingObjects
|
||||
segments = nested_alignment.IsNestedBy[0].RelatedObjects
|
||||
|
||||
for curve_segment, alignment_segment in zip(curve_segments, segments):
|
||||
axis_representation = file.create_entity(
|
||||
|
||||
-194
@@ -1,194 +0,0 @@
|
||||
# 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 ifcopenshell
|
||||
import ifcopenshell.api.alignment
|
||||
from ifcopenshell import entity_instance
|
||||
|
||||
import math
|
||||
from collections.abc import Sequence
|
||||
|
||||
|
||||
def create_vertical_alignment_by_pi_method(
|
||||
file: ifcopenshell.file, name: str, vpoints: Sequence[Sequence[float]], lengths: Sequence[float]
|
||||
) -> entity_instance:
|
||||
"""
|
||||
Create a vertical alignment using the PI layout method.
|
||||
|
||||
:param name: value for Name attribute
|
||||
:param base_curve: base curve representing the 2D projection of the gradient curve
|
||||
:param vpoints: (distance_along, Z_height) pairs denoting the location of the vertical PIs, including start and end.
|
||||
:param lengths: horizontal length of parabolic vertical curves
|
||||
:return: IfcAlignmentHorizontal
|
||||
"""
|
||||
if not (len(vpoints) - 2 == len(lengths)):
|
||||
raise ValueError("lengths should have two fewer elements that vpoints")
|
||||
|
||||
# Create the vertical alignment (IfcAlignmentVertical) and nest alignment segments
|
||||
vertical_alignment = file.create_entity(
|
||||
type="IfcAlignmentVertical",
|
||||
GlobalId=ifcopenshell.guid.new(),
|
||||
OwnerHistory=None,
|
||||
Name=f"{name} - Vertical",
|
||||
Description=None,
|
||||
ObjectType=None,
|
||||
ObjectPlacement=None,
|
||||
Representation=None,
|
||||
)
|
||||
|
||||
xPBG, yPBG = vpoints[0]
|
||||
xPVI, yPVI = vpoints[1]
|
||||
i = 1
|
||||
for length in lengths:
|
||||
# back gradient
|
||||
dxBG = xPVI - xPBG
|
||||
dyBG = yPVI - yPBG
|
||||
start_slope = math.tan(math.atan2(dyBG, dxBG))
|
||||
|
||||
# forward gradient
|
||||
i += 1
|
||||
xPFG, yPFG = vpoints[i]
|
||||
dxFG = xPFG - xPVI
|
||||
dyFG = yPFG - yPVI
|
||||
end_slope = math.tan(math.atan2(dyFG, dxFG))
|
||||
|
||||
xEVC = xPVI + length / 2.0
|
||||
yEVC = yPVI + end_slope * length / 2.0
|
||||
|
||||
# create gradient
|
||||
gradient_length = dxBG - length / 2.0
|
||||
design_parameters = file.create_entity(
|
||||
type="IfcAlignmentVerticalSegment",
|
||||
StartTag=None,
|
||||
EndTag=None,
|
||||
StartDistAlong=xPBG,
|
||||
HorizontalLength=gradient_length,
|
||||
StartHeight=yPBG,
|
||||
StartGradient=start_slope,
|
||||
EndGradient=start_slope,
|
||||
RadiusOfCurvature=None,
|
||||
PredefinedType="CONSTANTGRADIENT",
|
||||
)
|
||||
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, vertical_alignment, alignment_segment)
|
||||
|
||||
# create vertical curve
|
||||
if 0.0 < length:
|
||||
k = (end_slope - start_slope) / length
|
||||
xBVC = xPVI - length / 2.0
|
||||
yBVC = yPVI - start_slope * length / 2.0
|
||||
|
||||
design_parameters = file.create_entity(
|
||||
type="IfcAlignmentVerticalSegment",
|
||||
StartTag=None,
|
||||
EndTag=None,
|
||||
StartDistAlong=xBVC,
|
||||
HorizontalLength=length,
|
||||
StartHeight=yBVC,
|
||||
StartGradient=start_slope,
|
||||
EndGradient=end_slope,
|
||||
RadiusOfCurvature=1 / k,
|
||||
PredefinedType="PARABOLICARC",
|
||||
)
|
||||
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, vertical_alignment, alignment_segment)
|
||||
|
||||
# start of next curve is end of this curve
|
||||
xPBG = xEVC
|
||||
yPBG = yEVC
|
||||
xPVI = xPFG
|
||||
yPVI = yPFG
|
||||
|
||||
# create last gradient run
|
||||
dx = xPVI - xPBG
|
||||
dy = yPVI - yPBG
|
||||
slope = math.tan(math.atan2(dy, dx))
|
||||
gradient_length = dx
|
||||
|
||||
design_parameters = file.create_entity(
|
||||
type="IfcAlignmentVerticalSegment",
|
||||
StartTag=None,
|
||||
EndTag=None,
|
||||
StartDistAlong=xPBG,
|
||||
HorizontalLength=gradient_length,
|
||||
StartHeight=yPBG,
|
||||
StartGradient=slope,
|
||||
EndGradient=slope,
|
||||
RadiusOfCurvature=None,
|
||||
PredefinedType="CONSTANTGRADIENT",
|
||||
)
|
||||
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, vertical_alignment, alignment_segment)
|
||||
|
||||
# create zero length terminator segment
|
||||
design_parameters = file.create_entity(
|
||||
type="IfcAlignmentVerticalSegment",
|
||||
StartTag="VPOE",
|
||||
EndTag="VPOE",
|
||||
StartDistAlong=xPVI,
|
||||
HorizontalLength=0.0,
|
||||
StartHeight=yPVI,
|
||||
StartGradient=slope,
|
||||
EndGradient=slope,
|
||||
RadiusOfCurvature=None,
|
||||
PredefinedType="CONSTANTGRADIENT",
|
||||
)
|
||||
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, vertical_alignment, alignment_segment)
|
||||
|
||||
return vertical_alignment
|
||||
@@ -43,12 +43,6 @@ def distance_along_from_station(file: ifcopenshell.file, alignment: entity_insta
|
||||
print(dist_along) # 100.00
|
||||
"""
|
||||
|
||||
start_station = 0.0
|
||||
components = ifcopenshell.util.element.get_components(alignment)
|
||||
for c in components:
|
||||
if c.is_a("IfcReferent") and ifcopenshell.util.element.get_predefined_type(c) == "STATION":
|
||||
start_station = ifcopenshell.util.element.get_pset(c, name="Pset_Stationing", prop="Station")
|
||||
break
|
||||
|
||||
start_station = ifcopenshell.api.alignment.get_alignment_station(file, alignment)
|
||||
dist_along = station - start_station
|
||||
return dist_along
|
||||
|
||||
+7
-11
@@ -17,19 +17,15 @@
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api.alignment
|
||||
import ifcopenshell.util
|
||||
from ifcopenshell import entity_instance
|
||||
import ifcopenshell.api.alignment.remove_last_segment
|
||||
from typing import Sequence
|
||||
|
||||
import ifcopenshell.util.representation
|
||||
|
||||
|
||||
def remove_zero_length_segment(file: ifcopenshell.file, entity: entity_instance) -> entity_instance:
|
||||
def get_alignment(layout: entity_instance) -> entity_instance:
|
||||
"""
|
||||
Removes the zero length segment from the end of entity.
|
||||
|
||||
:param entity: An IfcAlignmentHorizontal, IfcAlignmentVertical, IfcAlignmentCant or IfcCompositeCurve
|
||||
:return: The zero length segment
|
||||
Returns the alignment that nests this layout
|
||||
"""
|
||||
if not ifcopenshell.api.alignment.has_zero_length_segment(entity):
|
||||
return None
|
||||
|
||||
return ifcopenshell.api.alignment.remove_last_segment(file, entity)
|
||||
return layout.Nests[0].RelatingObject if 0 < len(layout.Nests) else None
|
||||
@@ -0,0 +1,40 @@
|
||||
# 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 ifcopenshell
|
||||
from ifcopenshell import entity_instance
|
||||
|
||||
|
||||
def get_alignment_station(file: ifcopenshell.file, alignment: entity_instance) -> float:
|
||||
"""
|
||||
Returns the start station of the alignment. If the alignment is nested by an IfcReferent
|
||||
the referent is checked for PredefinedType of STATION and an occurance of Pset_Stationing.Station,
|
||||
otherwise start station is taken to be 0.0.
|
||||
"""
|
||||
|
||||
if not alignment.is_a("IfcAlignment"):
|
||||
raise TypeError(f"Expected entity type to be IfcAlignment, instead received {alignment.is_a()}")
|
||||
|
||||
start_station = 0.0
|
||||
components = ifcopenshell.util.element.get_components(alignment)
|
||||
for c in components:
|
||||
if c.is_a("IfcReferent") and ifcopenshell.util.element.get_predefined_type(c) == "STATION":
|
||||
start_station = ifcopenshell.util.element.get_pset(c, name="Pset_Stationing", prop="Station")
|
||||
break
|
||||
|
||||
return start_station
|
||||
@@ -45,6 +45,10 @@ def get_basis_curve(alignment: entity_instance) -> entity_instance:
|
||||
representation.RepresentationIdentifier == "FootPrint" and representation.RepresentationType == "Curve2D"
|
||||
):
|
||||
axis = representation
|
||||
break
|
||||
return None if axis.Items == None or len(axis.Items) == 0 else axis.Items[0]
|
||||
|
||||
return None if axis == None or axis.Items == None or len(axis.Items) == 0 else axis.Items[0]
|
||||
if axis == None and 0 < len(alignment.Decomposes):
|
||||
parent_alignment = alignment.Decomposes[0].RelatingObject
|
||||
return get_basis_curve(parent_alignment)
|
||||
|
||||
return None
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# 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/>.
|
||||
|
||||
from ifcopenshell import entity_instance
|
||||
|
||||
|
||||
def get_cant_layout(alignment: entity_instance) -> entity_instance:
|
||||
"""
|
||||
Returns the IfcAlignmentCant assocated with this alignment
|
||||
"""
|
||||
for rel in alignment.IsNestedBy:
|
||||
for layout in rel.RelatedObjects:
|
||||
if layout.is_a("IfcAlignmentCant"):
|
||||
return layout
|
||||
|
||||
return None
|
||||
@@ -26,7 +26,7 @@ import ifcopenshell.util.element
|
||||
|
||||
def get_child_alignments(alignment: entity_instance) -> Sequence[entity_instance]:
|
||||
"""
|
||||
Returns the aggregated child alignments to this alignment
|
||||
Returns the aggregated child alignments to this alignment per CT 4.1.4.4.1.2 Alignment Layout - Reusing Horizontal Layout
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# 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/>.
|
||||
|
||||
from ifcopenshell import entity_instance
|
||||
|
||||
|
||||
def get_horizontal_layout(alignment: entity_instance) -> entity_instance:
|
||||
"""
|
||||
Returns the IfcAlignmentHorizontal assocated with this alignment
|
||||
"""
|
||||
for rel in alignment.IsNestedBy:
|
||||
for layout in rel.RelatedObjects:
|
||||
if layout.is_a("IfcAlignmentHorizontal"):
|
||||
return layout
|
||||
|
||||
return None
|
||||
@@ -0,0 +1,55 @@
|
||||
# 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 ifcopenshell
|
||||
import ifcopenshell.util
|
||||
from ifcopenshell import entity_instance
|
||||
|
||||
import ifcopenshell.util.representation
|
||||
|
||||
|
||||
def get_layout_curve(layout: entity_instance) -> entity_instance:
|
||||
"""
|
||||
Returns the representation curve for the layout. This will be an IfcCompositeCurve, IfcGradientCurve, or IfcSegmentReferenceCurve
|
||||
for IfcAlignmentHorizontal, IfcAlignmentVertical, or IfcAlignmentCant, respectively.
|
||||
|
||||
:param layout: An alignment layout
|
||||
:return: The geometric representation curve
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
alignment = model.by_type("IfcAlignment")[0]
|
||||
layout = ifcopenshell.api.get_horizontal_layout(alignment)
|
||||
composite_curve = ifcopenshell.api.alignment.get_layout_curve(layout)
|
||||
"""
|
||||
alignment = ifcopenshell.api.alignment.get_alignment(layout)
|
||||
|
||||
curve = ifcopenshell.api.alignment.get_curve(alignment)
|
||||
if layout.is_a("IfcAlignmentHorizontal"):
|
||||
# Layout is horizontal so get the IfcCompositeCurve
|
||||
if curve.is_a("IfcGradientCurve"):
|
||||
curve = curve.BaseCurve
|
||||
elif curve.is_a("IfcSegmentedReferenceCurve"):
|
||||
curve = curve.BaseCurve.BaseCurve
|
||||
elif layout.is_a("IfcAlignmentVertical"):
|
||||
# Layout is vertical so get the IfcGradientCurve
|
||||
if curve.is_a("IfcSegmentedReferenceCurve"):
|
||||
curve = curve.BaseCurve
|
||||
|
||||
return curve
|
||||
@@ -0,0 +1,44 @@
|
||||
# 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 ifcopenshell
|
||||
import ifcopenshell.util
|
||||
from ifcopenshell import entity_instance
|
||||
from typing import Sequence
|
||||
|
||||
import ifcopenshell.util.element
|
||||
|
||||
|
||||
def get_layout_segments(layout: entity_instance) -> Sequence[entity_instance]:
|
||||
"""
|
||||
Returns the IfcAlignmentSegment nested to this alignment layout
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
horizontal = model.by_type("IfcAlignmentHorizontal")[0]
|
||||
segments = ifcopenshell.api.alignment.get_layout_segments(horizontal)
|
||||
"""
|
||||
segments = []
|
||||
for rel in layout.IsNestedBy:
|
||||
for segment in rel.RelatedObjects:
|
||||
if segment.is_a("IfcAlignmentSegment"):
|
||||
segments.append(segment)
|
||||
|
||||
return segments
|
||||
@@ -0,0 +1,31 @@
|
||||
# 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/>.
|
||||
|
||||
from ifcopenshell import entity_instance
|
||||
|
||||
|
||||
def get_vertical_layout(alignment: entity_instance) -> entity_instance:
|
||||
"""
|
||||
Returns the IfcAlignmentVertical assocated with this alignment
|
||||
"""
|
||||
for rel in alignment.IsNestedBy:
|
||||
for layout in rel.RelatedObjects:
|
||||
if layout.is_a("IfcAlignmentVertical"):
|
||||
return layout
|
||||
|
||||
return None
|
||||
@@ -22,40 +22,29 @@ import ifcopenshell.util.element
|
||||
from ifcopenshell import entity_instance
|
||||
|
||||
|
||||
def has_zero_length_segment(entity: entity_instance) -> bool:
|
||||
def has_zero_length_segment(layout: entity_instance) -> bool:
|
||||
"""
|
||||
Returns true if the entity ends with a zero length segment. If the entity is an IfcCompositeCurve the IfcCurveSegment.Transition must be DISCONTINUOUS
|
||||
Returns true if the layout ends with a zero length segment.
|
||||
|
||||
:param entity: An IfcAlignmentHorizontal, IfcAlignmentVertical, IfcAlignmentCant or IfcCompositeCurve
|
||||
:param layout: An IfcAlignmentHorizontal, IfcAlignmentVertical, or IfcAlignmentCant
|
||||
:return: True if the zero length segment is present
|
||||
"""
|
||||
expected_types = [
|
||||
"IfcAlignmentHorizontal",
|
||||
"IfcAlignmentVertical",
|
||||
"IfcAlignmentCant",
|
||||
"IfcCompositeCurve",
|
||||
"IfcGradientCurve",
|
||||
"IfcSegmentedReferenceCurve",
|
||||
]
|
||||
if not entity.is_a() in expected_types:
|
||||
expected_types = ["IfcAlignmentHorizontal", "IfcAlignmentVertical", "IfcAlignmentCant"]
|
||||
if not layout.is_a() in expected_types:
|
||||
raise TypeError(
|
||||
f"Expected entity type to be one of {[_ for _ in expected_types]}, instead received '{entity.is_a()}"
|
||||
f"Expected entity type to be one of {[_ for _ in expected_types]}, instead received '{layout.is_a()}"
|
||||
)
|
||||
|
||||
if entity.is_a("IfcCompositeCurve"):
|
||||
last_segment = entity.Segments[-1]
|
||||
return last_segment.Transition == "DISCONTINUOUS" and last_segment.SegmentLength.wrappedValue == 0.0
|
||||
else:
|
||||
segments = ifcopenshell.util.element.get_components(entity)
|
||||
for rel in entity.IsNestedBy:
|
||||
if 0 < len(rel.RelatedObjects):
|
||||
last_segment = rel.RelatedObjects[-1]
|
||||
if last_segment.is_a("IfcAlignmentSegment"):
|
||||
if last_segment.DesignParameters.is_a("IfcAlignmentHorizontalSegment"):
|
||||
return last_segment.DesignParameters.SegmentLength == 0.0
|
||||
elif last_segment.DesignParameters.is_a("IfcAlignmentVerticalSegment"):
|
||||
return last_segment.DesignParameters.HorizontalLength == 0.0
|
||||
elif last_segment.DesignParameters.is_a("IfcAlignmentCantSegment"):
|
||||
return last_segment.DesignParameters.HorizontalLength == 0.0
|
||||
result = False
|
||||
for rel in layout.IsNestedBy:
|
||||
if 0 < len(rel.RelatedObjects):
|
||||
last_segment = rel.RelatedObjects[-1]
|
||||
if last_segment.is_a("IfcAlignmentSegment"):
|
||||
if last_segment.DesignParameters.is_a("IfcAlignmentHorizontalSegment"):
|
||||
result = last_segment.DesignParameters.SegmentLength == 0.0
|
||||
elif last_segment.DesignParameters.is_a("IfcAlignmentVerticalSegment"):
|
||||
result = last_segment.DesignParameters.HorizontalLength == 0.0
|
||||
elif last_segment.DesignParameters.is_a("IfcAlignmentCantSegment"):
|
||||
result = last_segment.DesignParameters.HorizontalLength == 0.0
|
||||
|
||||
return False
|
||||
return result
|
||||
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
# 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 ifcopenshell
|
||||
from ifcopenshell import entity_instance
|
||||
|
||||
import math
|
||||
from collections.abc import Sequence
|
||||
|
||||
import ifcopenshell.api.alignment.create_layout_segment
|
||||
|
||||
|
||||
def layout_horizontal_alignment_by_pi_method(
|
||||
file: ifcopenshell.file, layout: entity_instance, hpoints: Sequence[Sequence[float]], radii: Sequence[float]
|
||||
) -> None:
|
||||
"""
|
||||
Appends IfcAlignmentHorizontalSegment to a previously defined IfcAlignmentHorizontal using the PI layout method.
|
||||
The zero length segment is updated.
|
||||
|
||||
:param file: file
|
||||
:param layout: An IfcAlignmentHorizontal layout
|
||||
:param hpoints: (X, Y) pairs denoting the location of the horizontal PIs, including start (POB) and end (POE).
|
||||
:param radii: radius values to use for transition
|
||||
:return: None
|
||||
"""
|
||||
if not (len(hpoints) - 2 == len(radii)):
|
||||
raise ValueError("radii should have two fewer elements that hpoints")
|
||||
|
||||
xBT, yBT = hpoints[0]
|
||||
xPI, yPI = hpoints[1]
|
||||
|
||||
i = 1
|
||||
|
||||
for radius in radii:
|
||||
# back tangent
|
||||
dxBT = xPI - xBT
|
||||
dyBT = yPI - yBT
|
||||
angleBT = math.atan2(dyBT, dxBT)
|
||||
lengthBT = math.sqrt(dxBT * dxBT + dyBT * dyBT)
|
||||
|
||||
# forward tangent
|
||||
i += 1
|
||||
xFT, yFT = hpoints[i]
|
||||
dxFT = xFT - xPI
|
||||
dyFT = yFT - yPI
|
||||
angleFT = math.atan2(dyFT, dxFT)
|
||||
|
||||
delta = angleFT - angleBT
|
||||
|
||||
tangent = abs(radius * math.tan(delta / 2))
|
||||
|
||||
lc = abs(radius * delta)
|
||||
|
||||
radius *= delta / abs(delta)
|
||||
|
||||
xPC = xPI - tangent * math.cos(angleBT)
|
||||
yPC = yPI - tangent * math.sin(angleBT)
|
||||
|
||||
xPT = xPI + tangent * math.cos(angleFT)
|
||||
yPT = yPI + tangent * math.sin(angleFT)
|
||||
|
||||
tangent_run = lengthBT - tangent
|
||||
|
||||
# create back tangent run
|
||||
if 1.0e-03 < tangent_run:
|
||||
pt = file.createIfcCartesianPoint(
|
||||
Coordinates=(xBT, yBT),
|
||||
)
|
||||
design_parameters = file.createIfcAlignmentHorizontalSegment(
|
||||
StartTag=None,
|
||||
EndTag=None,
|
||||
StartPoint=pt,
|
||||
StartDirection=angleBT,
|
||||
StartRadiusOfCurvature=0.0,
|
||||
EndRadiusOfCurvature=0.0,
|
||||
SegmentLength=tangent_run,
|
||||
GravityCenterLineHeight=None,
|
||||
PredefinedType="LINE",
|
||||
)
|
||||
ifcopenshell.api.alignment.create_layout_segment(file, layout, design_parameters)
|
||||
|
||||
# create circular curve
|
||||
if radius != 0.0:
|
||||
pc = file.createIfcCartesianPoint(
|
||||
Coordinates=(xPC, yPC),
|
||||
)
|
||||
design_parameters = file.createIfcAlignmentHorizontalSegment(
|
||||
StartTag=None,
|
||||
EndTag=None,
|
||||
StartPoint=pc,
|
||||
StartDirection=angleBT,
|
||||
StartRadiusOfCurvature=float(radius),
|
||||
EndRadiusOfCurvature=float(radius),
|
||||
SegmentLength=lc,
|
||||
GravityCenterLineHeight=None,
|
||||
PredefinedType="CIRCULARARC",
|
||||
)
|
||||
ifcopenshell.api.alignment.create_layout_segment(file, layout, design_parameters)
|
||||
|
||||
xBT = xPT
|
||||
yBT = yPT
|
||||
xPI = xFT
|
||||
yPI = yFT
|
||||
|
||||
# done processing radii
|
||||
# create last tangent run
|
||||
dx = xPI - xBT
|
||||
dy = yPI - yBT
|
||||
angleBT = math.atan2(dy, dx)
|
||||
tangent_run = math.sqrt(dx * dx + dy * dy)
|
||||
|
||||
if 1.0e-03 < tangent_run:
|
||||
pt = file.createIfcCartesianPoint(Coordinates=(xBT, yBT))
|
||||
|
||||
design_parameters = file.createIfcAlignmentHorizontalSegment(
|
||||
StartTag=None,
|
||||
EndTag=None,
|
||||
StartPoint=pt,
|
||||
StartDirection=angleBT,
|
||||
StartRadiusOfCurvature=0.0,
|
||||
EndRadiusOfCurvature=0.0,
|
||||
SegmentLength=tangent_run,
|
||||
GravityCenterLineHeight=None,
|
||||
PredefinedType="LINE",
|
||||
)
|
||||
ifcopenshell.api.alignment.create_layout_segment(file, layout, design_parameters)
|
||||
+123
@@ -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 ifcopenshell
|
||||
import ifcopenshell.api.alignment
|
||||
from ifcopenshell import entity_instance
|
||||
|
||||
import math
|
||||
from collections.abc import Sequence
|
||||
|
||||
import ifcopenshell.api.alignment.create_layout_segment
|
||||
|
||||
|
||||
def layout_vertical_alignment_by_pi_method(
|
||||
file: ifcopenshell.file, layout: entity_instance, vpoints: Sequence[Sequence[float]], lengths: Sequence[float]
|
||||
) -> None:
|
||||
"""
|
||||
Appends IfcAlignmentVerticalSegment to a previously defined IfcAlignmentVertical using the PI layout method.
|
||||
The zero length segment is updated.
|
||||
|
||||
:param file: file
|
||||
:param layout: An IfcAlignmentVertical layout
|
||||
:param vpoints: (distance_along, Z_height) pairs denoting the location of the vertical PIs, including start and end.
|
||||
:param lengths: horizontal length of parabolic vertical curves
|
||||
:return: None
|
||||
"""
|
||||
if not (len(vpoints) - 2 == len(lengths)):
|
||||
raise ValueError("lengths should have two fewer elements that vpoints")
|
||||
|
||||
xPBG, yPBG = vpoints[0]
|
||||
xPVI, yPVI = vpoints[1]
|
||||
i = 1
|
||||
for length in lengths:
|
||||
# back gradient
|
||||
dxBG = xPVI - xPBG
|
||||
dyBG = yPVI - yPBG
|
||||
start_slope = math.tan(math.atan2(dyBG, dxBG))
|
||||
|
||||
# forward gradient
|
||||
i += 1
|
||||
xPFG, yPFG = vpoints[i]
|
||||
dxFG = xPFG - xPVI
|
||||
dyFG = yPFG - yPVI
|
||||
end_slope = math.tan(math.atan2(dyFG, dxFG))
|
||||
|
||||
xEVC = xPVI + length / 2.0
|
||||
yEVC = yPVI + end_slope * length / 2.0
|
||||
|
||||
# create gradient
|
||||
gradient_length = dxBG - length / 2.0
|
||||
if 1.0e-03 < gradient_length:
|
||||
design_parameters = file.createIfcAlignmentVerticalSegment(
|
||||
StartTag=None,
|
||||
EndTag=None,
|
||||
StartDistAlong=xPBG,
|
||||
HorizontalLength=gradient_length,
|
||||
StartHeight=yPBG,
|
||||
StartGradient=start_slope,
|
||||
EndGradient=start_slope,
|
||||
RadiusOfCurvature=None,
|
||||
PredefinedType="CONSTANTGRADIENT",
|
||||
)
|
||||
ifcopenshell.api.alignment.create_layout_segment(file, layout, design_parameters)
|
||||
|
||||
# create vertical curve
|
||||
if 0.0 < length:
|
||||
k = (end_slope - start_slope) / length
|
||||
xBVC = xPVI - length / 2.0
|
||||
yBVC = yPVI - start_slope * length / 2.0
|
||||
|
||||
design_parameters = file.createIfcAlignmentVerticalSegment(
|
||||
StartTag=None,
|
||||
EndTag=None,
|
||||
StartDistAlong=xBVC,
|
||||
HorizontalLength=length,
|
||||
StartHeight=yBVC,
|
||||
StartGradient=start_slope,
|
||||
EndGradient=end_slope,
|
||||
RadiusOfCurvature=1 / k,
|
||||
PredefinedType="PARABOLICARC",
|
||||
)
|
||||
ifcopenshell.api.alignment.create_layout_segment(file, layout, design_parameters)
|
||||
|
||||
# start of next curve is end of this curve
|
||||
xPBG = xEVC
|
||||
yPBG = yEVC
|
||||
xPVI = xPFG
|
||||
yPVI = yPFG
|
||||
|
||||
# create last gradient run
|
||||
dx = xPVI - xPBG
|
||||
dy = yPVI - yPBG
|
||||
slope = math.tan(math.atan2(dy, dx))
|
||||
gradient_length = dx
|
||||
|
||||
if 1.0e-03 < gradient_length:
|
||||
design_parameters = file.createIfcAlignmentVerticalSegment(
|
||||
StartTag=None,
|
||||
EndTag=None,
|
||||
StartDistAlong=xPBG,
|
||||
HorizontalLength=gradient_length,
|
||||
StartHeight=yPBG,
|
||||
StartGradient=slope,
|
||||
EndGradient=slope,
|
||||
RadiusOfCurvature=None,
|
||||
PredefinedType="CONSTANTGRADIENT",
|
||||
)
|
||||
ifcopenshell.api.alignment.create_layout_segment(file, layout, design_parameters)
|
||||
@@ -1,68 +0,0 @@
|
||||
# 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 ifcopenshell
|
||||
import ifcopenshell.api.alignment
|
||||
from ifcopenshell import entity_instance
|
||||
|
||||
|
||||
def map_alignment_segments(
|
||||
file: ifcopenshell.file, alignment: entity_instance, composite_curve: entity_instance
|
||||
) -> None:
|
||||
"""
|
||||
Creates IfcCurveSegment entities for the supplied alignment business logic entity instance and assigns them to the composite curve.
|
||||
End-Start points of adjacent segments are evaluated and the IfcCurveSegment.Transition is set.
|
||||
|
||||
This function does not create an IfcShapeRepresentation. Use create_geometric_representation to create all the representations
|
||||
for an alignment. This function only populates the composite curve with IfcCurveSegment entities.
|
||||
|
||||
:param alignment: The business logic alignment, expected to be IfcAlignmentHorizontal, IfcAlignmentVertical, or IfcAlignmentCant
|
||||
:param composite_curve: The IfcCompositeCurve (or subclass) which will receive the IfcCurveSegment
|
||||
:return: None
|
||||
"""
|
||||
expected_types = ["IfcAlignmentHorizontal", "IfcAlignmentVertical", "IfcAlignmentCant"]
|
||||
if not alignment.is_a() in expected_types:
|
||||
raise TypeError(
|
||||
f"Expected entity type to be one of {[_ for _ in expected_types]}, instead received '{alignment.is_a()}"
|
||||
)
|
||||
|
||||
if alignment.is_a("IfcAlignmentHorizontal") and not composite_curve.is_a("IfcCompositeCurve"):
|
||||
raise TypeError(f"Expected to see IfcCompositeCurve, instead received '{composite_curve.is_a()}'.")
|
||||
elif alignment.is_a("IfcAlignmentVertical") and not composite_curve.is_a("IfcGradientCurve"):
|
||||
raise TypeError(f"Expected to see IfcGradientCurve, instead received '{composite_curve.is_a()}'.")
|
||||
elif alignment.is_a("IfcAlignmentCant") and not composite_curve.is_a("IfcSegmentedReferenceCurve"):
|
||||
raise TypeError(f"Expected to see IfcSegmentedReferenceCurve, instead received '{composite_curve.is_a()}'.")
|
||||
|
||||
composite_curve.SelfIntersect = False
|
||||
|
||||
for rel_nests in alignment.IsNestedBy:
|
||||
for layout in rel_nests.RelatedObjects:
|
||||
if layout.is_a("IfcLinearElement"):
|
||||
if alignment.is_a("IfcAlignmentHorizontal"):
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, layout)
|
||||
elif alignment.is_a("IfcAlignmentVertical"):
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_vertical_segment(file, layout)
|
||||
elif alignment.is_a("IfcAlignmentCant"):
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(
|
||||
file, layout, alignment.RailHeadDistance
|
||||
)
|
||||
else:
|
||||
assert False
|
||||
for mapped_segment in mapped_segments:
|
||||
if mapped_segment:
|
||||
ifcopenshell.api.alignment.add_segment_to_curve(file, mapped_segment, composite_curve)
|
||||
@@ -20,21 +20,21 @@ import ifcopenshell
|
||||
from ifcopenshell import entity_instance
|
||||
|
||||
|
||||
def name_segments(prefix: str, alignment: entity_instance) -> None:
|
||||
def name_segments(prefix: str, layout: entity_instance) -> None:
|
||||
"""
|
||||
Sets the segment name like ("H1" for horizontal, "V1" for vertical, "C1" for cant)
|
||||
Sets the IfcAlignmentSegment.Name attribute using a prefix and sequence number (e.g. "H1" for horizontal, "V1" for vertical, "C1" for cant)
|
||||
|
||||
:param prefix: The naming prefix
|
||||
:param alignment: The alignment whose segments are to be named. This should be a IfcAlignmentHorizontal, IfcAlignmentVertical or IfcAlignmentCant
|
||||
:param layout: The layout alignment whose segments are to be named. This should be a IfcAlignmentHorizontal, IfcAlignmentVertical or IfcAlignmentCant
|
||||
"""
|
||||
expected_types = ["IfcAlignmentHorizontal", "IfcAlignmentVertical", "IfcAlignmentCant"]
|
||||
if not alignment.is_a() in expected_types:
|
||||
if not layout.is_a() in expected_types:
|
||||
raise TypeError(
|
||||
f"Expected entity type to be one of {[_ for _ in expected_types]}, instead received '{v.is_a()}"
|
||||
f"Expected entity type to be one of {[_ for _ in expected_types]}, instead received '{layout.is_a()}"
|
||||
)
|
||||
|
||||
i = 1
|
||||
for rel in alignment.IsNestedBy:
|
||||
for rel in layout.IsNestedBy:
|
||||
for segment in rel.RelatedObjects:
|
||||
if segment.is_a("IfcAlignmentSegment"):
|
||||
segment.Name = f"{prefix}{i}"
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
# 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 ifcopenshell
|
||||
import ifcopenshell.api.alignment
|
||||
import ifcopenshell.api.nest
|
||||
import ifcopenshell.geom
|
||||
import ifcopenshell.ifcopenshell_wrapper as ifcopenshell_wrapper
|
||||
import numpy as np
|
||||
from ifcopenshell import entity_instance
|
||||
import ifcopenshell.util
|
||||
import ifcopenshell.util.element
|
||||
|
||||
|
||||
def remove_last_segment(file: ifcopenshell.file, entity: entity_instance) -> entity_instance:
|
||||
"""
|
||||
Removes the last segment from the end of entity.
|
||||
|
||||
:param entity: An IfcAlignmentHorizontal, IfcAlignmentVertical, IfcAlignmentCant or IfcCompositeCurve
|
||||
:return: The segment
|
||||
"""
|
||||
expected_types = [
|
||||
"IfcAlignmentHorizontal",
|
||||
"IfcAlignmentVertical",
|
||||
"IfcAlignmentCant",
|
||||
"IfcCompositeCurve",
|
||||
"IfcGradientCurve",
|
||||
"IfcSegmentedReferenceCurve",
|
||||
]
|
||||
if not entity.is_a() in expected_types:
|
||||
raise TypeError(
|
||||
f"Expected entity type to be one of {[_ for _ in expected_types]}, instead received '{entity.is_a()}"
|
||||
)
|
||||
|
||||
if entity.is_a("IfcCompositeCurve"):
|
||||
last_segment = entity.Segments[-1]
|
||||
entity.Segments = tuple(set(entity.Segments) - {last_segment})
|
||||
entity.Segments[-1].Transition = "DISCONTINUOUS"
|
||||
return last_segment
|
||||
else:
|
||||
components = ifcopenshell.util.element.get_components(entity)
|
||||
last_segment = components[-1]
|
||||
ifcopenshell.api.nest.unassign_object(file, (last_segment,))
|
||||
return last_segment
|
||||
@@ -123,6 +123,23 @@ def print_alignment(alignment, indent=0):
|
||||
print_alignment(child, indent + 2)
|
||||
|
||||
|
||||
def print_alignment_deep(alignment, indent=0):
|
||||
"""
|
||||
Debugging function to print alignment decomposition, including layout segments
|
||||
"""
|
||||
print(" " * indent, alignment)
|
||||
|
||||
for rel in alignment.IsNestedBy:
|
||||
for child in rel.RelatedObjects:
|
||||
print_alignment_deep(child, indent + 2)
|
||||
if child.is_a("IfcAlignmentSegment"):
|
||||
print(" " * (indent + 4), child.DesignParameters)
|
||||
|
||||
for agg in alignment.IsDecomposedBy:
|
||||
for child in agg.RelatedObjects:
|
||||
print_alignmen_deep(child, indent + 2)
|
||||
|
||||
|
||||
def print_composite_curve(curve):
|
||||
"""
|
||||
Debugging function to print composite curve segments
|
||||
@@ -131,3 +148,17 @@ def print_composite_curve(curve):
|
||||
|
||||
for segment in curve.Segments:
|
||||
print(" " * 2, segment)
|
||||
|
||||
|
||||
def print_composite_curve_deep(curve):
|
||||
"""
|
||||
Debugging function to print composite curve segments, including curve segment details
|
||||
"""
|
||||
print(str(curve)[0:100])
|
||||
|
||||
for segment in curve.Segments:
|
||||
print(" " * 2, segment)
|
||||
print(" " * 4, segment.ParentCurve)
|
||||
print(" " * 4, segment.Placement)
|
||||
print(" " * 4, segment.Placement.Location)
|
||||
print(" " * 4, segment.Placement.RefDirection)
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
# 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/>.
|
||||
|
||||
"""
|
||||
Coordinate Geometry (cogo) functions primarily for survey points and control monument for layout, parcels, etc.
|
||||
"""
|
||||
|
||||
from .add_survey_point import add_survey_point
|
||||
from .assign_survey_point import assign_survey_point
|
||||
from .edit_survey_point import edit_survey_point
|
||||
from .bearing2dd import bearing2dd
|
||||
|
||||
__all__ = [
|
||||
"add_survey_point",
|
||||
"assign_survey_point",
|
||||
"edit_survey_point",
|
||||
"bearing2dd",
|
||||
]
|
||||
@@ -0,0 +1,47 @@
|
||||
# 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 ifcopenshell
|
||||
from ifcopenshell import entity_instance
|
||||
import typing
|
||||
|
||||
def add_survey_point(file: ifcopenshell.file, survey_point: entity_instance, site:entity_instance = None) -> entity_instance:
|
||||
"""
|
||||
Adds a single survey point to the model based on IFC Concept Template 4.1.7.1.2.5.
|
||||
Survey points are located relative to IfcRepresentationContext.WorldCoordinateSystem
|
||||
|
||||
:param survey_point: The survey point
|
||||
:return: an IfcAnnotation entity
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
annotation = ifcopenshell.api.cogo.add_survey_point(file,file.createIfcCartesianPoint(4000.0,3500.0)))
|
||||
"""
|
||||
context = ifcopenshell.util.representation.get_context(file,"Model","Annotation","MODEL_VIEW")
|
||||
shape_representation = file.createIfcShapeRepresentation(ContextOfItems=context,RepresentationIdentifier='Annotation',RepresentationType='Point',Items=[survey_point])
|
||||
representation = file.createIfcProductDefinitionShape(Representations=[shape_representation])
|
||||
annotation = file.createIfcAnnotation(ifcopenshell.guid.new(),ObjectPlacement=context.WorldCoordinateSystem,Representation=representation,PredefinedType="SURVEY")
|
||||
|
||||
if (site == None):
|
||||
site = file.by_type("IfcSite")[0]
|
||||
|
||||
ifcopenshell.api.spatial.assign_container(file,relating_structure=site,products=[annotation])
|
||||
|
||||
return annotation
|
||||
@@ -0,0 +1,38 @@
|
||||
# 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 ifcopenshell
|
||||
from ifcopenshell import entity_instance
|
||||
import typing
|
||||
|
||||
def assign_survey_point(annotation: entity_instance, survey_point: entity_instance):
|
||||
"""
|
||||
Assigns a coordinate point to a survey point annotation
|
||||
|
||||
:param annotaton: The survey point annotation
|
||||
:param survey_point: The survey point
|
||||
:return: None
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
annotation = ifcopenshell.api.cogo.add_survey_point(file,file.createIfcCartesianPoint(4000.0,3500.0)))
|
||||
ifcopenshell.api.cogo.assign_surve_point(annotation,file.createIfcCartesianPoint(4000.0,3500.0,100.0))
|
||||
"""
|
||||
annotation.Representation.Representations[0].Items = [survey_point]
|
||||
@@ -0,0 +1,106 @@
|
||||
# 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 ifcopenshell.util.geolocation
|
||||
|
||||
def bearing2dd(bearing: str)->float:
|
||||
"""
|
||||
Converts a quadrant bearing string to decimal degrees
|
||||
|
||||
The format of the string is "N|S dd (mm (ss.s)) E|W"
|
||||
where:
|
||||
N|S is N or S for North or South
|
||||
dd is degree (required)
|
||||
mm is minute (optional, but required if second is provided)
|
||||
ss.s is second (required)
|
||||
E|W is E or W for East or West
|
||||
|
||||
:param str: the bearing string
|
||||
:return: Angle in radian
|
||||
"""
|
||||
error_msg = "Invalid bearing string"
|
||||
|
||||
bearing = bearing.strip() # trim external white space
|
||||
bearing = ' '.join(bearing.split()) # make sure all parts separated by a single space
|
||||
parts = bearing.split()
|
||||
nParts = len(parts)
|
||||
if nParts < 3 or 5 < nParts:
|
||||
raise ValueError(error_msg)
|
||||
|
||||
cY = parts[0]
|
||||
cY = cY.upper()
|
||||
if cY != 'N' and cY != 'S':
|
||||
raise ValueError(error_msg)
|
||||
|
||||
cX = parts[-1]
|
||||
cX = cX.upper()
|
||||
if cX != 'E' and cX != 'W':
|
||||
raise ValueError(error_msg)
|
||||
|
||||
d = 0
|
||||
m = 0
|
||||
s = 0.
|
||||
ms = 0
|
||||
|
||||
if nParts == 3:
|
||||
d = int(parts[1])
|
||||
elif nParts == 4:
|
||||
d = int(parts[1])
|
||||
m = int(parts[2])
|
||||
elif nParts == 5:
|
||||
d = int(parts[1])
|
||||
m = int(parts[2])
|
||||
s = float(parts[3])
|
||||
|
||||
# s in a decimal number
|
||||
# need to break it into whole seconds and milliseconds
|
||||
ms = 100.*(s - int(s))
|
||||
s = int(s)
|
||||
|
||||
if d < 0 or (m < 0 or 60 <= m) or (s < 0 or 60 <= s) or ms < 0:
|
||||
raise ValueError(error_msg)
|
||||
|
||||
if cY == 'N' and cX == 'E':
|
||||
angle = 90.
|
||||
sign = -1.
|
||||
elif cY == 'N' and cX == 'W':
|
||||
angle = 90.
|
||||
sign = 1.
|
||||
elif cY == 'S' and cX == 'E':
|
||||
angle = 270.
|
||||
sign = 1.
|
||||
elif cY == 'S' and cX == 'W':
|
||||
angle = 270.
|
||||
sign = -1.
|
||||
|
||||
try:
|
||||
dms = ifcopenshell.util.geolocation.dms2dd(d,m,s,ms)
|
||||
except ValueError:
|
||||
raise ValueError(error_msg)
|
||||
|
||||
if dms < 0. or 90. < dms:
|
||||
raise ValueError(error_msg)
|
||||
|
||||
angle += sign*dms
|
||||
|
||||
# S 90 E will evaluate to 360
|
||||
if angle == 360.:
|
||||
angle = 0.
|
||||
|
||||
return angle
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
# 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 ifcopenshell
|
||||
from ifcopenshell import entity_instance
|
||||
import typing
|
||||
|
||||
def edit_survey_point(annotation: entity_instance, x:float,y:float,z:float=0.0):
|
||||
"""
|
||||
Edits the location of a previously defined survey point
|
||||
|
||||
:param survey_point: The survey point
|
||||
:return: None
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
annotation = ifcopenshell.api.cogo.add_survey_point(file,file.createIfcCartesianPoint(4000.0,3500.0)))
|
||||
ifcopenshell.api.cogo.edit_surve_point(annotation,3500.0,2000.0)
|
||||
"""
|
||||
if annotation.Representation.Representations[0].Items[0].Dim == 2:
|
||||
annotation.Representation.Representations[0].Items[0].Coordinates = ((x,y))
|
||||
else:
|
||||
annotation.Representation.Representations[0].Items[0].Coordinates = ((x,y,z))
|
||||
@@ -17,15 +17,29 @@
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import math
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.unit
|
||||
|
||||
def station_as_string(file: ifcopenshell.file, sta: float):
|
||||
"""
|
||||
Returns a stringized version of a station. Example 100.0 is 1+00.00 as a stationing string.
|
||||
If the project units are SI-based, the string is in the format xxx+yyy.zzz
|
||||
If the project units are Emperial-based, the string is in the format xx+yy.zz
|
||||
:param station: the station to be stringized
|
||||
:return: stringized station
|
||||
"""
|
||||
|
||||
unit_type = ifcopenshell.util.unit.get_project_unit(file,"LENGTHUNIT")
|
||||
if unit_type.is_a("IfcConversionBasedUnit"):
|
||||
station = ifcopenshell.util.unit.convert(sta,from_unit=unit_type.Name,from_prefix=None,to_unit="foot",to_prefix=None)
|
||||
plus_seperator = 2
|
||||
precision = 2
|
||||
else:
|
||||
station = ifcopenshell.util.unit.convert(sta,from_unit=unit_type.Name,from_prefix=unit_type.Prefix,to_unit="meter",to_prefix=None)
|
||||
plus_seperator = 3
|
||||
precision = 3
|
||||
|
||||
|
||||
def station_as_string(station: float, plus_seperator=3, accuracy=3):
|
||||
"""
|
||||
Returns a stringized version of a station. Example 100.0 is 1+00.00 as a stationing string
|
||||
@param station: the station to be stringized
|
||||
@param plus_seperator: location of the '+' symbol relative to the decimal place (typically 2 for US units and 3 for SI units)
|
||||
@param accuracy: number of digits following the decimal place
|
||||
"""
|
||||
value = math.fabs(station)
|
||||
|
||||
shifter = math.pow(10.0, plus_seperator)
|
||||
@@ -34,13 +48,13 @@ def station_as_string(station: float, plus_seperator=3, accuracy=3):
|
||||
|
||||
# Check to make sure that v2 is not basically the same as shifter
|
||||
# If station = 69500.00000, we sometimes get 694+100.00 instead of 695+00.00
|
||||
if math.isclose(v2 - shifter, 5.0 * math.pow(10.0, -(accuracy + 1))):
|
||||
if math.isclose(v2-shifter, 0., abs_tol=5.0 * math.pow(10.0, -(precision + 1))):
|
||||
v2 = 0.0
|
||||
v1 += 1
|
||||
|
||||
v1 = -1 * v1 if station < 0 else v1
|
||||
|
||||
station_string = "{:d}+{:0{}.{}f}".format(v1, v2, plus_seperator + accuracy + 1, accuracy)
|
||||
station_string = "{:d}+{:0{}.{}f}".format(v1, v2, plus_seperator + precision + 1, precision)
|
||||
|
||||
# special case when v1 is 0 and station is negative, the string above doesn't get the leading
|
||||
# negative sign. this snippet fixes that
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
# 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")
|
||||
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
|
||||
@@ -20,10 +20,13 @@ import pytest
|
||||
import ifcopenshell.api.alignment
|
||||
import ifcopenshell.api.context
|
||||
|
||||
from ifcopenshell.api.alignment._add_segment_to_layout import _add_segment_to_layout
|
||||
|
||||
def test_add_segment_to_layout():
|
||||
file = ifcopenshell.file(schema="IFC4X3")
|
||||
project = file.createIfcProject(Name="Test")
|
||||
project = file.createIfcProject(GlobalId=ifcopenshell.guid.new(),Name="Test")
|
||||
length = ifcopenshell.api.unit.add_si_unit(file,unit_type="LENGTHUNIT")
|
||||
ifcopenshell.api.unit.assign_unit(file,units=[length])
|
||||
geometric_representation_context = ifcopenshell.api.context.add_context(file, context_type="Model")
|
||||
axis_model_representation_subcontext = ifcopenshell.api.context.add_context(
|
||||
file,
|
||||
@@ -33,16 +36,8 @@ def test_add_segment_to_layout():
|
||||
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,
|
||||
)
|
||||
alignment = ifcopenshell.api.alignment.create(file,"")
|
||||
horizontal_alignment = ifcopenshell.api.alignment.get_horizontal_layout(alignment)
|
||||
|
||||
design_parameters = file.create_entity(
|
||||
type="IfcAlignmentHorizontalSegment",
|
||||
@@ -68,8 +63,9 @@ def test_add_segment_to_layout():
|
||||
DesignParameters=design_parameters,
|
||||
)
|
||||
|
||||
ifcopenshell.api.alignment.add_segment_to_layout(file, horizontal_alignment, alignment_segment)
|
||||
_add_segment_to_layout(file, horizontal_alignment, alignment_segment)
|
||||
|
||||
assert len(horizontal_alignment.IsNestedBy) == 1
|
||||
assert len(horizontal_alignment.IsNestedBy[0].RelatedObjects) == 1
|
||||
assert len(horizontal_alignment.IsNestedBy[0].RelatedObjects) == 2 # The the segment we added and the automatically created zero length segment
|
||||
assert horizontal_alignment.IsNestedBy[0].RelatedObjects[0] == alignment_segment
|
||||
assert alignment_segment.IsNestedBy[0].RelatedObjects[0].is_a("IfcReferent") # a referent is automatically added at the start of the segment
|
||||
|
||||
@@ -21,10 +21,11 @@ import ifcopenshell.api.alignment
|
||||
import ifcopenshell.api.context
|
||||
import ifcopenshell.util.element
|
||||
|
||||
|
||||
def test_add_stationing_to_alignment():
|
||||
file = ifcopenshell.file(schema="IFC4X3")
|
||||
project = file.createIfcProject(Name="Test")
|
||||
project = file.createIfcProject(GlobalId=ifcopenshell.guid.new(),Name="Test")
|
||||
length = ifcopenshell.api.unit.add_si_unit(file,unit_type="LENGTHUNIT")
|
||||
ifcopenshell.api.unit.assign_unit(file,units=[length])
|
||||
geometric_representation_context = ifcopenshell.api.context.add_context(file, context_type="Model")
|
||||
axis_model_representation_subcontext = ifcopenshell.api.context.add_context(
|
||||
file,
|
||||
@@ -34,17 +35,9 @@ def test_add_stationing_to_alignment():
|
||||
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
|
||||
alignment = ifcopenshell.api.alignment.create(
|
||||
file, "TestAlignment", start_station=2000.
|
||||
)
|
||||
ifcopenshell.api.alignment.create_geometric_representation(file, alignment)
|
||||
|
||||
ifcopenshell.api.alignment.add_stationing_to_alignment(file, alignment, 2000.0)
|
||||
|
||||
for rel in alignment.IsNestedBy:
|
||||
for referent in rel.RelatedObjects:
|
||||
|
||||
+30
-26
@@ -21,9 +21,11 @@ import ifcopenshell.api.alignment
|
||||
import ifcopenshell.api.context
|
||||
|
||||
|
||||
def test_add_vertical_by_pi_method():
|
||||
def test_add_vertical_alignment():
|
||||
file = ifcopenshell.file(schema="IFC4X3")
|
||||
project = file.createIfcProject(Name="Test")
|
||||
project = file.createIfcProject(GlobalId=ifcopenshell.guid.new(),Name="Test")
|
||||
length = ifcopenshell.api.unit.add_si_unit(file,unit_type="LENGTHUNIT")
|
||||
ifcopenshell.api.unit.assign_unit(file,units=[length])
|
||||
geometric_representation_context = ifcopenshell.api.context.add_context(file, context_type="Model")
|
||||
axis_model_representation_subcontext = ifcopenshell.api.context.add_context(
|
||||
file,
|
||||
@@ -33,42 +35,44 @@ def test_add_vertical_by_pi_method():
|
||||
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)
|
||||
alignment = ifcopenshell.api.alignment.create(file,"A1",include_vertical=False)
|
||||
|
||||
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
|
||||
assert len(alignment.IsNestedBy) == 1 # one nest
|
||||
assert len(alignment.IsNestedBy[0].RelatedObjects) == 2 # nesting IfcReferent, IfcAlignmentHorizontal
|
||||
assert alignment.IsNestedBy[0].RelatedObjects[0].is_a("IfcReferent")
|
||||
assert alignment.IsNestedBy[0].RelatedObjects[1].is_a("IfcAlignmentHorizontal")
|
||||
curve = ifcopenshell.api.alignment.get_curve(alignment)
|
||||
assert curve.is_a("IfcCompositeCurve")
|
||||
|
||||
vertical_layout = ifcopenshell.api.alignment.add_vertical_layout(file,alignment)
|
||||
|
||||
# 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")
|
||||
assert len(alignment.IsNestedBy) == 1 # one nest
|
||||
assert len(alignment.IsNestedBy[0].RelatedObjects) == 3 # nesting IfcReferent, IfcAlignmentHorizontal, IfcAlignmentVertical
|
||||
assert alignment.IsNestedBy[0].RelatedObjects[0].is_a("IfcReferent")
|
||||
assert alignment.IsNestedBy[0].RelatedObjects[1].is_a("IfcAlignmentHorizontal")
|
||||
assert alignment.IsNestedBy[0].RelatedObjects[2].is_a("IfcAlignmentVertical")
|
||||
curve = ifcopenshell.api.alignment.get_curve(alignment)
|
||||
assert curve.is_a("IfcGradientCurve")
|
||||
|
||||
# add a second vertical alignment
|
||||
vertical_layout = ifcopenshell.api.alignment.add_vertical_layout(file,alignment)
|
||||
|
||||
# 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")
|
||||
assert len(alignment.IsNestedBy[0].RelatedObjects) == 2 # nesting IfcReferent and IfcAlignmentHorizontal
|
||||
assert alignment.IsNestedBy[0].RelatedObjects[0].is_a("IfcReferent")
|
||||
assert alignment.IsNestedBy[0].RelatedObjects[1].is_a("IfcAlignmentHorizontal")
|
||||
|
||||
test_add_vertical_alignment()
|
||||
@@ -0,0 +1,69 @@
|
||||
# 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.get_layout_segments
|
||||
import ifcopenshell.api.context
|
||||
|
||||
|
||||
def test_create_alignment():
|
||||
file = ifcopenshell.file(schema="IFC4X3_ADD2")
|
||||
project = file.createIfcProject(GlobalId=ifcopenshell.guid.new(),Name="Test")
|
||||
length = ifcopenshell.api.unit.add_si_unit(file,unit_type="LENGTHUNIT")
|
||||
ifcopenshell.api.unit.assign_unit(file,units=[length])
|
||||
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,
|
||||
)
|
||||
|
||||
include_vertical = [False,True,True]
|
||||
include_cant = [False, False, True]
|
||||
expected_curve_type = ["IfcCompositeCurve","IfcGradientCurve","IfcSegmentedReferenceCurve"]
|
||||
|
||||
for i in range(0,3) :
|
||||
ali = ifcopenshell.api.alignment.create(file,"A1",include_vertical[i],include_cant[i])
|
||||
assert ali != None
|
||||
|
||||
# verify the geometric representation was created
|
||||
curve = ifcopenshell.api.alignment.get_curve(ali)
|
||||
assert(curve.is_a() == expected_curve_type[i])
|
||||
assert len(curve.Segments) == 1
|
||||
|
||||
horiz = ifcopenshell.api.alignment.get_horizontal_layout(ali)
|
||||
vert = ifcopenshell.api.alignment.get_vertical_layout(ali)
|
||||
cant = ifcopenshell.api.alignment.get_cant_layout(ali)
|
||||
|
||||
assert horiz != None
|
||||
if include_vertical[i]:
|
||||
assert vert != None
|
||||
|
||||
if include_cant[i]:
|
||||
assert cant != None
|
||||
|
||||
# verify each layout has a zero length segment (which also tests if the geometry curve has a zero length segment)
|
||||
alignments = [horiz,vert,cant]
|
||||
for a in alignments:
|
||||
if a != None:
|
||||
segments = ifcopenshell.api.alignment.get_layout_segments(a)
|
||||
assert len(segments) == 1
|
||||
assert ifcopenshell.api.alignment.has_zero_length_segment(a) # there is a check in this function for the geometry curve
|
||||
@@ -0,0 +1,57 @@
|
||||
# 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_create_alignment_pi_method():
|
||||
file = ifcopenshell.file(schema="IFC4X3")
|
||||
project = file.createIfcProject(GlobalId=ifcopenshell.guid.new(),Name="Test")
|
||||
length = ifcopenshell.api.unit.add_conversion_based_unit(file,name="foot")
|
||||
ifcopenshell.api.unit.assign_unit(file,units=[length])
|
||||
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_by_pi_method(file, "TestAlignment", coordinates, radii, vpoints, lengths)
|
||||
|
||||
assert len(alignment.IsDecomposedBy) == 0 # no child alignments
|
||||
assert len(alignment.IsNestedBy) == 1 # one nest
|
||||
assert len(alignment.IsNestedBy[0].RelatedObjects) == 3 # nesting IfcReferent, IfcAlignmentHorizontal, IfcAlignmentVertical
|
||||
assert alignment.IsNestedBy[0].RelatedObjects[0].is_a("IfcReferent")
|
||||
assert alignment.IsNestedBy[0].RelatedObjects[1].is_a("IfcAlignmentHorizontal")
|
||||
assert alignment.IsNestedBy[0].RelatedObjects[2].is_a("IfcAlignmentVertical")
|
||||
assert (
|
||||
len(alignment.IsNestedBy[0].RelatedObjects[1].IsNestedBy) == 1
|
||||
) # nesting of segments beneath IfcAlignmentHorizontal
|
||||
assert len(alignment.IsNestedBy[0].RelatedObjects[1].IsNestedBy[0].RelatedObjects) == 8 # segments in horizontal layout
|
||||
assert len(alignment.IsNestedBy[0].RelatedObjects[2].IsNestedBy[0].RelatedObjects) == 10 # segments in vertical layout
|
||||
|
||||
test_create_alignment_pi_method()
|
||||
@@ -0,0 +1,275 @@
|
||||
# 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
|
||||
from ifcopenshell import entity_instance
|
||||
import math
|
||||
|
||||
def _test_horizontal() -> ifcopenshell.file:
|
||||
file = ifcopenshell.file(schema="IFC4X3_ADD2")
|
||||
project = file.createIfcProject(GlobalId=ifcopenshell.guid.new(),Name="Test")
|
||||
length = ifcopenshell.api.unit.add_si_unit(file,unit_type="LENGTHUNIT")
|
||||
ifcopenshell.api.unit.assign_unit(file,units=[length])
|
||||
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,
|
||||
)
|
||||
|
||||
# creates an IfcAlignment with an IfcAlignmentHorizontal layout containing only the zero length segment
|
||||
ali = ifcopenshell.api.alignment.create(file,"A1")
|
||||
|
||||
# append a segment to the horizontal layout
|
||||
horizontal_alignment = ifcopenshell.api.alignment.get_horizontal_layout(ali)
|
||||
|
||||
curve = ifcopenshell.api.alignment.get_curve(horizontal_alignment)
|
||||
assert curve == None # for single horizontal, geometric representation is on IfcAlignment
|
||||
curve = ifcopenshell.api.alignment.get_curve(ali)
|
||||
assert curve.is_a("IfcCompositeCurve")
|
||||
assert len(curve.Segments) == 1
|
||||
|
||||
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",
|
||||
)
|
||||
end = ifcopenshell.api.alignment.create_layout_segment(file,horizontal_alignment,design_parameters)
|
||||
|
||||
assert len(horizontal_alignment.IsNestedBy[0].RelatedObjects) == 2
|
||||
|
||||
x = end[0,3]
|
||||
y = end[1,3]
|
||||
z = end[2,3]
|
||||
|
||||
assert x == 100.0
|
||||
assert y == 0.0
|
||||
assert z == 0.0
|
||||
|
||||
curve = ifcopenshell.api.alignment.get_curve(ali)
|
||||
assert curve.is_a("IfcCompositeCurve")
|
||||
assert len(curve.Segments) == 2
|
||||
|
||||
|
||||
design_parameters = file.create_entity(
|
||||
type="IfcAlignmentHorizontalSegment",
|
||||
StartTag=None,
|
||||
EndTag=None,
|
||||
StartPoint=file.createIfcCartesianPoint(Coordinates=((x.item(), y.item()))),
|
||||
StartDirection=math.pi/6,
|
||||
StartRadiusOfCurvature=0.0,
|
||||
EndRadiusOfCurvature=0.0,
|
||||
SegmentLength=50.0,
|
||||
GravityCenterLineHeight=None,
|
||||
PredefinedType="LINE",
|
||||
)
|
||||
|
||||
end = ifcopenshell.api.alignment.create_layout_segment(file,horizontal_alignment,design_parameters)
|
||||
assert len(horizontal_alignment.IsNestedBy[0].RelatedObjects) == 3
|
||||
|
||||
x = end[0,3]
|
||||
y = end[1,3]
|
||||
z = end[2,3]
|
||||
|
||||
assert x == 100.0 + 50.0*math.cos(math.pi/6)
|
||||
assert y == 50.0*math.sin(math.pi/6)
|
||||
assert z == 0.0
|
||||
|
||||
curve = ifcopenshell.api.alignment.get_curve(ali)
|
||||
assert curve.is_a("IfcCompositeCurve")
|
||||
assert len(curve.Segments) == 3
|
||||
|
||||
return file
|
||||
|
||||
|
||||
def _test_horizontal_vertical():
|
||||
file = ifcopenshell.file(schema="IFC4X3_ADD2")
|
||||
project = file.createIfcProject(GlobalId=ifcopenshell.guid.new(),Name="Test")
|
||||
length = ifcopenshell.api.unit.add_si_unit(file,unit_type="LENGTHUNIT")
|
||||
ifcopenshell.api.unit.assign_unit(file,units=[length])
|
||||
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,
|
||||
)
|
||||
|
||||
# creates an IfcAlignment with an IfcAlignmentHorizontal layout containing only the zero length segment
|
||||
ali = ifcopenshell.api.alignment.create(file,"A1",True)
|
||||
|
||||
# append a segment to the horizontal layout
|
||||
horizontal_alignment = ifcopenshell.api.alignment.get_horizontal_layout(ali)
|
||||
vertical_alignment = ifcopenshell.api.alignment.get_vertical_layout(ali)
|
||||
|
||||
curve = ifcopenshell.api.alignment.get_curve(horizontal_alignment)
|
||||
assert curve == None
|
||||
|
||||
curve = ifcopenshell.api.alignment.get_curve(vertical_alignment)
|
||||
assert curve == None
|
||||
|
||||
basis_curve = ifcopenshell.api.alignment.get_basis_curve(ali)
|
||||
assert basis_curve.is_a("IfcCompositeCurve")
|
||||
curve = ifcopenshell.api.alignment.get_curve(ali)
|
||||
assert curve.is_a("IfcGradientCurve")
|
||||
assert len(basis_curve.Segments) == 1
|
||||
assert len(curve.Segments) == 1
|
||||
|
||||
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",
|
||||
)
|
||||
end = ifcopenshell.api.alignment.create_layout_segment(file,horizontal_alignment,design_parameters)
|
||||
basis_curve = ifcopenshell.api.alignment.get_basis_curve(ali)
|
||||
assert basis_curve.is_a("IfcCompositeCurve")
|
||||
assert len(basis_curve.Segments) == 2
|
||||
|
||||
design_parameters = file.createIfcAlignmentVerticalSegment(
|
||||
StartDistAlong=0.0,
|
||||
HorizontalLength=50.0,
|
||||
StartHeight=20.0,
|
||||
StartGradient = 1./100.,
|
||||
EndGradient = 1./100.,
|
||||
PredefinedType="CONSTANTGRADIENT"
|
||||
)
|
||||
end = ifcopenshell.api.alignment.create_layout_segment(file,vertical_alignment,design_parameters)
|
||||
|
||||
assert len(vertical_alignment.IsNestedBy[0].RelatedObjects) == 2
|
||||
|
||||
x = end[0,3]
|
||||
y = end[1,3]
|
||||
z = end[2,3]
|
||||
|
||||
assert x == 50.
|
||||
assert y == 20.5
|
||||
assert z == 0.0
|
||||
|
||||
dx = end[0,0]
|
||||
dy = end[1,0]
|
||||
gradient = dy/dx
|
||||
|
||||
design_parameters = file.createIfcAlignmentVerticalSegment(
|
||||
StartDistAlong=50.0,
|
||||
HorizontalLength=50.0,
|
||||
StartHeight=y.item(),
|
||||
StartGradient = -gradient,
|
||||
EndGradient = -gradient,
|
||||
PredefinedType="CONSTANTGRADIENT"
|
||||
)
|
||||
end = ifcopenshell.api.alignment.create_layout_segment(file,vertical_alignment,design_parameters)
|
||||
|
||||
assert len(vertical_alignment.IsNestedBy[0].RelatedObjects) == 3
|
||||
|
||||
x = end[0,3]
|
||||
y = end[1,3]
|
||||
z = end[2,3]
|
||||
|
||||
assert x == 100.
|
||||
assert y == 20.
|
||||
assert z == 0.0
|
||||
|
||||
basis_curve = ifcopenshell.api.alignment.get_basis_curve(ali)
|
||||
assert basis_curve.is_a("IfcCompositeCurve")
|
||||
curve = ifcopenshell.api.alignment.get_curve(ali)
|
||||
assert curve.is_a("IfcGradientCurve")
|
||||
assert len(basis_curve.Segments) == 2
|
||||
assert len(curve.Segments) == 3
|
||||
|
||||
|
||||
def _test_horizontal_vertical2(file: ifcopenshell.file):
|
||||
ali = file.by_type("IfcAlignment")[0]
|
||||
|
||||
vertical_alignment = ifcopenshell.api.alignment.get_vertical_layout(ali)
|
||||
assert vertical_alignment == None
|
||||
|
||||
vertical_alignment = ifcopenshell.api.alignment.add_vertical_layout(file,ali)
|
||||
|
||||
design_parameters = file.createIfcAlignmentVerticalSegment(
|
||||
StartDistAlong=0.0,
|
||||
HorizontalLength=50.0,
|
||||
StartHeight=20.0,
|
||||
StartGradient = 1./100.,
|
||||
EndGradient = 1./100.,
|
||||
PredefinedType="CONSTANTGRADIENT"
|
||||
)
|
||||
end = ifcopenshell.api.alignment.create_layout_segment(file,vertical_alignment,design_parameters)
|
||||
|
||||
assert len(vertical_alignment.IsNestedBy[0].RelatedObjects) == 2
|
||||
|
||||
x = end[0,3]
|
||||
y = end[1,3]
|
||||
z = end[2,3]
|
||||
|
||||
assert x == 50.
|
||||
assert y == 20.5
|
||||
assert z == 0.0
|
||||
|
||||
dx = end[0,0]
|
||||
dy = end[1,0]
|
||||
gradient = dy/dx
|
||||
|
||||
design_parameters = file.createIfcAlignmentVerticalSegment(
|
||||
StartDistAlong=50.0,
|
||||
HorizontalLength=50.0,
|
||||
StartHeight=y.item(),
|
||||
StartGradient = -gradient,
|
||||
EndGradient = -gradient,
|
||||
PredefinedType="CONSTANTGRADIENT"
|
||||
)
|
||||
end = ifcopenshell.api.alignment.create_layout_segment(file,vertical_alignment,design_parameters)
|
||||
|
||||
assert len(vertical_alignment.IsNestedBy[0].RelatedObjects) == 3
|
||||
|
||||
x = end[0,3]
|
||||
y = end[1,3]
|
||||
z = end[2,3]
|
||||
|
||||
assert x == 100.
|
||||
assert y == 20.
|
||||
assert z == 0.0
|
||||
|
||||
curve = ifcopenshell.api.alignment.get_curve(ali)
|
||||
assert curve.is_a("IfcGradientCurve")
|
||||
assert len(curve.Segments) == 3
|
||||
|
||||
def test_append_segment():
|
||||
file = _test_horizontal()
|
||||
_test_horizontal_vertical()
|
||||
_test_horizontal_vertical2(file)
|
||||
|
||||
test_append_segment()
|
||||
@@ -20,10 +20,11 @@ import pytest
|
||||
import ifcopenshell.api.alignment
|
||||
import ifcopenshell.api.context
|
||||
|
||||
|
||||
def test_add_stationing_to_alignment():
|
||||
def test_distance_along_from_station():
|
||||
file = ifcopenshell.file(schema="IFC4X3")
|
||||
project = file.createIfcProject(Name="Test")
|
||||
project = file.createIfcProject(GlobalId=ifcopenshell.guid.new(),Name="Test")
|
||||
length = ifcopenshell.api.unit.add_conversion_based_unit(file,name="foot")
|
||||
ifcopenshell.api.unit.assign_unit(file,units=[length])
|
||||
geometric_representation_context = ifcopenshell.api.context.add_context(file, context_type="Model")
|
||||
axis_model_representation_subcontext = ifcopenshell.api.context.add_context(
|
||||
file,
|
||||
@@ -38,18 +39,15 @@ def test_add_stationing_to_alignment():
|
||||
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
|
||||
alignment = ifcopenshell.api.alignment.create_by_pi_method(
|
||||
file, "TestAlignment", coordinates, radii, vpoints, lengths,start_station=10000.0
|
||||
)
|
||||
|
||||
# test alignment without stationing referent
|
||||
assert ifcopenshell.api.alignment.distance_along_from_station(file, alignment, 500.0) == pytest.approx(500.0)
|
||||
|
||||
# add stationing referent
|
||||
ifcopenshell.api.alignment.add_stationing_to_alignment(file, alignment, 10000.0)
|
||||
|
||||
# Station 138+83.96
|
||||
assert ifcopenshell.api.alignment.distance_along_from_station(file, alignment, 13883.96) == pytest.approx(3883.96)
|
||||
|
||||
# Station 175+25.36
|
||||
assert ifcopenshell.api.alignment.distance_along_from_station(file, alignment, 17525.36) == pytest.approx(7525.36)
|
||||
|
||||
|
||||
test_distance_along_from_station()
|
||||
@@ -0,0 +1,54 @@
|
||||
# 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_get_alignment():
|
||||
file = ifcopenshell.file(schema="IFC4X3_ADD2")
|
||||
project = file.createIfcProject(GlobalId=ifcopenshell.guid.new(),Name="Test")
|
||||
length = ifcopenshell.api.unit.add_si_unit(file,unit_type="LENGTHUNIT")
|
||||
ifcopenshell.api.unit.assign_unit(file,units=[length])
|
||||
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,
|
||||
)
|
||||
|
||||
include_vertical = [False,True,True]
|
||||
include_cant = [False, False, True]
|
||||
|
||||
for i in range(0,3) :
|
||||
ali = ifcopenshell.api.alignment.create(file,"A1",include_vertical[i],include_cant[i])
|
||||
assert ali != None
|
||||
|
||||
horiz = ifcopenshell.api.alignment.get_horizontal_layout(ali)
|
||||
vert = ifcopenshell.api.alignment.get_vertical_layout(ali)
|
||||
cant = ifcopenshell.api.alignment.get_cant_layout(ali)
|
||||
|
||||
assert ali == ifcopenshell.api.alignment.get_alignment(horiz)
|
||||
if include_vertical[i]:
|
||||
assert ali == ifcopenshell.api.alignment.get_alignment(vert)
|
||||
|
||||
if include_cant[i]:
|
||||
assert ali == ifcopenshell.api.alignment.get_alignment(cant)
|
||||
@@ -18,15 +18,15 @@
|
||||
|
||||
import pytest
|
||||
|
||||
# import test.bootstrap
|
||||
import ifcopenshell.api.alignment
|
||||
import ifcopenshell.api.context
|
||||
|
||||
|
||||
# class TestGetBasisCurve(test.bootstrap.IFC4X3):
|
||||
def test_horizontal():
|
||||
def _test_horizontal():
|
||||
file = ifcopenshell.file(schema="IFC4X3")
|
||||
project = file.createIfcProject(Name="Test")
|
||||
project = file.createIfcProject(GlobalId=ifcopenshell.guid.new(),Name="Test")
|
||||
length = ifcopenshell.api.unit.add_si_unit(file,unit_type="LENGTHUNIT")
|
||||
ifcopenshell.api.unit.assign_unit(file,units=[length])
|
||||
geometric_representation_context = ifcopenshell.api.context.add_context(file, context_type="Model")
|
||||
axis_model_representation_subcontext = ifcopenshell.api.context.add_context(
|
||||
file,
|
||||
@@ -36,18 +36,16 @@ def test_horizontal():
|
||||
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)
|
||||
alignment = ifcopenshell.api.alignment.create(file, "TestAlignment")
|
||||
basis_curve = ifcopenshell.api.alignment.get_basis_curve(alignment)
|
||||
assert basis_curve.is_a("IfcCompositeCurve")
|
||||
|
||||
|
||||
def test_horizontal_and_vertical():
|
||||
def _test_horizontal_and_vertical():
|
||||
file = ifcopenshell.file(schema="IFC4X3")
|
||||
project = file.createIfcProject(Name="Test")
|
||||
project = file.createIfcProject(GlobalId=ifcopenshell.guid.new(),Name="Test")
|
||||
length = ifcopenshell.api.unit.add_si_unit(file,unit_type="LENGTHUNIT")
|
||||
ifcopenshell.api.unit.assign_unit(file,units=[length])
|
||||
geometric_representation_context = ifcopenshell.api.context.add_context(file, context_type="Model")
|
||||
axis_model_representation_subcontext = ifcopenshell.api.context.add_context(
|
||||
file,
|
||||
@@ -57,14 +55,33 @@ def test_horizontal_and_vertical():
|
||||
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
|
||||
alignment = ifcopenshell.api.alignment.create(
|
||||
file, "TestAlignment", include_vertical=True
|
||||
)
|
||||
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_and_cant():
|
||||
file = ifcopenshell.file(schema="IFC4X3")
|
||||
project = file.createIfcProject(GlobalId=ifcopenshell.guid.new(),Name="Test")
|
||||
length = ifcopenshell.api.unit.add_si_unit(file,unit_type="LENGTHUNIT")
|
||||
ifcopenshell.api.unit.assign_unit(file,units=[length])
|
||||
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,
|
||||
)
|
||||
|
||||
alignment = ifcopenshell.api.alignment.create(
|
||||
file, "TestAlignment", include_vertical=True,include_cant=True
|
||||
)
|
||||
basis_curve = ifcopenshell.api.alignment.get_basis_curve(alignment)
|
||||
assert basis_curve.is_a("IfcCompositeCurve")
|
||||
|
||||
def test_get_basis_curve():
|
||||
_test_horizontal()
|
||||
_test_horizontal_and_vertical()
|
||||
_test_horizontal_and_vertical_and_cant()
|
||||
|
||||
@@ -16,17 +16,13 @@
|
||||
# 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():
|
||||
def test_get_curve():
|
||||
file = ifcopenshell.file(schema="IFC4X3")
|
||||
project = file.createIfcProject(Name="Test")
|
||||
project = file.createIfcProject(GlobalId=ifcopenshell.guid.new(),Name="Test")
|
||||
length = ifcopenshell.api.unit.add_si_unit(file,unit_type="LENGTHUNIT")
|
||||
ifcopenshell.api.unit.assign_unit(file,units=[length])
|
||||
geometric_representation_context = ifcopenshell.api.context.add_context(file, context_type="Model")
|
||||
axis_model_representation_subcontext = ifcopenshell.api.context.add_context(
|
||||
file,
|
||||
@@ -36,35 +32,14 @@ def test_horizontal():
|
||||
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)
|
||||
alignment = ifcopenshell.api.alignment.create(file, "TestAlignment",include_vertical=False,include_cant=False)
|
||||
curve = ifcopenshell.api.alignment.get_curve(alignment)
|
||||
assert curve.is_a("IfcCompositeCurve")
|
||||
|
||||
|
||||
def test_horizontal_and_vertical():
|
||||
file = ifcopenshell.file(schema="IFC4X3")
|
||||
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)
|
||||
alignment = ifcopenshell.api.alignment.create(file, "TestAlignment",include_vertical=True,include_cant=False)
|
||||
curve = ifcopenshell.api.alignment.get_curve(alignment)
|
||||
assert curve.is_a("IfcGradientCurve")
|
||||
|
||||
alignment = ifcopenshell.api.alignment.create(file, "TestAlignment",include_vertical=True,include_cant=True)
|
||||
curve = ifcopenshell.api.alignment.get_curve(alignment)
|
||||
assert curve.is_a("IfcSegmentedReferenceCurve")
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
# 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 ifcopenshell.api.alignment
|
||||
|
||||
def test_get_layout_curve():
|
||||
file = ifcopenshell.file(schema="IFC4X3")
|
||||
project = file.createIfcProject(GlobalId=ifcopenshell.guid.new(),Name="Test")
|
||||
length = ifcopenshell.api.unit.add_si_unit(file,unit_type="LENGTHUNIT")
|
||||
ifcopenshell.api.unit.assign_unit(file,units=[length])
|
||||
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,
|
||||
)
|
||||
|
||||
alignment = ifcopenshell.api.alignment.create(file, "TestAlignment",include_vertical=False,include_cant=False)
|
||||
layout = ifcopenshell.api.alignment.get_horizontal_layout(alignment)
|
||||
curve = ifcopenshell.api.alignment.get_layout_curve(layout)
|
||||
assert curve.is_a("IfcCompositeCurve")
|
||||
|
||||
alignment = ifcopenshell.api.alignment.create(file, "TestAlignment",include_vertical=True,include_cant=False)
|
||||
layout = ifcopenshell.api.alignment.get_horizontal_layout(alignment)
|
||||
curve = ifcopenshell.api.alignment.get_layout_curve(layout)
|
||||
assert curve.is_a("IfcCompositeCurve")
|
||||
layout = ifcopenshell.api.alignment.get_vertical_layout(alignment)
|
||||
curve = ifcopenshell.api.alignment.get_layout_curve(layout)
|
||||
assert curve.is_a("IfcGradientCurve")
|
||||
|
||||
alignment = ifcopenshell.api.alignment.create(file, "TestAlignment",include_vertical=True,include_cant=True)
|
||||
layout = ifcopenshell.api.alignment.get_horizontal_layout(alignment)
|
||||
curve = ifcopenshell.api.alignment.get_layout_curve(layout)
|
||||
assert curve.is_a("IfcCompositeCurve")
|
||||
layout = ifcopenshell.api.alignment.get_vertical_layout(alignment)
|
||||
curve = ifcopenshell.api.alignment.get_layout_curve(layout)
|
||||
assert curve.is_a("IfcGradientCurve")
|
||||
layout = ifcopenshell.api.alignment.get_cant_layout(alignment)
|
||||
curve = ifcopenshell.api.alignment.get_layout_curve(layout)
|
||||
assert curve.is_a("IfcSegmentedReferenceCurve")
|
||||
@@ -16,18 +16,15 @@
|
||||
# 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():
|
||||
def _test_horizontal():
|
||||
file = ifcopenshell.file(schema="IFC4X3")
|
||||
project = file.createIfcProject(Name="Test")
|
||||
project = file.createIfcProject(GlobalId=ifcopenshell.guid.new(),Name="Test")
|
||||
length = ifcopenshell.api.unit.add_si_unit(file,unit_type="LENGTHUNIT")
|
||||
ifcopenshell.api.unit.assign_unit(file,units=[length])
|
||||
geometric_representation_context = ifcopenshell.api.context.add_context(file, context_type="Model")
|
||||
axis_model_representation_subcontext = ifcopenshell.api.context.add_context(
|
||||
file,
|
||||
@@ -37,41 +34,15 @@ def _test_business_definition():
|
||||
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
|
||||
|
||||
alignment = ifcopenshell.api.alignment.create(file,"TestAlignment")
|
||||
horizontal = ifcopenshell.api.alignment.get_horizontal_layout(alignment)
|
||||
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():
|
||||
def _test_horizontal_vertical():
|
||||
file = ifcopenshell.file(schema="IFC4X3")
|
||||
project = file.createIfcProject(Name="Test")
|
||||
project = file.createIfcProject(GlobalId=ifcopenshell.guid.new(),Name="Test")
|
||||
length = ifcopenshell.api.unit.add_si_unit(file,unit_type="LENGTHUNIT")
|
||||
ifcopenshell.api.unit.assign_unit(file,units=[length])
|
||||
geometric_representation_context = ifcopenshell.api.context.add_context(file, context_type="Model")
|
||||
axis_model_representation_subcontext = ifcopenshell.api.context.add_context(
|
||||
file,
|
||||
@@ -80,44 +51,39 @@ def _test_geometric_definition():
|
||||
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,
|
||||
),
|
||||
|
||||
alignment = ifcopenshell.api.alignment.create(file,"TestAlignment",include_vertical=True)
|
||||
horizontal = ifcopenshell.api.alignment.get_horizontal_layout(alignment)
|
||||
assert True == ifcopenshell.api.alignment.has_zero_length_segment(horizontal)
|
||||
vertical = ifcopenshell.api.alignment.get_vertical_layout(alignment)
|
||||
assert True == ifcopenshell.api.alignment.has_zero_length_segment(vertical)
|
||||
|
||||
def _test_horizontal_vertical_cant():
|
||||
file = ifcopenshell.file(schema="IFC4X3")
|
||||
project = file.createIfcProject(GlobalId=ifcopenshell.guid.new(),Name="Test")
|
||||
length = ifcopenshell.api.unit.add_si_unit(file,unit_type="LENGTHUNIT")
|
||||
ifcopenshell.api.unit.assign_unit(file,units=[length])
|
||||
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,
|
||||
)
|
||||
|
||||
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)
|
||||
|
||||
alignment = ifcopenshell.api.alignment.create(file,"TestAlignment",include_vertical=True,include_cant=True)
|
||||
horizontal = ifcopenshell.api.alignment.get_horizontal_layout(alignment)
|
||||
assert True == ifcopenshell.api.alignment.has_zero_length_segment(horizontal)
|
||||
vertical = ifcopenshell.api.alignment.get_vertical_layout(alignment)
|
||||
assert True == ifcopenshell.api.alignment.has_zero_length_segment(vertical)
|
||||
cant = ifcopenshell.api.alignment.get_cant_layout(alignment)
|
||||
assert True == ifcopenshell.api.alignment.has_zero_length_segment(cant)
|
||||
|
||||
def test_has_zero_length_segment():
|
||||
_test_business_definition()
|
||||
_test_geometric_definition()
|
||||
_test_horizontal()
|
||||
_test_horizontal_vertical()
|
||||
_test_horizontal_vertical_cant()
|
||||
|
||||
|
||||
test_has_zero_length_segment()
|
||||
@@ -0,0 +1,55 @@
|
||||
# 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
|
||||
|
||||
# other test cases cover the typical vertical by PI method (test_create_alignment_by_pi_method)
|
||||
# this test will focus on the edge cases of no initial tangent run, no final tangent run, and
|
||||
# compound curve (no tangent between curves)
|
||||
def test_horizontal_layout_by_pi_method():
|
||||
file = ifcopenshell.file(schema="IFC4X3")
|
||||
project = file.createIfcProject(GlobalId=ifcopenshell.guid.new(),Name="Test")
|
||||
length = ifcopenshell.api.unit.add_conversion_based_unit(file,name="foot")
|
||||
ifcopenshell.api.unit.assign_unit(file,units=[length])
|
||||
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 = [(838.760, 224.745), (965.926, 258.819), (1226.296, 258.819), (1350.817, 291.415)]
|
||||
radii = [(1000.0), (1000.0)]
|
||||
|
||||
alignment = ifcopenshell.api.alignment.create_by_pi_method(file, "TestAlignment", coordinates, radii)
|
||||
|
||||
assert len(alignment.IsDecomposedBy) == 0 # no child alignments
|
||||
assert len(alignment.IsNestedBy) == 1 # one nest
|
||||
assert len(alignment.IsNestedBy[0].RelatedObjects) == 2 # nesting IfcReferent, IfcAlignmentHorizontal
|
||||
assert alignment.IsNestedBy[0].RelatedObjects[0].is_a("IfcReferent")
|
||||
assert alignment.IsNestedBy[0].RelatedObjects[1].is_a("IfcAlignmentHorizontal")
|
||||
assert (
|
||||
len(alignment.IsNestedBy[0].RelatedObjects[1].IsNestedBy) == 1
|
||||
) # nesting of segments beneath IfcAlignmentHorizontal
|
||||
assert len(alignment.IsNestedBy[0].RelatedObjects[1].IsNestedBy[0].RelatedObjects) == 3 # segments in horizontal layout
|
||||
|
||||
test_horizontal_layout_by_pi_method()
|
||||
@@ -19,7 +19,7 @@
|
||||
import pytest
|
||||
import ifcopenshell.api.alignment
|
||||
import ifcopenshell.api.context
|
||||
|
||||
from ifcopenshell.api.alignment._map_alignment_cant_segment import _map_alignment_cant_segment
|
||||
|
||||
def _BlossCurve_100_0_300_1000_1_Meter(file):
|
||||
design_parameters = file.createIfcAlignmentCantSegment(
|
||||
@@ -36,7 +36,7 @@ def _BlossCurve_100_0_300_1000_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -68,7 +68,7 @@ def _BlossCurve_100_0__300__1000_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -100,7 +100,7 @@ def _BlossCurve_100_0_300_inf_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -132,7 +132,7 @@ def _BlossCurve_100_0__300__inf_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -164,7 +164,7 @@ def _BlossCurve_100_0_1000_300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -196,7 +196,7 @@ def _BlossCurve_100_0__1000__300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -228,7 +228,7 @@ def _BlossCurve_100_0_inf_300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -260,7 +260,7 @@ def _BlossCurve_100_0__inf__300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -292,7 +292,7 @@ def _ConstantCant_100_0_300_1000_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -321,7 +321,7 @@ def _ConstantCant_100_0__300__1000_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -350,7 +350,7 @@ def _ConstantCant_100_0_300_inf_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -379,7 +379,7 @@ def _ConstantCant_100_0__300__inf_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -408,7 +408,7 @@ def _ConstantCant_100_0_1000_300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -437,7 +437,7 @@ def _ConstantCant_100_0__1000__300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -466,7 +466,7 @@ def _ConstantCant_100_0_inf_300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -495,7 +495,7 @@ def _ConstantCant_100_0__inf__300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -524,7 +524,7 @@ def _CosineCurve_100_0_300_1000_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -554,7 +554,7 @@ def _CosineCurve_100_0__300__1000_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -584,7 +584,7 @@ def _CosineCurve_100_0_300_inf_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -614,7 +614,7 @@ def _CosineCurve_100_0__300__inf_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -644,7 +644,7 @@ def _CosineCurve_100_0_1000_300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -674,7 +674,7 @@ def _CosineCurve_100_0__1000__300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -704,7 +704,7 @@ def _CosineCurve_100_0_inf_300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -734,7 +734,7 @@ def _CosineCurve_100_0__inf__300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -764,7 +764,7 @@ def _HelmertCurve_100_0_300_1000_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -809,7 +809,7 @@ def _HelmertCurve_100_0__300__1000_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -854,7 +854,7 @@ def _HelmertCurve_100_0_300_inf_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -899,7 +899,7 @@ def _HelmertCurve_100_0__300__inf_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -944,7 +944,7 @@ def _HelmertCurve_100_0_1000_300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -989,7 +989,7 @@ def _HelmertCurve_100_0__1000__300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -1034,7 +1034,7 @@ def _HelmertCurve_100_0_inf_300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -1079,7 +1079,7 @@ def _HelmertCurve_100_0__inf__300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -1124,7 +1124,7 @@ def _LinearTransition_100_0_300_1000_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -1155,7 +1155,7 @@ def _LinearTransition_100_0__300__1000_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -1186,7 +1186,7 @@ def _LinearTransition_100_0_300_inf_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -1217,7 +1217,7 @@ def _LinearTransition_100_0__300__inf_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -1248,7 +1248,7 @@ def _LinearTransition_100_0_1000_300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -1279,7 +1279,7 @@ def _LinearTransition_100_0__1000__300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -1310,7 +1310,7 @@ def _LinearTransition_100_0_inf_300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -1341,7 +1341,7 @@ def _LinearTransition_100_0__inf__300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -1372,7 +1372,7 @@ def _SineCurve_100_0_300_1000_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -1403,7 +1403,7 @@ def _SineCurve_100_0__300__1000_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -1434,7 +1434,7 @@ def _SineCurve_100_0_300_inf_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -1465,7 +1465,7 @@ def _SineCurve_100_0__300__inf_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -1496,7 +1496,7 @@ def _SineCurve_100_0_1000_300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -1527,7 +1527,7 @@ def _SineCurve_100_0__1000__300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -1558,7 +1558,7 @@ def _SineCurve_100_0_inf_300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
@@ -1589,7 +1589,7 @@ def _SineCurve_100_0__inf__300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_cant_segment(file, alignment_segment, 1.5)
|
||||
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
|
||||
|
||||
+65
-65
@@ -21,7 +21,7 @@
|
||||
|
||||
import pytest
|
||||
import ifcopenshell.api.alignment
|
||||
|
||||
from ifcopenshell.api.alignment._map_alignment_horizontal_segment import __map_alignment_horizontal_segment
|
||||
|
||||
def _BlossCurve_100_0_300_1000_1_Meter(file):
|
||||
design_parameters = file.createIfcAlignmentHorizontalSegment(
|
||||
@@ -37,7 +37,7 @@ def _BlossCurve_100_0_300_1000_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -68,7 +68,7 @@ def _BlossCurve_100_0__300__1000_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -99,7 +99,7 @@ def _BlossCurve_100_0_300_inf_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -130,7 +130,7 @@ def _BlossCurve_100_0__300__inf_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -161,7 +161,7 @@ def _BlossCurve_100_0_1000_300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -192,7 +192,7 @@ def _BlossCurve_100_0__1000__300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -223,7 +223,7 @@ def _BlossCurve_100_0_inf_300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -254,7 +254,7 @@ def _BlossCurve_100_0__inf__300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -285,7 +285,7 @@ def _CircularArc_100_0_300_1000_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -313,7 +313,7 @@ def _CircularArc_100_0__300__1000_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -341,7 +341,7 @@ def _CircularArc_100_0_300_inf_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -369,7 +369,7 @@ def _CircularArc_100_0__300__inf_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -397,7 +397,7 @@ def _CircularArc_100_0_1000_300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -425,7 +425,7 @@ def _CircularArc_100_0__1000__300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -453,7 +453,7 @@ def _CircularArc_100_0_inf_300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -481,7 +481,7 @@ def _CircularArc_100_0__inf__300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -509,7 +509,7 @@ def _Clothoid_100_0_300_1000_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -537,7 +537,7 @@ def _Clothoid_100_0__300__1000_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -565,7 +565,7 @@ def _Clothoid_100_0_300_inf_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -593,7 +593,7 @@ def _Clothoid_100_0__300__inf_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -621,7 +621,7 @@ def _Clothoid_100_0_1000_300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -649,7 +649,7 @@ def _Clothoid_100_0__1000__300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -677,7 +677,7 @@ def _Clothoid_100_0_inf_300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -705,7 +705,7 @@ def _Clothoid_100_0__inf__300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -733,7 +733,7 @@ def _CosineCurve_100_0_300_1000_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -762,7 +762,7 @@ def _CosineCurve_100_0__300__1000_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -791,7 +791,7 @@ def _CosineCurve_100_0_300_inf_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -820,7 +820,7 @@ def _CosineCurve_100_0__300__inf_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -849,7 +849,7 @@ def _CosineCurve_100_0_1000_300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -878,7 +878,7 @@ def _CosineCurve_100_0__1000__300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -907,7 +907,7 @@ def _CosineCurve_100_0_inf_300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -936,7 +936,7 @@ def _CosineCurve_100_0__inf__300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -965,7 +965,7 @@ def _Cubic_100_0_300_1000_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -994,7 +994,7 @@ def _Cubic_100_0__300__1000_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -1023,7 +1023,7 @@ def _Cubic_100_0_300_inf_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -1052,7 +1052,7 @@ def _Cubic_100_0__300__inf_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -1081,7 +1081,7 @@ def _Cubic_100_0_1000_300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -1110,7 +1110,7 @@ def _Cubic_100_0__1000__300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -1139,7 +1139,7 @@ def _Cubic_100_0_inf_300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -1168,7 +1168,7 @@ def _Cubic_100_0__inf__300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -1197,7 +1197,7 @@ def _HelmertCurve_100_0_300_1000_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -1245,7 +1245,7 @@ def _HelmertCurve_100_0__300__1000_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -1293,7 +1293,7 @@ def _HelmertCurve_100_0_300_inf_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -1341,7 +1341,7 @@ def _HelmertCurve_100_0__300__inf_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -1389,7 +1389,7 @@ def _HelmertCurve_100_0_1000_300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -1437,7 +1437,7 @@ def _HelmertCurve_100_0__1000__300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -1485,7 +1485,7 @@ def _HelmertCurve_100_0_inf_300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -1533,7 +1533,7 @@ def _HelmertCurve_100_0__inf__300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -1581,7 +1581,7 @@ def _Line_100_0_300_1000_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -1609,7 +1609,7 @@ def _Line_100_0__300__1000_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -1637,7 +1637,7 @@ def _Line_100_0_300_inf_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -1665,7 +1665,7 @@ def _Line_100_0__300__inf_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -1693,7 +1693,7 @@ def _Line_100_0_1000_300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -1721,7 +1721,7 @@ def _Line_100_0__1000__300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -1749,7 +1749,7 @@ def _Line_100_0_inf_300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -1777,7 +1777,7 @@ def _Line_100_0__inf__300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -1805,7 +1805,7 @@ def _SineCurve_100_0_300_1000_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -1835,7 +1835,7 @@ def _SineCurve_100_0__300__1000_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -1865,7 +1865,7 @@ def _SineCurve_100_0_300_inf_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -1895,7 +1895,7 @@ def _SineCurve_100_0__300__inf_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -1925,7 +1925,7 @@ def _SineCurve_100_0_1000_300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -1955,7 +1955,7 @@ def _SineCurve_100_0__1000__300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -1985,7 +1985,7 @@ def _SineCurve_100_0_inf_300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
@@ -2015,7 +2015,7 @@ def _SineCurve_100_0__inf__300_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segments = __map_alignment_horizontal_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert "DISCONTINUOUS" == mapped_segment.Transition
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
import pytest
|
||||
import ifcopenshell.api.alignment
|
||||
|
||||
from ifcopenshell.api.alignment._map_alignment_vertical_segment import _map_alignment_vertical_segment
|
||||
|
||||
def _CircularArc_100_0_10_0_0_0_0_5_1_Meter(file):
|
||||
design_parameters = file.createIfcAlignmentVerticalSegment(
|
||||
@@ -37,7 +37,7 @@ def _CircularArc_100_0_10_0_0_0_0_5_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segments = _map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert mapped_segments[1] == None
|
||||
@@ -66,7 +66,7 @@ def _CircularArc_100_0_10_0_0_0__0_5_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segments = _map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert mapped_segments[1] == None
|
||||
@@ -97,7 +97,7 @@ def _CircularArc_100_0_10_0_0_5_0_0_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segments = _map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert mapped_segments[1] == None
|
||||
@@ -128,7 +128,7 @@ def _CircularArc_100_0_10_0__0_5_0_0_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segments = _map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert mapped_segments[1] == None
|
||||
@@ -159,7 +159,7 @@ def _CircularArc_100_0_10_0_0_5_1_0_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segments = _map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert mapped_segments[1] == None
|
||||
@@ -192,7 +192,7 @@ def _CircularArc_100_0_10_0__0_5__1_0_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segments = _map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert mapped_segments[1] == None
|
||||
@@ -225,7 +225,7 @@ def _CircularArc_100_0_10_0_1_0_0_5_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segments = _map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert mapped_segments[1] == None
|
||||
@@ -258,7 +258,7 @@ def _CircularArc_100_0_10_0__1_0__0_5_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segments = _map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert mapped_segments[1] == None
|
||||
@@ -291,7 +291,7 @@ def _ConstantGradient_100_0_10_0_0_0_0_5_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segments = _map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert mapped_segments[1] == None
|
||||
@@ -320,7 +320,7 @@ def _ConstantGradient_100_0_10_0_0_0__0_5_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segments = _map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert mapped_segments[1] == None
|
||||
@@ -349,7 +349,7 @@ def _ConstantGradient_100_0_10_0_0_5_0_0_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segments = _map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert mapped_segments[1] == None
|
||||
@@ -380,7 +380,7 @@ def _ConstantGradient_100_0_10_0__0_5_0_0_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segments = _map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert mapped_segments[1] == None
|
||||
@@ -411,7 +411,7 @@ def _ConstantGradient_100_0_10_0_0_5_1_0_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segments = _map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert mapped_segments[1] == None
|
||||
@@ -442,7 +442,7 @@ def _ConstantGradient_100_0_10_0__0_5__1_0_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segments = _map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert mapped_segments[1] == None
|
||||
@@ -473,7 +473,7 @@ def _ConstantGradient_100_0_10_0_1_0_0_5_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segments = _map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert mapped_segments[1] == None
|
||||
@@ -504,7 +504,7 @@ def _ConstantGradient_100_0_10_0__1_0__0_5_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segments = _map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert mapped_segments[1] == None
|
||||
@@ -535,7 +535,7 @@ def _ParabolicArc_100_0_10_0_0_0_0_5_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segments = _map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert mapped_segments[1] == None
|
||||
@@ -564,7 +564,7 @@ def _ParabolicArc_100_0_10_0_0_0__0_5_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segments = _map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert mapped_segments[1] == None
|
||||
@@ -593,7 +593,7 @@ def _ParabolicArc_100_0_10_0_0_5_0_0_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segments = _map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert mapped_segments[1] == None
|
||||
@@ -624,7 +624,7 @@ def _ParabolicArc_100_0_10_0__0_5_0_0_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segments = _map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert mapped_segments[1] == None
|
||||
@@ -655,7 +655,7 @@ def _ParabolicArc_100_0_10_0_0_5_1_0_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segments = _map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert mapped_segments[1] == None
|
||||
@@ -686,7 +686,7 @@ def _ParabolicArc_100_0_10_0__0_5__1_0_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segments = _map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert mapped_segments[1] == None
|
||||
@@ -717,7 +717,7 @@ def _ParabolicArc_100_0_10_0_1_0_0_5_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segments = _map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert mapped_segments[1] == None
|
||||
@@ -748,7 +748,7 @@ def _ParabolicArc_100_0_10_0__1_0__0_5_1_Meter(file):
|
||||
GlobalId=ifcopenshell.guid.new(), DesignParameters=design_parameters
|
||||
)
|
||||
|
||||
mapped_segments = ifcopenshell.api.alignment.map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segments = _map_alignment_vertical_segment(file, alignment_segment)
|
||||
mapped_segment = mapped_segments[0]
|
||||
assert len(mapped_segments) == 2
|
||||
assert mapped_segments[1] == None
|
||||
|
||||
@@ -23,7 +23,9 @@ import ifcopenshell.api.context
|
||||
|
||||
def test_name_segments():
|
||||
file = ifcopenshell.file(schema="IFC4X3")
|
||||
project = file.createIfcProject(Name="Test")
|
||||
project = file.createIfcProject(GlobalId=ifcopenshell.guid.new(),Name="Test")
|
||||
length = ifcopenshell.api.unit.add_si_unit(file,unit_type="LENGTHUNIT")
|
||||
ifcopenshell.api.unit.assign_unit(file,units=[length])
|
||||
geometric_representation_context = ifcopenshell.api.context.add_context(file, context_type="Model")
|
||||
axis_model_representation_subcontext = ifcopenshell.api.context.add_context(
|
||||
file,
|
||||
@@ -38,7 +40,7 @@ def test_name_segments():
|
||||
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(
|
||||
alignment = ifcopenshell.api.alignment.create_by_pi_method(
|
||||
file, "TestAlignment", coordinates, radii, vpoints, lengths
|
||||
)
|
||||
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
# 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
|
||||
from pytest import fixture
|
||||
import ifcopenshell.api.alignment
|
||||
import ifcopenshell.api.context
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def default_names_alignment():
|
||||
file = ifcopenshell.file(schema="IFC4X3")
|
||||
project = file.createIfcProject(GlobalId=ifcopenshell.guid.new(), Name="Test")
|
||||
length = ifcopenshell.api.unit.add_conversion_based_unit(file, name="foot")
|
||||
ifcopenshell.api.unit.assign_unit(file, units=[length])
|
||||
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_by_pi_method(file, "TestAlignment", coordinates, radii, vpoints,
|
||||
lengths)
|
||||
yield alignment
|
||||
|
||||
|
||||
def _hcallback(prev_segment, segment):
|
||||
if (prev_segment is None) and (segment is not None):
|
||||
label = "A"
|
||||
elif (prev_segment is not None) and (segment is None):
|
||||
label = "Z"
|
||||
else:
|
||||
label = "Q"
|
||||
return label
|
||||
|
||||
|
||||
def _vcallback(prev_segment, segment):
|
||||
if (prev_segment is None) and (segment is not None):
|
||||
label = "a"
|
||||
elif (prev_segment is not None) and (segment is None):
|
||||
label = "z"
|
||||
else:
|
||||
label = "q"
|
||||
return label
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def callback_alignment():
|
||||
ifcopenshell.api.alignment.register_referent_name_callback(_hcallback, _vcallback, None)
|
||||
file = ifcopenshell.file(schema="IFC4X3")
|
||||
project = file.createIfcProject(GlobalId=ifcopenshell.guid.new(), Name="Test")
|
||||
length = ifcopenshell.api.unit.add_conversion_based_unit(file, name="foot")
|
||||
ifcopenshell.api.unit.assign_unit(file, units=[length])
|
||||
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_by_pi_method(file, "TestAlignment", coordinates, radii, vpoints,
|
||||
lengths)
|
||||
yield alignment
|
||||
|
||||
|
||||
def test_with_default_names(default_names_alignment):
|
||||
hlayout = ifcopenshell.api.alignment.get_horizontal_layout(default_names_alignment)
|
||||
|
||||
assert "P.O.B." in hlayout.IsNestedBy[0].RelatedObjects[0].IsNestedBy[0].RelatedObjects[0].Name
|
||||
assert "P.C." in hlayout.IsNestedBy[0].RelatedObjects[1].IsNestedBy[0].RelatedObjects[0].Name
|
||||
assert "P.T." in hlayout.IsNestedBy[0].RelatedObjects[2].IsNestedBy[0].RelatedObjects[0].Name
|
||||
assert "P.O.E." in hlayout.IsNestedBy[0].RelatedObjects[-1].IsNestedBy[0].RelatedObjects[0].Name
|
||||
|
||||
vlayout = ifcopenshell.api.alignment.get_vertical_layout(default_names_alignment)
|
||||
|
||||
assert "V.P.O.B." in vlayout.IsNestedBy[0].RelatedObjects[0].IsNestedBy[0].RelatedObjects[0].Name
|
||||
assert "P.V.C." in vlayout.IsNestedBy[0].RelatedObjects[1].IsNestedBy[0].RelatedObjects[0].Name
|
||||
assert "P.V.T." in vlayout.IsNestedBy[0].RelatedObjects[2].IsNestedBy[0].RelatedObjects[0].Name
|
||||
assert "V.P.O.E." in vlayout.IsNestedBy[0].RelatedObjects[-1].IsNestedBy[0].RelatedObjects[0].Name
|
||||
|
||||
def test_with_callbacks(callback_alignment):
|
||||
hlayout = ifcopenshell.api.alignment.get_horizontal_layout(callback_alignment)
|
||||
|
||||
assert "A" in hlayout.IsNestedBy[0].RelatedObjects[0].IsNestedBy[0].RelatedObjects[0].Name
|
||||
assert "Q" in hlayout.IsNestedBy[0].RelatedObjects[1].IsNestedBy[0].RelatedObjects[0].Name
|
||||
assert "Q" in hlayout.IsNestedBy[0].RelatedObjects[2].IsNestedBy[0].RelatedObjects[0].Name
|
||||
assert "Z" in hlayout.IsNestedBy[0].RelatedObjects[-1].IsNestedBy[0].RelatedObjects[0].Name
|
||||
|
||||
vlayout = ifcopenshell.api.alignment.get_vertical_layout(callback_alignment)
|
||||
|
||||
assert "a" in vlayout.IsNestedBy[0].RelatedObjects[0].IsNestedBy[0].RelatedObjects[0].Name
|
||||
assert "q" in vlayout.IsNestedBy[0].RelatedObjects[1].IsNestedBy[0].RelatedObjects[0].Name
|
||||
assert "q" in vlayout.IsNestedBy[0].RelatedObjects[2].IsNestedBy[0].RelatedObjects[0].Name
|
||||
assert "z" in vlayout.IsNestedBy[0].RelatedObjects[-1].IsNestedBy[0].RelatedObjects[0].Name
|
||||
+13
-16
@@ -17,13 +17,15 @@
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import pytest
|
||||
import ifcopenshell.api.alignment
|
||||
from ifcopenshell.api.alignment._update_curve_segment_transition_code import _update_curve_segment_transition_code
|
||||
import ifcopenshell.api.context
|
||||
|
||||
|
||||
def _test1():
|
||||
file = ifcopenshell.file(schema="IFC4X3")
|
||||
project = file.createIfcProject(Name="Test")
|
||||
project = file.createIfcProject(GlobalId=ifcopenshell.guid.new(),Name="Test")
|
||||
length = ifcopenshell.api.unit.add_si_unit(file,unit_type="LENGTHUNIT")
|
||||
ifcopenshell.api.unit.assign_unit(file,units=[length])
|
||||
geometric_representation_context = ifcopenshell.api.context.add_context(file, context_type="Model")
|
||||
axis_model_representation_subcontext = ifcopenshell.api.context.add_context(
|
||||
file,
|
||||
@@ -79,7 +81,7 @@ def _test1():
|
||||
|
||||
composite_curve = file.createIfcCompositeCurve(Segments=(circular_arc, line), SelfIntersect=False)
|
||||
|
||||
ifcopenshell.api.alignment.update_curve_segment_transition_code(circular_arc, line)
|
||||
_update_curve_segment_transition_code(circular_arc, line)
|
||||
assert circular_arc.Transition == "CONTSAMEGRADIENT"
|
||||
|
||||
|
||||
@@ -94,6 +96,7 @@ def _test2():
|
||||
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);
|
||||
@@ -220,29 +223,23 @@ def _test2():
|
||||
),
|
||||
)
|
||||
|
||||
composite_curve = file.createIfcCompositeCurve(Segments=[], SelfIntersect=False)
|
||||
composite_curve = file.createIfcCompositeCurve(Segments=[line1,clothoid1,circular_arc,clothoid2,line2], 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)
|
||||
_update_curve_segment_transition_code(line1,clothoid1)
|
||||
assert line1.Transition == "CONTSAMEGRADIENTSAMECURVATURE"
|
||||
assert clothoid1.Transition == "DISCONTINUOUS"
|
||||
|
||||
ifcopenshell.api.alignment.add_segment_to_curve(file, circular_arc, composite_curve)
|
||||
_update_curve_segment_transition_code(clothoid1,circular_arc)
|
||||
assert clothoid1.Transition == "CONTSAMEGRADIENTSAMECURVATURE"
|
||||
assert circular_arc.Transition == "DISCONTINUOUS"
|
||||
|
||||
ifcopenshell.api.alignment.add_segment_to_curve(file, clothoid2, composite_curve)
|
||||
_update_curve_segment_transition_code(circular_arc,clothoid2)
|
||||
assert circular_arc.Transition == "CONTSAMEGRADIENTSAMECURVATURE"
|
||||
assert clothoid2.Transition == "DISCONTINUOUS"
|
||||
|
||||
ifcopenshell.api.alignment.add_segment_to_curve(file, line2, composite_curve)
|
||||
_update_curve_segment_transition_code(clothoid2,line2)
|
||||
assert clothoid2.Transition == "CONTSAMEGRADIENTSAMECURVATURE"
|
||||
assert line2.Transition == "DISCONTINUOUS"
|
||||
|
||||
|
||||
def test_update_curve_segment_transition_code():
|
||||
_test1()
|
||||
_test2()
|
||||
|
||||
test_update_curve_segment_transition_code()
|
||||
@@ -0,0 +1,71 @@
|
||||
# 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
|
||||
|
||||
# other test cases cover the typical vertical by PI method (test_create_alignment_by_pi_method)
|
||||
# this test will focus on the edge cases of no initial gradient, no final gradient, and
|
||||
# compound vertical curve (no gradient between curves)
|
||||
def test_vertical_layout_by_pi_method():
|
||||
file = ifcopenshell.file(schema="IFC4X3")
|
||||
project = file.createIfcProject(GlobalId=ifcopenshell.guid.new(),Name="Test")
|
||||
length = ifcopenshell.api.unit.add_conversion_based_unit(file,name="foot")
|
||||
ifcopenshell.api.unit.assign_unit(file,units=[length])
|
||||
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,
|
||||
)
|
||||
|
||||
|
||||
alignment = ifcopenshell.api.alignment.create(file, "TestAlignment", include_vertical=True)
|
||||
hlayout = ifcopenshell.api.alignment.get_horizontal_layout(alignment)
|
||||
segment1 = file.createIfcAlignmentHorizontalSegment(
|
||||
StartPoint=file.createIfcCartesianPoint(Coordinates=((0.,0.))), # Actual coordinate unknown
|
||||
StartDirection=0.0,
|
||||
StartRadiusOfCurvature=0.0,
|
||||
EndRadiusOfCurvature=0.0,
|
||||
SegmentLength=10000.0,
|
||||
PredefinedType = "LINE"
|
||||
)
|
||||
|
||||
ifcopenshell.api.alignment.create_layout_segment(file,hlayout,segment1)
|
||||
|
||||
vpoints = [(0.0, 110.0), (400.0, 100.0), (800.0, 115.0), (1300.0, 125.0), (1800.0, 105.0)]
|
||||
lengths = [(800.0), (0.0), (1000.0)]
|
||||
vlayout = ifcopenshell.api.alignment.get_vertical_layout(alignment)
|
||||
ifcopenshell.api.alignment.layout_vertical_alignment_by_pi_method(file,vlayout,vpoints,lengths)
|
||||
|
||||
assert len(alignment.IsDecomposedBy) == 0 # no child alignments
|
||||
assert len(alignment.IsNestedBy) == 1 # one nest
|
||||
assert len(alignment.IsNestedBy[0].RelatedObjects) == 3 # nesting IfcReferent, IfcAlignmentHorizontal, IfcAlignmentVertical
|
||||
assert alignment.IsNestedBy[0].RelatedObjects[0].is_a("IfcReferent")
|
||||
assert alignment.IsNestedBy[0].RelatedObjects[1].is_a("IfcAlignmentHorizontal")
|
||||
assert alignment.IsNestedBy[0].RelatedObjects[2].is_a("IfcAlignmentVertical")
|
||||
assert (
|
||||
len(alignment.IsNestedBy[0].RelatedObjects[1].IsNestedBy) == 1
|
||||
) # nesting of segments beneath IfcAlignmentHorizontal
|
||||
assert len(alignment.IsNestedBy[0].RelatedObjects[1].IsNestedBy[0].RelatedObjects) == 2 # segments in horizontal layout
|
||||
assert len(alignment.IsNestedBy[0].RelatedObjects[2].IsNestedBy[0].RelatedObjects) == 3 # segments in vertical layout
|
||||
|
||||
test_vertical_layout_by_pi_method()
|
||||
@@ -0,0 +1,45 @@
|
||||
# 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
|
||||
import ifcopenshell.api.cogo
|
||||
|
||||
|
||||
def test_add_survey_point():
|
||||
file = ifcopenshell.file(schema="IFC4X3_ADD2")
|
||||
project = file.createIfcProject(Name="Test")
|
||||
site = file.createIfcSite(GlobalId=ifcopenshell.guid.new(),Name="MySite")
|
||||
ifcopenshell.api.aggregate.assign_object(file,relating_object=project,products=[site])
|
||||
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="Annotation",
|
||||
target_view="MODEL_VIEW",
|
||||
parent=geometric_representation_context,
|
||||
)
|
||||
|
||||
annotation = ifcopenshell.api.cogo.add_survey_point(file,file.createIfcCartesianPoint((50.0,10.0)))
|
||||
assert annotation
|
||||
assert annotation.PredefinedType == "SURVEY"
|
||||
assert annotation.Representation.Representations[0].RepresentationIdentifier == "Annotation"
|
||||
assert annotation.Representation.Representations[0].RepresentationType == "Point"
|
||||
assert annotation.Representation.Representations[0].Items[0].Coordinates == pytest.approx((50.0,10.0))
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
# 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
|
||||
import ifcopenshell.api.cogo
|
||||
|
||||
|
||||
def test_assign_survey_point():
|
||||
file = ifcopenshell.file(schema="IFC4X3_ADD2")
|
||||
project = file.createIfcProject(Name="Test")
|
||||
site = file.createIfcSite(GlobalId=ifcopenshell.guid.new(),Name="MySite")
|
||||
ifcopenshell.api.aggregate.assign_object(file,relating_object=project,products=[site])
|
||||
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="Annotation",
|
||||
target_view="MODEL_VIEW",
|
||||
parent=geometric_representation_context,
|
||||
)
|
||||
|
||||
annotation = ifcopenshell.api.cogo.add_survey_point(file,file.createIfcCartesianPoint((50.0,10.0)))
|
||||
assert annotation
|
||||
assert annotation.PredefinedType == "SURVEY"
|
||||
assert annotation.Representation.Representations[0].RepresentationIdentifier == "Annotation"
|
||||
assert annotation.Representation.Representations[0].RepresentationType == "Point"
|
||||
assert annotation.Representation.Representations[0].Items[0].Coordinates == pytest.approx((50.0,10.0))
|
||||
|
||||
ifcopenshell.api.cogo.assign_survey_point(annotation,file.createIfcCartesianPoint((20.0,30.0,40.0)))
|
||||
assert annotation.Representation.Representations[0].Items[0].Coordinates == pytest.approx((20.0,30.0,40.0))
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
# 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.cogo
|
||||
import math
|
||||
|
||||
|
||||
def test_bearing2dd():
|
||||
assert 44.743888875 == pytest.approx(ifcopenshell.api.cogo.bearing2dd("N 45 15 22.5 E"))
|
||||
assert 135.256111125 == pytest.approx(ifcopenshell.api.cogo.bearing2dd("N 45 15 22.5 W"))
|
||||
assert 224.743888875 == pytest.approx(ifcopenshell.api.cogo.bearing2dd("S 45 15 22.5 W"))
|
||||
assert 315.256111125 == pytest.approx(ifcopenshell.api.cogo.bearing2dd("S 45 15 22.5 E"))
|
||||
|
||||
assert 44.743888875 == pytest.approx(ifcopenshell.api.cogo.bearing2dd("n 45 15 22.5 e"))
|
||||
assert 135.256111125 == pytest.approx(ifcopenshell.api.cogo.bearing2dd("n 45 15 22.5 w"))
|
||||
assert 224.743888875 == pytest.approx(ifcopenshell.api.cogo.bearing2dd("s 45 15 22.5 w"))
|
||||
assert 315.256111125 == pytest.approx(ifcopenshell.api.cogo.bearing2dd("s 45 15 22.5 e"))
|
||||
|
||||
assert 0.0 == pytest.approx(ifcopenshell.api.cogo.bearing2dd("N 90 E"))
|
||||
assert 0.0 == pytest.approx(ifcopenshell.api.cogo.bearing2dd("S 90 E"))
|
||||
|
||||
assert 180. == pytest.approx(ifcopenshell.api.cogo.bearing2dd("N 90 W"))
|
||||
assert 180. == pytest.approx(ifcopenshell.api.cogo.bearing2dd("S 90 W"))
|
||||
|
||||
assert 120. == pytest.approx(ifcopenshell.api.cogo.bearing2dd("N 30 W"))
|
||||
assert 120.16666666666667 == pytest.approx(ifcopenshell.api.cogo.bearing2dd("N 30 10 W"))
|
||||
|
||||
assert 89.999722222222228 == pytest.approx(ifcopenshell.api.cogo.bearing2dd("N 00 00 1 E"))
|
||||
assert 89.99972222222222 == pytest.approx(ifcopenshell.api.cogo.bearing2dd("N 0 0 1 E"))
|
||||
assert 89.99972222222222 == pytest.approx(ifcopenshell.api.cogo.bearing2dd("N 00 00 1.0 E"))
|
||||
|
||||
with pytest.raises(ValueError,match="Invalid bearing string"):
|
||||
ifcopenshell.api.cogo.bearing2dd("Bad String")
|
||||
|
||||
with pytest.raises(ValueError,match="Invalid bearing string"):
|
||||
ifcopenshell.api.cogo.bearing2dd("Very Bad String")
|
||||
|
||||
with pytest.raises(ValueError,match="Invalid bearing string"):
|
||||
ifcopenshell.api.cogo.bearing2dd("N 100 15 22.5 E")
|
||||
|
||||
with pytest.raises(ValueError,match="Invalid bearing string"):
|
||||
ifcopenshell.api.cogo.bearing2dd("N -45 15 22.5 E")
|
||||
|
||||
with pytest.raises(ValueError,match="Invalid bearing string"):
|
||||
ifcopenshell.api.cogo.bearing2dd("N 45 -15 22.5 E")
|
||||
|
||||
with pytest.raises(ValueError,match="Invalid bearing string"):
|
||||
ifcopenshell.api.cogo.bearing2dd("N 45 88 22.5 E")
|
||||
|
||||
with pytest.raises(ValueError,match="Invalid bearing string"):
|
||||
ifcopenshell.api.cogo.bearing2dd("N 45 15 -22.5 E")
|
||||
|
||||
with pytest.raises(ValueError,match="Invalid bearing string"):
|
||||
ifcopenshell.api.cogo.bearing2dd("N 45 15 99.5 E")
|
||||
|
||||
test_bearing2dd()
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
# 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
|
||||
import ifcopenshell.api.cogo
|
||||
|
||||
|
||||
def test_edit_survey_point():
|
||||
file = ifcopenshell.file(schema="IFC4X3_ADD2")
|
||||
project = file.createIfcProject(Name="Test")
|
||||
site = file.createIfcSite(GlobalId=ifcopenshell.guid.new(),Name="MySite")
|
||||
ifcopenshell.api.aggregate.assign_object(file,relating_object=project,products=[site])
|
||||
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="Annotation",
|
||||
target_view="MODEL_VIEW",
|
||||
parent=geometric_representation_context,
|
||||
)
|
||||
|
||||
annotation = ifcopenshell.api.cogo.add_survey_point(file,file.createIfcCartesianPoint((50.0,10.0)))
|
||||
assert annotation
|
||||
assert annotation.PredefinedType == "SURVEY"
|
||||
assert annotation.Representation.Representations[0].RepresentationIdentifier == "Annotation"
|
||||
assert annotation.Representation.Representations[0].RepresentationType == "Point"
|
||||
assert annotation.Representation.Representations[0].Items[0].Coordinates == pytest.approx((50.0,10.0))
|
||||
|
||||
ifcopenshell.api.cogo.edit_survey_point(annotation,20.0,30.0)
|
||||
assert annotation.Representation.Representations[0].Items[0].Coordinates == pytest.approx((20.0,30.0))
|
||||
|
||||
@@ -16,31 +16,67 @@
|
||||
# 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 ifcopenshell
|
||||
import ifcopenshell.util.stationing as sta
|
||||
|
||||
def _test_si_stations():
|
||||
file = ifcopenshell.file(schema="IFC4X3_ADD2")
|
||||
project = file.createIfcProject(GlobalId=ifcopenshell.guid.new(),Name="Test")
|
||||
length = ifcopenshell.api.unit.add_si_unit(file,unit_type="LENGTHUNIT") # meter
|
||||
ifcopenshell.api.unit.assign_unit(file,units=[length])
|
||||
|
||||
s = sta.station_as_string(file,0.0)
|
||||
assert s == "0+000.000"
|
||||
|
||||
s = sta.station_as_string(file,100.00)
|
||||
assert s == "0+100.000"
|
||||
|
||||
s = sta.station_as_string(file,-100.00)
|
||||
assert s == "-0+100.000"
|
||||
|
||||
s = sta.station_as_string(file,123456.789)
|
||||
assert s == "123+456.789"
|
||||
|
||||
s = sta.station_as_string(file,-123456.789)
|
||||
assert s == "-123+456.789"
|
||||
|
||||
def _test_si_stations_millimeter():
|
||||
file = ifcopenshell.file(schema="IFC4X3_ADD2")
|
||||
project = file.createIfcProject(GlobalId=ifcopenshell.guid.new(),Name="Test")
|
||||
ifcopenshell.api.unit.assign_unit(file)
|
||||
|
||||
s = sta.station_as_string(file,100.00)
|
||||
assert s == "0+000.100"
|
||||
|
||||
s = sta.station_as_string(file,1000.00)
|
||||
assert s == "0+001.000"
|
||||
|
||||
def _test_us_stations():
|
||||
file = ifcopenshell.file(schema="IFC4X3_ADD2")
|
||||
project = file.createIfcProject(GlobalId=ifcopenshell.guid.new(),Name="Test")
|
||||
length = ifcopenshell.api.unit.add_conversion_based_unit(file,name="foot")
|
||||
ifcopenshell.api.unit.assign_unit(file,units=[length])
|
||||
|
||||
s = sta.station_as_string(file,0.0)
|
||||
assert s == "0+00.00"
|
||||
|
||||
s = sta.station_as_string(file,100.00)
|
||||
assert s == "1+00.00"
|
||||
|
||||
s = sta.station_as_string(file,-100.00)
|
||||
assert s == "-1+00.00"
|
||||
|
||||
s = sta.station_as_string(file,123456.789)
|
||||
assert s == "1234+56.79"
|
||||
|
||||
s = sta.station_as_string(file,-123456.789)
|
||||
assert s == "-1234+56.79"
|
||||
|
||||
|
||||
def test_station_as_string():
|
||||
# test with a bunch of "random" station values
|
||||
s = sta.station_as_string(0.0)
|
||||
assert s == "0+000.000"
|
||||
_test_si_stations()
|
||||
_test_si_stations_millimeter()
|
||||
_test_us_stations()
|
||||
|
||||
s = sta.station_as_string(0.0, 2, 2)
|
||||
assert s == "0+00.00"
|
||||
|
||||
s = sta.station_as_string(0.0, 2)
|
||||
assert s == "0+00.000"
|
||||
|
||||
s = sta.station_as_string(100.00)
|
||||
assert s == "0+100.000"
|
||||
|
||||
s = sta.station_as_string(-100.00)
|
||||
assert s == "-0+100.000"
|
||||
|
||||
s = sta.station_as_string(123456.789, 2, 2)
|
||||
assert s == "1234+56.79"
|
||||
|
||||
s = sta.station_as_string(-123456.789, 2, 2)
|
||||
assert s == "-1234+56.79"
|
||||
|
||||
s = sta.station_as_string(123456.789, 3, 4)
|
||||
assert s == "123+456.7890"
|
||||
test_station_as_string()
|
||||
Reference in New Issue
Block a user