Mobile App
The FastGIS mobile app is an Expo / React Native client for field capture, route planning, offline curvy-road discovery, and real-time elevation profiling. It connects to the same FastGIS server as the browser UI.
Tabs
| Tab | Purpose |
|---|---|
| Navigate | Full-screen MapLibre map — route planning, circular-route generator, POI search, curvy-road discovery, offline tile queries, turn-by-turn navigation |
| Capture | GPS field capture — track recording, waypoint photos/audio/notes, sync to server |
| Map | Static map viewer and overlay manager |
| Profile | Elevation transect tool — draw a line on the map, run GRASS r.profile against any loaded DEM, inspect the chart |
| Connection | Server connection, environment management, saved analyses, app settings |
Navigate is the default tab when the app opens.
Live engine data (OBD-II)
The app can read live engine data straight from the motorcycle over a Bluetooth-LE OBD-II adapter (ELM327 family — e.g. the Vgate iCar Pro 2S). Open More → OBD-II (Bluetooth), tap Scan, and pick the adapter — likely dongles are sorted to the top. There is no iOS Settings pairing step: BLE adapters connect inside the app.
Once connected the screen shows what your bike actually serves, live: engine RPM, vehicle speed, coolant temperature, throttle position, engine load, battery/module voltage — plus an extended probe that asks once per connection for fuel level, odometer, distance-since-service, fuel rate and intake temperature, and reports honestly which of them the ECU answers. Motorcycles vary widely here: a KTM 890 Adventure, for example, answers the core set plus distance and intake temperature, and declines the fuel PIDs.
For calibration rides the screen also includes a raw CAN capture tool with one-tap steady-speed markers (20/40/60 km/h) — groundwork for wheel-speed distance tracking and gear display on bikes that broadcast them.
The screen stays awake while connected, and works alongside CarPlay (minimise the companion overlay to reach it while the head unit is active).
Connecting to a server
Open Connection → Server and enter:
- Server URL — e.g.
https://fastgis.example.com - API key — issued in the server's admin panel
The app auto-reconnects on relaunch using credentials stored in the device's SecureStore.
Navigate tab
The Navigate tab is a full-screen MapLibre map with floating controls and a set of bottom sheets.
Floating controls
| Button | Action |
|---|---|
| ⊙ | GPS follow — tap to re-centre the map on your position and lock the camera to follow you. Tap again (or pan the map) to unlock. |
| + / − | Zoom in / out |
| 2D / 3D | Toggle perspective tilt |
| ⊕ | Open the POI category tray (see below) |
| ☰ | Map settings and basemap selector |
| ⊞ | Routing wizard — the entry point for all route planning |
In portrait these stack as a single right-side column. In landscape the same buttons sit in a horizontal bottom row, with the central Route pill flanked by zoom/perspective controls on the left and POI / GPS / nav-toggle on the right.
The Map tab mirrors this exact layout: same button sizes, same gaps, same right-column-portrait / bottom-row-landscape pattern (Map's primary action — the Capture FAB — sits in the visual centre slot equivalent to Navigate's Route pill).
Routing wizard
Tap ⊞ to open the ride wizard. Four options are available:
| Option | Description |
|---|---|
| 📍→📍 Plan a route | A-to-B route with waypoints, vehicle type, and routing preferences |
| ↺ Create a loop | Circular tour from your GPS position or map centre |
| 〰 Find curvy roads | Discover scenic and twisty roads from the curvature database |
| ⏺ Record Ride | Start a GPS field session — track, waypoints, photos, audio, notes |
POI chip bar
Tap ⊕ to reveal the POI category tray. Selecting a chip overlays the corresponding points of interest on the map.
| Chip | Category |
|---|---|
| ⭐ | Saved places |
| 📦 | Field captures (from the Capture tab) |
| 🏛 | Attractions |
| 〰 | Curvy roads (runs a quick curvature query) |
| ⛰ | Mountain passes |
| 📍 | Meeting points |
| ⛽ | Gas stations |
| 🍴 | Food & restaurants |
| ⛺ | Camping |
| 🏨 | Biker-friendly hotels |
| 🅿 | Motorcycle parking |
| 🍦 | Ice cream |
Tap a chip again to hide its layer. Tap the map or close the tray to collapse the bar.
Map overlays
Tap ☰ to open map settings. The Overlays section lists four toggleable data layers:
| Overlay | Description |
|---|---|
| 📷 Speed cameras | Fixed speed camera locations sourced from OpenStreetMap. Requires a server connection. |
| ⛽ Gas stations | Fuel stops in the current map area. Requires a server connection. |
| 🚧 Road works | Active construction and closures (NVDB data). Works offline. |
| 🌧 Rain radar | Live precipitation tiles via RainViewer. Works offline (pulls directly from RainViewer). |
Each overlay is toggled independently. Overlays stay active when you switch between sheets or tabs.
Standard route planner
Open via ⊞ → Plan a route.
- Search for a start and destination, or use Use my location for GPS origin.
- Add optional via-points (intermediate stops) — drag to reorder, tap ✕ to remove.
- Choose a vehicle type:
| Icon | Vehicle | Routing costing |
|---|---|---|
| 🏍 | Moto | Motorcycle — full costing options |
| 🚗 | Car | Auto — ferry, toll, highway avoidance |
| 🚲 | Bike | Bicycle — ferry avoidance |
| 🚶 | Walk | Pedestrian — ferry avoidance |
- Tap Calculate route — the route appears on the map and the summary shows distance and ETA. On a multi-stop route the stops editor also lists a per-stop breakdown — each stop's own leg distance, riding time, and projected arrival clock — so you can sanity-check the day before setting off.
A background surface trace then fills in two more numbers: the % unpaved share
(tap it to highlight the unpaved stretches on the map) and a Difficulty rating —
surface roughness amplified by climb, on the same 0–1 scale as the
max_difficultyrouting ceiling, with the hard kilometres (difficulty above 0.5) spelled out beside it. Steep tarmac stays easy: only steep rough ground raises the number. - Tap ▶ Navigate to begin turn-by-turn guidance.
- Tap ⛰ Elevation profile in the route summary to fetch and render the elevation chart.
Once the planner panel slides down you'll see a compact route summary chip floating over the map (route label + distance + ETA). The chip has three actions:
- ▶ (green) — start turn-by-turn directly without re-opening the planner sheet.
- ✕ Clear — discard the route.
- The replan icon (📍→📍) on the left of the chip reopens the planner if you want to edit waypoints or options.
Once turn-by-turn is running the ▶ Start and ✕ Clear buttons are replaced with a ◎ Hide / ◉ Show toggle that turns the background-map route line on/off without interrupting navigation.
Motorcycle options
Expand ▶ Advanced in the route planner to access fine-grained Valhalla costing sliders (highways, hills, trails, bad surfaces, ferry, tolls, top speed, wind screen) and the shortest-distance toggle.
The same panel carries the Scenic bias slider (off by default): it asks the server to bias the route toward the best-rated roads in the corridor, with a Bends / Climb picker for which axis "best" means. It is strictly opt-in — a biased request takes the server a little longer to compute — and only applies to server-computed routes; on-device routing ignores it.
Waypoint injection
While turn-by-turn navigation is active, open a curvy-road detail card and tap Inject stop or Inject full segment — the waypoint is smart-inserted at the lowest-detour position in the current route and navigation restarts automatically on the updated route.
Per-stop ETA on multi-stop routes
On a route with via-points, the HUD's cycling metric slots include three stop-aware metrics alongside the whole-trip ones: NEXT STOP (distance to the next intermediate stop), STOP ETA (projected arrival clock at that stop), and STOP (a "2/4"-style counter). The final-destination ETA is unchanged — partials are computed from the same per-maneuver time weighting, so the last stop's numbers always match the trip totals. On CarPlay / Android Auto the car's own estimate still means the final destination; a Stops map button (visible only during multi-stop navigation) opens a dedicated list page with each stop's remaining distance and arrival time.
These metrics deliberately go blank (—) when "next stop" would be a lie: single-leg routes, out-and-back tracks whose turnaround is not a stop, and imported-GPX / TET trail rides whose internal legs are stitching chunks rather than places you stop.
Off-route handling
While turn-by-turn is running, the app continuously projects your GPS position onto the active route polyline. If you stray further than the off-route threshold for several consecutive GPS ticks (defaults: 150 m / 3 ticks for motor, 90 m / 6 ticks for bicycle, 52 m / 9 ticks for walking), one of two things happens:
- Motorcycle, car, bicycle — the route is recalculated automatically from your current position to the destination. You hear "Off route. Recalculating." and the new route line replaces the old one on the map. No tap needed; your hands stay on the bars/wheel.
- Walking — the app surfaces a Tap to recalculate prompt instead. Pedestrians can safely stop and confirm, and the prompt also avoids triggering an expensive reroute every time you legitimately cut across a plaza.
You can tune the sensitivity in Settings → Safety alerts → Off-route detection:
- Off-route threshold (50–400 m, default 150) — the motor-vehicle baseline. Bicycle uses ×0.6 of this, walking ×0.35.
- Off-route strikes (2–8, default 3) — consecutive bad fixes before triggering. Bicycle uses ×2 of this, walking ×3.
The per-vehicle multipliers are not user-editable; the rationale is that slower / less-road-constrained costings need a narrower threshold but more strikes so shoulder positioning doesn't false-alarm.
Verbal voice cues by vehicle
TTS announcements ride on top of Valhalla's verbal_pre_* / verbal_transition_alert_* strings when populated. For costings that emit empty strings (notably bicycle, which can leave all verbal fields plus the visible instruction empty), the app synthesizes a fallback line from the maneuver type and street name — e.g. "Turn left onto Bergstien" — so the rider isn't dropped into silence even when the routing service skips the prose.
Rally roadbook navigation (geometry-only)
Any track's roadbook (a saved ride, an imported GPX, a TET trail, a library record) has a Road ⇄ Rally toggle. In Rally mode a Ride button starts a navigation session driven by the track's shape alone — no map-matching, no routing tiles, no server. Each clustered bend becomes a maneuver classified by its total turn angle (kink 10–30°, mild 30–60°, sharp 60–90°, elbow 90–135°, hairpin >135°; two tight opposite bends link into an S-bend), and the normal turn-by-turn engine advances through them as you cover ground along the track.
The HUD swaps the road arrow for a tulip-style shape glyph (coloured by direction) and adds: the distance to the next note, the CAP — compass heading to hold out of the bend, e.g. CAP 135° SE — and a danger chip (! / !! / !!!) from radius, blindness and downhill grade. Spoken cues are rally calls ("hairpin left, 160", "S-bends") in your navigation voice language.
A roadbook ride never replans: leaving the line shows the calm following your track hint with a one-time spoken cue, and guidance resumes when you rejoin. Mid-ride vehicle switches keep the track. An advisory corner-speed / gear hint (v = √(μ·g·r)) exists but is off by default — enable it under Settings → Navigation → Roadbook speed hints and set the grip coefficient μ to your surface.
Reset to defaults
Tap ↺ Reset to defaults at the bottom of the planner to restore all routing options to their factory settings (vehicle, avoid flags, all moto sliders). Locations and waypoints are preserved; the computed route is cleared.
Circular route planner
The circular route planner generates a loop that starts and ends at the same point. Open it from the Navigate tab via Routing → Circular route.
Start point
Tap the Start point row to toggle between two sources:
| Icon | Source | Notes |
|---|---|---|
| 🛰 GPS position | Device GPS | Requires a GPS fix. Greyed out with "No GPS signal" when unavailable. |
| 🗺 Map center | Current map centre | Always available. Pan the map before tapping Generate (or Recompute in the preview panel) to start from any point in the world. |
Ride profile (motorcycle only)
The ride profile translates directly into Valhalla costing weights sent to the routing engine — every weight in this table is verified against the engine with A/B route measurements. Highways and Hills are 0–1 preferences (higher = prefer more strongly); Surfaces is how strongly rough ground (gravel, dirt, tracks) is penalised.
| Profile | Highways | Hills | Surfaces | Character |
|---|---|---|---|---|
| Balanced | 0.35 | 0.50 | strict tarmac | Comfortable all-round motorcycle route |
| Curvy | 0.20 | 0.80 | strict tarmac | Maximises curves and elevation change, avoids fast roads |
| Scenic | 0.15 | 0.65 | light trail use allowed | Prioritises landscape and viewpoints |
| Fast | 0.75 | 0.35 | strict tarmac | Faster roads, minimal climbing, smooth surface preferred |
| Road bike safe | 0.40 | 0.45 | strict tarmac | Strictly avoids unpaved and gravel surfaces |
| Custom | slider | slider | slider ("Avoid bad surfaces") | Set your own percentages via the Advanced tuning panel |
The Hills weight rides on elevation-aware costing in the FastGIS routing engine (0.5 is neutral; below it the loop avoids gradient, above it seeks passes). It applies when the loop is generated online; loops generated fully offline on the device currently route as if Hills were neutral.
Ferry and toll avoidance settings from the Route Planner (standard routing sheet) are always blended in on top of these weights.
Choosing a profile also pre-sets the Avg speed used for ETA estimates (Curvy → 45 km/h, Fast → 75 km/h, etc.) — you can override this in Advanced settings.
Weave-ins — curvy roads and beaches
Include curvy roads (motorcycle and car) weaves the best-rated road near the loop into it as fixed via-points; the loop still converges on the target distance. When it is on, a Bends / Climb picker chooses which axis picks that road — bends is the classic curvature ranking, climb picks the biggest mountain road instead. Climb ranking always uses the server (on-device curvature data has no climb column). Include beaches does the same with beach-seeker beaches, with a sea / lakes / both filter.
Advanced settings
Expand ▶ Advanced settings (motorcycle and car only) to tune:
| Setting | Range | Effect |
|---|---|---|
| Avg speed | 15–120 km/h | ETA estimate only; does not cap actual routing speed |
| Waypoints | 2–12 | More waypoints → more varied loop shape and less chance of out-and-back detours |
| Reach depth | 0.30–1.00 | How far out waypoints are placed. 0.30 = tight radius; 1.00 = pushed to the furthest reachable edge. Lower values work better in fjord/valley terrain to avoid dead-end roads. |
| Avoid backtracking | toggle | Marks waypoints as Valhalla through stops — the engine passes through without U-turning, reducing same-road overlap |
| Force departure heading | toggle | Adds a directional heading constraint so the route departs in the chosen compass direction (±45°). Disabled when direction is set to Random. |
Tour direction
Tap Tour direction to open a compass rose and pick the preferred outbound heading: N, NE, E, SE, S, SW, W, NW, or R (Random). The engine biases waypoint placement in that direction but does not guarantee a straight outbound leg.
After generating
Once the route preview appears:
- The panel shows actual distance and estimated duration.
- Tap ▶ Start navigation to begin turn-by-turn guidance immediately.
- Tap ↺ Recompute to regenerate with the same settings — if you have panned the map and the start source is set to Map center, the recompute uses the current map centre, not the one when the panel first opened.
- Tap 💾 Save to store the route.
- Tap ⛰ Show elevation profile to fetch and display the elevation chart for the generated loop.
Curvy-road discovery
Tap 〰 Find Curvy Roads in the Navigate tab (via the Routing button → wizard).
- Scoring method — choose Total (default), Density, or Radius. Each algorithm measures curvature differently: Total accumulates degrees of turning along the road, Density divides that by distance so short and long roads compare fairly, and Radius scores the tightness of individual corners. The app rescales the threshold for you when you switch.
- Rank by — Bends (default) or Climb. Two separate axes on purpose: the bendiest road near you and the biggest mountain road near you are rarely the same road. Climb ranking orders results by a 0–100 climb rating (elevation range, metres climbed per km, mean altitude) and needs a server connection — on-device curvature data carries no climb column, so offline results stay curvature-ordered.
- Preset — Twisty, Scenic, or Mixed sets the baseline curvature threshold for the selected algorithm.
- Search radius — 25–200 km around your GPS position or the current map centre.
- Tap Find roads near me → (or Search here → after panning the map).
- Results appear as a ranked list and coloured line segments on the map.
- Tap any road to expand its detail card:
- Stats: curvature score, length, distance from you, climb rating, elevation range, elevation gain, water proximity.
- ⛰ Show elevation profile — fetches and renders the full elevation chart inline. Tap a point on the chart to highlight that position on the map.
- Route actions: Start here, Add stop, Route to it, Add full segment.
Tap ▶ Advanced in the sheet to access fine-grained filters: road class, surface type, min sinuosity, population density, scenic-only, near-water, and elevation change thresholds.
Elevation data comes from the best available national DEM for the road's location (see the API reference).
Field capture
Switch to the Capture tab.
Starting a session
- Select or create a GRASS environment (e.g. a project area) from the More → Connection sheet.
- Tap Start Recording — the big green CTA on the idle screen — to begin a new GPS session with a default timestamped title.
- Use the floating action buttons (or the bottom action bar once the session is recording) to add samples: photo, video, audio, waypoint, note, track point.
- Tap the red ■ End in the recording header when finished. The session and all its samples upload automatically when a server connection is available.
Browsing past sessions
The idle screen lists your Recent sessions below the Start CTA. Each row shows the session title, status (recording / paused / ready / completed) and the timestamp of the last save.
-
Tap a row to open a dedicated session detail view. The view replaces the list and shows: session title and status header, publish-target metadata, and a samples list where each card expands on tap to show its media preview (photo, video thumbnail, audio waveform, note text). Tap the ‹ Back button at the top-left to return to the list.
-
Swipe a row left to reveal two row actions:
- Push (teal) — uploads any pending samples for that session to the configured FastGIS server.
- Delete (red) — removes the session and all its samples from this device. A confirmation dialog appears first so a stray swipe doesn't destroy work.
Both actions are disabled while another publish / delete operation is already in flight.
Where past sessions go after upload
Once a session has been pushed and there's nothing pending, it stays in the local list as a "synced" record so you can still browse the samples on-device. To re-sync (e.g. after a server reset), use the More → Sync sheet which exposes "Push all" and granular controls.
Storage actions on a synced session
The session detail view (open a session row, or a capture card in the Library) offers three storage actions — all of them keep the captured data safe on the server:
- Remove from device — deletes the local copies of the session's captures to free space. The captures stay on the server and stream back into the same views (photo, video, and audio) whenever you're online. Only offered once the session is fully synced.
- Download for offline — the inverse: re-saves every streamed capture onto the device (rows and media files), so the session works without a connection again.
- Delete from library — removes the session from your listing, on this device and in the server's session list. This is a soft removal: the captured data and media stay stored on the server, and a permanent server-side delete remains a separate, explicit operation (swipe-delete in the sessions list, or the environment-wide Fresh Start).
Elevation profile tab
The Profile tab is a dedicated transect tool for detailed elevation analysis against server-side rasters.
- Load a GRASS environment that contains a DEM raster (More → Environment).
- On the Profile tab, choose the raster from the pill selector.
- Tap Start Transect Draw, then tap start and end points on the map.
- Tap Run Profile — the server executes
r.profileand the chart renders. - Tap Save Profile to Analyses to persist the result as an artifact.
This is different from the route/road inline chart: it uses the full-resolution server-side DEM rather than the automatic online elevation service.
Riding together — live sharing, voice, and group rides
FastGIS has a full social riding layer built on your friends and groups (More → Live sharing). All of it is opt-in and self-hosted — your location and voice never touch a third-party service.
Live location sharing
Share your live position with all friends, specific friends, and/or groups for a chosen duration (15 m up to "until I turn it off"). Friends appear on the Navigate map as avatars with a moving / stopped / stale status ring. You can also mint an expiring public link that anyone can open in a browser — no app or account needed.
Group voice — push-to-talk
Pick a group as your voice channel and talk walkie-talkie style. Riding-safe triggers: an on-map tap button (Navigate, turn-by-turn, and Active Ride), and a Bluetooth helmet media button. Only your active channel is audible, and a banner shows who is talking.
Live calls
Full-duplex calls — everyone talks at once, like a phone call:
- 1:1 calls to a mutual friend, and group calls for a whole group.
- While your call rings you hear the familiar ringback tone; if nobody picks up within about 45 seconds the call ends itself with a "No answer" notice.
- Join anytime: an ongoing group call shows a "call in progress — join" banner; one tap joins it. Calls persist while at least one person is in them.
- Background ringing: incoming calls ring on the lock screen with the native iOS call UI, even when the app is in the background.
- Calls list (More → Calls): every call in both directions — ↘ incoming (missed / answered / declined) and ↗ outgoing (including "No answer"); a missed group call that is still ongoing can be joined straight from the list.
- During a call, spoken navigation pauses (call > push-to-talk > nav voice); the repeat button on the nav HUD still speaks on demand.
Group Ride — convoy navigation
One rider (the leader) shares a planned route with a group; everyone rides the same road geometry, so the convoy stays together:
- Plan a route in Navigate, then open More → Live sharing → Group ride and tap Start ride on a group. Every member gets an invite.
- Accepting is a single consent: it joins the ride, shares your live location with the group, and selects the group as your voice channel. A green "In the convoy" strip stays visible with an instant Leave.
- The route heals itself. If the leader takes a detour or reroutes, the new route is pushed to every member automatically. If you drift off, the app quietly routes you back to a point ahead on the group's route — it never replans your own route to the destination.
- Leadership is handable. The leader can promote another member (Make leader). If the leader disconnects, the longest-connected member is promoted automatically (they can decline); with no leader the group simply keeps following the last shared route.
- Late joiners and reconnecting phones always receive the current route.
Settings and data reset
Open Connection → ⚙ Settings → Data → Reset offline data to erase all downloaded tiles, the curvature database, POI databases, and cached routes.
What is kept: server credentials, app preferences, field captures, bookmarks.
After tapping Reset, restart the app. Then use the Offline Packs sheet to re-download fresh tiles.
See also: Offline Data Tiles.