Skip to content

Keep curvature calculations finite for valid road geometry - #101

Open
FrogAi wants to merge 1 commit into
pfeiferj:mainfrom
FrogAi:codex/keep-curvature-geometry-finite
Open

Keep curvature calculations finite for valid road geometry#101
FrogAi wants to merge 1 commit into
pfeiferj:mainfrom
FrogAi:codex/keep-curvature-geometry-finite

Conversation

@FrogAi

@FrogAi FrogAi commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Developer summary

CalculateCurvature can produce NaN angle and arc values for valid straight, near-collinear, and inverse-trig-boundary road geometry. Those values then poison weighted curve averaging and can reject otherwise valid next-way connections.

This keeps the calculation finite by preserving float64 distance precision internally, using a cancellation-resistant form of Heron's formula, and applying the finite straight-line limit. The exported DistanceTo(Position) float32 API and its rounding are unchanged.

Verification

  • Current main fails the focused primitive and downstream-pipeline matrix; this branch passes it 100 consecutive times.
  • go test ./..., go test -race ./..., go vet ./..., and go build ./... pass on Linux with Go 1.25.1.
  • Exact-straight, near-collinear, inverse-trig-boundary, duplicate-point, reversal, and connection-threshold cases are covered.

Compatibility

Schemas, settings, dependencies, file formats, duplicate-point behavior, and the public distance API are unchanged. The numerical fixtures establish the failure and correction, but do not measure how often real routes encounter it.


Engineering record and audit trail

Root cause

CalculateCurvature narrowed all three side lengths to float32 before applying Heron's formula. Valid near-collinear coordinates could therefore acquire a negative radicand. Exact straight geometry divided through an infinite radius, while a valid near-semicircle fixture could put the inverse-cosine input just below -1. Each path produced NaN angle or arc fields.

The consequence is not limited to the offending point. GetAverageCurvatures weights each curvature by ArcLength, so one NaN arc poisons the three-element window. The averaged curvature and target velocity then become NaN, and later comparisons silently drop that point. isValidConnection also rejects Abs(NaN) <= threshold, so otherwise valid next-way connections can be discarded.

Implementation

  • Extract the existing Haversine calculation into an unexported float64 path for curvature geometry.
  • Keep DistanceTo(Position) float32 as the public wrapper.
  • Use the sorted-side form of Heron's formula to reduce cancellation.
  • Preserve the all-zero result when any side length is zero.
  • Represent straight geometry as curvature 0, angle 0, and arc length equal to the endpoint span so weighted smoothing retains straight distance.
  • Compute nonzero central angles with 2*asin(min(1, chord*curvature/2)), then derive arc length as angle/curvature.

Red/green behavior

Case Main 1daead9 Head d7c5918
Exact straight angle/arc NaN curvature 0, angle 0, arc 222.459666459 m
Seven-decimal near-collinear all scalars NaN curvature 1.55736201944e-5 1/m, all scalars finite
Inverse-trig boundary angle/arc NaN curvature 0.137769958673 1/m, all scalars finite
Mixed straight/curve pipeline average/target NaN average 0.00211377609422 1/m, target 29.9810823142 m/s

The focused matrix also covers four duplicate layouts, reversal symmetry, a deterministic 10,000-triple finite-coordinate sweep, and fixtures bracketing the 0.10, 0.15, and 0.30 connection thresholds.

An earlier differential campaign against the same production math change covered 252 circle fixtures, 600,000 generated road triples at three jitter levels, and 1,000,000 DistanceTo pairs. It found no candidate NaN/infinite scalars and preserved the exported float32 distance results bit-for-bit. This is synthetic numerical evidence, not a prevalence study.

Final validation

The final rebased, single-commit head is d7c5918396e2ad9c6c686864f538978522be432e on current main 1daead9757c9fb5830c47bf928eddebf377a6fbb.

Check Result
Main focused matrix Expected failure at the demonstrated NaN cases
Head focused matrix, -count=100 Pass
go test ./... Pass
go test -race ./... Pass
go vet ./... Pass
go build ./... Pass
git diff --check Pass

Scope limits

This establishes the demonstrated numerical failure modes, finite downstream behavior for the supplied fixtures, and connection-threshold preservation at the tested boundaries. It does not establish route prevalence, on-road frequency or impact, global pole/antimeridian behavior, or a policy for invalid GPS coordinates.

@FrogAi
FrogAi force-pushed the codex/keep-curvature-geometry-finite branch from d068322 to d7c5918 Compare August 10, 2026 02:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant