Open-source toolchain that ingests a free DEM and two station coordinates, then emits a permit-grade aerial-ropeway alignment — tower placement, catenary cable, Eurocode safety checks, AutoCAD DXF, LandXML, 3-D digital twin, bill of materials and regional capex estimate — in under fifteen seconds on a laptop.
Validated against textbook catenary identities to 0.00 % on three reference designs, and against twelve real installations covering all six system archetypes on five continents — jig-back (Aiguille du Midi, Zugspitze, Roosevelt Island, Portland OHSU), MGD (Mi Teleférico Línea Roja, Medellín Línea K, Cablebús Línea 2, IFS Cloud London), 3S (Whistler Peak 2 Peak), funitel (Péclet, Val Thorens), BGD (Ngong Ping 360), chairlift (Whistler) — within published-spec tolerances.
No cloud. No GPU. No vendor lock-in. Runs on a consumer PC.
Fed only the two station coordinates and a Copernicus GLO-30 DEM tile, the optimizer reproduces the world-record 2 867 m unsupported span of the Téléphérique de l'Aiguille du Midi (Stage 2) at 2 850 m — a 0.6 % delta — with no hand-tuning and no prior knowledge of the as-built design.
See docs/case_studies/aiguille_du_midi.md.
git clone https://github.com/harsh-pandhe/Autonomous-Ropeway-Alignment
cd Autonomous-Ropeway-Alignment
make install # creates .venv, pip-installs everything
make demo # 3 km synthetic terrain end-to-end run
make test # pytest (157 tests, ~26 s)
make ui # Streamlit UI at http://localhost:8501
ropeway serve # FastAPI service at :8000 (docs at /docs)
docker compose up --build # full stack: API + PostgresTo run against real terrain, download a free Copernicus GLO-30 tile:
curl -fL -o data/dem/Copernicus_DSM_N45_E006.tif \
"https://copernicus-dem-30m.s3.eu-central-1.amazonaws.com/Copernicus_DSM_COG_10_N45_00_E006_00_DEM/Copernicus_DSM_COG_10_N45_00_E006_00_DEM.tif"
ropeway run \
--dem data/dem/Copernicus_DSM_N45_E006.tif \
--start 6.870 45.892 --end 6.887 45.916 \
--system jigback --generations 60| Category | Capability |
|---|---|
| Terrain ingestion | Copernicus GLO-30 / NASADEM / SRTM GeoTIFF → 2-D corridor profile or 3-D terrain swath (auto UTM reprojection) |
| Catenary mechanics | Inclined catenary kernel; sag / tension / break-over; per-span horizontal tension with sheave-loss propagation |
| Load model | Eurocode EN 1991-1-4 wind, ISO 12494 ice, ANSI B77.1 live load (170 lbf/seat, 1.10 dynamic factor) |
| Safety envelope | EN 12929-1 piecewise clearance (open / road / railway / building / water), wind swing buffer, foundation overturning + sliding SF, EN 1993-1-1 tower buckling + bending |
| Optimizers | DEAP single-objective GA · pymoo NSGA-II Pareto front · stable-baselines3 PPO RL agent · scikit-learn RSM surrogate |
| System catalogue | MGD, BGD, 3S, jig-back, chairlift, funitel — system-appropriate defaults via --system flag |
| Comfort | ISO 2631 vertical + lateral acceleration, 4 h reduced-comfort boundary rating |
| Geometry | Straight-line or curved (Bezier / polyline waypoint) corridors. GA + NSGA-II honour no-tower exclusion zones (avalanche / water / property / protected / military) and pinned intermediate passenger stations — towers route around forbidden terrain and the layout always contains the pinned stations |
| Outputs | PNG plots, GeoJSON, CSV tower schedule, AutoCAD DXF, LandXML 1.2, multi-page validation PDF, interactive 3-D HTML twin, Bill of Materials, regional capex estimate |
| Service layer | FastAPI REST API with JWT auth, role-based access, audit log, immutable snapshots, Docker stack (API + Postgres 16) |
| Phase | Status | Summary |
|---|---|---|
| 1 | ✅ | Geospatial + catenary physics core |
| 2 | ✅ | GA optimizer + Streamlit MVP UI |
| 3 | ✅ | NSGA-II Pareto + RSM surrogate + LandXML + PDF report |
| 4 | ✅ | PyVista 3-D digital twin + project SQLite persistence |
| 5 | ✅ | Gymnasium RL env + PPO agent + GA/NSGA-II/RL benchmark |
| 6 | ✅ | Eurocode wind/ice + multi-rope catalogue + comfort + validation harness |
| 7 | ✅ | Curved 3-D routes + obstacle exclusion polygons |
| 8 | ✅ | AutoCAD DXF + Bill of Materials + regional cost estimator |
| 9 | ✅ | FastAPI service + JWT/RBAC + SQLAlchemy + audit log + Docker |
| 9.5 | ✅ | DEM upload endpoint + project optimize + export endpoints + CI |
| 11 | ✅ | Pricing + pitch + whitepaper + landing page |
| 12a | ✅ | Eurocode 3 tower structural check (buckling + bending) |
| 15a | ✅ | Case study: Aiguille du Midi + --system CLI flag |
| 15b | ✅ | Case study: Mi Teleférico Línea Roja (urban gondola) |
| 15c | ✅ | Case study: Whistler Peak 2 Peak (3S — motivated obstacle-zone gap) |
| 7+ | ✅ | No-tower exclusion zones + pinned intermediate stations wired into GA + NSGA-II |
| 12b | ✅ | Coupled elastic-cable solver (per-span elongation + thermal — hot day lowers clearance, cold day raises tension) |
| 12c | ✅ | Joint horizontal + vertical alignment optimization (per-tower lateral offset within a DEM swath) |
| 13 | ✅ | AI assistant (LLM natural-language → optimization) — ropeway ask "..." |
| 14 | ✅ | htmx web client (shareable links) — / + /htmx/run/{rid} |
| 12d | ✅ | ForcedFlyOverZone — bridge / freeway / shipping-channel corridor intervals where the cable must clear a minimum absolute elevation (dual of NoTowerZone) |
| 12f | ✅ | Curved corridor DEM extraction — `extract_profile_along_route(dem, waypoints, kind="polyline" |
| 15b-redux / 15c-redux | ✅ | Re-ran Línea Roja with Cementerio pinned (3-station topology now matches) + Whistler with Fitzsimmons no-tower valley (2 806 m single span, 7 % vs as-built 3 024 m, down from 47 %) |
| 15d | ✅ | Case study: Roosevelt Island Tramway (NYC urban jig-back) |
| 15e | ✅ | Case study: Medellín Metrocable Línea K (MGD, 4-station, 2 pinned waypoints) |
| 15f | ✅ | Case study: Seilbahn Zugspitze (jig-back record span + Phase 12b thermal sweep) |
| 15g/h/i | ✅ | Case studies: Funitel de Péclet, Ngong Ping 360 (BGD), Whistler chairlift — completes all six system archetypes |
| 15j/k/l | ✅ | Case studies: Cablebús Línea 2 (CDMX), IFS Cloud Cable Car (London), Portland OHSU Tram — twelve installations, five continents |
| 16 | ⬜ | Outreach prep (videos, LinkedIn list, translations) |
| 17 | ⬜ | Industry validation gate (3 engineer trials) |
| 18-23 | 🔒 | Money phases (TÜV, ISO 9001, conferences) — locked behind validation gate |
Honest scorecard: docs/SCORECARD.md — where this stands vs RopeCAD / ROPEKON / Cassia by segment.
| Case | System | Match | Doc |
|---|---|---|---|
| Téléphérique de l'Aiguille du Midi (Stage 2) | jig-back aerial tram | longest span: 2 850 m vs 2 867 m as-built (0.6 %) | aiguille_du_midi.md |
| Seilbahn Zugspitze (Eibsee) | jig-back aerial tram | longest span: 3 300 m vs 3 213 m as-built (+2.7 %), elevation gain 1 962 m vs 1 945 m (+0.9 %); + Phase 12b thermal sweep | zugspitze_eibsee.md |
| Roosevelt Island Tramway (NYC) | jig-back aerial tram | horizontal length: 872 m vs 940 m as-built (−7.2 %); honest gap — DEM has no Queensboro Bridge | roosevelt_island.md |
| Mi Teleférico Línea Roja (La Paz – El Alto) | MGD urban gondola | elevation gain: 476 m vs 485 m as-built (1.9 %); 3-station topology matches with Cementerio pinned (Phase 7+) | mi_teleferico_linea_roja.md |
| Metrocable Línea K (Medellín) | MGD urban gondola | 4-station topology matches with 2 pinned waypoints (Phase 7+); elevation gain 354 m vs 405 m | medellin_linea_k.md |
| Whistler Blackcomb Peak 2 Peak | 3S tri-cable | longest span: 2 806 m vs 3 024 m as-built (−7.2 %, was 47 % gap); single valley-spanning shot with Fitzsimmons no-tower zone (Phase 7+) | whistler_peak2peak.md |
| Funitel de Péclet (Val Thorens) | funitel | elevation gain: 650 m vs ≈ 650 m as-built (exact); world's first funitel | funitel_peclet.md |
| Ngong Ping 360 (Hong Kong) | BGD bi-cable gondola | straight-corridor 5 248 m vs 5 700 m route; reproduces the bay-crossing + hill-climb profile | ngong_ping_360.md |
| Whistler Mountain chairlift | chairlift | archetype match — short spans (mean 187 m), dense towers, low tension (198 kN) | whistler_peak_chair.md |
| Cablebús Línea 2 (CDMX) | MGD urban gondola | the longest urban gondola at opening (10.6 km, 7 stations); straight corridor 4 749 m baseline — 2.2× Phase 12c routing gap | cablebus_linea2.md |
| IFS Cloud Cable Car (London) | MGD urban gondola | Thames crossing single span 778 m vs ≈ 800 m as-built (−2.7 %); UK's only urban cable car | london_ifs_cloud.md |
| Portland Aerial Tram (OHSU) | jig-back aerial tram | elevation gain 137 m vs 152 m (−9.9 %); cabin 80 vs 79 pax (1-pax match); honest gap — DEM has no I-5 deck | portland_ohsu.md |
Twelve real installations now validated across all six system
archetypes (jig-back, MGD, BGD, 3S, funitel, chairlift) on five
continents. Phase 7+ closed the original "honest gaps": pinned
stations give Línea Roja (3-station) and Medellín Línea K (4-station)
like-for-like topology matches; the Fitzsimmons no-tower zone forces
Whistler into its single record span. Zugspitze reproduces a
world-record 3 213 m span to 2.7 % and adds the Phase 12b hot-day /
cold-day thermal sensitivity sweep. London Thames + Roosevelt Island +
Portland I-5 all point at the same next constraint: a forced-fly-over
obstacle volume (the dual of Phase 7+ NoTowerZone).
Each case study ships with the alignment plot, AutoCAD DXF, LandXML, validation PDF, BOM CSV and regional cost estimate so reviewers can inspect every artifact without re-running.
| Command | Purpose |
|---|---|
ropeway demo |
Synthetic terrain GA run (no DEM needed) |
ropeway run --dem DEM --start LON LAT --end LON LAT |
Real DEM GA run |
ropeway pareto --dem DEM ... |
NSGA-II Pareto front (cost / break-over / tension) |
ropeway view3d --dem DEM ... |
Export interactive 3-D digital_twin.html |
ropeway rl-train --timesteps 200000 --out outputs/rl_policy |
Train PPO policy |
ropeway rl-run --policy outputs/rl_policy.zip |
Roll out trained policy |
ropeway benchmark --seeds 1,2,3 |
GA vs NSGA-II vs RL comparison harness |
ropeway validate |
Reference-design validation harness (3 cases, 0 % error) |
ropeway serve --host 0.0.0.0 --port 8000 |
FastAPI service (auth / projects / optimize) |
All commands accept --system mgd|bgd|3s|jigback|chair|funitel to load
system-appropriate defaults from ropeway.multi_rope.
Both the GA (ropeway.optimizer.optimize) and NSGA-II
(ropeway.multi_optimizer.optimize_pareto) accept two extra parameters
that close the gaps surfaced by the Linea Roja and Whistler case studies:
from ropeway.obstacles import NoTowerZone, ZoneKind
from ropeway.optimizer import optimize
result = optimize(
profile_fn, corridor_length, cfg=cfg, ga=ga,
no_tower_zones=[
NoTowerZone(900.0, 1400.0, kind=ZoneKind.PROTECTED, name="Fitzsimmons Cr."),
],
intermediate_stations=[1500.0], # pinned passenger station
)no_tower_zones— list of forbidden along-corridor intervals. The decoder drops GA towers in zones and snaps max-span fillers past zone edges, so a decoded layout never places a non-station tower in forbidden terrain.intermediate_stations— distances of pinned passenger stations. They always appear in the layout, are flaggedis_station=True(break-over-exempt, zone-exempt), and GA towers that would crowd them are dropped.
See examples/demo_no_tower_zone.py for a three-run before/after demo.
ropeway serve # OpenAPI docs at /docs
curl -sX POST localhost:8000/auth/register \
-H 'Content-Type: application/json' \
-d '{"email":"eng@example.com","password":"supersecret123","role":"approver"}'
TOK=$(curl -sX POST localhost:8000/auth/login \
-d 'username=eng@example.com&password=supersecret123' | jq -r .access_token)
curl -sX POST localhost:8000/projects -H "Authorization: Bearer $TOK" \
-H 'Content-Type: application/json' -d '{"name":"My Gondola"}'
curl -sX POST localhost:8000/optimize/run -H "Authorization: Bearer $TOK" \
-H 'Content-Type: application/json' \
-d '{"corridor_length_m":3000,"generations":40,"population":60}'| Method | Path | Notes |
|---|---|---|
| POST | /auth/{register,login}, GET /auth/me |
JWT issuance + bearer auth |
| GET / POST / PUT | /projects[/{id}] |
CRUD with ownership + RBAC |
| POST | /projects/{id}/{submit,approve,lock} |
Workflow; lock creates immutable snapshot |
| GET | /projects/{id}/{snapshots,audit} |
Approval history + audit log |
| POST | /optimize/run |
GA on synthetic terrain |
| POST | /optimize/dem |
Multipart GeoTIFF upload + GA on real terrain |
| POST | /projects/{id}/optimize |
Run GA on stored project, bump version |
| GET | /projects/{id}/export/{fmt} |
fmt ∈ geojson | csv | landxml | dxf | pdf |
src/ropeway/
physics.py catenary cable mechanics (textbook-validated)
dem.py GeoTIFF loader, 2-D profile + 3-D corridor patch
safety.py EN 12929-1 + ANSI B77.1 envelope + foundation SF
structural.py EN 1993-1-1 tower buckling + bending
environmental_loads.py EN 1991-1-4 wind + ISO 12494 ice accretion
multi_rope.py ropeway system catalogue (MGD/BGD/3S/jigback/...)
comfort.py ISO 2631 passenger-comfort metrics
tension_solver.py per-span horizontal tension with sheave losses
alignment.py tower layout -> cable segments -> evaluation
optimizer.py DEAP GA driver
multi_optimizer.py pymoo NSGA-II Pareto driver
surrogate.py scikit-learn RSM surrogate
rl_env.py Gymnasium env for sequential tower placement
rl_agent.py PPO train + deterministic rollout
benchmark.py GA vs NSGA-II vs RL benchmark harness
validation.py reference-design diff harness
routes.py curved 3-D corridors (Bezier / polyline)
obstacles.py polygon exclusion zones
viz.py / viz3d.py matplotlib + PyVista visualization
io.py / landxml.py / dxf_export.py / report.py
bom.py / cost.py bill of materials + regional capex estimator
project.py SQLite project save/load
cli.py click CLI
server/ FastAPI service (config, db, models, schemas,
auth, api)
app/streamlit_app.py desktop / browser UI
examples/ demo scripts + case-study runners
tests/ pytest suite (124 tests)
docs/ case studies, GTM materials, whitepaper, pricing
.github/ CI workflow + issue/PR templates
ropeway validatecase sag err len err T err pass
----------------------------------------------------------------------
Alpine MGD short span 0.00% 0.00% 0.00% YES
Bi-cable tram long span 0.00% 0.00% 0.00% YES
3S level long span 0.00% 0.00% 0.00% YES
Overall: PASS
Three textbook closed-form catenary references are exercised every run. External validation (TÜV / Bureau Veritas) is on the roadmap — deferred until real industry users sign on, per Phase 17 gate criteria.
make test # 124 tests, ~20 s
env -u PYTHONPATH .venv/bin/pytest -v # full verbose suiteCI (.github/workflows/ci.yml) runs pytest + the validation harness on every
push / PR, plus a parallel Docker-build + container-health-check job.
- Copernicus GLO-30 (recommended, DSM, 30 m global) https://spacedata.copernicus.eu/
- NASADEM (DTM, 30 m, near-global) https://lpdaac.usgs.gov/
- SRTM 1-arcsec (DTM, 30 m, 60S-60N) https://earthexplorer.usgs.gov/
Reprojection to UTM and nodata interpolation are handled internally.
DXF viewer: Linux has no default for image/vnd.dxf so xdg-open will
fail. Install LibreCAD (sudo apt install librecad) or upload the file to
https://sharecad.org for a quick browser preview.
The Gymnasium env + PPO agent + benchmark harness all work end-to-end, but on the static single-corridor layout problem the GA / NSGA-II convincingly beat PPO. A representative benchmark (3 km synthetic corridor, 80 k training steps per RL run):
| Method | Feasible | Mean cost | Towers | Wall-clock |
|---|---|---|---|---|
| GA | 100 % | 694 k | 6.0 | 0.6 s |
| NSGA-II | 100 % | 675 k | 6.0 | 0.9 s |
| PPO | 0 % | n/a | n/a | 28.6 s |
PPO's value is tactical generalization across many similar problems (one trained policy, many corridors), not beating a global optimizer on one fixed corridor. Curriculum-style multi-corridor training is the natural next step; for production design work GA and NSGA-II remain the right default.
- docs/PRICING.md — tier table + discounts + procurement
- docs/PITCH.md — 10-slide investor / customer deck outline
- docs/WHITEPAPER.md — peer-review paper skeleton
- docs/landing.html — static landing page
PRs welcome. See CONTRIBUTING.md for the workflow
(feature branch → PR → CI → squash merge) and the per-phase pattern used
for everything currently in main.
Security issues: see SECURITY.md for the responsible-disclosure process. Code of conduct: CODE_OF_CONDUCT.md.
MIT — see LICENSE.
Standards referenced (none vendored): EN 12929-1, ANSI B77.1, EN 1991-1-3, EN 1991-1-4, EN 1993-1-1, ISO 12494, ISO 2631, EU 2016/424.