Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Transport for Cairo — OpenTripPlanner Portable Package (OTP 1.4.0)

Project: Abidjan Multimodal Transport Network
Maintained by: Transport for Cairo (TfC)
Contact: info@transportforcairo.com


Purpose

Run an OpenTripPlanner (OTP) 1.4.0 instance for Abidjan with zero installs. The bundle includes a portable Java runtime, your data, and scripts. Analyst mode (isochrones) is enabled.


Folder structure

abidjan-otp/
├─ otp.jar
├─ jre/                       # portable Java (JRE/JDK)
├─ data/
│  ├─ abidjan.osm.pbf
│  └─ abidjan.gtfs.zip
├─ graphs/                    # built graph (auto-created)
├─ config/
│  ├─ build-config.json
│  └─ router-config.json
├─ web/                       # your isochrones web app (index.html, js, css)
├─ proxy/
│  ├─ Caddyfile
│  ├─ caddy.exe               # Windows binary (no install)
│  ├─ caddy                   # macOS/Linux binary (no install, chmod +x)
│  ├─ start-proxy.bat
│  └─ start-proxy.sh
└─ scripts/
   ├─ build-graph.bat / build-graph.sh
   ├─ start-otp.bat / start-otp.sh
   └─ start-all.bat           # NEW: combined starter (Windows)

One-click startup (Windows) — start-all.bat

start-all.bat will:

  1. Build the graph if missing.
  2. Start OTP 1.4.0 in Analyst mode (auto-detects Java 8 vs 11/17 and adds module flags when needed).
  3. Start the local proxy at http://localhost:3000 which serves the web app and proxies /otp to OTP with CORS headers.

Usage: double-click scripts/start-all.bat, then open http://localhost:3000/


Classic (manual) usage

Build

scripts\build-graph.bat

(or on macOS/Linux: scripts/build-graph.sh)

Run OTP 1.4.0 in Analyst mode

scripts\start-otp.bat

Then (optional if you want same-origin+CORS solved):

proxy\start-proxy.bat    # then open http://localhost:3000

Java compatibility

  • OTP 1.4.0 was built for Java 8. It also runs on Java 11/17 if you add Java module opens flags.
  • The bundled scripts auto-detect Java version:
    • On Java 8: no extra flags.
    • On Java 11/17: adds: --add-opens=java.base/java.io=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/sun.nio.ch=ALL-UNNAMED

If you switch Java, rebuild the graph with the same otp.jar you run.


Analyst (isochrones) API

OTP 1.4.0 exposes the isochrone endpoint after starting in Analyst mode:

GET /otp/routers/default/isochrone?fromPlace=lon,lat&mode=WALK,TRANSIT&date=YYYY-MM-DD&time=HH:MM:SS&cutoffSec=900&cutoffSec=1800
  • The endpoint may return GeoJSON or a zipped Shapefile.
  • Your app should set header Accept: application/json. As a fallback, include shpjs to parse zipped shapefiles to GeoJSON in-browser.

Client helper (snippet)

// include in browser:
/*
<script src="https://unpkg.com/shpjs@latest/dist/shp.min.js"></script>
*/

async function fetchIsochrone(base, params) {
  const url = `${base}/isochrone?${params.toString()}`;
  const r = await fetch(url, {
    headers: { "Accept": "application/json", "Content-Type": "*/*" }
  });
  if (!r.ok) throw new Error(`${r.status} ${r.statusText}`);

  const ct = (r.headers.get("content-type") || "").toLowerCase();
  if (ct.includes("json")) return r.json();

  if (ct.includes("zip") || ct.includes("octet-stream")) {
    const buf = await (await r.blob()).arrayBuffer();
    const parsed = await shp(buf);
    if (parsed && parsed.type === "FeatureCollection") return parsed;
    if (parsed && typeof parsed === "object") {
      const feats = Object.values(parsed)
        .filter(v => v && v.type === "FeatureCollection")
        .flatMap(fc => fc.features || []);
      return { type: "FeatureCollection", features: feats };
    }
    throw new Error("Unrecognized shapefile contents");
  }
  throw new Error(`Unexpected content-type: ${ct}`);
}

Proxy (self-contained, no install)

We bundle Caddy (single binary) to serve the web app and proxy /otp to OTP. This solves CORS and gives a same-origin URL.

proxy/Caddyfile

:3000 {
  root * ../web
  file_server

  @preflight {
    method OPTIONS
    path /otp/*
  }
  header @preflight Access-Control-Allow-Origin "*"
  header @preflight Access-Control-Allow-Methods "GET, POST, OPTIONS"
  header @preflight Access-Control-Allow-Headers "Origin, Content-Type, Accept, Authorization"
  respond @preflight 204

  @otp path /otp/*
  header @otp Access-Control-Allow-Origin "*"
  header @otp Access-Control-Allow-Methods "GET, POST, OPTIONS"
  header @otp Access-Control-Allow-Headers "Origin, Content-Type, Accept, Authorization"
  reverse_proxy 127.0.0.1:8080
}

Client base URL (when proxy is running)

const base = "http://localhost:3000/otp/routers/default";

Troubleshooting

  • If OTP logs mention Kryo/Objenesis reflection errors, you are on Java 11/17 without module flags; use the included start scripts or Java 8.
  • If the API returns a zip, your fallback parser will convert it to GeoJSON.
  • If the browser shows CORS errors, ensure you started the proxy and your app is using http://localhost:3000 as base.

Contact

Transport for Cairo (TfC) — info@transportforcairo.com https://transportforcairo.com

About

Portabloe OTP viewer for AMUGA's first GTFS

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages