diff --git a/CHANGELOG.md b/CHANGELOG.md index ea3ea04..44cd1b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,32 @@ that may never merge. They are not releases and are not listed here. that passes them now fails with an unknown-argument error; drop the flags. `mapbox search forward` keeps them. (#76) +- `mapbox matrix`, travel time and/or distance between every pair in a set + of up to 25 coordinates in one call, for driving (with or without live + traffic), walking, or cycling. No subcommand: like `mapbox directions` + below, this API has one operation, so there's nothing a second word (the + old `compute`) would disambiguate; see `spec::FLATTENED_SERVICES`. + Hand-authored into `custom-openapi/` for the same reason the other + Navigation commands were: no upstream spec exists yet. Reuses the + `profile`-vs-`--profile` collision fix (`ARG_NAME_OVERRIDES` gets a + fourth row) and the free-form (not `enum`) routing profile, for the same + OEM-account reason. `--sources`/`--destinations` take + semicolon-separated indices, not comma; verified against production + after the API answered a comma-separated list with a 422. + +- `mapbox map-match`, snapping a noisy GPS trace to the road network and + returning the route it most likely followed, for driving (with or + without live traffic), walking, or cycling. No subcommand: like `mapbox + directions` below, this API has one operation, so there's nothing a + second word (the old `match`) would disambiguate; see + `spec::FLATTENED_SERVICES`. Hand-authored into `custom-openapi/` for the + same reason `mapbox directions` and `mapbox isochrone` were: no upstream + spec exists yet. Reuses the `profile`-vs-`--profile` collision fix + (`ARG_NAME_OVERRIDES` gets a third row) and the free-form (not `enum`) + routing profile, for the same OEM-account reason. Excludes POST, for the + same reason `directions` does: the API's own POST is for a trace too long + for a URL, a real gap rather than a design choice. + - `mapbox isochrone`, how far you can get from a point in a given time or distance, for driving (with or without live traffic), walking, or cycling, returned as GeoJSON polygons or linestrings. No subcommand: diff --git a/README.md b/README.md index 7037624..9573702 100644 --- a/README.md +++ b/README.md @@ -251,10 +251,11 @@ mapbox styles mapbox tilesets ``` -`mapbox directions` and `mapbox isochrone` are the exceptions: each API has -a single operation, so there's a bare command with no subcommand at all, -the same shape `mapbox usage` already has, see -[docs/commands.md](./docs/commands.md) for their own parameters. +`mapbox directions`, `mapbox isochrone`, `mapbox map-match`, and +`mapbox matrix` are the exceptions: each API has a single operation, so +there's a bare command with no subcommand at all, the same shape +`mapbox usage` already has, see [docs/commands.md](./docs/commands.md) +for their own parameters. A command group is not the same thing as a spec file: which one an operation belongs to is decided per operation. So `sprites` and `tilesets` are each diff --git a/custom-openapi/map-match/openapi/map-match.yaml b/custom-openapi/map-match/openapi/map-match.yaml new file mode 100644 index 0000000..0e0ad0a --- /dev/null +++ b/custom-openapi/map-match/openapi/map-match.yaml @@ -0,0 +1,280 @@ +openapi: "3.0.0" +# `parse_spec` turns `info.description` below into this service's clap +# `long_about`, so it also reaches `mapbox map-match --help`, `--schema` +# and `generate-skills` output. Keep it to API prose only — the provenance +# below is for whoever edits this file, not for a CLI user: +# +# Hand-authored down to the parameters documented at +# docs.mapbox.com/api/navigation/map-matching. See `custom-openapi/README.md` +# for how a file like this is wired in, and `directions.yaml`'s header for +# why `profile` needs `ARG_NAME_OVERRIDES` in `src/spec.rs` — the same +# reason applies here. Excludes POST, for the same reason `directions.yaml` +# does: this spec format has no way to say "GET or POST, caller's choice" +# for one operationId. The API's own POST is for a request too long for a +# URL (~8100 bytes) — a real gap for a very long trace, not a design choice. +info: + title: "Mapbox Map Matching API" + description: >- + Snaps a noisy GPS trace to the road network and returns the route it + most likely followed, for driving (with or without live traffic), + walking, or cycling. + version: "0.0.0" +servers: + - url: https://api.mapbox.com + description: Map Matching API +paths: + /matching/v5/{profile}/{coordinates}.json: + get: + operationId: match + summary: Match a GPS trace to the road network. + description: >- + Returns one or more matched routes (more than one where the trace is + ambiguous enough to split), each with a `confidence` the API assigns + itself, plus one tracepoint per input coordinate — `null` for a + coordinate too far from any candidate to match at all. + parameters: + - name: "profile" + in: path + required: true + # Not an `enum`: the four documented values are what's public, but + # not what's exhaustive — some customers (OEM agreements, mainly) + # have additional profiles never published to docs.mapbox.com. + # An `enum` here becomes a clap `PossibleValuesParser` that + # rejects anything else client-side, which would break this CLI + # for exactly the accounts that most need a routing profile + # named beyond `driving`/`walking`/`cycling`. Same fix as + # `directions.yaml`'s `profile`. + description: >- + The routing profile — `mapbox/driving-traffic` (accounts for + live traffic), `mapbox/driving`, `mapbox/walking`, or + `mapbox/cycling` are documented, but not necessarily + exhaustive: some accounts have additional profiles of their + own. Sent exactly as typed; the API is the authority on + whether a value is valid, not this description. + schema: + type: string + minLength: 1 + example: "mapbox/driving" + - name: "coordinates" + in: path + required: true + description: >- + 2-100 trace points, semicolon-separated, each + `{longitude},{latitude}` — or an OpenLR-encoded string of up to + 50 points, in which case use `--openlr-spec`/`--openlr-format` + to say which flavor. + schema: + type: string + minLength: 1 + example: "-122.42,37.78;-122.421,37.781;-122.422,37.782" + - name: "access_token" + in: query + required: true + description: "Mapbox API Access Token" + schema: + type: string + minLength: 1 + # Prose rather than an `enum`: this is a comma-separated list, and + # the command builder turns a spec `enum` into a clap + # `PossibleValuesParser`, which accepts one value and would refuse + # `distance,duration`. Same reasoning as `directions.yaml`'s + # `annotations`. + - name: "annotations" + in: query + required: false + description: >- + Segment-level metadata to add to each leg, comma-separated. + Requires `--overview full`. Options are `distance`, `duration`, + `speed`, `congestion`, `congestion_numeric` (both + `mapbox/driving-traffic` only), `maxspeed` (`mapbox/driving` + and `mapbox/driving-traffic` only). + schema: + type: string + example: "duration,distance" + - name: "approaches" + in: query + required: false + description: >- + Which side of the road to approach each waypoint from, + semicolon-separated — `unrestricted` or `curb` per coordinate. + Requires `--steps`. + schema: + type: string + - name: "geometries" + in: query + required: false + description: "The route geometry's format. Defaults to `polyline`." + schema: + type: string + enum: ["geojson", "polyline", "polyline6"] + - name: "overview" + in: query + required: false + description: >- + How much geometry detail the response carries. Defaults to + `simplified`. + schema: + type: string + enum: ["full", "simplified", "false"] + - name: "radiuses" + in: query + required: false + description: >- + Maximum distance in meters, 0-50, a coordinate may snap to the + road network, semicolon-separated, one per coordinate. Defaults + to 5. + schema: + type: string + - name: "steps" + in: query + required: false + description: >- + Return turn-by-turn instructions. Several other parameters + (`approaches`, `banner_instructions`, `language`, + `roundabout_exits`, `voice_instructions`) only take effect when + this is set. + schema: + type: boolean + - name: "banner_instructions" + in: query + required: false + description: "Return banner objects for display. Requires `--steps`." + schema: + type: boolean + - name: "language" + in: query + required: false + description: >- + The language turn-by-turn instructions are written in. Defaults + to `en`. Requires `--steps`. + schema: + type: string + example: "en" + - name: "roundabout_exits" + in: query + required: false + description: >- + Emit a separate instruction for entering and exiting a + roundabout, rather than one instruction for the whole + maneuver. Requires `--steps`. + schema: + type: boolean + - name: "voice_instructions" + in: query + required: false + description: >- + Return SSML-marked-up voice guidance text. Requires `--steps`. + schema: + type: boolean + - name: "voice_units" + in: query + required: false + description: >- + Units for voice instructions. Requires `--steps` and + `--voice-instructions`. + schema: + type: string + enum: ["imperial", "british_imperial", "metric"] + - name: "tidy" + in: query + required: false + description: >- + Remove clusters and resample the trace before matching — useful + for a trace recorded at an inconsistent sample rate. + schema: + type: boolean + - name: "timestamps" + in: query + required: false + description: >- + A Unix timestamp per coordinate, semicolon-separated and + ascending — when the trace was actually recorded, rather than + assumed from even spacing. + schema: + type: string + - name: "waypoint_names" + in: query + required: false + description: >- + A name per waypoint, semicolon-separated, used in that + waypoint's arrival instruction instead of the road name. Up to + 500 characters total. Requires `--steps`. + schema: + type: string + - name: "waypoints" + in: query + required: false + description: >- + Zero-based indices into `coordinates` marking which ones get + their own arrival instruction, semicolon-separated — must + include `0` and the last index. Most useful with `--steps`, + which it does not require. + schema: + type: string + example: "0;2" + # Prose rather than an `enum`, for the reason given on `annotations` + # above. + - name: "ignore" + in: query + required: false + description: >- + Restrictions to ignore while matching, comma-separated. + Options are `access`, `oneways`, `restrictions`. + `mapbox/driving` only. + schema: + type: string + - name: "linear_references" + in: query + required: false + description: >- + Return an OpenLR reference (base64) per matched leg, alongside + the ordinary geometry. `mapbox/driving` and + `mapbox/driving-traffic` only. + schema: + type: boolean + - name: "openlr_spec" + in: query + required: false + description: >- + Which OpenLR specification `coordinates` is encoded with, when + it is an OpenLR string rather than a coordinate list. Defaults + to `tomtom`. + schema: + type: string + enum: ["tomtom", "here"] + - name: "openlr_format" + in: query + required: false + description: >- + The OpenLR binary format `coordinates` is encoded in, when it + is an OpenLR string. Only `tomtom` exists today. + schema: + type: string + enum: ["tomtom"] + - name: "depart_at" + in: query + required: false + description: >- + Departure time from the first coordinate, one of + `YYYY-MM-DDThh:mm`, `YYYY-MM-DDThh:mm:ssZ` or + `YYYY-MM-DDThh:mm:ss±hh:mm` — not open ISO 8601, the API + rejects other valid ISO 8601 shapes. + schema: + type: string + responses: + "200": + description: >- + A JSON object with a `code`, a `matchings` array (each with + `confidence`, `distance`, `duration`, `geometry`, and `legs`), + and a `tracepoints` array — one entry per input coordinate, + `null` for one too far from any candidate to match. + "401": + description: Unauthorized + "403": + description: Forbidden + "404": + description: Not Found — an invalid profile. + "422": + description: >- + Unprocessable Entity — invalid input, or more coordinates than + the profile allows (100 for a coordinate list, 50 for OpenLR). diff --git a/custom-openapi/matrix/openapi/matrix.yaml b/custom-openapi/matrix/openapi/matrix.yaml new file mode 100644 index 0000000..f7b9edf --- /dev/null +++ b/custom-openapi/matrix/openapi/matrix.yaml @@ -0,0 +1,165 @@ +openapi: "3.0.0" +# `parse_spec` turns `info.description` below into this service's clap +# `long_about`, so it also reaches `mapbox matrix --help`, `--schema` and +# `generate-skills` output. Keep it to API prose only — the provenance below +# is for whoever edits this file, not for a CLI user: +# +# Hand-authored down to the parameters documented at +# docs.mapbox.com/api/navigation/matrix. See `custom-openapi/README.md` for +# how a file like this is wired in, and `directions.yaml`'s header for why +# `profile` needs `ARG_NAME_OVERRIDES` in `src/spec.rs` — the same reason +# applies here. +info: + title: "Mapbox Matrix API" + description: >- + Travel time and distance between every pair in a set of up to 25 + coordinates, in one call — for driving (with or without live traffic), + walking, or cycling. + version: "0.0.0" +servers: + - url: https://api.mapbox.com + description: Matrix API +paths: + /directions-matrix/v1/{profile}/{coordinates}: + get: + operationId: compute + summary: A travel time/distance matrix across a set of coordinates. + description: >- + Returns a `durations` and/or `distances` matrix in row-major order — + `durations[i][j]` is the time from the ith source to the jth + destination — across every source/destination pair. Defaults to + every coordinate as both a source and a destination (a full N×N + matrix); `--sources`/`--destinations` narrow either side to a + subset. Answers "which of these is reachable soonest", not a route + through all of them. See `mapbox directions` for a route through + fixed stops in order. + parameters: + - name: "profile" + in: path + required: true + # Not an `enum`: the four documented values are what's public, but + # not what's exhaustive. Some customers (OEM agreements, mainly) + # have additional profiles never published to docs.mapbox.com. + # An `enum` here becomes a clap `PossibleValuesParser` that + # rejects anything else client-side, which would break this CLI + # for exactly the accounts that most need a routing profile + # named beyond `driving`/`walking`/`cycling`. Same fix as + # `directions.yaml`'s `profile`. + description: >- + The routing profile. `mapbox/driving-traffic` (accounts for + live traffic, caps at 10 coordinates instead of 25), + `mapbox/driving`, `mapbox/walking`, and `mapbox/cycling` are + documented, but not necessarily exhaustive: some accounts have + additional profiles of their own. Sent exactly as typed, the + API is the authority on whether a value is valid, not this + description. + schema: + type: string + minLength: 1 + example: "mapbox/driving" + - name: "coordinates" + in: path + required: true + description: >- + 2-25 coordinates, semicolon-separated, each + `{longitude},{latitude}` — 10 max for `mapbox/driving-traffic`. + schema: + type: string + minLength: 1 + example: "-122.42,37.78;-122.45,37.91;-122.41,37.80" + - name: "access_token" + in: query + required: true + description: "Mapbox API Access Token" + schema: + type: string + minLength: 1 + - name: "annotations" + in: query + required: false + description: >- + Which matrix or matrices to return, comma-separated. Options + are `duration` (the default) and `distance` — both together + returns both matrices. + schema: + type: string + example: "duration,distance" + - name: "approaches" + in: query + required: false + description: >- + Which side of the road to approach each coordinate from, + semicolon-separated — `unrestricted` or `curb` per coordinate. + schema: + type: string + - name: "bearings" + in: query + required: false + description: >- + `{angle},{degrees}` per coordinate, semicolon-separated, + filtering the road segments considered by direction of travel. + schema: + type: string + - name: "sources" + in: query + required: false + description: >- + Which coordinates act as sources (matrix rows) — `all` + (the default), or zero-based indices, semicolon-separated. + Verified against production: a comma-separated list is a 422, + "may be \"all\" or semicolon-separated list of 0-based integer + indices" — unlike every other index/value list on this CLI's + Navigation commands, which are comma- or semicolon-separated + per parameter but never comma where this API wants semicolons. + schema: + type: string + example: "0;2" + - name: "destinations" + in: query + required: false + description: >- + Which coordinates act as destinations (matrix columns) — `all` + (the default), or zero-based indices, semicolon-separated. See + `sources` above — comma-separated is a 422 here specifically. + schema: + type: string + example: "1;3" + - name: "fallback_speed" + in: query + required: false + # Content before "Legacy", not after: `first_sentence` in + # `src/main.rs` cuts a `--help` line at the first `.`, and + # "Legacy." on its own left `--help` showing just that word. + # `--schema` and `docs/commands.md` still show it in full. + description: >- + Replaces a `null` (unreachable) cell with a straight-line + estimate at this speed, km/h, rather than leaving it `null`. + Legacy. + schema: + type: integer + minimum: 1 + - name: "depart_at" + in: query + required: false + description: >- + Departure time, ISO 8601, for future traffic conditions and + time-dependent road restrictions. + schema: + type: string + responses: + "200": + description: >- + A JSON object with a `code`, a `durations` and/or `distances` + matrix (row-major, seconds and meters respectively — `null` for + an unreachable pair), and the snapped `sources`/`destinations` + waypoints. + "401": + description: Unauthorized + "403": + description: Forbidden + "404": + description: Not Found — an invalid profile. + "422": + description: >- + Unprocessable Entity — invalid input, or more coordinates than + the profile allows. diff --git a/docs/commands.md b/docs/commands.md index f0228c5..028fc6a 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -97,6 +97,10 @@ nests, and is typed `mapbox styles draft get`. **[Isochrone](#isochrone)** — [isochrone](#mapbox-isochrone) +**[Map Match](#map-match)** — [map-match](#mapbox-map-match) + +**[Matrix](#matrix)** — [matrix](#mapbox-matrix) + **[Search](#search)** — [search.forward](#mapbox-search-forward) · [search.reverse](#mapbox-search-reverse) · [search.category](#mapbox-search-category) · @@ -1636,6 +1640,226 @@ line, same shape as `mapbox directions`'s Outputs section above: Trimmed to one of the two features (the response has one per `--contours-minutes` value) and the polygon's coordinates, for length. +--- +## Map Match + +Snaps a noisy GPS trace to the road network and returns the route it most +likely followed, for driving (with or without live traffic), walking, or +cycling. Curated by hand down to the parameters documented at +docs.mapbox.com/api/navigation/map-matching — see `custom-openapi/README.md` +for why this command group doesn't come from the vendored specs the way +most others do. Excludes POST, which this CLI's spec format has no way to +express alongside GET for the same operation — the API's own POST is for a +trace too long for a URL (~8100 bytes), a real gap rather than a design +choice. + +### `mapbox map-match` + +One or more matched routes — more than one where the trace is ambiguous +enough to split — each carrying a `confidence` the API assigns itself, plus +one tracepoint per input coordinate (`null` for one too far from any +candidate to match at all). No subcommand: this API has one operation, so +there's nothing a second word would disambiguate, the same reason `mapbox +directions` has none either. + +#### Parameters + +`` and `` (both positional) are required. +`` is sent exactly as typed, not checked against a fixed +list: `mapbox/driving-traffic`, `mapbox/driving`, `mapbox/walking` and +`mapbox/cycling` are documented, but some accounts (OEM agreements, mainly) +have additional profiles of their own that were never published, the API +is the authority on whether a value is valid, not this page. `` +is 2-100 `{longitude},{latitude}` trace points, semicolon-separated, or an +OpenLR-encoded string of up to 50 points (pair with `--openlr-spec`/ +`--openlr-format`). + +| Parameter | Effect | +| --- | --- | +| `--annotations ` | Segment-level metadata per leg, comma-separated (`distance`, `duration`, `speed`, `congestion`, `congestion_numeric` (both `mapbox/driving-traffic` only), `maxspeed` (`mapbox/driving` and `mapbox/driving-traffic` only)). Requires `--overview full`. | +| `--approaches ` | Which side of the road to approach each waypoint from. Requires `--steps`. | +| `--geometries ` | Route geometry format. Defaults to `polyline`. | +| `--overview ` | Geometry detail level. Defaults to `simplified`. | +| `--radiuses ` | Max snap distance, 0-50, one per coordinate. Defaults to 5. | +| `--steps` | Return turn-by-turn instructions. Several flags below only take effect with this set. | +| `--banner-instructions` | Return banner objects for display. Requires `--steps`. | +| `--language ` | Instruction language. Defaults to `en`. Requires `--steps`. | +| `--roundabout-exits` | Separate entry/exit instructions for a roundabout. Requires `--steps`. | +| `--voice-instructions` | Return SSML-marked voice guidance. Requires `--steps`. | +| `--voice-units ` | Requires `--steps` and `--voice-instructions`. | +| `--tidy` | Remove clusters and resample the trace before matching — for a trace recorded at an inconsistent sample rate. | +| `--timestamps ` | When the trace was recorded, per coordinate, ascending — rather than assumed from even spacing. | +| `--waypoint-names ` | A name per waypoint for its arrival instruction. Requires `--steps`. | +| `--waypoints ` | Which coordinates get their own arrival instruction, semicolon-separated — must include `0` and the last index. Most useful with `--steps`, which it does not require. | +| `--ignore ` | Restrictions to ignore, comma-separated (`access`, `oneways`, `restrictions`). `mapbox/driving` only. | +| `--linear-references` | Return an OpenLR reference (base64) per matched leg, alongside the ordinary geometry. `mapbox/driving` and `mapbox/driving-traffic` only. | +| `--openlr-spec ` | Which OpenLR spec `coordinates` is encoded with, if it's an OpenLR string. Defaults to `tomtom`. | +| `--openlr-format tomtom` | The OpenLR binary format `coordinates` is encoded in, if it's an OpenLR string. | +| `--depart-at