[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, CheckTransitData.
    Analysis: RunTravelTimeMatrix, RunAccessibility, RunServiceMinutes,
    RunCompetitiveAccessibility (2SFCA), SummarizeAccessibilityEquity,
    GenerateIsochrones, PreparePopulationLayer, PopulationOverlay. Scenarios:
    BuildScenario (new lines, removed / re-timed routes, applied by R5 in
    memory), CompareScenarios.
version=0.3.0
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.3.0
    * feat(scenarios): BuildScenario + a SCENARIO parameter on every
      matrix-based algorithm — new lines drawn in QGIS, routes removed, sped
      up/slowed down or re-timed; R5 applies the modifications in memory, no
      network rebuild. CompareScenarios diffs two result layers by id and
      refuses to mix method changes (percentile, decay, window).
    * feat(diagnostics): CheckTransitData — GTFS pre-flight report: active
      trips per day and on DATE, route types R5 7.6 cannot read, broken
      references, stops outside the study area, realized + static feeds in one
      folder.
    * feat(analysis): RunCompetitiveAccessibility — 2SFCA / E2SFCA-style
      competitive accessibility (capacity per N residents).
    * feat(analysis): SummarizeAccessibilityEquity — population-weighted share,
      quantiles and Gini, overall and per group, with an HTML report.
    * fix(runner): the compiled Java runner is rebuilt when a plugin update
      changes its source (a stale runner silently ignored new job fields).
    * fix(runner): timing results use a locale-independent decimal point, so
      the sampled time estimate works on a Polish-locale system.
    * fix(runner): MONTE_CARLO_DRAWS is now really per minute. R5 reads
      monteCarloDraws as the total over the window, so the default 5 gave about
      one draw per minute on networks with frequency routes (every scenario
      line, Warsaw's frequencies.txt). Such runs are slower (measured 1.4x on
      Lodz with one added line; up to 5x on mostly-frequency networks) but
      reproducible; networks without frequencies are unchanged.
    0.2.2
    * feat(analysis): RunServiceMinutes — for each origin-destination pair,
      counts how many of the departure window's minutes (120 by default) reach
      the destination within each cutoff, from R5's per-minute travel-time
      histogram (recordTravelTimeHistograms). Reuses the "matrix" runner
      command so the walk-only/dead-date safety checks stay single-sourced;
      Java does the cutoff-sum reduction, so the process boundary carries only
      svc_min_c<cutoff> columns, never the raw 120-minute array. This is NOT
      the same number as easy-OTP's service-time classification (otp_mean /
      st_class) — different mechanism, different reference window; see
      docs/prd/PR_easy-R5_v02_service-minutes.md.
    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.
