ifc-alignment 0.2.0

IFC4x3 linear positioning: alignments, referents, linear placement, spirals.
Documentation
# ifc-alignment instructions

Purpose: Interpret IFC4x3 alignment intent in both directions — read and lower
into exact neutral curves/frames, and author alignment records from plain
numbers (ADR 0011) — without meshing or backend selection.

Follow `../AGENTS.md`. Read `PLAN.md` only for assigned implementation or
roadmap work; keep progress, blockers, and evidence there.

- `IfcLinearElement` and `IfcLinearPositioningElement` authoring, both IFC4X3
  additions that IFC4 does not declare. The positioning element inherits
  `IfcPositioningElement.HasPlacement`, so its placement is a required
  argument even though the slot is declared OPTIONAL; the linear element has
  no such rule and takes an optional placement.

## Boundary

Allowed production dependencies: ifc-model, schema metadata, and exact neutral axiolid-core/axiolid-curve representations; axiolid-model only if graph output is required.

## Module ownership

- `alignment.rs`: root/nesting/representation association
- `view.rs`: pins the IFC4X3 schema and exposes bounded `IfcRelNests`
  traversal shared by every layout module
- `horizontal.rs`: horizontal layout and segment parameters
- `vertical.rs`: vertical profile segments
- `cant.rs`: cant/superelevation segments and layout assembly
- `segment.rs`: shared segment transitions/continuity
- `curve.rs`: exact neutral curve assembly (single-segment and composite)
- `placement.rs`: linear placement/point-by-distance
- `referent.rs`: stationing/referents and station equations
- `query.rs`: bounded alignment traversal
- `curve/elevation.rs`: vertical segments as exact `ElevationLaw`s. Only
  CONSTANTGRADIENT and PARABOLICARC are polynomial in plan distance;
  CIRCULARARC is refused rather than approximated by a parabola.
- `curve/gradient.rs`: plan and profile composed as `Curve3::Elevated`.
  Height is a function of PLAN distance, not 3D arc length -- they diverge by
  sqrt(1 + g^2) wherever grade is non-zero.
- `slot.rs`: attribute slots read from the IFC4X3 ADD2 schema, indexed by both
  the readers and `authoring/`. Never restate a slot number elsewhere.
- `authoring/`: write direction. Plain `f64` in the file's declared units; no
  unit conversion (the readers apply `AlignmentUnits` on the way out) and no
  kernel types. Refuses what the readers reject, before staging.

## Invariants

- Preserve exact transition intent; tessellation is a downstream explicit operation.
- Station, horizontal length, projected length, and 3D length are distinct quantities.
- No road/rail product workflow or rendering policy enters this bridge.

Keep cross-resource projections attribute-scoped: shared `ifc-model` storage
does not make one feature crate the owner of an IFC entity. Split typed views,
resolution, lowering, mutation, and validation before they grow together.

## Verification

Run targeted tests/clippy, isolated build, and the package architecture/context
gates. Geometry bridges also run declaration/corpus coverage and the full gate.

## Station for a horizontal segment

An `IfcAlignmentHorizontalSegment` does not state its own distance along:
position follows from chaining. A Viennese bend needs that station to read
the cant swing across itself, so both chain walks in `curve/assemble.rs`
accumulate it.

Two pitfalls, both mutation-tested:

- The partial walk `continue`s on a refused segment. Advance the station
  BEFORE that branch or every later segment is mis-stationed.
- There are TWO accumulators, one per walk. A test that only exercises
  `lower_horizontal_layout` leaves the partial walk unguarded.

A single-segment lowering has no chain context, so it refuses a Viennese
bend rather than passing a station of zero.