diff --git a/.gitignore b/.gitignore index 52e45c485..c8687aed3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,13 @@ +# Test folder # +################### +test/speedprofile.ini +test/data/*.osrm +test/data/*.osrm.* +test/data/denmark.osm.pbf +test/data/regh.osm.pbf +test/data/test.osm +test/data/test.osm.pbf + # Compiled source # ################### *.com @@ -6,6 +16,9 @@ *.exe *.o *.so +osrm-extract +osrm-prepare +osrm-routed # Packages # ############ @@ -70,4 +83,4 @@ win/*.suo win/Debug/ win/Release/ win/bin/ -win/bin-debug/ \ No newline at end of file +win/bin-debug/ diff --git a/DataStructures/ExtractorCallBacks.h b/DataStructures/ExtractorCallBacks.h index 9e63a42a0..5a967bae5 100644 --- a/DataStructures/ExtractorCallBacks.h +++ b/DataStructures/ExtractorCallBacks.h @@ -210,10 +210,6 @@ public: return true; } - if ( w.direction == _Way::opposite ){ - std::reverse( w.path.begin(), w.path.end() ); - } - for(vector< NodeID >::size_type n = 0; n < w.path.size()-1; ++n) { externalMemory->allEdges.push_back(_Edge(w.path[n], w.path[n+1], w.type, w.direction, w.speed, w.nameID, w.roundabout, highway == settings.excludeFromGrid)); externalMemory->usedNodeIDs.push_back(w.path[n]); diff --git a/DataStructures/SearchEngine.h b/DataStructures/SearchEngine.h index 38c2267fd..00cbc0116 100644 --- a/DataStructures/SearchEngine.h +++ b/DataStructures/SearchEngine.h @@ -122,15 +122,15 @@ public: _forwardHeap2->Clear(); //insert new starting nodes into forward heap, adjusted by previous distances. if(searchFrom1stStartNode) { - _forwardHeap->Insert(phantomNodePair.startPhantom.edgeBasedNode, distance1-phantomNodePair.startPhantom.weight1, phantomNodePair.startPhantom.edgeBasedNode); - _forwardHeap2->Insert(phantomNodePair.startPhantom.edgeBasedNode, distance2-phantomNodePair.startPhantom.weight1, phantomNodePair.startPhantom.edgeBasedNode); + _forwardHeap->Insert(phantomNodePair.startPhantom.edgeBasedNode, -phantomNodePair.startPhantom.weight1, phantomNodePair.startPhantom.edgeBasedNode); + _forwardHeap2->Insert(phantomNodePair.startPhantom.edgeBasedNode, -phantomNodePair.startPhantom.weight1, phantomNodePair.startPhantom.edgeBasedNode); // INFO("1,2)forw insert " << phantomNodePair.startPhantom.edgeBasedNode << " with weight " << phantomNodePair.startPhantom.weight1); // } else { // INFO("Skipping first start node"); } if(phantomNodePair.startPhantom.isBidirected() && searchFrom2ndStartNode) { - _forwardHeap->Insert(phantomNodePair.startPhantom.edgeBasedNode+1, distance1-phantomNodePair.startPhantom.weight2, phantomNodePair.startPhantom.edgeBasedNode+1); - _forwardHeap2->Insert(phantomNodePair.startPhantom.edgeBasedNode+1, distance2-phantomNodePair.startPhantom.weight2, phantomNodePair.startPhantom.edgeBasedNode+1); + _forwardHeap->Insert(phantomNodePair.startPhantom.edgeBasedNode+1, -phantomNodePair.startPhantom.weight2, phantomNodePair.startPhantom.edgeBasedNode+1); + _forwardHeap2->Insert(phantomNodePair.startPhantom.edgeBasedNode+1, -phantomNodePair.startPhantom.weight2, phantomNodePair.startPhantom.edgeBasedNode+1); // INFO("1)forw insert " << phantomNodePair.startPhantom.edgeBasedNode+1 << " with weight " << distance1-phantomNodePair.startPhantom.weight1); // INFO("2)forw insert " << phantomNodePair.startPhantom.edgeBasedNode+1 << " with weight " << distance2-phantomNodePair.startPhantom.weight1); // } else if(!searchFrom2ndStartNode) { diff --git a/Rakefile b/Rakefile new file mode 100644 index 000000000..bc9514e3f --- /dev/null +++ b/Rakefile @@ -0,0 +1,125 @@ +require 'OSM/StreamParser' + +#$:.unshift(File.dirname(__FILE__) + '/../../lib') +require 'cucumber/rake/task' + +Cucumber::Rake::Task.new do |t| + t.cucumber_opts = %w{--format pretty} +end + +areas = { + :test => {}, + :kbh => { :country => 'denmark', :bbox => 'top=55.6972 left=12.5222 right=12.624 bottom=55.6376' }, + :frd => { :country => 'denmark', :bbox => 'top=55.7007 left=12.4765 bottom=55.6576 right=12.5698' }, + :regh => { :country => 'denmark', :bbox => 'top=56.164 left=11.792 bottom=55.403 right=12.731' }, + :dk => { :country => 'denmark', :bbox => nil }, + :skaane => { :counry => 'sweden', :bbox => 'top=56.55 left=12.4 bottom=55.3 right=14.6' } +} +osm_data_area_name = ENV['area'] ? ENV['area'].to_s.to_sym : :test +raise "Unknown data area." unless areas[osm_data_area_name] +osm_data_country = areas[osm_data_area_name][:country] +osm_data_area_bbox = areas[osm_data_area_name][:bbox] + + +desc "Rebuild and run tests" +task :default => [:build, :cucumber] + +desc "Build using Scons" +task :build do + system "scons" +end + +namespace :data do + desc "Download OSM data" + task :download do + raise "Error while downloading data." unless system "curl http://download.geofabrik.de/osm/europe/#{osm_data_country}.osm.pbf -o test/data/#{osm_data_country}.osm.pbf" + if osm_data_area_bbox + raise "Error while cropping data." unless system "osmosis --read-pbf file=test/data/#{osm_data_country}.osm.pbf --bounding-box #{osm_data_area_bbox} --write-pbf file=test/data/#{osm_data_area_name}.osm.pbf omitmetadata=true" + end + end + + desc "Crop OSM data" + task :crop do + if osm_data_area_bbox + raise "Error while cropping data." unless system "osmosis --read-pbf file=test/data/#{osm_data_country}.osm.pbf --bounding-box #{osm_data_area_bbox} --write-pbf file=test/data/#{osm_data_area_name}.osm.pbf omitmetadata=true" + end + end + + desc "Reprocess OSM data" + task :process do + Dir.chdir "test" do #we must be in the test_folder folder to use the speedprofile.ini in that folder + raise "Error while extracting data." unless system "./osrm-extract data/#{osm_data_area_name}.osm.pbf" + puts + raise "Error while preparing data." unless system "./osrm-prepare data/#{osm_data_area_name}.osrm #{osm_data_area_name}.osrm.restrictions" + puts + end + end + + desc "Convert test file to protobuffer format" + task :protofy do + Dir.chdir "test" do + system "osmosis --read-xml data/test.osm --write-pbf data/test.osm.pbf omitmetadata=true" + puts + end + end + + desc "Delete preprocessing files" + task :clean do + File.delete *Dir.glob('test/data/*.osrm') + File.delete *Dir.glob('test/data/*.osrm.*') + end + +end + +desc "Launch the routing server" +task :run do + Dir.chdir "test" do + system "./osrm-routed" + end +end + +desc "Run all test" +task :test do + system "cucumber --tags @syn" + puts +end + +desc "Prepare test data" +task :prep => ['data:protofy', 'data:process'] do +end + + + + +class OSMTestParserCallbacks < OSM::Callbacks + attr_accessor :locations + + def initialize + @locations = {} + end + def node(node) + puts node + @locations[node.name] = [node.lat,node.lon] + end + + def way(way) + puts way + end + + def relation(relation) + puts relation + end +end + + +task :read do + Dir.chdir "test" do + file = 'data/test.osm' + callbacks = OSMTestParserCallbacks.new + parser = OSM::StreamParser.new(:filename => file, :callbacks => callbacks) + parser.parse + puts callbacks.locations + end +end + + diff --git a/SConstruct b/SConstruct index eb1566e04..bc6d52789 100644 --- a/SConstruct +++ b/SConstruct @@ -49,49 +49,72 @@ def CheckProtobuf(context, version): context.Result(ret) return ret + AddOption('--cxx', dest='cxx', type='string', nargs=1, action='store', metavar='STRING', help='C++ Compiler') AddOption('--stxxlroot', dest='stxxlroot', type='string', nargs=1, action='store', metavar='STRING', help='root directory of STXXL') AddOption('--verbosity', dest='verbosity', type='string', nargs=1, action='store', metavar='STRING', help='make Scons talking') AddOption('--buildconfiguration', dest='buildconfiguration', type='string', nargs=1, action='store', metavar='STRING', help='debug or release') -env = Environment(ENV = {'PATH' : os.environ['PATH']} ,COMPILER = GetOption('cxx')) -if sys.platform.startswith("freebsd"): - env.ParseConfig('pkg-config --cflags --libs protobuf') + +env = Environment( ENV = {'PATH' : os.environ['PATH']} ,COMPILER = GetOption('cxx')) +conf = Configure(env, custom_tests = { 'CheckBoost' : CheckBoost, 'CheckProtobuf' : CheckProtobuf }) + + if GetOption('cxx') is None: #default Compiler print 'Using default C++ Compiler: ', env['CXX'] else: env.Replace(CXX = GetOption('cxx')) print 'Using user supplied C++ Compiler: ', env['CXX'] -if GetOption('stxxlroot') is not None: - env.Append(CPPPATH = GetOption('stxxlroot')+'/include') - env.Append(LIBPATH = GetOption('stxxlroot')+'/lib') - print 'STXXLROOT = ', GetOption('stxxlroot') -if sys.platform == 'win32': - #SCons really wants to use Microsoft compiler - print "Compiling is not yet supported on Windows" - Exit(-1) -else: #Mac OS X - if sys.platform == 'darwin': - print "Compiling is experimental on Mac" - env.Append(CPPPATH = ['/opt/local/include/', '/opt/local/include/libxml2']) - env.Append(LIBPATH = ['/opt/local/lib']) - elif sys.platform.startswith('freebsd'): - env.Append(CPPPATH = ['/usr/local/include', '/usr/local/include/libxml2']) - env.Append(LIBPATH = ['/usr/local/lib']) - else: - env.Append(CPPPATH = ['/usr/include', '/usr/include/include', '/usr/include/libxml2/']) + if GetOption('buildconfiguration') == 'debug': env.Append(CCFLAGS = ['-Wall', '-g3', '-rdynamic']) else: - env.Append(CCFLAGS = ['-O3', '-DNDEBUG', '-march=native']) -#print "Compiling with: ", env['CXX'] -conf = Configure(env, custom_tests = { 'CheckBoost' : CheckBoost, 'CheckProtobuf' : CheckProtobuf }) -if not conf.CheckHeader('omp.h'): - print "Compiler does not support OpenMP. Exiting" - if sys.platform == 'darwin': - print "Continuing because we are on Mac. This might be fatal." - else: + env.Append(CCFLAGS = ['-O3', '-DNDEBUG']) + + +if sys.platform == 'darwin': #Mac OS X + env.Append(CPPPATH = ['/usr/include/libxml2'] ) #comes with os x + #assume dependencies are installed with homebrew, and call out get folder locations + import subprocess + stxxl_prefix = subprocess.check_output(["brew", "--prefix", "libstxxl"]).strip() + env.Append(CPPPATH = [stxxl_prefix+"/include"] ) + env.Append(LIBPATH = [stxxl_prefix+"/lib"] ) + + boost_prefix = subprocess.check_output(["brew", "--prefix", "boost"]).strip() + env.Append(CPPPATH = [boost_prefix+"/include"] ) + env.Append(LIBPATH = [boost_prefix+"/lib"] ) + + #libxml2_prefix = subprocess.check_output(["brew", "--prefix", "libxml2"]).strip() + #env.Append(CPPPATH = [libxml2_prefix+"/include"] ) + #env.Append(LIBPATH = [libxml2_prefix+"/lib"] ) + +elif sys.platform.startswith("freebsd"): + env.ParseConfig('pkg-config --cflags --libs protobuf') + env.Append(CPPPATH = ['/usr/local/include', '/usr/local/include/libxml2']) + env.Append(LIBPATH = ['/usr/local/lib']) + if GetOption('stxxlroot') is not None: + env.Append(CPPPATH = GetOption('stxxlroot')+'/include') + env.Append(LIBPATH = GetOption('stxxlroot')+'/lib') + print 'STXXLROOT = ', GetOption('stxxlroot') + if GetOption('buildconfiguration') != 'debug': + env.Append(CCFLAGS = ['-march=native']) + #print "Compiling with: ", env['CXX'] + env.Append(CCFLAGS = ['-fopenmp']) + env.Append(LINKFLAGS = ['-fopenmp']) +elif sys.platform == 'win32': + #SCons really wants to use Microsoft compiler + print "Compiling is not yet supported on Windows" + Exit(-1) +else: + print "Unknown platform.." + env.Append(CPPPATH = ['/usr/include', '/usr/include/include', '/usr/include/libxml2/']) + + +if sys.platform != 'darwin': + if not conf.CheckHeader('omp.h'): + print "Compiler does not support OpenMP. Exiting" Exit(-1) + if not conf.CheckLibWithHeader('bz2', 'bzlib.h', 'CXX'): print "bz2 library not found. Exiting" Exit(-1) @@ -132,9 +155,6 @@ if not conf.CheckLibWithHeader('Magick++', 'ImageMagick/Magick++.h', 'CXX'): if not (conf.CheckBoost('1.41')): print 'Boost version >= 1.41 needed' Exit(-1); -if not conf.CheckLib('boost_system', language="C++"): - print "boost_system library not found. Exiting" - Exit(-1) if not conf.CheckLibWithHeader('boost_thread', 'boost/thread.hpp', 'CXX'): if not conf.CheckLibWithHeader('boost_thread-mt', 'boost/thread.hpp', 'CXX'): print "boost thread library not found. Exiting" @@ -144,14 +164,21 @@ if not conf.CheckLibWithHeader('boost_thread', 'boost/thread.hpp', 'CXX'): env.Append(CCFLAGS = ' -lboost_thread-mt') env.Append(LINKFLAGS = ' -lboost_thread-mt') if not conf.CheckLibWithHeader('boost_regex', 'boost/regex.hpp', 'CXX'): - print "boost/regex.hpp not found. Exiting" - Exit(-1) -if not conf.CheckCXXHeader('boost/array.hpp'): - print "boost/thread.hpp not found. Exiting" - Exit(-1) -if not conf.CheckCXXHeader('boost/asio.hpp'): - print "boost/thread.hpp not found. Exiting" - Exit(-1) + if not conf.CheckLibWithHeader('boost_regex-mt', 'boost/regex.hpp', 'CXX'): + print "boost/regex.hpp not found. Exiting" + Exit(-1) + else: + print "using boost_regex -mt" + env.Append(CCFLAGS = ' -lboost_regex-mt') + env.Append(LINKFLAGS = ' -lboost_regex-mt') +if not conf.CheckLib('boost_system', language="C++"): + if not conf.CheckLib('boost_system-mt', language="C++"): + print "boost_system library not found. Exiting" + Exit(-1) + else: + print "using boost -mt" + env.Append(CCFLAGS = ' -lboost_system-mt') + env.Append(LINKFLAGS = ' -lboost_system-mt') if not conf.CheckCXXHeader('boost/bind.hpp'): print "boost/bind.hpp not found. Exiting" Exit(-1) @@ -194,18 +221,27 @@ if not conf.CheckCXXHeader('boost/tuple/tuple.hpp'): if not conf.CheckCXXHeader('boost/unordered_map.hpp'): print "boost thread header not found. Exiting" Exit(-1) +#if os.sysconf('SC_NPROCESSORS_ONLN') > 1: +# env.Append(CCFLAGS = ' -D_GLIBCXX_PARALLEL'); +if not (conf.CheckBoost('1.41')): + print 'Boost version >= 1.41 needed' + Exit(-1); +#check for protobuf 2.3.0, else rebuild proto files +if not (conf.CheckProtobuf('2.3.0')): + print 'libprotobuf version >= 2.3.0 needed' + Exit(-1); +if not (env.Detect('protoc')): + print 'protobuffer compiler not found' + protobld = Builder(action = 'protoc -I=DataStructures/pbf-proto --cpp_out=DataStructures/pbf-proto $SOURCE') env.Append(BUILDERS = {'Protobuf' : protobld}) env.Protobuf('DataStructures/pbf-proto/fileformat.proto') env.Protobuf('DataStructures/pbf-proto/osmformat.proto') -env.Append(CCFLAGS = ['-fopenmp']) -env.Append(LINKFLAGS = ['-fopenmp']) +#env.Append(LINKFLAGS = ['-lboost_system']) -env.Program(target = 'osrm-extract', source = ["extractor.cpp", Glob('DataStructures/pbf-proto/*.pb.cc'), Glob('Util/*.cpp')]) -env.Program(target = 'osrm-prepare', source = ["createHierarchy.cpp", 'Contractor/EdgeBasedGraphFactory.cpp', Glob('Util/SRTMLookup/*.cpp')]) -env.Append(CCFLAGS = ['-lboost_regex', '-lboost_iostreams', '-lbz2', '-lz', '-lprotobuf']) -env.Append(LINKFLAGS = ['-lboost_system']) -env.Program(target = 'osrm-routed', source = ["routed.cpp", 'Descriptors/DescriptionFactory.cpp'], CCFLAGS = ['-DROUTED']) +env.Program(target = 'test/osrm-extract', source = ["extractor.cpp", 'DataStructures/pbf-proto/fileformat.pb.cc', 'DataStructures/pbf-proto/osmformat.pb.cc']) +env.Program(target = 'test/osrm-prepare', source = ["createHierarchy.cpp", 'Contractor/EdgeBasedGraphFactory.cpp']) +env.Program(target = 'test/osrm-routed', source = ["routed.cpp", 'Descriptors/DescriptionFactory.cpp']) env = conf.Finish() diff --git a/contractor.ini b/contractor.ini deleted file mode 100644 index d82afbbff..000000000 --- a/contractor.ini +++ /dev/null @@ -1,2 +0,0 @@ -Threads = 4 -SRTM = /opt/storage/srtm/Eurasia \ No newline at end of file diff --git a/createHierarchy.cpp b/createHierarchy.cpp index 17b6e37ed..cd3e69657 100644 --- a/createHierarchy.cpp +++ b/createHierarchy.cpp @@ -79,7 +79,7 @@ int main (int argc, char *argv[]) { INFO("Loading SRTM from/to " << SRTM_ROOT); omp_set_num_threads(numberOfThreads); - INFO("preprocessing data from input file " << argv[2] << " using STL " + INFO("preprocessing data from input file " << argv[1] << " using STL " #ifdef _GLIBCXX_PARALLEL "parallel (GCC)" #else diff --git a/extractor.ini b/extractor.ini deleted file mode 100644 index 15f135ff8..000000000 --- a/extractor.ini +++ /dev/null @@ -1 +0,0 @@ -Memory = 2 diff --git a/features/0_process.feature b/features/0_process.feature new file mode 100644 index 000000000..ef2789162 --- /dev/null +++ b/features/0_process.feature @@ -0,0 +1,25 @@ +@process +Feature: Preprocessing OpenStreetMap data + In order to enable efficient routing + As the OSRM server + I want to be able to preprocess OpenStreetMap data + + Scenario: Processing OpenStreetMap data using bicycle profile + Given I am in the test folder + And the data file "data/kbh.osm.pbf" is present + And the "bicycle" speedprofile is used + + When I run the extractor with "./osrm-extract data/kbh.osm.pbf" + Then the response should include "extracting data from input file data/kbh.osm.pbf" + And the response should include 'Using profile "bicycle"' + And the response should include "[extractor] finished" + And I should see the file "data/kbh.osrm" + And I should see the file "data/kbh.osrm.names" + And I should see the file "data/kbh.osrm.restrictions" + + When I run the preprocessor with "./osrm-prepare data/kbh.osrm data/kbh.osrm.restrictions" + Then the response should include "finished preprocessing" + And I should see the file "data/kbh.osrm.hsgr" + And I should see the file "data/kbh.osrm.nodes" + And I should see the file "data/kbh.osrm.ramIndex" + And I should see the file "data/kbh.osrm.fileIndex" diff --git a/features/1_launch.feature b/features/1_launch.feature new file mode 100644 index 000000000..9e29bab38 --- /dev/null +++ b/features/1_launch.feature @@ -0,0 +1,13 @@ +@launch +Feature: Launching OSRM server + In order to handle routing request + As a user + I want to launch the OSRM server + +Scenario: Launching the OSRM server + Given I am in the test folder + And the preprocessed files for "data/kbh" are present and up to date + When I start the server with "./osrm-routed" + Then a process called "osrm-routed" should be running + And I should see "running and waiting for requests" on the terminal + diff --git a/features/basic.feature b/features/basic.feature new file mode 100644 index 000000000..07cdb2505 --- /dev/null +++ b/features/basic.feature @@ -0,0 +1,100 @@ +@routing @basic +Feature: Basic Routing + + Scenario Outline: Smallest possible datasat + Given the nodes + | a | b | + + And the ways + | nodes | + | ab | + + When I route between "" and "" + Then "" should be returned + + Examples: + | from | to | route | + | a | b | ab | + | b | a | ba | + + Scenario Outline: Smallest possible datasat + Given the nodes + | a | b | + + And the ways + | nodes | + | ab | + + When I route between "" and "" + Then "" should be returned + + Examples: + | from | to | route | + | a | b | ab | + | b | a | ba | + + Scenario Outline: Connected ways + Given the nodes + | a | | c | + | | b | | + + And the ways + | nodes | + | ab | + | bc | + + When I route between "" and "" + Then "" should be returned + + Examples: + | from | to | route | + | a | c | abc | + | c | a | cba | + | a | b | ab | + | b | a | ba | + | b | c | bc | + | c | b | cb | + + Scenario Outline: Unconnected ways + Given the nodes + | a | b | + | c | d | + + And the ways + | nodes | + | ab | + | cd | + + When I route between "" and "" + Then "" should be returned + + Examples: + | from | to | route | + | a | b | ab | + | b | a | ba | + | c | d | cd | + | d | c | dc | + | a | c | | + | c | a | | + | b | d | | + | d | c | | + | a | d | | + | d | a | | + + Scenario Outline: Pick the fastest way type + Given the nodes + | a | s | + | p | b | + + And the ways + | nodes | highway | + | apb | primary | + | asb | secondary | + + When I route between "" and "" + Then "" should be returned + + Examples: + | from | to | route | + | a | b | apb | + | b | a | bpa | \ No newline at end of file diff --git a/features/bicycle.feature b/features/bicycle.feature new file mode 100644 index 000000000..4c041cda8 --- /dev/null +++ b/features/bicycle.feature @@ -0,0 +1,5 @@ +@routing @bicycle +Feature: Bicycle Routing from A to B + To enable bicycle routing + OSRM should handle all relevant bicycle tags + diff --git a/features/kbh.feature b/features/kbh.feature new file mode 100644 index 000000000..2dbd53f11 --- /dev/null +++ b/features/kbh.feature @@ -0,0 +1,37 @@ +@routing +Feature: Real-world routing test in the Copenhagen area + + Scenario: Phantom shortcut + When I request a route from 55.662740149207,12.576105114488& to 55.665753800212,12.575547215013 + Then I should get a route + And the distance should be close to 450m + + Scenario: Start and stop markers should snap to closest streets + When I request a route from 55.6634,12.5724 to 55.6649,12.5742 + Then I should get a route + And the route should stay on "Islands Brygge" + And the distance should be close to 200m + + Scenario: Crossing roundabout at Amalienborg + When I request a route from 55.683797649183,12.593940686704 to 55.6842149924,12.592476200581 + Then I should get a route + And the distance should be close to 150m + + Scenario: Requesting invalid routes + When I request a route from 0,0 to 0,0 + Then I should not get a route + And no error should be reported in terminal + + Scenario: Dont flicker + When I request a route from 55.658833555366,12.592788454378 to 55.663871808364,12.583497282355 + Then I should get a route + And the route should follow "Amagerfælledvej, Njalsgade, Artillerivej" + And no error should be reported in terminal + When I request a route from 55.658821450674,12.592466589296 to 55.663871808364,12.583497282355 + Then I should get a route + And the route should follow "Kaj Munks Vej, Tom Kristensens Vej, Ørestads Boulevard, Njalsgade, Artillerivej" + And no error should be reported in terminal + When I request a route from 55.658857764739,12.592058893525 to 55.663871808364,12.583497282355 + Then I should get a route + And the route should follow "Kaj Munks Vej, Tom Kristensens Vej, Ørestads Boulevard, Njalsgade, Artillerivej" + And no error should be reported in terminal diff --git a/features/oneways.feature b/features/oneways.feature new file mode 100644 index 000000000..f8a64ef2b --- /dev/null +++ b/features/oneways.feature @@ -0,0 +1,96 @@ +@routing @oneways +Feature: Oneway streets + Handle oneways streets, as defined at http://wiki.openstreetmap.org/wiki/OSM_tags_for_routing + + Scenario: Implied oneways + Given the speedprofile "car" + Then routability should be + | highway | junction | forw | backw | + | motorway | | x | x | + | motorway_link | | x | | + | trunk | | x | x | + | trunk_link | | x | | + | primary | roundabout | x | | + + Scenario: Overriding implied oneways + Given the defaults + Then routability should be + | highway | junction | oneway | forw | backw | + | motorway_link | | no | x | x | + | trunk_link | | no | x | x | + | primary | roundabout | no | x | x | + | motorway_link | | -1 | | x | + | trunk_link | | -1 | | x | + | primary | roundabout | -1 | | x | + + Scenario: Handle various oneway tag values + Given the defaults + Then routability should be + | highway | oneway | forw | backw | + | primary | | x | x | + | primary | nonsense | x | x | + | primary | no | x | x | + | primary | false | x | x | + | primary | 0 | x | x | + | primary | yes | x | | + | primary | true | x | | + | primary | 1 | x | | + | primary | -1 | | x | + + Scenario: Disabling oneways in speedprofile + Given the speedprofile settings + | obeyOneways | no | + Then routability should be + | highway | junction | oneway | forw | backw | + | primary | | yes | x | x | + | primary | | true | x | x | + | primary | | 1 | x | x | + | primary | | -1 | x | x | + | motorway_link | | | x | x | + | trunk_link | | | x | x | + | primary | roundabout | | x | x | + + Scenario: Oneways and bicycles + Given the defaults + Then routability should be + | highway | junction | oneway | oneway:bicycle | forw | backw | + | primary | | | yes | x | | + | primary | | yes | yes | x | | + | primary | | no | yes | x | | + | primary | | -1 | yes | x | | + | motorway | | | yes | x | | + | motorway_link | | | yes | x | | + | primary | roundabout | | yes | x | | + | primary | | | no | x | x | + | primary | | yes | no | x | x | + | primary | | no | no | x | x | + | primary | | -1 | no | x | x | + | motorway | | | no | x | x | + | motorway_link | | | no | x | x | + | primary | roundabout | | no | x | x | + | primary | | | -1 | | x | + | primary | | yes | -1 | | x | + | primary | | no | -1 | | x | + | primary | | -1 | -1 | | x | + | motorway | | | -1 | | x | + | motorway_link | | | -1 | | x | + | primary | roundabout | | -1 | | x | + + Scenario: Cars should not be affected by bicycle tags + Given the speedprofile settings + | accessTag | motorcar | + + Then routability should be + | highway | junction | oneway | oneway:bicycle | forw | backw | + | primary | | yes | yes | x | | + | primary | | yes | no | x | | + | primary | | yes | -1 | x | | + | primary | | no | yes | x | x | + | primary | | no | no | x | x | + | primary | | no | -1 | x | x | + | primary | | -1 | yes | | x | + | primary | | -1 | no | | x | + | primary | | -1 | -1 | | x | + | primary | roundabout | | yes | x | | + | primary | roundabout | | no | x | | + | primary | roundabout | | -1 | x | | diff --git a/features/other.feature b/features/other.feature new file mode 100644 index 000000000..2b2cd636f --- /dev/null +++ b/features/other.feature @@ -0,0 +1,65 @@ +@other +Feature: Other stuff + +Scenario: No left turn when crossing a oneway street + When I request a route from 55.689741159238,12.574720202639 to 55.689741159232,12.57455927015 + Then I should get a route + And the route should start at "Sølvgade" + And the route should end at "Øster Farimagsgade" + And the route should not include "Sølvgade, Øster Farimagsgade" + And no error should be reported in terminal + +Scenario: No left turn at T-junction: Don't turn left from side road into main road + When I request a route from 55.66442995717,12.549384056343 to 55.664218154805,12.5502638209 + Then I should get a route + And the route should start at "Sigerstedgade" + And the route should end at "Ingerslevsgade" + And the route should not include "Sigerstedgade, Ingerslevsgade" + And there should be more than 1 turn + +Scenario: No left turn at T-junction: OK to turn right from side road into main road + When I request a route from 55.66442995717,12.549384056343 to 55.664060815164,12.548944174065 + Then I should get a route + And the route should start at "Sigerstedgade" + And the route should end at "Ingerslevsgade" + And the route should include "Sigerstedgade, Ingerslevsgade" + And there should be 1 turn + +Scenario: No left turn at T-junction: OK to go straight on main road + When I request a route from 55.66419092299,12.550333558335 to 55.664060815164,12.548944174065 + Then I should get a route + And the route should stay on "Ingerslevsgade" + +Scenario: No left turn at T-junction: OK to turn right from main road into side road + When I request a route from 55.664060815164,12.548944174065 to 55.66442995717,12.549384056343 + Then I should get a route + And the route should start at "Ingerslevsgade" + And the route should end at "Sigerstedgade" + And the route should include "Ingerslevsgade, Sigerstedgade" + And there should be 1 turn + +Scenario: No left turn at T-junction: OK to turn left from main road into side road + When I request a route from 55.664218154805,12.5502638209 to 55.66442995717,12.549384056343 + Then I should get a route + And the route should start at "Ingerslevsgade" + And the route should end at "Sigerstedgade" + And the route should include "Ingerslevsgade, Sigerstedgade" + And there should be 1 turn + + + +Scenario: oneway:bicycle + When I request a route from 55.673168935147,12.563557740441 to 55.67380116846,12.563107129324& + Then I should get a route + And the route should follow "Banegårdspladsen" + And there should not be any turns + And the distance should be close to 80m + +Scenario: cycleway=opposite_lane + When I request a route from 55.689126237262,12.553137305887 to 55.688666612359,12.55296564451 + Then I should get a route + And the route should follow "Kapelvej" + And there should not be any turns + And the distance should be close to 50m + + diff --git a/features/outlines.feature b/features/outlines.feature new file mode 100644 index 000000000..48394f9f7 --- /dev/null +++ b/features/outlines.feature @@ -0,0 +1,25 @@ +@outlines +Feature: Outlines + Scenario outlines is another way to test routes... not sure which method is best? + + Scenario Outline: ways + Given the nodes + | a | | c | + | | b | | + + And the ways + | nodes | + | ab | + | bc | + + When I route from "" to "" + Then I should get the route "" + + Examples: + | from | to | route | + | a | c | abc | + | c | a | cba | + | a | b | ab | + | b | a | ba | + | b | c | bc | + | c | b | cb | diff --git a/features/restrictions.feature b/features/restrictions.feature new file mode 100644 index 000000000..dd35b1126 --- /dev/null +++ b/features/restrictions.feature @@ -0,0 +1,30 @@ +@routing @restrictions +Feature: Turn restrictions + Handle turn restrictions as defined by http://wiki.openstreetmap.org/wiki/Relation:restriction + + Scenario Outline: No left turn at T-junction + Given the nodes + | a | j | b | + | | s | | + + And the ways + | nodes | + | aj | + | jb | + | sj | + + And the relations + | from | to | via | restriction | + | sj | ja | j | no_left_turn | + + When I route between "" and "" + Then "" should be returned + + Examples: + | from | to | route | + | a | b | ajb | + | a | s | ajs | + | b | a | bja | + | b | s | bjs | + | s | a | | + | s | b | sjb | \ No newline at end of file diff --git a/features/step_definitions/launch.rb b/features/step_definitions/launch.rb new file mode 100644 index 000000000..c3895cf52 --- /dev/null +++ b/features/step_definitions/launch.rb @@ -0,0 +1,96 @@ +require 'pathname' +require 'json' +require 'open4' +require "net/http" +require "uri" + +$stdout.sync = true +$server_pipe = nil +$server_running = false + +def read_terminal + return $server_pipe.read_nonblock 10000 rescue nil +end + +def running? + `ps -eo command | grep #{@test_folder}/osrm-running$`.size != 0 +end + +def launch cmd = "./osrm-routed" + $server_pipe = IO.popen(cmd) + sleep 2 # so the daemon has a chance to boot + + at_exit do + if $server_pipe + Process.kill("KILL", $server_pipe.pid) # clean up the daemon when the tests finish + end + end +end + +def kill + if $server_pipe + Process.kill("KILL", $server_pipe.pid) + $server_pipe = nil + sleep 2 # so the daemon has a chance to quit + end +end + +Given /^I am in the test folder$/ do + @root = Pathname.new(File.dirname(__FILE__)).parent.parent.expand_path + @test_folder = "#{@root}/test" + Dir.chdir @test_folder +end + +Given /^the server is configured for bike routing$/ do + pending # express the regexp above with the code you wish you had +end + +Given /^the "([^"]*)" speedprofile is used$/ do |profile| + FileUtils.cp "speedprofiles/#{profile}.ini", "speedprofile.ini" +end + +Then /^the response should include "([^"]*)"$/ do |string| + @response.include?(string).should_not == nil +end + +Then /^the response should include '([^']*)'$/ do |string| + @response.include?(string).should_not == nil +end + +Given /^the server is running$/ do + unless $server_running + step 'a process called "osrm-routed" should be running' + @server_running = true + end +end + +When /^I start the server with "([^']*)"$/ do |cmd| + launch cmd +end + +When /^I stop the server$/ do + kill +end + +Then /^a process called "([^']*)" should be running$/ do |daemon| + #puts `ps -eo command | grep #{@test_folder}/#{daemon}` + `ps -eo command | grep #{@test_folder}/#{daemon}`.size.should > 0 +end + +Then /^a process called "([^']*)" should not be running$/ do |daemon| + `ps -eo command | grep #{@test_folder}/#{daemon}$`.size.should == 0 +end + +Then /^a process called "([^']*)" is not running$/ do |daemon| + step "a process called \"#{daemon}\" should not be running" +end + + +Then /^I should see "([^']*)" on the terminal$/ do |string| + out = read_terminal + out.should =~ /#{string}/ +end + +Then /^no error should be reported in terminal$/ do + read_terminal.should_not =~ /error/ +end diff --git a/features/step_definitions/processing.rb b/features/step_definitions/processing.rb new file mode 100644 index 000000000..86c6f63d9 --- /dev/null +++ b/features/step_definitions/processing.rb @@ -0,0 +1,77 @@ +require 'OSM/StreamParser' + +class OSMTestParserCallbacks < OSM::Callbacks + @@locations = nil + + def self.locations + if @@locations + @@locations + else + #parse the test file, so we can later reference nodes and ways by name in tests + @@locations = {} + file = 'test/data/test.osm' + callbacks = OSMTestParserCallbacks.new + parser = OSM::StreamParser.new(:filename => file, :callbacks => callbacks) + parser.parse + puts @@locations + end + end + + def node(node) + @@locations[node.name] = [node.lat,node.lon] + end + + def way(way) + end + + def relation(relation) + end +end + + +Given /^the OSM file contains$/ do |string| + file = 'data/test.osm' + File.open( file, 'w') {|f| f.write(string) } + + #convert from .osm to .osm.pbf, which is the format osrm reads + system "osmosis --read-xml data/test.osm --write-pbf data/test.osm.pbf omitmetadata=true" +end + +Given /^the speedprofile contains$/ do |string| + File.open( 'speedprofile.ini', 'w') {|f| f.write(string) } +end + + + +Given /^the data file "([^"]*)" is present$/ do |file| + File.exists?(file).should == true +end + +When /^I run the extractor with "([^"]*)"$/ do |cmd| + @response = `#{cmd}` + #Dir.chdir @test_folder do + # @response = IO.popen([cmd, :err=>[:child, :out]]) { |ls_io| ls_result_with_error = ls_io.read } + #end +end + +When /^I run the preprocessor with "([^"]*)"$/ do |cmd| + @response = `#{cmd}` +end + +Given /^the preprocessed files for "([^"]*)" are present and up to date$/ do |area| + File.exists?("#{area}.osrm").should == true + File.exists?("#{area}.osrm.names").should == true + File.exists?("#{area}.osrm.restrictions").should == true + File.exists?("#{area}.osrm.hsgr").should == true + File.exists?("#{area}.osrm.nodes").should == true + File.exists?("#{area}.osrm.ramIndex").should == true + File.exists?("#{area}.osrm.fileIndex").should == true +end + +Then /^I should see the file "([^"]*)"$/ do |file| + File.exists?(file).should == true +end + +When /^preprocessed files for "([^"]*)" has been removed$/ do |file| + FileUtils.rm_r Dir["#{file}.*"], :secure => true +end diff --git a/features/step_definitions/routing.rb b/features/step_definitions/routing.rb new file mode 100644 index 000000000..9b49b2a80 --- /dev/null +++ b/features/step_definitions/routing.rb @@ -0,0 +1,234 @@ + + +def request_route a,b + uri = URI.parse "http://localhost:5000/viaroute&start=#{a}&dest=#{b}&output=json&geomformat=cmp" + #puts "routing: #{uri}" + Net::HTTP.get_response uri +rescue Errno::ECONNREFUSED => e + raise "*** osrm-routed is not running." +rescue Timeout::Error + raise "*** osrm-routed didn't respond." +end + +When /^I request a route from ([^"]+) to ([^"]+)$/ do |a,b| + @response = request_route a,b + #puts @response.body + #@response +end + +When /^I request a route from "([^"]*)" to "([^"]*)"$/ do |a,b| + locations = OSMTestParserCallbacks.locations + raise "Locations hash is empty. To reference nodes by name, please preprocess the test file earlier in the test." unless locations + raise "Unknown node: #{a}" unless locations[a] + raise "Unknown node: #{b}" unless locations[b] + @response = request_route "#{locations[a][0]},#{locations[a][1]}", "#{locations[b][0]},#{locations[b][1]}" +end + + +Then /^I should get a response/ do + @response.code.should == "200" + @response.body.should_not == nil + @response.body.should_not == '' +end + +Then /^response should be valid JSON$/ do + @json = JSON.parse @response.body +end + +Then /^response should be well-formed$/ do + @json['version'].class.should == Float + @json['status'].class.should == Fixnum + @json['status_message'].class.should == String + @json['route_summary'].class.should == Hash + @json['route_geometry'].class.should == String + @json['route_instructions'].class.should == Array + @json['via_points'].class.should == Array + @json['transactionId'].class.should == String +end + +Then /^a route should be found$/ do + @json['status'].should == 0 + @json['status_message'].should == "Found route between points" +end + +Then /^no route should be found$/ do + @json['status'].should == 207 + @json['status_message'].should == "Cannot find route between points" +end + +Then /^I should get a valid response$/ do + step "I should get a response" + step "response should be valid JSON" + step "response should be well-formed" + #step "no error should be reported in terminal" +end + +Then /^I should get a route$/ do + step "I should get a valid response" + step "a route should be found" + #puts @response.body +end + +Then /^I should not get a route$/ do + step "I should get a valid response" + step "no route should be found" +end + +Then /^the route should start at "([^']*)"$/ do |name| + @json['route_summary']['start_point'].should == name +end + +Then /^the route should end at "([^']*)"$/ do |name| + @json['route_summary']['end_point'].should == name +end + +Then /^distance should be between (\d+) and (\d+)$/ do |min,max| + @json['route_summary']['total_distance'].to_i.should >= min.to_i + @json['route_summary']['total_distance'].to_i.should <= max.to_i +end + +Then /^the distance should be close to (\d+)m$/ do |d| + @json['route_summary']['total_distance'].to_i.should >= d.to_i*0.95 + @json['route_summary']['total_distance'].to_i.should <= d.to_i/0.95 +end + +Then /^number of instructions should be (\d+)$/ do |n| + @json['route_instructions'].size.should == n +end + +Then /^there should be 1 turn$/ do + step 'there should be 1 turns' +end + +Then /^there should be (\d+) turns$/ do |n| + @json['route_instructions'].map {|t| t.first}.select {|t| t =~ /^Turn/ }.size.should == n.to_i +end + +Then /^there should be more than (\d+) turn$/ do |n| + @json['route_instructions'].map {|t| t.first}.select {|t| t =~ /^Turn/ }.size.should > n.to_i +end + +Then /^there should not be any turns$/ do + (@json['route_instructions'].size-1).should == 0 +end + +def sanitize_route route + route.split(',').map{|w| w.strip}.reject(&:empty?).join(', ') +end + +def computed_route + @json['route_instructions'].map { |r| r[1] }.reject(&:empty?).join(', ') +end + +Then /^the route should follow "([^"]*)"$/ do |route| + computed_route.should == sanitize_route(route) +end + +Then /^the route should not follow "([^"]*)"$/ do |route| + computed_route.should_not == sanitize_route(route) +end + +Then /^the route should include "([^"]*)"$/ do |route| + sanitize_route(route).should =~ /#{computed_route}/ +end + +Then /^the route should not include "([^"]*)"$/ do |route| + sanitize_route(route).should_not =~ /#{computed_route}/ +end + +Then /^the route should stay on "([^"]*)"$/ do |way| + step "the route should start at \"#{way}\"" + step "the route should end at \"#{way}\"" + step "the route should follow \"#{way}\"" + step "there should not be any turns" +end + +def parse_response response + if response.code == "200" && response.body.empty? == false + json = JSON.parse response.body + #puts response.body + if json['status'] == 0 + route = json['route_instructions'].map { |r| r[1] }.reject(&:empty?).join(', ') + if route.empty? + "Empty route: #{json['route_instructions']}" + else + route + end + elsif json['status'] == 207 + nil #no route found + else + "Status: #{json['status']}" + end + else + "HTTP: #{response.code}" + end +end + + +When /^I route I should get$/ do |table| + actual = [] + reprocess_if_needed + Dir.chdir 'test' do + launch + table.hashes.each do |row| + from_node = @name_node_hash[ row['from'] ] + to_node = @name_node_hash[ row['to'] ] + route = parse_response( request_route("#{from_node.lon},#{from_node.lat}", "#{to_node.lat},#{to_node.lat}") ) + actual << { 'from' => row['from'].dup, 'to' => row['to'].dup, 'route' => route } + end + kill + end + table.diff! actual + end + +When /^I route on tagged ways I should get $/ do |table| + pending +end + +When /^I route between "([^"]*)" and "([^"]*)"$/ do |from,to| +end + +Then /^"([^"]*)" should be returned$/ do |route| +end + +def build_ways_from_table table + #add one unconnected way for each row + table.hashes.each_with_index do |row,ri| + #two nodes... + node1 = OSM::Node.new nil, OSM_USER, OSM_TIMESTAMP, ORIGIN[0]+0*ZOOM, ORIGIN[1]-ri*ZOOM + node2 = OSM::Node.new nil, OSM_USER, OSM_TIMESTAMP, ORIGIN[0]+1*ZOOM, ORIGIN[1]-ri*ZOOM + node1.uid = OSM_UID + node2.uid = OSM_UID + osm_db << node1 + osm_db << node2 + + #...with a way between them + way = OSM::Way.new -ri-1, OSM_USER, OSM_TIMESTAMP + way.uid = OSM_UID + tags = row.dup + tags.delete 'forw' + tags.delete 'backw' + tags.reject! { |k,v| v=='' } + way << tags + way << node1 + way << node2 + osm_db << way + end + Dir.chdir TEST_FOLDER do + write_osm + end + must_reprocess +end + +Then /^routability should be$/ do |table| + build_ways_from_table table + reprocess_if_needed + actual = [ table.column_names ] + Dir.chdir 'test' do + launch + p "#{ORIGIN[0]+0*ZOOM},#{ORIGIN[1]-0*ZOOM}", "#{ORIGIN[0]+1*ZOOM},#{ORIGIN[1]-0*ZOOM}" + p request_route("#{ORIGIN[0]+0*ZOOM},#{ORIGIN[1]-0*ZOOM}", "#{ORIGIN[0]+1*ZOOM},#{ORIGIN[1]-0*ZOOM}").body + kill + end + table.diff! actual +end diff --git a/features/step_definitions/test_data.rb b/features/step_definitions/test_data.rb new file mode 100644 index 000000000..ca32387e5 --- /dev/null +++ b/features/step_definitions/test_data.rb @@ -0,0 +1,183 @@ +require 'OSM/objects' #osmlib gem +require 'OSM/Database' +require 'builder' + +OSM_USER = 'osrm' +OSM_TIMESTAMP = '2012-01-01T00:00:00Z' +OSM_GENERATOR = 'osrm-test' +OSM_UID = 1 +TEST_FOLDER = 'test' +DATA_FOLDER = 'data' +OSM_FILE = 'test' +LOG_FILE = 'test.log' + +DEFAULT_SPEEDPROFILE = 'bicycle' + +ORIGIN = [1,1] +ZOOM = 0.001 + +def must_reprocess + @must_reprocess = true +end + +def must_reprocess? + @must_reprocess ||= true +end + +def reprocess_if_needed + if must_reprocess? + raise "*** osrm-routed is running. Please stop it before running tests." if running? + #puts "Reprocessing: #{@osm_db.nodes.size} nodes, #{@name_way_hash.size} ways, #{@relations.size} relations... " + + Dir.chdir TEST_FOLDER do + write_speedprofile + write_osm + reprocess + end + @must_reprocess = false + end +end + +def reprocess + file = "#{DATA_FOLDER}/#{OSM_FILE}" + raise "*** osrm-extract failed. Please see test.log for more info." unless system "./osrm-extract #{file}.osm.pbf 1>>#{LOG_FILE} 2>>#{LOG_FILE}" + raise "*** osrm-prepare failed. Please see test.log for more info." unless system "./osrm-prepare #{file}.osrm #{file}.restrictions 1>>#{LOG_FILE} 2>>#{LOG_FILE}" +end + +def find_node_by_name s + name_node_hash[s.to_s] +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 + osm_db.clear + name_node_hash.clear + name_way_hash.clear + must_reprocess + reset_speedprofile +end + +def clear_data_files + File.delete *Dir.glob("#{DATA_FOLDER}/test.*") +end + +def clear_log + File.delete *Dir.glob("*.log") +end + +def speedprofile + @speedprofile ||= reset_speedprofile +end + +def reset_speedprofile + @speedprofile = {} + read_speedprofile DEFAULT_SPEEDPROFILE +end + +def read_speedprofile profile + @speedprofile = {} + s = File.read "test/speedprofiles/#{profile}.ini" + s.scan /(.*)=(.*)/ do |option| + @speedprofile[option[0].strip] = option[1].strip + end +end + +def dump_speedprofile + "[default]\n" + @speedprofile.map { |k,v| "\t#{k} = #{v}" }.join("\n") +end + +def write_speedprofile + File.open( 'speedprofile.ini', 'w') {|f| f.write( dump_speedprofile ) } +end + +def osm_db + @osm_db ||= OSM::Database.new +end + +def name_node_hash + @name_node_hash ||= {} +end + +def name_way_hash + @name_way_hash ||= {} +end + +def write_osm + xml = '' + doc = Builder::XmlMarkup.new :indent => 2, :target => xml + doc.instruct! + osm_db.to_xml doc, OSM_GENERATOR + + #write .oms file + file = "#{DATA_FOLDER}/#{OSM_FILE}" + File.open( "#{file}.osm", 'w') {|f| f.write(xml) } + + #convert from .osm to .osm.pbf, which is the format osrm reads + #convert. redirect stdout and stderr to a log file avoid output in the cucumber console + unless system "osmosis --read-xml #{file}.osm --write-pbf #{file}.osm.pbf omitmetadata=true 1>>#{LOG_FILE} 2>>#{LOG_FILE}" + raise "Failed to convert to proto buffer format. Please see #{file}.log for more info." + end +end + + +Given /^the speedprofile "([^"]*)"$/ do |profile| + read_speedprofile profile +end + + +Given /^the speedprofile settings$/ do |table| + table.raw.each do |row| + speedprofile[ row[0] ] = row[1] + end +end + +Given /^the nodes$/ do |table| + table.raw.each_with_index do |row,ri| + row.each_with_index do |name,ci| + unless name.empty? + node = OSM::Node.new nil, OSM_USER, OSM_TIMESTAMP, ORIGIN[0]+ci*ZOOM, ORIGIN[1]-ri*ZOOM + node << { :name => name } + node.uid = OSM_UID + osm_db << node + name_node_hash[name] = node + end + end + end +end + +Given /^the ways$/ do |table| + must_reprocess + table.hashes.each do |row| + name = row.delete 'nodes' + way = OSM::Way.new nil, OSM_USER, OSM_TIMESTAMP + defaults = { 'highway' => 'primary' } + way << defaults.merge( 'name' => name ).merge(row) + way.uid = OSM_UID + name.each_char { |c| way << find_node_by_name(c) } + osm_db << way + name_way_hash[name] = way + end +end + +Given /^the relations$/ do |table| + must_reprocess + table.hashes.each do |row| + relation = OSM::Relation.new nil, OSM_USER, OSM_TIMESTAMP + relation << { :type => :restriction, :restriction => 'no_left_turn' } + relation << OSM::Member.new( 'way', find_way_by_name(row['from']).id, 'from' ) + relation << OSM::Member.new( 'way', find_way_by_name(row['to']).id, 'to' ) + relation << OSM::Member.new( 'node', find_node_by_name(row['via']).id, 'via' ) + relation.uid = OSM_UID + osm_db << relation + end +end + +Given /^the defaults$/ do +end diff --git a/features/support/hooks.rb b/features/support/hooks.rb new file mode 100644 index 000000000..adf806b64 --- /dev/null +++ b/features/support/hooks.rb @@ -0,0 +1,3 @@ +Before do + reset_data +end \ No newline at end of file diff --git a/server.ini b/server.ini index fbf0108d2..2a6d1dac5 100644 --- a/server.ini +++ b/server.ini @@ -2,8 +2,8 @@ Threads = 8 IP = 0.0.0.0 Port = 5000 -hsgrData=/opt/osm/germany.osrm.hsgr -nodesData=/opt/osm/germany.osrm.nodes -ramIndex=/opt/osm/germany.osrm.ramIndex -fileIndex=/opt/osm/germany.osrm.fileIndex -namesData=/opt/osm/germany.osrm.names +hsgrData=data/kbh.osrm.hsgr +nodesData=data/kbh.osrm.nodes +ramIndex=data/kbh.osrm.ramIndex +fileIndex=data/kbh.osrm.fileIndex +namesData=data/kbh.osrm.names diff --git a/speedprofile.ini b/speedprofile.ini deleted file mode 100644 index 2a504a0cd..000000000 --- a/speedprofile.ini +++ /dev/null @@ -1,48 +0,0 @@ -[car] - motorway = 110 - motorway_link = 90 - trunk = 90 - trunk_link = 70 - primary = 70 - primary_link = 60 - secondary = 60 - secondary_link = 50 - tertiary = 55 - unclassified = 25 - residential = 40 - living_street = 10 - service = 30 - ferry = 5 - pier = 5 - obeyBollards = yes - obeyOneways = yes - useRestrictions = yes - accessTag = motorcar - excludeFromGrid = ferry - defaultSpeed = 50 - trafficLightPenalty = 15 -[bike] - trunk = 16 - trunk_link = 16 - primary = 16 - primary_link = 16 - secondary = 16 - secondary_link = 16 - tertiary = 16 - unclassified = 16 - residential = 16 - living_street = 16 - service = 16 - track = 16 - cycleway = 16 - path = 16 - ferry = 5 - pier = 5 - obeyOneways = yes - useRestrictions = no - accessTag = bicycle - excludeFromGrid = ferry - defaultSpeed = 5 - trafficLightPenalty = 15 - obeyBollards = no - \ No newline at end of file diff --git a/test/contractor.ini b/test/contractor.ini new file mode 100644 index 000000000..fa39ddf73 --- /dev/null +++ b/test/contractor.ini @@ -0,0 +1,2 @@ +Threads = 4 +SRTM = data/srtm/Eurasia \ No newline at end of file diff --git a/test/data/kbh.osm.pbf b/test/data/kbh.osm.pbf new file mode 100644 index 000000000..e00a5c3e2 Binary files /dev/null and b/test/data/kbh.osm.pbf differ diff --git a/test/extractor.ini b/test/extractor.ini new file mode 100644 index 000000000..aa6ba2e30 --- /dev/null +++ b/test/extractor.ini @@ -0,0 +1 @@ +Memory = 1 \ No newline at end of file diff --git a/test/server.ini b/test/server.ini new file mode 100644 index 000000000..b43aa11a5 --- /dev/null +++ b/test/server.ini @@ -0,0 +1,9 @@ +Threads = 8 +IP = 0.0.0.0 +Port = 5000 + +hsgrData=data/test.osrm.hsgr +nodesData=data/test.osrm.nodes +ramIndex=data/test.osrm.ramIndex +fileIndex=data/test.osrm.fileIndex +namesData=data/test.osrm.names diff --git a/test/speedprofiles/bicycle.ini b/test/speedprofiles/bicycle.ini new file mode 100644 index 000000000..c6f12cec8 --- /dev/null +++ b/test/speedprofiles/bicycle.ini @@ -0,0 +1,28 @@ +[bicycle] + cycleway = 19 + trunk = 19 + trunk_link = 19 + primary = 19 + primary_link = 19 + secondary = 17 + secondary_link = 17 + tertiary = 15 + residential = 15 + unclassified = 15 + living_street = 13 + service = 12 + track = 12 + path = 12 + footway = 10 + pedestrian = 5 + pier = 5 + steps = 3 + ferry = 5 + obeyOneways = yes + useRestrictions = yes + accessTag = bicycle + excludeFromGrid = ferry + defaultSpeed = 17 + obeyBollards = no + trafficLightPenalty = 20 + diff --git a/test/speedprofiles/car.ini b/test/speedprofiles/car.ini new file mode 100644 index 000000000..e72baf75b --- /dev/null +++ b/test/speedprofiles/car.ini @@ -0,0 +1,22 @@ +[car] + motorway = 110 + motorway_link = 90 + trunk = 90 + trunk_link = 70 + primary = 70 + primary_link = 60 + secondary = 60 + secondary_link = 50 + tertiary = 55 + unclassified = 25 + residential = 40 + living_street = 10 + service = 30 + ferry = 5 + pier = 5 + barrier = bollard + obeyOneways = yes + useRestrictions = yes + accessTag = motorcar + excludeFromGrid = ferry + defaultSpeed = 50 \ No newline at end of file diff --git a/test/speedprofiles/default.ini b/test/speedprofiles/default.ini new file mode 100644 index 000000000..a7db8683f --- /dev/null +++ b/test/speedprofiles/default.ini @@ -0,0 +1,20 @@ +[default] + accessTag = motorcar + defaultSpeed = 50 + + barrier = bollard + + motorway = 110 + motorway_link = 90 + trunk = 90 + trunk_link = 70 + primary = 70 + primary_link = 60 + secondary = 60 + secondary_link = 50 + tertiary = 40 + residential = 30 + living_street = 25 + service = 25 + unclassified = 25 + \ No newline at end of file diff --git a/test/speedprofiles/ebike.ini b/test/speedprofiles/ebike.ini new file mode 100644 index 000000000..0ec406061 --- /dev/null +++ b/test/speedprofiles/ebike.ini @@ -0,0 +1,25 @@ +[ebike] + cycleway = 25 + trunk = 25 + trunk_link = 25 + primary = 25 + primary_link = 25 + secondary = 25 + secondary_link = 25 + tertiary = 25 + unclassified = 25 + residential = 25 + living_street = 20 + service = 20 + track = 20 + path = 15 + ferry = 5 + pier = 5 + pedestrian = 5 + footway = 5 + steps = 3 + obeyOneways = yes + useRestrictions = no + accessTag = bicycle + excludeFromGrid = ferry + defaultSpeed = 25