[general]
name=Easy-R5
qgisMinimumVersion=3.22
qgisMaximumVersion=3.99
description=Transit accessibility analysis with the Conveyal R5 routing engine.
about=Runs the Conveyal R5 routing engine (v7.6, MIT) as a child process to
    compute one-to-many and many-to-many travel-time matrices,
    cumulative-opportunity accessibility and travel-time isochrones over a
    departure-time window, returning styled QGIS layers. R5 and a Temurin 21 JDK
    are downloaded on first setup — no R, no Docker, no administrator rights.
    The two population algorithms need openpyxl; its pure-Python wheel is fetched
    from PyPI (SHA-256 verified, no pip) on first load and every other algorithm
    runs without it.
    Setup: DownloadR5 (Temurin 21 JDK + r5-v7.6-all.jar, SHA-256 verified),
    DownloadRealizedGtfs (archival / realized feeds from GISBoost's
    gtfs-dashboard index), BuildNetwork (cached network.dat + network.json with
    per-date active trip counts). Diagnostics: TestR5Setup. Analysis:
    RunTravelTimeMatrix, RunAccessibility, GenerateIsochrones,
    PreparePopulationLayer, PopulationOverlay.
version=0.2.1
author=Michal Kaczorowski
email=michal.kaczorowsx@gmail.com
repository=https://github.com/GISBoost/easy-R5
tracker=https://github.com/GISBoost/easy-R5/issues
homepage=https://gisboost.github.io/easy-R5/
category=Analysis
icon=resources/icon.svg
license=GPL-3.0-or-later
tags=accessibility,r5,conveyal,transit,gtfs,travel time,isochrone,public transport,routing,java
experimental=True
deprecated=False
hasProcessingProvider=yes
hasTranslations=yes
changelog=0.2.1
    * fix(qt6): every enum access across algorithms/ + gui/ fully qualified
      (e.g. QgsFeatureSink.Flag.FastInsert, not QgsFeatureSink.FastInsert) —
      the short form is a PyQt5-only convenience that PyQt6 drops, and QGIS
      3.40 can be built against either. 53 call sites, no logic change,
      identical behaviour under Qt5.
    * fix(matrix): points — a destination/origin layer whose schema changed on
      disk after being loaded into QGIS (e.g. columns added by another
      script/algorithm run) could leave the project holding a stale cached
      field list; write_points_csv() now raises loudly, naming the missing
      field(s), instead of silently writing wrong/zero values (#5).
    * perf(runner): EasyR5Runner matrix mode routes origins across a thread
      pool (one thread per available core) instead of one at a time — R5's
      LinkageCache and EgressCostTable are safe to share across origins run in
      parallel, each origin still gets its own RegionalTask/TravelTimeComputer;
      measured ~3x wall-clock on a 213-origin job, byte-identical output vs.
      the old sequential path (#4).
    * feat(resources): real plugin icon — a point-up hexagon with a
      schematic route network (own composition, own accent color; not a
      copy of r5r/r5py's sticker) replaces the placeholder "R5" square;
      sized 512x512 intrinsic to match easy-OTP's icon and display at the
      same size in the QGIS Plugin Manager.
    0.2.0
    * feat(setup): DownloadRealizedGtfs — pick a city + date + variant (realized
      P50/P85 or scheduled) and download that GTFS feed from GISBoost's
      gtfs-dashboard index, into a folder ready for Build R5 network. No GitHub
      API calls (the manifest is a static CDN file); no checksum published, so
      the download is CRC-checked and sniffed for the GTFS files only.
    * feat(gui): 'Plugins > Easy-R5 > Download transit recordings…' — a
      cascading city > month > day picker over the live index. The plugin's
      first and only dialog (see docs/prd/PR_easy-R5_v02_realized-gtfs.md §1).
    * refactor(core): downloads — HTTP download + safe zip/tar extraction moved
      out of DownloadR5 so both Setup algorithms share it.
    * feat(core): gtfs_dashboard — manifest client (fetch + disk cache + resolve).
    0.1.0
    * M5 — isochrones, population layers, release.
    * fix(deps): drop the pip fallback from the openpyxl bootstrap — urllib
      wheel + _vendor/ only, never shell out to pip (CLAUDE.md).
    * fix(java): -XX:+ExitOnOutOfMemoryError so an R5 worker-thread OOM cannot
      hang the process; runner reports setup vs routing time for a sane estimate.
    * fix(analysis): validate DATE/DEPARTURE_TIME before the JVM; RunAccessibility
      lifts MAX_TRIP_DURATION to cover a larger cutoff and joins results by id;
      GenerateIsochrones takes exactly one percentile; output field percentiles
      -> percentile (PRD 5.2).
    * feat(analysis): GenerateIsochrones — travel-time polygons per cutoff from
      N points (grid -> one-origin matrix -> contour in QGIS; R5 does not
      contour). Styled output, per-cutoff error isolation.
    * feat(analysis): PreparePopulationLayer + PopulationOverlay — ported from
      easy-OTP (GUS NSP 2021 -> census geometry; area-weighted onto a hex grid,
      fractional). XLSX read in a subprocess. openpyxl bootstrap (CLAUDE.md
      exception, confirmed).
    * feat: styles/ QML auto-applied to matrix / accessibility / isochrone
      outputs.
    * feat(i18n): easy_r5.pro + i18n/easy_r5_pl.ts/.qm (partial PL — see #1).
    * docs: README rewritten with real usage + the hex-grid recipe;
      KNOWN_ISSUES.md.
    * No hex-grid algorithm (PRD §4.7) and no service-minutes / scenarios /
      itineraries / GTFS-RT (§9) — v0.2+.
    0.0.4
    * M4 — cumulative-opportunity accessibility.
    * feat(analysis): RunAccessibility — opportunities reachable per origin /
      cutoff / percentile, summed in Python from the matrix (STEP, LOGISTIC,
      EXPONENTIAL decay); long CSV in r5r's layout + an ORIGINS copy with
      acc_<opp>_p<pct>_c<cutoff> fields.
    * feat(core): accessibility — decay weights + the cumulative sum.
    * refactor: shared matrix machinery (gates, point export, estimate, batched
      processes, walk-only guard) moved to algorithms/_matrix_base.MatrixBase.
    * docs: validation-gdansk.md — RunAccessibility vs r5r's Gdańsk output.
    0.0.3
    * M3 — travel-time matrix (the flagship algorithm).
    * feat(analysis): RunTravelTimeMatrix — one-to-many / many-to-many travel
      times over a departure window; percentiles, batched processes, sampled
      time estimate, hard dead-date gate + post-run walk-only detector.
    * feat(java): EasyR5Runner command "matrix" — ports the verified
      Probe.java RegionalTask / FreeFormPointSet recipe.
    * feat(core): points (layer -> id,lon,lat CSV, EPSG:4326, stable ids),
      matrix (batch merge, systematic sample, nearest served days).
    0.0.2
    * M2 — network building + GTFS service-day validation.
    * feat(setup): BuildNetwork — build a cached network.dat from an OSM extract
      and a folder of GTFS feeds; cache keyed by input hash + R5 version;
      FORCE_REBUILD bypasses it.
    * feat: network.json carries service_days — active trip count per date over
      a 90-day window (calendar.txt + calendar_dates.txt, type 1/2 exceptions).
    * feat(java): EasyR5Runner command "build".
    0.0.1
    * M1 — plugin skeleton + R5 engine on disk.
    * feat: Processing provider "Easy-R5" (id easyr5).
    * feat(setup): DownloadR5 — Temurin 21 JDK + r5-v7.6-all.jar, SHA-256
      verified, paths saved under the easy_r5/ QSettings namespace, one-file
      Java runner compiled to <target>/runner_cache/.
    * feat(diagnostics): TestR5Setup — reports each check independently
      (JDK / jar / runner / optional command=info on a network.dat).
    * feat(java): EasyR5Runner.java — command "info" only; full stdout protocol.
