Skip to content

OpenDRIVE elevation round-trip: carry z on points, refit profiles on export - #96

Merged
kosuke55 merged 3 commits into
mainfrom
odr-elevation-round-trip
Aug 6, 2026
Merged

OpenDRIVE elevation round-trip: carry z on points, refit profiles on export#96
kosuke55 merged 3 commits into
mainfrom
odr-elevation-round-trip

Conversation

@kosuke55

@kosuke55 kosuke55 commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Summary

OpenDRIVE elevation used to be dropped at import (collapsed to a boolean) and
regenerated roads always emitted an empty <elevationProfile/>. This PR makes
elevation survive a full import → edit → export round trip.

What changed

Import (0ce7e22)

  • The parser retains <elevation> polynomial records instead of discarding them.
  • The reference-line sampler evaluates z at every station. Elevation
    records deliberately do not alter the 2D station set (5c26085) —
    inserting them perturbed the plan-view fit and opened ASAM QC
    contact-point gaps on CARLA maps with dense all-zero records.
  • odrToShapes stamps the height onto each boundary point as an optional
    z (world meters) on PointProps / ImportedPoint.

Export (19bfaa7)

  • New odrElevationFit reconstructs centerline z(s) from boundary-point
    heights and least-squares fits piecewise cubic <elevation> records
    (0.05 m tolerance, matching the plan-view fitting error budget).
  • The exporter emits the fitted profile for roads whose points carry z.

Design notes

  • z rides on the point, so plain 2D editing (dragging, nudges, rotation
    bake) preserves it without extra plumbing.
  • Backward compatible: absent or all-zero z still emits the empty
    <elevationProfile/>, so existing 2D-only flows are byte-identical.
  • Superelevation (<lateralProfile>) is out of scope and still dropped
    with a warning.

Tests

  • 12 new unit tests (__tests__/exporter/odrElevation.test.ts):
    z evaluation, fit accuracy against known polynomials, all-zero
    fallback, editing-preservation invariants, and a regression pin that
    elevation records leave the 2D stations untouched.
  • Full suite: 318 passed. ASAM QC gate clean (Town01 round-trip is
    byte-identical to the pre-elevation baseline, header timestamp aside).

The parser used to collapse <elevationProfile> to a boolean and drop the
records. Now it retains the <elevation> polynomials, the reference-line
sampler pins elevation breakpoints as stations and evaluates z at each
sample, and odrToShapes stamps the height onto every boundary point.

z rides on the point (optional PointProps.z / ImportedPoint.z), so plain
2D editing preserves it without extra plumbing. Absent or all-zero z
still means "no elevation".
Regenerated roads used to always emit an empty <elevationProfile/>.
New odrElevationFit reconstructs centerline z(s) from boundary-point
heights and least-squares fits piecewise cubics (0.05 m tolerance),
and the exporter emits the fitted <elevation> records. Roads whose
points carry no z keep emitting the empty profile, so existing
2D-only flows are unchanged. Includes unit tests (11 cases).
@kosuke55 kosuke55 added the run-tests Trigger CI test execution label Aug 6, 2026
Inserting elevation breakpoints as stations perturbed the plan-view fit:
CARLA exports carry dense all-zero <elevation> records, and the extra
clustered samples rotated short junction roads enough to open contact-
point gaps (ASAM QC lane_smoothness failure on Town01, caught by CI).

Height is now evaluated at the unmodified 2D station set. The z
interpolation error from skipping a breakpoint is bounded by the <= 5 m
station spacing and realistic vertical-curve curvature — centimetres,
the same order as the export refit tolerance. A regression test pins
that elevation records leave stations (s, x, y, hdg) untouched, with
breakpoints deliberately off the 5 m grid so dedup cannot mask it.

Town01 round-trip output is byte-identical to the pre-elevation
baseline again (header timestamp aside); ASAM QC is clean.
@kosuke55
kosuke55 merged commit 29a8fe2 into main Aug 6, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

run-tests Trigger CI test execution

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant