Skip to content

feat(phase-12d): ForcedFlyOverZone — bridge/freeway/water corridor intervals#22

Merged
harsh-pandhe merged 1 commit into
mainfrom
feat/phase-12d-forced-flyover
May 20, 2026
Merged

feat(phase-12d): ForcedFlyOverZone — bridge/freeway/water corridor intervals#22
harsh-pandhe merged 1 commit into
mainfrom
feat/phase-12d-forced-flyover

Conversation

@harsh-pandhe
Copy link
Copy Markdown
Owner

Summary

Dual of NoTowerZone. Three case studies in a row surfaced the same gap — Roosevelt Island (Queensboro Bridge), London Thames (shipping channel), Portland OHSU (I-5 deck) — all man-made obstacles the DEM does not contain, so the optimizer was producing physically valid but practically wrong single-span layouts.

ForcedFlyOverZone declares an along-corridor interval where the cable must clear a minimum absolute elevation. The evaluator penalises any cable sample inside the zone that sits below min_cable_elev_m, so the GA gets a smooth gradient pushing tower heights up / inserting intermediates to lift the cable over the obstacle.

API additions

  • src/ropeway/obstacles.pyForcedFlyOverZone dataclass with normalised interval, contains / overlaps_span helpers, deficit_at (worst below-minimum inside the zone, element-wise on arrays).
  • Alignment.forced_flyover_zones (list, defaults []).
  • optimize(forced_flyover_zones=[...]) threads the list through to every alignment built per individual.

Penalty: 5e3 * deficit_m per offending span — same order as the no-tower-zone weight, so the two zones compete cleanly and the GA honours both.

Test plan

  • tests/test_forced_flyover.py10 new tests: dataclass invariants, deficit math, evaluator penalty firing / silent / outside-corridor, GA-raises-towers integration, NoTowerZone + ForcedFlyOverZone coexistence
  • Full suite 184 → 199 passing, zero regressions

…tervals

The dual of NoTowerZone. Three case studies in a row surfaced the same
gap: Roosevelt Island Queensboro Bridge, London Thames shipping
channel, Portland OHSU I-5 deck — all man-made obstacles the DEM does
not contain, so the optimizer was producing physically valid but
practically wrong single-span layouts.

ForcedFlyOverZone declares an along-corridor interval where the cable
must clear a minimum absolute elevation. The evaluator penalises any
cable sample inside the zone that sits below min_cable_elev_m, so the
GA gets a smooth gradient pushing tower heights up / inserting
intermediates to lift the cable over the obstacle.

API additions:
  - src/ropeway/obstacles.py — ForcedFlyOverZone dataclass with
    normalised interval, contains/overlaps_span helpers, deficit_at
    (worst below-minimum inside the zone, element-wise on arrays).
  - Alignment.forced_flyover_zones (list, defaults []).
  - optimize(forced_flyover_zones=[...]) threads the list through to
    every alignment built per individual.

Penalty: 5e3 * deficit_m per offending span — same order as the
no-tower-zone weight, so the two zones compete cleanly and the GA
honours both.

Tests: tests/test_forced_flyover.py — 10 new (dataclass invariants,
deficit math, evaluator penalty firing / silent / outside corridor, GA
raises towers to clear, NoTowerZone + ForcedFlyOverZone coexist on the
same corridor). Suite 184 -> 199, zero regressions.
@harsh-pandhe harsh-pandhe merged commit 28c0895 into main May 20, 2026
2 checks passed
@harsh-pandhe harsh-pandhe deleted the feat/phase-12d-forced-flyover branch May 20, 2026 07:08
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