1-- Foot profile
2
3api_version = 2
4
5Set = require('lib/set')
6Sequence = require('lib/sequence')
7Handlers = require("lib/way_handlers")
8find_access_tag = require("lib/access").find_access_tag
9
10function setup()
11  local walking_speed = 5
12  return {
13    properties = {
14      weight_name                   = 'duration',
15      max_speed_for_map_matching    = 40/3.6, -- kmph -> m/s
16      call_tagless_node_function    = false,
17      traffic_light_penalty         = 2,
18      u_turn_penalty                = 2,
19      continue_straight_at_waypoint = false,
20      use_turn_restrictions         = false,
21    },
22
23    default_mode            = mode.walking,
24    default_speed           = walking_speed,
25    oneway_handling         = 'specific',     -- respect 'oneway:foot' but not 'oneway'
26
27    barrier_blacklist = Set {
28      'yes',
29      'wall',
30      'fence'
31    },
32
33    access_tag_whitelist = Set {
34      'yes',
35      'foot',
36      'permissive',
37      'designated'
38    },
39
40    access_tag_blacklist = Set {
41      'no',
42      'agricultural',
43      'forestry',
44      'private',
45      'delivery',
46    },
47
48    restricted_access_tag_list = Set { },
49
50    restricted_highway_whitelist = Set { },
51
52    construction_whitelist = Set {},
53
54    access_tags_hierarchy = Sequence {
55      'foot',
56      'access'
57    },
58
59    -- tags disallow access to in combination with highway=service
60    service_access_tag_blacklist = Set { },
61
62    restrictions = Sequence {
63      'foot'
64    },
65
66    -- list of suffixes to suppress in name change instructions
67    suffix_list = Set {
68      'N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW', 'North', 'South', 'West', 'East'
69    },
70
71    avoid = Set {
72      'impassable'
73    },
74
75    speeds = Sequence {
76      highway = {
77        primary         = walking_speed,
78        primary_link    = walking_speed,
79        secondary       = walking_speed,
80        secondary_link  = walking_speed,
81        tertiary        = walking_speed,
82        tertiary_link   = walking_speed,
83        unclassified    = walking_speed,
84        residential     = walking_speed,
85        road            = walking_speed,
86        living_street   = walking_speed,
87        service         = walking_speed,
88        track           = walking_speed,
89        path            = walking_speed,
90        steps           = walking_speed,
91        pedestrian      = walking_speed,
92        footway         = walking_speed,
93        pier            = walking_speed,
94      },
95
96      railway = {
97        platform        = walking_speed
98      },
99
100      amenity = {
101        parking         = walking_speed,
102        parking_entrance= walking_speed
103      },
104
105      man_made = {
106        pier            = walking_speed
107      },
108
109      leisure = {
110        track           = walking_speed
111      }
112    },
113
114    route_speeds = {
115      ferry = 5
116    },
117
118    bridge_speeds = {
119    },
120
121    surface_speeds = {
122      fine_gravel =   walking_speed*0.75,
123      gravel =        walking_speed*0.75,
124      pebblestone =   walking_speed*0.75,
125      mud =           walking_speed*0.5,
126      sand =          walking_speed*0.5
127    },
128
129    tracktype_speeds = {
130    },
131
132    smoothness_speeds = {
133    }
134  }
135end
136
137function process_node(profile, node, result)
138  -- parse access and barrier tags
139  local access = find_access_tag(node, profile.access_tags_hierarchy)
140  if access then
141    if profile.access_tag_blacklist[access] then
142      result.barrier = true
143    end
144  else
145    local barrier = node:get_value_by_key("barrier")
146    if barrier then
147      --  make an exception for rising bollard barriers
148      local bollard = node:get_value_by_key("bollard")
149      local rising_bollard = bollard and "rising" == bollard
150
151      if profile.barrier_blacklist[barrier] and not rising_bollard then
152        result.barrier = true
153      end
154    end
155  end
156
157  -- check if node is a traffic light
158  local tag = node:get_value_by_key("highway")
159  if "traffic_signals" == tag then
160    result.traffic_lights = true
161  end
162end
163
164-- main entry point for processsing a way
165function process_way(profile, way, result)
166  -- the intial filtering of ways based on presence of tags
167  -- affects processing times significantly, because all ways
168  -- have to be checked.
169  -- to increase performance, prefetching and intial tag check
170  -- is done in directly instead of via a handler.
171
172  -- in general we should  try to abort as soon as
173  -- possible if the way is not routable, to avoid doing
174  -- unnecessary work. this implies we should check things that
175  -- commonly forbids access early, and handle edge cases later.
176
177  -- data table for storing intermediate values during processing
178  local data = {
179    -- prefetch tags
180    highway = way:get_value_by_key('highway'),
181    bridge = way:get_value_by_key('bridge'),
182    route = way:get_value_by_key('route'),
183    leisure = way:get_value_by_key('leisure'),
184    man_made = way:get_value_by_key('man_made'),
185    railway = way:get_value_by_key('railway'),
186    platform = way:get_value_by_key('platform'),
187    amenity = way:get_value_by_key('amenity'),
188    public_transport = way:get_value_by_key('public_transport')
189  }
190
191  -- perform an quick initial check and abort if the way is
192  -- obviously not routable. here we require at least one
193  -- of the prefetched tags to be present, ie. the data table
194  -- cannot be empty
195  if next(data) == nil then     -- is the data table empty?
196    return
197  end
198
199  local handlers = Sequence {
200    -- set the default mode for this profile. if can be changed later
201    -- in case it turns we're e.g. on a ferry
202    WayHandlers.default_mode,
203
204    -- check various tags that could indicate that the way is not
205    -- routable. this includes things like status=impassable,
206    -- toll=yes and oneway=reversible
207    WayHandlers.blocked_ways,
208
209    -- determine access status by checking our hierarchy of
210    -- access tags, e.g: motorcar, motor_vehicle, vehicle
211    WayHandlers.access,
212
213    -- check whether forward/backward directons are routable
214    WayHandlers.oneway,
215
216    -- check whether forward/backward directons are routable
217    WayHandlers.destinations,
218
219    -- check whether we're using a special transport mode
220    WayHandlers.ferries,
221    WayHandlers.movables,
222
223    -- compute speed taking into account way type, maxspeed tags, etc.
224    WayHandlers.speed,
225    WayHandlers.surface,
226
227    -- handle turn lanes and road classification, used for guidance
228    WayHandlers.classification,
229
230    -- handle various other flags
231    WayHandlers.roundabouts,
232    WayHandlers.startpoint,
233
234    -- set name, ref and pronunciation
235    WayHandlers.names,
236
237    -- set weight properties of the way
238    WayHandlers.weights
239  }
240
241  WayHandlers.run(profile, way, result, data, handlers)
242end
243
244function process_turn (profile, turn)
245  turn.duration = 0.
246
247  if turn.direction_modifier == direction_modifier.u_turn then
248     turn.duration = turn.duration + profile.properties.u_turn_penalty
249  end
250
251  if turn.has_traffic_light then
252     turn.duration = profile.properties.traffic_light_penalty
253  end
254  if profile.properties.weight_name == 'routability' then
255      -- penalize turns from non-local access only segments onto local access only tags
256      if not turn.source_restricted and turn.target_restricted then
257          turn.weight = turn.weight + 3000
258      end
259  end
260end
261
262return {
263  setup = setup,
264  process_way =  process_way,
265  process_node = process_node,
266  process_turn = process_turn
267}
268