-
Notifications
You must be signed in to change notification settings - Fork 12
/
foot-vampire.lua
221 lines (188 loc) · 6.71 KB
/
foot-vampire.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
-- Noch ein Tipp: OSRM 5.7.0 feature: `force_split_edges` flag to the global properties which
-- when set to true guarantees that the segment function will be called for all segments,
-- but also doubles memory consumption in the worst case.
api_version = 4
Set = require('lib/set')
Sequence = require('lib/sequence')
Handlers = require("lib/way_handlers")
find_access_tag = require("lib/access").find_access_tag
-- Setup function to load the raster file (shadow data) and initialize the walking profile
function setup()
local raster_path = os.getenv('OSRM_RASTER_SOURCE') or "shadows_zurich_city.asc"
-- Update these values as per your .asc file header:
-- This is an example. Ensure these match the actual ASC file's metadata.
local lon_min = 8.811776471450 -- xllcorner
local ncols = 509
local nrows = 347
local cellsize = 0.000026370000
local lon_max = lon_min + (ncols * cellsize)
local lat_min = 47.221587715161 -- yllcorner
local lat_max = lat_min + (nrows * cellsize)
local raster_source = raster:load(
raster_path,
lon_min, lon_max,
lat_min, lat_max,
nrows,
ncols
)
local walking_speed = 5
return {
properties = {
weight_name = 'duration',
max_speed_for_map_matching = 40/3.6, -- km/h to m/s
call_tagless_node_function = false,
traffic_light_penalty = 2,
u_turn_penalty = 2,
continue_straight_at_waypoint = false,
use_turn_restrictions = false,
force_split_edges = true, -- Ensures segment processing is always called
},
raster_source = raster_source,
default_mode = mode.walking,
default_speed = walking_speed,
oneway_handling = 'specific',
barrier_whitelist = Set { 'cycle_barrier', 'bollard', 'entrance' },
access_tag_whitelist = Set { 'yes', 'foot', 'permissive', 'designated' },
access_tag_blacklist = Set { 'no', 'agricultural', 'forestry', 'private', 'delivery' },
restricted_highway_whitelist = Set { },
access_tags_hierarchy = Sequence { 'foot', 'access' },
restricted_access_tag_list = Set { },
service_access_tag_blacklist = Set { },
restrictions = Sequence { 'foot' },
suffix_list = Set { 'N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW', 'North', 'South', 'West', 'East' },
avoid = Set { 'impassable' },
speeds = Sequence {
highway = {
primary = walking_speed,
primary_link = walking_speed,
secondary = walking_speed,
secondary_link = walking_speed,
tertiary = walking_speed,
tertiary_link = walking_speed,
unclassified = walking_speed,
residential = walking_speed,
road = walking_speed,
living_street = walking_speed,
service = walking_speed,
track = walking_speed,
path = walking_speed,
steps = walking_speed,
pedestrian = walking_speed,
footway = walking_speed,
pier = walking_speed,
},
railway = { platform = walking_speed },
amenity = { parking = walking_speed, parking_entrance = walking_speed },
man_made = { pier = walking_speed },
leisure = { track = walking_speed },
},
route_speeds = { ferry = 5 },
bridge_speeds = { },
surface_speeds = {
fine_gravel = walking_speed * 0.75,
gravel = walking_speed * 0.75,
pebblestone = walking_speed * 0.75,
mud = walking_speed * 0.5,
sand = walking_speed * 0.5,
},
tracktype_speeds = { },
smoothness_speeds = { }
}
end
-- Calculate rate based on shadow_value:
-- - -9999 (nodata): return 0, no adjustment
-- - 0 (black/shadow): very high preference
-- - Increasing values: decreasing preference
function calculate_rate(shadow_value)
if shadow_value == -9999 then
return 0
end
if shadow_value < 0 then
return 0
end
-- Fourth power penalty:
-- At 0: rate = large_factor / 1 = large_factor (very high preference)
-- At 1: rate = large_factor / 2 still relatively high
-- At 2: rate = large_factor / (1 + 2^4) = large_factor / 17, a huge drop
-- At 10: rate = large_factor / (1 + 10^4) = large_factor / 10001, enormous penalty
local large_factor = 1000000
local exponent = 4 -- Increase exponent for more severe penalty
local rate = large_factor / (1.0 + (shadow_value ^ exponent))
return rate
end
function process_node(profile, node, result)
local access = find_access_tag(node, profile.access_tags_hierarchy)
if access then
if profile.access_tag_blacklist[access] then
result.barrier = true
end
else
local barrier = node:get_value_by_key("barrier")
if barrier then
local bollard = node:get_value_by_key("bollard")
local rising_bollard = bollard and "rising" == bollard
if not profile.barrier_whitelist[barrier] and not rising_bollard then
result.barrier = true
end
end
end
local tag = node:get_value_by_key("highway")
if "traffic_signals" == tag then
result.traffic_lights = true
end
end
function process_way(profile, way, result)
local data = {
highway = way:get_value_by_key('highway')
}
if next(data) == nil then
return
end
local handlers = Sequence {
WayHandlers.default_mode,
WayHandlers.access,
WayHandlers.speed,
WayHandlers.surface
}
WayHandlers.run(profile, way, result, data, handlers)
end
function process_segment(profile, segment)
-- Query raster data for source location
local sourceData = raster:query(profile.raster_source, segment.source.lon, segment.source.lat)
-- Query raster data for target location
local targetData = raster:query(profile.raster_source, segment.target.lon, segment.target.lat)
-- Calculate rates for source and target
local sourceRate = calculate_rate(sourceData.datum)
local targetRate = calculate_rate(targetData.datum)
-- Average the rates; if both are 0 (nodata), no adjustment
local average_rate = 0
if sourceRate > 0 or targetRate > 0 then
average_rate = (sourceRate + targetRate) / 2
end
-- If we have a positive average_rate, adjust the segment weight
-- Since lower shadow_value = higher rate = more preferred,
-- we divide the segment weight by average_rate to reduce cost in those areas
if average_rate > 0 then
segment.weight = segment.weight / average_rate
end
end
function process_turn(profile, turn)
turn.duration = 0.
if turn.is_u_turn then
turn.duration = turn.duration + profile.properties.u_turn_penalty
end
if turn.has_traffic_light then
turn.duration = profile.properties.traffic_light_penalty
end
if profile.properties.weight_name == 'routability' then
if not turn.source_restricted and turn.target_restricted then
turn.weight = turn.weight + 3000
end
end
end
return {
setup = setup,
process_way = process_way,
process_node = process_node,
process_segment = process_segment,
}