Expand description
Stations: positions named by a distance along a basis curve (#241, ADR 0082).
A station is exact stored data – a distance and three offsets – that a kernel resolves by evaluating the basis curve; the graph never does.
§Distance
Station::distance is measured from the basis curve’s start in that
curve’s own convention: PLAN distance on an elevated or a banked curve
(their parameter), arc length on every other curve, 2D or 3D. The start
is parameter 0, or the first parameter of the domain of a polyline or
a B-spline. A resolver refuses by name a distance before the start or
past the curve’s length; the graph refuses a non-finite or negative one
when the node is pushed.
A basis may also be a curve relation a distance runs along (#285): a
CurveRelation::Composite, a CurveRelation::Trimmed, a curve
placed by an InstanceAtStation, nested in any combination. The
distance then runs end to end through the atomic curves it is made of,
each span in its own curve’s convention, and those must agree: plan
distance when every span is an elevated or banked curve, arc length
when none is. A composite of segments placed at stations of another
curve is measured along its own segments, whatever curve they were
placed on. Each joint of a composite is a seam (below), and its pieces
must meet end to start; a resolver refuses by name pieces measured
differently, a gap, and a piece whose undeclared sense runs it
backwards.
§Frame and offsets
The basis curve’s section frame at the distance has three unit axes:
the tangent, the lateral axis to the LEFT of it, and up = tangent x lateral. For a 2D curve (lying in z = 0) they are the tangent, the
left normal and +Z; for a banked curve, its rolled section (lateral
towards the left rail head); for every other 3D curve, an elevated one
included, the reference-up frame against +Z (lateral horizontal, up
leaning back with the grade). StationFrame::Plan instead takes the
tangent’s horizontal projection, the horizontal left normal and +Z.
The station’s point is point + lateral * l + up * v + tangent * g for
the offsets (l, v, g) of StationOffsets. A resolver presents the
frame as x the tangent, y up, z to the right (-lateral), the
curve-evaluation provider’s layout.
§Explicit orientation (#246)
A station may carry a StationOrientation: an optional axis and an
optional ref_direction, both given as COMPONENTS IN THE STATION’S BASE
FRAME at its distance (the StationFrame it names), never in world
coordinates: a vector (a, b, c) means a * tangent + b * lateral + c * up. This is how a linear placement reads its own axes: they “are
relative to the curve used for linear referencing …, maintaining the
relationship to the tangent of the curve” (buildingSMART IFC 4.3,
IfcAxis2PlacementLinear), whose local X is the tangent, Y the left
lateral and Z up, this module’s (tangent, lateral, up).
axisis the exact direction of the oriented frame’s up (localZ); absent, it is(0, 0, 1), the base frame’s up.ref_directionfixes the oriented frame’s tangent role (localX); absent, it is(1, 0, 0), the curve tangent.- The frame is orthonormalised by Gram-Schmidt with the axis primary:
up' = axis / |axis|,tangent' = normalise(r - (r . up') up')for the unitr = ref_direction / |ref_direction|, andlateral' = up' x tangent', so(tangent', lateral', up')stays right-handed. - A zero or non-finite vector, and an axis and reference direction
(given or defaulted) parallel or anti-parallel within
ORIENTATION_TOLERANCE(the sine of the angle between them), are refused by name when the node is pushed.
The oriented triad replaces the base one wherever a frame ORIENTS
something: the frame a resolved station presents, and the plane a
section’s profile is placed in (profile x along lateral', y
along up'). The OFFSETS stay in the base frame: they locate the
station’s origin, which the orientation does not move.
§Seams (#263)
A basis curve made of pieces – a polyline, a B-spline with a corner
knot, an elevated curve whose profile’s grade breaks, a banked curve
whose cant or pivot law jumps – has two frames where two pieces meet.
A station within the arc-length tolerance of such a seam is ON it and
reads the frame of one piece, chosen by SeamSide: the piece that
starts there (SeamSide::Outgoing, the default and what every curve
evaluator reads) or the one that ends there (SeamSide::Incoming).
An OrientedCurveStation carries the side (OrientedCurveStation::seam);
a plain CurveStation reads the outgoing piece, and
CurveStation::with_seam_side turns it into an oriented station in
its base frame that reads the other one.
A run of sections or offsets (Stations along one directrix) decides
most sides itself: a section standing exactly on an interior seam where
the tangent turns is cut in the mitre plane, the bisector of the
incoming and outgoing tangents, and so is the run where it crosses such
a seam between two of its stations. The run’s first station reads the
outgoing piece and its last the incoming one, the pieces the run lies
on. A seam where the tangent does not turn keeps the outgoing frame,
unless the station standing on it names the other side (#301, below).
§Seam-snapping window (#294)
An authoring rule may put a station ON a seam when it lies within the
model’s precision of one – IFC 4.3 ADD2 8.9.3.48.3 lets the previous
segment’s tangent govern a station “within precision limits” of a
tangent discontinuity – and that precision (up to a millimetre) is far
wider than the arc-length tolerance. An OrientedCurveStation
carries it as OrientedCurveStation::seam_window, a non-negative
distance in the basis’s station measure, set by
OrientedCurveStation::with_seam_window; 0, the default, is the
arc-length tolerance alone.
A resolver snaps a station whose distance lies within the window of a
seam of its basis whose frame may jump (a joint of a composite, a
polyline vertex, a corner knot, a grade or cant seam) onto that seam,
and reads it from the station’s SeamSide; the station’s point is
then the seam’s. Where a seam’s distance is numerical (after an offset
piece, an ellipse or a B-spline), the resolver uses a certified
interval of it. It refuses by name a window holding two seams, and a
seam whose certified interval straddles the window’s edge (inside or
outside cannot be told). The graph refuses a negative or non-finite
window when the node is pushed. A plain CurveStation has no window.
§Seam windows on run stations (#301)
The stations of a run carry the same window and a SeamSide: a
SectionAtStation (in SolidOperation::SectionsAtStations and
SurfaceRelation::OpenSectionsAtStations) through
SectionAtStation::with_seam_window and
SectionAtStation::with_seam_side, an offset’s RunStation (in
CurveRelation::OffsetsAtStations) likewise. Defaults are a window
of 0 and Outgoing, today’s reading. Station,
StationedSection and StationedOpenSection have public fields
and stay window-free, so SolidOperation::StationedSpine,
SurfaceRelation::SectionedSurface and
CurveRelation::OffsetByStations read as before; their general forms
above carry windows.
- Snapping. Each windowed station is snapped by the #294 rule against the run’s directrix: onto the one seam whose frame may jump within its window, at the seam’s own (certified) distance; a window holding two seams, or a seam whose certified position straddles its edge, is refused by name. The run then uses the snapped distance everywhere: the section’s place, the linear interpolation between stations, the run’s span. Snapped distances must still increase strictly; two stations snapped onto one seam, or one snapped past its neighbour, are refused by name.
- Side. The run’s first station reads the outgoing piece and its last the incoming one, whatever side they name: the run lies on those pieces, as a curve’s start and end have one piece. An interior station on a seam where the tangent turns stands in the mitre plane, so its section (or offset point) is the mitre section, placed in BOTH pieces’ frames and projected: its side is not read. An interior station on a seam where the tangent does not turn but the frame may jump (a banked curve’s roll) is placed in the frame of the piece its side names.
§Run stations at the basis’s ends (#303)
An offset by distances often continues its first and last offsets
unchanged out to its basis’s ends (IFC 4.3 ADD2 8.9.3.42.3), so its
run needs a station AT the basis’s end. Where the basis’s length has
no closed form (an offset beside a gradient curve, a clothoid or a
B-spline, a B-spline itself), a caller without a provider cannot state
that distance. A RunStation may therefore stand at the basis’s
start or end without stating it (RunStation::at_basis_start,
RunStation::at_basis_end): its RunStation::basis_end names
which, and its stated distance is 0 and not read.
- Resolution. A resolver reads the start as distance
0, where the station measure starts on every curve, and the end as the basis’s length by the kernel’s own measure of it, the number a curve path’s open end resolves to (#298): the length of the flattened basis (axiolid-mesh-compile’sstation::curve_path) asaxiolid-evaluate’sCompositeBasismeasures it, bitwise; on an unbounded line its parameter domain end,|direction|, as inside a composite. A station at the end is then the same station stated at that number. - Order. The graph refuses, when the node is pushed, a station at
the start that is not the run’s first, one at the end that is not its
last, and either stating a distance other than
0; the stated distances must increase strictly from a start station’s0. Whether the end comes after the last stated station needs the length, so a resolver refuses by name a run whose resolved distances do not increase strictly (a stated station at or past the basis’s end). - Windows. Snapping (#301) applies after resolution: a station at the end with a window snaps onto the one seam within the window of the resolved end, by the #294 rule.
Only the stations of a CurveRelation::OffsetsAtStations carry it;
a SectionAtStation states its distance.
§Placing a node at a station (#264)
InstanceAtStation reuses a node – a curve, a solid, a surface –
in the frame of an OrientedCurveStation, the way Instance
reuses one under a fixed transform. The station stays symbolic: a
kernel resolves its frame when it evaluates the node, with the
station’s StationFrame, orientation and SeamSide. The source’s
local axes map onto the station’s oriented frame as a linear placement
reads them (buildingSMART IFC 4.3, IfcAxis2PlacementLinear):
- local
xonto the oriented tangent (tangent'), - local
yonto the oriented lateral, to the LEFT (lateral'), - local
zonto the oriented up (up' = tangent' x lateral'), - the local origin onto the station’s point, its offsets read in the base frame.
This is a rigid motion (right-handed, no scale). It is not the profile
mapping above (a section’s x along lateral and y along up), and not
the provider layout a resolved station presents (x tangent, y up,
z right): a placed curve is laid ALONG the curve, a section ACROSS
it. A 2D source curve lies in its local z = 0, so it is placed in the
plane of the oriented tangent and lateral, and the placed curve is a 3D
curve whatever the source’s dimension.
§Sections between stations
A profile placed at a station maps its x onto the lateral axis and its
y onto up, so its normal x x y is the tangent. Between two stations
everything is interpolated LINEARLY in distance: the offsets, each
section point with its counterpart in the next section, and an explicit
orientation (the unit axis and the unit reference direction,
component-wise in the base frame, an absent one counting as (0, 0, 1)
and (1, 0, 0), then orthonormalised as above; a resolver refuses by
name an interpolated pair that degenerates).
§Matching points between sections
Untagged sections are matched by position: a closed profile’s points by
ring and vertex index, an open section’s by vertex index. Tagged
sections (SectionAtStation::tags, StationedOpenSection::tags)
are matched by tag. One run of sections is tagged throughout or not at
all, and every section carries the same SET of tags, none repeated, so
the tags are a bijection between any two sections:
- an open section’s tags run along its polyline in the first section’s order or in reverse (a reversed section is joined reversed); any other order would cross the sheet and is refused;
- a closed section’s tags name its contour vertices, the outer ring’s
then each hole’s, each ring from its first segment’s start in its
authored sense. Its profile must be polygonal (straight segments only,
optionally under a
Profile::Derivedtransform). The tags must map each ring of the first section onto one ring of every other, the outer onto the outer, in the same cyclic order once both are wound alike (outer counter-clockwise, holes clockwise): a section may start a ring at another vertex, list its holes in another order or wind a ring the other way, nothing else. A resolver checks this, since it needs the profile’s vertices.
Structs§
- Curve
Station - A point and frame at a station along a basis curve.
- Instance
AtStation - A node reused in the frame of an
OrientedCurveStation(#264): the station-framed form ofInstance. - Oriented
Curve Station - A
CurveStationwith an explicit orientation (#246) and the side of a seam it reads (#263). - RunStation
- A station of an offset run with the side of a seam it reads and its
seam-snapping window (#301): the general form of the plain
StationaCurveRelation::OffsetByStationstakes, used byCurveRelation::OffsetsAtStations. It may also stand at its basis’s start or end, its distance measured by the kernel (#303). - Section
AtStation - A section standing at a station, with optional tags and an optional
explicit orientation (#246): the general form of
StationedSection(closed) andStationedOpenSection(open). - Station
- A distance along a basis curve with offsets in its section frame.
- Station
Offsets - Offsets of a station from its basis curve, in the curve’s section frame.
- Station
Orientation - An explicit in-section orientation at a station (#246).
- Stationed
Open Section - An open section standing at a station along a sectioned surface’s directrix, its points named by tags.
- Stationed
Section - A closed profile standing at a station along a sectioned spine’s directrix.
Enums§
- Basis
End - Which end of its basis a
RunStationstands at, measured by the kernel (#303; see the module documentation). - Seam
Side - The piece a position exactly on a seam is read from.
- Station
Frame - Which frame a station’s offsets and orientation are read in.
Constants§
- ORIENTATION_
TOLERANCE - Largest sine of the angle between a
StationOrientation’s axis and reference direction that still counts as parallel.