Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 31 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ local socket. Use a separate database for tests. The tables are the cache's
## External services and changed behavior

The previous implementation depended on the legacy Hiking Project API. This
version instead queries hiking-route relations from
version instead queries hiking-route relations and named trail paths from
[OpenStreetMap via Overpass](https://wiki.openstreetmap.org/wiki/Overpass_API).
It does not scrape Hiking Project or require its old API key.
Current Hiking Project availability could not be confirmed. Live probes of both
Expand Down Expand Up @@ -116,12 +116,34 @@ test Overpass connectivity from your deployment before launching.
the coarse terrain routes' promise uses, then the quickest: with buses as well
as trains, flat suburbs are often as quick as the hills beyond them, and from
New York they took the places of the Catskills, Poconos, and Lehigh Valley.
The four quickest are queried first, the rest four neighbors at a time, each
query finding the routes of the region around its tiles once, then keeping
those in the tiles (a tile's routes are left out when its query fails).
Routes spanning less than 300 m, under **1 mile** or over **30 miles** long,
at least half on paved paths or roads, and repeated sections of one named trail (the same
name within 5 km) are left out: they are walks or multi-day trails rather than
- **Named paths.** Where trails are mapped as named paths alone rather than as
hiking routes, as across the American West (around the Columbia River Gorge,
30 routes against 218 named trails; in LA's San Gabriels, 8 against 135), the
tiles' named footpaths, bridleways, and paths that aren't sidewalks,
crossings, private, or part of a hiking route are routes too
(`OverpassService::PATH_FILTER`): each the ways of one name joined at a node,
listed with their nodes but not their geometry (about 3 MB for four tiles
around the Issaquah Alps or Marin), and 0.05° beyond the tiles, so a trail
across a tile's edge is found whole from either side. Pieces of one that
tiles list apart, the first four tiles' and the rest's too, are joined where
they share a way, keeping the id of a piece already checked. A path measured
from fewer of its ways than a search knows is measured again from them all,
or, where that fails, as Overpass does from the server, keeps what was
measured, without trying again for 6 hours; details list the ways a path was
measured from, those gone since too, so they aren't asked for again. A
named path's id is the negative of its first way's, its details are measured
from its ways once a search picks it, and its highlights found along them,
and its OpenStreetMap link is to that way. A mapped hiking route is likelier
to be a hike worth the trip, so a named path is half a point less promising.
Where named paths are too many to list with the routes (over 8 MB), as around
Zürich, which has hiking routes aplenty, tiles keep their routes alone, and a
response that large isn't asked of the other instance.
- The four quickest tiles are queried first, the rest four neighbors at a
time, each query finding the routes of the region around its tiles once, then
keeping those in the tiles (a tile's routes are left out when its query
fails). Routes spanning less than 300 m, under **1 mile** or over **30
miles** long, at least half on paved paths or roads, and repeated sections of
one named trail (the same name within 5 km) are left out: they are walks or multi-day trails rather than
day hikes. Routes within a 30-minute walk of a stop (the most the planner
walks) are checked, most promising first, up to **120** per search, keeping
the section of a trail that transit reaches soonest. Promise counts much as the
Expand All @@ -135,7 +157,8 @@ test Overpass connectivity from your deployment before launching.
and back. Without the land, an area where most routes
have Wikidata entries, such as Franconia's, took most checks from Munich, and
the Alps few. Results are not an exhaustive trail inventory; where few hiking
routes are mapped in OpenStreetMap near stations, there are few results.
routes or named paths are mapped in OpenStreetMap near stops, there are few
results.
- Routes are checked in batches of 40, starting with the first tiles' while the
others are found, and each batch's hikes show as soon as their trips there and
back are known. Routes that can't be looked up at once, as when Overpass is
Expand Down
5 changes: 3 additions & 2 deletions app/controllers/hikes_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ class HikesController < ApplicationController
# The page shows without the route's highlights, terrain, or photos when they take longer.
EXTRAS_WAIT_SECONDS = 10

# route is the OpenStreetMap relation id; from, to, and finish are
# route is the OpenStreetMap relation id, or a named path's (see
# OverpassService::PATH_FILTER), whose details its search kept; from, to, and finish are
# "latitude,longitude" for the search's starting point, where transit
# reaches the route, and where a hike to the far end finishes; station, if
# given, is "latitude,longitude" for the station trips leave from, and
Expand All @@ -23,7 +24,7 @@ def show
@zone = ActiveSupport::TimeZone[params[:tz]] if params[:tz].is_a?(String) && params[:tz].length <= 64
route = Integer(params[:route], 10, exception: false) if params[:route].is_a?(String)
@origin_name, @station_name = [params[:origin], params[:station_name]].map { |name| name_param(name) }
unless origin && start && route&.positive? && PLANS.include?(params[:plan]) && (finish || params[:plan] != "through") &&
unless origin && start && route&.nonzero? && PLANS.include?(params[:plan]) && (finish || params[:plan] != "through") &&
(station || !params.key?(:station)) &&
leave && back_by && @zone && leave.between?(1.day.ago, 8.days.from_now) && back_by.between?(leave, leave + 1.day)
return head(:bad_request)
Expand Down
Loading
Loading