만약 데이터가 있다면, 그 데이터를 기반으로 가중치를 주고 회피하는 알고리즘을 짜서 길을 생성하는 거를 해보겠다.
https://wiki.openstreetmap.org/wiki/Wheelchair_routing
비슷한 프로젝트 발견.
우선 OSRM을 하기 위해서는, 나만의 새로운 길을 만들기 위해서는 Profile을 만들어야한다.
나같은 경우는 safest / foot 이 되겠다.
https://github.com/Project-OSRM/osrm-backend/blob/master/docs/profiles.md
아.. 문서를 읽을 수록 영어 공부를 해야겠다는 생각이 가득찬다.
그래도 내가 해내면 다른 개발자들이 내 고군분투를 보며 편하게 개발할 수 있겠지..
A profile describes whether or not it's possible to route along a particular type of way, whether we can pass a particular node, and how quickly we'll be traveling when we do. This feeds into the way the routing graph is created and thus influences the output routes.
-> 프로필은 특정 유형의 길을 따라 경로를 지정하는 것이 가능한지, 특정 노드를 통과할 수 있는지, 통과할 때 얼마나 빨리 이동할 수 있는지를 설명한다. 이는 라우팅 그래프가 생성되는 방식에 반영되어 출력 경로에 영향을 미친다.
Profiles have a 'lua' extension, and are placed in 'profiles' directory.
-> 프로필은 프로필 폴더에 위치하고 확장자가 lua 이다. 나중에 다른 유저가 이걸로 라우팅을 하고 싶을 때 사용하는 거 같다.
이 프로필을 사용하기 위해서는 OSM 데이터를 전처리하는 흐름을 이해해야한다.
Settings: .lua file
Input: Raw OSM data. (.xml or .pbf file)
Output: Intermediate OSRM format. (.osrm and .names files)
여기서 프로필을 설정해놓으면, 길이 Raw data로 들어오고, 그러면 아웃풋으로 경로가 나가는 흐름이다.
프로필은 lua 스크립트 언어로 작성해놨다고 함. 어려워보이네.
근데 막상 foot.lua 를 보니까 그렇게 어렵지는 않은거 같다.
-- Foot profile
api_version = 2
Set = require('lib/set')
Sequence = require('lib/sequence')
Handlers = require("lib/way_handlers")
find_access_tag = require("lib/access").find_access_tag
function setup()
local walking_speed = 5
return {
properties = {
weight_name = 'duration',
max_speed_for_map_matching = 40/3.6, -- kmph -> m/s
call_tagless_node_function = false,
traffic_light_penalty = 2,
u_turn_penalty = 2,
continue_straight_at_waypoint = false,
use_turn_restrictions = false,
},
default_mode = mode.walking,
default_speed = walking_speed,
oneway_handling = 'specific', -- respect 'oneway:foot' but not 'oneway'
barrier_blacklist = Set {
'yes',
'wall',
'fence'
},
access_tag_whitelist = Set {
'yes',
'foot',
'permissive',
'designated'
},
access_tag_blacklist = Set {
'no',
'agricultural',
'forestry',
'private',
'delivery',
},
restricted_access_tag_list = Set { },
restricted_highway_whitelist = Set { },
construction_whitelist = Set {},
access_tags_hierarchy = Sequence {
'foot',
'access'
},
-- tags disallow access to in combination with highway=service
service_access_tag_blacklist = Set { },
restrictions = Sequence {
'foot'
},
-- list of suffixes to suppress in name change instructions
suffix_list = Set {
'N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW', 'North', 'South', 'West', 'East'
},
avoid = Set {
'impassable',
'proposed'
},
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
function process_node(profile, node, result)
-- parse access and barrier tags
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
-- make an exception for rising bollard barriers
local bollard = node:get_value_by_key("bollard")
local rising_bollard = bollard and "rising" == bollard
if profile.barrier_blacklist[barrier] and not rising_bollard then
result.barrier = true
end
end
end
-- check if node is a traffic light
local tag = node:get_value_by_key("highway")
if "traffic_signals" == tag then
-- Direction should only apply to vehicles
result.traffic_lights = true
end
end
-- main entry point for processsing a way
function process_way(profile, way, result)
-- the intial filtering of ways based on presence of tags
-- affects processing times significantly, because all ways
-- have to be checked.
-- to increase performance, prefetching and intial tag check
-- is done in directly instead of via a handler.
-- in general we should try to abort as soon as
-- possible if the way is not routable, to avoid doing
-- unnecessary work. this implies we should check things that
-- commonly forbids access early, and handle edge cases later.
-- data table for storing intermediate values during processing
local data = {
-- prefetch tags
highway = way:get_value_by_key('highway'),
bridge = way:get_value_by_key('bridge'),
route = way:get_value_by_key('route'),
leisure = way:get_value_by_key('leisure'),
man_made = way:get_value_by_key('man_made'),
railway = way:get_value_by_key('railway'),
platform = way:get_value_by_key('platform'),
amenity = way:get_value_by_key('amenity'),
public_transport = way:get_value_by_key('public_transport')
}
-- perform an quick initial check and abort if the way is
-- obviously not routable. here we require at least one
-- of the prefetched tags to be present, ie. the data table
-- cannot be empty
if next(data) == nil then -- is the data table empty?
return
end
local handlers = Sequence {
-- set the default mode for this profile. if can be changed later
-- in case it turns we're e.g. on a ferry
WayHandlers.default_mode,
-- check various tags that could indicate that the way is not
-- routable. this includes things like status=impassable,
-- toll=yes and oneway=reversible
WayHandlers.blocked_ways,
-- determine access status by checking our hierarchy of
-- access tags, e.g: motorcar, motor_vehicle, vehicle
WayHandlers.access,
-- check whether forward/backward directons are routable
WayHandlers.oneway,
-- check whether forward/backward directons are routable
WayHandlers.destinations,
-- check whether we're using a special transport mode
WayHandlers.ferries,
WayHandlers.movables,
-- compute speed taking into account way type, maxspeed tags, etc.
WayHandlers.speed,
WayHandlers.surface,
-- handle turn lanes and road classification, used for guidance
WayHandlers.classification,
-- handle various other flags
WayHandlers.roundabouts,
WayHandlers.startpoint,
-- set name, ref and pronunciation
WayHandlers.names,
-- set weight properties of the way
WayHandlers.weights
}
WayHandlers.run(profile, way, result, data, handlers)
end
function process_turn (profile, turn)
turn.duration = 0.
if turn.direction_modifier == direction_modifier.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
-- penalize turns from non-local access only segments onto local access only tags
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_turn = process_turn
}
이 코드는 지리 정보 시스템(GIS) 또는 매핑 응용 프로그램과 관련된 루아(Lua) 스크립트이다. 지금 OSRM의 도보 길찾기의 프로필이다.
Setup 함수:
Process Node 함수:
Process Way 함수:
Process Turn 함수:
반환된 모듈:
setup, process_way, process_node, 및 process_turn 함수를 내보낸다.https://github.com/Project-OSRM/osrm-backend/blob/master/docs/profiles.md
참고하였습니다.
내가 원하는 태그와 옵션, 스피드 등을 설정하여 새롭게 lua 파일을 커스텀하였다.
OSRM에 정말 많은 태그가 있는 것으로 아는데, 그 종류를 어떻게 하면 확인할 수 있는지 그리고 사용할 수 있는지 잘 모르겠다.
그래도 우선은 완성은 했다.
이제 Docker을 이용해 배포를 한 뒤, 잘 불러와 지는지 테스트를 해보겠다.
라우팅을 하는 것은 물론 처음 설계가 가장 중요하겠지만, 잘 모르겠을 때는 일단 부딫혀봐야 한다.
기존 라우팅과 다른 .. 조금 차별점이 있고 좋은 알고리즘이 반영되었으면 좋겠다.