Geoshift consistency: A1–A3 vs Abschnitt 4_5

2026-07-15 · for LaneFinder consumers (humans and their Claude Codes) · verified against blob outputs, N: exports, and source LAS headers

Verdict

Are the geoshifts consistent between A1–A3 and A4_5? YES. Same convention, same schema, same math, commit-verified identical writer code. The only thing that differs is the numeric anchor value — and that differs between every dataset by design (each Abschnitt has its own data-derived UTM anchor stored in its own XML). A4_5 is not an outlier in any way: read the <Geoshift> from the file, add it to the points, done — identical procedure for all four.

Consistent All four fresh productions — A1, A2, A3 (Azure, 2026-07-12) and Abschnitt 4_5 (local run, 2026-07-12) — use the same geoshift convention, and every run7_lanes XML lands on its source LAS footprint once its embedded <Geoshift> is applied.

One rule XML point coordinates are local-frame (±6 km around 0). World position = point + <Geoshift> from the same file. Skip that and you are ~700 km off.

Caveat resolved The 4_5 XML was exported by the older local pipeline (SoftwareVersion 0.9.1 vs Azure 0.9.3). The version gap changed provenance metadata only — the Point/Feature/Geoshift schema is element-for-element identical and the frame convention is the same. Treat it interchangeably with the Azure XMLs.

The two geoshift layers (don't confuse them)

Step-4 tile sidecar geoshiftXML <Geoshift>
Where…_segment_NNN.json next to each tile PNGOne element per XML, right after <MetaData>
ScaleSmall integer km multiples, e.g. (-4000,-5000), (0,0), (5000,4000) — negative and positiveUTM32-scale anchor, e.g. 694541.44 / 5386372.37
Meaningkm-grid cell origin of the tile in the step-3 local frame (internal km-snap; geoshift_source: null)Offset from step-3 local frame to absolute UTM32 for the whole dataset (the run-3 anchor)
Formulatile origin in local frame = sidecar (x, y) + sidecar geoshiftworld point = XML point (X, Y, Z) + <Geoshift>

All four datasets follow this identically. Verified quantitatively: sidecar-derived tile corners bracket the XML coordinate extents to within meters at both ends of the 4_5 branch and A1 branch_000 (e.g. 4_5 seg000 tile origin (-1815.73, -3356.04) vs XML min (-1810.48, -3299.33) — inside the tile).

Historic note: the May 2026 4_5 ACC export carried a slightly different UTM anchor (725769 / 5421417). Anchors are data-derived per run, so this is expected — always read the <Geoshift> from the file you are consuming, never hard-code it.

How to consume the XML (Rhino / TopoDOT / scripts)

Schema: HighwayData → MetaData → Geoshift → Features → Feature → Points → Point. Each <Point> holds ID, LaneID, PointerNumber, X, Y, Z, Color, FeatureClass, FeatureID, RoadPoint.

world_X = Point.X + Geoshift.X     # e.g. -221.163 + 725883.541 = 725662.378 (UTM32 easting)
world_Y = Point.Y + Geoshift.Y
world_Z = Point.Z + Geoshift.Z

XML vs source LAS placement

DatasetXML <Geoshift> X / YXML world extent E / N (m)Source LAS header samples E / N (m)Verdict
A1 (b000 + b001)694541.44 / 5386372.37691063–699713 / 5382320–5390723689331–690596 / 5384091–5385063OK sampled records 001/159 sit 0.5–1.7 km W of the modelled extent — untrimmed route tail, Z and N agree
A2702168.55 / 5395493.77699265–706469 / 5390080–5399451701094–706582 / 5396099–5399598OK inside extent (±150 m edge trim)
A3710993.55 / 5404278.64705474–715792 / 5399003–5410358706421–715645 / 5399239–5410109OK whole-route LAS fully inside
4_5725883.54 / 5422097.81724073–726420 / 5418799–5425138724054–726108 / 5418602–5421814OK lands on LAS footprint

The four Abschnitte form a coherent SW→NE chain (E 691→726 km) with sensible per-dataset anchors. LAS extents are per-file header min/max from sampled files (2 per dataset; A3's are whole-route Run files), so LAS columns understate full dataset extents slightly.

The 4_5 caveat: different code version, same convention

The 4_5 XML (run7_lanes_20260712-204522.xml) was not produced on Azure — it came from the legacy local pipeline. Metadata comparison against the Azure XMLs:

4_5 (local)A1 / A3 (Azure)A2 (Azure)
Exporter (SoftwareVersion)0.9.10.9.30.9.3
MetaData steps listedlegacy step1/3/4/5/6 (monolithic), 13–14 packages eachstep3 only, 8 packagesstep3 only, 8 packages
segmentation-trajectory0.7.10.7.20.7.1
filtering-surface0.7.50.7.50.7.4 (step3 ran 2026-05-28)
Shared geometry pins (common 0.3.2, geometry 0.6.1, filtering-intensity 0.6.2, las-tools 0.6.0, logstash 0.5.6)identical across all four
Point/Feature/Geoshift XML schemaidentical element structure in all five files

Commit-level evidence (not just version numbers)

We diffed the actual git history of the involved packages between the exact versions:

Package / rangeWhat changedGeoshift impact
modelling-lines 0.9.1→0.9.3
467feaa → 594f452, 17 commits
(writes the XML incl. <Geoshift>)
All AI3D-261: lane edge-role dedupe v1–v4, junction lateral-continuity guard, axis-review/crossing-region hardening. Diff grep for geoshift/anchor/utm/frame: zero geoshift hits. None git log -L over the geoshift load/write block in cluster_stepper.py (_load_geoshift, xml_dict["geoshift"], --geoshift-file): 0 commits touch it — byte-identical.
segmentation-trajectory 0.7.1→0.7.2
394f3cc → e7688ff, 3 commits
(step 3 — produces the run3 geoshift)
Memory/perf only (np.memmapopen_memmap, zip-streamed npz writes) + an unrelated write_only_segments filter. None geoshift-reuse code paths untouched.
filtering-surface 0.7.4 vs 0.7.5 Quirk: 0.7.5 is absent from the repo history (tags: 0.7.3 → 0.8.0; 0.7.4 sits on the diverged AI3D-288 branch). 0.7.3→0.7.4 contains a real local-axis bugfix (OBB rotation row/column swap + grid-cell centering in the road-surface lattice). Indirect only this package doesn't compute or write the XML geoshift; the axis fix affects road-surface patch geometry, not coordinate frames of exported points.

Conclusion: commit evidence proves the geoshift computation and the XML <Geoshift> write path are identical code in 0.9.1 and 0.9.3 — the version gap is provenance-only (which steps MetaData lists, two minor step-3 pins). The 4_5 XML is safe to consume by the same rule as the Azure XMLs.

Data locations

Method

How this was verified (2026-07-15)
  • Sidecars: 15 sampled (first/middle/last segment per branch: A1 b000+b001, A2, A3 from blob s4 outputs; 4_5 from N:). All carry km-multiple geoshift, sub-km (x, y), pixels_per_meter 15.0, geoshift_source: null. 4_5 sidecars lack the s4 provenance fields (pipeline_step, branch_id, segment_name, file_prefix) — geometric fields identical in form.
  • XMLs: all five parsed fully (97k–189k points each); min/max of every Point X/Y/Z computed; <MetaData> and <Geoshift> extracted verbatim.
  • LAS: header-only reads (bytes 0–499, struct-parsed min/max; signature LASF checked) — 2 files per Azure dataset via ranged blob download, 2 for 4_5 from N:. A1/A2/4_5 are LAS 1.2 per-record files; A3 is LAS 1.4 whole-route Run files.
  • Frame cross-check: sidecar-derived tile spans bracket XML extents at both ends of 4_5 (seg000, seg142) and A1 b000 (seg000, seg130), within 1–8 m of tile edges.
  • Segment counts: A1 131+11, A2 253, A3 311, 4_5 143.