2012-02-14 11:21:07 -05:00
require 'OSM/objects' #osmlib gem
require 'OSM/Database'
require 'builder'
2013-04-13 05:38:41 -04:00
class Location
2013-09-18 02:16:19 -04:00
attr_accessor :lon , :lat
2013-08-29 13:32:11 -04:00
2013-09-18 02:16:19 -04:00
def initialize lon , lat
@lat = lat
@lon = lon
end
2013-04-13 05:38:41 -04:00
end
2014-03-19 13:03:38 -04:00
def set_input_format format
raise '*** Input format must be eiter "osm" or "pbf"' unless [ 'pbf' , 'osm' ] . include? format . to_s
@input_format = format . to_s
end
def input_format
@input_format || DEFAULT_INPUT_FORMAT
end
2012-09-28 15:23:13 -04:00
def sanitized_scenario_title
@sanitized_scenario_title || = @scenario_title . gsub / [^0-9A-Za-z. \ -] / , '_'
end
2012-09-21 13:54:22 -04:00
def set_grid_size meters
#the constant is calculated (with BigDecimal as: 1.0/(DEG_TO_RAD*EARTH_RADIUS_IN_METERS
#see ApproximateDistance() in ExtractorStructs.h
#it's only accurate when measuring along the equator, or going exactly north-south
@zoom = meters . to_f * 0 . 8990679362704610899694577444566908445396483347536032203503 E - 5
2012-02-18 09:19:11 -05:00
end
2012-02-14 11:21:07 -05:00
2013-08-31 17:35:26 -04:00
def set_origin origin
@origin = origin
end
2012-02-14 11:21:07 -05:00
def build_ways_from_table table
#add one unconnected way for each row
table . hashes . each_with_index do | row , ri |
#NOTE:
2013-06-26 09:34:01 -04:00
#currently osrm crashes when processing an isolated oneway with just 2 nodes, so we use 4 edges
#this is relatated to the fact that a oneway dead-end street doesn't make a lot of sense
2013-08-29 13:32:11 -04:00
2013-06-26 09:34:01 -04:00
#if we stack ways on different x coordinates, routability tests get messed up, because osrm might pick a neighboring way if the one test can't be used.
2012-02-14 11:21:07 -05:00
#instead we place all lines as a string on the same y coordinate. this prevents using neightboring ways.
2013-08-29 13:32:11 -04:00
2012-02-14 11:21:07 -05:00
#a few nodes...
2013-08-31 17:35:26 -04:00
node1 = OSM :: Node . new make_osm_id , OSM_USER , OSM_TIMESTAMP , @origin [ 0 ] + ( 0 + WAY_SPACING * ri ) * @zoom , @origin [ 1 ]
node2 = OSM :: Node . new make_osm_id , OSM_USER , OSM_TIMESTAMP , @origin [ 0 ] + ( 1 + WAY_SPACING * ri ) * @zoom , @origin [ 1 ]
node3 = OSM :: Node . new make_osm_id , OSM_USER , OSM_TIMESTAMP , @origin [ 0 ] + ( 2 + WAY_SPACING * ri ) * @zoom , @origin [ 1 ]
node4 = OSM :: Node . new make_osm_id , OSM_USER , OSM_TIMESTAMP , @origin [ 0 ] + ( 3 + WAY_SPACING * ri ) * @zoom , @origin [ 1 ]
node5 = OSM :: Node . new make_osm_id , OSM_USER , OSM_TIMESTAMP , @origin [ 0 ] + ( 4 + WAY_SPACING * ri ) * @zoom , @origin [ 1 ]
2012-02-14 11:21:07 -05:00
node1 . uid = OSM_UID
node2 . uid = OSM_UID
node3 . uid = OSM_UID
node4 . uid = OSM_UID
2012-09-29 05:32:53 -04:00
node5 . uid = OSM_UID
2012-02-14 11:21:07 -05:00
node1 << { :name = > " a #{ ri } " }
node2 << { :name = > " b #{ ri } " }
node3 << { :name = > " c #{ ri } " }
node4 << { :name = > " d #{ ri } " }
2012-09-29 05:32:53 -04:00
node5 << { :name = > " e #{ ri } " }
2012-02-14 11:21:07 -05:00
osm_db << node1
osm_db << node2
osm_db << node3
osm_db << node4
2012-09-29 05:32:53 -04:00
osm_db << node5
2013-08-29 13:32:11 -04:00
2012-02-14 11:21:07 -05:00
#...with a way between them
way = OSM :: Way . new make_osm_id , OSM_USER , OSM_TIMESTAMP
way . uid = OSM_UID
way << node1
way << node2
way << node3
way << node4
2012-09-29 05:32:53 -04:00
way << node5
2013-08-29 13:32:11 -04:00
2012-02-14 11:21:07 -05:00
tags = row . dup
2013-08-29 13:32:11 -04:00
2013-02-03 07:07:30 -05:00
# remove tags that describe expected test result
tags . reject! do | k , v |
2013-08-29 13:32:11 -04:00
k =~ / ^forw \ b / ||
2013-02-03 07:07:30 -05:00
k =~ / ^backw \ b / ||
k =~ / ^bothw \ b /
end
2013-08-29 13:32:11 -04:00
2013-02-03 07:07:30 -05:00
##remove empty tags
2012-02-14 11:21:07 -05:00
tags . reject! { | k , v | v == '' }
2013-08-29 13:32:11 -04:00
2012-09-29 05:32:53 -04:00
# sort tag keys in the form of 'node/....'
2012-09-30 06:01:56 -04:00
way_tags = { 'highway' = > 'primary' }
2013-08-29 13:32:11 -04:00
2012-09-29 05:32:53 -04:00
node_tags = { }
tags . each_pair do | k , v |
if k =~ / node \/ (.*) /
2012-10-05 09:37:36 -04:00
if v == '(nil)'
node_tags . delete k
else
node_tags [ $1 ] = v
end
2012-09-29 05:32:53 -04:00
else
2012-10-05 09:37:36 -04:00
if v == '(nil)'
way_tags . delete k
else
way_tags [ k ] = v
end
2012-09-29 05:32:53 -04:00
end
end
2013-08-29 13:32:11 -04:00
2012-09-29 05:32:53 -04:00
way_tags [ 'name' ] = " w #{ ri } "
way << way_tags
node3 << node_tags
2013-08-29 13:32:11 -04:00
2012-02-14 11:21:07 -05:00
osm_db << way
end
end
2013-04-13 05:38:41 -04:00
def table_coord_to_lonlat ci , ri
2013-09-18 02:16:19 -04:00
[ @origin [ 0 ] + ci * @zoom , @origin [ 1 ] - ri * @zoom ]
2013-04-13 05:38:41 -04:00
end
def add_osm_node name , lon , lat
2013-09-18 02:16:19 -04:00
node = OSM :: Node . new make_osm_id , OSM_USER , OSM_TIMESTAMP , lon , lat
node << { :name = > name }
node . uid = OSM_UID
osm_db << node
name_node_hash [ name ] = node
2013-04-13 05:38:41 -04:00
end
def add_location name , lon , lat
2013-09-18 02:16:19 -04:00
location_hash [ name ] = Location . new ( lon , lat )
2013-04-13 05:38:41 -04:00
end
2012-02-14 11:21:07 -05:00
def find_node_by_name s
2013-09-18 02:16:19 -04:00
raise " ***invalid node name ' #{ s } ', must be single characters " unless s . size == 1
raise " *** invalid node name ' #{ s } ', must be alphanumeric " unless s . match / [a-z0-9] /
if s . match / [a-z] /
from_node = name_node_hash [ s . to_s ]
else
from_node = location_hash [ s . to_s ]
end
2012-02-14 11:21:07 -05:00
end
def find_way_by_name s
name_way_hash [ s . to_s ] || name_way_hash [ s . to_s . reverse ]
end
def reset_data
Dir . chdir TEST_FOLDER do
#clear_log
#clear_data_files
end
2012-12-16 07:36:47 -05:00
reset_profile
2012-02-14 11:21:07 -05:00
reset_osm
@fingerprint = nil
end
def make_osm_id
@osm_id = @osm_id + 1
end
def reset_osm
osm_db . clear
name_node_hash . clear
2013-04-13 05:38:41 -04:00
location_hash . clear
2012-02-14 11:21:07 -05:00
name_way_hash . clear
@osm_str = nil
@osm_hash = nil
@osm_id = 0
end
def clear_data_files
File . delete * Dir . glob ( " #{ DATA_FOLDER } /test.* " )
end
def clear_log
File . delete * Dir . glob ( " *.log " )
end
def osm_db
@osm_db || = OSM :: Database . new
end
def name_node_hash
@name_node_hash || = { }
end
2013-04-13 05:38:41 -04:00
def location_hash
@location_hash || = { }
end
2012-02-14 11:21:07 -05:00
def name_way_hash
@name_way_hash || = { }
end
def osm_str
return @osm_str if @osm_str
@osm_str = ''
doc = Builder :: XmlMarkup . new :indent = > 2 , :target = > @osm_str
doc . instruct!
osm_db . to_xml doc , OSM_GENERATOR
@osm_str
end
2013-08-29 13:32:11 -04:00
def write_osm
2012-02-14 11:21:07 -05:00
#write .oms file if needed
Dir . mkdir DATA_FOLDER unless File . exist? DATA_FOLDER
2012-09-28 15:23:13 -04:00
@osm_file = " #{ DATA_FOLDER } / #{ sanitized_scenario_title } _ #{ fingerprint } "
2012-02-14 11:21:07 -05:00
unless File . exist? ( " #{ @osm_file } .osm " )
File . open ( " #{ @osm_file } .osm " , 'w' ) { | f | f . write ( osm_str ) }
end
end
def convert_osm_to_pbf
unless File . exist? ( " #{ @osm_file } .osm.pbf " )
log_preprocess_info
log " == Converting #{ @osm_file } .osm to protobuffer format... " , :preprocess
unless system " osmosis --read-xml #{ @osm_file } .osm --write-pbf #{ @osm_file } .osm.pbf omitmetadata=true 1>> #{ PREPROCESS_LOG_FILE } 2>> #{ PREPROCESS_LOG_FILE } "
2012-12-17 13:27:18 -05:00
raise OsmosisError . new $? , " osmosis exited with code #{ $? . exitstatus } "
2012-02-14 11:21:07 -05:00
end
log '' , :preprocess
end
end
def extracted?
File . exist? ( " #{ @osm_file } .osrm " ) &&
File . exist? ( " #{ @osm_file } .osrm.names " ) &&
File . exist? ( " #{ @osm_file } .osrm.restrictions " )
end
def prepared?
2012-09-28 15:23:13 -04:00
File . exist? ( " #{ @osm_file } .osrm.hsgr " )
2012-02-14 11:21:07 -05:00
end
2012-12-10 10:07:47 -05:00
def write_timestamp
File . open ( " #{ @osm_file } .osrm.timestamp " , 'w' ) { | f | f . write ( OSM_TIMESTAMP ) }
end
2014-04-21 09:24:42 -04:00
def pbf?
input_format == 'pbf'
end
def write_input_data
2012-02-14 11:21:07 -05:00
Dir . chdir TEST_FOLDER do
write_osm
2012-12-10 10:07:47 -05:00
write_timestamp
2014-04-21 09:24:42 -04:00
convert_osm_to_pbf if pbf?
end
end
def extract_data
Dir . chdir TEST_FOLDER do
log_preprocess_info
log " == Extracting #{ @osm_file } .osm... " , :preprocess
unless system " #{ BIN_PATH } /osrm-extract #{ @osm_file } .osm #{ '.pbf' if pbf? } --profile #{ PROFILES_PATH } / #{ @profile } .lua 1>> #{ PREPROCESS_LOG_FILE } 2>> #{ PREPROCESS_LOG_FILE } "
log " *** Exited with code #{ $? . exitstatus } . " , :preprocess
raise ExtractError . new $? . exitstatus , " osrm-extract exited with code #{ $? . exitstatus } . "
2012-02-14 11:21:07 -05:00
end
2014-04-21 09:24:42 -04:00
log '' , :preprocess
end
end
def prepare_data
Dir . chdir TEST_FOLDER do
log_preprocess_info
log " == Preparing #{ @osm_file } .osm... " , :preprocess
unless system " #{ BIN_PATH } /osrm-prepare #{ @osm_file } .osrm --profile #{ PROFILES_PATH } / #{ @profile } .lua 1>> #{ PREPROCESS_LOG_FILE } 2>> #{ PREPROCESS_LOG_FILE } "
log " *** Exited with code #{ $? . exitstatus } . " , :preprocess
raise PrepareError . new $? . exitstatus , " osrm-prepare exited with code #{ $? . exitstatus } . "
2012-02-14 11:21:07 -05:00
end
2014-04-21 09:24:42 -04:00
log '' , :preprocess
2012-02-14 11:21:07 -05:00
end
end
2014-04-21 09:24:42 -04:00
def reprocess
write_input_data
extract_data unless extracted?
prepare_data unless prepared?
log_preprocess_done
end