diff --git a/.gitignore b/.gitignore index 37b6140ca..1de40a583 100644 --- a/.gitignore +++ b/.gitignore @@ -77,6 +77,7 @@ stxxl.errlog /osrm-routed /osrm-datastore /osrm-prepare +/osrm-unlock-all /osrm-cli /nohup.out diff --git a/.travis.yml b/.travis.yml index af602bdd4..2146f557e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,21 +5,32 @@ compiler: # Make sure CMake is installed install: - sudo apt-get update >/dev/null - - sudo apt-get -q install libprotoc-dev libprotobuf7 protobuf-compiler libprotobuf-dev libosmpbf-dev libpng12-dev libbz2-dev libstxxl-dev libstxxl-doc libstxxl1 libxml2-dev libzip-dev libboost1.46-all-dev lua5.1 liblua5.1-0-dev libluabind-dev rubygems osmosis + - sudo apt-get -q install libprotoc-dev libprotobuf7 libprotobuf-dev libosmpbf-dev libbz2-dev libstxxl-dev libstxxl1 libxml2-dev libzip-dev libboost1.46-all-dev lua5.1 liblua5.1-0-dev libluabind-dev rubygems + - curl -s https://gist.githubusercontent.com/DennisOSRM/803a64a9178ec375069f/raw/ | sudo bash before_script: - - sudo gem install bundler + - rvm use 1.9.3 + - gem install bundler - bundle install - mkdir build - cd build - cmake .. $CMAKEOPTIONS -script: make +script: + - make -j 2 + - cd .. + - cucumber -p verify +after_script: +# - cd .. +# - cucumber -p verify branches: only: - master - develop +cache: +- bundler +- apt env: - - CMAKEOPTIONS="-DCMAKE_BUILD_TYPE=Release" - - CMAKEOPTIONS="-DCMAKE_BUILD_TYPE=Debug" + - CMAKEOPTIONS="-DCMAKE_BUILD_TYPE=Release" OSRM_PORT=5000 OSRM_TIMEOUT=60 + - CMAKEOPTIONS="-DCMAKE_BUILD_TYPE=Debug" OSRM_PORT=5010 OSRM_TIMEOUT=60 notifications: irc: channels: diff --git a/Algorithms/DouglasePeucker.cpp b/Algorithms/DouglasPeucker.cpp similarity index 61% rename from Algorithms/DouglasePeucker.cpp rename to Algorithms/DouglasPeucker.cpp index 8baaf8a24..a45484e2b 100644 --- a/Algorithms/DouglasePeucker.cpp +++ b/Algorithms/DouglasPeucker.cpp @@ -26,60 +26,92 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "DouglasPeucker.h" +#include "../DataStructures/SegmentInformation.h" +#include "../Util/MercatorUtil.h" + +#include //These thresholds are more or less heuristically chosen. static double DouglasPeuckerThresholds[19] = { - 32000000., //z0 - 16240000., //z1 - 8240000., //z2 - 4240000., //z3 - 2000000., //z4 - 1000000., //z5 - 500000., //z6 - 240000., //z7 - 120000., //z8 - 60000., //z9 - 30000., //z10 - 19000., //z11 - 5000., //z12 - 2000., //z13 - 200., //z14 - 16., //z15 - 6., //z16 - 3., //z17 - 3. //z18 + 262144., //z0 + 131072., //z1 + 65536., //z2 + 32768., //z3 + 16384., //z4 + 8192., //z5 + 4096., //z6 + 2048., //z7 + 960., //z8 + 480., //z9 + 240., //z10 + 90., //z11 + 50., //z12 + 25., //z13 + 15., //z14 + 5., //z15 + .65, //z16 + .5, //z17 + .35 //z18 }; /** - * This distance computation does integer arithmetic only and is about twice as - * fast as the other distance function. It is an approximation only, but works - * more or less ok. + * Yuck! Code duplication. This function is also in EgdeBasedNode.h */ -int DouglasPeucker::fastDistance( +double DouglasPeucker::ComputeDistance( const FixedPointCoordinate& point, const FixedPointCoordinate& segA, const FixedPointCoordinate& segB ) const { - const int p2x = (segB.lon - segA.lon); - const int p2y = (segB.lat - segA.lat); - const int something = p2x*p2x + p2y*p2y; - double u = ( 0 == something ? 0 : ((point.lon - segA.lon) * p2x + (point.lat - segA.lat) * p2y) / something); + const double x = lat2y(point.lat/COORDINATE_PRECISION); + const double y = point.lon/COORDINATE_PRECISION; + const double a = lat2y(segA.lat/COORDINATE_PRECISION); + const double b = segA.lon/COORDINATE_PRECISION; + const double c = lat2y(segB.lat/COORDINATE_PRECISION); + const double d = segB.lon/COORDINATE_PRECISION; + double p,q,nY; + if( std::abs(a-c) > std::numeric_limits::epsilon() ){ + const double m = (d-b)/(c-a); // slope + // Projection of (x,y) on line joining (a,b) and (c,d) + p = ((x + (m*y)) + (m*m*a - m*b))/(1. + m*m); + q = b + m*(p - a); + } else { + p = c; + q = y; + } + nY = (d*p - c*q)/(a*d - b*c); - if (u > 1) { - u = 1; - } else if (u < 0) { - u = 0; + //discretize the result to coordinate precision. it's a hack! + if( std::abs(nY) < (1./COORDINATE_PRECISION) ) { + nY = 0.; } - const int x = segA.lon + u * p2x; - const int y = segA.lat + u * p2y; - - const int dx = x - point.lon; - const int dy = y - point.lat; - - const int dist = (dx*dx + dy*dy); - - return dist; + double r = (p - nY*a)/c; + if( std::isnan(r) ) { + r = ((segB.lat == point.lat) && (segB.lon == point.lon)) ? 1. : 0.; + } else if( std::abs(r) <= std::numeric_limits::epsilon() ) { + r = 0.; + } else if( std::abs(r-1.) <= std::numeric_limits::epsilon() ) { + r = 1.; + } + FixedPointCoordinate nearest_location; + BOOST_ASSERT( !std::isnan(r) ); + if( r <= 0. ){ + nearest_location.lat = segA.lat; + nearest_location.lon = segA.lon; + } else if( r >= 1. ){ + nearest_location.lat = segB.lat; + nearest_location.lon = segB.lon; + } else { // point lies in between + nearest_location.lat = y2lat(p)*COORDINATE_PRECISION; + nearest_location.lon = q*COORDINATE_PRECISION; + } + BOOST_ASSERT( nearest_location.isValid() ); + const double approximated_distance = FixedPointCoordinate::ApproximateEuclideanDistance( + point, + nearest_location + ); + BOOST_ASSERT( 0. <= approximated_distance ); + return approximated_distance; } void DouglasPeucker::Run( @@ -91,7 +123,7 @@ void DouglasPeucker::Run( BOOST_ASSERT_MSG(1 < input_geometry.size(), "geometry invalid"); std::size_t left_border = 0; std::size_t right_border = 1; - //Sweep linerarily over array and identify those ranges that need to be checked + //Sweep over array and identify those ranges that need to be checked do { BOOST_ASSERT_MSG( input_geometry[left_border].necessary, @@ -109,7 +141,7 @@ void DouglasPeucker::Run( ++right_border; } while( right_border < input_geometry.size()); } - while(!recursion_stack.empty()) { + while( !recursion_stack.empty() ) { //pop next element const PairOfPoints pair = recursion_stack.top(); recursion_stack.pop(); @@ -129,17 +161,17 @@ void DouglasPeucker::Run( pair.first < pair.second, "left border on the wrong side" ); - int max_distance = INT_MIN; + double max_distance = std::numeric_limits::min(); std::size_t farthest_element_index = pair.second; //find index idx of element with max_distance for(std::size_t i = pair.first+1; i < pair.second; ++i){ - const int temp_dist = fastDistance( + const int temp_dist = ComputeDistance( input_geometry[i].location, input_geometry[pair.first].location, input_geometry[pair.second].location ); - const double distance = std::fabs(temp_dist); + const double distance = std::abs(temp_dist); if( distance > DouglasPeuckerThresholds[zoom_level] && distance > max_distance diff --git a/Algorithms/DouglasPeucker.h b/Algorithms/DouglasPeucker.h index a26036bb5..6f7ecb0e4 100644 --- a/Algorithms/DouglasPeucker.h +++ b/Algorithms/DouglasPeucker.h @@ -28,10 +28,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef DOUGLASPEUCKER_H_ #define DOUGLASPEUCKER_H_ -#include "../DataStructures/Coordinate.h" -#include "../DataStructures/SegmentInformation.h" +#include "../Util/SimpleLogger.h" + +#include #include +#include #include @@ -39,30 +41,31 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -/*This class object computes the bitvector of indicating generalized input points - * according to the (Ramer-)Douglas-Peucker algorithm. +/* This class object computes the bitvector of indicating generalized input + * points according to the (Ramer-)Douglas-Peucker algorithm. * - * Input is vector of pairs. Each pair consists of the point information and a bit - * indicating if the points is present in the generalization. + * Input is vector of pairs. Each pair consists of the point information and a + * bit indicating if the points is present in the generalization. * Note: points may also be pre-selected*/ +struct SegmentInformation; + class DouglasPeucker { private: typedef std::pair PairOfPoints; //Stack to simulate the recursion - std::stack recursion_stack; + std::stack recursion_stack; - /** - * This distance computation does integer arithmetic only and is about twice as fast as - * the other distance function. It is an approximation only, but works more or less ok. - */ - int fastDistance( + double ComputeDistance( const FixedPointCoordinate& point, const FixedPointCoordinate& segA, const FixedPointCoordinate& segB ) const; public: - void Run(std::vector & input_geometry, const unsigned zoom_level); + void Run( + std::vector & input_geometry, + const unsigned zoom_level + ); }; diff --git a/Algorithms/IteratorBasedCRC32.h b/Algorithms/IteratorBasedCRC32.h index 4f012b06b..f85b70532 100644 --- a/Algorithms/IteratorBasedCRC32.h +++ b/Algorithms/IteratorBasedCRC32.h @@ -25,32 +25,55 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ITERATORBASEDCRC32_H_ -#define ITERATORBASEDCRC32_H_ +#ifndef ITERATOR_BASED_CRC32_H +#define ITERATOR_BASED_CRC32_H #include "../Util/SimpleLogger.h" -#include // for boost::crc_32_type #include +#if defined(__x86_64__) + #include +#else + #include // for boost::crc_32_type + + inline void __get_cpuid( + int param, + unsigned *eax, + unsigned *ebx, + unsigned *ecx, + unsigned *edx + ) { *ecx = 0; } +#endif + template class IteratorbasedCRC32 { private: - typedef typename ContainerT::iterator ContainerT_iterator; + typedef typename ContainerT::iterator IteratorType; unsigned crc; - typedef boost::crc_optimal<32, 0x1EDC6F41, 0x0, 0x0, true, true> my_crc_32_type; - typedef unsigned (IteratorbasedCRC32::*CRC32CFunctionPtr)(char *str, unsigned len, unsigned crc); + bool use_SSE42_CRC_function; - unsigned SoftwareBasedCRC32(char *str, unsigned len, unsigned ){ - boost::crc_optimal<32, 0x1EDC6F41, 0x0, 0x0, true, true> CRC32_Processor; - CRC32_Processor.process_bytes( str, len); - return CRC32_Processor.checksum(); +#if !defined(__x86_64__) + boost::crc_optimal<32, 0x1EDC6F41, 0x0, 0x0, true, true> CRC32_processor; +#endif + unsigned SoftwareBasedCRC32( char *str, unsigned len ) + { +#if !defined(__x86_64__) + CRC32_processor.process_bytes( str, len); + return CRC32_processor.checksum(); +#else + return 0; +#endif } - unsigned SSEBasedCRC32( char *str, unsigned len, unsigned crc){ - unsigned q=len/sizeof(unsigned), - r=len%sizeof(unsigned), - *p=(unsigned*)str/*, crc*/; + + // adapted from http://byteworm.com/2010/10/13/crc32/ + unsigned SSE42BasedCRC32( char *str, unsigned len ) + { +#if defined(__x86_64__) + unsigned q = len/sizeof(unsigned); + unsigned r = len%sizeof(unsigned); + unsigned *p = (unsigned*)str; //crc=0; while (q--) { @@ -71,47 +94,55 @@ private: ); ++str; } +#endif return crc; } - unsigned cpuid(unsigned functionInput){ - unsigned eax; - unsigned ebx; - unsigned ecx; - unsigned edx; - asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (functionInput)); + inline unsigned cpuid() const + { + unsigned eax = 0, ebx = 0, ecx = 0, edx = 0; + // on X64 this calls hardware cpuid(.) instr. otherwise a dummy impl. + __get_cpuid( 1, &eax, &ebx, &ecx, &edx ); return ecx; } - CRC32CFunctionPtr detectBestCRC32C(){ - static const int SSE42_BIT = 20; - unsigned ecx = cpuid(1); - bool hasSSE42 = ecx & (1 << SSE42_BIT); - if (hasSSE42) { + bool DetectNativeCRC32Support() + { + static const int SSE42_BIT = 0x00100000; + const unsigned ecx = cpuid(); + const bool has_SSE42 = ecx & SSE42_BIT; + if (has_SSE42) { SimpleLogger().Write() << "using hardware based CRC32 computation"; - return &IteratorbasedCRC32::SSEBasedCRC32; //crc32 hardware accelarated; } else { SimpleLogger().Write() << "using software based CRC32 computation"; - return &IteratorbasedCRC32::SoftwareBasedCRC32; //crc32cSlicingBy8; } + return has_SSE42; } - CRC32CFunctionPtr crcFunction; + public: - IteratorbasedCRC32(): crc(0) { - crcFunction = detectBestCRC32C(); + IteratorbasedCRC32() : crc(0) + { + use_SSE42_CRC_function = DetectNativeCRC32Support(); } - virtual ~IteratorbasedCRC32() { } - - unsigned operator()( ContainerT_iterator iter, const ContainerT_iterator end) { + unsigned operator()( IteratorType iter, const IteratorType end ) + { unsigned crc = 0; while(iter != end) { char * data = reinterpret_cast(&(*iter) ); - crc =((*this).*(crcFunction))(data, sizeof(typename ContainerT::value_type*), crc); + + if (use_SSE42_CRC_function) + { + crc = SSE42BasedCRC32( data, sizeof(typename ContainerT::value_type) ); + } + else + { + crc = SoftwareBasedCRC32( data, sizeof(typename ContainerT::value_type) ); + } ++iter; } return crc; } }; -#endif /* ITERATORBASEDCRC32_H_ */ +#endif /* ITERATOR_BASED_CRC32_H */ diff --git a/Algorithms/PolylineCompressor.cpp b/Algorithms/PolylineCompressor.cpp index 4d3609d99..acab45656 100644 --- a/Algorithms/PolylineCompressor.cpp +++ b/Algorithms/PolylineCompressor.cpp @@ -108,10 +108,10 @@ void PolylineCompressor::printUnencodedString( output += "["; std::string tmp; for(unsigned i = 0; i < polyline.size(); i++) { - convertInternalLatLonToString(polyline[i].lat, tmp); + FixedPointCoordinate::convertInternalLatLonToString(polyline[i].lat, tmp); output += "["; output += tmp; - convertInternalLatLonToString(polyline[i].lon, tmp); + FixedPointCoordinate::convertInternalLatLonToString(polyline[i].lon, tmp); output += ", "; output += tmp; output += "]"; @@ -132,10 +132,10 @@ void PolylineCompressor::printUnencodedString( if(!polyline[i].necessary) { continue; } - convertInternalLatLonToString(polyline[i].location.lat, tmp); + FixedPointCoordinate::convertInternalLatLonToString(polyline[i].location.lat, tmp); output += "["; output += tmp; - convertInternalLatLonToString(polyline[i].location.lon, tmp); + FixedPointCoordinate::convertInternalLatLonToString(polyline[i].location.lon, tmp); output += ", "; output += tmp; output += "]"; diff --git a/Algorithms/StronglyConnectedComponents.h b/Algorithms/StronglyConnectedComponents.h index d3a1b3cd7..e0245ef38 100644 --- a/Algorithms/StronglyConnectedComponents.h +++ b/Algorithms/StronglyConnectedComponents.h @@ -28,7 +28,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef STRONGLYCONNECTEDCOMPONENTS_H_ #define STRONGLYCONNECTEDCOMPONENTS_H_ -#include "../DataStructures/Coordinate.h" #include "../DataStructures/DeallocatingVector.h" #include "../DataStructures/DynamicGraph.h" #include "../DataStructures/ImportEdge.h" @@ -39,6 +38,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "../Util/SimpleLogger.h" +#include + #include #include #include @@ -385,7 +386,7 @@ public: } const TarjanDynamicGraph::NodeIterator v = m_node_based_graph->GetTarget(e1); - total_network_distance += 100*ApproximateDistance( + total_network_distance += 100*FixedPointCoordinate::ApproximateDistance( m_coordinate_list[u].lat, m_coordinate_list[u].lon, m_coordinate_list[v].lat, diff --git a/CMakeLists.txt b/CMakeLists.txt index af8258d5c..e033134a6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,58 +1,73 @@ cmake_minimum_required(VERSION 2.6) project(OSRM) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +include(CheckCXXCompilerFlag) include(FindPackageHandleStandardArgs) list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") include(GetGitRevisionDescription) git_describe(GIT_DESCRIPTION) -TRY_RUN(SHARED_LIBRARY_PATH_TYPE SHARED_LIBRARY_PATH_INFO_COMPILED ${PROJECT_BINARY_DIR}/CMakeTmp ${PROJECT_SOURCE_DIR}/cmake/size.cpp OUTPUT_VARIABLE IS_64_SYSTEM) -if(IS_64_SYSTEM) - message(STATUS "System supports 64 bits.") - set( HAS64BITS 1 ) -else(IS_64_SYSTEM) - MESSAGE(WARNING "Compiling on a 32 bit system is unsupported!") - set( HAS64BITS 0 ) -endif(IS_64_SYSTEM) - set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) +set(bitness 32) +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(bitness 64) + message(STATUS "Building on a 64 bit system") +else() + message(WARNING "Building on a 32 bit system is unsupported") +endif() + +include_directories(${CMAKE_SOURCE_DIR}/Include/) + add_custom_command(OUTPUT ${CMAKE_SOURCE_DIR}/Util/UUID.cpp UUID.cpp.alwaysbuild COMMAND ${CMAKE_COMMAND} -DSOURCE_DIR=${CMAKE_SOURCE_DIR} -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/UUID-Config.cmake DEPENDS ${CMAKE_SOURCE_DIR}/Util/UUID.cpp.in - ${CMAKE_SOURCE_DIR}/cmake/UUID-Config.cmake + ${CMAKE_SOURCE_DIR}/cmake/UUID-Config.cmake COMMENT "Configuring UUID.cpp" VERBATIM) -add_custom_target(UUIDConfigure DEPENDS ${CMAKE_SOURCE_DIR}/Util/UUID.cpp ) +add_custom_target(UUIDConfigure DEPENDS ${CMAKE_SOURCE_DIR}/Util/UUID.cpp) -set(BOOST_COMPONENTS filesystem iostreams program_options regex system thread) +set(BOOST_COMPONENTS date_time filesystem iostreams program_options regex system thread) -configure_file(Util/GitDescription.cpp.in ${CMAKE_SOURCE_DIR}/Util/GitDescription.cpp) +configure_file( + ${CMAKE_SOURCE_DIR}/Util/GitDescription.cpp.in + ${CMAKE_SOURCE_DIR}/Util/GitDescription.cpp +) file(GLOB ExtractorGlob Extractor/*.cpp) set(ExtractorSources extractor.cpp ${ExtractorGlob}) -add_executable(osrm-extract ${ExtractorSources} ) +add_executable(osrm-extract ${ExtractorSources}) -file( GLOB PrepareGlob Contractor/*.cpp ) -set( PrepareSources prepare.cpp ${PrepareGlob} ) -add_executable( osrm-prepare ${PrepareSources} ) +file(GLOB PrepareGlob Contractor/*.cpp DataStructures/HilbertValue.cpp) +set(PrepareSources prepare.cpp ${PrepareGlob}) +add_executable(osrm-prepare ${PrepareSources}) file(GLOB ServerGlob Server/*.cpp) file(GLOB DescriptorGlob Descriptors/*.cpp) -file(GLOB DatastructureGlob DataStructures/*.cpp) +file(GLOB DatastructureGlob DataStructures/SearchEngineData.cpp) +file(GLOB CoordinateGlob DataStructures/Coordinate.cpp) file(GLOB AlgorithmGlob Algorithms/*.cpp) file(GLOB HttpGlob Server/Http/*.cpp) file(GLOB LibOSRMGlob Library/*.cpp) -set(OSRMSources ${LibOSRMGlob} ${DescriptorGlob} ${DatastructureGlob} ${AlgorithmGlob} ${HttpGlob}) -add_library( OSRM SHARED ${OSRMSources} ) -add_library( UUID STATIC Util/UUID.cpp ) -add_library( GITDESCRIPTION STATIC Util/GitDescription.cpp ) -add_dependencies( UUID UUIDConfigure ) -add_dependencies( GITDESCRIPTION GIT_DESCRIPTION ) +set( + OSRMSources + ${LibOSRMGlob} + ${DescriptorGlob} + ${DatastructureGlob} + ${CoordinateGlob} + ${AlgorithmGlob} + ${HttpGlob} +) +add_library(COORDLIB STATIC ${CoordinateGlob}) +add_library(OSRM ${OSRMSources} Util/GitDescription.cpp Util/UUID.cpp) +add_library(UUID STATIC Util/UUID.cpp) +add_library(GITDESCRIPTION STATIC Util/GitDescription.cpp) +add_dependencies(UUID UUIDConfigure) +add_dependencies(GITDESCRIPTION GIT_DESCRIPTION) add_executable(osrm-routed routed.cpp ${ServerGlob}) set_target_properties(osrm-routed PROPERTIES COMPILE_FLAGS -DROUTED) @@ -60,148 +75,195 @@ add_executable(osrm-datastore datastore.cpp) # Check the release mode if(NOT CMAKE_BUILD_TYPE MATCHES Debug) - set(CMAKE_BUILD_TYPE Release) -endif(NOT CMAKE_BUILD_TYPE MATCHES Debug) + set(CMAKE_BUILD_TYPE Release) +endif() if(CMAKE_BUILD_TYPE MATCHES Debug) - message(STATUS "Configuring OSRM in debug mode") -endif(CMAKE_BUILD_TYPE MATCHES Debug) + message(STATUS "Configuring OSRM in debug mode") + if(NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + message(STATUS "adding profiling flags") + set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage -fno-inline") + set(CMAKE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage -fno-inline") + endif() +endif() if(CMAKE_BUILD_TYPE MATCHES Release) message(STATUS "Configuring OSRM in release mode") -endif(CMAKE_BUILD_TYPE MATCHES Release) - -# set compile switches -if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") - # not using Visual Studio C++ - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fPIC") - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fPIC") endif() # Configuring compilers -if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") - # using Clang - set(CMAKE_CXX_FLAGS "-Wall -Wno-unknown-pragmas -Wno-unneeded-internal-declaration") - message(STATUS "OpenMP parallelization not available using clang++") -elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") - # using GCC - set(CMAKE_CXX_FLAGS "-Wall -fopenmp -pedantic") -elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel") - # using Intel C++ - set(CMAKE_CXX_FLAGS "-static-intel -wd10237 -Wall -openmp -ipo") -elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") - # using Visual Studio C++ +if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + # using Clang + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-unknown-pragmas -Wno-unneeded-internal-declaration -pedantic -fPIC") + message(STATUS "OpenMP parallelization not available using clang++") +elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + # using GCC + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fopenmp -pedantic -fPIC") +elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel") + # using Intel C++ + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-intel -wd10237 -Wall -openmp -ipo -fPIC") +elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + # using Visual Studio C++ endif() +# Check if LTO is available +set(LTO_FLAGS "") +CHECK_CXX_COMPILER_FLAG("-flto" HAS_LTO_FLAG) +if (HAS_LTO_FLAG) + set(LTO_FLAGS "${LTO_FLAGS} -flto") +endif (HAS_LTO_FLAG) + +# disable partitioning of LTO process when possible (fixes Debian issues) +set(LTO_PARTITION_FLAGS "") +CHECK_CXX_COMPILER_FLAG("-flto-partition=none" HAS_LTO_PARTITION_FLAG) +if (HAS_LTO_PARTITION_FLAG) + set(LTO_PARTITION_FLAGS "${LTO_PARTITION_FLAGS} -flto-partition=none") +endif (HAS_LTO_PARTITION_FLAG) + +# Add Link-Time-Optimization flags, if supported (GCC >= 4.5) and enabled +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LTO_FLAGS}") +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LTO_FLAGS} ${LTO_PARTITION_FLAGS}") +set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LTO_FLAGS} ${LTO_PARTITION_FLAGS}") + # Configuring other platform dependencies if(APPLE) - SET(CMAKE_OSX_ARCHITECTURES "x86_64") - message(STATUS "Set Architecture to x64 on OS X") - EXEC_PROGRAM(uname ARGS -v OUTPUT_VARIABLE DARWIN_VERSION) - STRING(REGEX MATCH "[0-9]+" DARWIN_VERSION ${DARWIN_VERSION}) - IF (DARWIN_VERSION GREATER 12) - MESSAGE(STATUS "Activating -std=c++11 flag for >= OS X 10.9") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -stdlib=libc++") - ENDIF (DARWIN_VERSION GREATER 12) + set(CMAKE_OSX_ARCHITECTURES "x86_64") + message(STATUS "Set Architecture to x64 on OS X") + exec_program(uname ARGS -v OUTPUT_VARIABLE DARWIN_VERSION) + string(REGEX MATCH "[0-9]+" DARWIN_VERSION ${DARWIN_VERSION}) + if(DARWIN_VERSION GREATER 12 AND NOT OSXLIBSTD) + message(STATUS "Activating -std=c++11 flag for >= OS X 10.9") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + endif() + if(OSXLIBSTD) + message(STATUS "linking against ${OSXLIBSTD}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=${OSXLIBSTD}") + elseif(DARWIN_VERSION GREATER 12) + message(STATUS "linking against libc++") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") + endif() endif() if(UNIX AND NOT APPLE) - target_link_libraries( osrm-datastore rt ) - target_link_libraries( OSRM rt ) -endif(UNIX AND NOT APPLE) + target_link_libraries(osrm-datastore rt) + target_link_libraries(OSRM rt) +endif() #Check Boost -set(BOOST_MIN_VERSION "1.44.0") -find_package( Boost ${BOOST_MIN_VERSION} COMPONENTS ${BOOST_COMPONENTS} REQUIRED ) -if (NOT Boost_FOUND) - message(FATAL_ERROR "Fatal error: Boost (version >= 1.44.0) required.\n") -endif (NOT Boost_FOUND) +set(BOOST_MIN_VERSION "1.46.0") +find_package(Boost ${BOOST_MIN_VERSION} COMPONENTS ${BOOST_COMPONENTS} REQUIRED) +if(NOT Boost_FOUND) + message(FATAL_ERROR "Fatal error: Boost (version >= 1.46.0) required.\n") +endif() include_directories(${Boost_INCLUDE_DIRS}) -IF( APPLE ) - target_link_libraries( OSRM ${Boost_LIBRARIES} UUID ) -ELSE( APPLE ) - target_link_libraries( OSRM ${Boost_LIBRARIES} ) -ENDIF( APPLE ) -target_link_libraries( osrm-extract ${Boost_LIBRARIES} UUID GITDESCRIPTION ) -target_link_libraries( osrm-prepare ${Boost_LIBRARIES} UUID GITDESCRIPTION ) -target_link_libraries( osrm-routed ${Boost_LIBRARIES} OSRM UUID GITDESCRIPTION ) -target_link_libraries( osrm-datastore ${Boost_LIBRARIES} UUID GITDESCRIPTION ) +target_link_libraries(OSRM ${Boost_LIBRARIES} COORDLIB) +target_link_libraries(osrm-extract ${Boost_LIBRARIES} UUID GITDESCRIPTION COORDLIB) +target_link_libraries(osrm-prepare ${Boost_LIBRARIES} UUID GITDESCRIPTION COORDLIB) +target_link_libraries(osrm-routed ${Boost_LIBRARIES} OSRM UUID GITDESCRIPTION) +target_link_libraries(osrm-datastore ${Boost_LIBRARIES} UUID GITDESCRIPTION COORDLIB) -find_package ( BZip2 REQUIRED ) -include_directories(${BZIP_INCLUDE_DIRS}) -target_link_libraries (osrm-extract ${BZIP2_LIBRARIES}) +find_package(Threads REQUIRED) +target_link_libraries(osrm-extract ${CMAKE_THREAD_LIBS_INIT}) -find_package( ZLIB REQUIRED ) -include_directories(${ZLIB_INCLUDE_DIRS}) -target_link_libraries (osrm-extract ${ZLIB_LIBRARY}) -target_link_libraries (osrm-routed ${ZLIB_LIBRARY}) +find_package(Lua52) +if(NOT LUA52_FOUND) + find_package(Lua51 REQUIRED) + if(NOT APPLE) + find_package(LuaJIT 5.1) + endif() +else() + if(NOT APPLE) + find_package(LuaJIT 5.2) + endif() +endif() -find_package( Threads REQUIRED ) -target_link_libraries (osrm-extract ${Threads_LIBRARY}) - -find_package( Lua52 ) -IF ( NOT LUA52_FOUND ) - find_package( Lua51 REQUIRED ) - IF (NOT APPLE) - find_package( LuaJIT 5.1 ) - ENDIF ( NOT APPLE ) -ELSE( NOT LUA52_FOUND ) - IF(NOT APPLE) - find_package( LuaJIT 5.2 ) - ENDIF(NOT APPLE) -ENDIF( NOT LUA52_FOUND ) - -IF ( LUAJIT_FOUND ) - target_link_libraries( osrm-extract ${LUAJIT_LIBRARIES} ) - target_link_libraries( osrm-prepare ${LUAJIT_LIBRARIES} ) -ELSE () - target_link_libraries( osrm-extract ${LUA_LIBRARY} ) - target_link_libraries( osrm-prepare ${LUA_LIBRARY} ) -ENDIF () +if( LUAJIT_FOUND ) + target_link_libraries(osrm-extract ${LUAJIT_LIBRARIES}) + target_link_libraries(osrm-prepare ${LUAJIT_LIBRARIES}) +else() + target_link_libraries(osrm-extract ${LUA_LIBRARY}) + target_link_libraries(osrm-prepare ${LUA_LIBRARY}) +endif() include_directories(${LUA_INCLUDE_DIR}) - -find_package( LibXml2 REQUIRED ) +find_package(LibXml2 REQUIRED) include_directories(${LIBXML2_INCLUDE_DIR}) -target_link_libraries (osrm-extract ${LIBXML2_LIBRARIES}) +target_link_libraries(osrm-extract ${LIBXML2_LIBRARIES}) find_package( Luabind REQUIRED ) include_directories(${LUABIND_INCLUDE_DIR}) -target_link_libraries (osrm-extract ${LUABIND_LIBRARY}) -target_link_libraries (osrm-prepare ${LUABIND_LIBRARY}) - -find_package( Protobuf REQUIRED ) -include_directories(${PROTOBUF_INCLUDE_DIRS}) -target_link_libraries (osrm-extract ${PROTOBUF_LIBRARY}) -target_link_libraries (osrm-prepare ${PROTOBUF_LIBRARY}) +target_link_libraries(osrm-extract ${LUABIND_LIBRARY}) +target_link_libraries(osrm-prepare ${LUABIND_LIBRARY}) find_package( STXXL REQUIRED ) include_directories(${STXXL_INCLUDE_DIR}) -target_link_libraries (OSRM ${STXXL_LIBRARY}) -target_link_libraries (osrm-extract ${STXXL_LIBRARY}) -target_link_libraries (osrm-prepare ${STXXL_LIBRARY}) +target_link_libraries(OSRM ${STXXL_LIBRARY}) +target_link_libraries(osrm-extract ${STXXL_LIBRARY}) +target_link_libraries(osrm-prepare ${STXXL_LIBRARY}) find_package( OSMPBF REQUIRED ) include_directories(${OSMPBF_INCLUDE_DIR}) -target_link_libraries (osrm-extract ${OSMPBF_LIBRARY}) -target_link_libraries (osrm-prepare ${OSMPBF_LIBRARY}) +target_link_libraries(osrm-extract ${OSMPBF_LIBRARY}) +target_link_libraries(osrm-prepare ${OSMPBF_LIBRARY}) + +find_package(Protobuf REQUIRED) +include_directories(${PROTOBUF_INCLUDE_DIRS}) +target_link_libraries(osrm-extract ${PROTOBUF_LIBRARY}) +target_link_libraries(osrm-prepare ${PROTOBUF_LIBRARY}) + +find_package(BZip2 REQUIRED) +include_directories(${BZIP_INCLUDE_DIRS}) +target_link_libraries(osrm-extract ${BZIP2_LIBRARIES}) + +find_package(ZLIB REQUIRED) +include_directories(${ZLIB_INCLUDE_DIRS}) +target_link_libraries(osrm-extract ${ZLIB_LIBRARY}) +target_link_libraries(osrm-routed ${ZLIB_LIBRARY}) if(WITH_TOOLS) - message(STATUS "Activating OSRM internal tools") - find_package( GDAL ) - if(GDAL_FOUND) - add_executable(osrm-components Tools/componentAnalysis.cpp) - include_directories(${GDAL_INCLUDE_DIR}) - target_link_libraries( - osrm-components ${GDAL_LIBRARIES} ${Boost_LIBRARIES} UUID GITDESCRIPTION - ) - endif(GDAL_FOUND) - add_executable ( osrm-cli Tools/simpleclient.cpp) - target_link_libraries( osrm-cli ${Boost_LIBRARIES} OSRM UUID GITDESCRIPTION ) - add_executable ( osrm-io-benchmark Tools/io-benchmark.cpp ) - target_link_libraries( osrm-io-benchmark ${Boost_LIBRARIES} GITDESCRIPTION) - add_executable ( osrm-unlock-all Tools/unlock_all_mutexes.cpp ) - target_link_libraries( osrm-unlock-all ${Boost_LIBRARIES} GITDESCRIPTION) + message(STATUS "Activating OSRM internal tools") + find_package(GDAL) + if(GDAL_FOUND) + add_executable(osrm-components Tools/componentAnalysis.cpp) + include_directories(${GDAL_INCLUDE_DIR}) + target_link_libraries( + osrm-components + ${GDAL_LIBRARIES} ${Boost_LIBRARIES} UUID GITDESCRIPTION COORDLIB) + endif() + add_executable(osrm-cli Tools/simpleclient.cpp) + target_link_libraries(osrm-cli ${Boost_LIBRARIES} OSRM UUID GITDESCRIPTION) + add_executable(osrm-io-benchmark Tools/io-benchmark.cpp) + target_link_libraries(osrm-io-benchmark ${Boost_LIBRARIES} GITDESCRIPTION) + add_executable(osrm-unlock-all Tools/unlock_all_mutexes.cpp) + target_link_libraries(osrm-unlock-all ${Boost_LIBRARIES} GITDESCRIPTION) if(UNIX AND NOT APPLE) - target_link_libraries( osrm-unlock-all rt ) - endif(UNIX AND NOT APPLE) -endif(WITH_TOOLS) + target_link_libraries(osrm-unlock-all rt) + endif() +endif() + +file(GLOB InstallGlob Include/osrm/*.h Library/OSRM.h) + +# Add RPATH info to executables so that when they are run after being installed +# (i.e., from /usr/local/bin/) the linker can find library dependencies. For +# more info see http://www.cmake.org/Wiki/CMake_RPATH_handling +set_property(TARGET osrm-extract PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE) +set_property(TARGET osrm-prepare PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE) +set_property(TARGET osrm-datastore PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE) +set_property(TARGET osrm-routed PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE) + +install(FILES ${InstallGlob} DESTINATION include/osrm) +install(TARGETS osrm-extract DESTINATION bin) +install(TARGETS osrm-prepare DESTINATION bin) +install(TARGETS osrm-datastore DESTINATION bin) +install(TARGETS osrm-routed DESTINATION bin) +install(TARGETS OSRM DESTINATION lib) +list(GET Boost_LIBRARIES 1 BOOST_LIBRARY_FIRST) +get_filename_component(BOOST_LIBRARY_LISTING "${BOOST_LIBRARY_FIRST}" PATH) +set(BOOST_LIBRARY_LISTING "-L${BOOST_LIBRARY_LISTING}") +foreach (lib ${Boost_LIBRARIES}) + get_filename_component(BOOST_LIBRARY_NAME "${lib}" NAME_WE) + string(REPLACE "lib" "" BOOST_LIBRARY_NAME ${BOOST_LIBRARY_NAME}) + set(BOOST_LIBRARY_LISTING "${BOOST_LIBRARY_LISTING} -l${BOOST_LIBRARY_NAME}") +endforeach () + +configure_file(${CMAKE_SOURCE_DIR}/cmake/pkgconfig.in libosrm.pc @ONLY) +install(FILES ${PROJECT_BINARY_DIR}/libosrm.pc DESTINATION lib/pkgconfig) diff --git a/Contractor/Contractor.h b/Contractor/Contractor.h index 976cd9124..357f05b6d 100644 --- a/Contractor/Contractor.h +++ b/Contractor/Contractor.h @@ -45,8 +45,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -#include - #include #include #include @@ -54,10 +52,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. class Contractor { private: - struct _ContractorEdgeData { - _ContractorEdgeData() : + struct ContractorEdgeData { + ContractorEdgeData() : distance(0), id(0), originalEdges(0), shortcut(0), forward(0), backward(0), originalViaNodeID(false) {} - _ContractorEdgeData( unsigned _distance, unsigned _originalEdges, unsigned _id, bool _shortcut, bool _forward, bool _backward) : + ContractorEdgeData( unsigned _distance, unsigned _originalEdges, unsigned _id, bool _shortcut, bool _forward, bool _backward) : distance(_distance), id(_id), originalEdges(std::min((unsigned)1<<28, _originalEdges) ), shortcut(_shortcut), forward(_forward), backward(_backward), originalViaNodeID(false) {} unsigned distance; unsigned id; @@ -75,7 +73,7 @@ private: _HeapData( short h, bool t ) : hop(h), target(t) {} }; - typedef DynamicGraph< _ContractorEdgeData > _DynamicGraph; + typedef DynamicGraph< ContractorEdgeData > _DynamicGraph; // typedef BinaryHeap< NodeID, NodeID, int, _HeapData, ArrayStorage > _Heap; typedef BinaryHeap< NodeID, NodeID, int, _HeapData, XORFastHashStorage > _Heap; typedef _DynamicGraph::InputEdge _ContractorEdge; @@ -118,6 +116,7 @@ public: Contractor( int nodes, ContainerT& inputEdges) { std::vector< _ContractorEdge > edges; edges.reserve(inputEdges.size()*2); + temp_edge_counter = 0; typename ContainerT::deallocation_iterator diter = inputEdges.dbegin(); typename ContainerT::deallocation_iterator dend = inputEdges.dend(); @@ -126,7 +125,7 @@ public: while(diter!=dend) { newEdge.source = diter->source(); newEdge.target = diter->target(); - newEdge.data = _ContractorEdgeData( (std::max)((int)diter->weight(), 1 ), 1, diter->id(), false, diter->isForward(), diter->isBackward()); + newEdge.data = ContractorEdgeData( (std::max)((int)diter->weight(), 1 ), 1, diter->id(), false, diter->isForward(), diter->isBackward()); BOOST_ASSERT_MSG( newEdge.data.distance > 0, "edge distance < 1" ); #ifndef NDEBUG @@ -195,6 +194,7 @@ public: _graph = boost::make_shared<_DynamicGraph>( nodes, edges ); edges.clear(); std::vector<_ContractorEdge>().swap(edges); + BOOST_ASSERT( 0 == edges.capacity() ); // unsigned maxdegree = 0; // NodeID highestNode = 0; // @@ -214,14 +214,14 @@ public: //Create temporary file // GetTemporaryFileName(temporaryEdgeStorageFilename); - temporaryStorageSlotID = TemporaryStorage::GetInstance().allocateSlot(); + edge_storage_slot = TemporaryStorage::GetInstance().AllocateSlot(); std::cout << "contractor finished initalization" << std::endl; } ~Contractor() { //Delete temporary file // remove(temporaryEdgeStorageFilename.c_str()); - TemporaryStorage::GetInstance().deallocateSlot(temporaryStorageSlotID); + TemporaryStorage::GetInstance().DeallocateSlot(edge_storage_slot); } void Run() { @@ -264,11 +264,11 @@ public: std::cout << " [flush " << numberOfContractedNodes << " nodes] " << std::flush; //Delete old heap data to free memory that we need for the coming operations - BOOST_FOREACH(_ThreadData * data, threadData) + BOOST_FOREACH(_ThreadData * data, threadData) { delete data; + } threadData.clear(); - //Create new priority array std::vector newNodePriority(remainingNodes.size()); //this map gives the old IDs from the new ones, necessary to get a consistent graph at the end of contraction @@ -285,12 +285,6 @@ public: remainingNodes[newNodeID].id = newNodeID; } TemporaryStorage & tempStorage = TemporaryStorage::GetInstance(); - //Write dummy number of edges to temporary file - // std::ofstream temporaryEdgeStorage(temporaryEdgeStorageFilename.c_str(), std::ios::binary); - uint64_t initialFilePosition = tempStorage.tell(temporaryStorageSlotID); - unsigned numberOfTemporaryEdges = 0; - tempStorage.writeToSlot(temporaryStorageSlotID, (char*)&numberOfTemporaryEdges, sizeof(unsigned)); - //walk over all nodes for(unsigned i = 0; i < _graph->GetNumberOfNodes(); ++i) { const NodeID start = i; @@ -299,11 +293,11 @@ public: const NodeID target = _graph->GetTarget(currentEdge); if(UINT_MAX == newNodeIDFromOldNodeIDMap[i] ){ //Save edges of this node w/o renumbering. - tempStorage.writeToSlot(temporaryStorageSlotID, (char*)&start, sizeof(NodeID)); - tempStorage.writeToSlot(temporaryStorageSlotID, (char*)&target, sizeof(NodeID)); - tempStorage.writeToSlot(temporaryStorageSlotID, (char*)&data, sizeof(_DynamicGraph::EdgeData)); - ++numberOfTemporaryEdges; - }else { + tempStorage.WriteToSlot(edge_storage_slot, (char*)&start, sizeof(NodeID)); + tempStorage.WriteToSlot(edge_storage_slot, (char*)&target, sizeof(NodeID)); + tempStorage.WriteToSlot(edge_storage_slot, (char*)&data, sizeof(_DynamicGraph::EdgeData)); + ++temp_edge_counter; + } else { //node is not yet contracted. //add (renumbered) outgoing edges to new DynamicGraph. _ContractorEdge newEdge; @@ -323,9 +317,6 @@ public: } } } - //Note the number of temporarily stored edges - tempStorage.seek(temporaryStorageSlotID, initialFilePosition); - tempStorage.writeToSlot(temporaryStorageSlotID, (char*)&numberOfTemporaryEdges, sizeof(unsigned)); //Delete map from old NodeIDs to new ones. std::vector().swap(newNodeIDFromOldNodeIDMap); @@ -394,10 +385,14 @@ public: _DynamicGraph::EdgeIterator currentEdgeID = _graph->FindEdge(edge.source, edge.target); if(currentEdgeID < _graph->EndEdges(edge.source) ) { _DynamicGraph::EdgeData & currentEdgeData = _graph->GetEdgeData(currentEdgeID); - if( currentEdgeData.shortcut - && edge.data.forward == currentEdgeData.forward - && edge.data.backward == currentEdgeData.backward ) { - currentEdgeData.distance = std::min(currentEdgeData.distance, edge.data.distance); + if( currentEdgeData.shortcut && + edge.data.forward == currentEdgeData.forward && + edge.data.backward == currentEdgeData.backward && + edge.data.distance < currentEdgeData.distance + ) { + // found a duplicate edge with smaller weight, update it. + currentEdgeData = edge.data; + // currentEdgeData.distance = std::min(currentEdgeData.distance, edge.data.distance); continue; } } @@ -454,13 +449,13 @@ public: SimpleLogger().Write() << "Getting edges of minimized graph"; NodeID numberOfNodes = _graph->GetNumberOfNodes(); if(_graph->GetNumberOfNodes()) { + Edge newEdge; for ( NodeID node = 0; node < numberOfNodes; ++node ) { p.printStatus(node); for ( _DynamicGraph::EdgeIterator edge = _graph->BeginEdges( node ), endEdges = _graph->EndEdges( node ); edge < endEdges; ++edge ) { const NodeID target = _graph->GetTarget( edge ); const _DynamicGraph::EdgeData& data = _graph->GetEdgeData( edge ); - Edge newEdge; - if(0 != oldNodeIDFromNewNodeIDMap.size()) { + if( !oldNodeIDFromNewNodeIDMap.empty() ) { newEdge.source = oldNodeIDFromNewNodeIDMap[node]; newEdge.target = oldNodeIDFromNewNodeIDMap[target]; } else { @@ -477,7 +472,10 @@ public: ); newEdge.data.distance = data.distance; newEdge.data.shortcut = data.shortcut; - if(!data.originalViaNodeID && oldNodeIDFromNewNodeIDMap.size()) { + if( + !data.originalViaNodeID && + !oldNodeIDFromNewNodeIDMap.empty() + ) { newEdge.data.id = oldNodeIDFromNewNodeIDMap[data.id]; } else { newEdge.data.id = data.id; @@ -494,31 +492,29 @@ public: } _graph.reset(); std::vector().swap(oldNodeIDFromNewNodeIDMap); + BOOST_ASSERT( 0 == oldNodeIDFromNewNodeIDMap.capacity() ); TemporaryStorage & tempStorage = TemporaryStorage::GetInstance(); - //Also get the edges from temporary storage - unsigned numberOfTemporaryEdges = 0; - tempStorage.readFromSlot(temporaryStorageSlotID, (char*)&numberOfTemporaryEdges, sizeof(unsigned)); //loads edges of graph before renumbering, no need for further numbering action. NodeID start; NodeID target; - //edges.reserve(edges.size()+numberOfTemporaryEdges); _DynamicGraph::EdgeData data; - for(unsigned i = 0; i < numberOfTemporaryEdges; ++i) { - tempStorage.readFromSlot(temporaryStorageSlotID, (char*)&start, sizeof(NodeID)); - tempStorage.readFromSlot(temporaryStorageSlotID, (char*)&target, sizeof(NodeID)); - tempStorage.readFromSlot(temporaryStorageSlotID, (char*)&data, sizeof(_DynamicGraph::EdgeData)); - Edge newEdge; - newEdge.source = start; - newEdge.target = target; - newEdge.data.distance = data.distance; - newEdge.data.shortcut = data.shortcut; - newEdge.data.id = data.id; - newEdge.data.forward = data.forward; - newEdge.data.backward = data.backward; - edges.push_back( newEdge ); + + Edge restored_edge; + for(unsigned i = 0; i < temp_edge_counter; ++i) { + tempStorage.ReadFromSlot(edge_storage_slot, (char*)&start, sizeof(NodeID)); + tempStorage.ReadFromSlot(edge_storage_slot, (char*)&target, sizeof(NodeID)); + tempStorage.ReadFromSlot(edge_storage_slot, (char*)&data, sizeof(_DynamicGraph::EdgeData)); + restored_edge.source = start; + restored_edge.target = target; + restored_edge.data.distance = data.distance; + restored_edge.data.shortcut = data.shortcut; + restored_edge.data.id = data.id; + restored_edge.data.forward = data.forward; + restored_edge.data.backward = data.backward; + edges.push_back( restored_edge ); } - tempStorage.deallocateSlot(temporaryStorageSlotID); + tempStorage.DeallocateSlot(edge_storage_slot); } private: @@ -548,7 +544,7 @@ private: //iterate over all edges of node for ( _DynamicGraph::EdgeIterator edge = _graph->BeginEdges( node ), endEdges = _graph->EndEdges( node ); edge != endEdges; ++edge ) { - const _ContractorEdgeData& data = _graph->GetEdgeData( edge ); + const ContractorEdgeData& data = _graph->GetEdgeData( edge ); if ( !data.forward ){ continue; } @@ -594,7 +590,7 @@ private: std::vector< _ContractorEdge >& insertedEdges = data->insertedEdges; for ( _DynamicGraph::EdgeIterator inEdge = _graph->BeginEdges( node ), endInEdges = _graph->EndEdges( node ); inEdge != endInEdges; ++inEdge ) { - const _ContractorEdgeData& inData = _graph->GetEdgeData( inEdge ); + const ContractorEdgeData& inData = _graph->GetEdgeData( inEdge ); const NodeID source = _graph->GetTarget( inEdge ); if ( Simulate ) { assert( stats != NULL ); @@ -610,7 +606,7 @@ private: unsigned numTargets = 0; for ( _DynamicGraph::EdgeIterator outEdge = _graph->BeginEdges( node ), endOutEdges = _graph->EndEdges( node ); outEdge != endOutEdges; ++outEdge ) { - const _ContractorEdgeData& outData = _graph->GetEdgeData( outEdge ); + const ContractorEdgeData& outData = _graph->GetEdgeData( outEdge ); if ( !outData.forward ) { continue; } @@ -629,7 +625,7 @@ private: _Dijkstra( maxDistance, numTargets, 2000, data, node ); } for ( _DynamicGraph::EdgeIterator outEdge = _graph->BeginEdges( node ), endOutEdges = _graph->EndEdges( node ); outEdge != endOutEdges; ++outEdge ) { - const _ContractorEdgeData& outData = _graph->GetEdgeData( outEdge ); + const ContractorEdgeData& outData = _graph->GetEdgeData( outEdge ); if ( !outData.forward ) { continue; } @@ -645,7 +641,7 @@ private: _ContractorEdge newEdge; newEdge.source = source; newEdge.target = target; - newEdge.data = _ContractorEdgeData( pathDistance, outData.originalEdges + inData.originalEdges, node/*, 0, inData.turnInstruction*/, true, true, false);; + newEdge.data = ContractorEdgeData( pathDistance, outData.originalEdges + inData.originalEdges, node/*, 0, inData.turnInstruction*/, true, true, false);; insertedEdges.push_back( newEdge ); std::swap( newEdge.source, newEdge.target ); newEdge.data.forward = false; @@ -738,7 +734,7 @@ private: if ( priority > targetPriority ) return false; //tie breaking - if ( fabs(priority - targetPriority) < std::numeric_limits::epsilon() && bias(node, target) ) { + if ( std::abs(priority - targetPriority) < std::numeric_limits::epsilon() && bias(node, target) ) { return false; } neighbours.push_back( target ); @@ -760,7 +756,7 @@ private: if ( priority > targetPriority) return false; //tie breaking - if ( fabs(priority - targetPriority) < std::numeric_limits::epsilon() && bias(node, target) ) { + if ( std::abs(priority - targetPriority) < std::numeric_limits::epsilon() && bias(node, target) ) { return false; } } @@ -784,7 +780,8 @@ private: boost::shared_ptr<_DynamicGraph> _graph; std::vector<_DynamicGraph::InputEdge> contractedEdges; - unsigned temporaryStorageSlotID; + unsigned edge_storage_slot; + uint64_t temp_edge_counter; std::vector oldNodeIDFromNewNodeIDMap; XORFastHash fastHash; }; diff --git a/Contractor/EdgeBasedGraphFactory.cpp b/Contractor/EdgeBasedGraphFactory.cpp index 32389f1f2..e765c90b4 100644 --- a/Contractor/EdgeBasedGraphFactory.cpp +++ b/Contractor/EdgeBasedGraphFactory.cpp @@ -25,7 +25,21 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + #include "EdgeBasedGraphFactory.h" +#include "../Util/ComputeAngle.h" + +#include +#include +#include + +//TODO: CompressionWorker +//TODO: EdgeBasedEdgeGenerator + +// template +// inline static void TraverseGraph(NodeBasedDynamicGraph & graph, Work & work) { + +// } EdgeBasedGraphFactory::EdgeBasedGraphFactory( int number_of_nodes, @@ -43,7 +57,8 @@ EdgeBasedGraphFactory::EdgeBasedGraphFactory( std::pair restriction_source = std::make_pair(restriction.fromNode, restriction.viaNode); unsigned index; - RestrictionMap::iterator restriction_iter = m_restriction_map.find(restriction_source); + RestrictionMap::iterator restriction_iter; + restriction_iter = m_restriction_map.find(restriction_source); if(restriction_iter == m_restriction_map.end()) { index = m_restriction_bucket_list.size(); m_restriction_bucket_list.resize(index+1); @@ -93,7 +108,7 @@ EdgeBasedGraphFactory::EdgeBasedGraphFactory( continue; } edge.data.distance = (std::max)((int)import_edge.weight(), 1 ); - assert( edge.data.distance > 0 ); + BOOST_ASSERT( edge.data.distance > 0 ); edge.data.shortcut = false; edge.data.roundabout = import_edge.isRoundabout(); edge.data.ignoreInGrid = import_edge.ignoreInGrid(); @@ -131,8 +146,8 @@ void EdgeBasedGraphFactory::GetEdgeBasedEdges( void EdgeBasedGraphFactory::GetEdgeBasedNodes( std::vector & nodes) { #ifndef NDEBUG BOOST_FOREACH(const EdgeBasedNode & node, m_edge_based_node_list){ - assert(node.lat1 != INT_MAX); assert(node.lon1 != INT_MAX); - assert(node.lat2 != INT_MAX); assert(node.lon2 != INT_MAX); + BOOST_ASSERT(node.lat1 != INT_MAX); BOOST_ASSERT(node.lon1 != INT_MAX); + BOOST_ASSERT(node.lat2 != INT_MAX); BOOST_ASSERT(node.lon2 != INT_MAX); } #endif nodes.swap(m_edge_based_node_list); @@ -143,7 +158,8 @@ NodeID EdgeBasedGraphFactory::CheckForEmanatingIsOnlyTurn( const NodeID v ) const { const std::pair < NodeID, NodeID > restriction_source = std::make_pair(u, v); - RestrictionMap::const_iterator restriction_iter = m_restriction_map.find(restriction_source); + RestrictionMap::const_iterator restriction_iter; + restriction_iter = m_restriction_map.find(restriction_source); if (restriction_iter != m_restriction_map.end()) { const unsigned index = restriction_iter->second; BOOST_FOREACH( @@ -165,7 +181,8 @@ bool EdgeBasedGraphFactory::CheckIfTurnIsRestricted( ) const { //only add an edge if turn is not a U-turn except it is the end of dead-end street. const std::pair < NodeID, NodeID > restriction_source = std::make_pair(u, v); - RestrictionMap::const_iterator restriction_iter = m_restriction_map.find(restriction_source); + RestrictionMap::const_iterator restriction_iter; + restriction_iter = m_restriction_map.find(restriction_source); if (restriction_iter != m_restriction_map.end()) { const unsigned index = restriction_iter->second; BOOST_FOREACH( @@ -199,13 +216,34 @@ void EdgeBasedGraphFactory::InsertEdgeBasedNode( m_edge_based_node_list.push_back(currentNode); } + +void EdgeBasedGraphFactory::FlushVectorToStream( + std::ofstream & edge_data_file, + std::vector & original_edge_data_vector +) const { + edge_data_file.write( + (char*)&(original_edge_data_vector[0]), + original_edge_data_vector.size()*sizeof(OriginalEdgeData) + ); + original_edge_data_vector.clear(); +} + void EdgeBasedGraphFactory::Run( const char * original_edge_data_filename, lua_State *lua_state ) { + SimpleLogger().Write() << "Compressing geometry of input graph"; + //TODO: iterate over all turns + + //TODO: compress geometries + + //TODO: update turn restrictions if concerned by compression + + //TODO: do some compression statistics + + SimpleLogger().Write() << "Identifying components of the road network"; - Percent p(m_node_based_graph->GetNumberOfNodes()); unsigned skipped_turns_counter = 0; unsigned node_based_edge_counter = 0; unsigned original_edges_counter = 0; @@ -221,93 +259,21 @@ void EdgeBasedGraphFactory::Run( sizeof(unsigned) ); - unsigned current_component = 0, current_component_size = 0; //Run a BFS on the undirected graph and identify small components - std::queue > bfs_queue; - std::vector component_index_list( - m_node_based_graph->GetNumberOfNodes(), - UINT_MAX - ); + std::vector component_index_list; + std::vector component_index_size; + BFSCompentExplorer( component_index_list, component_index_size); - std::vector component_size_list; - //put unexplorered node with parent pointer into queue - for( - NodeID node = 0, - last_node = m_node_based_graph->GetNumberOfNodes(); - node < last_node; - ++node - ) { - if(UINT_MAX == component_index_list[node]) { - bfs_queue.push(std::make_pair(node, node)); - //mark node as read - component_index_list[node] = current_component; - p.printIncrement(); - while(!bfs_queue.empty()) { - //fetch element from BFS queue - std::pair current_queue_item = bfs_queue.front(); - bfs_queue.pop(); - // SimpleLogger().Write() << "sizeof queue: " << bfs_queue.size() << - // ", current_component_sizes: " << current_component_size << - //", settled nodes: " << settledNodes++ << ", max: " << endNodes; - const NodeID v = current_queue_item.first; //current node - const NodeID u = current_queue_item.second; //parent - //increment size counter of current component - ++current_component_size; - const bool is_barrier_node = (m_barrier_nodes.find(v) != m_barrier_nodes.end()); - if(!is_barrier_node) { - const NodeID to_node_of_only_restriction = CheckForEmanatingIsOnlyTurn(u, v); - - //relaxieren edge outgoing edge like below where edge-expanded graph - for( - EdgeIterator e2 = m_node_based_graph->BeginEdges(v); - e2 < m_node_based_graph->EndEdges(v); - ++e2 - ) { - NodeIterator w = m_node_based_graph->GetTarget(e2); - - if( - to_node_of_only_restriction != UINT_MAX && - w != to_node_of_only_restriction - ) { - //We are at an only_-restriction but not at the right turn. - continue; - } - if( u != w ) { - //only add an edge if turn is not a U-turn except - //when it is at the end of a dead-end street. - if (!CheckIfTurnIsRestricted(u, v, w) ) { - //only add an edge if turn is not prohibited - if(UINT_MAX == component_index_list[w]) { - //insert next (node, parent) only if w has - //not yet been explored - //mark node as read - component_index_list[w] = current_component; - bfs_queue.push(std::make_pair(w,v)); - p.printIncrement(); - } - } - } - } - } - } - //push size into vector - component_size_list.push_back(current_component_size); - //reset counters; - current_component_size = 0; - ++current_component; - } - } SimpleLogger().Write() << - "identified: " << component_size_list.size() << " many components"; + "identified: " << component_index_size.size() << " many components"; SimpleLogger().Write() << "generating edge-expanded nodes"; - p.reinit(m_node_based_graph->GetNumberOfNodes()); + Percent p(m_node_based_graph->GetNumberOfNodes()); //loop over all edges and generate new set of nodes. for( - NodeIterator u = 0, - number_of_nodes = m_node_based_graph->GetNumberOfNodes(); - u < number_of_nodes; + NodeIterator u = 0, end = m_node_based_graph->GetNumberOfNodes(); + u < end; ++u ) { p.printIncrement(); @@ -326,8 +292,8 @@ void EdgeBasedGraphFactory::Run( //Note: edges that end on barrier nodes or on a turn restriction //may actually be in two distinct components. We choose the smallest const unsigned size_of_component = std::min( - component_size_list[component_index_list[u]], - component_size_list[component_index_list[v]] + component_index_size[component_index_list[u]], + component_index_size[component_index_list[v]] ); InsertEdgeBasedNode( e1, u, v, size_of_component < 1000 ); @@ -338,12 +304,11 @@ void EdgeBasedGraphFactory::Run( SimpleLogger().Write() << "Generated " << m_edge_based_node_list.size() << " nodes in " << "edge-expanded graph"; - SimpleLogger().Write() << - "generating edge-expanded edges"; + SimpleLogger().Write() << "generating edge-expanded edges"; - std::vector().swap(component_size_list); + std::vector().swap(component_index_size); BOOST_ASSERT_MSG( - 0 == component_size_list.capacity(), + 0 == component_index_size.capacity(), "component size vector not deallocated" ); std::vector().swap(component_index_list); @@ -359,9 +324,8 @@ void EdgeBasedGraphFactory::Run( //linear number of turns only. p.reinit(m_node_based_graph->GetNumberOfNodes()); for( - NodeIterator u = 0, - last_node = m_node_based_graph->GetNumberOfNodes(); - u < last_node; + NodeIterator u = 0, end = m_node_based_graph->GetNumberOfNodes(); + u < end; ++u ) { for( @@ -371,9 +335,10 @@ void EdgeBasedGraphFactory::Run( ++e1 ) { ++node_based_edge_counter; - NodeIterator v = m_node_based_graph->GetTarget(e1); - bool is_barrier_node = (m_barrier_nodes.find(v) != m_barrier_nodes.end()); - NodeID to_node_of_only_restriction = CheckForEmanatingIsOnlyTurn(u, v); + const NodeIterator v = m_node_based_graph->GetTarget(e1); + const NodeID to_node_of_only_restriction = CheckForEmanatingIsOnlyTurn(u, v); + const bool is_barrier_node = ( m_barrier_nodes.find(v) != m_barrier_nodes.end() ); + for( EdgeIterator e2 = m_node_based_graph->BeginEdges(v), last_edge_v = m_node_based_graph->EndEdges(v); @@ -390,83 +355,91 @@ void EdgeBasedGraphFactory::Run( continue; } - if(u == w && 1 != m_node_based_graph->GetOutDegree(v) ) { + if( is_barrier_node) { + if(u != w) { + ++skipped_turns_counter; + continue; + } + } else { + if ( (u == w) && (m_node_based_graph->GetOutDegree(v) > 1) ) { + ++skipped_turns_counter; + continue; + } + } + + //only add an edge if turn is not a U-turn except when it is + //at the end of a dead-end street + if ( + CheckIfTurnIsRestricted(u, v, w) && + (to_node_of_only_restriction == UINT_MAX) && + (w != to_node_of_only_restriction) + ) { + ++skipped_turns_counter; continue; } - if( !is_barrier_node ) { - //only add an edge if turn is not a U-turn except when it is - //at the end of a dead-end street - if ( - !CheckIfTurnIsRestricted(u, v, w) || - (to_node_of_only_restriction != UINT_MAX && w == to_node_of_only_restriction) - ) { //only add an edge if turn is not prohibited - const EdgeData edge_data1 = m_node_based_graph->GetEdgeData(e1); - const EdgeData edge_data2 = m_node_based_graph->GetEdgeData(e2); - assert(edge_data1.edgeBasedNodeID < m_node_based_graph->GetNumberOfEdges()); - assert(edge_data2.edgeBasedNodeID < m_node_based_graph->GetNumberOfEdges()); + //only add an edge if turn is not prohibited + const EdgeData edge_data1 = m_node_based_graph->GetEdgeData(e1); + const EdgeData edge_data2 = m_node_based_graph->GetEdgeData(e2); - if(!edge_data1.forward || !edge_data2.forward) { - continue; - } + BOOST_ASSERT( + edge_data1.edgeBasedNodeID < m_node_based_graph->GetNumberOfEdges() + ); + BOOST_ASSERT( + edge_data2.edgeBasedNodeID < m_node_based_graph->GetNumberOfEdges() + ); + BOOST_ASSERT( + edge_data1.edgeBasedNodeID != edge_data2.edgeBasedNodeID + ); + BOOST_ASSERT( edge_data1.forward ); + BOOST_ASSERT( edge_data2.forward ); - unsigned distance = edge_data1.distance; - if(m_traffic_lights.find(v) != m_traffic_lights.end()) { - distance += speed_profile.trafficSignalPenalty; - } - const unsigned penalty = - GetTurnPenalty(u, v, w, lua_state); - TurnInstruction turnInstruction = AnalyzeTurn(u, v, w); - if(turnInstruction == TurnInstructions.UTurn){ - distance += speed_profile.uTurnPenalty; - } - distance += penalty; - - assert(edge_data1.edgeBasedNodeID != edge_data2.edgeBasedNodeID); - original_edge_data_vector.push_back( - OriginalEdgeData( - v, - edge_data2.nameID, - turnInstruction - ) - ); - ++original_edges_counter; - - if(original_edge_data_vector.size() > 100000) { - edge_data_file.write( - (char*)&(original_edge_data_vector[0]), - original_edge_data_vector.size()*sizeof(OriginalEdgeData) - ); - original_edge_data_vector.clear(); - } - - m_edge_based_edge_list.push_back( - EdgeBasedEdge( - edge_data1.edgeBasedNodeID, - edge_data2.edgeBasedNodeID, - m_edge_based_edge_list.size(), - distance, - true, - false - ) - ); - } else { - ++skipped_turns_counter; - } + // the following is the core of the loop. + unsigned distance = edge_data1.distance; + if( m_traffic_lights.find(v) != m_traffic_lights.end() ) { + distance += speed_profile.trafficSignalPenalty; } + const int turn_penalty = GetTurnPenalty(u, v, w, lua_state); + TurnInstruction turnInstruction = AnalyzeTurn(u, v, w); + if(turnInstruction == TurnInstructions.UTurn){ + distance += speed_profile.uTurnPenalty; + } + distance += turn_penalty; + + original_edge_data_vector.push_back( + OriginalEdgeData( + v, + edge_data2.nameID, + turnInstruction + ) + ); + ++original_edges_counter; + + if(original_edge_data_vector.size() > 100000) { + FlushVectorToStream( + edge_data_file, + original_edge_data_vector + ); + } + + m_edge_based_edge_list.push_back( + EdgeBasedEdge( + edge_data1.edgeBasedNodeID, + edge_data2.edgeBasedNodeID, + m_edge_based_edge_list.size(), + distance, + true, + false + ) + ); } } p.printIncrement(); } - edge_data_file.write( - (char*)&(original_edge_data_vector[0]), - original_edge_data_vector.size()*sizeof(OriginalEdgeData) - ); - edge_data_file.seekp(std::ios::beg); - edge_data_file.write( - (char*)&original_edges_counter, - sizeof(unsigned) - ); + FlushVectorToStream( edge_data_file, original_edge_data_vector ); + + edge_data_file.seekp( std::ios::beg ); + edge_data_file.write( (char*)&original_edges_counter, sizeof(unsigned) ); edge_data_file.close(); SimpleLogger().Write() << @@ -518,11 +491,11 @@ TurnInstruction EdgeBasedGraphFactory::AnalyzeTurn( return TurnInstructions.UTurn; } - EdgeIterator edge1 = m_node_based_graph->FindEdge(u, v); - EdgeIterator edge2 = m_node_based_graph->FindEdge(v, w); + const EdgeIterator edge1 = m_node_based_graph->FindEdge(u, v); + const EdgeIterator edge2 = m_node_based_graph->FindEdge(v, w); - EdgeData & data1 = m_node_based_graph->GetEdgeData(edge1); - EdgeData & data2 = m_node_based_graph->GetEdgeData(edge2); + const EdgeData & data1 = m_node_based_graph->GetEdgeData(edge1); + const EdgeData & data2 = m_node_based_graph->GetEdgeData(edge2); if(!data1.contraFlow && data2.contraFlow) { return TurnInstructions.EnterAgainstAllowedDirection; @@ -569,10 +542,87 @@ TurnInstruction EdgeBasedGraphFactory::AnalyzeTurn( m_node_info_list[v], m_node_info_list[w] ); - return TurnInstructions.GetTurnDirectionOfInstruction(angle); } unsigned EdgeBasedGraphFactory::GetNumberOfNodes() const { return m_node_based_graph->GetNumberOfEdges(); } + +void EdgeBasedGraphFactory::BFSCompentExplorer( + std::vector & component_index_list, + std::vector & component_index_size +) const { + std::queue > bfs_queue; + Percent p( m_node_based_graph->GetNumberOfNodes() ); + unsigned current_component, current_component_size; + current_component = current_component_size = 0; + + BOOST_ASSERT( component_index_list.empty() ); + BOOST_ASSERT( component_index_size.empty() ); + + component_index_list.resize( + m_node_based_graph->GetNumberOfNodes(), + UINT_MAX + ); + + //put unexplorered node with parent pointer into queue + for( NodeID node = 0, end = m_node_based_graph->GetNumberOfNodes(); node < end; ++node) { + if(UINT_MAX == component_index_list[node]) { + bfs_queue.push(std::make_pair(node, node)); + //mark node as read + component_index_list[node] = current_component; + p.printIncrement(); + while(!bfs_queue.empty()) { + //fetch element from BFS queue + std::pair current_queue_item = bfs_queue.front(); + bfs_queue.pop(); + + const NodeID v = current_queue_item.first; //current node + const NodeID u = current_queue_item.second; //parent + //increment size counter of current component + ++current_component_size; + const bool is_barrier_node = (m_barrier_nodes.find(v) != m_barrier_nodes.end()); + if(!is_barrier_node) { + const NodeID to_node_of_only_restriction = CheckForEmanatingIsOnlyTurn(u, v); + + for( + EdgeIterator e2 = m_node_based_graph->BeginEdges(v); + e2 < m_node_based_graph->EndEdges(v); + ++e2 + ) { + NodeIterator w = m_node_based_graph->GetTarget(e2); + + if( + to_node_of_only_restriction != UINT_MAX && + w != to_node_of_only_restriction + ) { + // At an only_-restriction but not at the right turn + continue; + } + if( u != w ) { + //only add an edge if turn is not a U-turn except + //when it is at the end of a dead-end street. + if (!CheckIfTurnIsRestricted(u, v, w) ) { + //only add an edge if turn is not prohibited + if(UINT_MAX == component_index_list[w]) { + //insert next (node, parent) only if w has + //not yet been explored + //mark node as read + component_index_list[w] = current_component; + bfs_queue.push(std::make_pair(w,v)); + p.printIncrement(); + } + } + } + } + } + } + //push size into vector + component_index_size.push_back(current_component_size); + //reset counters; + current_component_size = 0; + ++current_component; + } + } +} diff --git a/Contractor/EdgeBasedGraphFactory.h b/Contractor/EdgeBasedGraphFactory.h index 0bd2fc6b2..4621d752c 100644 --- a/Contractor/EdgeBasedGraphFactory.h +++ b/Contractor/EdgeBasedGraphFactory.h @@ -34,17 +34,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "../DataStructures/DeallocatingVector.h" #include "../DataStructures/DynamicGraph.h" #include "../DataStructures/EdgeBasedNode.h" -#include "../Extractor/ExtractorStructs.h" #include "../DataStructures/HashTable.h" #include "../DataStructures/ImportEdge.h" -#include "../DataStructures/QueryEdge.h" +#include "../DataStructures/OriginalEdgeData.h" #include "../DataStructures/Percent.h" +#include "../DataStructures/QueryEdge.h" +#include "../DataStructures/QueryNode.h" #include "../DataStructures/TurnInstructions.h" +#include "../DataStructures/Restriction.h" #include "../Util/LuaUtil.h" #include "../Util/SimpleLogger.h" -#include -#include +#include "GeometryCompressor.h" + #include #include #include @@ -80,14 +82,17 @@ public: ); void Run(const char * originalEdgeDataFilename, lua_State *myLuaState); + void GetEdgeBasedEdges( DeallocatingVector< EdgeBasedEdge >& edges ); + void GetEdgeBasedNodes( std::vector< EdgeBasedNode> & nodes); - void GetOriginalEdgeData( std::vector & originalEdgeData); + TurnInstruction AnalyzeTurn( const NodeID u, const NodeID v, const NodeID w ) const; + int GetTurnPenalty( const NodeID u, const NodeID v, @@ -112,15 +117,6 @@ private: bool contraFlow:1; }; - struct _EdgeBasedEdgeData { - int distance; - unsigned via; - unsigned nameID; - bool forward; - bool backward; - TurnInstruction turnInstruction; - }; - unsigned m_turn_restrictions_count; typedef DynamicGraph NodeBasedDynamicGraph; @@ -144,7 +140,6 @@ private: RestrictionMap m_restriction_map; - NodeID CheckForEmanatingIsOnlyTurn( const NodeID u, const NodeID v @@ -157,10 +152,21 @@ private: ) const; void InsertEdgeBasedNode( - NodeBasedDynamicGraph::EdgeIterator e1, - NodeBasedDynamicGraph::NodeIterator u, - NodeBasedDynamicGraph::NodeIterator v, - bool belongsToTinyComponent); + NodeBasedDynamicGraph::EdgeIterator e1, + NodeBasedDynamicGraph::NodeIterator u, + NodeBasedDynamicGraph::NodeIterator v, + bool belongsToTinyComponent + ); + + void BFSCompentExplorer( + std::vector & component_index_list, + std::vector & component_index_size + ) const; + + void FlushVectorToStream( + std::ofstream & edge_data_file, + std::vector & original_edge_data_vector + ) const; }; #endif /* EDGEBASEDGRAPHFACTORY_H_ */ diff --git a/Contractor/GeometryCompressor.cpp b/Contractor/GeometryCompressor.cpp new file mode 100644 index 000000000..5f97a751c --- /dev/null +++ b/Contractor/GeometryCompressor.cpp @@ -0,0 +1,94 @@ +/* + +Copyright (c) 2013, Project OSRM, Dennis Luxen, others +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include "GeometryCompressor.h" + +int current_free_list_maximum = 0; +int UniqueNumber () { return ++current_free_list_maximum; } + +GeometryCompressor::GeometryCompressor() { + m_free_list.resize(100); + IncreaseFreeList(); +} + +void GeometryCompressor::IncreaseFreeList() { + m_compressed_geometries.resize(m_compressed_geometries.size() + 100); + std::generate_n (m_free_list.rend(), 100, UniqueNumber); +} + +void GeometryCompressor::AppendNodeIDsToGeomtry( NodeID node_id, NodeID contracted_node_id ) { + //check if node_id already has a list + boost::unordered_map::const_iterator map_iterator; + map_iterator = m_node_id_to_index_map.find( node_id ); + + unsigned geometry_bucket_index = std::numeric_limits::max(); + if( m_node_id_to_index_map.end() == map_iterator ) { + //if not, create one + if( m_free_list.empty() ) { + IncreaseFreeList(); + } + geometry_bucket_index = m_free_list.back(); + m_free_list.pop_back(); + } else { + geometry_bucket_index = map_iterator->second; + } + + BOOST_ASSERT( std::numeric_limits::max() != geometry_bucket_index ); + BOOST_ASSERT( geometry_bucket_index < m_compressed_geometries.size() ); + + //append contracted_node_id to m_compressed_geometries[node_id] + m_compressed_geometries[geometry_bucket_index].push_back(contracted_node_id); + + //append m_compressed_geometries[contracted_node_id] to m_compressed_geometries[node_id] + map_iterator = m_node_id_to_index_map.find(contracted_node_id); + if ( m_node_id_to_index_map.end() != map_iterator) { + const unsigned bucket_index_to_remove = map_iterator->second; + BOOST_ASSERT( bucket_index_to_remove < m_compressed_geometries.size() ); + + m_compressed_geometries[geometry_bucket_index].insert( + m_compressed_geometries[geometry_bucket_index].end(), + m_compressed_geometries[bucket_index_to_remove].begin(), + m_compressed_geometries[bucket_index_to_remove].end() + ); + //remove m_compressed_geometries[contracted_node_id], add to free list + m_compressed_geometries[bucket_index_to_remove].clear(); + m_free_list.push_back(bucket_index_to_remove); + } +} + +void GeometryCompressor::PrintStatistics() const { + unsigned compressed_node_count = 0; + const unsigned surviving_node_count = m_compressed_geometries.size(); + + BOOST_FOREACH(const std::vector & current_vector, m_compressed_geometries) { + compressed_node_count += current_vector.size(); + } + SimpleLogger().Write() << + "surv: " << surviving_node_count << + ", comp: " << compressed_node_count << + ", comp ratio: " << ((float)surviving_node_count/std::max(compressed_node_count, 1u) ); +} diff --git a/Contractor/GeometryCompressor.h b/Contractor/GeometryCompressor.h new file mode 100644 index 000000000..8d2bf66a6 --- /dev/null +++ b/Contractor/GeometryCompressor.h @@ -0,0 +1,58 @@ +/* + +Copyright (c) 2013, Project OSRM, Dennis Luxen, others +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include "../Util/SimpleLogger.h" +#include "../typedefs.h" + +#include +#include +#include + +#include +#include +#include + +#ifndef GEOMETRY_COMPRESSOR_H +#define GEOMETRY_COMPRESSOR_H + +class GeometryCompressor { +public: + GeometryCompressor(); + void AppendNodeIDsToGeomtry( NodeID node_id, NodeID contracted_node_id ); + void PrintStatistics() const; + +private: + + void IncreaseFreeList(); + + std::vector > m_compressed_geometries; + std::vector m_free_list; + boost::unordered_map m_node_id_to_index_map; +}; + + +#endif //GEOMETRY_COMPRESSOR_H diff --git a/Contractor/TemporaryStorage.cpp b/Contractor/TemporaryStorage.cpp index 0a4fcb6ae..d0e160b6f 100644 --- a/Contractor/TemporaryStorage.cpp +++ b/Contractor/TemporaryStorage.cpp @@ -28,113 +28,135 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "TemporaryStorage.h" TemporaryStorage::TemporaryStorage() { - tempDirectory = boost::filesystem::temp_directory_path(); + temp_directory = boost::filesystem::temp_directory_path(); } TemporaryStorage & TemporaryStorage::GetInstance(){ - static TemporaryStorage runningInstance; - return runningInstance; + static TemporaryStorage static_instance; + return static_instance; } TemporaryStorage::~TemporaryStorage() { - removeAll(); + RemoveAll(); } -void TemporaryStorage::removeAll() { +void TemporaryStorage::RemoveAll() { boost::mutex::scoped_lock lock(mutex); - for(unsigned slot_id = 0; slot_id < vectorOfStreamDatas.size(); ++slot_id) { - deallocateSlot(slot_id); + for(unsigned slot_id = 0; slot_id < stream_data_list.size(); ++slot_id) { + DeallocateSlot(slot_id); } - vectorOfStreamDatas.clear(); + stream_data_list.clear(); } -int TemporaryStorage::allocateSlot() { +int TemporaryStorage::AllocateSlot() { boost::mutex::scoped_lock lock(mutex); try { - vectorOfStreamDatas.push_back(StreamData()); - //SimpleLogger().Write() << "created new temporary file: " << vectorOfStreamDatas.back().pathToTemporaryFile; + stream_data_list.push_back(StreamData()); } catch(boost::filesystem::filesystem_error & e) { - abort(e); + Abort(e); } - return vectorOfStreamDatas.size() - 1; + CheckIfTemporaryDeviceFull(); + return stream_data_list.size() - 1; } -void TemporaryStorage::deallocateSlot(int slotID) { +void TemporaryStorage::DeallocateSlot(const int slot_id) { try { - StreamData & data = vectorOfStreamDatas[slotID]; + StreamData & data = stream_data_list[slot_id]; boost::mutex::scoped_lock lock(*data.readWriteMutex); - if(!boost::filesystem::exists(data.pathToTemporaryFile)) { + if(!boost::filesystem::exists(data.temp_path)) { return; } - if(data.streamToTemporaryFile->is_open()) { - data.streamToTemporaryFile->close(); + if(data.temp_file->is_open()) { + data.temp_file->close(); } - boost::filesystem::remove(data.pathToTemporaryFile); + boost::filesystem::remove(data.temp_path); } catch(boost::filesystem::filesystem_error & e) { - abort(e); + Abort(e); } } -void TemporaryStorage::writeToSlot(int slotID, char * pointer, std::streamsize size) { +void TemporaryStorage::WriteToSlot( + const int slot_id, + char * pointer, + const std::size_t size +) { try { - StreamData & data = vectorOfStreamDatas[slotID]; + StreamData & data = stream_data_list[slot_id]; + BOOST_ASSERT(data.write_mode); + boost::mutex::scoped_lock lock(*data.readWriteMutex); BOOST_ASSERT_MSG( - data.writeMode, + data.write_mode, "Writing after first read is not allowed" ); - data.streamToTemporaryFile->write(pointer, size); - } catch(boost::filesystem::filesystem_error & e) { - abort(e); - } -} -void TemporaryStorage::readFromSlot(int slotID, char * pointer, std::streamsize size) { - try { - StreamData & data = vectorOfStreamDatas[slotID]; - boost::mutex::scoped_lock lock(*data.readWriteMutex); - if(data.writeMode) { - data.writeMode = false; - data.streamToTemporaryFile->seekg(0, data.streamToTemporaryFile->beg); + if( 1073741824 < data.buffer.size() ) { + data.temp_file->write(&data.buffer[0], data.buffer.size()); + // data.temp_file->write(pointer, size); + data.buffer.clear(); + CheckIfTemporaryDeviceFull(); } - data.streamToTemporaryFile->read(pointer, size); + data.buffer.insert(data.buffer.end(), pointer, pointer+size); + } catch(boost::filesystem::filesystem_error & e) { - abort(e); + Abort(e); } } - -unsigned TemporaryStorage::getFreeBytesOnTemporaryDevice() { - boost::filesystem::space_info tempSpaceInfo; +void TemporaryStorage::ReadFromSlot( + const int slot_id, + char * pointer, + const std::size_t size +) { try { - tempSpaceInfo = boost::filesystem::space(tempDirectory); + StreamData & data = stream_data_list[slot_id]; + boost::mutex::scoped_lock lock(*data.readWriteMutex); + if( data.write_mode ) { + data.write_mode = false; + data.temp_file->write(&data.buffer[0], data.buffer.size()); + data.buffer.clear(); + data.temp_file->seekg( data.temp_file->beg ); + BOOST_ASSERT( data.temp_file->beg == data.temp_file->tellg() ); + } + BOOST_ASSERT( !data.write_mode ); + data.temp_file->read(pointer, size); } catch(boost::filesystem::filesystem_error & e) { - abort(e); + Abort(e); } - return tempSpaceInfo.available; } -boost::filesystem::fstream::pos_type TemporaryStorage::tell(int slotID) { +uint64_t TemporaryStorage::GetFreeBytesOnTemporaryDevice() { + uint64_t value = -1; + try { + boost::filesystem::path p = boost::filesystem::temp_directory_path(); + boost::filesystem::space_info s = boost::filesystem::space( p ); + value = s.free; + } catch(boost::filesystem::filesystem_error & e) { + Abort(e); + } + return value; +} + +void TemporaryStorage::CheckIfTemporaryDeviceFull() { + boost::filesystem::path p = boost::filesystem::temp_directory_path(); + boost::filesystem::space_info s = boost::filesystem::space( p ); + if( (1024*1024) > s.free ) { + throw OSRMException("temporary device is full"); + } +} + +boost::filesystem::fstream::pos_type TemporaryStorage::Tell(const int slot_id) { boost::filesystem::fstream::pos_type position; try { - StreamData & data = vectorOfStreamDatas[slotID]; + StreamData & data = stream_data_list[slot_id]; boost::mutex::scoped_lock lock(*data.readWriteMutex); - position = data.streamToTemporaryFile->tellp(); + position = data.temp_file->tellp(); } catch(boost::filesystem::filesystem_error & e) { - abort(e); - } + Abort(e); + } return position; } -void TemporaryStorage::abort(boost::filesystem::filesystem_error& ) { - removeAll(); -} - -void TemporaryStorage::seek(int slotID, boost::filesystem::fstream::pos_type position) { - try { - StreamData & data = vectorOfStreamDatas[slotID]; - boost::mutex::scoped_lock lock(*data.readWriteMutex); - data.streamToTemporaryFile->seekg(position); - } catch(boost::filesystem::filesystem_error & e) { - abort(e); - } +void TemporaryStorage::Abort(const boost::filesystem::filesystem_error& e) { + RemoveAll(); + throw OSRMException(e.what()); } diff --git a/Contractor/TemporaryStorage.h b/Contractor/TemporaryStorage.h index 214d0b325..e929836c5 100644 --- a/Contractor/TemporaryStorage.h +++ b/Contractor/TemporaryStorage.h @@ -28,46 +28,23 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef TEMPORARYSTORAGE_H_ #define TEMPORARYSTORAGE_H_ -#include -#include - -#include -#include -#include -#include -#include -#include - +#include "../Util/BoostFileSystemFix.h" #include "../Util/OSRMException.h" #include "../Util/SimpleLogger.h" #include "../typedefs.h" -//This is one big workaround for latest boost renaming woes. +#include +#include +#include +#include +#include +#include +#include +#include -#if BOOST_FILESYSTEM_VERSION < 3 -#warning Boost Installation with Filesystem3 missing, activating workaround -#include -namespace boost { -namespace filesystem { -inline path temp_directory_path() { - char * buffer; - buffer = tmpnam (NULL); +#include +#include - return path(buffer); -} - -inline path unique_path(const path&) { - return temp_directory_path(); -} - -} -} - -#endif - -#ifndef BOOST_FILESYSTEM_VERSION -#define BOOST_FILESYSTEM_VERSION 3 -#endif /** * This class implements a singleton file storage for temporary data. * temporary slots can be accessed by other objects through an int @@ -77,49 +54,65 @@ inline path unique_path(const path&) { * -> Data is written in first phase and reread in second. */ -static boost::filesystem::path tempDirectory; +static boost::filesystem::path temp_directory; static std::string TemporaryFilePattern("OSRM-%%%%-%%%%-%%%%"); class TemporaryStorage { public: static TemporaryStorage & GetInstance(); virtual ~TemporaryStorage(); - int allocateSlot(); - void deallocateSlot(int slotID); - void writeToSlot(int slotID, char * pointer, std::streamsize size); - void readFromSlot(int slotID, char * pointer, std::streamsize size); + int AllocateSlot(); + void DeallocateSlot(const int slot_id); + void WriteToSlot(const int slot_id, char * pointer, const std::size_t size); + void ReadFromSlot(const int slot_id, char * pointer, const std::size_t size); //returns the number of free bytes - unsigned getFreeBytesOnTemporaryDevice(); - boost::filesystem::fstream::pos_type tell(int slotID); - void seek(int slotID, boost::filesystem::fstream::pos_type); - void removeAll(); + uint64_t GetFreeBytesOnTemporaryDevice(); + boost::filesystem::fstream::pos_type Tell(const int slot_id); + void RemoveAll(); private: TemporaryStorage(); TemporaryStorage(TemporaryStorage const &){}; - TemporaryStorage& operator=(TemporaryStorage const &) { + + TemporaryStorage & operator=(TemporaryStorage const &) { return *this; } - void abort(boost::filesystem::filesystem_error& e); + + void Abort(const boost::filesystem::filesystem_error& e); + void CheckIfTemporaryDeviceFull(); struct StreamData { - bool writeMode; - boost::filesystem::path pathToTemporaryFile; - boost::shared_ptr streamToTemporaryFile; + bool write_mode; + boost::filesystem::path temp_path; + boost::shared_ptr temp_file; boost::shared_ptr readWriteMutex; + std::vector buffer; + StreamData() : - writeMode(true), - pathToTemporaryFile (boost::filesystem::unique_path(tempDirectory.append(TemporaryFilePattern.begin(), TemporaryFilePattern.end()))), - streamToTemporaryFile(new boost::filesystem::fstream(pathToTemporaryFile, std::ios::in | std::ios::out | std::ios::trunc | std::ios::binary)), - readWriteMutex(new boost::mutex) + write_mode(true), + temp_path( + boost::filesystem::unique_path( + temp_directory.append( + TemporaryFilePattern.begin(), + TemporaryFilePattern.end() + ) + ) + ), + temp_file( + new boost::filesystem::fstream( + temp_path, + std::ios::in|std::ios::out|std::ios::trunc|std::ios::binary + ) + ), + readWriteMutex(boost::make_shared()) { - if(streamToTemporaryFile->fail()) { + if( temp_file->fail() ) { throw OSRMException("temporary file could not be created"); } } }; //vector of file streams that is used to store temporary data - std::vector vectorOfStreamDatas; boost::mutex mutex; + std::vector stream_data_list; }; #endif /* TEMPORARYSTORAGE_H_ */ diff --git a/DataStructures/BinaryHeap.h b/DataStructures/BinaryHeap.h index 0cf61229b..7cd17f66f 100644 --- a/DataStructures/BinaryHeap.h +++ b/DataStructures/BinaryHeap.h @@ -25,8 +25,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef BINARYHEAP_H_INCLUDED -#define BINARYHEAP_H_INCLUDED +#ifndef BINARY_HEAP_H +#define BINARY_HEAP_H //Not compatible with non contiguous node ids @@ -82,6 +82,9 @@ private: template< typename NodeID, typename Key > class UnorderedMapStorage { + typedef boost::unordered_map UnorderedMapType; + typedef typename UnorderedMapType::iterator UnorderedMapIterator; + typedef typename UnorderedMapType::const_iterator UnorderedMapConstIterator; public: UnorderedMapStorage( size_t ) { @@ -89,8 +92,8 @@ public: nodes.rehash(1000); } - Key &operator[]( const NodeID node ) { - return nodes[node]; + Key & operator[]( const NodeID node ) { + return nodes[node]; } void Clear() { @@ -101,13 +104,13 @@ private: boost::unordered_map< NodeID, Key > nodes; }; -template -struct _SimpleHeapData { - NodeID parent; - _SimpleHeapData( NodeID p ) : parent(p) { } -}; - -template < typename NodeID, typename Key, typename Weight, typename Data, typename IndexStorage = ArrayStorage > +template< + typename NodeID, + typename Key, + typename Weight, + typename Data, + typename IndexStorage = ArrayStorage +> class BinaryHeap { private: BinaryHeap( const BinaryHeap& right ); @@ -117,7 +120,9 @@ public: typedef Data DataType; BinaryHeap( size_t maxID ) - : nodeIndex( maxID ) { + : + nodeIndex( maxID ) + { Clear(); } @@ -210,11 +215,13 @@ public: private: class HeapNode { public: - HeapNode() { - } HeapNode( NodeID n, Key k, Weight w, Data d ) - : node( n ), key( k ), weight( w ), data( d ) { - } + : + node(n), + key(k), + weight(w), + data(d) + { } NodeID node; Key key; @@ -234,14 +241,17 @@ private: const Key droppingIndex = heap[key].index; const Weight weight = heap[key].weight; Key nextKey = key << 1; - while ( nextKey < static_cast( heap.size() ) ) { + while( nextKey < static_cast( heap.size() ) ){ const Key nextKeyOther = nextKey + 1; - if ( ( nextKeyOther < static_cast ( heap.size() ) )&& ( heap[nextKey].weight > heap[nextKeyOther].weight) ) + if ( + ( nextKeyOther < static_cast( heap.size() ) ) && + ( heap[nextKey].weight > heap[nextKeyOther].weight ) + ) { nextKey = nextKeyOther; - - if ( weight <= heap[nextKey].weight ) + } + if ( weight <= heap[nextKey].weight ){ break; - + } heap[key] = heap[nextKey]; insertedNodes[heap[key].index].key = key; key = nextKey; @@ -277,4 +287,4 @@ private: } }; -#endif //#ifndef BINARYHEAP_H_INCLUDED +#endif //BINARY_HEAP_H diff --git a/DataStructures/Coordinate.h b/DataStructures/Coordinate.cpp similarity index 54% rename from DataStructures/Coordinate.h rename to DataStructures/Coordinate.cpp index 6747616db..58598b206 100644 --- a/DataStructures/Coordinate.h +++ b/DataStructures/Coordinate.cpp @@ -25,55 +25,51 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef FIXED_POINT_COORDINATE_H_ -#define FIXED_POINT_COORDINATE_H_ - -#include "../DataStructures/MercatorUtil.h" +#include #include "../Util/StringUtil.h" #include #include #include -#include +FixedPointCoordinate::FixedPointCoordinate() + : lat(INT_MIN), + lon(INT_MIN) +{ } -static const double COORDINATE_PRECISION = 1000000.; +FixedPointCoordinate::FixedPointCoordinate(int lat, int lon) + : lat(lat), + lon(lon) +{ } -struct FixedPointCoordinate { - int lat; - int lon; - FixedPointCoordinate () : lat(INT_MIN), lon(INT_MIN) {} - explicit FixedPointCoordinate (int lat, int lon) : lat(lat) , lon(lon) {} - - void Reset() { - lat = INT_MIN; - lon = INT_MIN; +void FixedPointCoordinate::Reset() { + lat = INT_MIN; + lon = INT_MIN; +} +bool FixedPointCoordinate::isSet() const { + return (INT_MIN != lat) && (INT_MIN != lon); +} +bool FixedPointCoordinate::isValid() const { + if( + lat > 90*COORDINATE_PRECISION || + lat < -90*COORDINATE_PRECISION || + lon > 180*COORDINATE_PRECISION || + lon < -180*COORDINATE_PRECISION + ) { + return false; } - bool isSet() const { - return (INT_MIN != lat) && (INT_MIN != lon); - } - inline bool isValid() const { - if( - lat > 90*COORDINATE_PRECISION || - lat < -90*COORDINATE_PRECISION || - lon > 180*COORDINATE_PRECISION || - lon < -180*COORDINATE_PRECISION - ) { - return false; - } - return true; - } - bool operator==(const FixedPointCoordinate & other) const { - return lat == other.lat && lon == other.lon; - } -}; - -inline std::ostream & operator<<(std::ostream & out, const FixedPointCoordinate & c){ - out << "(" << c.lat << "," << c.lon << ")"; - return out; + return true; +} +bool FixedPointCoordinate::operator==(const FixedPointCoordinate & other) const { + return lat == other.lat && lon == other.lon; } -inline double ApproximateDistance( const int lat1, const int lon1, const int lat2, const int lon2 ) { +double FixedPointCoordinate::ApproximateDistance( + const int lat1, + const int lon1, + const int lat2, + const int lon2 +) { BOOST_ASSERT(lat1 != INT_MIN); BOOST_ASSERT(lon1 != INT_MIN); BOOST_ASSERT(lat2 != INT_MIN); @@ -94,18 +90,24 @@ inline double ApproximateDistance( const int lat1, const int lon1, const int lat double aHarv= pow(sin(dLat/2.0),2.0)+cos(dlat1)*cos(dlat2)*pow(sin(dLong/2.),2); double cHarv=2.*atan2(sqrt(aHarv),sqrt(1.0-aHarv)); - //earth's radius from wikipedia varies between 6,356.750 km — 6,378.135 km (˜3,949.901 — 3,963.189 miles) - //The IUGG value for the equatorial radius of the Earth is 6378.137 km (3963.19 mile) - const double earth=6372797.560856;//I am doing miles, just change this to radius in kilometers to get distances in km + //earth radius varies between 6,356.750-6,378.135 km (3,949.901-3,963.189mi) + //The IUGG value for the equatorial radius is 6378.137 km (3963.19 miles) + const double earth=6372797.560856; double distance=earth*cHarv; return distance; } -inline double ApproximateDistance(const FixedPointCoordinate &c1, const FixedPointCoordinate &c2) { +double FixedPointCoordinate::ApproximateDistance( + const FixedPointCoordinate &c1, + const FixedPointCoordinate &c2 +) { return ApproximateDistance( c1.lat, c1.lon, c2.lat, c2.lon ); } -inline double ApproximateEuclideanDistance(const FixedPointCoordinate &c1, const FixedPointCoordinate &c2) { +double FixedPointCoordinate::ApproximateEuclideanDistance( + const FixedPointCoordinate &c1, + const FixedPointCoordinate &c2 +) { BOOST_ASSERT(c1.lat != INT_MIN); BOOST_ASSERT(c1.lon != INT_MIN); BOOST_ASSERT(c2.lat != INT_MIN); @@ -123,48 +125,38 @@ inline double ApproximateEuclideanDistance(const FixedPointCoordinate &c1, const return d; } -static inline void convertInternalLatLonToString(const int value, std::string & output) { +void FixedPointCoordinate::convertInternalLatLonToString( + const int value, + std::string & output +) { char buffer[100]; buffer[11] = 0; // zero termination char* string = printInt< 11, 6 >( buffer, value ); output = string; } -static inline void convertInternalCoordinateToString(const FixedPointCoordinate & coord, std::string & output) { - std::string tmp; - convertInternalLatLonToString(coord.lon, tmp); - output = tmp; - output += ","; - convertInternalLatLonToString(coord.lat, tmp); - output += tmp; - output += " "; -} -static inline void convertInternalReversedCoordinateToString(const FixedPointCoordinate & coord, std::string & output) { - std::string tmp; - convertInternalLatLonToString(coord.lat, tmp); - output = tmp; - output += ","; - convertInternalLatLonToString(coord.lon, tmp); - output += tmp; - output += " "; -} - - -/* Get angle of line segment (A,C)->(C,B), atan2 magic, formerly cosine theorem*/ -template -static inline double GetAngleBetweenThreeFixedPointCoordinates ( - const CoordinateT & A, - const CoordinateT & C, - const CoordinateT & B +void FixedPointCoordinate::convertInternalCoordinateToString( + const FixedPointCoordinate & coord, + std::string & output ) { - const double v1x = (A.lon - C.lon)/COORDINATE_PRECISION; - const double v1y = lat2y(A.lat/COORDINATE_PRECISION) - lat2y(C.lat/COORDINATE_PRECISION); - const double v2x = (B.lon - C.lon)/COORDINATE_PRECISION; - const double v2y = lat2y(B.lat/COORDINATE_PRECISION) - lat2y(C.lat/COORDINATE_PRECISION); - - double angle = (atan2(v2y,v2x) - atan2(v1y,v1x) )*180/M_PI; - while(angle < 0) - angle += 360; - return angle; + std::string tmp; + tmp.reserve(23); + convertInternalLatLonToString(coord.lon, tmp); + output = tmp; + output += ","; + convertInternalLatLonToString(coord.lat, tmp); + output += tmp; +} + +void FixedPointCoordinate::convertInternalReversedCoordinateToString( + const FixedPointCoordinate & coord, + std::string & output +) { + std::string tmp; + tmp.reserve(23); + convertInternalLatLonToString(coord.lat, tmp); + output = tmp; + output += ","; + convertInternalLatLonToString(coord.lon, tmp); + output += tmp; } -#endif /* FIXED_POINT_COORDINATE_H_ */ diff --git a/DataStructures/DynamicGraph.h b/DataStructures/DynamicGraph.h index b4502d9e6..1ad5cc9a2 100644 --- a/DataStructures/DynamicGraph.h +++ b/DataStructures/DynamicGraph.h @@ -41,8 +41,8 @@ template< typename EdgeDataT> class DynamicGraph { public: typedef EdgeDataT EdgeData; - typedef uint32_t NodeIterator; - typedef uint32_t EdgeIterator; + typedef unsigned NodeIterator; + typedef unsigned EdgeIterator; class InputEdge { public: @@ -101,15 +101,15 @@ class DynamicGraph { ~DynamicGraph(){ } - uint32_t GetNumberOfNodes() const { + unsigned GetNumberOfNodes() const { return m_numNodes; } - uint32_t GetNumberOfEdges() const { + unsigned GetNumberOfEdges() const { return m_numEdges; } - uint32_t GetOutDegree( const NodeIterator n ) const { + unsigned GetOutDegree( const NodeIterator n ) const { return m_nodes[n].edges; } @@ -117,6 +117,10 @@ class DynamicGraph { return NodeIterator( m_edges[e].target ); } + void SetTarget( const EdgeIterator e, const NodeIterator n ) { + m_edges[e].target = n; + } + EdgeDataT &GetEdgeData( const EdgeIterator e ) { return m_edges[e].data; } @@ -143,7 +147,7 @@ class DynamicGraph { m_edges[node.firstEdge] = m_edges[node.firstEdge + node.edges]; } else { EdgeIterator newFirstEdge = ( EdgeIterator ) m_edges.size(); - uint32_t newSize = node.edges * 1.1 + 2; + unsigned newSize = node.edges * 1.1 + 2; EdgeIterator requiredCapacity = newSize + m_edges.size(); EdgeIterator oldCapacity = m_edges.capacity(); if ( requiredCapacity >= oldCapacity ) { @@ -170,9 +174,12 @@ class DynamicGraph { //removes an edge. Invalidates edge iterators for the source node void DeleteEdge( const NodeIterator source, const EdgeIterator e ) { Node &node = m_nodes[source]; + #pragma omp atomic --m_numEdges; --node.edges; - const uint32_t last = node.firstEdge + node.edges; + BOOST_ASSERT(UINT_MAX != node.edges); + const unsigned last = node.firstEdge + node.edges; + BOOST_ASSERT( UINT_MAX != last); //swap with last edge m_edges[e] = m_edges[last]; makeDummy( last ); @@ -222,7 +229,7 @@ class DynamicGraph { //index of the first edge EdgeIterator firstEdge; //amount of edges - uint32_t edges; + unsigned edges; }; struct Edge { diff --git a/DataStructures/EdgeBasedNode.h b/DataStructures/EdgeBasedNode.h index 542eda451..895baa8dd 100644 --- a/DataStructures/EdgeBasedNode.h +++ b/DataStructures/EdgeBasedNode.h @@ -1,21 +1,74 @@ #ifndef EDGE_BASED_NODE_H #define EDGE_BASED_NODE_H -#include "Coordinate.h" +#include +#include + +#include "../Util/MercatorUtil.h" +#include "../typedefs.h" + +#include + +// An EdgeBasedNode represents a node in the edge-expanded graph. struct EdgeBasedNode { + EdgeBasedNode() : - id(INT_MAX), - lat1(INT_MAX), - lat2(INT_MAX), - lon1(INT_MAX), - lon2(INT_MAX >> 1), - belongsToTinyComponent(false), - nameID(UINT_MAX), - weight(UINT_MAX >> 1), - ignoreInGrid(false) + id(INT_MAX), + lat1(INT_MAX), + lat2(INT_MAX), + lon1(INT_MAX), + lon2(INT_MAX >> 1), + belongsToTinyComponent(false), + nameID(UINT_MAX), + weight(UINT_MAX >> 1), + ignoreInGrid(false) { } + // Computes: + // - the distance from the given query location to nearest point on this edge (and returns it) + // - the location on this edge which is nearest to the query location + // - the ratio ps:pq, where p and q are the end points of this edge, and s is the perpendicular foot of + // the query location on the line defined by p and q. + double ComputePerpendicularDistance( + const FixedPointCoordinate& query_location, + FixedPointCoordinate & nearest_location, + double & ratio, + double precision = COORDINATE_PRECISION + ) const { + BOOST_ASSERT( query_location.isValid() ); + + const double epsilon = 1.0/precision; + + if( ignoreInGrid ) { + return std::numeric_limits::max(); + } + + // p, q : the end points of the underlying edge + const Point p(lat2y(lat1/COORDINATE_PRECISION), lon1/COORDINATE_PRECISION); + const Point q(lat2y(lat2/COORDINATE_PRECISION), lon2/COORDINATE_PRECISION); + + // r : query location + const Point r(lat2y(query_location.lat/COORDINATE_PRECISION), + query_location.lon/COORDINATE_PRECISION); + + const Point foot = ComputePerpendicularFoot(p, q, r, epsilon); + ratio = ComputeRatio(p, q, foot, epsilon); + + BOOST_ASSERT( !std::isnan(ratio) ); + + nearest_location = ComputeNearestPointOnSegment(foot, ratio); + + BOOST_ASSERT( nearest_location.isValid() ); + + // TODO: Replace with euclidean approximation when k-NN search is done + // const double approximated_distance = FixedPointCoordinate::ApproximateEuclideanDistance( + const double approximated_distance = FixedPointCoordinate::ApproximateDistance(query_location, nearest_location); + + BOOST_ASSERT( 0.0 <= approximated_distance ); + return approximated_distance; + } + bool operator<(const EdgeBasedNode & other) const { return other.id < id; } @@ -24,28 +77,100 @@ struct EdgeBasedNode { return id == other.id; } + // Returns the midpoint of the underlying edge. inline FixedPointCoordinate Centroid() const { - FixedPointCoordinate centroid; - //The coordinates of the midpoint are given by: - //x = (x1 + x2) /2 and y = (y1 + y2) /2. - centroid.lon = (std::min(lon1, lon2) + std::max(lon1, lon2))/2; - centroid.lat = (std::min(lat1, lat2) + std::max(lat1, lat2))/2; - return centroid; - } - - inline bool isIgnored() const { - return ignoreInGrid; + return FixedPointCoordinate((lat1+lat2)/2, (lon1+lon2)/2); } NodeID id; + + // The coordinates of the end-points of the underlying edge. int lat1; int lat2; int lon1; int lon2:31; + bool belongsToTinyComponent:1; NodeID nameID; + + // The weight of the underlying edge. unsigned weight:31; + bool ignoreInGrid:1; + +private: + + typedef std::pair Point; + + // Compute the perpendicular foot of point r on the line defined by p and q. + Point ComputePerpendicularFoot(const Point &p, const Point &q, const Point &r, double epsilon) const { + + // the projection of r onto the line pq + double foot_x, foot_y; + + const bool is_parallel_to_y_axis = std::abs(q.first - p.first) < epsilon; + + if( is_parallel_to_y_axis ) { + foot_x = q.first; + foot_y = r.second; + } else { + // the slope of the line through (a|b) and (c|d) + const double m = (q.second - p.second) / (q.first - p.first); + + // Projection of (x|y) onto the line joining (a|b) and (c|d). + foot_x = ((r.first + (m*r.second)) + (m*m*p.first - m*p.second))/(1.0 + m*m); + foot_y = p.second + m*(foot_x - p.first); + } + + return Point(foot_x, foot_y); + } + + // Compute the ratio of the line segment pr to line segment pq. + double ComputeRatio(const Point & p, const Point & q, const Point & r, double epsilon) const { + + const bool is_parallel_to_x_axis = std::abs(q.second-p.second) < epsilon; + const bool is_parallel_to_y_axis = std::abs(q.first -p.first ) < epsilon; + + double ratio; + + if( !is_parallel_to_y_axis ) { + ratio = (r.first - p.first)/(q.first - p.first); + } else if( !is_parallel_to_x_axis ) { + ratio = (r.second - p.second)/(q.second - p.second); + } else { + // (a|b) and (c|d) are essentially the same point + // by convention, we set the ratio to 0 in this case + //ratio = ((lat2 == query_location.lat) && (lon2 == query_location.lon)) ? 1. : 0.; + ratio = 0.0; + } + + // Round to integer if the ratio is close to 0 or 1. + if( std::abs(ratio) <= epsilon ) { + ratio = 0.0; + } else if( std::abs(ratio-1.0) <= epsilon ) { + ratio = 1.0; + } + + return ratio; + } + + // Computes the point on the segment pq which is nearest to a point r = p + lambda * (q-p). + // p and q are the end points of the underlying edge. + FixedPointCoordinate ComputeNearestPointOnSegment(const Point & r, double lambda) const { + + if( lambda <= 0.0 ) { + return FixedPointCoordinate(lat1, lon1); + } else if( lambda >= 1.0 ) { + return FixedPointCoordinate(lat2, lon2); + } + + // r lies between p and q + return FixedPointCoordinate( + y2lat(r.first)*COORDINATE_PRECISION, + r.second*COORDINATE_PRECISION + ); + } + }; -#endif //EDGE_BASED_NODE_H \ No newline at end of file +#endif //EDGE_BASED_NODE_H diff --git a/DataStructures/HashTable.h b/DataStructures/HashTable.h index f1c5a3210..1e9c3333c 100644 --- a/DataStructures/HashTable.h +++ b/DataStructures/HashTable.h @@ -25,43 +25,44 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef HASHTABLE_H_ -#define HASHTABLE_H_ +#ifndef HASH_TABLE_H +#define HASH_TABLE_H #include #include -template -class HashTable : public boost::unordered_map { +template +class HashTable : public boost::unordered_map { private: - typedef boost::unordered_map super; + typedef boost::unordered_map super; public: + static ValueT default_value; + HashTable() : super() { } HashTable(const unsigned size) : super(size) { } - HashTable &operator=(const HashTable &other) { - super::operator = (other); - return *this; + inline void Add( KeyT const & key, ValueT const & value) { + super::emplace(std::make_pair(key, value)); } - inline void Add(const keyT& key, const valueT& value){ - super::insert(std::make_pair(key, value)); - } - - inline valueT Find(const keyT& key) const { - if(super::find(key) == super::end()) { - return valueT(); + inline const ValueT Find(KeyT const & key) const { + typename super::const_iterator iter = super::find(key); + if( iter == super::end() ) { + return boost::cref(default_value); } - return boost::ref(super::find(key)->second); + return boost::cref(iter->second); } - inline bool Holds(const keyT& key) const { - if(super::find(key) == super::end()) { + inline bool Holds( KeyT const & key) const { + if( super::find(key) == super::end() ) { return false; } return true; } }; -#endif /* HASHTABLE_H_ */ +template +ValueT HashTable::default_value; + +#endif /* HASH_TABLE_H */ diff --git a/DataStructures/HilbertValue.cpp b/DataStructures/HilbertValue.cpp new file mode 100644 index 000000000..4f7d43c88 --- /dev/null +++ b/DataStructures/HilbertValue.cpp @@ -0,0 +1,88 @@ +/* + +Copyright (c) 2013, Project OSRM, Dennis Luxen, others +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include "HilbertValue.h" + +uint64_t HilbertCode::operator() ( + const FixedPointCoordinate & current_coordinate +) const { + unsigned location[2]; + location[0] = current_coordinate.lat+( 90*COORDINATE_PRECISION); + location[1] = current_coordinate.lon+(180*COORDINATE_PRECISION); + + TransposeCoordinate(location); + return BitInterleaving(location[0], location[1]); +} + +uint64_t HilbertCode::BitInterleaving(const uint32_t latitude, const uint32_t longitude) const +{ + uint64_t result = 0; + for(int8_t index = 31; index >= 0; --index){ + result |= (latitude >> index) & 1; + result <<= 1; + result |= (longitude >> index) & 1; + if(0 != index){ + result <<= 1; + } + } + return result; +} + +void HilbertCode::TransposeCoordinate( uint32_t * X) const +{ + uint32_t M = 1 << (32-1), P, Q, t; + int i; + // Inverse undo + for( Q = M; Q > 1; Q >>= 1 ) { + P=Q-1; + for( i = 0; i < 2; ++i ) { + + const bool condition = (X[i] & Q); + if( condition ) { + X[0] ^= P; // invert + } else { + t = (X[0]^X[i]) & P; + X[0] ^= t; + X[i] ^= t; + } + } // exchange + } + // Gray encode + for( i = 1; i < 2; ++i ) { + X[i] ^= X[i-1]; + } + t=0; + for( Q = M; Q > 1; Q >>= 1 ) { + const bool condition = (X[2-1] & Q); + if( condition ) { + t ^= Q-1; + } + } //check if this for loop is wrong + for( i = 0; i < 2; ++i ) { + X[i] ^= t; + } +} diff --git a/DataStructures/HilbertValue.h b/DataStructures/HilbertValue.h index d0d49f655..b86c13180 100644 --- a/DataStructures/HilbertValue.h +++ b/DataStructures/HilbertValue.h @@ -28,70 +28,23 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef HILBERTVALUE_H_ #define HILBERTVALUE_H_ -#include "Coordinate.h" +#include #include #include // computes a 64 bit value that corresponds to the hilbert space filling curve -class HilbertCode : boost::noncopyable { +class HilbertCode : boost::noncopyable +{ public: - static uint64_t GetHilbertNumberForCoordinate( + uint64_t operator() + ( const FixedPointCoordinate & current_coordinate - ) { - unsigned location[2]; - location[0] = current_coordinate.lat+( 90*COORDINATE_PRECISION); - location[1] = current_coordinate.lon+(180*COORDINATE_PRECISION); - - TransposeCoordinate(location); - const uint64_t result = BitInterleaving(location[0], location[1]); - return result; - } + ) const; private: - static inline uint64_t BitInterleaving(const uint32_t a, const uint32_t b) { - uint64_t result = 0; - for(int8_t index = 31; index >= 0; --index){ - result |= (a >> index) & 1; - result <<= 1; - result |= (b >> index) & 1; - if(0 != index){ - result <<= 1; - } - } - return result; - } - - static inline void TransposeCoordinate( uint32_t * X) { - uint32_t M = 1 << (32-1), P, Q, t; - int i; - // Inverse undo - for( Q = M; Q > 1; Q >>= 1 ) { - P=Q-1; - for( i = 0; i < 2; ++i ) { - if( X[i] & Q ) { - X[0] ^= P; // invert - } else { - t = (X[0]^X[i]) & P; - X[0] ^= t; - X[i] ^= t; - } - } // exchange - } - // Gray encode - for( i = 1; i < 2; ++i ) { - X[i] ^= X[i-1]; - } - t=0; - for( Q = M; Q > 1; Q >>= 1 ) { - if( X[2-1] & Q ) { - t ^= Q-1; - } - } //check if this for loop is wrong - for( i = 0; i < 2; ++i ) { - X[i] ^= t; - } - } + inline uint64_t BitInterleaving( const uint32_t a, const uint32_t b) const; + inline void TransposeCoordinate( uint32_t * X) const; }; #endif /* HILBERTVALUE_H_ */ diff --git a/DataStructures/OriginalEdgeData.h b/DataStructures/OriginalEdgeData.h new file mode 100644 index 000000000..894cf8add --- /dev/null +++ b/DataStructures/OriginalEdgeData.h @@ -0,0 +1,58 @@ +/* + +Copyright (c) 2013, Project OSRM, Dennis Luxen, others +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef ORIGINAL_EDGE_DATA_H +#define ORIGINAL_EDGE_DATA_H + +#include "TurnInstructions.h" +#include "../typedefs.h" + +#include + +struct OriginalEdgeData{ + explicit OriginalEdgeData( + NodeID via_node, + unsigned name_id, + TurnInstruction turn_instruction + ) : + via_node(via_node), + name_id(name_id), + turn_instruction(turn_instruction) + { } + + OriginalEdgeData() : + via_node(UINT_MAX), + name_id(UINT_MAX), + turn_instruction(UCHAR_MAX) + { } + + NodeID via_node; + unsigned name_id; + TurnInstruction turn_instruction; +}; + +#endif //ORIGINAL_EDGE_DATA_H diff --git a/DataStructures/PhantomNodes.h b/DataStructures/PhantomNodes.h index 48c65508b..3a3fbbd93 100644 --- a/DataStructures/PhantomNodes.h +++ b/DataStructures/PhantomNodes.h @@ -28,7 +28,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef PHANTOMNODES_H_ #define PHANTOMNODES_H_ -#include "Coordinate.h" +#include + +#include "../typedefs.h" struct PhantomNode { PhantomNode() : diff --git a/DataStructures/QueryEdge.h b/DataStructures/QueryEdge.h index 53a671616..41c9e066f 100644 --- a/DataStructures/QueryEdge.h +++ b/DataStructures/QueryEdge.h @@ -28,32 +28,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef QUERYEDGE_H_ #define QUERYEDGE_H_ -#include "TurnInstructions.h" #include "../typedefs.h" #include -struct OriginalEdgeData{ - explicit OriginalEdgeData( - NodeID viaNode, - unsigned nameID, - TurnInstruction turnInstruction - ) : viaNode(viaNode), nameID(nameID), turnInstruction(turnInstruction) {} - OriginalEdgeData() : viaNode(UINT_MAX), nameID(UINT_MAX), turnInstruction(UCHAR_MAX) {} - NodeID viaNode; - unsigned nameID; - TurnInstruction turnInstruction; -}; - struct QueryEdge { NodeID source; NodeID target; struct EdgeData { NodeID id:31; - bool shortcut:1; - int distance:30; - bool forward:1; - bool backward:1; + bool shortcut:1; + int distance:30; + bool forward:1; + bool backward:1; } data; bool operator<( const QueryEdge& right ) const { @@ -64,9 +51,14 @@ struct QueryEdge { } bool operator== ( const QueryEdge& right ) const { - return ( source == right.source && target == right.target && data.distance == right.data.distance && - data.shortcut == right.data.shortcut && data.forward == right.data.forward && data.backward == right.data.backward - && data.id == right.data.id + return ( + source == right.source && + target == right.target && + data.distance == right.data.distance && + data.shortcut == right.data.shortcut && + data.forward == right.data.forward && + data.backward == right.data.backward && + data.id == right.data.id ); } }; diff --git a/DataStructures/QueryNode.h b/DataStructures/QueryNode.h index 011d43552..89dccb47a 100644 --- a/DataStructures/QueryNode.h +++ b/DataStructures/QueryNode.h @@ -28,9 +28,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef _NODE_COORDS_H #define _NODE_COORDS_H -#include "Coordinate.h" #include "../typedefs.h" +#include + #include #include diff --git a/DataStructures/RawRouteData.h b/DataStructures/RawRouteData.h index d1aa21d3c..509c4ca97 100644 --- a/DataStructures/RawRouteData.h +++ b/DataStructures/RawRouteData.h @@ -28,29 +28,53 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef RAWROUTEDATA_H_ #define RAWROUTEDATA_H_ -#include "../DataStructures/Coordinate.h" #include "../DataStructures/PhantomNodes.h" #include "../typedefs.h" +#include + +#include + #include -struct _PathData { - _PathData(NodeID no, unsigned na, unsigned tu, unsigned dur) : node(no), nameID(na), durationOfSegment(dur), turnInstruction(tu) { } +struct PathData { + PathData() : + node(UINT_MAX), + name_id(UINT_MAX), + durationOfSegment(UINT_MAX), + turnInstruction(UCHAR_MAX) + { } + + PathData( + NodeID no, + unsigned na, + unsigned tu, + unsigned dur + ) : + node(no), + name_id(na), + durationOfSegment(dur), + turnInstruction(tu) + { } NodeID node; - unsigned nameID; + unsigned name_id; unsigned durationOfSegment; short turnInstruction; }; struct RawRouteData { - std::vector< _PathData > computedShortestPath; - std::vector< _PathData > computedAlternativePath; + std::vector< std::vector > unpacked_path_segments; + std::vector< PathData > unpacked_alternative; std::vector< PhantomNodes > segmentEndCoordinates; std::vector< FixedPointCoordinate > rawViaNodeCoordinates; unsigned checkSum; int lengthOfShortestPath; int lengthOfAlternativePath; - RawRouteData() : checkSum(UINT_MAX), lengthOfShortestPath(INT_MAX), lengthOfAlternativePath(INT_MAX) {} + RawRouteData() : + checkSum(UINT_MAX), + lengthOfShortestPath(INT_MAX), + lengthOfAlternativePath(INT_MAX) + { } }; #endif /* RAWROUTEDATA_H_ */ diff --git a/DataStructures/Restriction.h b/DataStructures/Restriction.h index 7a942612f..9f53ce3bf 100644 --- a/DataStructures/Restriction.h +++ b/DataStructures/Restriction.h @@ -105,13 +105,16 @@ struct InputRestrictionContainer { return InputRestrictionContainer(0, 0, 0, 0); } static InputRestrictionContainer max_value() { - return InputRestrictionContainer(UINT_MAX, UINT_MAX, UINT_MAX, UINT_MAX); + return InputRestrictionContainer( + UINT_MAX, + UINT_MAX, + UINT_MAX, + UINT_MAX + ); } }; -struct CmpRestrictionContainerByFrom : - public std::binary_function -{ +struct CmpRestrictionContainerByFrom { typedef InputRestrictionContainer value_type; inline bool operator()( const InputRestrictionContainer & a, @@ -127,9 +130,9 @@ struct CmpRestrictionContainerByFrom : } }; -struct CmpRestrictionContainerByTo: public std::binary_function { +struct CmpRestrictionContainerByTo { typedef InputRestrictionContainer value_type; - inline bool operator ()( + inline bool operator()( const InputRestrictionContainer & a, const InputRestrictionContainer & b ) const { diff --git a/DataStructures/SearchEngine.h b/DataStructures/SearchEngine.h index e0fb41db7..025805cc4 100644 --- a/DataStructures/SearchEngine.h +++ b/DataStructures/SearchEngine.h @@ -28,7 +28,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef SEARCHENGINE_H #define SEARCHENGINE_H -#include "Coordinate.h" #include "SearchEngineData.h" #include "PhantomNodes.h" #include "QueryEdge.h" @@ -38,6 +37,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "../Util/StringUtil.h" #include "../typedefs.h" +#include + #include #include diff --git a/DataStructures/SearchEngineData.cpp b/DataStructures/SearchEngineData.cpp index 2a8bf23d2..8db7e4530 100644 --- a/DataStructures/SearchEngineData.cpp +++ b/DataStructures/SearchEngineData.cpp @@ -27,41 +27,65 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "SearchEngineData.h" -void SearchEngineData::InitializeOrClearFirstThreadLocalStorage(const unsigned number_of_nodes) { - if(!forwardHeap.get()) { - forwardHeap.reset(new QueryHeap(number_of_nodes)); - } else { +void SearchEngineData::InitializeOrClearFirstThreadLocalStorage(const unsigned number_of_nodes) +{ + if (forwardHeap.get()) + { forwardHeap->Clear(); } - if(!backwardHeap.get()) { - backwardHeap.reset(new QueryHeap(number_of_nodes)); - } else { + else + { + forwardHeap.reset(new QueryHeap(number_of_nodes)); + } + + if (backwardHeap.get()) + { backwardHeap->Clear(); } + else + { + backwardHeap.reset(new QueryHeap(number_of_nodes)); + } } -void SearchEngineData::InitializeOrClearSecondThreadLocalStorage(const unsigned number_of_nodes) { - if(!forwardHeap2.get()) { - forwardHeap2.reset(new QueryHeap(number_of_nodes)); - } else { +void SearchEngineData::InitializeOrClearSecondThreadLocalStorage(const unsigned number_of_nodes) +{ + if (forwardHeap2.get()) + { forwardHeap2->Clear(); } - if(!backwardHeap2.get()) { - backwardHeap2.reset(new QueryHeap(number_of_nodes)); - } else { + else + { + forwardHeap2.reset(new QueryHeap(number_of_nodes)); + } + + if (backwardHeap2.get()) + { backwardHeap2->Clear(); } + else + { + backwardHeap2.reset(new QueryHeap(number_of_nodes)); + } } -void SearchEngineData::InitializeOrClearThirdThreadLocalStorage(const unsigned number_of_nodes) { - if(!forwardHeap3.get()) { - forwardHeap3.reset(new QueryHeap(number_of_nodes)); - } else { +void SearchEngineData::InitializeOrClearThirdThreadLocalStorage(const unsigned number_of_nodes) +{ + if (forwardHeap3.get()) + { forwardHeap3->Clear(); } - if(!backwardHeap3.get()) { - backwardHeap3.reset(new QueryHeap(number_of_nodes)); - } else { + else + { + forwardHeap3.reset(new QueryHeap(number_of_nodes)); + } + + if (backwardHeap3.get()) + { backwardHeap3->Clear(); } + else + { + backwardHeap3.reset(new QueryHeap(number_of_nodes)); + } } diff --git a/DataStructures/SegmentInformation.h b/DataStructures/SegmentInformation.h index c99690517..c17c788f9 100644 --- a/DataStructures/SegmentInformation.h +++ b/DataStructures/SegmentInformation.h @@ -28,24 +28,54 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef SEGMENTINFORMATION_H_ #define SEGMENTINFORMATION_H_ -#include "Coordinate.h" #include "TurnInstructions.h" + #include "../typedefs.h" -#include +#include +// Struct fits everything in one cache line struct SegmentInformation { FixedPointCoordinate location; - NodeID nameID; - double length; + NodeID name_id; unsigned duration; - double bearing; - TurnInstruction turnInstruction; + double length; + short bearing; //more than enough [0..3600] fits into 12 bits + TurnInstruction turn_instruction; bool necessary; - SegmentInformation(const FixedPointCoordinate & loc, const NodeID nam, const double len, const unsigned dur, const TurnInstruction tInstr, const bool nec) : - location(loc), nameID(nam), length(len), duration(dur), bearing(0.), turnInstruction(tInstr), necessary(nec) {} - SegmentInformation(const FixedPointCoordinate & loc, const NodeID nam, const double len, const unsigned dur, const TurnInstruction tInstr) : - location(loc), nameID(nam), length(len), duration(dur), bearing(0.), turnInstruction(tInstr), necessary(tInstr != 0) {} + + explicit SegmentInformation( + const FixedPointCoordinate & location, + const NodeID name_id, + const unsigned duration, + const double length, + const TurnInstruction turn_instruction, + const bool necessary + ) : + location(location), + name_id(name_id), + duration(duration), + length(length), + bearing(0), + turn_instruction(turn_instruction), + necessary(necessary) + { } + + explicit SegmentInformation( + const FixedPointCoordinate & location, + const NodeID name_id, + const unsigned duration, + const double length, + const TurnInstruction turn_instruction + ) : + location(location), + name_id(name_id), + duration(duration), + length(length), + bearing(0), + turn_instruction(turn_instruction), + necessary(turn_instruction != 0) + { } }; #endif /* SEGMENTINFORMATION_H_ */ diff --git a/DataStructures/StaticRTree.h b/DataStructures/StaticRTree.h index 5feab4c7d..059a9b0ef 100644 --- a/DataStructures/StaticRTree.h +++ b/DataStructures/StaticRTree.h @@ -28,19 +28,20 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef STATICRTREE_H_ #define STATICRTREE_H_ -#include "Coordinate.h" #include "DeallocatingVector.h" #include "HilbertValue.h" -#include "MercatorUtil.h" #include "PhantomNodes.h" #include "SharedMemoryFactory.h" #include "SharedMemoryVectorWrapper.h" +#include "../Util/MercatorUtil.h" #include "../Util/OSRMException.h" #include "../Util/SimpleLogger.h" #include "../Util/TimingUtil.h" #include "../typedefs.h" +#include + #include #include #include @@ -124,10 +125,10 @@ public: FixedPointCoordinate lower_left (other.min_lat, other.min_lon); return ( - Contains(upper_left) - || Contains(upper_right) - || Contains(lower_right) - || Contains(lower_left) + Contains(upper_left ) || + Contains(upper_right) || + Contains(lower_right) || + Contains(lower_left ) ); } @@ -140,7 +141,7 @@ public: double min_dist = std::numeric_limits::max(); min_dist = std::min( min_dist, - ApproximateDistance( + FixedPointCoordinate::ApproximateDistance( location.lat, location.lon, max_lat, @@ -149,7 +150,7 @@ public: ); min_dist = std::min( min_dist, - ApproximateDistance( + FixedPointCoordinate::ApproximateDistance( location.lat, location.lon, max_lat, @@ -158,7 +159,7 @@ public: ); min_dist = std::min( min_dist, - ApproximateDistance( + FixedPointCoordinate::ApproximateDistance( location.lat, location.lon, min_lat, @@ -167,7 +168,7 @@ public: ); min_dist = std::min( min_dist, - ApproximateDistance( + FixedPointCoordinate::ApproximateDistance( location.lat, location.lon, min_lat, @@ -188,32 +189,32 @@ public: min_max_dist = std::min( min_max_dist, std::max( - ApproximateDistance(location, upper_left ), - ApproximateDistance(location, upper_right) + FixedPointCoordinate::ApproximateDistance(location, upper_left ), + FixedPointCoordinate::ApproximateDistance(location, upper_right) ) ); min_max_dist = std::min( min_max_dist, std::max( - ApproximateDistance(location, upper_right), - ApproximateDistance(location, lower_right) + FixedPointCoordinate::ApproximateDistance(location, upper_right), + FixedPointCoordinate::ApproximateDistance(location, lower_right) ) ); min_max_dist = std::min( min_max_dist, std::max( - ApproximateDistance(location, lower_right), - ApproximateDistance(location, lower_left ) + FixedPointCoordinate::ApproximateDistance(location, lower_right), + FixedPointCoordinate::ApproximateDistance(location, lower_left ) ) ); min_max_dist = std::min( min_max_dist, std::max( - ApproximateDistance(location, lower_left ), - ApproximateDistance(location, upper_left ) + FixedPointCoordinate::ApproximateDistance(location, lower_left ), + FixedPointCoordinate::ApproximateDistance(location, upper_left ) ) ); return min_max_dist; @@ -307,6 +308,8 @@ public: double time1 = get_timestamp(); std::vector input_wrapper_vector(m_element_count); + HilbertCode get_hilbert_number; + //generate auxiliary vector of hilbert-values #pragma omp parallel for schedule(guided) for(uint64_t element_counter = 0; element_counter < m_element_count; ++element_counter) { @@ -316,10 +319,10 @@ public: FixedPointCoordinate current_centroid = current_element.Centroid(); current_centroid.lat = COORDINATE_PRECISION*lat2y(current_centroid.lat/COORDINATE_PRECISION); - uint64_t current_hilbert_value = HilbertCode::GetHilbertNumberForCoordinate(current_centroid); + uint64_t current_hilbert_value = get_hilbert_number(current_centroid); input_wrapper_vector[element_counter].m_hilbert_value = current_hilbert_value; - } + //open leaf file boost::filesystem::ofstream leaf_node_file(leaf_node_filename, std::ios::binary); leaf_node_file.write((char*) &m_element_count, sizeof(uint64_t)); @@ -334,6 +337,7 @@ public: LeafNode current_leaf; TreeNode current_node; + //SimpleLogger().Write() << "reading " << tree_size << " tree nodes in " << (sizeof(TreeNode)*tree_size) << " bytes"; for(uint32_t current_element_index = 0; RTREE_LEAF_NODE_SIZE > current_element_index; ++current_element_index) { if(m_element_count > (processed_objects_count + current_element_index)) { uint32_t index_of_next_object = input_wrapper_vector[processed_objects_count + current_element_index].m_array_index; @@ -391,6 +395,7 @@ public: //reverse and renumber tree to have root at index 0 std::reverse(m_search_tree.begin(), m_search_tree.end()); + #pragma omp parallel for schedule(guided) for(uint32_t i = 0; i < m_search_tree.size(); ++i) { TreeNode & current_tree_node = m_search_tree[i]; @@ -435,7 +440,7 @@ public: uint32_t tree_size = 0; tree_node_file.read((char*)&tree_size, sizeof(uint32_t)); - //SimpleLogger().Write() << "reading " << tree_size << " tree nodes in " << (sizeof(TreeNode)*tree_size) << " bytes"; + m_search_tree.resize(tree_size); tree_node_file.read((char*)&m_search_tree[0], sizeof(TreeNode)*tree_size); tree_node_file.close(); @@ -526,12 +531,10 @@ public: } double current_ratio = 0.; - double current_perpendicular_distance = ComputePerpendicularDistance( + double current_perpendicular_distance = current_edge.ComputePerpendicularDistance( input_coordinate, - FixedPointCoordinate(current_edge.lat1, current_edge.lon1), - FixedPointCoordinate(current_edge.lat2, current_edge.lon2), nearest, - ¤t_ratio + current_ratio ); if( @@ -556,7 +559,7 @@ public: } else if( DoubleEpsilonCompare(current_perpendicular_distance, min_dist) && 1 == abs(current_edge.id - result_phantom_node.edgeBasedNode ) - && CoordinatesAreEquivalent( + && EdgesAreEquivalent( current_start_coordinate, FixedPointCoordinate( current_edge.lat1, @@ -675,11 +678,8 @@ public: ) { continue; } - if(current_edge.isIgnored()) { - continue; - } - double current_minimum_distance = ApproximateDistance( + double current_minimum_distance = FixedPointCoordinate::ApproximateDistance( input_coordinate.lat, input_coordinate.lon, current_edge.lat1, @@ -693,7 +693,7 @@ public: found_a_nearest_edge = true; } - current_minimum_distance = ApproximateDistance( + current_minimum_distance = FixedPointCoordinate::ApproximateDistance( input_coordinate.lat, input_coordinate.lon, current_edge.lat2, @@ -736,7 +736,6 @@ public: return found_a_nearest_edge; } - bool FindPhantomNodeForCoordinate( const FixedPointCoordinate & input_coordinate, PhantomNode & result_phantom_node, @@ -746,7 +745,7 @@ public: bool ignore_tiny_components = (zoom_level <= 14); DataT nearest_edge; - uint32_t io_count = 0; + // uint32_t io_count = 0; uint32_t explored_tree_nodes_count = 0; //SimpleLogger().Write() << "searching for coordinate " << input_coordinate; double min_dist = std::numeric_limits::max(); @@ -758,15 +757,14 @@ public: //initialize queue with root element std::priority_queue traversal_queue; double current_min_dist = m_search_tree[0].minimum_bounding_rectangle.GetMinDist(input_coordinate); - traversal_queue.push( - QueryCandidate(0, current_min_dist) - ); + traversal_queue.push( QueryCandidate(0, current_min_dist) ); BOOST_ASSERT_MSG( std::numeric_limits::epsilon() > (0. - traversal_queue.top().min_dist), "Root element in NN Search has min dist != 0." ); + LeafNode current_leaf_node; while(!traversal_queue.empty()) { const QueryCandidate current_query_node = traversal_queue.top(); traversal_queue.pop(); @@ -776,33 +774,29 @@ public: if( !prune_downward && !prune_upward ) { //downward pruning TreeNode & current_tree_node = m_search_tree[current_query_node.node_id]; if (current_tree_node.child_is_on_disk) { - LeafNode current_leaf_node; LoadLeafFromDisk(current_tree_node.children[0], current_leaf_node); - ++io_count; + // ++io_count; for(uint32_t i = 0; i < current_leaf_node.object_count; ++i) { DataT & current_edge = current_leaf_node.objects[i]; if(ignore_tiny_components && current_edge.belongsToTinyComponent) { continue; } - if(current_edge.isIgnored()) { - continue; - } - double current_ratio = 0.; - double current_perpendicular_distance = ComputePerpendicularDistance( - input_coordinate, - FixedPointCoordinate(current_edge.lat1, current_edge.lon1), - FixedPointCoordinate(current_edge.lat2, current_edge.lon2), - nearest, - ¤t_ratio + double current_ratio = 0.; + double current_perpendicular_distance = current_edge.ComputePerpendicularDistance( + input_coordinate, + nearest, + current_ratio ); + BOOST_ASSERT( 0. <= current_perpendicular_distance ); + if( - current_perpendicular_distance < min_dist - && !DoubleEpsilonCompare( - current_perpendicular_distance, - min_dist - ) + ( current_perpendicular_distance < min_dist ) && + !DoubleEpsilonCompare( + current_perpendicular_distance, + min_dist + ) ) { //found a new minimum min_dist = current_perpendicular_distance; result_phantom_node.edgeBasedNode = current_edge.id; @@ -816,10 +810,10 @@ public: current_end_coordinate.lon = current_edge.lon2; nearest_edge = current_edge; found_a_nearest_edge = true; - } else if( - DoubleEpsilonCompare(current_perpendicular_distance, min_dist) && - 1 == abs(current_edge.id - result_phantom_node.edgeBasedNode ) - && CoordinatesAreEquivalent( + } else + if( DoubleEpsilonCompare(current_perpendicular_distance, min_dist) && + ( 1 == abs(current_edge.id - result_phantom_node.edgeBasedNode ) ) && + EdgesAreEquivalent( current_start_coordinate, FixedPointCoordinate( current_edge.lat1, @@ -853,10 +847,10 @@ public: if( current_min_max_dist < min_max_dist ) { min_max_dist = current_min_max_dist; } - if (current_min_dist > min_max_dist) { + if( current_min_dist > min_max_dist ) { continue; } - if (current_min_dist > min_dist) { //upward pruning + if( current_min_dist > min_dist ) { //upward pruning continue; } traversal_queue.push(QueryCandidate(child_id, current_min_dist)); @@ -865,17 +859,6 @@ public: } } - const double ratio = (found_a_nearest_edge ? - std::min(1., ApproximateDistance(current_start_coordinate, - result_phantom_node.location)/ApproximateDistance(current_start_coordinate, current_end_coordinate) - ) : 0 - ); - result_phantom_node.weight1 *= ratio; - if(INT_MAX != result_phantom_node.weight2) { - result_phantom_node.weight2 *= (1.-ratio); - } - result_phantom_node.ratio = ratio; - //Hack to fix rounding errors and wandering via nodes. if(std::abs(input_coordinate.lon - result_phantom_node.location.lon) == 1) { result_phantom_node.location.lon = input_coordinate.lon; @@ -884,8 +867,30 @@ public: result_phantom_node.location.lat = input_coordinate.lat; } - return found_a_nearest_edge; + double ratio = 0.; + if( found_a_nearest_edge) { + const double distance_1 = FixedPointCoordinate::ApproximateDistance( + current_start_coordinate, + result_phantom_node.location + ); + + const double distance_2 = FixedPointCoordinate::ApproximateDistance( + current_start_coordinate, + current_end_coordinate + ); + + ratio = distance_1/distance_2; + ratio = std::min(1., ratio); + } + + result_phantom_node.weight1 *= ratio; + if(INT_MAX != result_phantom_node.weight2) { + result_phantom_node.weight2 *= (1.-ratio); + } + result_phantom_node.ratio = ratio; + + return found_a_nearest_edge; } private: @@ -910,60 +915,17 @@ private: thread_local_rtree_stream->read((char *)&result_node, sizeof(LeafNode)); } - inline double ComputePerpendicularDistance( - const FixedPointCoordinate& inputPoint, - const FixedPointCoordinate& source, - const FixedPointCoordinate& target, - FixedPointCoordinate& nearest, double *r) const { - const double x = inputPoint.lat/COORDINATE_PRECISION; - const double y = inputPoint.lon/COORDINATE_PRECISION; - const double a = source.lat/COORDINATE_PRECISION; - const double b = source.lon/COORDINATE_PRECISION; - const double c = target.lat/COORDINATE_PRECISION; - const double d = target.lon/COORDINATE_PRECISION; - double p,q,mX,nY; - if(std::fabs(a-c) > std::numeric_limits::epsilon() ){ - const double m = (d-b)/(c-a); // slope - // Projection of (x,y) on line joining (a,b) and (c,d) - p = ((x + (m*y)) + (m*m*a - m*b))/(1. + m*m); - q = b + m*(p - a); - } else { - p = c; - q = y; - } - nY = (d*p - c*q)/(a*d - b*c); - mX = (p - nY*a)/c;// These values are actually n/m+n and m/m+n , we need - // not calculate the explicit values of m an n as we - // are just interested in the ratio - if(std::isnan(mX)) { - *r = (target == inputPoint) ? 1. : 0.; - } else { - *r = mX; - } - if(*r<=0.){ - nearest.lat = source.lat; - nearest.lon = source.lon; - return ((b - y)*(b - y) + (a - x)*(a - x)); -// return std::sqrt(((b - y)*(b - y) + (a - x)*(a - x))); - } else if(*r >= 1.){ - nearest.lat = target.lat; - nearest.lon = target.lon; - return ((d - y)*(d - y) + (c - x)*(c - x)); -// return std::sqrt(((d - y)*(d - y) + (c - x)*(c - x))); - } - // point lies in between - nearest.lat = p*COORDINATE_PRECISION; - nearest.lon = q*COORDINATE_PRECISION; -// return std::sqrt((p-x)*(p-x) + (q-y)*(q-y)); - return (p-x)*(p-x) + (q-y)*(q-y); - } - - inline bool CoordinatesAreEquivalent(const FixedPointCoordinate & a, const FixedPointCoordinate & b, const FixedPointCoordinate & c, const FixedPointCoordinate & d) const { + inline bool EdgesAreEquivalent( + const FixedPointCoordinate & a, + const FixedPointCoordinate & b, + const FixedPointCoordinate & c, + const FixedPointCoordinate & d + ) const { return (a == b && c == d) || (a == c && b == d) || (a == d && b == c); } inline bool DoubleEpsilonCompare(const double d1, const double d2) const { - return (std::fabs(d1 - d2) < std::numeric_limits::epsilon() ); + return (std::abs(d1 - d2) < std::numeric_limits::epsilon() ); } }; diff --git a/Descriptors/BaseDescriptor.h b/Descriptors/BaseDescriptor.h index 029332527..ba5dacad2 100644 --- a/Descriptors/BaseDescriptor.h +++ b/Descriptors/BaseDescriptor.h @@ -28,15 +28,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef BASE_DESCRIPTOR_H_ #define BASE_DESCRIPTOR_H_ -#include "../DataStructures/HashTable.h" #include "../DataStructures/PhantomNodes.h" #include "../DataStructures/RawRouteData.h" -#include "../Server/Http/Reply.h" -#include "../Util/StringUtil.h" #include "../typedefs.h" -#include -#include +#include #include #include @@ -61,10 +57,10 @@ public: //Maybe someone can explain the pure virtual destructor thing to me (dennis) virtual ~BaseDescriptor() { } virtual void Run( - http::Reply & reply, - const RawRouteData &rawRoute, - PhantomNodes &phantomNodes, - const DataFacadeT * facade + const RawRouteData & rawRoute, + const PhantomNodes & phantomNodes, + DataFacadeT * facade, + http::Reply & reply ) = 0; virtual void SetConfig(const DescriptorConfig & config) = 0; }; diff --git a/Descriptors/DescriptionFactory.cpp b/Descriptors/DescriptionFactory.cpp index cae651394..90b57d2b3 100644 --- a/Descriptors/DescriptionFactory.cpp +++ b/Descriptors/DescriptionFactory.cpp @@ -43,13 +43,13 @@ double DescriptionFactory::GetBearing( const FixedPointCoordinate & A, const FixedPointCoordinate & B ) const { - double deltaLong = DegreeToRadian(B.lon/COORDINATE_PRECISION - A.lon/COORDINATE_PRECISION); + double delta_long = DegreeToRadian(B.lon/COORDINATE_PRECISION - A.lon/COORDINATE_PRECISION); const double lat1 = DegreeToRadian(A.lat/COORDINATE_PRECISION); const double lat2 = DegreeToRadian(B.lat/COORDINATE_PRECISION); - const double y = sin(deltaLong) * cos(lat2); - const double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(deltaLong); + const double y = sin(delta_long) * cos(lat2); + const double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(delta_long); double result = RadianToDegree(atan2(y, x)); while(result < 0.) { result += 360.; @@ -60,22 +60,22 @@ double DescriptionFactory::GetBearing( return result; } -void DescriptionFactory::SetStartSegment(const PhantomNode & sph) { - start_phantom = sph; +void DescriptionFactory::SetStartSegment(const PhantomNode & start) { + start_phantom = start; AppendSegment( - sph.location, - _PathData(0, sph.nodeBasedEdgeNameID, 10, sph.weight1) + start.location, + PathData(0, start.nodeBasedEdgeNameID, 10, start.weight1) ); } -void DescriptionFactory::SetEndSegment(const PhantomNode & tph) { - target_phantom = tph; +void DescriptionFactory::SetEndSegment(const PhantomNode & target) { + target_phantom = target; pathDescription.push_back( SegmentInformation( - tph.location, - tph.nodeBasedEdgeNameID, + target.location, + target.nodeBasedEdgeNameID, 0, - tph.weight1, + target.weight1, 0, true ) @@ -84,12 +84,23 @@ void DescriptionFactory::SetEndSegment(const PhantomNode & tph) { void DescriptionFactory::AppendSegment( const FixedPointCoordinate & coordinate, - const _PathData & data + const PathData & data ) { - if(1 == pathDescription.size() && pathDescription.back().location == coordinate) { - pathDescription.back().nameID = data.nameID; + if( + ( 1 == pathDescription.size()) && + ( pathDescription.back().location == coordinate) + ) { + pathDescription.back().name_id = data.name_id; } else { - pathDescription.push_back(SegmentInformation(coordinate, data.nameID, 0, data.durationOfSegment, data.turnInstruction) ); + pathDescription.push_back( + SegmentInformation( + coordinate, + data.name_id, + data.durationOfSegment, + 0, + data.turnInstruction + ) + ); } } @@ -122,127 +133,6 @@ void DescriptionFactory::AppendUnencodedPolylineString( output.push_back(temp); } -// void DescriptionFactory::Run(const SearchEngine &sEngine, const unsigned zoomLevel) { - -// if(0 == pathDescription.size()) -// return; - -// // unsigned entireLength = 0; -// /** starts at index 1 */ -// pathDescription[0].length = 0; -// for(unsigned i = 1; i < pathDescription.size(); ++i) { -// pathDescription[i].length = ApproximateEuclideanDistance(pathDescription[i-1].location, pathDescription[i].location); -// } - -// double lengthOfSegment = 0; -// unsigned durationOfSegment = 0; -// unsigned indexOfSegmentBegin = 0; - -// std::string string0 = sEngine.GetEscapedNameForNameID(pathDescription[0].nameID); -// std::string string1; - - -// /*Simplify turn instructions -// Input : -// 10. Turn left on B 36 for 20 km -// 11. Continue on B 35; B 36 for 2 km -// 12. Continue on B 36 for 13 km - -// becomes: -// 10. Turn left on B 36 for 35 km -// */ -// //TODO: rework to check only end and start of string. -// // stl string is way to expensive - -// // unsigned lastTurn = 0; -// // for(unsigned i = 1; i < pathDescription.size(); ++i) { -// // string1 = sEngine.GetEscapedNameForNameID(pathDescription[i].nameID); -// // if(TurnInstructionsClass::GoStraight == pathDescription[i].turnInstruction) { -// // if(std::string::npos != string0.find(string1+";") -// // || std::string::npos != string0.find(";"+string1) -// // || std::string::npos != string0.find(string1+" ;") -// // || std::string::npos != string0.find("; "+string1) -// // ){ -// // SimpleLogger().Write() << "->next correct: " << string0 << " contains " << string1; -// // for(; lastTurn != i; ++lastTurn) -// // pathDescription[lastTurn].nameID = pathDescription[i].nameID; -// // pathDescription[i].turnInstruction = TurnInstructionsClass::NoTurn; -// // } else if(std::string::npos != string1.find(string0+";") -// // || std::string::npos != string1.find(";"+string0) -// // || std::string::npos != string1.find(string0+" ;") -// // || std::string::npos != string1.find("; "+string0) -// // ){ -// // SimpleLogger().Write() << "->prev correct: " << string1 << " contains " << string0; -// // pathDescription[i].nameID = pathDescription[i-1].nameID; -// // pathDescription[i].turnInstruction = TurnInstructionsClass::NoTurn; -// // } -// // } -// // if (TurnInstructionsClass::NoTurn != pathDescription[i].turnInstruction) { -// // lastTurn = i; -// // } -// // string0 = string1; -// // } - - -// for(unsigned i = 1; i < pathDescription.size(); ++i) { -// entireLength += pathDescription[i].length; -// lengthOfSegment += pathDescription[i].length; -// durationOfSegment += pathDescription[i].duration; -// pathDescription[indexOfSegmentBegin].length = lengthOfSegment; -// pathDescription[indexOfSegmentBegin].duration = durationOfSegment; - - -// if(TurnInstructionsClass::NoTurn != pathDescription[i].turnInstruction) { -// //SimpleLogger().Write() << "Turn after " << lengthOfSegment << "m into way with name id " << segment.nameID; -// assert(pathDescription[i].necessary); -// lengthOfSegment = 0; -// durationOfSegment = 0; -// indexOfSegmentBegin = i; -// } -// } -// // SimpleLogger().Write() << "#segs: " << pathDescription.size(); - -// //Post-processing to remove empty or nearly empty path segments -// if(FLT_EPSILON > pathDescription.back().length) { -// // SimpleLogger().Write() << "#segs: " << pathDescription.size() << ", last ratio: " << target_phantom.ratio << ", length: " << pathDescription.back().length; -// if(pathDescription.size() > 2){ -// pathDescription.pop_back(); -// pathDescription.back().necessary = true; -// pathDescription.back().turnInstruction = TurnInstructions.NoTurn; -// target_phantom.nodeBasedEdgeNameID = (pathDescription.end()-2)->nameID; -// // SimpleLogger().Write() << "Deleting last turn instruction"; -// } -// } else { -// pathDescription[indexOfSegmentBegin].duration *= (1.-target_phantom.ratio); -// } -// if(FLT_EPSILON > pathDescription[0].length) { -// //TODO: this is never called actually? -// if(pathDescription.size() > 2) { -// pathDescription.erase(pathDescription.begin()); -// pathDescription[0].turnInstruction = TurnInstructions.HeadOn; -// pathDescription[0].necessary = true; -// start_phantom.nodeBasedEdgeNameID = pathDescription[0].nameID; -// // SimpleLogger().Write() << "Deleting first turn instruction, ratio: " << start_phantom.ratio << ", length: " << pathDescription[0].length; -// } -// } else { -// pathDescription[0].duration *= start_phantom.ratio; -// } - -// //Generalize poly line -// dp.Run(pathDescription, zoomLevel); - -// //fix what needs to be fixed else -// for(unsigned i = 0; i < pathDescription.size()-1 && pathDescription.size() >= 2; ++i){ -// if(pathDescription[i].necessary) { -// double angle = GetBearing(pathDescription[i].location, pathDescription[i+1].location); -// pathDescription[i].bearing = angle; -// } -// } - -// // BuildRouteSummary(entireLength, duration); -// return; -// } - void DescriptionFactory::BuildRouteSummary( const double distance, const unsigned time diff --git a/Descriptors/DescriptionFactory.h b/Descriptors/DescriptionFactory.h index 8c8a3c0b3..53deca7f4 100644 --- a/Descriptors/DescriptionFactory.h +++ b/Descriptors/DescriptionFactory.h @@ -30,7 +30,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "../Algorithms/DouglasPeucker.h" #include "../Algorithms/PolylineCompressor.h" -#include "../DataStructures/Coordinate.h" #include "../DataStructures/PhantomNodes.h" #include "../DataStructures/RawRouteData.h" #include "../DataStructures/SegmentInformation.h" @@ -38,6 +37,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "../Util/SimpleLogger.h" #include "../typedefs.h" +#include + #include #include @@ -70,8 +71,8 @@ public: ) { //compute distance/duration for route summary intToString(round(distance), lengthString); - int travelTime = time/10 + 1; - intToString(travelTime, durationString); + int travel_time = time/10; + intToString(std::max(travel_time, 1), durationString); } } summary; @@ -84,34 +85,31 @@ public: double GetBearing(const FixedPointCoordinate& C, const FixedPointCoordinate& B) const; void AppendEncodedPolylineString(std::vector &output) const; void AppendUnencodedPolylineString(std::vector &output) const; - void AppendSegment(const FixedPointCoordinate & coordinate, const _PathData & data); + void AppendSegment(const FixedPointCoordinate & coordinate, const PathData & data); void BuildRouteSummary(const double distance, const unsigned time); void SetStartSegment(const PhantomNode & start_phantom); void SetEndSegment(const PhantomNode & start_phantom); void AppendEncodedPolylineString( const bool return_encoded, std::vector & output - ); + ); template - void Run(const DataFacadeT * facade, const unsigned zoomLevel) { - + void Run( + const DataFacadeT * facade, + const unsigned zoomLevel + ) { if( pathDescription.empty() ) { return; } - // unsigned entireLength = 0; /** starts at index 1 */ pathDescription[0].length = 0; for(unsigned i = 1; i < pathDescription.size(); ++i) { - pathDescription[i].length = ApproximateEuclideanDistance(pathDescription[i-1].location, pathDescription[i].location); + pathDescription[i].length = FixedPointCoordinate::ApproximateEuclideanDistance(pathDescription[i-1].location, pathDescription[i].location); } - double lengthOfSegment = 0; - unsigned durationOfSegment = 0; - unsigned indexOfSegmentBegin = 0; - - // std::string string0 = facade->GetEscapedNameForNameID(pathDescription[0].nameID); + // std::string string0 = facade->GetEscapedNameForNameID(pathDescription[0].name_id); // std::string string1; @@ -129,8 +127,8 @@ public: // unsigned lastTurn = 0; // for(unsigned i = 1; i < pathDescription.size(); ++i) { - // string1 = sEngine.GetEscapedNameForNameID(pathDescription[i].nameID); - // if(TurnInstructionsClass::GoStraight == pathDescription[i].turnInstruction) { + // string1 = sEngine.GetEscapedNameForNameID(pathDescription[i].name_id); + // if(TurnInstructionsClass::GoStraight == pathDescription[i].turn_instruction) { // if(std::string::npos != string0.find(string1+";") // || std::string::npos != string0.find(";"+string1) // || std::string::npos != string0.find(string1+" ;") @@ -138,24 +136,27 @@ public: // ){ // SimpleLogger().Write() << "->next correct: " << string0 << " contains " << string1; // for(; lastTurn != i; ++lastTurn) - // pathDescription[lastTurn].nameID = pathDescription[i].nameID; - // pathDescription[i].turnInstruction = TurnInstructionsClass::NoTurn; + // pathDescription[lastTurn].name_id = pathDescription[i].name_id; + // pathDescription[i].turn_instruction = TurnInstructionsClass::NoTurn; // } else if(std::string::npos != string1.find(string0+";") // || std::string::npos != string1.find(";"+string0) // || std::string::npos != string1.find(string0+" ;") // || std::string::npos != string1.find("; "+string0) // ){ // SimpleLogger().Write() << "->prev correct: " << string1 << " contains " << string0; - // pathDescription[i].nameID = pathDescription[i-1].nameID; - // pathDescription[i].turnInstruction = TurnInstructionsClass::NoTurn; + // pathDescription[i].name_id = pathDescription[i-1].name_id; + // pathDescription[i].turn_instruction = TurnInstructionsClass::NoTurn; // } // } - // if (TurnInstructionsClass::NoTurn != pathDescription[i].turnInstruction) { + // if (TurnInstructionsClass::NoTurn != pathDescription[i].turn_instruction) { // lastTurn = i; // } // string0 = string1; // } + double lengthOfSegment = 0; + unsigned durationOfSegment = 0; + unsigned indexOfSegmentBegin = 0; for(unsigned i = 1; i < pathDescription.size(); ++i) { entireLength += pathDescription[i].length; @@ -165,37 +166,31 @@ public: pathDescription[indexOfSegmentBegin].duration = durationOfSegment; - if(TurnInstructionsClass::NoTurn != pathDescription[i].turnInstruction) { - //SimpleLogger().Write() << "Turn after " << lengthOfSegment << "m into way with name id " << pathDescription[i].nameID; - assert(pathDescription[i].necessary); + if(TurnInstructionsClass::NoTurn != pathDescription[i].turn_instruction) { + BOOST_ASSERT(pathDescription[i].necessary); lengthOfSegment = 0; durationOfSegment = 0; indexOfSegmentBegin = i; } } - // SimpleLogger().Write() << "#segs: " << pathDescription.size(); //Post-processing to remove empty or nearly empty path segments if(std::numeric_limits::epsilon() > pathDescription.back().length) { - // SimpleLogger().Write() << "#segs: " << pathDescription.size() << ", last ratio: " << target_phantom.ratio << ", length: " << pathDescription.back().length; if(pathDescription.size() > 2){ pathDescription.pop_back(); pathDescription.back().necessary = true; - pathDescription.back().turnInstruction = TurnInstructions.NoTurn; - target_phantom.nodeBasedEdgeNameID = (pathDescription.end()-2)->nameID; - // SimpleLogger().Write() << "Deleting last turn instruction"; + pathDescription.back().turn_instruction = TurnInstructions.NoTurn; + target_phantom.nodeBasedEdgeNameID = (pathDescription.end()-2)->name_id; } } else { pathDescription[indexOfSegmentBegin].duration *= (1.-target_phantom.ratio); } if(std::numeric_limits::epsilon() > pathDescription[0].length) { - //TODO: this is never called actually? if(pathDescription.size() > 2) { pathDescription.erase(pathDescription.begin()); - pathDescription[0].turnInstruction = TurnInstructions.HeadOn; + pathDescription[0].turn_instruction = TurnInstructions.HeadOn; pathDescription[0].necessary = true; - start_phantom.nodeBasedEdgeNameID = pathDescription[0].nameID; - // SimpleLogger().Write() << "Deleting first turn instruction, ratio: " << start_phantom.ratio << ", length: " << pathDescription[0].length; + start_phantom.nodeBasedEdgeNameID = pathDescription[0].name_id; } } else { pathDescription[0].duration *= start_phantom.ratio; @@ -208,11 +203,9 @@ public: for(unsigned i = 0; i < pathDescription.size()-1 && pathDescription.size() >= 2; ++i){ if(pathDescription[i].necessary) { double angle = GetBearing(pathDescription[i].location, pathDescription[i+1].location); - pathDescription[i].bearing = angle; + pathDescription[i].bearing = angle*10; } } - - // BuildRouteSummary(entireLength, duration); return; } }; diff --git a/Descriptors/GPXDescriptor.h b/Descriptors/GPXDescriptor.h index 3a3ccafc2..105a09abf 100644 --- a/Descriptors/GPXDescriptor.h +++ b/Descriptors/GPXDescriptor.h @@ -44,10 +44,10 @@ public: //TODO: reorder parameters void Run( - http::Reply & reply, - const RawRouteData &rawRoute, - PhantomNodes &phantomNodes, - const DataFacadeT * facade + const RawRouteData &raw_route, + const PhantomNodes &phantom_node_list, + DataFacadeT * facade, + http::Reply & reply ) { reply.content.push_back(""); reply.content.push_back( @@ -61,38 +61,41 @@ public: " OpenStreetMap contributors (ODbL)" ""); reply.content.push_back(""); - bool found_route = (rawRoute.lengthOfShortestPath != INT_MAX) && - (rawRoute.computedShortestPath.size() ); + bool found_route = (raw_route.lengthOfShortestPath != INT_MAX) && + (raw_route.unpacked_path_segments[0].size()); if( found_route ) { - convertInternalLatLonToString( - phantomNodes.startPhantom.location.lat, + FixedPointCoordinate::convertInternalLatLonToString( + phantom_node_list.startPhantom.location.lat, tmp ); reply.content.push_back(""); - BOOST_FOREACH( - const _PathData & pathData, - rawRoute.computedShortestPath - ) { - current = facade->GetCoordinateOfNode(pathData.node); + for(unsigned i=0; i < raw_route.unpacked_path_segments.size(); ++i){ + BOOST_FOREACH( + const PathData & pathData, + raw_route.unpacked_path_segments[i] + ) { + current = facade->GetCoordinateOfNode(pathData.node); - convertInternalLatLonToString(current.lat, tmp); - reply.content.push_back(""); + FixedPointCoordinate::convertInternalLatLonToString(current.lat, tmp); + reply.content.push_back(""); + } } - convertInternalLatLonToString( - phantomNodes.targetPhantom.location.lat, + // Add the via point or the end coordinate + FixedPointCoordinate::convertInternalLatLonToString( + phantom_node_list.targetPhantom.location.lat, tmp ); reply.content.push_back(""); diff --git a/Descriptors/JSONDescriptor.h b/Descriptors/JSONDescriptor.h index 80d7a7e2d..2d367a9cc 100644 --- a/Descriptors/JSONDescriptor.h +++ b/Descriptors/JSONDescriptor.h @@ -44,9 +44,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. template class JSONDescriptor : public BaseDescriptor { private: + DataFacadeT * facade; DescriptorConfig config; DescriptionFactory description_factory; - DescriptionFactory alternateDescriptionFactory; + DescriptionFactory alternate_descriptionFactory; FixedPointCoordinate current; unsigned entered_restricted_area_count; struct RoundAbout{ @@ -68,6 +69,7 @@ private: int position; }; std::vector shortest_path_segments, alternative_path_segments; + std::vector shortest_leg_end_indices, alternative_leg_end_indices; struct RouteNames { std::string shortestPathName1; @@ -77,37 +79,72 @@ private: }; public: - JSONDescriptor() : entered_restricted_area_count(0) {} + JSONDescriptor() : + facade(NULL), + entered_restricted_area_count(0) + { + shortest_leg_end_indices.push_back(0); + alternative_leg_end_indices.push_back(0); + } + void SetConfig(const DescriptorConfig & c) { config = c; } - //TODO: reorder parameters - void Run( - http::Reply & reply, - const RawRouteData & raw_route_information, - PhantomNodes & phantom_nodes, - const DataFacadeT * facade + int DescribeLeg( + const std::vector & route_leg, + const PhantomNodes & leg_phantoms ) { + int added_element_count = 0; + //Get all the coordinates for the computed route + FixedPointCoordinate current_coordinate; + BOOST_FOREACH(const PathData & path_data, route_leg) { + current_coordinate = facade->GetCoordinateOfNode(path_data.node); + description_factory.AppendSegment(current_coordinate, path_data ); + ++added_element_count; + } + // description_factory.SetEndSegment( leg_phantoms.targetPhantom ); + ++added_element_count; + BOOST_ASSERT( (int)(route_leg.size() + 1) == added_element_count ); + return added_element_count; + } - WriteHeaderToOutput(reply.content); + void Run( + const RawRouteData & raw_route, + const PhantomNodes & phantom_nodes, + // TODO: move facade initalization to c'tor + DataFacadeT * f, + http::Reply & reply + ) { + facade = f; + reply.content.push_back( + "{\"status\":" + ); - if(raw_route_information.lengthOfShortestPath != INT_MAX) { - description_factory.SetStartSegment(phantom_nodes.startPhantom); - reply.content.push_back("0," - "\"status_message\": \"Found route between points\","); - - //Get all the coordinates for the computed route - BOOST_FOREACH(const _PathData & path_data, raw_route_information.computedShortestPath) { - current = facade->GetCoordinateOfNode(path_data.node); - description_factory.AppendSegment(current, path_data ); - } - description_factory.SetEndSegment(phantom_nodes.targetPhantom); - } else { + if(INT_MAX == raw_route.lengthOfShortestPath) { //We do not need to do much, if there is no route ;-) - reply.content.push_back("207," - "\"status_message\": \"Cannot find route between points\","); + reply.content.push_back( + "207,\"status_message\": \"Cannot find route between points\"}" + ); + return; } + description_factory.SetStartSegment(phantom_nodes.startPhantom); + reply.content.push_back("0," + "\"status_message\": \"Found route between points\","); + + BOOST_ASSERT( raw_route.unpacked_path_segments.size() == raw_route.segmentEndCoordinates.size() ); + for( unsigned i = 0; i < raw_route.unpacked_path_segments.size(); ++i ) { + const int added_segments = DescribeLeg( + raw_route.unpacked_path_segments[i], + raw_route.segmentEndCoordinates[i] + ); + BOOST_ASSERT( 0 < added_segments ); + shortest_leg_end_indices.push_back( + added_segments + shortest_leg_end_indices.back() + ); + } + description_factory.SetEndSegment(phantom_nodes.targetPhantom); description_factory.Run(facade, config.zoom_level); + reply.content.push_back("\"route_geometry\": "); if(config.geometry) { description_factory.AppendEncodedPolylineString( @@ -118,30 +155,20 @@ public: reply.content.push_back("[]"); } - reply.content.push_back("," - "\"route_instructions\": ["); - entered_restricted_area_count = 0; + reply.content.push_back(",\"route_instructions\": ["); if(config.instructions) { BuildTextualDescription( description_factory, reply, - raw_route_information.lengthOfShortestPath, + raw_route.lengthOfShortestPath, facade, shortest_path_segments ); - } else { - BOOST_FOREACH( - const SegmentInformation & segment, - description_factory.pathDescription - ) { - TurnInstruction current_instruction = segment.turnInstruction & TurnInstructions.InverseAccessRestrictionFlag; - entered_restricted_area_count += (current_instruction != segment.turnInstruction); - } } reply.content.push_back("],"); description_factory.BuildRouteSummary( description_factory.entireLength, - raw_route_information.lengthOfShortestPath - ( entered_restricted_area_count*TurnInstructions.AccessRestrictionPenalty) + raw_route.lengthOfShortestPath ); reply.content.push_back("\"route_summary\":"); @@ -167,62 +194,67 @@ public: //only one alternative route is computed at this time, so this is hardcoded - if(raw_route_information.lengthOfAlternativePath != INT_MAX) { - alternateDescriptionFactory.SetStartSegment(phantom_nodes.startPhantom); + if(raw_route.lengthOfAlternativePath != INT_MAX) { + alternate_descriptionFactory.SetStartSegment(phantom_nodes.startPhantom); //Get all the coordinates for the computed route - BOOST_FOREACH(const _PathData & path_data, raw_route_information.computedAlternativePath) { + BOOST_FOREACH(const PathData & path_data, raw_route.unpacked_alternative) { current = facade->GetCoordinateOfNode(path_data.node); - alternateDescriptionFactory.AppendSegment(current, path_data ); + alternate_descriptionFactory.AppendSegment(current, path_data ); } - alternateDescriptionFactory.SetEndSegment(phantom_nodes.targetPhantom); + alternate_descriptionFactory.SetEndSegment(phantom_nodes.targetPhantom); } - alternateDescriptionFactory.Run(facade, config.zoom_level); + alternate_descriptionFactory.Run(facade, config.zoom_level); - //give an array of alternative routes + // //give an array of alternative routes reply.content.push_back("\"alternative_geometries\": ["); - if(config.geometry && INT_MAX != raw_route_information.lengthOfAlternativePath) { + if(config.geometry && INT_MAX != raw_route.lengthOfAlternativePath) { //Generate the linestrings for each alternative - alternateDescriptionFactory.AppendEncodedPolylineString( + alternate_descriptionFactory.AppendEncodedPolylineString( config.encode_geometry, reply.content ); } reply.content.push_back("],"); reply.content.push_back("\"alternative_instructions\":["); - entered_restricted_area_count = 0; - if(INT_MAX != raw_route_information.lengthOfAlternativePath) { + if(INT_MAX != raw_route.lengthOfAlternativePath) { reply.content.push_back("["); //Generate instructions for each alternative if(config.instructions) { BuildTextualDescription( - alternateDescriptionFactory, + alternate_descriptionFactory, reply, - raw_route_information.lengthOfAlternativePath, + raw_route.lengthOfAlternativePath, facade, alternative_path_segments ); - } else { - BOOST_FOREACH(const SegmentInformation & segment, alternateDescriptionFactory.pathDescription) { - TurnInstruction current_instruction = segment.turnInstruction & TurnInstructions.InverseAccessRestrictionFlag; - entered_restricted_area_count += (current_instruction != segment.turnInstruction); - } } reply.content.push_back("]"); } reply.content.push_back("],"); reply.content.push_back("\"alternative_summaries\":["); - if(INT_MAX != raw_route_information.lengthOfAlternativePath) { + if(INT_MAX != raw_route.lengthOfAlternativePath) { //Generate route summary (length, duration) for each alternative - alternateDescriptionFactory.BuildRouteSummary(alternateDescriptionFactory.entireLength, raw_route_information.lengthOfAlternativePath - ( entered_restricted_area_count*TurnInstructions.AccessRestrictionPenalty)); + alternate_descriptionFactory.BuildRouteSummary( + alternate_descriptionFactory.entireLength, + raw_route.lengthOfAlternativePath + ); reply.content.push_back("{"); reply.content.push_back("\"total_distance\":"); - reply.content.push_back(alternateDescriptionFactory.summary.lengthString); + reply.content.push_back( + alternate_descriptionFactory.summary.lengthString + ); reply.content.push_back("," "\"total_time\":"); - reply.content.push_back(alternateDescriptionFactory.summary.durationString); + reply.content.push_back( + alternate_descriptionFactory.summary.durationString + ); reply.content.push_back("," "\"start_point\":\""); - reply.content.push_back(facade->GetEscapedNameForNameID(description_factory.summary.startName)); + reply.content.push_back( + facade->GetEscapedNameForNameID( + description_factory.summary.startName + ) + ); reply.content.push_back("\"," "\"end_point\":\""); reply.content.push_back(facade->GetEscapedNameForNameID(description_factory.summary.destName)); @@ -231,7 +263,7 @@ public: } reply.content.push_back("],"); - //Get Names for both routes + // //Get Names for both routes RouteNames routeNames; GetRouteNames(shortest_path_segments, alternative_path_segments, facade, routeNames); @@ -249,47 +281,66 @@ public: reply.content.push_back("],"); //list all viapoints so that the client may display it reply.content.push_back("\"via_points\":["); - std::string tmp; - if(config.geometry && INT_MAX != raw_route_information.lengthOfShortestPath) { - for(unsigned i = 0; i < raw_route_information.segmentEndCoordinates.size(); ++i) { - reply.content.push_back("["); - if(raw_route_information.segmentEndCoordinates[i].startPhantom.location.isSet()) - convertInternalReversedCoordinateToString(raw_route_information.segmentEndCoordinates[i].startPhantom.location, tmp); - else - convertInternalReversedCoordinateToString(raw_route_information.rawViaNodeCoordinates[i], tmp); - reply.content.push_back(tmp); - reply.content.push_back("],"); - } - reply.content.push_back("["); - if(raw_route_information.segmentEndCoordinates.back().startPhantom.location.isSet()) - convertInternalReversedCoordinateToString(raw_route_information.segmentEndCoordinates.back().targetPhantom.location, tmp); - else - convertInternalReversedCoordinateToString(raw_route_information.rawViaNodeCoordinates.back(), tmp); + BOOST_ASSERT( !raw_route.segmentEndCoordinates.empty() ); + + std::string tmp; + FixedPointCoordinate::convertInternalReversedCoordinateToString( + raw_route.segmentEndCoordinates.front().startPhantom.location, + tmp + ); + reply.content.push_back("["); + reply.content.push_back(tmp); + reply.content.push_back("]"); + + BOOST_FOREACH(const PhantomNodes & nodes, raw_route.segmentEndCoordinates) { + tmp.clear(); + FixedPointCoordinate::convertInternalReversedCoordinateToString( + nodes.targetPhantom.location, + tmp + ); + reply.content.push_back(",["); reply.content.push_back(tmp); reply.content.push_back("]"); } + + reply.content.push_back("],"); + reply.content.push_back("\"via_indices\":["); + BOOST_FOREACH(const unsigned index, shortest_leg_end_indices) { + tmp.clear(); + intToString(index, tmp); + reply.content.push_back(tmp); + if( index != shortest_leg_end_indices.back() ) { + reply.content.push_back(","); + } + } + reply.content.push_back("],\"alternative_indices\":["); + if(INT_MAX != raw_route.lengthOfAlternativePath) { + reply.content.push_back("0,"); + tmp.clear(); + intToString(alternate_descriptionFactory.pathDescription.size(), tmp); + reply.content.push_back(tmp); + } + reply.content.push_back("],"); reply.content.push_back("\"hint_data\": {"); reply.content.push_back("\"checksum\":"); - intToString(raw_route_information.checkSum, tmp); + intToString(raw_route.checkSum, tmp); reply.content.push_back(tmp); reply.content.push_back(", \"locations\": ["); std::string hint; - for(unsigned i = 0; i < raw_route_information.segmentEndCoordinates.size(); ++i) { + for(unsigned i = 0; i < raw_route.segmentEndCoordinates.size(); ++i) { reply.content.push_back("\""); - EncodeObjectToBase64(raw_route_information.segmentEndCoordinates[i].startPhantom, hint); + EncodeObjectToBase64(raw_route.segmentEndCoordinates[i].startPhantom, hint); reply.content.push_back(hint); reply.content.push_back("\", "); } - EncodeObjectToBase64(raw_route_information.segmentEndCoordinates.back().targetPhantom, hint); + EncodeObjectToBase64(raw_route.segmentEndCoordinates.back().targetPhantom, hint); reply.content.push_back("\""); reply.content.push_back(hint); reply.content.push_back("\"]"); - reply.content.push_back("},"); - reply.content.push_back("\"transactionId\": \"OSRM Routing Engine JSON Descriptor (v0.3)\""); - reply.content.push_back("}"); + reply.content.push_back("}}"); } // construct routes names @@ -357,14 +408,6 @@ public: } } - inline void WriteHeaderToOutput(std::vector & output) { - output.push_back( - "{" - "\"version\": 0.3," - "\"status\":" - ); - } - //TODO: reorder parameters inline void BuildTextualDescription( DescriptionFactory & description_factory, @@ -383,11 +426,11 @@ public: std::string tmpDist, tmpLength, tmpDuration, tmpBearing, tmpInstruction; //Fetch data from Factory and generate a string from it. BOOST_FOREACH(const SegmentInformation & segment, description_factory.pathDescription) { - TurnInstruction current_instruction = segment.turnInstruction & TurnInstructions.InverseAccessRestrictionFlag; - entered_restricted_area_count += (current_instruction != segment.turnInstruction); + TurnInstruction current_instruction = segment.turn_instruction & TurnInstructions.InverseAccessRestrictionFlag; + entered_restricted_area_count += (current_instruction != segment.turn_instruction); if(TurnInstructions.TurnIsNecessary( current_instruction) ) { if(TurnInstructions.EnterRoundAbout == current_instruction) { - roundAbout.name_id = segment.nameID; + roundAbout.name_id = segment.name_id; roundAbout.start_index = prefixSumOfNecessarySegments; } else { if(0 != prefixSumOfNecessarySegments){ @@ -407,7 +450,7 @@ public: } reply.content.push_back("\",\""); - reply.content.push_back(facade->GetEscapedNameForNameID(segment.nameID)); + reply.content.push_back(facade->GetEscapedNameForNameID(segment.name_id)); reply.content.push_back("\","); intToString(segment.length, tmpDist); reply.content.push_back(tmpDist); @@ -421,15 +464,16 @@ public: intToString(segment.length, tmpLength); reply.content.push_back(tmpLength); reply.content.push_back("m\",\""); - reply.content.push_back(Azimuth::Get(segment.bearing)); + double bearing_value = round(segment.bearing/10.); + reply.content.push_back(Azimuth::Get(bearing_value)); reply.content.push_back("\","); - intToString(round(segment.bearing), tmpBearing); + intToString(bearing_value, tmpBearing); reply.content.push_back(tmpBearing); reply.content.push_back("]"); route_segments_list.push_back( Segment( - segment.nameID, + segment.name_id, segment.length, route_segments_list.size() ) @@ -461,6 +505,6 @@ public: reply.content.push_back("]"); } } - }; + #endif /* JSON_DESCRIPTOR_H_ */ diff --git a/Extractor/BaseParser.cpp b/Extractor/BaseParser.cpp index 7b1ab140f..23464e413 100644 --- a/Extractor/BaseParser.cpp +++ b/Extractor/BaseParser.cpp @@ -26,22 +26,37 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "BaseParser.h" +#include "ExtractionWay.h" +#include "ScriptingEnvironment.h" -BaseParser::BaseParser(ExtractorCallbacks* ec, ScriptingEnvironment& se) : -extractor_callbacks(ec), scriptingEnvironment(se), luaState(NULL), use_turn_restrictions(true) { - luaState = se.getLuaStateForThreadID(0); +#include "../DataStructures/ImportNode.h" +#include "../Util/LuaUtil.h" +#include "../Util/OSRMException.h" +#include "../Util/SimpleLogger.h" + +#include +#include +#include +#include + +BaseParser::BaseParser( + ExtractorCallbacks * extractor_callbacks, + ScriptingEnvironment & scripting_environment +) : extractor_callbacks(extractor_callbacks), + lua_state(scripting_environment.getLuaStateForThreadID(0)), + scripting_environment(scripting_environment), + use_turn_restrictions(true) +{ ReadUseRestrictionsSetting(); ReadRestrictionExceptions(); } void BaseParser::ReadUseRestrictionsSetting() { - if( 0 != luaL_dostring( luaState, "return use_turn_restrictions\n") ) { - throw OSRMException( - /*lua_tostring( luaState, -1 ) + */"ERROR occured in scripting block" - ); + if( 0 != luaL_dostring( lua_state, "return use_turn_restrictions\n") ) { + throw OSRMException("ERROR occured in scripting block"); } - if( lua_isboolean( luaState, -1) ) { - use_turn_restrictions = lua_toboolean(luaState, -1); + if( lua_isboolean( lua_state, -1) ) { + use_turn_restrictions = lua_toboolean(lua_state, -1); } if( use_turn_restrictions ) { SimpleLogger().Write() << "Using turn restrictions"; @@ -51,16 +66,18 @@ void BaseParser::ReadUseRestrictionsSetting() { } void BaseParser::ReadRestrictionExceptions() { - if(lua_function_exists(luaState, "get_exceptions" )) { + if(lua_function_exists(lua_state, "get_exceptions" )) { //get list of turn restriction exceptions luabind::call_function( - luaState, + lua_state, "get_exceptions", boost::ref(restriction_exceptions) ); - SimpleLogger().Write() << "Found " << restriction_exceptions.size() << " exceptions to turn restriction"; + const unsigned exception_count = restriction_exceptions.size(); + SimpleLogger().Write() << + "Found " << exception_count << " exceptions to turn restrictions:"; BOOST_FOREACH(const std::string & str, restriction_exceptions) { - SimpleLogger().Write() << " " << str; + SimpleLogger().Write() << " " << str; } } else { SimpleLogger().Write() << "Found no exceptions to turn restrictions"; @@ -74,20 +91,32 @@ void BaseParser::report_errors(lua_State *L, const int status) const { } } -void BaseParser::ParseNodeInLua(ImportNode& n, lua_State* localLuaState) { - luabind::call_function( localLuaState, "node_function", boost::ref(n) ); +void BaseParser::ParseNodeInLua(ImportNode& n, lua_State* local_lua_state) { + luabind::call_function( + local_lua_state, + "node_function", + boost::ref(n) + ); } -void BaseParser::ParseWayInLua(ExtractionWay& w, lua_State* localLuaState) { - luabind::call_function( localLuaState, "way_function", boost::ref(w) ); +void BaseParser::ParseWayInLua(ExtractionWay& w, lua_State* local_lua_state) { + luabind::call_function( + local_lua_state, + "way_function", + boost::ref(w) + ); } -bool BaseParser::ShouldIgnoreRestriction(const std::string & except_tag_string) const { +bool BaseParser::ShouldIgnoreRestriction( + const std::string & except_tag_string +) const { //should this restriction be ignored? yes if there's an overlap between: - //a) the list of modes in the except tag of the restriction (except_tag_string), ex: except=bus;bicycle - //b) the lua profile defines a hierachy of modes, ex: [access, vehicle, bicycle] + // a) the list of modes in the except tag of the restriction + // (except_tag_string), eg: except=bus;bicycle + // b) the lua profile defines a hierachy of modes, + // eg: [access, vehicle, bicycle] - if( "" == except_tag_string ) { + if( except_tag_string.empty() ) { return false; } @@ -95,8 +124,14 @@ bool BaseParser::ShouldIgnoreRestriction(const std::string & except_tag_string) //only a few exceptions are actually defined. std::vector exceptions; boost::algorithm::split_regex(exceptions, except_tag_string, boost::regex("[;][ ]*")); - BOOST_FOREACH(std::string& str, exceptions) { - if( restriction_exceptions.end() != std::find(restriction_exceptions.begin(), restriction_exceptions.end(), str) ) { + BOOST_FOREACH(std::string& current_string, exceptions) { + std::vector::const_iterator string_iterator; + string_iterator = std::find( + restriction_exceptions.begin(), + restriction_exceptions.end(), + current_string + ); + if( restriction_exceptions.end() != string_iterator ) { return true; } } diff --git a/Extractor/BaseParser.h b/Extractor/BaseParser.h index a59073f03..98c2aeef2 100644 --- a/Extractor/BaseParser.h +++ b/Extractor/BaseParser.h @@ -28,11 +28,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef BASEPARSER_H_ #define BASEPARSER_H_ -#include "ExtractorCallbacks.h" -#include "ScriptingEnvironment.h" -#include "../Util/OSRMException.h" -#include "../Util/SimpleLogger.h" - extern "C" { #include #include @@ -40,29 +35,40 @@ extern "C" { } #include +#include +#include + +class ExtractorCallbacks; +class ScriptingEnvironment; +struct ExtractionWay; +struct ImportNode; class BaseParser : boost::noncopyable { public: - BaseParser(ExtractorCallbacks* ec, ScriptingEnvironment& se); + BaseParser( + ExtractorCallbacks * extractor_callbacks, + ScriptingEnvironment & scripting_environment + ); virtual ~BaseParser() {} virtual bool ReadHeader() = 0; virtual bool Parse() = 0; - virtual void ParseNodeInLua(ImportNode& n, lua_State* luaStateForThread); - virtual void ParseWayInLua(ExtractionWay& n, lua_State* luaStateForThread); - virtual void report_errors(lua_State *L, const int status) const; + virtual void ParseNodeInLua(ImportNode & n, lua_State* thread_lua_state); + virtual void ParseWayInLua(ExtractionWay & n, lua_State* thread_lua_state); + virtual void report_errors(lua_State * lua_state, const int status) const; protected: virtual void ReadUseRestrictionsSetting(); virtual void ReadRestrictionExceptions(); - virtual bool ShouldIgnoreRestriction(const std::string& except_tag_string) const; + virtual bool ShouldIgnoreRestriction( + const std::string & except_tag_string + ) const; - ExtractorCallbacks* extractor_callbacks; - ScriptingEnvironment& scriptingEnvironment; - lua_State* luaState; + ExtractorCallbacks * extractor_callbacks; + lua_State * lua_state; + ScriptingEnvironment & scripting_environment; std::vector restriction_exceptions; bool use_turn_restrictions; - }; #endif /* BASEPARSER_H_ */ diff --git a/Extractor/ExtractionContainers.cpp b/Extractor/ExtractionContainers.cpp index 11b2345c6..dc1a7ff60 100644 --- a/Extractor/ExtractionContainers.cpp +++ b/Extractor/ExtractionContainers.cpp @@ -26,6 +26,31 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "ExtractionContainers.h" +#include "ExtractionWay.h" +#include "../Util/SimpleLogger.h" +#include "../Util/TimingUtil.h" + +#include +#include +#include +#include + +#include + +ExtractionContainers::ExtractionContainers() { + //Check if stxxl can be instantiated + stxxl::vector dummy_vector; + name_list.push_back(""); +} + +ExtractionContainers::~ExtractionContainers() { + used_node_id_list.clear(); + all_nodes_list.clear(); + all_edges_list.clear(); + name_list.clear(); + restrictions_list.clear(); + way_start_end_id_list.clear(); +} void ExtractionContainers::PrepareData( const std::string & output_file_name, @@ -304,7 +329,7 @@ void ExtractionContainers::PrepareData( edge_iterator->targetCoord.lat = node_iterator->lat; edge_iterator->targetCoord.lon = node_iterator->lon; - const double distance = ApproximateDistance( + const double distance = FixedPointCoordinate::ApproximateDistance( edge_iterator->startCoord.lat, edge_iterator->startCoord.lon, node_iterator->lat, diff --git a/Extractor/ExtractionContainers.h b/Extractor/ExtractionContainers.h index 254c358da..8fe4d8e10 100644 --- a/Extractor/ExtractionContainers.h +++ b/Extractor/ExtractionContainers.h @@ -28,17 +28,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef EXTRACTIONCONTAINERS_H_ #define EXTRACTIONCONTAINERS_H_ +#include "InternalExtractorEdge.h" #include "ExtractorStructs.h" -#include "../Util/SimpleLogger.h" -#include "../Util/TimingUtil.h" +#include "../DataStructures/Restriction.h" #include "../Util/UUID.h" -#include -#include -#include -#include - -#include #include class ExtractionContainers { @@ -58,20 +52,9 @@ public: STXXLWayIDStartEndVector way_start_end_id_list; const UUID uuid; - ExtractionContainers() { - //Check if stxxl can be instantiated - stxxl::vector dummy_vector; - name_list.push_back(""); - } + ExtractionContainers(); - virtual ~ExtractionContainers() { - used_node_id_list.clear(); - all_nodes_list.clear(); - all_edges_list.clear(); - name_list.clear(); - restrictions_list.clear(); - way_start_end_id_list.clear(); - } + virtual ~ExtractionContainers(); void PrepareData( const std::string & output_file_name, diff --git a/Extractor/ExtractionWay.h b/Extractor/ExtractionWay.h new file mode 100644 index 000000000..addd8ce80 --- /dev/null +++ b/Extractor/ExtractionWay.h @@ -0,0 +1,78 @@ +/* + +Copyright (c) 2013, Project OSRM, Dennis Luxen, others +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef EXTRACTION_WAY_H +#define EXTRACTION_WAY_H + +#include "../DataStructures/HashTable.h" +#include "../typedefs.h" + +#include +#include + +struct ExtractionWay { + ExtractionWay() { + Clear(); + } + + inline void Clear(){ + id = UINT_MAX; + nameID = UINT_MAX; + path.clear(); + keyVals.clear(); + direction = ExtractionWay::notSure; + speed = -1; + backward_speed = -1; + duration = -1; + type = -1; + access = true; + roundabout = false; + isAccessRestricted = false; + ignoreInGrid = false; + } + + enum Directions { + notSure = 0, oneway, bidirectional, opposite + }; + unsigned id; + unsigned nameID; + double speed; + double backward_speed; + double duration; + Directions direction; + std::string name; + short type; + bool access; + bool roundabout; + bool isAccessRestricted; + bool ignoreInGrid; + std::vector< NodeID > path; + HashTable keyVals; +}; + + +#endif //EXTRACTION_WAY_H diff --git a/Extractor/ExtractorCallbacks.cpp b/Extractor/ExtractorCallbacks.cpp index 8ac71f7da..c1ef1326c 100644 --- a/Extractor/ExtractorCallbacks.cpp +++ b/Extractor/ExtractorCallbacks.cpp @@ -25,13 +25,38 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "ExtractionContainers.h" +#include "ExtractionHelperFunctions.h" +#include "ExtractionWay.h" #include "ExtractorCallbacks.h" -ExtractorCallbacks::ExtractorCallbacks() {externalMemory = NULL; stringMap = NULL; } -ExtractorCallbacks::ExtractorCallbacks(ExtractionContainers * ext, StringMap * strMap) { - externalMemory = ext; - stringMap = strMap; -} +#include "../DataStructures/Restriction.h" +#include "../Util/SimpleLogger.h" + +#include + +#include + +#include +#include +#include + +#include +#include + +ExtractorCallbacks::ExtractorCallbacks() + : + stringMap(NULL), + externalMemory(NULL) +{ } + +ExtractorCallbacks::ExtractorCallbacks( + ExtractionContainers * ext, + StringMap * strMap +) : + stringMap(strMap), + externalMemory(ext) +{ } ExtractorCallbacks::~ExtractorCallbacks() { } @@ -62,14 +87,14 @@ void ExtractorCallbacks::wayFunction(ExtractionWay &parsed_way) { parsed_way.speed = parsed_way.duration/(parsed_way.path.size()-1); } - if(std::numeric_limits::epsilon() >= fabs(-1. - parsed_way.speed)){ + if(std::numeric_limits::epsilon() >= std::abs(-1. - parsed_way.speed)){ SimpleLogger().Write(logDEBUG) << "found way with bogus speed, id: " << parsed_way.id; return; } //Get the unique identifier for the street name - const StringMap::const_iterator string_map_iterator = stringMap->find(parsed_way.name); + const StringMap::const_iterator & string_map_iterator = stringMap->find(parsed_way.name); if(stringMap->end() == string_map_iterator) { parsed_way.nameID = externalMemory->name_list.size(); externalMemory->name_list.push_back(parsed_way.name); diff --git a/Extractor/ExtractorCallbacks.h b/Extractor/ExtractorCallbacks.h index e95505762..555d19a12 100644 --- a/Extractor/ExtractorCallbacks.h +++ b/Extractor/ExtractorCallbacks.h @@ -28,29 +28,30 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef EXTRACTORCALLBACKS_H_ #define EXTRACTORCALLBACKS_H_ -#include "ExtractionContainers.h" -#include "ExtractionHelperFunctions.h" #include "ExtractorStructs.h" +#include "../typedefs.h" -#include "../DataStructures/Coordinate.h" - -#include - -#include -#include -#include - +#include #include -#include + +class ExtractionContainers; +struct ExtractionWay; +struct InputRestrictionContainer; + +typedef boost::unordered_map StringMap; class ExtractorCallbacks{ private: + StringMap * stringMap; ExtractionContainers * externalMemory; ExtractorCallbacks(); public: - explicit ExtractorCallbacks(ExtractionContainers * ext, StringMap * strMap); + explicit ExtractorCallbacks( + ExtractionContainers * ext, + StringMap * strMap + ); ~ExtractorCallbacks(); diff --git a/Extractor/ExtractorStructs.h b/Extractor/ExtractorStructs.h index 144bf7f71..3803436dd 100644 --- a/Extractor/ExtractorStructs.h +++ b/Extractor/ExtractorStructs.h @@ -28,64 +28,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef EXTRACTORSTRUCTS_H_ #define EXTRACTORSTRUCTS_H_ -#include "../DataStructures/Coordinate.h" #include "../DataStructures/HashTable.h" #include "../DataStructures/ImportNode.h" -#include "../DataStructures/QueryNode.h" -#include "../DataStructures/Restriction.h" #include "../typedefs.h" -#include -#include -#include -#include - -#include #include -typedef boost::unordered_map StringMap; -typedef boost::unordered_map > StringToIntPairMap; - -struct ExtractionWay { - ExtractionWay() { - Clear(); - } - - inline void Clear(){ - id = UINT_MAX; - nameID = UINT_MAX; - path.clear(); - keyVals.clear(); - direction = ExtractionWay::notSure; - speed = -1; - backward_speed = -1; - duration = -1; - type = -1; - access = true; - roundabout = false; - isAccessRestricted = false; - ignoreInGrid = false; - } - - enum Directions { - notSure = 0, oneway, bidirectional, opposite - }; - Directions direction; - unsigned id; - unsigned nameID; - std::string name; - double speed; - double backward_speed; - double duration; - short type; - bool access; - bool roundabout; - bool isAccessRestricted; - bool ignoreInGrid; - std::vector< NodeID > path; - HashTable keyVals; -}; - struct ExtractorRelation { ExtractorRelation() : type(unknown){} enum { @@ -94,49 +42,34 @@ struct ExtractorRelation { HashTable keyVals; }; -struct InternalExtractorEdge { - InternalExtractorEdge() : start(0), target(0), type(0), direction(0), speed(0), nameID(0), isRoundabout(false), ignoreInGrid(false), isDurationSet(false), isAccessRestricted(false), isContraFlow(false) {}; - InternalExtractorEdge(NodeID s, NodeID t) : start(s), target(t), type(0), direction(0), speed(0), nameID(0), isRoundabout(false), ignoreInGrid(false), isDurationSet(false), isAccessRestricted(false), isContraFlow(false) { } - InternalExtractorEdge(NodeID s, NodeID t, short tp, short d, double sp): start(s), target(t), type(tp), direction(d), speed(sp), nameID(0), isRoundabout(false), ignoreInGrid(false), isDurationSet(false), isAccessRestricted(false), isContraFlow(false) { } - InternalExtractorEdge(NodeID s, NodeID t, short tp, short d, double sp, unsigned nid, bool isra, bool iing, bool ids, bool iar): start(s), target(t), type(tp), direction(d), speed(sp), nameID(nid), isRoundabout(isra), ignoreInGrid(iing), isDurationSet(ids), isAccessRestricted(iar), isContraFlow(false) { - assert(0 <= type); - } - InternalExtractorEdge(NodeID s, NodeID t, short tp, short d, double sp, unsigned nid, bool isra, bool iing, bool ids, bool iar, bool icf): start(s), target(t), type(tp), direction(d), speed(sp), nameID(nid), isRoundabout(isra), ignoreInGrid(iing), isDurationSet(ids), isAccessRestricted(iar), isContraFlow(icf) { - assert(0 <= type); - } - NodeID start; - NodeID target; - short type; - short direction; - double speed; - unsigned nameID; - bool isRoundabout; - bool ignoreInGrid; - bool isDurationSet; - bool isAccessRestricted; - bool isContraFlow; - - FixedPointCoordinate startCoord; - FixedPointCoordinate targetCoord; - - static InternalExtractorEdge min_value() { - return InternalExtractorEdge(0,0); - } - static InternalExtractorEdge max_value() { - return InternalExtractorEdge((std::numeric_limits::max)(), (std::numeric_limits::max)()); - } -}; - - - struct _WayIDStartAndEndEdge { unsigned wayID; NodeID firstStart; NodeID firstTarget; NodeID lastStart; NodeID lastTarget; - _WayIDStartAndEndEdge() : wayID(UINT_MAX), firstStart(UINT_MAX), firstTarget(UINT_MAX), lastStart(UINT_MAX), lastTarget(UINT_MAX) {} - _WayIDStartAndEndEdge(unsigned w, NodeID fs, NodeID ft, NodeID ls, NodeID lt) : wayID(w), firstStart(fs), firstTarget(ft), lastStart(ls), lastTarget(lt) {} + _WayIDStartAndEndEdge() + : + wayID(UINT_MAX), + firstStart(UINT_MAX), + firstTarget(UINT_MAX), + lastStart(UINT_MAX), + lastTarget(UINT_MAX) + { } + + explicit _WayIDStartAndEndEdge( + unsigned w, + NodeID fs, + NodeID ft, + NodeID ls, + NodeID lt + ) : + wayID(w), + firstStart(fs), + firstTarget(ft), + lastStart(ls), + lastTarget(lt) + { } static _WayIDStartAndEndEdge min_value() { return _WayIDStartAndEndEdge((std::numeric_limits::min)(), (std::numeric_limits::min)(), (std::numeric_limits::min)(), (std::numeric_limits::min)(), (std::numeric_limits::min)()); @@ -146,9 +79,12 @@ struct _WayIDStartAndEndEdge { } }; -struct CmpWayByID : public std::binary_function<_WayIDStartAndEndEdge, _WayIDStartAndEndEdge, bool> { +struct CmpWayByID { typedef _WayIDStartAndEndEdge value_type; - bool operator () (const _WayIDStartAndEndEdge & a, const _WayIDStartAndEndEdge & b) const { + bool operator ()( + const _WayIDStartAndEndEdge & a, + const _WayIDStartAndEndEdge & b + ) const { return a.wayID < b.wayID; } value_type max_value() { @@ -159,9 +95,12 @@ struct CmpWayByID : public std::binary_function<_WayIDStartAndEndEdge, _WayIDSta } }; -struct Cmp : public std::binary_function { +struct Cmp { typedef NodeID value_type; - bool operator () (const NodeID a, const NodeID b) const { + bool operator ()( + const NodeID a, + const NodeID b + ) const { return a < b; } value_type max_value() { @@ -172,7 +111,7 @@ struct Cmp : public std::binary_function { } }; -struct CmpNodeByID : public std::binary_function { +struct CmpNodeByID { typedef ExternalMemoryNode value_type; bool operator () ( const ExternalMemoryNode & a, @@ -188,44 +127,4 @@ struct CmpNodeByID : public std::binary_function { - typedef InternalExtractorEdge value_type; - bool operator () (const InternalExtractorEdge & a, const InternalExtractorEdge & b) const { - return a.start < b.start; - } - value_type max_value() { - return InternalExtractorEdge::max_value(); - } - value_type min_value() { - return InternalExtractorEdge::min_value(); - } -}; - -struct CmpEdgeByTargetID : public std::binary_function { - typedef InternalExtractorEdge value_type; - bool operator () (const InternalExtractorEdge & a, const InternalExtractorEdge & b) const { - return a.target < b.target; - } - value_type max_value() { - return InternalExtractorEdge::max_value(); - } - value_type min_value() { - return InternalExtractorEdge::min_value(); - } -}; - -inline std::string GetRandomString() { - char s[128]; - static const char alphanum[] = - "0123456789" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz"; - - for (int i = 0; i < 127; ++i) { - s[i] = alphanum[rand() % (sizeof(alphanum) - 1)]; - } - s[127] = 0; - return std::string(s); -} - #endif /* EXTRACTORSTRUCTS_H_ */ diff --git a/Extractor/InternalExtractorEdge.h b/Extractor/InternalExtractorEdge.h new file mode 100644 index 000000000..3dca1fa1d --- /dev/null +++ b/Extractor/InternalExtractorEdge.h @@ -0,0 +1,207 @@ +/* + +Copyright (c) 2013, Project OSRM, Dennis Luxen, others +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef INTERNAL_EXTRACTOR_EDGE_H +#define INTERNAL_EXTRACTOR_EDGE_H + +#include + +#include "../typedefs.h" + +#include + +struct InternalExtractorEdge { + InternalExtractorEdge() + : + start(0), + target(0), + type(0), + direction(0), + speed(0), + nameID(0), + isRoundabout(false), + ignoreInGrid(false), + isDurationSet(false), + isAccessRestricted(false), + isContraFlow(false) + { } + + explicit InternalExtractorEdge(NodeID start, NodeID target) + : + start(start), + target(target), + type(0), + direction(0), + speed(0), + nameID(0), + isRoundabout(false), + ignoreInGrid(false), + isDurationSet(false), + isAccessRestricted(false), + isContraFlow(false) + { } + + explicit InternalExtractorEdge( + NodeID start, + NodeID target, + short type, + short d, + double speed + ) : + start(start), + target(target), + type(type), + direction(d), + speed(speed), + nameID(0), + isRoundabout(false), + ignoreInGrid(false), + isDurationSet(false), + isAccessRestricted(false), + isContraFlow(false) + { } + + explicit InternalExtractorEdge( + NodeID start, + NodeID target, + short type, + short direction, + double speed, + unsigned nameID, + bool isRoundabout, + bool ignoreInGrid, + bool isDurationSet, + bool isAccressRestricted + ) : + start(start), + target(target), + type(type), + direction(direction), + speed(speed), + nameID(nameID), + isRoundabout(isRoundabout), + ignoreInGrid(ignoreInGrid), + isDurationSet(isDurationSet), + isAccessRestricted(isAccressRestricted), + isContraFlow(false) + { + BOOST_ASSERT(0 <= type); + } + + explicit InternalExtractorEdge( + NodeID start, + NodeID target, + short type, + short direction, + double speed, + unsigned nameID, + bool isRoundabout, + bool ignoreInGrid, + bool isDurationSet, + bool isAccressRestricted, + bool isContraFlow + ) : + start(start), + target(target), + type(type), + direction(direction), + speed(speed), + nameID(nameID), + isRoundabout(isRoundabout), + ignoreInGrid(ignoreInGrid), + isDurationSet(isDurationSet), + isAccessRestricted(isAccressRestricted), + isContraFlow(isContraFlow) + { + BOOST_ASSERT(0 <= type); + } + + // necessary static util functions for stxxl's sorting + static InternalExtractorEdge min_value() { + return InternalExtractorEdge(0,0); + } + static InternalExtractorEdge max_value() { + return InternalExtractorEdge( + std::numeric_limits::max(), + std::numeric_limits::max() + ); + } + + NodeID start; + NodeID target; + short type; + short direction; + double speed; + unsigned nameID; + bool isRoundabout; + bool ignoreInGrid; + bool isDurationSet; + bool isAccessRestricted; + bool isContraFlow; + + FixedPointCoordinate startCoord; + FixedPointCoordinate targetCoord; +}; + +struct CmpEdgeByStartID { + typedef InternalExtractorEdge value_type; + bool operator ()( + const InternalExtractorEdge & a, + const InternalExtractorEdge & b + ) const { + return a.start < b.start; + } + + value_type max_value() { + return InternalExtractorEdge::max_value(); + } + + value_type min_value() { + return InternalExtractorEdge::min_value(); + } +}; + +struct CmpEdgeByTargetID { + typedef InternalExtractorEdge value_type; + + bool operator ()( + const InternalExtractorEdge & a, + const InternalExtractorEdge & b + ) const { + return a.target < b.target; + } + + value_type max_value() { + return InternalExtractorEdge::max_value(); + } + + value_type min_value() { + return InternalExtractorEdge::min_value(); + } +}; + +#endif //INTERNAL_EXTRACTOR_EDGE_H diff --git a/Extractor/PBFParser.cpp b/Extractor/PBFParser.cpp index 96c71603f..f229ae103 100644 --- a/Extractor/PBFParser.cpp +++ b/Extractor/PBFParser.cpp @@ -27,21 +27,45 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "PBFParser.h" -PBFParser::PBFParser(const char * fileName, ExtractorCallbacks* ec, ScriptingEnvironment& se) : BaseParser( ec, se ) { +#include "ExtractionWay.h" +#include "ExtractorCallbacks.h" +#include "ScriptingEnvironment.h" + +#include "../DataStructures/HashTable.h" +#include "../DataStructures/Restriction.h" +#include "../Util/MachineInfo.h" +#include "../Util/OpenMPWrapper.h" +#include "../Util/OSRMException.h" +#include "../Util/SimpleLogger.h" +#include "../typedefs.h" + +#include + +#include +#include +#include + +#include + +PBFParser::PBFParser( + const char * fileName, + ExtractorCallbacks * extractor_callbacks, + ScriptingEnvironment& scripting_environment +) : BaseParser( extractor_callbacks, scripting_environment ) { GOOGLE_PROTOBUF_VERIFY_VERSION; //TODO: What is the bottleneck here? Filling the queue or reading the stuff from disk? //NOTE: With Lua scripting, it is parsing the stuff. I/O is virtually for free. - threadDataQueue = boost::make_shared >( 2500 ); /* Max 2500 items in queue, hardcoded. */ + + // Max 2500 items in queue, hardcoded. + threadDataQueue = boost::make_shared >( 2500 ); input.open(fileName, std::ios::in | std::ios::binary); if (!input) { throw OSRMException("pbf file not found."); } -#ifndef NDEBUG blockCount = 0; groupCount = 0; -#endif } PBFParser::~PBFParser() { @@ -50,18 +74,17 @@ PBFParser::~PBFParser() { } // Clean up any leftover ThreadData objects in the queue - _ThreadData* td; - while (threadDataQueue->try_pop(td)) { - delete td; + _ThreadData* thread_data; + while (threadDataQueue->try_pop(thread_data)) + { + delete thread_data; } google::protobuf::ShutdownProtobufLibrary(); -#ifndef NDEBUG SimpleLogger().Write(logDEBUG) << "parsed " << blockCount << " blocks from pbf with " << groupCount << " groups"; -#endif } inline bool PBFParser::ReadHeader() { @@ -194,12 +217,15 @@ inline void PBFParser::parseDenseNode(_ThreadData * threadData) { #pragma omp parallel for schedule ( guided ) for(int i = 0; i < number_of_nodes; ++i) { - ImportNode &n = extracted_nodes_vector[i]; - ParseNodeInLua( n, scriptingEnvironment.getLuaStateForThreadID(omp_get_thread_num()) ); + ImportNode & import_node = extracted_nodes_vector[i]; + ParseNodeInLua( + import_node, + scripting_environment.getLuaStateForThreadID(omp_get_thread_num()) + ); } - BOOST_FOREACH(const ImportNode &n, extracted_nodes_vector) { - extractor_callbacks->nodeFunction(n); + BOOST_FOREACH(const ImportNode &import_node, extracted_nodes_vector) { + extractor_callbacks->nodeFunction(import_node); } } @@ -232,12 +258,12 @@ inline void PBFParser::parseRelation(_ThreadData * threadData) { break; } } - if ("restriction" == key) { - if(val.find("only_") == 0) { - isOnlyRestriction = true; - } + if ( ("restriction" == key) && (val.find("only_") == 0) ) + { + isOnlyRestriction = true; } - if ("except" == key) { + if ("except" == key) + { except_tag_string = val; } } @@ -326,18 +352,23 @@ inline void PBFParser::parseWay(_ThreadData * threadData) { #pragma omp parallel for schedule ( guided ) for(int i = 0; i < number_of_ways; ++i) { - ExtractionWay & w = parsed_way_vector[i]; - if(2 > w.path.size()) { + ExtractionWay & extraction_way = parsed_way_vector[i]; + if (2 > extraction_way.path.size()) + { continue; } - ParseWayInLua( w, scriptingEnvironment.getLuaStateForThreadID( omp_get_thread_num()) ); + ParseWayInLua( + extraction_way, + scripting_environment.getLuaStateForThreadID( omp_get_thread_num()) + ); } - BOOST_FOREACH(ExtractionWay & w, parsed_way_vector) { - if(2 > w.path.size()) { + BOOST_FOREACH(ExtractionWay & extraction_way, parsed_way_vector) { + if (2 > extraction_way.path.size()) + { continue; } - extractor_callbacks->wayFunction(w); + extractor_callbacks->wayFunction(extraction_way); } } @@ -365,9 +396,7 @@ inline void PBFParser::loadGroup(_ThreadData * threadData) { } inline void PBFParser::loadBlock(_ThreadData * threadData) { -#ifndef NDEBUG ++blockCount; -#endif threadData->currentGroupID = 0; threadData->currentEntityID = 0; } diff --git a/Extractor/PBFParser.h b/Extractor/PBFParser.h index b726fa407..91c89157b 100644 --- a/Extractor/PBFParser.h +++ b/Extractor/PBFParser.h @@ -29,24 +29,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define PBFPARSER_H_ #include "BaseParser.h" - -#include "../DataStructures/Coordinate.h" -#include "../DataStructures/HashTable.h" #include "../DataStructures/ConcurrentQueue.h" -#include "../Util/MachineInfo.h" -#include "../Util/OpenMPWrapper.h" -#include "../Util/OSRMException.h" -#include "../Util/SimpleLogger.h" -#include "../typedefs.h" #include -#include -#include #include #include -#include +#include class PBFParser : public BaseParser { @@ -73,7 +63,11 @@ class PBFParser : public BaseParser { }; public: - PBFParser(const char * fileName, ExtractorCallbacks* ec, ScriptingEnvironment& se); + PBFParser( + const char * fileName, + ExtractorCallbacks* ec, + ScriptingEnvironment& se + ); virtual ~PBFParser(); inline bool ReadHeader(); @@ -99,11 +93,8 @@ private: static const int MAX_BLOB_HEADER_SIZE = 64 * 1024; static const int MAX_BLOB_SIZE = 32 * 1024 * 1024; -#ifndef NDEBUG - /* counting the number of read blocks and groups */ unsigned groupCount; unsigned blockCount; -#endif std::fstream input; // the input stream to parse boost::shared_ptr > threadDataQueue; diff --git a/Extractor/ScriptingEnvironment.cpp b/Extractor/ScriptingEnvironment.cpp index 82d30b8d7..d904b649a 100644 --- a/Extractor/ScriptingEnvironment.cpp +++ b/Extractor/ScriptingEnvironment.cpp @@ -27,6 +27,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "ScriptingEnvironment.h" +#include "ExtractionHelperFunctions.h" +#include "ExtractionWay.h" +#include "../DataStructures/ImportNode.h" +#include "../Util/LuaUtil.h" +#include "../Util/OpenMPWrapper.h" +#include "../Util/OSRMException.h" +#include "../Util/SimpleLogger.h" +#include "../typedefs.h" + ScriptingEnvironment::ScriptingEnvironment() {} ScriptingEnvironment::ScriptingEnvironment(const char * fileName) { SimpleLogger().Write() << "Using script " << fileName; diff --git a/Extractor/ScriptingEnvironment.h b/Extractor/ScriptingEnvironment.h index 3e00f4c73..de3e96e8d 100644 --- a/Extractor/ScriptingEnvironment.h +++ b/Extractor/ScriptingEnvironment.h @@ -28,17 +28,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef SCRIPTINGENVIRONMENT_H_ #define SCRIPTINGENVIRONMENT_H_ -#include "ExtractionHelperFunctions.h" -#include "ExtractorStructs.h" -#include "../DataStructures/ImportNode.h" -#include "../Util/LuaUtil.h" -#include "../Util/OpenMPWrapper.h" -#include "../Util/OSRMException.h" -#include "../Util/SimpleLogger.h" -#include "../typedefs.h" - #include +struct lua_State; + class ScriptingEnvironment { public: ScriptingEnvironment(); diff --git a/Extractor/XMLParser.cpp b/Extractor/XMLParser.cpp index c67e5c177..26c31ebd2 100644 --- a/Extractor/XMLParser.cpp +++ b/Extractor/XMLParser.cpp @@ -27,16 +27,20 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "XMLParser.h" -#include "ExtractorStructs.h" +#include "ExtractionWay.h" #include "../DataStructures/HashTable.h" +#include "../DataStructures/ImportNode.h" #include "../DataStructures/InputReaderFactory.h" +#include "../DataStructures/Restriction.h" +#include "../Util/SimpleLogger.h" +#include "../Util/StringUtil.h" +#include "../typedefs.h" + +#include #include XMLParser::XMLParser(const char * filename, ExtractorCallbacks* ec, ScriptingEnvironment& se) : BaseParser(ec, se) { - SimpleLogger().Write(logWARNING) << - "Parsing plain .osm/.osm.bz2 is deprecated. Switch to .pbf"; - inputReader = inputReaderFactory(filename); } @@ -59,7 +63,7 @@ bool XMLParser::Parse() { if ( xmlStrEqual( currentName, ( const xmlChar* ) "node" ) == 1 ) { ImportNode n = _ReadXMLNode(); - ParseNodeInLua( n, luaState ); + ParseNodeInLua( n, lua_state ); extractor_callbacks->nodeFunction(n); // if(!extractor_callbacks->nodeFunction(n)) // std::cerr << "[XMLParser] dense node not parsed" << std::endl; @@ -67,7 +71,7 @@ bool XMLParser::Parse() { if ( xmlStrEqual( currentName, ( const xmlChar* ) "way" ) == 1 ) { ExtractionWay way = _ReadXMLWay( ); - ParseWayInLua( way, luaState ); + ParseWayInLua( way, lua_state ); extractor_callbacks->wayFunction(way); // if(!extractor_callbacks->wayFunction(way)) // std::cerr << "[PBFParser] way not parsed" << std::endl; diff --git a/Extractor/XMLParser.h b/Extractor/XMLParser.h index 99e72b69e..9e307fcc1 100644 --- a/Extractor/XMLParser.h +++ b/Extractor/XMLParser.h @@ -28,18 +28,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef XMLPARSER_H_ #define XMLPARSER_H_ +#include "ExtractorCallbacks.h" #include "BaseParser.h" -#include "../DataStructures/Coordinate.h" -#include "../Util/SimpleLogger.h" -#include "../Util/StringUtil.h" -#include "../typedefs.h" #include class XMLParser : public BaseParser { public: - XMLParser(const char* filename, ExtractorCallbacks* ec, ScriptingEnvironment& se); + XMLParser( + const char* filename, + ExtractorCallbacks* ec, + ScriptingEnvironment& se + ); bool ReadHeader(); bool Parse(); diff --git a/Include/osrm/Coordinate.h b/Include/osrm/Coordinate.h new file mode 100644 index 000000000..1f7a27a28 --- /dev/null +++ b/Include/osrm/Coordinate.h @@ -0,0 +1,84 @@ +/* + +Copyright (c) 2013, Project OSRM, Dennis Luxen, others +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef FIXED_POINT_COORDINATE_H_ +#define FIXED_POINT_COORDINATE_H_ + +#include + +static const double COORDINATE_PRECISION = 1000000.; + +struct FixedPointCoordinate { + int lat; + int lon; + + FixedPointCoordinate(); + explicit FixedPointCoordinate (int lat, int lon); + void Reset(); + bool isSet() const; + bool isValid() const; + bool operator==(const FixedPointCoordinate & other) const; + + static double ApproximateDistance( + const int lat1, + const int lon1, + const int lat2, + const int lon2 + ); + + static double ApproximateDistance( + const FixedPointCoordinate & c1, + const FixedPointCoordinate & c2 + ); + + static double ApproximateEuclideanDistance( + const FixedPointCoordinate & c1, + const FixedPointCoordinate & c2 + ); + + static void convertInternalLatLonToString( + const int value, + std::string & output + ); + + static void convertInternalCoordinateToString( + const FixedPointCoordinate & coord, + std::string & output + ); + + static void convertInternalReversedCoordinateToString( + const FixedPointCoordinate & coord, + std::string & output + ); +}; + +inline std::ostream & operator<<(std::ostream & out, const FixedPointCoordinate & c){ + out << "(" << c.lat << "," << c.lon << ")"; + return out; +} + +#endif /* FIXED_POINT_COORDINATE_H_ */ diff --git a/Server/Http/Header.h b/Include/osrm/Header.h similarity index 99% rename from Server/Http/Header.h rename to Include/osrm/Header.h index 833af27d3..29c300061 100644 --- a/Server/Http/Header.h +++ b/Include/osrm/Header.h @@ -43,4 +43,3 @@ namespace http { } #endif //HTTP_HEADER_H - diff --git a/Server/Http/Reply.h b/Include/osrm/Reply.h similarity index 76% rename from Server/Http/Reply.h rename to Include/osrm/Reply.h index 635b62d03..8e9b31750 100644 --- a/Server/Http/Reply.h +++ b/Include/osrm/Reply.h @@ -29,10 +29,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define REPLY_H #include "Header.h" -#include "../../Util/StringUtil.h" #include -#include #include @@ -48,24 +46,26 @@ const std::string badRequestString = "HTTP/1.0 400 Bad Request\r\n"; const std::string internalServerErrorString = "HTTP/1.0 500 Internal Server Error\r\n"; class Reply { - public: +public: enum status_type { - ok = 200, - badRequest = 400, - internalServerError = 500 - } status; + ok = 200, + badRequest = 400, + internalServerError = 500 + } status; - std::vector
headers; - std::vector toBuffers(); - std::vector HeaderstoBuffers(); - std::vector content; - static Reply StockReply(status_type status); - void setSize(const unsigned size); - Reply(); - private: - static std::string ToString(Reply::status_type status); - boost::asio::const_buffer ToBuffer(Reply::status_type status); + std::vector
headers; + std::vector toBuffers(); + std::vector HeaderstoBuffers(); + std::vector content; + static Reply StockReply(status_type status); + void setSize(const unsigned size); + void SetUncompressedSize(); + + Reply(); +private: + static std::string ToString(Reply::status_type status); + boost::asio::const_buffer ToBuffer(Reply::status_type status); }; } diff --git a/Server/DataStructures/RouteParameters.h b/Include/osrm/RouteParameters.h similarity index 92% rename from Server/DataStructures/RouteParameters.h rename to Include/osrm/RouteParameters.h index ce0653e5a..b35a0cf60 100644 --- a/Server/DataStructures/RouteParameters.h +++ b/Include/osrm/RouteParameters.h @@ -28,8 +28,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ROUTE_PARAMETERS_H #define ROUTE_PARAMETERS_H -#include "../../DataStructures/Coordinate.h" -#include "../../DataStructures/HashTable.h" +#include #include #include @@ -46,7 +45,9 @@ struct RouteParameters { geometry(true), compression(true), deprecatedAPI(false), - checkSum(-1) {} + checkSum(-1) + { } + short zoomLevel; bool printInstructions; bool alternateRoute; @@ -60,10 +61,9 @@ struct RouteParameters { std::string language; std::vector hints; std::vector coordinates; - typedef HashTable::const_iterator OptionsIterator; void setZoomLevel(const short i) { - if (18 > i && 0 < i) { + if (18 >= i && 0 <= i) { zoomLevel = i; } } @@ -97,8 +97,10 @@ struct RouteParameters { } void addHint(const std::string & s) { - hints.resize(coordinates.size()); - hints.back() = s; + hints.resize( coordinates.size() ); + if( !hints.empty() ) { + hints.back() = s; + } } void setLanguage(const std::string & s) { diff --git a/cmake/size.cpp b/Include/osrm/ServerPaths.h similarity index 84% rename from cmake/size.cpp rename to Include/osrm/ServerPaths.h index 5cd002333..d804f49e9 100644 --- a/cmake/size.cpp +++ b/Include/osrm/ServerPaths.h @@ -24,12 +24,15 @@ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include -int main( int argc, char* argv[] ) { - size_t size = sizeof(void*); - if ( 4 == size ) { - return 0; - } - return 1; -} +#ifndef SERVER_PATH_H +#define SERVER_PATH_H + +#include +#include + +#include + +typedef boost::unordered_map ServerPaths; + +#endif //SERVER_PATH_H diff --git a/Library/OSRM.h b/Library/OSRM.h index a2d58e73b..738c977a0 100644 --- a/Library/OSRM.h +++ b/Library/OSRM.h @@ -28,38 +28,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef OSRM_H #define OSRM_H -#include "OSRM.h" +#include -#include "../Plugins/BasePlugin.h" -#include "../Plugins/HelloWorldPlugin.h" -#include "../Plugins/LocatePlugin.h" -#include "../Plugins/NearestPlugin.h" -#include "../Plugins/TimestampPlugin.h" -#include "../Plugins/ViaRoutePlugin.h" -#include "../Server/DataStructures/BaseDataFacade.h" -#include "../Server/DataStructures/InternalDataFacade.h" -#include "../Server/DataStructures/SharedBarriers.h" -#include "../Server/DataStructures/SharedDataFacade.h" -#include "../Server/DataStructures/RouteParameters.h" -#include "../Util/InputFileUtil.h" -#include "../Util/OSRMException.h" -#include "../Util/SimpleLogger.h" +#include +#include +#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +class OSRM_impl; -#include - -class OSRM : boost::noncopyable { +class OSRM { private: - typedef boost::unordered_map PluginMap; + OSRM_impl * OSRM_pimpl_; public: OSRM( const ServerPaths & paths, @@ -67,14 +46,6 @@ public: ); ~OSRM(); void RunQuery(RouteParameters & route_parameters, http::Reply & reply); - -private: - void RegisterPlugin(BasePlugin * plugin); - PluginMap plugin_map; - bool use_shared_memory; - SharedBarriers barrier; - //base class pointer to the objects - BaseDataFacade * query_data_facade; }; -#endif //OSRM_H +#endif // OSRM_H diff --git a/Library/OSRM.cpp b/Library/OSRM_impl.cpp similarity index 71% rename from Library/OSRM.cpp rename to Library/OSRM_impl.cpp index 2ffcee1a6..51846ab26 100644 --- a/Library/OSRM.cpp +++ b/Library/OSRM_impl.cpp @@ -26,17 +26,35 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "OSRM.h" +#include "OSRM_impl.h" -OSRM::OSRM( const ServerPaths & server_paths, const bool use_shared_memory ) +#include "../Plugins/HelloWorldPlugin.h" +#include "../Plugins/LocatePlugin.h" +#include "../Plugins/NearestPlugin.h" +#include "../Plugins/TimestampPlugin.h" +#include "../Plugins/ViaRoutePlugin.h" + +#include "../Server/DataStructures/BaseDataFacade.h" +#include "../Server/DataStructures/InternalDataFacade.h" +#include "../Server/DataStructures/SharedBarriers.h" +#include "../Server/DataStructures/SharedDataFacade.h" + +#include + +OSRM_impl::OSRM_impl( const ServerPaths & server_paths, const bool use_shared_memory ) : use_shared_memory(use_shared_memory) { - if( !use_shared_memory ) { + if (use_shared_memory) + { + barrier = new SharedBarriers(); + query_data_facade = new SharedDataFacade( ); + } + else + { query_data_facade = new InternalDataFacade( server_paths ); - } else { - query_data_facade = new SharedDataFacade( ); } //The following plugins handle all requests. @@ -65,13 +83,16 @@ OSRM::OSRM( const ServerPaths & server_paths, const bool use_shared_memory ) ); } -OSRM::~OSRM() { +OSRM_impl::~OSRM_impl() { BOOST_FOREACH(PluginMap::value_type & plugin_pointer, plugin_map) { delete plugin_pointer.second; } + if( use_shared_memory ) { + delete barrier; + } } -void OSRM::RegisterPlugin(BasePlugin * plugin) { +void OSRM_impl::RegisterPlugin(BasePlugin * plugin) { SimpleLogger().Write() << "loaded plugin: " << plugin->GetDescriptor(); if( plugin_map.find(plugin->GetDescriptor()) != plugin_map.end() ) { delete plugin_map.find(plugin->GetDescriptor())->second; @@ -79,7 +100,7 @@ void OSRM::RegisterPlugin(BasePlugin * plugin) { plugin_map.emplace(plugin->GetDescriptor(), plugin); } -void OSRM::RunQuery(RouteParameters & route_parameters, http::Reply & reply) { +void OSRM_impl::RunQuery(RouteParameters & route_parameters, http::Reply & reply) { const PluginMap::const_iterator & iter = plugin_map.find( route_parameters.service ); @@ -90,18 +111,18 @@ void OSRM::RunQuery(RouteParameters & route_parameters, http::Reply & reply) { // lock update pending boost::interprocess::scoped_lock< boost::interprocess::named_mutex - > pending_lock(barrier.pending_update_mutex); + > pending_lock(barrier->pending_update_mutex); // lock query boost::interprocess::scoped_lock< boost::interprocess::named_mutex - > query_lock(barrier.query_mutex); + > query_lock(barrier->query_mutex); // unlock update pending pending_lock.unlock(); // increment query count - ++(barrier.number_of_queries); + ++(barrier->number_of_queries); (static_cast* >(query_data_facade))->CheckAndReloadFacade(); } @@ -111,21 +132,36 @@ void OSRM::RunQuery(RouteParameters & route_parameters, http::Reply & reply) { // lock query boost::interprocess::scoped_lock< boost::interprocess::named_mutex - > query_lock(barrier.query_mutex); + > query_lock(barrier->query_mutex); // decrement query count - --(barrier.number_of_queries); + --(barrier->number_of_queries); BOOST_ASSERT_MSG( - 0 <= barrier.number_of_queries, + 0 <= barrier->number_of_queries, "invalid number of queries" ); // notify all processes that were waiting for this condition - if (0 == barrier.number_of_queries) { - barrier.no_running_queries_condition.notify_all(); + if (0 == barrier->number_of_queries) { + barrier->no_running_queries_condition.notify_all(); } } } else { reply = http::Reply::StockReply(http::Reply::badRequest); } } + +// proxy code for compilation firewall + +OSRM::OSRM( + const ServerPaths & paths, + const bool use_shared_memory +) : OSRM_pimpl_(new OSRM_impl(paths, use_shared_memory)) { } + +OSRM::~OSRM() { + delete OSRM_pimpl_; +} + +void OSRM::RunQuery(RouteParameters & route_parameters, http::Reply & reply) { + OSRM_pimpl_->RunQuery(route_parameters, reply); +} diff --git a/Library/OSRM_impl.h b/Library/OSRM_impl.h new file mode 100644 index 000000000..a96071b54 --- /dev/null +++ b/Library/OSRM_impl.h @@ -0,0 +1,65 @@ +/* + +Copyright (c) 2013, Project OSRM, Dennis Luxen, others +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef OSRM_IMPL_H +#define OSRM_IMPL_H + +#include +#include +#include + +#include "../DataStructures/QueryEdge.h" +#include "../Plugins/BasePlugin.h" +#include "../Util/ProgramOptions.h" + +#include + +struct SharedBarriers; +template +class BaseDataFacade; + +class OSRM_impl : boost::noncopyable { +private: + typedef boost::unordered_map PluginMap; +public: + OSRM_impl( + const ServerPaths & paths, + const bool use_shared_memory + ); + virtual ~OSRM_impl(); + void RunQuery(RouteParameters & route_parameters, http::Reply & reply); + +private: + void RegisterPlugin(BasePlugin * plugin); + PluginMap plugin_map; + bool use_shared_memory; + SharedBarriers * barrier; + //base class pointer to the objects + BaseDataFacade * query_data_facade; +}; + +#endif //OSRM_IMPL_H diff --git a/Plugins/BasePlugin.h b/Plugins/BasePlugin.h index 037b63580..bf1ecf90f 100644 --- a/Plugins/BasePlugin.h +++ b/Plugins/BasePlugin.h @@ -28,9 +28,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef BASEPLUGIN_H_ #define BASEPLUGIN_H_ -#include "../DataStructures/Coordinate.h" -#include "../Server/DataStructures/RouteParameters.h" -#include "../Server/Http/Reply.h" +#include +#include +#include #include #include diff --git a/Plugins/LocatePlugin.h b/Plugins/LocatePlugin.h index 85603fc53..7994b0edf 100644 --- a/Plugins/LocatePlugin.h +++ b/Plugins/LocatePlugin.h @@ -68,7 +68,6 @@ public: } reply.status = http::Reply::ok; reply.content.push_back ("{"); - reply.content.push_back ("\"version\":0.3,"); if( !facade->LocateClosestEndPointForCoordinate( routeParameters.coordinates[0], @@ -82,15 +81,14 @@ public: reply.status = http::Reply::ok; reply.content.push_back ("\"status\":0,"); reply.content.push_back ("\"mapped_coordinate\":"); - convertInternalLatLonToString(result.lat, tmp); + FixedPointCoordinate::convertInternalLatLonToString(result.lat, tmp); reply.content.push_back("["); reply.content.push_back(tmp); - convertInternalLatLonToString(result.lon, tmp); + FixedPointCoordinate::convertInternalLatLonToString(result.lon, tmp); reply.content.push_back(","); reply.content.push_back(tmp); reply.content.push_back("]"); } - reply.content.push_back(",\"transactionId\": \"OSRM Routing Engine JSON Locate (v0.3)\""); reply.content.push_back("}"); reply.headers.resize(3); if(!routeParameters.jsonpParameter.empty()) { diff --git a/Plugins/NearestPlugin.h b/Plugins/NearestPlugin.h index e3a2f53e0..5a4bcbab7 100644 --- a/Plugins/NearestPlugin.h +++ b/Plugins/NearestPlugin.h @@ -25,13 +25,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef NearestPlugin_H_ -#define NearestPlugin_H_ +#ifndef NEAREST_PLUGIN_H +#define NEAREST_PLUGIN_H #include "BasePlugin.h" #include "../DataStructures/PhantomNodes.h" #include "../Util/StringUtil.h" +#include + /* * This Plugin locates the nearest point on a street in the road network for a given coordinate. */ @@ -44,11 +46,15 @@ public: facade(facade), descriptor_string("nearest") { - descriptorTable.insert(std::make_pair("" , 0)); //default descriptor - descriptorTable.insert(std::make_pair("json", 1)); + descriptorTable.emplace("", 0); //default descriptor + descriptorTable.emplace("json", 1); } const std::string & GetDescriptor() const { return descriptor_string; } - void HandleRequest(const RouteParameters & routeParameters, http::Reply& reply) { + + void HandleRequest( + const RouteParameters & routeParameters, + http::Reply& reply + ) { //check number of parameters if(!routeParameters.coordinates.size()) { reply = http::Reply::StockReply(http::Reply::badRequest); @@ -75,32 +81,26 @@ public: } reply.status = http::Reply::ok; - reply.content.push_back("{"); - reply.content.push_back("\"version\":0.3,"); - reply.content.push_back("\"status\":"); + reply.content.push_back("{\"status\":"); if(UINT_MAX != result.edgeBasedNode) { reply.content.push_back("0,"); } else { reply.content.push_back("207,"); } - reply.content.push_back("\"mapped_coordinate\":"); - reply.content.push_back("["); + reply.content.push_back("\"mapped_coordinate\":["); if(UINT_MAX != result.edgeBasedNode) { - convertInternalLatLonToString(result.location.lat, temp_string); + FixedPointCoordinate::convertInternalLatLonToString(result.location.lat, temp_string); reply.content.push_back(temp_string); - convertInternalLatLonToString(result.location.lon, temp_string); + FixedPointCoordinate::convertInternalLatLonToString(result.location.lon, temp_string); reply.content.push_back(","); reply.content.push_back(temp_string); } - reply.content.push_back("],"); - reply.content.push_back("\"name\":\""); + reply.content.push_back("],\"name\":\""); if(UINT_MAX != result.edgeBasedNode) { facade->GetName(result.nodeBasedEdgeNameID, temp_string); reply.content.push_back(temp_string); } - reply.content.push_back("\""); - reply.content.push_back(",\"transactionId\":\"OSRM Routing Engine JSON Nearest (v0.3)\""); - reply.content.push_back("}"); + reply.content.push_back("\"}"); reply.headers.resize(3); if( !routeParameters.jsonpParameter.empty() ) { reply.content.push_back(")"); @@ -125,8 +125,8 @@ public: private: DataFacadeT * facade; - HashTable descriptorTable; + boost::unordered_map descriptorTable; std::string descriptor_string; }; -#endif /* NearestPlugin_H_ */ +#endif /* NEAREST_PLUGIN_H */ diff --git a/Plugins/TimestampPlugin.h b/Plugins/TimestampPlugin.h index e863a4c00..7d46a9c1a 100644 --- a/Plugins/TimestampPlugin.h +++ b/Plugins/TimestampPlugin.h @@ -48,13 +48,11 @@ public: reply.status = http::Reply::ok; reply.content.push_back("{"); - reply.content.push_back("\"version\":0.3,"); reply.content.push_back("\"status\":"); reply.content.push_back("0,"); reply.content.push_back("\"timestamp\":\""); reply.content.push_back(facade->GetTimestamp()); reply.content.push_back("\""); - reply.content.push_back(",\"transactionId\":\"OSRM Routing Engine JSON timestamp (v0.3)\""); reply.content.push_back("}"); reply.headers.resize(3); if("" != routeParameters.jsonpParameter) { diff --git a/Plugins/ViaRoutePlugin.h b/Plugins/ViaRoutePlugin.h index 8ca74e7ef..6f2880e04 100644 --- a/Plugins/ViaRoutePlugin.h +++ b/Plugins/ViaRoutePlugin.h @@ -83,7 +83,7 @@ public: RawRouteData rawRoute; rawRoute.checkSum = facade->GetCheckSum(); - bool checksumOK = (routeParameters.checkSum == rawRoute.checkSum); + const bool checksumOK = (routeParameters.checkSum == rawRoute.checkSum); std::vector textCoord; for(unsigned i = 0; i < routeParameters.coordinates.size(); ++i) { if( !checkCoord(routeParameters.coordinates[i]) ) { @@ -110,12 +110,13 @@ public: ); } + PhantomNodes segmentPhantomNodes; for(unsigned i = 0; i < phantomNodeVector.size()-1; ++i) { - PhantomNodes segmentPhantomNodes; segmentPhantomNodes.startPhantom = phantomNodeVector[i]; segmentPhantomNodes.targetPhantom = phantomNodeVector[i+1]; rawRoute.segmentEndCoordinates.push_back(segmentPhantomNodes); } + if( ( routeParameters.alternateRoute ) && (1 == rawRoute.segmentEndCoordinates.size()) @@ -175,7 +176,7 @@ public: phantomNodes.targetPhantom = rawRoute.segmentEndCoordinates[rawRoute.segmentEndCoordinates.size()-1].targetPhantom; desc->SetConfig(descriptorConfig); - desc->Run(reply, rawRoute, phantomNodes, facade); + desc->Run(rawRoute, phantomNodes, facade, reply); if("" != routeParameters.jsonpParameter) { reply.content.push_back(")\n"); } diff --git a/RoutingAlgorithms/AlternativePathRouting.h b/RoutingAlgorithms/AlternativePathRouting.h index 9f0fdeaa2..80a410e1e 100644 --- a/RoutingAlgorithms/AlternativePathRouting.h +++ b/RoutingAlgorithms/AlternativePathRouting.h @@ -31,6 +31,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "BasicRoutingInterface.h" #include "../DataStructures/SearchEngineData.h" +#include #include #include #include @@ -77,7 +78,8 @@ public: void operator()( const PhantomNodes & phantom_node_pair, - RawRouteData & raw_route_data) { + RawRouteData & raw_route_data + ) { if( (!phantom_node_pair.AtLeastOnePhantomNodeIsUINTMAX()) || phantom_node_pair.PhantomNodesHaveEqualLocation() ) { @@ -212,12 +214,19 @@ public: approximated_reverse_sharing[v] = reverse_heap1.GetKey(u); } else { //sharing (s) = sharing (t) - approximated_reverse_sharing[v] = approximated_reverse_sharing[u]; + boost::unordered_map::const_iterator rev_iterator = approximated_reverse_sharing.find(u); + const int rev_sharing = (rev_iterator != approximated_reverse_sharing.end()) ? rev_iterator->second : 0; + approximated_reverse_sharing[v] = rev_sharing; } } std::vector nodes_that_passed_preselection; BOOST_FOREACH(const NodeID node, via_node_candidate_list) { - int approximated_sharing = approximated_forward_sharing[node] + approximated_reverse_sharing[node]; + boost::unordered_map::const_iterator fwd_iterator = approximated_forward_sharing.find(node); + const int fwd_sharing = (fwd_iterator != approximated_forward_sharing.end()) ? fwd_iterator->second : 0; + boost::unordered_map::const_iterator rev_iterator = approximated_reverse_sharing.find(node); + const int rev_sharing = (rev_iterator != approximated_reverse_sharing.end()) ? rev_iterator->second : 0; + + int approximated_sharing = fwd_sharing + rev_sharing; int approximated_length = forward_heap1.GetKey(node)+reverse_heap1.GetKey(node); bool lengthPassed = (approximated_length < upper_bound_to_shortest_path_distance*(1+VIAPATH_EPSILON)); bool sharingPassed = (approximated_sharing <= upper_bound_to_shortest_path_distance*VIAPATH_GAMMA); @@ -255,16 +264,18 @@ public: } } + //Unpack shortest path and alternative, if they exist if(INT_MAX != upper_bound_to_shortest_path_distance) { - super::UnpackPath(packedShortestPath, raw_route_data.computedShortestPath); + raw_route_data.unpacked_path_segments.resize(1); + super::UnpackPath(packedShortestPath, raw_route_data.unpacked_path_segments[0]); raw_route_data.lengthOfShortestPath = upper_bound_to_shortest_path_distance; } else { raw_route_data.lengthOfShortestPath = INT_MAX; } if(selectedViaNode != UINT_MAX) { - retrievePackedViaPath(forward_heap1, reverse_heap1, forward_heap2, reverse_heap2, s_v_middle, v_t_middle, raw_route_data.computedAlternativePath); + retrievePackedViaPath(forward_heap1, reverse_heap1, forward_heap2, reverse_heap2, s_v_middle, v_t_middle, raw_route_data.unpacked_alternative); raw_route_data.lengthOfAlternativePath = lengthOfViaPath; } else { raw_route_data.lengthOfAlternativePath = INT_MAX; @@ -274,7 +285,7 @@ public: private: //unpack by exploring search spaces from v inline void retrievePackedViaPath(QueryHeap & _forwardHeap1, QueryHeap & _backwardHeap1, QueryHeap & _forwardHeap2, QueryHeap & _backwardHeap2, - const NodeID s_v_middle, const NodeID v_t_middle, std::vector<_PathData> & unpackedPath) { + const NodeID s_v_middle, const NodeID v_t_middle, std::vector & unpackedPath) { //unpack [s,v) std::vector packed_s_v_path, packed_v_t_path; super::RetrievePackedPathFromHeap(_forwardHeap1, _backwardHeap2, s_v_middle, packed_s_v_path); @@ -305,19 +316,19 @@ private: std::vector partiallyUnpackedViaPath; NodeID s_v_middle = UINT_MAX; - int upperBoundFor_s_v_Path = INT_MAX;//compute path by reusing forward search from s + int upperBoundFor_s_vPath = INT_MAX;//compute path by reusing forward search from s newBackwardHeap.Insert(via_node, 0, via_node); while (0 < newBackwardHeap.Size()) { - super::RoutingStep(newBackwardHeap, existingForwardHeap, &s_v_middle, &upperBoundFor_s_v_Path, 2 * offset, false); + super::RoutingStep(newBackwardHeap, existingForwardHeap, &s_v_middle, &upperBoundFor_s_vPath, 2 * offset, false); } //compute path by reusing backward search from node t NodeID v_t_middle = UINT_MAX; - int upperBoundFor_v_t_Path = INT_MAX; + int upperBoundFor_v_tPath = INT_MAX; newForwardHeap.Insert(via_node, 0, via_node); while (0 < newForwardHeap.Size() ) { - super::RoutingStep(newForwardHeap, existingBackwardHeap, &v_t_middle, &upperBoundFor_v_t_Path, 2 * offset, true); + super::RoutingStep(newForwardHeap, existingBackwardHeap, &v_t_middle, &upperBoundFor_v_tPath, 2 * offset, true); } - *real_length_of_via_path = upperBoundFor_s_v_Path + upperBoundFor_v_t_Path; + *real_length_of_via_path = upperBoundFor_s_vPath + upperBoundFor_v_tPath; if(UINT_MAX == s_v_middle || UINT_MAX == v_t_middle) return; @@ -469,28 +480,28 @@ private: std::vector < NodeID > packed_v_t_path; *s_v_middle = UINT_MAX; - int upperBoundFor_s_v_Path = INT_MAX; + int upperBoundFor_s_vPath = INT_MAX; //compute path by reusing forward search from s newBackwardHeap.Insert(candidate.node, 0, candidate.node); while (newBackwardHeap.Size() > 0) { - super::RoutingStep(newBackwardHeap, existingForwardHeap, s_v_middle, &upperBoundFor_s_v_Path, 2*offset, false); + super::RoutingStep(newBackwardHeap, existingForwardHeap, s_v_middle, &upperBoundFor_s_vPath, 2*offset, false); } - if(INT_MAX == upperBoundFor_s_v_Path) + if(INT_MAX == upperBoundFor_s_vPath) return false; //compute path by reusing backward search from t *v_t_middle = UINT_MAX; - int upperBoundFor_v_t_Path = INT_MAX; + int upperBoundFor_v_tPath = INT_MAX; newForwardHeap.Insert(candidate.node, 0, candidate.node); while (newForwardHeap.Size() > 0) { - super::RoutingStep(newForwardHeap, existingBackwardHeap, v_t_middle, &upperBoundFor_v_t_Path, 2*offset, true); + super::RoutingStep(newForwardHeap, existingBackwardHeap, v_t_middle, &upperBoundFor_v_tPath, 2*offset, true); } - if(INT_MAX == upperBoundFor_v_t_Path) + if(INT_MAX == upperBoundFor_v_tPath) return false; - *lengthOfViaPath = upperBoundFor_s_v_Path + upperBoundFor_v_t_Path; + *lengthOfViaPath = upperBoundFor_s_vPath + upperBoundFor_v_tPath; //retrieve packed paths super::RetrievePackedPathFromHeap(existingForwardHeap, newBackwardHeap, *s_v_middle, packed_s_v_path); @@ -547,7 +558,7 @@ private: } } - int lengthOfPathT_Test_Path = unpackedUntilDistance; + int lengthOfPathT_TestPath = unpackedUntilDistance; unpackedUntilDistance = 0; //Traverse path s-->v for (unsigned i = 0, lengthOfPackedPath = packed_v_t_path.size() - 1; (i < lengthOfPackedPath) && unpackStack.empty(); ++i) { @@ -587,7 +598,7 @@ private: } } - lengthOfPathT_Test_Path += unpackedUntilDistance; + lengthOfPathT_TestPath += unpackedUntilDistance; //Run actual T-Test query and compare if distances equal. engine_working_data.InitializeOrClearThirdThreadLocalStorage( super::facade->GetNumberOfNodes() @@ -608,7 +619,7 @@ private: super::RoutingStep(backward_heap3, forward_heap3, &middle, &_upperBound, offset, false); } } - return (_upperBound <= lengthOfPathT_Test_Path); + return (_upperBound <= lengthOfPathT_TestPath); } }; diff --git a/RoutingAlgorithms/BasicRoutingInterface.h b/RoutingAlgorithms/BasicRoutingInterface.h index 8eab47cdb..1335f43af 100644 --- a/RoutingAlgorithms/BasicRoutingInterface.h +++ b/RoutingAlgorithms/BasicRoutingInterface.h @@ -136,7 +136,7 @@ public: inline void UnpackPath( const std::vector & packed_path, - std::vector<_PathData> & unpacked_path + std::vector & unpacked_path ) const { const unsigned packed_path_size = packed_path.size(); std::stack > recursion_stack; @@ -199,7 +199,7 @@ public: } else { BOOST_ASSERT_MSG(!ed.shortcut, "edge must be a shortcut"); unpacked_path.push_back( - _PathData( + PathData( ed.id, facade->GetNameIndexFromEdgeID(ed.id), facade->GetTurnInstructionForEdgeID(ed.id), diff --git a/RoutingAlgorithms/ShortestPathRouting.h b/RoutingAlgorithms/ShortestPathRouting.h index 0fca7ee65..982b7b13d 100644 --- a/RoutingAlgorithms/ShortestPathRouting.h +++ b/RoutingAlgorithms/ShortestPathRouting.h @@ -29,9 +29,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define SHORTESTPATHROUTING_H_ #include +#include #include "BasicRoutingInterface.h" #include "../DataStructures/SearchEngineData.h" +#include "../typedefs.h" template class ShortestPathRouting : public BasicRoutingInterface{ @@ -51,7 +53,7 @@ public: ~ShortestPathRouting() {} void operator()( - std::vector & phantom_nodes_vector, + const std::vector & phantom_nodes_vector, RawRouteData & raw_route_data ) const { BOOST_FOREACH( @@ -66,13 +68,12 @@ public: } int distance1 = 0; int distance2 = 0; - bool search_from_1st_node = true; bool search_from_2nd_node = true; NodeID middle1 = UINT_MAX; NodeID middle2 = UINT_MAX; - std::vector packed_path1; - std::vector packed_path2; + std::vector > packed_legs1(phantom_nodes_vector.size()); + std::vector > packed_legs2(phantom_nodes_vector.size()); engine_working_data.InitializeOrClearFirstThreadLocalStorage( super::facade->GetNumberOfNodes() @@ -89,10 +90,10 @@ public: QueryHeap & forward_heap2 = *(engine_working_data.forwardHeap2); QueryHeap & reverse_heap2 = *(engine_working_data.backwardHeap2); + int current_leg = 0; //Get distance to next pair of target nodes. BOOST_FOREACH( - const PhantomNodes & phantom_node_pair, - phantom_nodes_vector + const PhantomNodes & phantom_node_pair, phantom_nodes_vector ){ forward_heap1.Clear(); forward_heap2.Clear(); reverse_heap1.Clear(); reverse_heap2.Clear(); @@ -109,27 +110,23 @@ public: distance1-phantom_node_pair.startPhantom.weight1, phantom_node_pair.startPhantom.edgeBasedNode ); - // INFO("fw1: " << phantom_node_pair.startPhantom.edgeBasedNode << "´, w: " << -phantomNodePair.startPhantom.weight1); forward_heap2.Insert( phantom_node_pair.startPhantom.edgeBasedNode, distance1-phantom_node_pair.startPhantom.weight1, phantom_node_pair.startPhantom.edgeBasedNode ); - // INFO("fw2: " << phantom_node_pair.startPhantom.edgeBasedNode << "´, w: " << -phantomNodePair.startPhantom.weight1); - } + } if(phantom_node_pair.startPhantom.isBidirected() && search_from_2nd_node) { forward_heap1.Insert( phantom_node_pair.startPhantom.edgeBasedNode+1, distance2-phantom_node_pair.startPhantom.weight2, phantom_node_pair.startPhantom.edgeBasedNode+1 ); - // INFO("fw1: " << phantom_node_pair.startPhantom.edgeBasedNode+1 << "´, w: " << -phantomNodePair.startPhantom.weight2); forward_heap2.Insert( phantom_node_pair.startPhantom.edgeBasedNode+1, distance2-phantom_node_pair.startPhantom.weight2, phantom_node_pair.startPhantom.edgeBasedNode+1 ); - // INFO("fw2: " << phantom_node_pair.startPhantom.edgeBasedNode+1 << "´, w: " << -phantomNodePair.startPhantom.weight2); } //insert new backward nodes into backward heap, unadjusted. @@ -138,15 +135,14 @@ public: phantom_node_pair.targetPhantom.weight1, phantom_node_pair.targetPhantom.edgeBasedNode ); - // INFO("rv1: " << phantom_node_pair.targetPhantom.edgeBasedNode << ", w;" << phantom_node_pair.targetPhantom.weight1 ); if(phantom_node_pair.targetPhantom.isBidirected() ) { reverse_heap2.Insert( phantom_node_pair.targetPhantom.edgeBasedNode+1, phantom_node_pair.targetPhantom.weight2, phantom_node_pair.targetPhantom.edgeBasedNode+1 ); - // INFO("rv2: " << phantom_node_pair.targetPhantom.edgeBasedNode+1 << ", w;" << phantom_node_pair.targetPhantom.weight2 ); - } + } + const int forward_offset = super::ComputeEdgeOffset( phantom_node_pair.startPhantom ); @@ -177,6 +173,7 @@ public: ); } } + if( !reverse_heap2.Empty() ) { while(0 < (forward_heap2.Size() + reverse_heap2.Size() )){ if( !forward_heap2.Empty() ){ @@ -225,14 +222,18 @@ public: ); //Unpack paths if they exist - std::vector temporary_packed_path1; - std::vector temporary_packed_path2; + std::vector temporary_packed_leg1; + std::vector temporary_packed_leg2; + + BOOST_ASSERT( (unsigned)current_leg < packed_legs1.size() ); + BOOST_ASSERT( (unsigned)current_leg < packed_legs2.size() ); + if(INT_MAX != local_upper_bound1) { super::RetrievePackedPathFromHeap( forward_heap1, reverse_heap1, middle1, - temporary_packed_path1 + temporary_packed_leg1 ); } @@ -241,100 +242,123 @@ public: forward_heap2, reverse_heap2, middle2, - temporary_packed_path2 + temporary_packed_leg2 ); } //if one of the paths was not found, replace it with the other one. - if( temporary_packed_path1.empty() ) { - temporary_packed_path1.insert( - temporary_packed_path1.end(), - temporary_packed_path2.begin(), - temporary_packed_path2.end() + if( temporary_packed_leg1.empty() ) { + temporary_packed_leg1.insert( + temporary_packed_leg1.end(), + temporary_packed_leg2.begin(), + temporary_packed_leg2.end() ); local_upper_bound1 = local_upper_bound2; } - if( temporary_packed_path2.empty() ) { - temporary_packed_path2.insert( - temporary_packed_path2.end(), - temporary_packed_path1.begin(), - temporary_packed_path1.end() + if( temporary_packed_leg2.empty() ) { + temporary_packed_leg2.insert( + temporary_packed_leg2.end(), + temporary_packed_leg1.begin(), + temporary_packed_leg1.end() ); local_upper_bound2 = local_upper_bound1; } + // SimpleLogger().Write() << "fetched packed paths"; + BOOST_ASSERT_MSG( - !temporary_packed_path1.empty() || - !temporary_packed_path2.empty(), + !temporary_packed_leg1.empty() || + !temporary_packed_leg2.empty(), "tempory packed paths empty" ); - //Plug paths together, s.t. end of packed path is begin of temporary packed path - if( !packed_path1.empty() && !packed_path2.empty() ) { - if( - temporary_packed_path1.front() == - temporary_packed_path2.front() - ) { - //both new route segments start with the same node - //thus, one of the packedPath must go. - BOOST_ASSERT_MSG( - (packed_path1.size() == packed_path2.size() ) || - (packed_path1.back() != packed_path2.back() ), - "packed paths must be different" - ); + BOOST_ASSERT( + (0 == current_leg) || !packed_legs1[current_leg-1].empty() + ); + BOOST_ASSERT( + (0 == current_leg) || !packed_legs2[current_leg-1].empty() + ); - if( packed_path1.back() == temporary_packed_path1.front()) { - packed_path2.clear(); - packed_path2.insert( - packed_path2.end(), - packed_path1.begin(), - packed_path1.end() + if( 0 < current_leg ) { + const NodeID end_id_of_segment1 = packed_legs1[current_leg-1].back(); + const NodeID end_id_of_segment2 = packed_legs2[current_leg-1].back(); + BOOST_ASSERT( !temporary_packed_leg1.empty() ); + const NodeID start_id_of_leg1 = temporary_packed_leg1.front(); + const NodeID start_id_of_leg2 = temporary_packed_leg2.front(); + if( ( end_id_of_segment1 != start_id_of_leg1 ) && + ( end_id_of_segment2 != start_id_of_leg2 ) + ) { + std::swap(temporary_packed_leg1, temporary_packed_leg2); + std::swap(local_upper_bound1, local_upper_bound2); + } + } + + // remove one path if both legs end at the same segment + if( 0 < current_leg ) { + const NodeID start_id_of_leg1 = temporary_packed_leg1.front(); + const NodeID start_id_of_leg2 = temporary_packed_leg2.front(); + if( + start_id_of_leg1 == start_id_of_leg2 + ) { + const NodeID last_id_of_packed_legs1 = packed_legs1[current_leg-1].back(); + const NodeID last_id_of_packed_legs2 = packed_legs2[current_leg-1].back(); + if( start_id_of_leg1 != last_id_of_packed_legs1 ) { + packed_legs1 = packed_legs2; + BOOST_ASSERT( + start_id_of_leg1 == temporary_packed_leg1.front() ); - } else { - packed_path1.clear(); - packed_path1.insert( - packed_path1.end(), - packed_path2.begin(), - packed_path2.end() + } else + if( start_id_of_leg2 != last_id_of_packed_legs2 ) { + packed_legs2 = packed_legs1; + BOOST_ASSERT( + start_id_of_leg2 == temporary_packed_leg2.front() ); } - } else { - //packed paths 1 and 2 may need to switch. - if( packed_path1.back() != temporary_packed_path1.front()) { - packed_path1.swap(packed_path2); - std::swap(distance1, distance2); - } } } - packed_path1.insert( - packed_path1.end(), - temporary_packed_path1.begin(), - temporary_packed_path1.end() - ); - packed_path2.insert( - packed_path2.end(), - temporary_packed_path2.begin(), - temporary_packed_path2.end() + BOOST_ASSERT( + packed_legs1.size() == packed_legs2.size() ); + packed_legs1[current_leg].insert( + packed_legs1[current_leg].end(), + temporary_packed_leg1.begin(), + temporary_packed_leg1.end() + ); + BOOST_ASSERT(packed_legs1[current_leg].size() == temporary_packed_leg1.size() ); + packed_legs2[current_leg].insert( + packed_legs2[current_leg].end(), + temporary_packed_leg2.begin(), + temporary_packed_leg2.end() + ); + BOOST_ASSERT(packed_legs2[current_leg].size() == temporary_packed_leg2.size() ); + if( - (packed_path1.back() == packed_path2.back()) && + (packed_legs1[current_leg].back() == packed_legs2[current_leg].back()) && phantom_node_pair.targetPhantom.isBidirected() ) { - const NodeID last_node_id = packed_path2.back(); + const NodeID last_node_id = packed_legs2[current_leg].back(); search_from_1st_node &= !(last_node_id == phantom_node_pair.targetPhantom.edgeBasedNode+1); search_from_2nd_node &= !(last_node_id == phantom_node_pair.targetPhantom.edgeBasedNode); + BOOST_ASSERT( search_from_1st_node != search_from_2nd_node ); } distance1 = local_upper_bound1; distance2 = local_upper_bound2; + ++current_leg; } if( distance1 > distance2 ) { - std::swap( packed_path1, packed_path2 ); + std::swap( packed_legs1, packed_legs2 ); + } + raw_route_data.unpacked_path_segments.resize( packed_legs1.size() ); + for(unsigned i = 0; i < packed_legs1.size(); ++i){ + BOOST_ASSERT(packed_legs1.size() == raw_route_data.unpacked_path_segments.size() ); + super::UnpackPath( + packed_legs1[i], + raw_route_data.unpacked_path_segments[i] + ); } - remove_consecutive_duplicates_from_vector(packed_path1); - super::UnpackPath(packed_path1, raw_route_data.computedShortestPath); raw_route_data.lengthOfShortestPath = std::min(distance1, distance2); } }; diff --git a/Server/APIGrammar.h b/Server/APIGrammar.h index bca0b9e30..f377e6f10 100644 --- a/Server/APIGrammar.h +++ b/Server/APIGrammar.h @@ -42,7 +42,7 @@ struct APIGrammar : qi::grammar { zoom = (-qi::lit('&')) >> qi::lit('z') >> '=' >> qi::short_[boost::bind(&HandlerT::setZoomLevel, handler, ::_1)]; output = (-qi::lit('&')) >> qi::lit("output") >> '=' >> string[boost::bind(&HandlerT::setOutputFormat, handler, ::_1)]; - jsonp = (-qi::lit('&')) >> qi::lit("jsonp") >> '=' >> stringwithDot[boost::bind(&HandlerT::setJSONpParameter, handler, ::_1)]; + jsonp = (-qi::lit('&')) >> qi::lit("jsonp") >> '=' >> stringwithPercent[boost::bind(&HandlerT::setJSONpParameter, handler, ::_1)]; checksum = (-qi::lit('&')) >> qi::lit("checksum") >> '=' >> qi::int_[boost::bind(&HandlerT::setChecksum, handler, ::_1)]; instruction = (-qi::lit('&')) >> qi::lit("instructions") >> '=' >> qi::bool_[boost::bind(&HandlerT::setInstructionFlag, handler, ::_1)]; geometry = (-qi::lit('&')) >> qi::lit("geometry") >> '=' >> qi::bool_[boost::bind(&HandlerT::setGeometryFlag, handler, ::_1)]; @@ -53,16 +53,17 @@ struct APIGrammar : qi::grammar { alt_route = (-qi::lit('&')) >> qi::lit("alt") >> '=' >> qi::bool_[boost::bind(&HandlerT::setAlternateRouteFlag, handler, ::_1)]; old_API = (-qi::lit('&')) >> qi::lit("geomformat") >> '=' >> string[boost::bind(&HandlerT::setDeprecatedAPIFlag, handler, ::_1)]; - string = +(qi::char_("a-zA-Z")); - stringwithDot = +(qi::char_("a-zA-Z0-9_.-")); + string = +(qi::char_("a-zA-Z")); + stringwithDot = +(qi::char_("a-zA-Z0-9_.-")); + stringwithPercent = +(qi::char_("a-zA-Z0-9_.-") | qi::char_('[') | qi::char_(']') | (qi::char_('%') >> qi::char_("0-9A-Z") >> qi::char_("0-9A-Z") )); } + qi::rule api_call, query; qi::rule service, zoom, output, string, jsonp, checksum, location, hint, - stringwithDot, language, instruction, geometry, + stringwithDot, stringwithPercent, language, instruction, geometry, cmp, alt_route, old_API; HandlerT * handler; }; - #endif /* APIGRAMMAR_H_ */ diff --git a/Server/Connection.cpp b/Server/Connection.cpp new file mode 100644 index 000000000..227852364 --- /dev/null +++ b/Server/Connection.cpp @@ -0,0 +1,240 @@ +/* + +Copyright (c) 2013, Project OSRM, Dennis Luxen, others +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include "Connection.h" +#include "RequestHandler.h" +#include "RequestParser.h" + +#include +#include +#include +#include +#include + +#include +#include + +namespace http { + +Connection::Connection( + boost::asio::io_service& io_service, + RequestHandler& handler +) : + strand(io_service), + TCP_socket(io_service), + request_handler(handler), + request_parser(new RequestParser()) +{ } + +Connection::~Connection() { + delete request_parser; +} + +boost::asio::ip::tcp::socket& Connection::socket() { + return TCP_socket; +} + +/// Start the first asynchronous operation for the connection. +void Connection::start() { + TCP_socket.async_read_some( + boost::asio::buffer(incoming_data_buffer), + strand.wrap( boost::bind( + &Connection::handle_read, + this->shared_from_this(), + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred) + ) + ); +} + +void Connection::handle_read( + const boost::system::error_code& e, + std::size_t bytes_transferred +) { + if( !e ) { + CompressionType compression_type(noCompression); + boost::tribool result; + boost::tie(result, boost::tuples::ignore) = request_parser->Parse( + request, + incoming_data_buffer.data(), + incoming_data_buffer.data() + bytes_transferred, + &compression_type + ); + + if( result ) { + request.endpoint = TCP_socket.remote_endpoint().address(); + request_handler.handle_request(request, reply); + + Header compression_header; + std::vector compressed_output; + std::vector output_buffer; + switch(compression_type) { + case deflateRFC1951: + compression_header.name = "Content-Encoding"; + compression_header.value = "deflate"; + reply.headers.insert( + reply.headers.begin(), + compression_header + ); + compressBufferCollection( + reply.content, + compression_type, + compressed_output + ); + reply.setSize(compressed_output.size()); + output_buffer = reply.HeaderstoBuffers(); + output_buffer.push_back( + boost::asio::buffer(compressed_output) + ); + boost::asio::async_write( + TCP_socket, + output_buffer, + strand.wrap( + boost::bind( + &Connection::handle_write, + this->shared_from_this(), + boost::asio::placeholders::error + ) + ) + ); + break; + case gzipRFC1952: + compression_header.name = "Content-Encoding"; + compression_header.value = "gzip"; + reply.headers.insert( + reply.headers.begin(), + compression_header + ); + compressBufferCollection( + reply.content, + compression_type, + compressed_output + ); + reply.setSize(compressed_output.size()); + output_buffer = reply.HeaderstoBuffers(); + output_buffer.push_back( + boost::asio::buffer(compressed_output) + ); + boost::asio::async_write( + TCP_socket, + output_buffer, + strand.wrap( + boost::bind( + &Connection::handle_write, + this->shared_from_this(), + boost::asio::placeholders::error + ) + ) + ); + break; + case noCompression: + reply.SetUncompressedSize(); + output_buffer = reply.toBuffers(); + boost::asio::async_write( + TCP_socket, + output_buffer, + strand.wrap( + boost::bind( + &Connection::handle_write, + this->shared_from_this(), + boost::asio::placeholders::error + ) + ) + ); + break; + } + } else if (!result) { + reply = Reply::StockReply(Reply::badRequest); + + boost::asio::async_write( + TCP_socket, + reply.toBuffers(), + strand.wrap( + boost::bind( + &Connection::handle_write, + this->shared_from_this(), + boost::asio::placeholders::error + ) + ) + ); + } else { + TCP_socket.async_read_some( + boost::asio::buffer(incoming_data_buffer), + strand.wrap( + boost::bind( + &Connection::handle_read, + this->shared_from_this(), + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred + ) + ) + ); + } + } +} + +/// Handle completion of a write operation. +void Connection::handle_write(const boost::system::error_code& e) { + if (!e) { + // Initiate graceful connection closure. + boost::system::error_code ignoredEC; + TCP_socket.shutdown( + boost::asio::ip::tcp::socket::shutdown_both, + ignoredEC + ); + } +} + +void Connection::compressBufferCollection( + std::vector uncompressed_data, + CompressionType compression_type, + std::vector & compressed_data +) { + boost::iostreams::gzip_params compression_parameters; + + compression_parameters.level = boost::iostreams::zlib::best_speed; + if ( deflateRFC1951 == compression_type ) { + compression_parameters.noheader = true; + } + + BOOST_ASSERT( compressed_data.empty() ); + boost::iostreams::filtering_ostream compressing_stream; + + compressing_stream.push( + boost::iostreams::gzip_compressor(compression_parameters) + ); + compressing_stream.push( + boost::iostreams::back_inserter(compressed_data) + ); + + BOOST_FOREACH( const std::string & line, uncompressed_data) { + compressing_stream << line; + } + + compressing_stream.reset(); +} +} diff --git a/Server/Connection.h b/Server/Connection.h index bd7d3e879..1e484fd0e 100644 --- a/Server/Connection.h +++ b/Server/Connection.h @@ -29,27 +29,24 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define CONNECTION_H #include "Http/CompressionType.h" -#include "RequestHandler.h" -#include "RequestParser.h" +#include "Http/Request.h" + +#include #include #include -#include -#include #include -#include -#include #include -#include - - -// #include #include #include +class RequestHandler; + namespace http { +class RequestParser; + /// Represents a single connection from a client. class Connection : public boost::enable_shared_from_this, private boost::noncopyable { @@ -57,262 +54,36 @@ public: explicit Connection( boost::asio::io_service& io_service, RequestHandler& handler - ) : strand(io_service), TCP_socket(io_service), request_handler(handler) { } + ); - boost::asio::ip::tcp::socket& socket() { - return TCP_socket; - } + ~Connection(); + + boost::asio::ip::tcp::socket& socket(); /// Start the first asynchronous operation for the connection. - void start() { - TCP_socket.async_read_some( - boost::asio::buffer(incoming_data_buffer), - strand.wrap( boost::bind( - &Connection::handle_read, - this->shared_from_this(), - boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred) - ) - ); - } + void start(); private: void handle_read( const boost::system::error_code& e, std::size_t bytes_transferred - ) { - if( !e ) { - CompressionType compression_type(noCompression); - boost::tribool result; - boost::tie(result, boost::tuples::ignore) = request_parser.Parse( - request, - incoming_data_buffer.data(), - incoming_data_buffer.data() + bytes_transferred, - &compression_type - ); - - if( result ) { - request.endpoint = TCP_socket.remote_endpoint().address(); - request_handler.handle_request(request, reply); - - Header compression_header; - std::vector compressed_output; - std::vector output_buffer; - switch(compression_type) { - case deflateRFC1951: - compression_header.name = "Content-Encoding"; - compression_header.value = "deflate"; - reply.headers.insert( - reply.headers.begin(), - compression_header - ); - compressBufferCollection( - reply.content, - compression_type, - compressed_output - ); - reply.setSize(compressed_output.size()); - output_buffer = reply.HeaderstoBuffers(); - output_buffer.push_back( - boost::asio::buffer(compressed_output) - ); - boost::asio::async_write( - TCP_socket, - output_buffer, - strand.wrap( - boost::bind( - &Connection::handle_write, - this->shared_from_this(), - boost::asio::placeholders::error - ) - ) - ); - break; - case gzipRFC1952: - compression_header.name = "Content-Encoding"; - compression_header.value = "gzip"; - reply.headers.insert( - reply.headers.begin(), - compression_header - ); - compressBufferCollection( - reply.content, - compression_type, - compressed_output - ); - reply.setSize(compressed_output.size()); - output_buffer = reply.HeaderstoBuffers(); - output_buffer.push_back( - boost::asio::buffer(compressed_output) - ); - boost::asio::async_write( - TCP_socket, - output_buffer, - strand.wrap( - boost::bind( - &Connection::handle_write, - this->shared_from_this(), - boost::asio::placeholders::error - ) - ) - ); - break; - case noCompression: - boost::asio::async_write( - TCP_socket, - reply.toBuffers(), - strand.wrap( - boost::bind( - &Connection::handle_write, - this->shared_from_this(), - boost::asio::placeholders::error - ) - ) - ); - break; - } - } else if (!result) { - reply = Reply::StockReply(Reply::badRequest); - boost::asio::async_write( - TCP_socket, - reply.toBuffers(), - strand.wrap( - boost::bind( - &Connection::handle_write, - this->shared_from_this(), - boost::asio::placeholders::error - ) - ) - ); - } else { - TCP_socket.async_read_some( - boost::asio::buffer(incoming_data_buffer), - strand.wrap( - boost::bind( - &Connection::handle_read, - this->shared_from_this(), - boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred - ) - ) - ); - } - } - } + ); /// Handle completion of a write operation. - void handle_write(const boost::system::error_code& e) { - if (!e) { - // Initiate graceful connection closure. - boost::system::error_code ignoredEC; - TCP_socket.shutdown( - boost::asio::ip::tcp::socket::shutdown_both, - ignoredEC - ); - } - } + void handle_write(const boost::system::error_code& e); void compressBufferCollection( std::vector uncompressed_data, CompressionType compression_type, std::vector & compressed_data - ) { - boost::iostreams::gzip_params compression_parameters; - - compression_parameters.level = boost::iostreams::zlib::best_speed; - if ( deflateRFC1951 == compression_type ) { - compression_parameters.noheader = true; - } - - BOOST_ASSERT( compressed_data.empty() ); - boost::iostreams::filtering_ostream compressing_stream; - - compressing_stream.push( - boost::iostreams::gzip_compressor(compression_parameters) - ); - compressing_stream.push( - boost::iostreams::back_inserter(compressed_data) - ); - - BOOST_FOREACH( const std::string & line, uncompressed_data) { - compressing_stream << line; - } - - compressing_stream.reset(); - } - - // Big thanks to deusty who explains how to use gzip compression by - // the right call to deflateInit2(): - // http://deusty.blogspot.com/2007/07/gzip-compressiondecompression.html - // void compressCharArray( - // const char * in_data, - // size_t in_data_size, - // std::vector & buffer, - // CompressionType type - // ) { - // const size_t BUFSIZE = 128 * 1024; - // unsigned char temp_buffer[BUFSIZE]; - - // z_stream strm; - // strm.zalloc = Z_NULL; - // strm.zfree = Z_NULL; - // strm.opaque = Z_NULL; - // strm.total_out = 0; - // strm.next_in = (unsigned char *)(in_data); - // strm.avail_in = in_data_size; - // strm.next_out = temp_buffer; - // strm.avail_out = BUFSIZE; - // strm.data_type = Z_ASCII; - - // switch(type){ - // case deflateRFC1951: - // deflateInit(&strm, Z_BEST_SPEED); - // break; - // case gzipRFC1952: - // deflateInit2( - // &strm, - // Z_DEFAULT_COMPRESSION, - // Z_DEFLATED, - // (15+16), - // 9, - // Z_DEFAULT_STRATEGY - // ); - // break; - // default: - // BOOST_ASSERT_MSG(false, "should not happen"); - // break; - // } - - // int deflate_res = Z_OK; - // do { - // if ( 0 == strm.avail_out ) { - // buffer.insert(buffer.end(), temp_buffer, temp_buffer + BUFSIZE); - // strm.next_out = temp_buffer; - // strm.avail_out = BUFSIZE; - // } - // deflate_res = deflate(&strm, Z_FINISH); - - // } while (deflate_res == Z_OK); - - // BOOST_ASSERT_MSG( - // deflate_res == Z_STREAM_END, - // "compression not properly finished" - // ); - - // buffer.insert( - // buffer.end(), - // temp_buffer, - // temp_buffer + BUFSIZE - strm.avail_out - // ); - // deflateEnd(&strm); - // } + ); boost::asio::io_service::strand strand; boost::asio::ip::tcp::socket TCP_socket; RequestHandler& request_handler; boost::array incoming_data_buffer; Request request; - RequestParser request_parser; + RequestParser * request_parser; Reply reply; }; diff --git a/Server/DataStructures/BaseDataFacade.h b/Server/DataStructures/BaseDataFacade.h index fec11b47e..6c4726a9c 100644 --- a/Server/DataStructures/BaseDataFacade.h +++ b/Server/DataStructures/BaseDataFacade.h @@ -30,7 +30,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. //Exposes all data access interfaces to the algorithms via base class ptr -#include "../../DataStructures/Coordinate.h" #include "../../DataStructures/EdgeBasedNode.h" #include "../../DataStructures/ImportNode.h" #include "../../DataStructures/PhantomNodes.h" @@ -39,6 +38,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "../../Util/StringUtil.h" #include "../../typedefs.h" +#include + #include template @@ -113,7 +114,7 @@ public: std::string GetEscapedNameForNameID(const unsigned name_id) const { std::string temporary_string; GetName(name_id, temporary_string); - return HTMLEntitize(temporary_string); + return EscapeJSONString(temporary_string); } virtual std::string GetTimestamp() const = 0; diff --git a/Server/DataStructures/InternalDataFacade.h b/Server/DataStructures/InternalDataFacade.h index e7b7de713..c6ae80832 100644 --- a/Server/DataStructures/InternalDataFacade.h +++ b/Server/DataStructures/InternalDataFacade.h @@ -32,7 +32,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "BaseDataFacade.h" -#include "../../DataStructures/Coordinate.h" +#include "../../DataStructures/OriginalEdgeData.h" #include "../../DataStructures/QueryNode.h" #include "../../DataStructures/QueryEdge.h" #include "../../DataStructures/SharedMemoryVectorWrapper.h" @@ -40,10 +40,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "../../DataStructures/StaticRTree.h" #include "../../Util/BoostFileSystemFix.h" #include "../../Util/GraphLoader.h" -#include "../../Util/IniFile.h" #include "../../Util/ProgramOptions.h" #include "../../Util/SimpleLogger.h" +#include + template class InternalDataFacade : public BaseDataFacade { @@ -155,9 +156,9 @@ private: (char*)&(current_edge_data), sizeof(OriginalEdgeData) ); - m_via_node_list[i] = current_edge_data.viaNode; - m_name_ID_list[i] = current_edge_data.nameID; - m_turn_instruction_list[i] = current_edge_data.turnInstruction; + m_via_node_list[i] = current_edge_data.via_node; + m_name_ID_list[i] = current_edge_data.name_id; + m_turn_instruction_list[i] = current_edge_data.turn_instruction; } edges_input_stream.close(); } diff --git a/Server/DataStructures/SharedBarriers.h b/Server/DataStructures/SharedBarriers.h index c11f121f3..9e38f51b5 100644 --- a/Server/DataStructures/SharedBarriers.h +++ b/Server/DataStructures/SharedBarriers.h @@ -1,3 +1,33 @@ +/* + +Copyright (c) 2013, Project OSRM, Dennis Luxen, others +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef SHARED_BARRIER_H +#define SHARED_BARRIER_H + #include #include @@ -38,3 +68,5 @@ struct SharedBarriers { // Is there any query? int number_of_queries; }; + +#endif //SHARED_BARRIER_H diff --git a/Server/DataStructures/SharedDataFacade.h b/Server/DataStructures/SharedDataFacade.h index 8f208d122..0778eb06d 100644 --- a/Server/DataStructures/SharedDataFacade.h +++ b/Server/DataStructures/SharedDataFacade.h @@ -356,14 +356,14 @@ public: name_id < m_name_begin_indices.size(), "name id too high" ); - unsigned begin_index = m_name_begin_indices[name_id]; - unsigned end_index = m_name_begin_indices[name_id+1]; + const unsigned begin_index = m_name_begin_indices[name_id]; + const unsigned end_index = m_name_begin_indices[name_id+1]; BOOST_ASSERT_MSG( - begin_index < m_names_char_list.size(), + begin_index <= m_names_char_list.size(), "begin index of name too high" ); BOOST_ASSERT_MSG( - end_index < m_names_char_list.size(), + end_index <= m_names_char_list.size(), "end index of name too high" ); diff --git a/Server/DataStructures/SharedDataType.h b/Server/DataStructures/SharedDataType.h index 11470c57d..902eea986 100644 --- a/Server/DataStructures/SharedDataType.h +++ b/Server/DataStructures/SharedDataType.h @@ -31,7 +31,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "BaseDataFacade.h" -#include "../../DataStructures/Coordinate.h" #include "../../DataStructures/QueryEdge.h" #include "../../DataStructures/StaticGraph.h" #include "../../DataStructures/StaticRTree.h" @@ -39,6 +38,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "../../typedefs.h" +#include + #include typedef BaseDataFacade::RTreeLeaf RTreeLeaf; diff --git a/Server/Http/Reply.cpp b/Server/Http/Reply.cpp index c3c82d295..9d2bd0c42 100644 --- a/Server/Http/Reply.cpp +++ b/Server/Http/Reply.cpp @@ -25,7 +25,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "Reply.h" +#include + +#include + +#include "../../Util/StringUtil.h" namespace http { @@ -38,6 +42,18 @@ void Reply::setSize(const unsigned size) { } } +// Sets the size of the uncompressed output. +void Reply::SetUncompressedSize() +{ + unsigned uncompressed_size = 0; + BOOST_FOREACH ( const std::string & current_line, content) + { + uncompressed_size += current_line.size(); + } + setSize(uncompressed_size); +} + + std::vector Reply::toBuffers(){ std::vector buffers; buffers.push_back(ToBuffer(status)); @@ -88,25 +104,27 @@ Reply Reply::StockReply(Reply::status_type status) { } std::string Reply::ToString(Reply::status_type status) { - switch (status) { - case Reply::ok: + if (Reply::ok == status) + { return okHTML; - case Reply::badRequest: - return badRequestHTML; - default: - return internalServerErrorHTML; } + if (Reply::badRequest == status) + { + return badRequestHTML; + } + return internalServerErrorHTML; } boost::asio::const_buffer Reply::ToBuffer(Reply::status_type status) { - switch (status) { - case Reply::ok: + if (Reply::ok == status) + { return boost::asio::buffer(okString); - case Reply::internalServerError: - return boost::asio::buffer(internalServerErrorString); - default: - return boost::asio::buffer(badRequestString); } + if (Reply::internalServerError == status) + { + return boost::asio::buffer(internalServerErrorString); + } + return boost::asio::buffer(badRequestString); } diff --git a/Server/RequestHandler.cpp b/Server/RequestHandler.cpp new file mode 100644 index 000000000..ba6d20629 --- /dev/null +++ b/Server/RequestHandler.cpp @@ -0,0 +1,113 @@ +/* + +Copyright (c) 2013, Project OSRM, Dennis Luxen, others +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include "APIGrammar.h" +#include "RequestHandler.h" + +#include "../Library/OSRM.h" +#include "../Util/SimpleLogger.h" +#include "../Util/StringUtil.h" +#include "../typedefs.h" + +#include + +#include + +#include +#include + +RequestHandler::RequestHandler() : routing_machine(NULL) { } + +void RequestHandler::handle_request(const http::Request& req, http::Reply& rep){ + //parse command + try { + std::string request; + URIDecode(req.uri, request); + + time_t ltime; + struct tm *Tm; + + ltime=time(NULL); + Tm=localtime(<ime); + + SimpleLogger().Write() << + (Tm->tm_mday < 10 ? "0" : "" ) << Tm->tm_mday << "-" << + (Tm->tm_mon+1 < 10 ? "0" : "" ) << (Tm->tm_mon+1) << "-" << + 1900+Tm->tm_year << " " << (Tm->tm_hour < 10 ? "0" : "" ) << + Tm->tm_hour << ":" << (Tm->tm_min < 10 ? "0" : "" ) << + Tm->tm_min << ":" << (Tm->tm_sec < 10 ? "0" : "" ) << + Tm->tm_sec << " " << req.endpoint.to_string() << " " << + req.referrer << ( 0 == req.referrer.length() ? "- " :" ") << + req.agent << ( 0 == req.agent.length() ? "- " :" ") << request; + + RouteParameters route_parameters; + APIGrammarParser api_parser(&route_parameters); + + std::string::iterator it = request.begin(); + const bool result = boost::spirit::qi::parse( + it, + request.end(), + api_parser + ); + + if ( !result || (it != request.end()) ) { + rep = http::Reply::StockReply(http::Reply::badRequest); + const int position = std::distance(request.begin(), it); + std::string tmp_position_string; + intToString(position, tmp_position_string); + rep.content.push_back( + "Input seems to be malformed close to position " + "
"
+            );
+            rep.content.push_back( request );
+            rep.content.push_back(tmp_position_string);
+            rep.content.push_back("
"); + const unsigned end = std::distance(request.begin(), it); + for(unsigned i = 0; i < end; ++i) { + rep.content.push_back(" "); + } + rep.content.push_back("^
"); + } else { + //parsing done, lets call the right plugin to handle the request + BOOST_ASSERT_MSG( + routing_machine != NULL, + "pointer not init'ed" + ); + routing_machine->RunQuery(route_parameters, rep); + return; + } + } catch(const std::exception& e) { + rep = http::Reply::StockReply(http::Reply::internalServerError); + SimpleLogger().Write(logWARNING) << + "[server error] code: " << e.what() << ", uri: " << req.uri; + return; + } +} + +void RequestHandler::RegisterRoutingMachine(OSRM * osrm) { + routing_machine = osrm; +} diff --git a/Server/RequestHandler.h b/Server/RequestHandler.h index 37802fe49..320c0b5b7 100644 --- a/Server/RequestHandler.h +++ b/Server/RequestHandler.h @@ -28,95 +28,28 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef REQUEST_HANDLER_H #define REQUEST_HANDLER_H -#include "APIGrammar.h" -#include "DataStructures/RouteParameters.h" #include "Http/Request.h" -#include "../Library/OSRM.h" -#include "../Util/SimpleLogger.h" -#include "../Util/StringUtil.h" -#include "../typedefs.h" -#include +#include + #include -#include -#include -#include #include +template +struct APIGrammar; +struct RouteParameters; +class OSRM; + class RequestHandler : private boost::noncopyable { + public: typedef APIGrammar APIGrammarParser; - explicit RequestHandler() : routing_machine(NULL) { } - void handle_request(const http::Request& req, http::Reply& rep){ - //parse command - try { - std::string request(req.uri); + RequestHandler(); - time_t ltime; - struct tm *Tm; - - ltime=time(NULL); - Tm=localtime(<ime); - - SimpleLogger().Write() << - (Tm->tm_mday < 10 ? "0" : "" ) << Tm->tm_mday << "-" << - (Tm->tm_mon+1 < 10 ? "0" : "" ) << (Tm->tm_mon+1) << "-" << - 1900+Tm->tm_year << " " << (Tm->tm_hour < 10 ? "0" : "" ) << - Tm->tm_hour << ":" << (Tm->tm_min < 10 ? "0" : "" ) << - Tm->tm_min << ":" << (Tm->tm_sec < 10 ? "0" : "" ) << - Tm->tm_sec << " " << req.endpoint.to_string() << " " << - req.referrer << ( 0 == req.referrer.length() ? "- " :" ") << - req.agent << ( 0 == req.agent.length() ? "- " :" ") << req.uri; - - RouteParameters routeParameters; - APIGrammarParser apiParser(&routeParameters); - - std::string::iterator it = request.begin(); - const bool result = boost::spirit::qi::parse( - it, - request.end(), - apiParser - ); - - if ( !result || (it != request.end()) ) { - rep = http::Reply::StockReply(http::Reply::badRequest); - const int position = std::distance(request.begin(), it); - std::string tmp_position_string; - intToString(position, tmp_position_string); - rep.content.push_back( - "Input seems to be malformed close to position " - "
"
-                );
-                rep.content.push_back( request );
-                rep.content.push_back(tmp_position_string);
-                rep.content.push_back("
"); - const unsigned end = std::distance(request.begin(), it); - for(unsigned i = 0; i < end; ++i) { - rep.content.push_back(" "); - } - rep.content.push_back("^
"); - } else { - //parsing done, lets call the right plugin to handle the request - BOOST_ASSERT_MSG( - routing_machine != NULL, - "pointer not init'ed" - ); - routing_machine->RunQuery(routeParameters, rep); - return; - } - } catch(std::exception& e) { - rep = http::Reply::StockReply(http::Reply::internalServerError); - SimpleLogger().Write(logWARNING) << - "[server error] code: " << e.what() << ", uri: " << req.uri; - return; - } - }; - - void RegisterRoutingMachine(OSRM * osrm) { - routing_machine = osrm; - } + void handle_request(const http::Request& req, http::Reply& rep); + void RegisterRoutingMachine(OSRM * osrm); private: OSRM * routing_machine; diff --git a/Server/RequestParser.cpp b/Server/RequestParser.cpp index 7a9cacc67..8b2b1a985 100644 --- a/Server/RequestParser.cpp +++ b/Server/RequestParser.cpp @@ -25,6 +25,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "Http/Request.h" #include "RequestParser.h" namespace http { diff --git a/Server/RequestParser.h b/Server/RequestParser.h index 9fdbc1d90..b06c027f5 100644 --- a/Server/RequestParser.h +++ b/Server/RequestParser.h @@ -29,14 +29,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define REQUEST_PARSER_H #include "Http/CompressionType.h" -#include "Http/Header.h" -#include "Http/Request.h" +#include #include #include namespace http { +struct Request; + class RequestParser { public: RequestParser(); diff --git a/Server/ServerFactory.h b/Server/ServerFactory.h index b463e5f37..89f2e5b8f 100644 --- a/Server/ServerFactory.h +++ b/Server/ServerFactory.h @@ -29,23 +29,32 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define SERVERFACTORY_H_ #include "Server.h" +#include "../Util/OpenMPWrapper.h" #include "../Util/SimpleLogger.h" #include "../Util/StringUtil.h" #include #include -#include struct ServerFactory : boost::noncopyable { - static Server * CreateServer(std::string& ip_address, int ip_port, int threads) { + static Server * CreateServer( + std::string& ip_address, + int ip_port, + int threads + ) { SimpleLogger().Write() << "http 1.1 compression handled by zlib version " << zlibVersion(); - std::stringstream port_stream; - port_stream << ip_port; - return new Server( ip_address, port_stream.str(), std::min( omp_get_num_procs(), threads) ); + std::string port_stream; + intToString(ip_port, port_stream); + + return new Server( + ip_address, + port_stream, + std::min( omp_get_num_procs(), threads ) + ); } }; diff --git a/Tools/io-benchmark.cpp b/Tools/io-benchmark.cpp index a2aa0f8b6..e235c1208 100644 --- a/Tools/io-benchmark.cpp +++ b/Tools/io-benchmark.cpp @@ -79,6 +79,11 @@ int main (int argc, char * argv[]) { "starting up engines, " << g_GIT_DESCRIPTION << ", " << "compiled at " << __DATE__ << ", " __TIME__; +#ifdef __FreeBSD__ + SimpleLogger().Write() << "Not supported on FreeBSD"; + return 0; +#endif + if( 1 == argc ) { SimpleLogger().Write(logWARNING) << "usage: " << argv[0] << " /path/on/device"; @@ -222,6 +227,12 @@ int main (int argc, char * argv[]) { int ret1 = fseek(fd, current_offset, SEEK_SET); int ret2 = read(fileno(fd), (char*)&single_block[0], 4096); #endif + +#ifdef __FreeBSD__ + int ret1 = 0; + int ret2 = 0; +#endif + #ifdef __linux__ int ret1 = lseek(f, current_offset, SEEK_SET); int ret2 = read(f, (char*)single_block, 4096); @@ -281,6 +292,12 @@ int main (int argc, char * argv[]) { int ret1 = fseek(fd, current_offset, SEEK_SET); int ret2 = read(fileno(fd), (char*)&single_block, 4096); #endif + + #ifdef __FreeBSD__ + int ret1 = 0; + int ret2 = 0; + #endif + #ifdef __linux__ int ret1 = lseek(f, current_offset, SEEK_SET); diff --git a/Tools/simpleclient.cpp b/Tools/simpleclient.cpp index f617b462a..b1a2556ef 100644 --- a/Tools/simpleclient.cpp +++ b/Tools/simpleclient.cpp @@ -26,8 +26,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "../Library/OSRM.h" +#include "../Util/GitDescription.h" +#include "../Util/ProgramOptions.h" #include "../Util/SimpleLogger.h" +#include #include #include @@ -37,15 +40,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include //Dude, real recursions on the OS stack? You must be brave... -void print_tree(boost::property_tree::ptree const& pt, const unsigned recursion_depth) +void print_tree(boost::property_tree::ptree const& property_tree, const unsigned recursion_depth) { - boost::property_tree::ptree::const_iterator end = pt.end(); - for (boost::property_tree::ptree::const_iterator it = pt.begin(); it != end; ++it) { - for(unsigned i = 0; i < recursion_depth; ++i) { + boost::property_tree::ptree::const_iterator end = property_tree.end(); + for (boost::property_tree::ptree::const_iterator tree_iterator = property_tree.begin(); tree_iterator != end; ++tree_iterator) + { + for (unsigned current_recursion = 0; current_recursion < recursion_depth; ++current_recursion) + { std::cout << " " << std::flush; } - std::cout << it->first << ": " << it->second.get_value() << std::endl; - print_tree(it->second, recursion_depth+1); + std::cout << tree_iterator->first << ": " << tree_iterator->second.get_value() << std::endl; + print_tree(tree_iterator->second, recursion_depth+1); } } @@ -54,8 +59,8 @@ int main (int argc, const char * argv[]) { LogPolicy::GetInstance().Unmute(); try { std::string ip_address; - int ip_port, requested_num_threads; - bool use_shared_memory = false; + int ip_port, requested_thread_num; + bool use_shared_memory = false, trial = false; ServerPaths server_paths; if( !GenerateServerProgramOptions( argc, @@ -63,8 +68,9 @@ int main (int argc, const char * argv[]) { server_paths, ip_address, ip_port, - requested_num_threads, - use_shared_memory + requested_thread_num, + use_shared_memory, + trial ) ) { return 0; @@ -100,19 +106,20 @@ int main (int argc, const char * argv[]) { //attention: super-inefficient hack below: - std::stringstream ss; - BOOST_FOREACH(const std::string & line, osrm_reply.content) { + std::stringstream my_stream; + BOOST_FOREACH(const std::string & line, osrm_reply.content) + { std::cout << line; - ss << line; + my_stream << line; } std::cout << std::endl; - boost::property_tree::ptree pt; - boost::property_tree::read_json(ss, pt); + boost::property_tree::ptree property_tree; + boost::property_tree::read_json(my_stream, property_tree); - print_tree(pt, 0); - } catch (std::exception & e) { - SimpleLogger().Write(logWARNING) << "caught exception: " << e.what(); + print_tree(property_tree, 0); + } catch (std::exception & current_exception) { + SimpleLogger().Write(logWARNING) << "caught exception: " << current_exception.what(); return -1; } return 0; diff --git a/Util/BoostFileSystemFix.h b/Util/BoostFileSystemFix.h index 1e5bcda52..0919857dc 100644 --- a/Util/BoostFileSystemFix.h +++ b/Util/BoostFileSystemFix.h @@ -28,15 +28,87 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef BOOST_FILE_SYSTEM_FIX_H #define BOOST_FILE_SYSTEM_FIX_H +#include "OSRMException.h" + +#include #include +#include //This is one big workaround for latest boost renaming woes. #if BOOST_FILESYSTEM_VERSION < 3 #warning Boost Installation with Filesystem3 missing, activating workaround #include +#endif + + namespace boost { namespace filesystem { + +// Validator for boost::filesystem::path, that verifies that the file +// exists. The validate() function must be defined in the same namespace +// as the target type, (boost::filesystem::path in this case), otherwise +// it is not called +// inline void validate( +// boost::any & v, +// const std::vector & values, +// boost::filesystem::path *, +// int +// ) { +// boost::program_options::validators::check_first_occurrence(v); +// const std::string & input_string = +// boost::program_options::validators::get_single_string(values); +// // SimpleLogger().Write() << "validator called for " << input_string; +// // SimpleLogger().Write() << "validator called for " << input_string; +// if(boost::filesystem::is_regular_file(input_string)) { +// v = boost::any(boost::filesystem::path(input_string)); +// } else { +// throw OSRMException(input_string + " not found"); +// } +// } + +// adapted from: http://stackoverflow.com/questions/1746136/how-do-i-normalize-a-pathname-using-boostfilesystem +inline boost::filesystem::path portable_canonical( + const boost::filesystem::path & relative_path, + const boost::filesystem::path & current_path = boost::filesystem::current_path()) +{ + const boost::filesystem::path absolute_path = boost::filesystem::absolute( + relative_path, + current_path + ); + + boost::filesystem::path canonical_path; + for( + boost::filesystem::path::const_iterator path_iterator = absolute_path.begin(); + path_iterator!=absolute_path.end(); + ++path_iterator + ) { + if( ".." == path_iterator->string() ) { + // /a/b/.. is not necessarily /a if b is a symbolic link + if( boost::filesystem::is_symlink(canonical_path) ) { + canonical_path /= *path_iterator; + } else if( ".." == canonical_path.filename() ) { + // /a/b/../.. is not /a/b/.. under most circumstances + // We can end up with ..s in our result because of symbolic links + canonical_path /= *path_iterator; + } else { + // Otherwise it should be safe to resolve the parent + canonical_path = canonical_path.parent_path(); + } + } else if( "." == path_iterator->string() ) { + // Ignore + } else { + // Just cat other path entries + canonical_path /= *path_iterator; + } + } + BOOST_ASSERT( canonical_path.is_absolute() ); + BOOST_ASSERT( boost::filesystem::exists( canonical_path ) ); + return canonical_path; +} + +#if BOOST_FILESYSTEM_VERSION < 3 + inline path temp_directory_path() { char * buffer; buffer = tmpnam (NULL); @@ -48,10 +120,9 @@ inline path unique_path(const path&) { return temp_directory_path(); } -} -} - #endif +} +} #ifndef BOOST_FILESYSTEM_VERSION #define BOOST_FILESYSTEM_VERSION 3 diff --git a/Util/ComputeAngle.h b/Util/ComputeAngle.h new file mode 100644 index 000000000..ef5dad9f1 --- /dev/null +++ b/Util/ComputeAngle.h @@ -0,0 +1,56 @@ +/* + +Copyright (c) 2013, Project OSRM, Dennis Luxen, others +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef COMPUTE_ANGLE_H +#define COMPUTE_ANGLE_H + +#include "../Util/MercatorUtil.h" +#include + +#include +#include + +/* Get angle of line segment (A,C)->(C,B), atan2 magic, formerly cosine theorem*/ +template +inline static double GetAngleBetweenThreeFixedPointCoordinates ( + const CoordinateT & A, + const CoordinateT & C, + const CoordinateT & B +) { + const double v1x = (A.lon - C.lon)/COORDINATE_PRECISION; + const double v1y = lat2y(A.lat/COORDINATE_PRECISION) - lat2y(C.lat/COORDINATE_PRECISION); + const double v2x = (B.lon - C.lon)/COORDINATE_PRECISION; + const double v2y = lat2y(B.lat/COORDINATE_PRECISION) - lat2y(C.lat/COORDINATE_PRECISION); + + double angle = (atan2(v2y,v2x) - atan2(v1y,v1x) )*180/M_PI; + while(angle < 0) + angle += 360; + return angle; +} + + +#endif // COMPUTE_ANGLE_H diff --git a/Util/ContainerUtils.h b/Util/ContainerUtils.h index 40771069b..bc77b8ef5 100644 --- a/Util/ContainerUtils.h +++ b/Util/ContainerUtils.h @@ -50,5 +50,19 @@ inline void remove_consecutive_duplicates_from_vector(std::vector & vector) { vector.resize(number_of_unique_elements); } +template< typename FwdIter, typename Func > +Func for_each_pair( FwdIter iter_begin, FwdIter iter_end, Func func ) { + if( iter_begin == iter_end ) { + return func; + } + + FwdIter iter_next = iter_begin; + ++iter_next; + + for( ; iter_next != iter_end; ++iter_begin, ++iter_next ){ + func( *iter_begin, *iter_next ); + } + return func; +} #endif /* CONTAINERUTILS_H_ */ diff --git a/Util/DataStoreOptions.h b/Util/DataStoreOptions.h new file mode 100644 index 000000000..1802ee999 --- /dev/null +++ b/Util/DataStoreOptions.h @@ -0,0 +1,336 @@ +/* + +Copyright (c) 2013, Project OSRM, Dennis Luxen, others +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef DATA_STORE_OPTIONS_H +#define DATA_STORE_OPTIONS_H + +#include "BoostFileSystemFix.h" +#include "GitDescription.h" +#include "OSRMException.h" +#include "SimpleLogger.h" + +#include + +#include +#include +#include +#include +#include +#include + +#include + +void AssertPathExists(const boost::filesystem::path& path) +{ + if (!boost::filesystem::is_regular_file(path)) + { + SimpleLogger().Write(logDEBUG) << path << " check failed"; + throw OSRMException(path.string() + " not found."); + } else { + SimpleLogger().Write(logDEBUG) << path << " exists"; + } +} + +// support old capitalized option names by down-casing them with a regex replace +inline void PrepareConfigFile( + const boost::filesystem::path & path, + std::string & output +) { + boost::filesystem::fstream config_stream(path); + std::string input_str( + (std::istreambuf_iterator(config_stream)), + std::istreambuf_iterator() + ); + boost::regex regex("^([^=]*)"); //match from start of line to '=' + std::string format("\\L$1\\E"); //replace with downcased substring + output = boost::regex_replace( input_str, regex, format ); +} + +// generate boost::program_options object for the routing part +inline bool GenerateDataStoreOptions(const int argc, const char * argv[], ServerPaths & paths) +{ + // declare a group of options that will be allowed only on command line + boost::program_options::options_description generic_options("Options"); + generic_options.add_options() + ("version,v", "Show version") + ("help,h", "Show this help message") + ( + "config,c", + boost::program_options::value( + &paths["config"] + )->default_value("server.ini"), + "Path to a configuration file" + ); + + // declare a group of options that will be allowed both on command line + // as well as in a config file + boost::program_options::options_description config_options("Configuration"); + config_options.add_options() + ( + "hsgrdata", + boost::program_options::value(&paths["hsgrdata"]), + ".hsgr file" + ) + ( + "nodesdata", + boost::program_options::value(&paths["nodesdata"]), + ".nodes file" + ) + ( + "edgesdata", + boost::program_options::value(&paths["edgesdata"]), + ".edges file" + ) + // ( + // "geometry", + // boost::program_options::value(&paths["geometries"]), + // ".geometry file" + // ) + ( + "ramindex", + boost::program_options::value(&paths["ramindex"]), + ".ramIndex file" + ) + ( + "fileindex", + boost::program_options::value(&paths["fileindex"]), + ".fileIndex file" + ) + ( + "namesdata", + boost::program_options::value(&paths["namesdata"]), + ".names file" + ) + ( + "timestamp", + boost::program_options::value(&paths["timestamp"]), + ".timestamp file" + ); + + // hidden options, will be allowed both on command line and in config + // file, but will not be shown to the user + boost::program_options::options_description hidden_options("Hidden options"); + hidden_options.add_options() + ( + "base,b", + boost::program_options::value(&paths["base"]), + "base path to .osrm file" + ); + + // positional option + boost::program_options::positional_options_description positional_options; + positional_options.add("base", 1); + + // combine above options for parsing + boost::program_options::options_description cmdline_options; + cmdline_options.add(generic_options).add(config_options).add(hidden_options); + + boost::program_options::options_description config_file_options; + config_file_options.add(config_options).add(hidden_options); + + boost::program_options::options_description visible_options( + boost::filesystem::basename(argv[0]) + " [] " + ); + visible_options.add(generic_options).add(config_options); + + // parse command line options + boost::program_options::variables_map option_variables; + boost::program_options::store + ( + boost::program_options::command_line_parser(argc, argv).options(cmdline_options).positional(positional_options).run(), + option_variables + ); + + if(option_variables.count("version")) + { + SimpleLogger().Write() << g_GIT_DESCRIPTION; + return false; + } + + if(option_variables.count("help")) + { + SimpleLogger().Write() << visible_options; + return false; + } + + boost::program_options::notify(option_variables); + + const bool parameter_present = + (paths.find("hsgrdata") != paths.end() && !paths.find("hsgrdata")->second.string().empty() ) || + (paths.find("nodesdata") != paths.end() && !paths.find("nodesdata")->second.string().empty()) || + (paths.find("edgesdata") != paths.end() && !paths.find("edgesdata")->second.string().empty()) || + // (paths.find("geometry") != paths.end() && !paths.find("geometry")->second.string().empty())) || + (paths.find("ramindex") != paths.end() && !paths.find("ramindex")->second.string().empty()) || + (paths.find("fileindex") != paths.end() && !paths.find("fileindex")->second.string().empty()) || + (paths.find("timestamp") != paths.end() && !paths.find("timestamp")->second.string().empty()) ; + + if (parameter_present) + { + if ( + ( paths.find("config") != paths.end() && + boost::filesystem::is_regular_file(paths.find("config")->second) + ) || option_variables.count("base") + ) + { + SimpleLogger().Write(logWARNING) << "conflicting parameters"; + SimpleLogger().Write() << visible_options; + return false; + } + } + + // parse config file + ServerPaths::iterator path_iterator = paths.find("config"); + if ( + path_iterator != paths.end() && + boost::filesystem::is_regular_file(path_iterator->second) && + !option_variables.count("base") + ) + { + SimpleLogger().Write() << "Reading options from: " << path_iterator->second.string(); + std::string config_str; + PrepareConfigFile( path_iterator->second, config_str ); + std::stringstream config_stream( config_str ); + boost::program_options::store( + parse_config_file(config_stream, config_file_options), + option_variables + ); + boost::program_options::notify(option_variables); + } + else if (option_variables.count("base")) + { + path_iterator = paths.find("base"); + BOOST_ASSERT( paths.end() != path_iterator ); + std::string base_string = path_iterator->second.string(); + + path_iterator = paths.find("hsgrdata"); + if (path_iterator != paths.end()) + { + path_iterator->second = base_string + ".hsgr"; + } + + path_iterator = paths.find("nodesdata"); + if (path_iterator != paths.end()) + { + path_iterator->second = base_string + ".nodes"; + } + + path_iterator = paths.find("edgesdata"); + if (path_iterator != paths.end()) + { + path_iterator->second = base_string + ".edges"; + } + + // path_iterator = paths.find("geometries"); + // if (path_iterator != paths.end()) + // { + // path_iterator->second = base_string + ".geometry"; + // } + + path_iterator = paths.find("ramindex"); + if (path_iterator != paths.end()) + { + path_iterator->second = base_string + ".ramIndex"; + } + + path_iterator = paths.find("fileindex"); + if (path_iterator != paths.end()) + { + path_iterator->second = base_string + ".fileIndex"; + } + + path_iterator = paths.find("namesdata"); + if (path_iterator != paths.end()) + { + path_iterator->second = base_string + ".names"; + } + + path_iterator = paths.find("timestamp"); + if (path_iterator != paths.end()) + { + path_iterator->second = base_string + ".timestamp"; + } + } + + path_iterator = paths.find("hsgrdata"); + if (path_iterator == paths.end() || path_iterator->second.string().empty()) + { + throw OSRMException(".hsgr file must be specified"); + } + AssertPathExists(path_iterator->second); + + path_iterator = paths.find("nodesdata"); + if (path_iterator == paths.end() || path_iterator->second.string().empty()) + { + throw OSRMException(".nodes file must be specified"); + } + AssertPathExists(path_iterator->second); + + path_iterator = paths.find("edgesdata"); + if (path_iterator == paths.end() || path_iterator->second.string().empty()) + { + throw OSRMException(".edges file must be specified"); + } + AssertPathExists(path_iterator->second); + + // path_iterator = paths.find("geometries"); + // if (path_iterator == paths.end() || path_iterator->second.string().empty()) + // { + // path_iterator->second = base_string + ".geometry"; + // } + // AssertPathExists(path_iterator->second); + + path_iterator = paths.find("ramindex"); + if (path_iterator == paths.end() || path_iterator->second.string().empty()) + { + throw OSRMException(".ramindex file must be specified"); + } + AssertPathExists(path_iterator->second); + + path_iterator = paths.find("fileindex"); + if (path_iterator == paths.end() || path_iterator->second.string().empty()) + { + throw OSRMException(".fileindex file must be specified"); + } + AssertPathExists(path_iterator->second); + + path_iterator = paths.find("namesdata"); + if (path_iterator == paths.end() || path_iterator->second.string().empty()) + { + throw OSRMException(".names file must be specified"); + } + AssertPathExists(path_iterator->second); + + path_iterator = paths.find("timestamp"); + if (path_iterator == paths.end() || path_iterator->second.string().empty()) + { + throw OSRMException(".timestamp file must be specified"); + } + + return true; +} + +#endif /* DATA_STORE_OPTIONS_H */ diff --git a/Util/GitDescription.h b/Util/GitDescription.h index 92a6af337..d3a00f49a 100644 --- a/Util/GitDescription.h +++ b/Util/GitDescription.h @@ -25,4 +25,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#ifndef GIT_DESCRIPTION_H +#define GIT_DESCRIPTION_H + extern char g_GIT_DESCRIPTION[]; + +#endif //GIT_DESCRIPTION_H diff --git a/Util/IniFile.cpp b/Util/IniFile.cpp new file mode 100644 index 000000000..8d0dc5845 --- /dev/null +++ b/Util/IniFile.cpp @@ -0,0 +1,100 @@ +/* + +Copyright (c) 2013, Project OSRM, Dennis Luxen, others +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include "IniFile.h" + +#include "OSRMException.h" +#include "../DataStructures/HashTable.h" + +#include +#include +#include + +#include + +IniFile::IniFile(const char * config_filename) { + boost::filesystem::path config_file(config_filename); + if ( !boost::filesystem::exists( config_file ) ) { + std::string error = std::string(config_filename) + " not found"; + throw OSRMException(error); + } + if ( 0 == boost::filesystem::file_size( config_file ) ) { + std::string error = std::string(config_filename) + " is empty"; + throw OSRMException(error); + } + + boost::filesystem::ifstream config( config_file ); + std::string line; + if (config.is_open()) { + while ( config.good() ) { + getline (config,line); + std::vector tokens; + Tokenize(line, tokens); + if(2 == tokens.size() ) { + parameters.insert(std::make_pair(tokens[0], tokens[1])); + } + } + config.close(); + } +} + +std::string IniFile::GetParameter(const std::string & key){ + return parameters.Find(key); +} + +std::string IniFile::GetParameter(const std::string & key) const { + return parameters.Find(key); +} + +bool IniFile::Holds(const std::string & key) const { + return parameters.Holds(key); +} + +void IniFile::SetParameter(const char* key, const char* value) { + SetParameter(std::string(key), std::string(value)); +} + +void IniFile::SetParameter(const std::string & key, const std::string & value) { + parameters.insert(std::make_pair(key, value)); +} + +void IniFile::Tokenize( + const std::string& str, + std::vector& tokens, + const std::string& delimiters +) { + std::string::size_type lastPos = str.find_first_not_of(delimiters, 0); + std::string::size_type pos = str.find_first_of(delimiters, lastPos); + + while (std::string::npos != pos || std::string::npos != lastPos) { + std::string temp = str.substr(lastPos, pos - lastPos); + boost::trim(temp); + tokens.push_back( temp ); + lastPos = str.find_first_not_of(delimiters, pos); + pos = str.find_first_of(delimiters, lastPos); + } +} diff --git a/Util/IniFile.h b/Util/IniFile.h index 80f33f728..0a9c26216 100644 --- a/Util/IniFile.h +++ b/Util/IniFile.h @@ -28,82 +28,31 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef INI_FILE_H_ #define INI_FILE_H_ -#include "OSRMException.h" #include "../DataStructures/HashTable.h" -#include -#include -#include - -#include -#include #include +#include class IniFile { public: - IniFile(const char * config_filename) { - boost::filesystem::path config_file(config_filename); - if ( !boost::filesystem::exists( config_file ) ) { - std::string error = std::string(config_filename) + " not found"; - throw OSRMException(error); - } - if ( 0 == boost::filesystem::file_size( config_file ) ) { - std::string error = std::string(config_filename) + " is empty"; - throw OSRMException(error); - } + IniFile(const char * config_filename); - boost::filesystem::ifstream config( config_file ); - std::string line; - if (config.is_open()) { - while ( config.good() ) { - getline (config,line); - std::vector tokens; - Tokenize(line, tokens); - if(2 == tokens.size() ) { - parameters.insert(std::make_pair(tokens[0], tokens[1])); - } - } - config.close(); - } - } + std::string GetParameter(const std::string & key); - std::string GetParameter(const std::string & key){ - return parameters.Find(key); - } + std::string GetParameter(const std::string & key) const; - std::string GetParameter(const std::string & key) const { - return parameters.Find(key); - } + bool Holds(const std::string & key) const; - bool Holds(const std::string & key) const { - return parameters.Holds(key); - } + void SetParameter(const char* key, const char* value); - void SetParameter(const char* key, const char* value) { - SetParameter(std::string(key), std::string(value)); - } - - void SetParameter(const std::string & key, const std::string & value) { - parameters.insert(std::make_pair(key, value)); - } + void SetParameter(const std::string & key, const std::string & value); private: void Tokenize( const std::string& str, std::vector& tokens, const std::string& delimiters = "=" - ) { - std::string::size_type lastPos = str.find_first_not_of(delimiters, 0); - std::string::size_type pos = str.find_first_of(delimiters, lastPos); - - while (std::string::npos != pos || std::string::npos != lastPos) { - std::string temp = str.substr(lastPos, pos - lastPos); - boost::trim(temp); - tokens.push_back( temp ); - lastPos = str.find_first_not_of(delimiters, pos); - pos = str.find_first_of(delimiters, lastPos); - } - } + ); HashTable parameters; }; diff --git a/Util/LinuxStackTrace.h b/Util/LinuxStackTrace.h deleted file mode 100644 index f04290794..000000000 --- a/Util/LinuxStackTrace.h +++ /dev/null @@ -1,160 +0,0 @@ -/* - -Copyright (c) 2013, Project OSRM, Dennis Luxen, others -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -*/ - -#ifndef LINUXSTACKTRACE_H_ -#define LINUXSTACKTRACE_H_ - -#include - -#ifdef __linux__ -#include -#include -#include -#include -#include -#include - -#include - -std::string binaryName; - -std::string getFileAndLine (char * offset_end) { - std::string a(offset_end); - std::string result; - a = a.substr(2,a.length()-3); - static char buf[256]; - std::string command("/usr/bin/addr2line -C -e " + binaryName + " -f -i " + a); - // prepare command to be executed - // our program need to be passed after the -e parameter - FILE* f = popen (command.c_str(), "r"); - - if (f == NULL) { - perror (buf); - return ""; - } - // get function name - if ( NULL != fgets (buf, 256, f) ) { - - // get file and line - if ( NULL != fgets (buf, 256, f) ) { - - if (buf[0] != '?') { - result = ( buf); - } else { - result = "unkown"; - } - } else { result = ""; } - } else { result = ""; } - pclose(f); - return result; -} - - -void crashHandler(int sig_num, siginfo_t * info, void * ) { - const size_t maxDepth = 100; - //size_t stackDepth; - - void *stackAddrs[maxDepth]; - backtrace(stackAddrs, maxDepth); - - std::cerr << "signal " << sig_num << " (" << strsignal(sig_num) << "), address is " << info->si_addr << " from " << stackAddrs[0] << std::endl; - - void * array[50]; - int size = backtrace(array, 50); - - array[1] = stackAddrs[0]; - - char ** messages = backtrace_symbols(array, size); - - // skip first stack frame (points here) - for (int i = 1; i < size-1 && messages != NULL; ++i) { - char *mangledname = 0, *offset_begin = 0, *offset_end = 0; - - // find parantheses and +address offset surrounding mangled name - for (char *p = messages[i+1]; *p; ++p) { - if (*p == '(') { - mangledname = p; - } else if (*p == '+') { - offset_begin = p; - } else if (*p == ')') { - offset_end = p; - break; - } - } - - // if the line could be processed, attempt to demangle the symbol - if (mangledname && offset_begin && offset_end && mangledname < offset_begin) { - *mangledname++ = '\0'; - *offset_begin++ = '\0'; - *offset_end++ = '\0'; - - int status; - char * real_name = abi::__cxa_demangle(mangledname, 0, 0, &status); - - // if demangling is successful, output the demangled function name - if (status == 0) { - std::cerr << "[bt]: (" << i << ") " << messages[i+1] << " : " << real_name << " " << getFileAndLine(offset_end); - } - // otherwise, output the mangled function name - else { - std::cerr << "[bt]: (" << i << ") " << messages[i+1] << " : " - << mangledname << "+" << offset_begin << offset_end - << std::endl; - } - free(real_name); - } - // otherwise, print the whole line - else { - std::cerr << "[bt]: (" << i << ") " << messages[i+1] << std::endl; - } - } - std::cerr << std::endl; - - free(messages); - - exit(EXIT_FAILURE); -} - -void installCrashHandler(std::string b) { - binaryName = b; -#ifndef NDEBUG - struct sigaction sigact; - sigemptyset(&sigact.sa_mask); - sigact.sa_sigaction = crashHandler; - sigact.sa_flags = SA_RESTART | SA_SIGINFO; - - if (sigaction(SIGSEGV, &sigact, (struct sigaction *)NULL) != 0) { - std::cerr << "error setting signal handler for " << SIGSEGV << " " << strsignal(SIGSEGV) << std::endl; - - exit(EXIT_FAILURE); - } -#endif -} -#else -inline void installCrashHandler(std::string ) {} -#endif -#endif /* LINUXSTACKTRACE_H_ */ diff --git a/Util/MachineInfo.h b/Util/MachineInfo.h index 3fcb55e94..2000ee5f0 100644 --- a/Util/MachineInfo.h +++ b/Util/MachineInfo.h @@ -28,15 +28,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef MACHINE_INFO_H #define MACHINE_INFO_H -#if defined(__APPLE__) || defined(__FreeBSD__) -extern "C" { - #include - #include -} -#elif defined _WIN32 - #include -#endif - enum Endianness { LittleEndian = 1, BigEndian = 2 @@ -46,8 +37,9 @@ enum Endianness { inline Endianness getMachineEndianness() { int i(1); char *p = (char *) &i; - if (1 == p[0]) + if (1 == p[0]) { return LittleEndian; + } return BigEndian; } @@ -58,36 +50,4 @@ inline unsigned swapEndian(unsigned x) { return x; } -// Returns the physical memory size in kilobytes -inline unsigned GetPhysicalmemory(void){ -#if defined(SUN5) || defined(__linux__) - return (sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE)); - -#elif defined(__APPLE__) - int mib[2] = {CTL_HW, HW_MEMSIZE}; - long long memsize; - size_t len = sizeof(memsize); - sysctl(mib, 2, &memsize, &len, NULL, 0); - return memsize/1024; - -#elif defined(__FreeBSD__) - int mib[2] = {CTL_HW, HW_PHYSMEM}; - long long memsize; - size_t len = sizeof(memsize); - sysctl(mib, 2, &memsize, &len, NULL, 0); - return memsize/1024; - -#elif defined(_WIN32) - MEMORYSTATUSEX status; - status.dwLength = sizeof(status); - GlobalMemoryStatusEx(&status); - return status.ullTotalPhys/1024; -#else - std::cout << "[Warning] Compiling on unknown architecture." << std::endl - << "Please file a ticket at http://project-osrm.org" << std::endl; - return 2048*1024; /* 128 Mb default memory */ - -#endif -} #endif // MACHINE_INFO_H - diff --git a/DataStructures/MercatorUtil.h b/Util/MercatorUtil.h similarity index 100% rename from DataStructures/MercatorUtil.h rename to Util/MercatorUtil.h diff --git a/Util/ProgramOptions.h b/Util/ProgramOptions.h index 83b9daa9d..2c311698f 100644 --- a/Util/ProgramOptions.h +++ b/Util/ProgramOptions.h @@ -32,6 +32,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "OSRMException.h" #include "SimpleLogger.h" +#include + #include #include #include @@ -40,36 +42,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -#include -typedef boost::unordered_map< - const std::string, - boost::filesystem::path - > ServerPaths; - -namespace boost { - namespace filesystem { - // Validator for boost::filesystem::path, that verifies that the file - // exists. The validate() function must be defined in the same namespace - // as the target type, (boost::filesystem::path in this case), otherwise - // it is not called - inline void validate( - boost::any & v, - const std::vector & values, - boost::filesystem::path *, - int - ) { - boost::program_options::validators::check_first_occurrence(v); - const std::string & input_string = - boost::program_options::validators::get_single_string(values); - if(boost::filesystem::is_regular_file(input_string)) { - v = boost::any(boost::filesystem::path(input_string)); - } else { - throw OSRMException(input_string + " not found"); - } - } - } -} +const static unsigned INIT_OK_START_ENGINE = 0; +const static unsigned INIT_OK_DO_NOT_START_ENGINE = 1; +const static unsigned INIT_FAILED = -1; // support old capitalized option names by down-casing them with a regex replace inline void PrepareConfigFile( @@ -86,16 +62,16 @@ inline void PrepareConfigFile( output = boost::regex_replace( input_str, regex, format ); } - // generate boost::program_options object for the routing part -inline bool GenerateServerProgramOptions( +inline unsigned GenerateServerProgramOptions( const int argc, const char * argv[], ServerPaths & paths, std::string & ip_address, int & ip_port, int & requested_num_threads, - bool & use_shared_memory + bool & use_shared_memory, + bool & trial ) { // declare a group of options that will be allowed only on command line @@ -109,6 +85,11 @@ inline bool GenerateServerProgramOptions( &paths["config"] )->default_value("server.ini"), "Path to a configuration file" + ) + ( + "trial", + boost::program_options::value(&trial)->implicit_value(true), + "Quit after initialization" ); // declare a group of options that will be allowed both on command line @@ -162,7 +143,7 @@ inline bool GenerateServerProgramOptions( ) ( "sharedmemory,s", - boost::program_options::value(&use_shared_memory)->default_value(false), + boost::program_options::value(&use_shared_memory)->implicit_value(true), "Load data from shared memory" ); @@ -201,12 +182,12 @@ inline bool GenerateServerProgramOptions( if(option_variables.count("version")) { SimpleLogger().Write() << g_GIT_DESCRIPTION; - return false; + return INIT_OK_DO_NOT_START_ENGINE; } if(option_variables.count("help")) { SimpleLogger().Write() << visible_options; - return false; + return INIT_OK_DO_NOT_START_ENGINE; } boost::program_options::notify(option_variables); @@ -221,7 +202,7 @@ inline bool GenerateServerProgramOptions( SimpleLogger().Write() << "Reading options from: " << path_iterator->second.string(); std::string config_str; - PrepareConfigFile( paths["config"], config_str ); + PrepareConfigFile( path_iterator->second, config_str ); std::stringstream config_stream( config_str ); boost::program_options::store( parse_config_file(config_stream, config_file_options), @@ -230,14 +211,23 @@ inline bool GenerateServerProgramOptions( boost::program_options::notify(option_variables); } + if( 1 > requested_num_threads ) { + throw OSRMException("Number of threads must be a positive number"); + } + if( !use_shared_memory && option_variables.count("base") ) { - std::string base_string = paths["base"].string(); + path_iterator = paths.find("base"); + BOOST_ASSERT( paths.end() != path_iterator ); + std::string base_string = path_iterator->second.string(); + path_iterator = paths.find("hsgrdata"); if( path_iterator != paths.end() && !boost::filesystem::is_regular_file(path_iterator->second) ) { path_iterator->second = base_string + ".hsgr"; + } else { + throw OSRMException(base_string + ".hsgr not found"); } path_iterator = paths.find("nodesdata"); @@ -246,38 +236,52 @@ inline bool GenerateServerProgramOptions( !boost::filesystem::is_regular_file(path_iterator->second) ) { path_iterator->second = base_string + ".nodes"; + } else { + throw OSRMException(base_string + ".nodes not found"); } + path_iterator = paths.find("edgesdata"); if( path_iterator != paths.end() && !boost::filesystem::is_regular_file(path_iterator->second) ) { path_iterator->second = base_string + ".edges"; + } else { + throw OSRMException(base_string + ".edges not found"); } + path_iterator = paths.find("ramindex"); if( path_iterator != paths.end() && !boost::filesystem::is_regular_file(path_iterator->second) ) { path_iterator->second = base_string + ".ramIndex"; + } else { + throw OSRMException(base_string + ".ramIndex not found"); } + path_iterator = paths.find("fileindex"); if( path_iterator != paths.end() && !boost::filesystem::is_regular_file(path_iterator->second) ) { path_iterator->second = base_string + ".fileIndex"; + } else { + throw OSRMException(base_string + ".fileIndex not found"); } + path_iterator = paths.find("namesdata"); if( path_iterator != paths.end() && !boost::filesystem::is_regular_file(path_iterator->second) ) { path_iterator->second = base_string + ".names"; + } else { + throw OSRMException(base_string + ".namesIndex not found"); } path_iterator = paths.find("timestamp"); @@ -287,12 +291,15 @@ inline bool GenerateServerProgramOptions( ) { path_iterator->second = base_string + ".timestamp"; } - } - if( 1 > requested_num_threads ) { - throw OSRMException("Number of threads must be a positive number"); + return INIT_OK_START_ENGINE; } - return true; + if (use_shared_memory && !option_variables.count("base")) + { + return INIT_OK_START_ENGINE; + } + SimpleLogger().Write() << visible_options; + return INIT_OK_DO_NOT_START_ENGINE; } #endif /* PROGRAM_OPTIONS_H */ diff --git a/Util/StringUtil.h b/Util/StringUtil.h index d4b46cce2..158928820 100644 --- a/Util/StringUtil.h +++ b/Util/StringUtil.h @@ -36,6 +36,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include #include // precision: position after decimal point @@ -159,6 +160,47 @@ inline void stringSplit( boost::split(result, s, boost::is_any_of(std::string(&delim))); } +inline std::string EscapeJSONString(const std::string& input) { + std::string output; + output.reserve(input.size()); + for( + std::string::const_iterator iter = input.begin(); + iter != input.end(); + ++iter + ) { + switch (iter[0]) { + case '\\': + output += "\\\\"; + break; + case '"': + output += "\\\""; + break; + case '/': + output += "\\/"; + break; + case '\b': + output += "\\b"; + break; + case '\f': + output += "\\f"; + break; + case '\n': + output += "\\n"; + break; + case '\r': + output += "\\r"; + break; + case '\t': + output += "\\t"; + break; + default: + output += *iter; + break; + } + } + return output; +} + static std::string originals[] = {"&", "\"", "<", ">", "'", "[", "]", "\\"}; static std::string entities[] = {"&", """, "<", ">", "'", "&91;", "&93;", " \" }; @@ -177,6 +219,36 @@ inline std::string HTMLDeEntitize( std::string & result) { return result; } +inline std::size_t URIDecode(const std::string & input, std::string & output) { + std::string::const_iterator src_iter = input.begin(); + output.resize(input.size()+1); + std::size_t decoded_length = 0; + for( decoded_length = 0; src_iter != input.end(); ++decoded_length ) { + if( + src_iter[0] == '%' && + src_iter[1] && + src_iter[2] && + isxdigit(src_iter[1]) && + isxdigit(src_iter[2]) + ) { + std::string::value_type a = src_iter[1]; + std::string::value_type b = src_iter[2]; + a -= src_iter[1] < 58 ? 48 : src_iter[1] < 71 ? 55 : 87; + b -= src_iter[2] < 58 ? 48 : src_iter[2] < 71 ? 55 : 87; + output[decoded_length] = 16 * a + b; + src_iter += 3; + continue; + } + output[decoded_length] = *src_iter++; + } + output.resize(decoded_length); + return decoded_length; +} + +inline std::size_t URIDecodeInPlace(std::string & URI) { + return URIDecode(URI, URI); +} + inline bool StringStartsWith( const std::string & input, const std::string & prefix @@ -184,4 +256,18 @@ inline bool StringStartsWith( return boost::starts_with(input, prefix); } +inline std::string GetRandomString() { + char s[128]; + static const char alphanum[] = + "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"; + + for (int i = 0; i < 127; ++i) { + s[i] = alphanum[rand() % (sizeof(alphanum) - 1)]; + } + s[127] = 0; + return std::string(s); +} + #endif /* STRINGUTIL_H_ */ diff --git a/cmake/CheckCXXCompilerFlag.cmake b/cmake/CheckCXXCompilerFlag.cmake new file mode 100644 index 000000000..e396f75a9 --- /dev/null +++ b/cmake/CheckCXXCompilerFlag.cmake @@ -0,0 +1,29 @@ +# - Check whether the CXX compiler supports a given flag. +# CHECK_CXX_COMPILER_FLAG( ) +# - the compiler flag +# - variable to store the result +# This internally calls the check_cxx_source_compiles macro. See help +# for CheckCXXSourceCompiles for a listing of variables that can +# modify the build. + +# Copyright (c) 2006, Alexander Neundorf, +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + + +INCLUDE(CheckCXXSourceCompiles) + +MACRO (CHECK_CXX_COMPILER_FLAG _FLAG _RESULT) + SET(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}") + SET(CMAKE_REQUIRED_DEFINITIONS "${_FLAG}") + CHECK_CXX_SOURCE_COMPILES("int main() { return 0;}" ${_RESULT} + # Some compilers do not fail with a bad flag + FAIL_REGEX "unrecognized .*option" # GNU + FAIL_REGEX "ignoring unknown option" # MSVC + FAIL_REGEX "[Uu]nknown option" # HP + FAIL_REGEX "[Ww]arning: [Oo]ption" # SunPro + FAIL_REGEX "command option .* is not recognized" # XL + ) + SET (CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}") +ENDMACRO (CHECK_CXX_COMPILER_FLAG) diff --git a/cmake/pkgconfig.in b/cmake/pkgconfig.in new file mode 100644 index 000000000..e81febad8 --- /dev/null +++ b/cmake/pkgconfig.in @@ -0,0 +1,11 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +includedir=${prefix}/include/osrm +libdir=${prefix}/lib + +Name: libOSRM +Description: Project OSRM library +Version: @GIT_DESCRIPTION@ +Requires: +Libs: -L${libdir} -lOSRM +Libs.private: @BOOST_LIBRARY_LISTING@ +Cflags: -I${includedir} diff --git a/config/cucumber.yml b/config/cucumber.yml index fe3e05d9c..2cdea3688 100644 --- a/config/cucumber.yml +++ b/config/cucumber.yml @@ -2,7 +2,8 @@ ##YAML Template --- default: --require features --tags ~@todo --tags ~@bug --tag ~@stress -verify: --require features --tags ~@todo --tags ~@bug --tag ~@stress -f progress +verify: --require features --tags ~@todo --tags ~@bug --tags ~@stress -f progress +jenkins: --require features --tags ~@todo --tags ~@bug --tags ~@stress --tags ~@options -f progress bugs: --require features --tags @bug todo: --require features --tags @todo -all: --require features \ No newline at end of file +all: --require features diff --git a/datastore.cpp b/datastore.cpp index 74a7bcd0b..8eefc0fba 100644 --- a/datastore.cpp +++ b/datastore.cpp @@ -25,6 +25,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "DataStructures/OriginalEdgeData.h" #include "DataStructures/QueryEdge.h" #include "DataStructures/SharedMemoryFactory.h" #include "DataStructures/SharedMemoryVectorWrapper.h" @@ -34,7 +35,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "Server/DataStructures/SharedDataType.h" #include "Server/DataStructures/SharedBarriers.h" #include "Util/BoostFileSystemFix.h" -#include "Util/ProgramOptions.h" +#include "Util/DataStoreOptions.h" #include "Util/SimpleLogger.h" #include "Util/UUID.h" #include "typedefs.h" @@ -50,8 +51,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include int main( const int argc, const char * argv[] ) { - SharedBarriers barrier; + LogPolicy::GetInstance().Unmute(); + SharedBarriers barrier; #ifdef __linux__ if( -1 == mlockall(MCL_CURRENT | MCL_FUTURE) ) { @@ -61,31 +63,27 @@ int main( const int argc, const char * argv[] ) { #endif try { - boost::interprocess::scoped_lock< - boost::interprocess::named_mutex - > pending_lock(barrier.pending_update_mutex); - } catch(...) { - // hard unlock in case of any exception. - barrier.pending_update_mutex.unlock(); + try { + boost::interprocess::scoped_lock< + boost::interprocess::named_mutex + > pending_lock(barrier.pending_update_mutex); + } catch(...) { + // hard unlock in case of any exception. + barrier.pending_update_mutex.unlock(); + } + } catch(const std::exception & e) { + SimpleLogger().Write(logWARNING) << "[exception] " << e.what(); } - try { - LogPolicy::GetInstance().Unmute(); - SimpleLogger().Write(logDEBUG) << "Checking input parameters"; - bool use_shared_memory = false; - std::string ip_address; - int ip_port, requested_num_threads; + try { + SimpleLogger().Write(logDEBUG) << "Checking input parameters"; ServerPaths server_paths; if( - !GenerateServerProgramOptions( + !GenerateDataStoreOptions( argc, argv, - server_paths, - ip_address, - ip_port, - requested_num_threads, - use_shared_memory + server_paths ) ) { return 0; @@ -124,7 +122,8 @@ int main( const int argc, const char * argv[] ) { paths_iterator = server_paths.find("fileindex"); BOOST_ASSERT(server_paths.end() != paths_iterator); BOOST_ASSERT(!paths_iterator->second.empty()); - const std::string & file_index_file_name = paths_iterator->second.string(); + const boost::filesystem::path index_file_path_absolute = boost::filesystem::portable_canonical(paths_iterator->second); + const std::string & file_index_file_name = index_file_path_absolute.string(); paths_iterator = server_paths.find("nodesdata"); BOOST_ASSERT(server_paths.end() != paths_iterator); BOOST_ASSERT(!paths_iterator->second.empty()); @@ -160,7 +159,7 @@ int main( const int argc, const char * argv[] ) { shared_layout_ptr->ram_index_file_name ); // add zero termination - unsigned end_of_string_index = std::min(1023ul, file_index_file_name.length()); + unsigned end_of_string_index = std::min((std::size_t)1023, file_index_file_name.length()); shared_layout_ptr->ram_index_file_name[end_of_string_index] = '\0'; // collect number of elements to store in shared memory object @@ -324,9 +323,9 @@ int main( const int argc, const char * argv[] ) { (char*)&(current_edge_data), sizeof(OriginalEdgeData) ); - via_node_ptr[i] = current_edge_data.viaNode; - name_id_ptr[i] = current_edge_data.nameID; - turn_instructions_ptr[i] = current_edge_data.turnInstruction; + via_node_ptr[i] = current_edge_data.via_node; + name_id_ptr[i] = current_edge_data.name_id; + turn_instructions_ptr[i] = current_edge_data.turn_instruction; } edges_input_stream.close(); @@ -379,7 +378,7 @@ int main( const int argc, const char * argv[] ) { ); hsgr_input_stream.close(); - //TODO acquire lock + // acquire lock SharedMemory * data_type_memory = SharedMemoryFactory::Get( CURRENT_REGIONS, sizeof(SharedDataTimestamp), diff --git a/extractor.cpp b/extractor.cpp index 35c590cb7..deae476a9 100644 --- a/extractor.cpp +++ b/extractor.cpp @@ -37,6 +37,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "Util/ProgramOptions.h" #include "Util/SimpleLogger.h" #include "Util/StringUtil.h" +#include "Util/TimingUtil.h" #include "Util/UUID.h" #include "typedefs.h" @@ -122,6 +123,7 @@ int main (int argc, char *argv[]) { if(!option_variables.count("input")) { SimpleLogger().Write(logWARNING) << "No input file specified"; + SimpleLogger().Write() << visible_options; return -1; } @@ -191,6 +193,11 @@ int main (int argc, char *argv[]) { (get_timestamp() - parsing_start_time) << " seconds"; + if( externalMemory.all_edges_list.empty() ) { + SimpleLogger().Write(logWARNING) << "The input data is empty, exiting."; + return -1; + } + externalMemory.PrepareData(output_file_name, restrictionsFileName); delete parser; diff --git a/features/bicycle/access.feature b/features/bicycle/access.feature index ad6378836..2087327ca 100644 --- a/features/bicycle/access.feature +++ b/features/bicycle/access.feature @@ -1,6 +1,6 @@ @routing @bicycle @access Feature: Bike - Access tags on ways -Reference: http://wiki.openstreetmap.org/wiki/Key:access +# Reference: http://wiki.openstreetmap.org/wiki/Key:access Background: Given the profile "bicycle" @@ -153,14 +153,14 @@ Reference: http://wiki.openstreetmap.org/wiki/Key:access Scenario: Bike - Access combinations Then routability should be - | highway | access | vehicle | bicycle | bothw | - | runway | private | | yes | x | - | footway | | no | permissive | x | - | motorway | | | yes | x | - | track | forestry | | permissive | x | - | cycleway | yes | designated | no | | - | primary | | yes | private | | - | residential | permissive | | no | | + | highway | access | vehicle | bicycle | forw | backw | + | runway | private | | yes | x | x | + | footway | | no | permissive | x | x | + | motorway | | | yes | x | | + | track | forestry | | permissive | x | x | + | cycleway | yes | designated | no | | | + | primary | | yes | private | | | + | residential | permissive | | no | | | Scenario: Bike - Ignore access tags for other modes Then routability should be diff --git a/features/bicycle/access_node.feature b/features/bicycle/access_node.feature index a926896e9..5a6f2b5f9 100644 --- a/features/bicycle/access_node.feature +++ b/features/bicycle/access_node.feature @@ -1,6 +1,6 @@ @routing @bicycle @access Feature: Bike - Access tags on nodes -Reference: http://wiki.openstreetmap.org/wiki/Key:access +# Reference: http://wiki.openstreetmap.org/wiki/Key:access Background: Given the profile "bicycle" diff --git a/features/bicycle/cycleway.feature b/features/bicycle/cycleway.feature index 989e2ae79..643fdcea2 100644 --- a/features/bicycle/cycleway.feature +++ b/features/bicycle/cycleway.feature @@ -1,29 +1,29 @@ @routing @bicycle @cycleway Feature: Bike - Cycle tracks/lanes -Reference: http://wiki.openstreetmap.org/wiki/Key:cycleway +# Reference: http://wiki.openstreetmap.org/wiki/Key:cycleway Background: Given the profile "bicycle" Scenario: Bike - Cycle tracks/lanes should enable biking Then routability should be - | highway | cycleway | bothw | - | motorway | | | - | motorway | track | x | - | motorway | lane | x | - | motorway | shared | x | - | motorway | share_busway | x | - | motorway | sharrow | x | - | some_tag | track | x | - | some_tag | lane | x | - | some_tag | shared | x | - | some_tag | share_busway | x | - | some_tag | sharrow | x | - | residential | track | x | - | residential | lane | x | - | residential | shared | x | - | residential | share_busway | x | - | residential | sharrow | x | + | highway | cycleway | forw | backw | + | motorway | | | | + | motorway | track | x | | + | motorway | lane | x | | + | motorway | shared | x | | + | motorway | share_busway | x | | + | motorway | sharrow | x | | + | some_tag | track | x | x | + | some_tag | lane | x | x | + | some_tag | shared | x | x | + | some_tag | share_busway | x | x | + | some_tag | sharrow | x | x | + | residential | track | x | x | + | residential | lane | x | x | + | residential | shared | x | x | + | residential | share_busway | x | x | + | residential | sharrow | x | x | Scenario: Bike - Left/right side cycleways on implied bidirectionals Then routability should be @@ -70,12 +70,12 @@ Reference: http://wiki.openstreetmap.org/wiki/Key:cycleway Scenario: Bike - Access tags should overwrite cycleway access Then routability should be - | highway | cycleway | access | bothw | - | motorway | track | no | | - | residential | track | no | | - | footway | track | no | | - | cycleway | track | no | | - | motorway | lane | yes | x | - | residential | lane | yes | x | - | footway | lane | yes | x | - | cycleway | lane | yes | x | + | highway | cycleway | access | forw | backw | + | motorway | track | no | | | + | residential | track | no | | | + | footway | track | no | | | + | cycleway | track | no | | | + | motorway | lane | yes | x | | + | residential | lane | yes | x | x | + | footway | lane | yes | x | x | + | cycleway | lane | yes | x | x | diff --git a/features/bicycle/maxspeed.feature b/features/bicycle/maxspeed.feature index 22732e1ef..ba5bfba4b 100644 --- a/features/bicycle/maxspeed.feature +++ b/features/bicycle/maxspeed.feature @@ -3,18 +3,19 @@ Feature: Bike - Max speed restrictions Background: Use specific speeds Given the profile "bicycle" + And a grid size of 1000 meters Scenario: Bicycle - Respect maxspeeds when lower that way type speed Then routability should be - | highway | maxspeed | bothw | - | residential | | 49s ~10% | - | residential | 10 | 72s ~10% | + | highway | maxspeed | bothw | + | residential | | 15 km/h | + | residential | 10 | 10 km/h | Scenario: Bicycle - Ignore maxspeed when higher than way speed Then routability should be - | highway | maxspeed | bothw | - | residential | | 49s ~10% | - | residential | 80 | 49s ~10% | + | highway | maxspeed | bothw | + | residential | | 15 km/h | + | residential | 80 | 15 km/h | @todo Scenario: Bicycle - Maxspeed formats @@ -47,9 +48,9 @@ Feature: Bike - Max speed restrictions | bc | residential | 80 | When I route I should get - | from | to | route | time | - | a | b | ab | 24s ~5% | - | b | c | bc | 24s ~5% | + | from | to | route | speed | + | a | b | ab | 15 km/h | + | b | c | bc | 15 km/h | Scenario: Bike - Forward/backward maxspeed Given the shortcuts @@ -60,14 +61,14 @@ Feature: Bike - Max speed restrictions | snail | 720s ~10% | Then routability should be - | maxspeed | maxspeed:forward | maxspeed:backward | forw | backw | - | | | | bike | bike | - | 10 | | | run | run | - | | 10 | | run | bike | - | | | 10 | bike | run | - | 1 | 10 | | run | snail | - | 1 | | 10 | snail | run | - | 1 | 5 | 10 | walk | run | + | maxspeed | maxspeed:forward | maxspeed:backward | forw | backw | + | | | | 15 km/h | 15 km/h | + | 10 | | | 10 km/h | 10 km/h | + | | 10 | | 10 km/h | 15 km/h | + | | | 10 | 15 km/h | 10 km/h | + | 2 | 10 | | 10 km/h | 2 km/h | + | 2 | | 10 | 2 km/h | 10 km/h | + | 2 | 5 | 10 | 5 km/h | 10 km/h | Scenario: Bike - Maxspeed should not allow routing on unroutable ways Then routability should be diff --git a/features/bicycle/oneway.feature b/features/bicycle/oneway.feature index e2d609a31..4dd9e1fa7 100644 --- a/features/bicycle/oneway.feature +++ b/features/bicycle/oneway.feature @@ -1,7 +1,7 @@ @routing @bicycle @oneway Feature: Bike - Oneway streets -Handle oneways streets, as defined at http://wiki.openstreetmap.org/wiki/OSM_tags_for_routing -Usually we can push bikes against oneways, but we use foot=no to prevent this in these tests +# Handle oneways streets, as defined at http://wiki.openstreetmap.org/wiki/OSM_tags_for_routing +# Usually we can push bikes against oneways, but we use foot=no to prevent this in these tests Background: Given the profile "bicycle" diff --git a/features/bicycle/pushing.feature b/features/bicycle/pushing.feature index cd6723a6f..2b238292a 100644 --- a/features/bicycle/pushing.feature +++ b/features/bicycle/pushing.feature @@ -57,11 +57,11 @@ Feature: Bike - Accessability of different way types Scenario: Bike - Pushing bikes on ways with foot=yes Then routability should be - | highway | foot | bothw | - | motorway | | | - | motorway | yes | foot | - | runway | | | - | runway | yes | foot | + | highway | foot | forw | backw | + | motorway | | | | + | motorway | yes | foot | | + | runway | | | | + | runway | yes | foot | foot | @todo Scenario: Bike - Pushing bikes on ways with foot=yes in one direction diff --git a/features/bicycle/restrictions.feature b/features/bicycle/restrictions.feature index 081d72eac..6218d812b 100644 --- a/features/bicycle/restrictions.feature +++ b/features/bicycle/restrictions.feature @@ -1,7 +1,7 @@ @routing @bicycle @restrictions Feature: Bike - Turn restrictions - Ignore turn restrictions on bicycle, since you always become a temporary pedestrian. - Note that if u-turns are allowed, turn restrictions can lead to suprising, but correct, routes. +# Ignore turn restrictions on bicycle, since you always become a temporary pedestrian. +# Note that if u-turns are allowed, turn restrictions can lead to suprising, but correct, routes. Background: Given the profile "bicycle" diff --git a/features/bicycle/stop_area.feature b/features/bicycle/stop_area.feature index a51b951a1..5f6c3bc26 100644 --- a/features/bicycle/stop_area.feature +++ b/features/bicycle/stop_area.feature @@ -1,7 +1,7 @@ @routing @bicycle @stop_area @todo Feature: Bike - Stop areas for public transport -Platforms and railway/bus lines are connected using a relation rather that a way, as specified in: -http://wiki.openstreetmap.org/wiki/Tag:public_transport%3Dstop_area +# Platforms and railway/bus lines are connected using a relation rather that a way, as specified in: +# http://wiki.openstreetmap.org/wiki/Tag:public_transport%3Dstop_area Background: Given the profile "bicycle" diff --git a/features/bicycle/surface.feature b/features/bicycle/surface.feature index a723119e7..216307b21 100644 --- a/features/bicycle/surface.feature +++ b/features/bicycle/surface.feature @@ -7,34 +7,34 @@ Feature: Bike - Surfaces Scenario: Bicycle - Slow surfaces Then routability should be | highway | surface | bothw | - | cycleway | | 49s | - | cycleway | asphalt | 49s | - | cycleway | cobblestone:flattened | 73s | - | cycleway | paving_stones | 73s | - | cycleway | compacted | 73s | - | cycleway | cobblestone | 121s | - | cycleway | unpaved | 121s | - | cycleway | fine_gravel | 121s | - | cycleway | gravel | 121s | - | cycleway | pebbelstone | 121s | - | cycleway | dirt | 121s | - | cycleway | earth | 121s | - | cycleway | grass | 121s | - | cycleway | mud | 241s | - | cycleway | sand | 241s | + | cycleway | | 48s | + | cycleway | asphalt | 48s | + | cycleway | cobblestone:flattened | 72s | + | cycleway | paving_stones | 72s | + | cycleway | compacted | 72s | + | cycleway | cobblestone | 120s | + | cycleway | unpaved | 120s | + | cycleway | fine_gravel | 120s | + | cycleway | gravel | 120s | + | cycleway | pebbelstone | 120s | + | cycleway | dirt | 120s | + | cycleway | earth | 120s | + | cycleway | grass | 120s | + | cycleway | mud | 240s | + | cycleway | sand | 240s | Scenario: Bicycle - Good surfaces on small paths Then routability should be | highway | surface | bothw | - | cycleway | | 49s | - | path | | 61s | - | track | | 61s | - | track | asphalt | 49s | - | path | asphalt | 49s | + | cycleway | | 48s | + | path | | 60s | + | track | | 60s | + | track | asphalt | 48s | + | path | asphalt | 48s | Scenario: Bicycle - Surfaces should not make unknown ways routable Then routability should be | highway | surface | bothw | - | cycleway | | 49s | + | cycleway | | 48s | | nosense | | | | nosense | asphalt | | diff --git a/features/bicycle/train.feature b/features/bicycle/train.feature index d9b43a3bf..aafa2030b 100644 --- a/features/bicycle/train.feature +++ b/features/bicycle/train.feature @@ -1,6 +1,6 @@ @routing @bicycle @train Feature: Bike - Handle ferry routes -Bringing bikes on trains and subways +# Bringing bikes on trains and subways Background: Given the profile "bicycle" diff --git a/features/bicycle/way.feature b/features/bicycle/way.feature index 07eea546b..b9beb5f0f 100644 --- a/features/bicycle/way.feature +++ b/features/bicycle/way.feature @@ -5,8 +5,8 @@ Feature: Bike - Accessability of different way types Given the profile "bicycle" Scenario: Bike - Routability of way types - Bikes are allowed on footways etc because you can pull your bike at a lower speed. - Pier is not allowed, since it's tagged using man_made=pier. + # Bikes are allowed on footways etc because you can pull your bike at a lower speed. + # Pier is not allowed, since it's tagged using man_made=pier. Then routability should be | highway | bothw | diff --git a/features/car/access.feature b/features/car/access.feature index 758e7939d..37dfed4c6 100644 --- a/features/car/access.feature +++ b/features/car/access.feature @@ -1,6 +1,6 @@ @routing @car @access Feature: Car - Restricted access -Reference: http://wiki.openstreetmap.org/wiki/Key:access +# Reference: http://wiki.openstreetmap.org/wiki/Key:access Background: Given the profile "car" diff --git a/features/car/maxspeed.feature b/features/car/maxspeed.feature index bce449d88..df37e3fb5 100644 --- a/features/car/maxspeed.feature +++ b/features/car/maxspeed.feature @@ -1,5 +1,6 @@ @routing @maxspeed @car Feature: Car - Max speed restrictions +When a max speed is set, osrm will use 2/3 of that as the actual speed. Background: Use specific speeds Given the profile "car" @@ -12,12 +13,12 @@ Feature: Car - Max speed restrictions And the ways | nodes | highway | maxspeed | | ab | trunk | | - | bc | trunk | 10 | + | bc | trunk | 60 | When I route I should get - | from | to | route | time | - | a | b | ab | 42s ~10% | - | b | c | bc | 360s ~10% | + | from | to | route | speed | + | a | b | ab | 85 km/h | + | b | c | bc | 40 km/h | Scenario: Car - Do not ignore maxspeed when higher than way speed Given the node map @@ -26,32 +27,25 @@ Feature: Car - Max speed restrictions And the ways | nodes | highway | maxspeed | | ab | residential | | - | bc | residential | 85 | + | bc | residential | 90 | When I route I should get - | from | to | route | time | - | a | b | ab | 144s ~10% | - | b | c | bc | 42s ~10% | + | from | to | route | speed | + | a | b | ab | 25 km/h | + | b | c | bc | 60 km/h | Scenario: Car - Forward/backward maxspeed - Given the shortcuts - | key | value | - | car | 12s ~10% | - | run | 73s ~10% | - | walk | 146s ~10% | - | snail | 720s ~10% | - - And a grid size of 100 meters + Given a grid size of 100 meters Then routability should be - | maxspeed | maxspeed:forward | maxspeed:backward | forw | backw | - | | | | car | car | - | 10 | | | run | run | - | | 10 | | run | car | - | | | 10 | car | run | - | 1 | 10 | | run | snail | - | 1 | | 10 | snail | run | - | 1 | 5 | 10 | walk | run | + | highway | maxspeed | maxspeed:forward | maxspeed:backward | forw | backw | + | primary | | | | 65 km/h | 65 km/h | + | primary | 60 | | | 40 km/h | 40 km/h | + | primary | | 60 | | 40 km/h | 65 km/h | + | primary | | | 60 | 65 km/h | 40 km/h | + | primary | 15 | 60 | | 40 km/h | 10 km/h | + | primary | 15 | | 60 | 10 km/h | 40 km/h | + | primary | 15 | 30 | 60 | 20 km/h | 40 km/h | Scenario: Car - Maxspeed should not allow routing on unroutable ways Then routability should be @@ -68,4 +62,4 @@ Feature: Car - Max speed restrictions | runway | | | | | | | | runway | | | 100 | | | | | runway | | | | 100 | | | - | runway | | | | | 100 | | + | runway | | | | | 100 | | \ No newline at end of file diff --git a/features/car/oneway.feature b/features/car/oneway.feature index 9d209fd20..b47c3c6fd 100644 --- a/features/car/oneway.feature +++ b/features/car/oneway.feature @@ -1,6 +1,6 @@ @routing @car @oneway Feature: Car - Oneway streets -Handle oneways streets, as defined at http://wiki.openstreetmap.org/wiki/OSM_tags_for_routing +# Handle oneways streets, as defined at http://wiki.openstreetmap.org/wiki/OSM_tags_for_routing Background: Given the profile "car" diff --git a/features/car/restrictions.feature b/features/car/restrictions.feature index b3170093b..f808c5d91 100644 --- a/features/car/restrictions.feature +++ b/features/car/restrictions.feature @@ -1,7 +1,7 @@ @routing @car @restrictions Feature: Car - Turn restrictions - Handle turn restrictions as defined by http://wiki.openstreetmap.org/wiki/Relation:restriction - Note that if u-turns are allowed, turn restrictions can lead to suprising, but correct, routes. +# Handle turn restrictions as defined by http://wiki.openstreetmap.org/wiki/Relation:restriction +# Note that if u-turns are allowed, turn restrictions can lead to suprising, but correct, routes. Background: Use car routing Given the profile "car" diff --git a/features/car/speed.feature b/features/car/speed.feature new file mode 100644 index 000000000..261f9aa62 --- /dev/null +++ b/features/car/speed.feature @@ -0,0 +1,24 @@ +@routing @car @speed +Feature: Car - speeds + + Background: + Given the profile "car" + And a grid size of 1000 meters + + Scenario: Car - speed of various way types + Then routability should be + | highway | oneway | bothw | + | motorway | no | 90 km/h | + | motorway_link | no | 75 km/h | + | trunk | no | 85 km/h | + | trunk_link | no | 70 km/h | + | primary | no | 65 km/h | + | primary_link | no | 60 km/h | + | secondary | no | 55 km/h | + | secondary_link | no | 50 km/h | + | tertiary | no | 40 km/h | + | tertiary_link | no | 30 km/h | + | unclassified | no | 25 km/h | + | residential | no | 25 km/h | + | living_street | no | 10 km/h | + | service | no | 15 km/h | diff --git a/features/foot/access.feature b/features/foot/access.feature index b870ae392..4d81d0e45 100644 --- a/features/foot/access.feature +++ b/features/foot/access.feature @@ -1,6 +1,6 @@ @routing @foot @access Feature: Foot - Access tags on ways -Reference: http://wiki.openstreetmap.org/wiki/Key:access +# Reference: http://wiki.openstreetmap.org/wiki/Key:access Background: Given the profile "foot" diff --git a/features/foot/access_node.feature b/features/foot/access_node.feature index 477f8b4a8..5a4a1314e 100644 --- a/features/foot/access_node.feature +++ b/features/foot/access_node.feature @@ -1,6 +1,6 @@ @routing @foot @access Feature: Foot - Access tags on nodes -Reference: http://wiki.openstreetmap.org/wiki/Key:access +# Reference: http://wiki.openstreetmap.org/wiki/Key:access Background: Given the profile "foot" diff --git a/features/foot/oneway.feature b/features/foot/oneway.feature index 0a9498a4e..77562e5e2 100644 --- a/features/foot/oneway.feature +++ b/features/foot/oneway.feature @@ -1,6 +1,6 @@ @routing @foot @oneway Feature: Foot - Oneway streets -Handle oneways streets, as defined at http://wiki.openstreetmap.org/wiki/OSM_tags_for_routing +# Handle oneways streets, as defined at http://wiki.openstreetmap.org/wiki/OSM_tags_for_routing Background: Given the profile "foot" diff --git a/features/foot/restrictions.feature b/features/foot/restrictions.feature index d16965b05..8d6a0297f 100644 --- a/features/foot/restrictions.feature +++ b/features/foot/restrictions.feature @@ -1,6 +1,6 @@ @routing @foot @restrictions Feature: Foot - Turn restrictions - Ignore turn restrictions on foot. +# Ignore turn restrictions on foot. Background: Given the profile "foot" diff --git a/features/foot/roundabout.feature b/features/foot/roundabout.feature index cfe65d476..5aa9860fb 100644 --- a/features/foot/roundabout.feature +++ b/features/foot/roundabout.feature @@ -6,8 +6,8 @@ Feature: Roundabout Instructions @todo Scenario: Foot - Roundabout instructions - You can walk in both directions on a roundabout, bu the normal roundabout instructions don't - make sense when you're going the opposite way around the roundabout. + # You can walk in both directions on a roundabout, bu the normal roundabout instructions don't + # make sense when you're going the opposite way around the roundabout. Given the node map | | | v | | | diff --git a/features/nearest/pick.feature b/features/nearest/pick.feature index c0761f62d..08e665243 100644 --- a/features/nearest/pick.feature +++ b/features/nearest/pick.feature @@ -59,12 +59,12 @@ Feature: Locating Nearest node on a Way - pick closest way Given the node locations | node | lat | lon | | a | -85 | -180 | - | b | 0 | 0 | - | c | 85 | 180 | - | x | -70 | -100 | - | y | 70 | 100 | - | v | 1 | 1 | - | w | -1 | -1 | + | b | -85 | -160 | + | c | -85 | -140 | + | x | 75 | -180 | + | y | 75 | -180 | + | v | 1 | 1 | + | w | -1 | -1 | And the ways | nodes | @@ -73,6 +73,6 @@ Feature: Locating Nearest node on a Way - pick closest way When I request nearest I should get | in | out | | x | a | - | y | c | - | v | b | - | w | b | + | y | a | + | v | c | + | w | c | diff --git a/features/options/files.feature b/features/options/files.feature new file mode 100644 index 000000000..41252238e --- /dev/null +++ b/features/options/files.feature @@ -0,0 +1,27 @@ +@routing @options @files +Feature: Command line options: files +# Normally when launching osrm-routed, it will keep running as a server until it's shut down. +# For testing program options, the --trial option is used, which causes osrm-routed to quit +# immediately after initialization. This makes testing easier and faster. +# +# The {base} part of the options to osrm-routed will be expanded to the actual base path of +# the preprocessed file. + + Background: + Given the profile "testbot" + And the node map + | a | b | + And the ways + | nodes | + | ab | + And I preprocess data + + Scenario: Passing base file + When I run "osrm-routed {base}.osrm --trial" + Then stdout should contain /^\[info\] starting up engines/ + And stdout should contain /\d{1,2}\.\d{1,2}\.\d{1,2}/ + And stdout should contain /compiled at/ + And stdout should contain /^\[info\] loaded plugin: viaroute/ + And stdout should contain /^\[info\] trial run/ + And stdout should contain /^\[info\] shutdown completed/ + And it should exit with code 0 diff --git a/features/options/help.feature b/features/options/help.feature new file mode 100644 index 000000000..40ec0177e --- /dev/null +++ b/features/options/help.feature @@ -0,0 +1,74 @@ +@routing @options +Feature: Command line options: help + + Background: + Given the profile "testbot" + + Scenario: Help should be shown when no options are passed + When I run "osrm-routed" + Then stderr should be empty + And stdout should contain "osrm-routed []:" + And stdout should contain "Options:" + And stdout should contain "--version" + And stdout should contain "--help" + And stdout should contain "--config" + And stdout should contain "--trial" + And stdout should contain "Configuration:" + And stdout should contain "--hsgrdata arg" + And stdout should contain "--nodesdata arg" + And stdout should contain "--edgesdata arg" + And stdout should contain "--ramindex arg" + And stdout should contain "--fileindex arg" + And stdout should contain "--namesdata arg" + And stdout should contain "--timestamp arg" + And stdout should contain "--ip" + And stdout should contain "--port" + And stdout should contain "--threads" + And stdout should contain "--sharedmemory" + And it should exit with code 0 + + Scenario: Help, short + When I run "osrm-routed -h" + Then stderr should be empty + And stdout should contain "osrm-routed []:" + And stdout should contain "Options:" + And stdout should contain "--version" + And stdout should contain "--help" + And stdout should contain "--config" + And stdout should contain "--trial" + And stdout should contain "Configuration:" + And stdout should contain "--hsgrdata arg" + And stdout should contain "--nodesdata arg" + And stdout should contain "--edgesdata arg" + And stdout should contain "--ramindex arg" + And stdout should contain "--fileindex arg" + And stdout should contain "--namesdata arg" + And stdout should contain "--timestamp arg" + And stdout should contain "--ip" + And stdout should contain "--port" + And stdout should contain "--threads" + And stdout should contain "--sharedmemory" + And it should exit with code 0 + + Scenario: Help, long + When I run "osrm-routed --help" + Then stderr should be empty + And stdout should contain "osrm-routed []:" + And stdout should contain "Options:" + And stdout should contain "--version" + And stdout should contain "--help" + And stdout should contain "--config" + And stdout should contain "--trial" + And stdout should contain "Configuration:" + And stdout should contain "--hsgrdata arg" + And stdout should contain "--nodesdata arg" + And stdout should contain "--edgesdata arg" + And stdout should contain "--ramindex arg" + And stdout should contain "--fileindex arg" + And stdout should contain "--namesdata arg" + And stdout should contain "--timestamp arg" + And stdout should contain "--ip" + And stdout should contain "--port" + And stdout should contain "--threads" + And stdout should contain "--sharedmemory" + And it should exit with code 0 \ No newline at end of file diff --git a/features/options/invalid.feature b/features/options/invalid.feature new file mode 100644 index 000000000..b1ea4b420 --- /dev/null +++ b/features/options/invalid.feature @@ -0,0 +1,19 @@ +@routing @options +Feature: Command line options: invalid options + + Background: + Given the profile "testbot" + + Scenario: Non-existing option + When I run "osrm-routed --fly-me-to-the-moon" + Then stdout should be empty + And stderr should contain "exception" + And stderr should contain "fly-me-to-the-moon" + And it should exit with code 1 + + Scenario: Missing file + When I run "osrm-routed over-the-rainbow.osrm" + Then stdout should contain "over-the-rainbow.osrm" + And stderr should contain "exception" + And stderr should contain "does not exist" + And it should exit with code 1 diff --git a/features/options/version.feature b/features/options/version.feature new file mode 100644 index 000000000..9ad933924 --- /dev/null +++ b/features/options/version.feature @@ -0,0 +1,22 @@ +@routing @options +Feature: Command line options: version +# the regex will match these two formats: +# v0.3.7.0 # this is the normal format when you build from a git clone +# -128-NOTFOUND # if you build from a shallow clone (used on Travis) + + Background: + Given the profile "testbot" + + Scenario: Version, short + When I run "osrm-routed --v" + Then stderr should be empty + And stdout should contain 1 line + And stdout should contain /(v\d{1,2}\.\d{1,2}\.\d{1,2}|\w*-\d+-\w+)/ + And it should exit with code 0 + + Scenario: Version, long + When I run "osrm-routed --version" + Then stderr should be empty + And stdout should contain 1 line + And stdout should contain /(v\d{1,2}\.\d{1,2}\.\d{1,2}|\w*-\d+-\w+)/ + And it should exit with code 0 diff --git a/features/step_definitions/data.rb b/features/step_definitions/data.rb index 1e9fa7149..d6cea41da 100644 --- a/features/step_definitions/data.rb +++ b/features/step_definitions/data.rb @@ -2,6 +2,10 @@ Given /^the profile "([^"]*)"$/ do |profile| set_profile profile end +Given(/^the import format "(.*?)"$/) do |format| + set_input_format format +end + Given /^a grid size of (\d+) meters$/ do |meters| set_grid_size meters end diff --git a/features/step_definitions/locate.rb b/features/step_definitions/locate.rb index 3b1d5d7da..9d3d74f65 100644 --- a/features/step_definitions/locate.rb +++ b/features/step_definitions/locate.rb @@ -1,7 +1,7 @@ When /^I request locate I should get$/ do |table| reprocess actual = [] - OSRMLauncher.new("#{@osm_file}.osrm") do + OSRMBackgroundLauncher.new("#{@osm_file}.osrm") do table.hashes.each_with_index do |row,ri| in_node = find_node_by_name row['in'] raise "*** unknown in-node '#{row['in']}" unless in_node diff --git a/features/step_definitions/nearest.rb b/features/step_definitions/nearest.rb index 352f6bc89..ae5a79cf5 100644 --- a/features/step_definitions/nearest.rb +++ b/features/step_definitions/nearest.rb @@ -1,7 +1,7 @@ When /^I request nearest I should get$/ do |table| reprocess actual = [] - OSRMLauncher.new("#{@osm_file}.osrm") do + OSRMBackgroundLauncher.new("#{@osm_file}.osrm") do table.hashes.each_with_index do |row,ri| in_node = find_node_by_name row['in'] raise "*** unknown in-node '#{row['in']}" unless in_node diff --git a/features/step_definitions/options.rb b/features/step_definitions/options.rb new file mode 100644 index 000000000..6b349f8b5 --- /dev/null +++ b/features/step_definitions/options.rb @@ -0,0 +1,55 @@ +When(/^I run "osrm\-routed\s?(.*?)"$/) do |options| + Dir.chdir TEST_FOLDER do + if options.include? '{base}' + # expand {base} to base path of preprocessed data file + raise "*** Cannot expand {base} without a preprocessed file." unless @osm_file + options_expanded = options.gsub "{base}", "#{@osm_file}" + else + options_expanded = options + end + + begin + Timeout.timeout(1) do + @stdout = `#{BIN_PATH}/osrm-routed #{options_expanded} 2>error.log` + @stderr = File.read 'error.log' + @exit_code = $?.exitstatus + end + rescue Timeout::Error + raise "*** osrm-routed didn't quit. Maybe the --trial option wasn't used?" + end + end +end + +Then /^it should exit with code (\d+)$/ do |code| + @exit_code.should == code.to_i +end + +Then /^stdout should contain "(.*?)"$/ do |str| + @stdout.should include(str) +end + +Then /^stderr should contain "(.*?)"$/ do |str| + @stderr.should include(str) +end + +Then(/^stdout should contain \/(.*)\/$/) do |regex_str| + regex = Regexp.new regex_str + @stdout.should =~ regex +end + +Then(/^stderr should contain \/(.*)\/$/) do |regex_str| + regex = Regexp.new regex_str + @stderr.should =~ regex +end + +Then /^stdout should be empty$/ do + @stdout.should == "" +end + +Then /^stderr should be empty$/ do + @stderr.should == "" +end + +Then /^stdout should contain (\d+) lines?$/ do |lines| + @stdout.lines.count.should == lines.to_i +end diff --git a/features/step_definitions/requests.rb b/features/step_definitions/requests.rb index fb1f9f8b7..e6bdcae84 100644 --- a/features/step_definitions/requests.rb +++ b/features/step_definitions/requests.rb @@ -1,6 +1,6 @@ When /^I request \/(.*)$/ do |path| reprocess - OSRMLauncher.new("#{@osm_file}.osrm") do + OSRMBackgroundLauncher.new("#{@osm_file}.osrm") do @response = request_path path end end @@ -16,9 +16,7 @@ Then /^response should be valid JSON$/ do end Then /^response should be well-formed$/ do - @json['version'].class.should == Float @json['status'].class.should == Fixnum - @json['transactionId'].class.should == String end Then /^response should be a well-formed route$/ do @@ -28,6 +26,7 @@ Then /^response should be a well-formed route$/ do @json['route_geometry'].class.should == String @json['route_instructions'].class.should == Array @json['via_points'].class.should == Array + @json['via_indices'].class.should == Array end When /^I preprocess data$/ do diff --git a/features/step_definitions/routability.rb b/features/step_definitions/routability.rb index 6c5148b14..d8a8a3945 100644 --- a/features/step_definitions/routability.rb +++ b/features/step_definitions/routability.rb @@ -1,3 +1,42 @@ +def test_routability_row i + result = {} + ['forw','backw'].each do |direction| + a = Location.new @origin[0]+(1+WAY_SPACING*i)*@zoom, @origin[1] + b = Location.new @origin[0]+(3+WAY_SPACING*i)*@zoom, @origin[1] + r = {} + r[:response] = request_route direction=='forw' ? [a,b] : [b,a] + r[:query] = @query + r[:json] = JSON.parse(r[:response].body) + + r[:status] = route_status r[:response] + if r[:status].empty? == false + r[:route] = way_list r[:json]['route_instructions'] + + if r[:route]=="w#{i}" + r[:time] = r[:json]['route_summary']['total_time'] + r[:distance] = r[:json]['route_summary']['total_distance'] + r[:speed] = r[:time]>0 ? (3.6*r[:distance]/r[:time]).to_i : nil + else + # if we hit the wrong way segment, we assume it's + # because the one we tested was not unroutable + r = {} + end + end + result[direction] = r + end + + # check if forw and backw returned the same values + result['bothw'] = {} + [:status,:time,:distance,:speed].each do |key| + if result['forw'][key] == result['backw'][key] + result['bothw'][key] = result['forw'][key] + else + result['bothw'][key] = 'diff' + end + end + result +end + Then /^routability should be$/ do |table| build_ways_from_table table reprocess @@ -5,42 +44,34 @@ Then /^routability should be$/ do |table| if table.headers&["forw","backw","bothw"] == [] raise "*** routability tabel must contain either 'forw', 'backw' or 'bothw' column" end - OSRMLauncher.new("#{@osm_file}.osrm") do + OSRMBackgroundLauncher.new("#{@osm_file}.osrm") do table.hashes.each_with_index do |row,i| - got = row.dup + output_row = row.dup attempts = [] - ['forw','backw','bothw'].each do |direction| - if table.headers.include? direction - if direction == 'forw' || direction == 'bothw' - a = Location.new @origin[0]+(1+WAY_SPACING*i)*@zoom, @origin[1] - b = Location.new @origin[0]+(3+WAY_SPACING*i)*@zoom, @origin[1] - response = request_route [a,b] - elsif direction == 'backw' || direction == 'bothw' - a = Location.new @origin[0]+(3+WAY_SPACING*i)*@zoom, @origin[1] - b = Location.new @origin[0]+(1+WAY_SPACING*i)*@zoom, @origin[1] - response = request_route [a,b] - end - want = shortcuts_hash[row[direction]] || row[direction] #expand shortcuts - got[direction] = route_status response - json = JSON.parse(response.body) - if got[direction].empty? == false - route = way_list json['route_instructions'] - if route != "w#{i}" - got[direction] = '' - elsif want =~ /^\d+s/ - time = json['route_summary']['total_time'] - got[direction] = "#{time}s" - end - end - if FuzzyMatch.match got[direction], want - got[direction] = row[direction] - else - attempts << { :attempt => direction, :query => @query, :response => response } - end + result = test_routability_row i + directions = ['forw','backw','bothw'] + (directions & table.headers).each do |direction| + want = shortcuts_hash[row[direction]] || row[direction] #expand shortcuts + case want + when '', 'x' + output_row[direction] = result[direction][:status].to_s + when /^\d+s/ + output_row[direction] = "#{result[direction][:time]}s" + when /^\d+ km\/h/ + output_row[direction] = "#{result[direction][:speed]} km/h" + else + raise "*** Unknown expectation format: #{want}" + end + + if FuzzyMatch.match output_row[direction], want + output_row[direction] = row[direction] end end - log_fail row,got,attempts if got != row - actual << got + + if output_row != row + log_fail row,output_row,result + end + actual << output_row end end table.routing_diff! actual diff --git a/features/step_definitions/routing.rb b/features/step_definitions/routing.rb index ead847166..ecefd79be 100644 --- a/features/step_definitions/routing.rb +++ b/features/step_definitions/routing.rb @@ -1,7 +1,7 @@ When /^I route I should get$/ do |table| reprocess actual = [] - OSRMLauncher.new("#{@osm_file}.osrm") do + OSRMBackgroundLauncher.new("#{@osm_file}.osrm") do table.hashes.each_with_index do |row,ri| waypoints = [] if row['from'] and row['to'] @@ -46,6 +46,8 @@ When /^I route I should get$/ do |table| compasses = compass_list json['route_instructions'] turns = turn_list json['route_instructions'] modes = mode_list json['route_instructions'] + times = time_list json['route_instructions'] + distances = distance_list json['route_instructions'] end end @@ -67,6 +69,17 @@ When /^I route I should get$/ do |table| raise "*** Time must be specied in seconds. (ex: 60s)" unless row['time'] =~ /\d+s/ got['time'] = instructions ? "#{json['route_summary']['total_time'].to_s}s" : '' end + if table.headers.include?('speed') + if row['speed'] != '' && instructions + raise "*** Speed must be specied in km/h. (ex: 50 km/h)" unless row['speed'] =~ /\d+ km\/h/ + time = json['route_summary']['total_time'] + distance = json['route_summary']['total_distance'] + speed = time>0 ? (3.6*distance/time).to_i : nil + got['speed'] = "#{speed} km/h" + else + got['speed'] = '' + end + end if table.headers.include? 'bearing' got['bearing'] = bearings end @@ -79,6 +92,12 @@ When /^I route I should get$/ do |table| if table.headers.include? 'modes' got['modes'] = modes end + if table.headers.include? 'times' + got['times'] = times + end + if table.headers.include? 'distances' + got['distances'] = distances + end if table.headers.include? '#' # comment column got['#'] = row['#'] # copy value so it always match end @@ -94,8 +113,7 @@ When /^I route I should get$/ do |table| end unless ok - failed = { :attempt => 'route', :query => @query, :response => response } - log_fail row,got,[failed] + log_fail row,got, { 'route' => {:query => @query, :response => response} } end actual << got diff --git a/features/support/data.rb b/features/support/data.rb index b11e460f7..1d9522994 100644 --- a/features/support/data.rb +++ b/features/support/data.rb @@ -7,15 +7,13 @@ OSM_GENERATOR = 'osrm-test' OSM_UID = 1 TEST_FOLDER = 'test' DATA_FOLDER = 'cache' -PREPROCESS_LOG_FILE = 'preprocessing.log' -LOG_FILE = 'fail.log' OSM_TIMESTAMP = '2000-00-00T00:00:00Z' DEFAULT_SPEEDPROFILE = 'bicycle' WAY_SPACING = 100 DEFAULT_GRID_SIZE = 100 #meters PROFILES_PATH = '../profiles' BIN_PATH = '../build' - +DEFAULT_INPUT_FORMAT = 'osm' DEFAULT_ORIGIN = [1,1] class Location @@ -27,6 +25,15 @@ class Location end end +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 + def sanitized_scenario_title @sanitized_scenario_title ||= @scenario_title.gsub /[^0-9A-Za-z.\-]/, '_' end @@ -246,8 +253,8 @@ def write_timestamp end def reprocess - use_pbf = true Dir.chdir TEST_FOLDER do + use_pbf = (input_format=='pbf') write_osm write_timestamp convert_osm_to_pbf if use_pbf diff --git a/features/support/env.rb b/features/support/env.rb index a6a99b9f5..2cbc4e46d 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -1,7 +1,7 @@ require 'rspec/expectations' DEFAULT_PORT = 5000 - +DEFAULT_TIMEOUT = 2 puts "Ruby version #{RUBY_VERSION}" unless RUBY_VERSION.to_f >= 1.9 @@ -16,3 +16,15 @@ else puts "Using default port #{OSRM_PORT}" end +if ENV["OSRM_TIMEOUT"] + OSRM_TIMEOUT = ENV["OSRM_TIMEOUT"].to_i + puts "Timeout set to #{OSRM_TIMEOUT}" +else + OSRM_TIMEOUT = DEFAULT_TIMEOUT + puts "Using default timeout #{OSRM_TIMEOUT}" +end + + +AfterConfiguration do |config| + clear_log_files +end \ No newline at end of file diff --git a/features/support/hooks.rb b/features/support/hooks.rb index e3b6df0e5..4c58a1750 100644 --- a/features/support/hooks.rb +++ b/features/support/hooks.rb @@ -2,7 +2,23 @@ STRESS_TIMEOUT = 300 Before do |scenario| - @scenario_title = scenario.title + # feature name + case scenario + when Cucumber::Ast::Scenario + @feature_name = scenario.feature.name + when Cucumber::Ast::OutlineTable::ExampleRow + @feature_name = scenario.scenario_outline.feature.name + end + + # scenario name + case scenario + when Cucumber::Ast::Scenario + @scenario_title = scenario.name + when Cucumber::Ast::OutlineTable::ExampleRow + @scenario_title = scenario.scenario_outline.name + end + + @scenario_time = Time.now.strftime("%Y-%m-%dT%H:%m:%SZ") reset_data @has_logged_preprocess_info = false diff --git a/features/support/launch.rb b/features/support/launch.rb index 02e236665..6699fb947 100644 --- a/features/support/launch.rb +++ b/features/support/launch.rb @@ -1,11 +1,9 @@ require 'socket' require 'open3' -LAUNCH_TIMEOUT = 2 -SHUTDOWN_TIMEOUT = 2 OSRM_ROUTED_LOG_FILE = 'osrm-routed.log' -class OSRMLauncher +class OSRMBackgroundLauncher def initialize input_file, &block @input_file = input_file Dir.chdir TEST_FOLDER do @@ -21,7 +19,7 @@ class OSRMLauncher private def launch - Timeout.timeout(LAUNCH_TIMEOUT) do + Timeout.timeout(OSRM_TIMEOUT) do osrm_up wait_for_connection end @@ -30,7 +28,7 @@ class OSRMLauncher end def shutdown - Timeout.timeout(SHUTDOWN_TIMEOUT) do + Timeout.timeout(OSRM_TIMEOUT) do osrm_down end rescue Timeout::Error @@ -50,6 +48,7 @@ class OSRMLauncher def osrm_up return if osrm_up? @pid = Process.spawn("#{BIN_PATH}/osrm-routed #{@input_file} --port #{OSRM_PORT}",:out=>OSRM_ROUTED_LOG_FILE, :err=>OSRM_ROUTED_LOG_FILE) + Process.detach(@pid) # avoid zombie processes end def osrm_down diff --git a/features/support/locate.rb b/features/support/locate.rb index b7dc55f6d..900724703 100644 --- a/features/support/locate.rb +++ b/features/support/locate.rb @@ -3,7 +3,7 @@ require 'net/http' def request_locate_url path @query = path uri = URI.parse "#{HOST}/#{path}" - Timeout.timeout(REQUEST_TIMEOUT) do + Timeout.timeout(OSRM_TIMEOUT) do Net::HTTP.get_response uri end rescue Errno::ECONNREFUSED => e diff --git a/features/support/log.rb b/features/support/log.rb index 1607bfb59..e5d34cc26 100644 --- a/features/support/log.rb +++ b/features/support/log.rb @@ -1,3 +1,19 @@ +# logging + +PREPROCESS_LOG_FILE = 'preprocessing.log' +LOG_FILE = 'fail.log' + + +def clear_log_files + Dir.chdir TEST_FOLDER do + # emptying existing files, rather than deleting and writing new ones makes it + # easier to use tail -f from the command line + `echo '' > #{OSRM_ROUTED_LOG_FILE}` + `echo '' > #{PREPROCESS_LOG_FILE}` + `echo '' > #{LOG_FILE}` + end +end + def log s='', type=nil if type == :preprocess file = PREPROCESS_LOG_FILE @@ -24,17 +40,20 @@ def log_scenario_fail_info @has_logged_scenario_info = true end -def log_fail expected,actual,failed +def log_fail expected,got,attempts log_scenario_fail_info log "== " log "Expected: #{expected}" - log "Got: #{actual}" + log "Got: #{got}" log - failed.each do |fail| - log "Attempt: #{fail[:attempt]}" - log "Query: #{fail[:query]}" - log "Response: #{fail[:response].body}" - log + ['route','forw','backw'].each do |direction| + if attempts[direction] + attempts[direction] + log "Direction: #{direction}" + log "Query: #{attempts[direction][:query]}" + log "Response: #{attempts[direction][:response].body}" + log + end end end diff --git a/features/support/nearest.rb b/features/support/nearest.rb index e37130735..77fc351a9 100644 --- a/features/support/nearest.rb +++ b/features/support/nearest.rb @@ -3,7 +3,7 @@ require 'net/http' def request_nearest_url path @query = path uri = URI.parse "#{HOST}/#{path}" - Timeout.timeout(REQUEST_TIMEOUT) do + Timeout.timeout(OSRM_TIMEOUT) do Net::HTTP.get_response uri end rescue Errno::ECONNREFUSED => e diff --git a/features/support/route.rb b/features/support/route.rb index b1cb71b01..1fb7398e4 100644 --- a/features/support/route.rb +++ b/features/support/route.rb @@ -1,7 +1,6 @@ require 'net/http' HOST = "http://localhost:#{OSRM_PORT}" -REQUEST_TIMEOUT = 1 DESTINATION_REACHED = 15 #OSRM instruction code class Hash @@ -17,7 +16,8 @@ def request_path path, waypoints=[], options={} params = (locs + options.to_param).join('&') params = nil if params=="" uri = URI.parse ["#{HOST}/#{path}", params].compact.join('?') - Timeout.timeout(REQUEST_TIMEOUT) do + @query = uri.to_s + Timeout.timeout(OSRM_TIMEOUT) do Net::HTTP.get_response uri end rescue Errno::ECONNREFUSED => e @@ -80,25 +80,23 @@ def route_status response end end -def way_list instructions +def extract_instruction_list instructions, index, postfix=nil instructions.reject { |r| r[0].to_s=="#{DESTINATION_REACHED}" }. - map { |r| r[1] }. - map { |r| r=="" ? '""' : r }. + map { |r| r[index] }. + map { |r| (r=="" || r==nil) ? '""' : "#{r}#{postfix}" }. join(',') end +def way_list instructions + extract_instruction_list instructions, 1 +end + def compass_list instructions - instructions.reject { |r| r[0].to_s=="#{DESTINATION_REACHED}" }. - map { |r| r[6] }. - map { |r| r=="" ? '""' : r }. - join(',') + extract_instruction_list instructions, 6 end def bearing_list instructions - instructions.reject { |r| r[0].to_s=="#{DESTINATION_REACHED}" }. - map { |r| r[7] }. - map { |r| r=="" ? '""' : r }. - join(',') + extract_instruction_list instructions, 7 end def turn_list instructions @@ -125,15 +123,20 @@ def turn_list instructions # replace instructions codes with strings # "11-3" (enter roundabout and leave a 3rd exit) gets converted to "enter_roundabout-3" instructions.map do |r| - r[0].to_s.gsub!(/^\d*/) do |match| + r[0].to_s.gsub(/^\d*/) do |match| types[match.to_i].to_s end end.join(',') end def mode_list instructions - instructions.reject { |r| r[0].to_s=="#{DESTINATION_REACHED}" }. - map { |r| r[8] }. - map { |r| (r=="" || r==nil) ? '""' : r }. - join(',') + extract_instruction_list instructions, 8 +end + +def time_list instructions + extract_instruction_list instructions, 4, "s" +end + +def distance_list instructions + extract_instruction_list instructions, 2, "m" end \ No newline at end of file diff --git a/features/testbot/bad.feature b/features/testbot/bad.feature index e3a2ded9f..98f5dbef2 100644 --- a/features/testbot/bad.feature +++ b/features/testbot/bad.feature @@ -45,8 +45,8 @@ Feature: Handle bad data in a graceful manner @poles Scenario: Routing close to the north/south pole - Mercator is undefined close to the poles. - All nodes and request with latitude to close to either of the poles should therefore be ignored. + # Mercator is undefined close to the poles. + # All nodes and request with latitude to close to either of the poles should therefore be ignored. Given the node locations | node | lat | lon | diff --git a/features/testbot/bearing.feature b/features/testbot/bearing.feature index bd282e7bd..c306af92d 100644 --- a/features/testbot/bearing.feature +++ b/features/testbot/bearing.feature @@ -141,8 +141,8 @@ Feature: Compass bearing | f | e | abcdef | W | 270 | Scenario: Bearings at high latitudes - The coordinas below was calculated using http://www.movable-type.co.uk/scripts/latlong.html, - to form square with sides of 1 km. + # The coordinas below was calculated using http://www.movable-type.co.uk/scripts/latlong.html, + # to form square with sides of 1 km. Given the node locations | node | lat | lon | @@ -176,8 +176,8 @@ Feature: Compass bearing | d | b | bd | NW | 315 | Scenario: Bearings at high negative latitudes - The coordinas below was calculated using http://www.movable-type.co.uk/scripts/latlong.html, - to form square with sides of 1 km. + # The coordinas below was calculated using http://www.movable-type.co.uk/scripts/latlong.html, + # to form square with sides of 1 km. Given the node locations | node | lat | lon | diff --git a/features/testbot/bugs.feature b/features/testbot/bugs.feature index d79967cea..26be28aa6 100644 --- a/features/testbot/bugs.feature +++ b/features/testbot/bugs.feature @@ -3,61 +3,3 @@ Feature: Known bugs Background: Given the profile "testbot" - - Scenario: Routing on a oneway roundabout - Given the node map - | | d | c | | - | e | | | b | - | f | | | a | - | | g | h | | - - And the ways - | nodes | oneway | - | ab | yes | - | bc | yes | - | cd | yes | - | de | yes | - | ef | yes | - | fg | yes | - | gh | yes | - | ha | yes | - - When I route I should get - | from | to | route | - | a | b | ab | - | b | c | bc | - | c | d | cd | - | d | e | de | - | e | f | ef | - | f | g | fg | - | g | h | gh | - | h | a | ha | - | b | a | bc,cd,de,ef,fg,gh,ha | - | c | b | cd,de,ef,fg,gh,ha,ab | - | d | c | de,ef,fg,gh,ha,ab,bc | - | e | d | ef,fg,gh,ha,ab,bc,cd | - | f | e | fg,gh,ha,ab,bc,cd,de | - | g | f | gh,ha,ab,bc,cd,de,ef | - | h | g | ha,ab,bc,cd,de,ef,fg | - | a | h | ab,bc,cd,de,ef,fg,gh | - - @726 - Scenario: Weird looping, manual input - Given the node locations - | node | lat | lon | - | a | 55.660778 | 12.573909 | - | b | 55.660672 | 12.573693 | - | c | 55.660128 | 12.572546 | - | d | 55.660015 | 12.572476 | - | e | 55.660119 | 12.572325 | - | x | 55.660818 | 12.574051 | - | y | 55.660073 | 12.574067 | - - And the ways - | nodes | - | abc | - | cdec | - - When I route I should get - | from | to | route | turns | - | x | y | abc | head,destination | diff --git a/features/testbot/example.feature b/features/testbot/example.feature index d0c44ac32..c2aa1e926 100644 --- a/features/testbot/example.feature +++ b/features/testbot/example.feature @@ -1,6 +1,5 @@ @routing @testbot @example Feature: Testbot - Walkthrough - # A complete walk-through of how this data is processed can be found at: # https://github.com/DennisOSRM/Project-OSRM/wiki/Processing-Flow diff --git a/features/testbot/fixed.feature b/features/testbot/fixed.feature new file mode 100644 index 000000000..0edf25c15 --- /dev/null +++ b/features/testbot/fixed.feature @@ -0,0 +1,26 @@ +@routing @testbot @fixed +Feature: Fixed bugs, kept to check for regressions + + Background: + Given the profile "testbot" + + @726 + Scenario: Weird looping, manual input + Given the node locations + | node | lat | lon | + | a | 55.660778 | 12.573909 | + | b | 55.660672 | 12.573693 | + | c | 55.660128 | 12.572546 | + | d | 55.660015 | 12.572476 | + | e | 55.660119 | 12.572325 | + | x | 55.660818 | 12.574051 | + | y | 55.660073 | 12.574067 | + + And the ways + | nodes | + | abc | + | cdec | + + When I route I should get + | from | to | route | turns | + | x | y | abc | head,destination | diff --git a/features/testbot/impedance.feature b/features/testbot/impedance.feature index 72a814c2c..cab9ec3da 100644 --- a/features/testbot/impedance.feature +++ b/features/testbot/impedance.feature @@ -1,9 +1,8 @@ @routing @testbot @impedance @todo Feature: Setting impedance and speed separately -These tests assume that the speed is not factored into the impedance by OSRM internally. -Instead the speed can optionally be factored into the weiht in the lua profile. - -Note: With the default grid size of 100m, the diagonals has a length if 141.42m +# These tests assume that the speed is not factored into the impedance by OSRM internally. +# Instead the speed can optionally be factored into the weiht in the lua profile. +# Note: With the default grid size of 100m, the diagonals has a length if 141.42m Background: Given the profile "testbot" @@ -55,8 +54,8 @@ Note: With the default grid size of 100m, the diagonals has a length if 141.42m | c | b | btc | Scenario: Use both impedance and speed (multiplied) when picking route - OSRM should not factor speed into impedance internally. However, the profile can choose to do so, - and this test expect the testbot profile to do it. + # OSRM should not factor speed into impedance internally. However, the profile can choose to do so, + # and this test expect the testbot profile to do it. Given the node map | | s | | t | | | a | | b | | c | diff --git a/features/testbot/maxspeed.feature b/features/testbot/maxspeed.feature index efe143241..5b27f9d9d 100644 --- a/features/testbot/maxspeed.feature +++ b/features/testbot/maxspeed.feature @@ -5,48 +5,25 @@ Feature: Car - Max speed restrictions Given the profile "testbot" Scenario: Testbot - Respect maxspeeds when lower that way type speed - Given the node map - | a | b | c | d | - - And the ways - | nodes | maxspeed | - | ab | | - | bc | 24 | - | cd | 18 | - - When I route I should get - | from | to | route | time | - | a | b | ab | 10s +-1 | - | b | a | ab | 10s +-1 | - | b | c | bc | 15s +-1 | - | c | b | bc | 15s +-1 | - | c | d | cd | 20s +-1 | - | d | c | cd | 20s +-1 | + Then routability should be + | maxspeed | bothw | + | | 36 km/h | + | 18 | 18 km/h | Scenario: Testbot - Ignore maxspeed when higher than way speed - Given the node map - | a | b | c | - - And the ways - | nodes | maxspeed | - | ab | | - | bc | 200 | - - When I route I should get - | from | to | route | time | - | a | b | ab | 10s +-1 | - | b | a | ab | 10s +-1 | - | b | c | bc | 10s +-1 | - | c | b | bc | 10s +-1 | + Then routability should be + | maxspeed | bothw | + | | 36 km/h | + | 100 km/h | 36 km/h | @opposite Scenario: Testbot - Forward/backward maxspeed Then routability should be | maxspeed | maxspeed:forward | maxspeed:backward | forw | backw | - | | | | 20s +-1 | 20s +-1 | - | 18 | | | 40s +-1 | 40s +-1 | - | | 18 | | 40s +-1 | 20s +-1 | - | | | 18 | 20s +-1 | 40s +-1 | - | 9 | 18 | | 40s +-1 | 80s +-1 | - | 9 | | 18 | 80s +-1 | 40s +-1 | - | 9 | 24 | 18 | 30s +-1 | 40s +-1 | + | | | | 36 km/h | 36 km/h | + | 18 | | | 18 km/h | 18 km/h | + | | 18 | | 18 km/h | 36 km/h | + | | | 18 | 36 km/h | 18 km/h | + | 9 | 18 | | 18 km/h | 9 km/h | + | 9 | | 18 | 9 km/h | 18 km/h | + | 9 | 24 | 18 | 24 km/h | 18 km/h | \ No newline at end of file diff --git a/features/testbot/oneway.feature b/features/testbot/oneway.feature new file mode 100644 index 000000000..42f50acda --- /dev/null +++ b/features/testbot/oneway.feature @@ -0,0 +1,42 @@ +@routing @testbot @oneway +Feature: Testbot - oneways + + Background: + Given the profile "testbot" + + Scenario: Routing on a oneway roundabout + Given the node map + | | d | c | | + | e | | | b | + | f | | | a | + | | g | h | | + + And the ways + | nodes | oneway | + | ab | yes | + | bc | yes | + | cd | yes | + | de | yes | + | ef | yes | + | fg | yes | + | gh | yes | + | ha | yes | + + When I route I should get + | from | to | route | + | a | b | ab | + | b | c | bc | + | c | d | cd | + | d | e | de | + | e | f | ef | + | f | g | fg | + | g | h | gh | + | h | a | ha | + | b | a | bc,cd,de,ef,fg,gh,ha | + | c | b | cd,de,ef,fg,gh,ha,ab | + | d | c | de,ef,fg,gh,ha,ab,bc | + | e | d | ef,fg,gh,ha,ab,bc,cd | + | f | e | fg,gh,ha,ab,bc,cd,de | + | g | f | gh,ha,ab,bc,cd,de,ef | + | h | g | ha,ab,bc,cd,de,ef,fg | + | a | h | ab,bc,cd,de,ef,fg,gh | \ No newline at end of file diff --git a/features/testbot/opposite.feature b/features/testbot/opposite.feature index f4b4822e4..cd350e73b 100644 --- a/features/testbot/opposite.feature +++ b/features/testbot/opposite.feature @@ -13,6 +13,6 @@ Feature: Separate settings for forward/backward direction | abcd | river | When I route I should get - | from | to | route | distance | time | - | a | d | abcd | 300 +- 1m | 31s | - | d | a | abcd | 300 +- 1m | 68s | + | from | to | route | distance | speed | + | a | d | abcd | 300 +- 1m | 36 km/h | + | d | a | abcd | 300 +- 1m | 16 km/h | diff --git a/features/testbot/penalty.feature b/features/testbot/penalty.feature index dcf280430..85f43c7ed 100644 --- a/features/testbot/penalty.feature +++ b/features/testbot/penalty.feature @@ -1,6 +1,6 @@ @routing @penalty @signal Feature: Penalties -Testbot uses a signal penalty of 7s. +# Testbot uses a signal penalty of 7s. Background: Given the profile "testbot" diff --git a/features/testbot/projection.feature b/features/testbot/projection.feature index 6d94480dc..5b35f47bf 100644 --- a/features/testbot/projection.feature +++ b/features/testbot/projection.feature @@ -1,13 +1,13 @@ -@routing @projection @todo +@routing @projection Feature: Projection to nearest point on road -Waypoints should be projected perpendicular onto the closest road, also at high latitudes. +# Waypoints are projected perpendiculary onto the closest road Background: - The coordinas below was calculated using http://www.movable-type.co.uk/scripts/latlong.html - The nodes are placed as follows, with ab, bc and bd all being 1 km in length each: - | | | c | - | | b | | (this is sketch only, real data is in the table below) - | a | | d | + # The coordinas below was calculated using http://www.movable-type.co.uk/scripts/latlong.html + # The nodes are placed as follows, with ab, bc and bd all being 1 km in length each: + # | | | c | + # | | b | | (this is sketch only, real data is in the table below) + # | a | | d | Given the profile "testbot" Given the node locations @@ -24,15 +24,15 @@ Waypoints should be projected perpendicular onto the closest road, also at high Scenario: Projection onto way at high latitudes, 1km distance When I route I should get | from | to | route | compass | bearing | distance | - | b | a | abc | SW | 225 | 1000m +-3 | - | b | c | abc | NE | 45 | 1000m +-3 | - | a | d | abc | NE | 45 | 1000m +-3 | - | d | a | abc | SW | 225 | 1000m +-3 | - | c | d | abc | SW | 225 | 1000m +-3 | - | d | c | abc | NE | 45 | 1000m +-3 | + | b | a | abc | SW | 225 | 1000m +-7 | + | b | c | abc | NE | 45 | 1000m +-7 | + | a | d | abc | NE | 45 | 1000m +-7 | + | d | a | abc | SW | 225 | 1000m +-7 | + | c | d | abc | SW | 225 | 1000m +-7 | + | d | c | abc | NE | 45 +-1 | 1000m +-7 | - Scenario: Projection onto way at high latitudes, no distance + Scenario: Projection onto way at high latitudes, no distance When I route I should get | from | to | route | distance | - | d | b | abc | 0m | - | b | d | abc | 0m | + | d | b | abc | 0m +-4 | + | b | d | abc | 0m +-4 | diff --git a/features/testbot/protobuffer.feature b/features/testbot/protobuffer.feature new file mode 100644 index 000000000..016a233be --- /dev/null +++ b/features/testbot/protobuffer.feature @@ -0,0 +1,156 @@ +@routing @pbf +Feature: Importing protobuffer (.pbf) format +# Test normally read .osm, which is faster than .pbf files, +# since we don't need to use osmosis to first convert to .pbf +# The scenarios in this file test the ability to import .pbf files, +# including nodes, way, restictions, and a various special situations. + + Background: + Given the profile "testbot" + And the import format "pbf" + + Scenario: Testbot - Protobuffer import, nodes and ways + Given the node map + | | | | d | + | a | b | c | | + | | | | e | + + And the ways + | nodes | highway | oneway | + | abc | primary | | + | cd | primary | yes | + | ce | river | | + | de | primary | | + + When I route I should get + | from | to | route | + | d | c | de,ce | + | e | d | de | + + + Scenario: Testbot - Protobuffer import, turn restiction relations + Given the node map + | | n | | + | w | j | e | + | | s | | + + And the ways + | nodes | oneway | + | sj | yes | + | nj | -1 | + | wj | -1 | + | ej | -1 | + + And the relations + | type | way:from | way:to | node:via | restriction | + | restriction | sj | wj | j | no_left_turn | + + When I route I should get + | from | to | route | + | s | w | | + | s | n | sj,nj | + | s | e | sj,ej | + + + Scenario: Testbot - Protobuffer import, distances at longitude 45 + Given the node locations + | node | lat | lon | + | a | 80 | 45 | + | b | 0 | 45 | + + And the ways + | nodes | + | ab | + + When I route I should get + | from | to | route | distance | + | a | b | ab | 8905559m ~0.1% | + + Scenario: Testbot - Protobuffer import, distances at longitude 80 + Given the node locations + | node | lat | lon | + | a | 80 | 80 | + | b | 0 | 80 | + + And the ways + | nodes | + | ab | + + When I route I should get + | from | to | route | distance | + | a | b | ab | 8905559m ~0.1% | + + Scenario: Testbot - Protobuffer import, empty dataset + Given the node map + | | + + Given the ways + | nodes | + + When I preprocess data + Then "osrm-extract" should return code 255 + + + Scenario: Testbot - Protobuffer import, streetnames with UTF characters + Given the node map + | a | b | c | d | + + And the ways + | nodes | name | + | ab | Scandinavian København | + | bc | Japanese 東京 | + | cd | Cyrillic Москва | + + When I route I should get + | from | to | route | + | a | b | Scandinavian København | + | b | c | Japanese 東京 | + | c | d | Cyrillic Москва | + + Scenario: Testbot - Protobuffer import, bearing af 45 degree intervals + Given the node map + | b | a | h | + | c | x | g | + | d | e | f | + + And the ways + | nodes | + | xa | + | xb | + | xc | + | xd | + | xe | + | xf | + | xg | + | xh | + + When I route I should get + | from | to | route | compass | bearing | + | x | a | xa | N | 0 | + | x | b | xb | NW | 315 | + | x | c | xc | W | 270 | + | x | d | xd | SW | 225 | + | x | e | xe | S | 180 | + | x | f | xf | SE | 135 | + | x | g | xg | E | 90 | + | x | h | xh | NE | 45 | + + + Scenario: Testbot - Protobuffer import, rraffic signals should incur a delay + Given the node map + | a | b | c | + | d | e | f | + + And the nodes + | node | highway | + | e | traffic_signals | + + And the ways + | nodes | + | abc | + | def | + + When I route I should get + | from | to | route | time | distance | + | a | c | abc | 20s +-1 | 200m +-1 | + | d | f | def | 27s +-1 | 200m +-1 | diff --git a/features/testbot/routes.feature b/features/testbot/routes.feature index 9d3e5e9f9..bc1d75eb4 100644 --- a/features/testbot/routes.feature +++ b/features/testbot/routes.feature @@ -5,7 +5,7 @@ Feature: OSM Route Relation Given the profile "testbot" Scenario: Prioritize ways that are part of route relations - This scenario assumes that the testbot uses an impedance of 0.5 for ways that are part of 'testbot' routes. + # This scenario assumes that the testbot uses an impedance of 0.5 for ways that are part of 'testbot' routes. Given the node map | s | | | t | | | | diff --git a/features/testbot/speed.feature b/features/testbot/speed.feature new file mode 100644 index 000000000..c9a983136 --- /dev/null +++ b/features/testbot/speed.feature @@ -0,0 +1,31 @@ +@routing @speed @testbot +Feature: Testbot - speeds + + Background: Use specific speeds + Given the profile "testbot" + + Scenario: Testbot - Speed on roads + Then routability should be + | highway | bothw | + | primary | 36 km/h | + | unknown | 24 km/h | + | secondary | 18 km/h | + | tertiary | 12 km/h | + + Scenario: Testbot - Speed on rivers, table + Then routability should be + | highway | forw | backw | + | river | 36 km/h | 16 km/h | + + Scenario: Testbot - Speed on rivers, map + Given the node map + | a | b | + + And the ways + | nodes | highway | + | ab | river | + + When I route I should get + | from | to | route | speed | time | distance | + | a | b | ab | 36 km/h | 10s | 100m | + | b | a | ab | 16 km/h | 22s | 100m | diff --git a/features/testbot/time.feature b/features/testbot/time.feature index 7d05607c9..f15a499b8 100644 --- a/features/testbot/time.feature +++ b/features/testbot/time.feature @@ -1,9 +1,9 @@ @routing @time Feature: Estimation of travel time -Testbot speeds: -Primary road: 36km/h = 36000m/3600s = 100m/10s -Secondary road: 18km/h = 18000m/3600s = 100m/20s -Tertiary road: 12km/h = 12000m/3600s = 100m/30s +# Testbot speeds: +# Primary road: 36km/h = 36000m/3600s = 100m/10s +# Secondary road: 18km/h = 18000m/3600s = 100m/20s +# Tertiary road: 12km/h = 12000m/3600s = 100m/30s Background: Use specific speeds Given the profile "testbot" @@ -16,15 +16,15 @@ Tertiary road: 12km/h = 12000m/3600s = 100m/30s | f | e | d | And the ways - | nodes | highway | - | xa | primary | - | xb | primary | - | xc | primary | - | xd | primary | - | xe | primary | - | xf | primary | - | xg | primary | - | xh | primary | + | nodes | highway | + | xa | primary | + | xb | primary | + | xc | primary | + | xd | primary | + | xe | primary | + | xf | primary | + | xg | primary | + | xh | primary | When I route I should get | from | to | route | time | @@ -45,15 +45,15 @@ Tertiary road: 12km/h = 12000m/3600s = 100m/30s | f | e | d | And the ways - | nodes | highway | - | xa | primary | - | xb | primary | - | xc | primary | - | xd | primary | - | xe | primary | - | xf | primary | - | xg | primary | - | xh | primary | + | nodes | highway | + | xa | primary | + | xb | primary | + | xc | primary | + | xd | primary | + | xe | primary | + | xf | primary | + | xg | primary | + | xh | primary | When I route I should get | from | to | route | time | @@ -74,15 +74,15 @@ Tertiary road: 12km/h = 12000m/3600s = 100m/30s | f | e | d | And the ways - | nodes | highway | - | xa | primary | - | xb | primary | - | xc | primary | - | xd | primary | - | xe | primary | - | xf | primary | - | xg | primary | - | xh | primary | + | nodes | highway | + | xa | primary | + | xb | primary | + | xc | primary | + | xd | primary | + | xe | primary | + | xf | primary | + | xg | primary | + | xh | primary | When I route I should get | from | to | route | time | @@ -103,15 +103,15 @@ Tertiary road: 12km/h = 12000m/3600s = 100m/30s | f | e | d | And the ways - | nodes | highway | - | xa | primary | - | xb | primary | - | xc | primary | - | xd | primary | - | xe | primary | - | xf | primary | - | xg | primary | - | xh | primary | + | nodes | highway | + | xa | primary | + | xb | primary | + | xc | primary | + | xd | primary | + | xe | primary | + | xf | primary | + | xg | primary | + | xh | primary | When I route I should get | from | to | route | time | @@ -183,9 +183,9 @@ Tertiary road: 12km/h = 12000m/3600s = 100m/30s | | | e | And the ways - | nodes | highway | - | abc | primary | - | cde | tertiary | + | nodes | highway | + | abc | primary | + | cde | tertiary | When I route I should get | from | to | route | time | @@ -213,3 +213,26 @@ Tertiary road: 12km/h = 12000m/3600s = 100m/30s | 4 | 3 | ab | 10s +-1 | | 4 | 2 | ab | 20s +-1 | | 4 | 1 | ab | 30s +-1 | + + @bug + Scenario: Total travel time should match sum of times of individual ways + Given a grid size of 1000 meters + And the node map + | a | b | | | | + | | | | | | + | | c | | | d | + + And the ways + | nodes | highway | + | ab | primary | + | bc | primary | + | cd | primary | + + When I route I should get + | from | to | route | distances | distance | times | time | + | a | b | ab | 1000m +-1 | 1000m +-1 | 100s +-1 | 100s +-1 | + | b | c | bc | 2000m +-1 | 2000m +-1 | 200s +-1 | 200s +-1 | + | c | d | cd | 3000m +-1 | 3000m +-1 | 300s +-1 | 300s +-1 | + | a | c | ab,bc | 1000m,2000m +-1 | 3000m +-1 | 100s,200s +-1 | 300s +-1 | + | b | d | bc,cd | 2000m,3000m +-1 | 5000m +-1 | 200s,300s +-1 | 500s +-1 | + | a | d | ab,bc,cd | 1000m,2000m,3000m +-1 | 6000m +-1 | 100s,200s,300s +-1 | 600s +-1 | diff --git a/features/testbot/turns.feature b/features/testbot/turns.feature index 6f922a615..87bf21f55 100644 --- a/features/testbot/turns.feature +++ b/features/testbot/turns.feature @@ -98,7 +98,7 @@ Feature: Turn directions/codes | g | e | xg,xe | head,sharp_right,destination | Scenario: Turn instructions at high latitude - https://github.com/DennisOSRM/Project-OSRM/issues/532 + # https://github.com/DennisOSRM/Project-OSRM/issues/532 Given the node locations | node | lat | lon | | a | 55.68740 | 12.52430 | diff --git a/features/testbot/via.feature b/features/testbot/via.feature index 96da64353..03ef2ea51 100644 --- a/features/testbot/via.feature +++ b/features/testbot/via.feature @@ -48,5 +48,6 @@ Feature: Via points | dh | When I route I should get - | waypoints | route | - | a,c,f,h | ab,bcd,de,efg,gh | + | waypoints | route | + | a,c,f | ab,bcd,de,efg | + | a,c,f,h | ab,bcd,de,efg,gh | diff --git a/prepare.cpp b/prepare.cpp index a432c7eaa..5664a5035 100644 --- a/prepare.cpp +++ b/prepare.cpp @@ -39,7 +39,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "Util/LuaUtil.h" #include "Util/OpenMPWrapper.h" #include "Util/OSRMException.h" -#include "Util/ProgramOptions.h" +// #include "Util/ProgramOptions.h" #include "Util/SimpleLogger.h" #include "Util/StringUtil.h" #include "typedefs.h" @@ -127,14 +127,14 @@ int main (int argc, char *argv[]) { boost::program_options::notify(option_variables); - if(boost::filesystem::is_regular_file(config_file_path)) { - SimpleLogger().Write() << "Reading options from: " << config_file_path.c_str(); - std::string config_str; - PrepareConfigFile( config_file_path.c_str(), config_str ); - std::stringstream config_stream( config_str ); - boost::program_options::store(parse_config_file(config_stream, config_file_options), option_variables); - boost::program_options::notify(option_variables); - } + // if(boost::filesystem::is_regular_file(config_file_path)) { + // SimpleLogger().Write() << "Reading options from: " << config_file_path.c_str(); + // std::string config_str; + // PrepareConfigFile( config_file_path.c_str(), config_str ); + // std::stringstream config_stream( config_str ); + // boost::program_options::store(parse_config_file(config_stream, config_file_options), option_variables); + // boost::program_options::notify(option_variables); + // } if(!option_variables.count("restrictions")) { restrictions_path = std::string( input_path.c_str()) + ".restrictions"; @@ -142,6 +142,7 @@ int main (int argc, char *argv[]) { if(!option_variables.count("input")) { SimpleLogger().Write(logWARNING) << "No input file specified"; + SimpleLogger().Write() << visible_options; return -1; } @@ -235,17 +236,17 @@ int main (int argc, char *argv[]) { std::vector edgeList; NodeID nodeBasedNodeNumber = readBinaryOSRMGraphFromStream(in, edgeList, bollardNodes, trafficLightNodes, &internalToExternalNodeMapping, inputRestrictions); in.close(); + + if( edgeList.empty() ) { + SimpleLogger().Write(logWARNING) << "The input data is empty, exiting."; + return -1; + } + SimpleLogger().Write() << inputRestrictions.size() << " restrictions, " << bollardNodes.size() << " bollard nodes, " << trafficLightNodes.size() << " traffic lights"; - if( edgeList.empty() ) { - SimpleLogger().Write(logWARNING) << "The input data is broken. " - "It is impossible to do any turns in this graph"; - return -1; - } - /*** * Building an edge-expanded graph from node-based input an turn restrictions */ @@ -296,6 +297,7 @@ int main (int argc, char *argv[]) { IteratorbasedCRC32 > crc32; unsigned crc32OfNodeBasedEdgeList = crc32(nodeBasedEdgeList.begin(), nodeBasedEdgeList.end() ); nodeBasedEdgeList.clear(); + std::vector(nodeBasedEdgeList).swap(nodeBasedEdgeList); SimpleLogger().Write() << "CRC32: " << crc32OfNodeBasedEdgeList; /*** @@ -320,7 +322,6 @@ int main (int argc, char *argv[]) { * Sorting contracted edges in a way that the static query graph can read some in in-place. */ - SimpleLogger().Write() << "Building Node Array"; std::sort(contractedEdgeList.begin(), contractedEdgeList.end()); unsigned numberOfNodes = 0; unsigned numberOfEdges = contractedEdgeList.size(); @@ -332,6 +333,8 @@ int main (int argc, char *argv[]) { std::ofstream hsgr_output_stream(graphOut.c_str(), std::ios::binary); hsgr_output_stream.write((char*)&uuid_orig, sizeof(UUID) ); BOOST_FOREACH(const QueryEdge & edge, contractedEdgeList) { + BOOST_ASSERT( UINT_MAX != edge.source ); + BOOST_ASSERT( UINT_MAX != edge.target ); if(edge.source > numberOfNodes) { numberOfNodes = edge.source; } @@ -372,8 +375,10 @@ int main (int argc, char *argv[]) { hsgr_output_stream.write((char*) &_nodes[0], sizeof(StaticGraph::_StrNode)*(numberOfNodes)); //serialize all edges --numberOfNodes; + edge = 0; int usedEdgeCounter = 0; + SimpleLogger().Write() << "Building Node Array"; StaticGraph::_StrEdge currentEdge; for ( StaticGraph::NodeIterator node = 0; node < numberOfNodes; ++node ) { for ( StaticGraph::EdgeIterator i = _nodes[node].firstEdge, e = _nodes[node+1].firstEdge; i != e; ++i ) { diff --git a/profiles/bicycle.lua b/profiles/bicycle.lua index 048963c94..08f78b8ce 100644 --- a/profiles/bicycle.lua +++ b/profiles/bicycle.lua @@ -1,8 +1,8 @@ require("lib/access") -- Begin of globals -barrier_whitelist = { [""] = true, ["cycle_barrier"] = true, ["bollard"] = true, ["entrance"] = true, ["cattle_grid"] = true, ["border_control"] = true, ["toll_booth"] = true, ["sally_port"] = true, ["gate"] = true, ["no"] = true} -access_tag_whitelist = { ["yes"] = true, ["permissive"] = true, ["designated"] = true } +barrier_whitelist = { [""] = true, ["cycle_barrier"] = true, ["bollard"] = true, ["entrance"] = true, ["cattle_grid"] = true, ["border_control"] = true, ["toll_booth"] = true, ["sally_port"] = true, ["gate"] = true, ["no"] = true } +access_tag_whitelist = { ["yes"] = true, ["permissive"] = true, ["designated"] = true } access_tag_blacklist = { ["no"] = true, ["private"] = true, ["agricultural"] = true, ["forestery"] = true } access_tag_restricted = { ["destination"] = true, ["delivery"] = true } access_tags_hierachy = { "bicycle", "vehicle", "access" } @@ -15,349 +15,348 @@ default_speed = 15 walking_speed = 6 bicycle_speeds = { - ["cycleway"] = default_speed, - ["primary"] = default_speed, - ["primary_link"] = default_speed, - ["secondary"] = default_speed, - ["secondary_link"] = default_speed, - ["tertiary"] = default_speed, - ["tertiary_link"] = default_speed, - ["residential"] = default_speed, - ["unclassified"] = default_speed, - ["living_street"] = default_speed, - ["road"] = default_speed, - ["service"] = default_speed, - ["track"] = 12, - ["path"] = 12 - --["footway"] = 12, - --["pedestrian"] = 12, + ["cycleway"] = default_speed, + ["primary"] = default_speed, + ["primary_link"] = default_speed, + ["secondary"] = default_speed, + ["secondary_link"] = default_speed, + ["tertiary"] = default_speed, + ["tertiary_link"] = default_speed, + ["residential"] = default_speed, + ["unclassified"] = default_speed, + ["living_street"] = default_speed, + ["road"] = default_speed, + ["service"] = default_speed, + ["track"] = 12, + ["path"] = 12 + --["footway"] = 12, + --["pedestrian"] = 12, } pedestrian_speeds = { - ["footway"] = walking_speed, - ["pedestrian"] = walking_speed, - ["steps"] = 2 + ["footway"] = walking_speed, + ["pedestrian"] = walking_speed, + ["steps"] = 2 } railway_speeds = { - ["train"] = 10, - ["railway"] = 10, - ["subway"] = 10, - ["light_rail"] = 10, - ["monorail"] = 10, - ["tram"] = 10 + ["train"] = 10, + ["railway"] = 10, + ["subway"] = 10, + ["light_rail"] = 10, + ["monorail"] = 10, + ["tram"] = 10 } platform_speeds = { - ["platform"] = walking_speed + ["platform"] = walking_speed } amenity_speeds = { - ["parking"] = 10, - ["parking_entrance"] = 10 + ["parking"] = 10, + ["parking_entrance"] = 10 } man_made_speeds = { - ["pier"] = walking_speed + ["pier"] = walking_speed } route_speeds = { - ["ferry"] = 5 + ["ferry"] = 5 } surface_speeds = { - ["asphalt"] = default_speed, - ["cobblestone:flattened"] = 10, - ["paving_stones"] = 10, - ["compacted"] = 10, - ["cobblestone"] = 6, - ["unpaved"] = 6, - ["fine_gravel"] = 6, - ["gravel"] = 6, - ["fine_gravel"] = 6, - ["pebbelstone"] = 6, - ["ground"] = 6, - ["dirt"] = 6, - ["earth"] = 6, - ["grass"] = 6, - ["mud"] = 3, - ["sand"] = 3 + ["asphalt"] = default_speed, + ["cobblestone:flattened"] = 10, + ["paving_stones"] = 10, + ["compacted"] = 10, + ["cobblestone"] = 6, + ["unpaved"] = 6, + ["fine_gravel"] = 6, + ["gravel"] = 6, + ["fine_gravel"] = 6, + ["pebbelstone"] = 6, + ["ground"] = 6, + ["dirt"] = 6, + ["earth"] = 6, + ["grass"] = 6, + ["mud"] = 3, + ["sand"] = 3 } -take_minimum_of_speeds = true -obey_oneway = true -obey_bollards = false -use_restrictions = true -ignore_areas = true -- future feature -traffic_signal_penalty = 5 -u_turn_penalty = 20 +take_minimum_of_speeds = true +obey_oneway = true +obey_bollards = false +use_restrictions = true +ignore_areas = true -- future feature +traffic_signal_penalty = 5 +u_turn_penalty = 20 use_turn_restrictions = false -turn_penalty = 60 -turn_bias = 1.4 +turn_penalty = 60 +turn_bias = 1.4 -- End of globals function get_exceptions(vector) - for i,v in ipairs(restriction_exception_tags) do - vector:Add(v) - end + for i,v in ipairs(restriction_exception_tags) do + vector:Add(v) + end end function node_function (node) - local barrier = node.tags:Find ("barrier") - local access = Access.find_access_tag(node, access_tags_hierachy) - local traffic_signal = node.tags:Find("highway") + local barrier = node.tags:Find ("barrier") + local access = Access.find_access_tag(node, access_tags_hierachy) + local traffic_signal = node.tags:Find("highway") - -- flag node if it carries a traffic light - if traffic_signal == "traffic_signals" then - node.traffic_light = true - end + -- flag node if it carries a traffic light + if traffic_signal == "traffic_signals" then + node.traffic_light = true + end - -- parse access and barrier tags - if access and access ~= "" then - if access_tag_blacklist[access] then - node.bollard = true - else - node.bollard = false - end - elseif barrier and barrier ~= "" then - if barrier_whitelist[barrier] then - node.bollard = false - else - node.bollard = true - end - end + -- parse access and barrier tags + if access and access ~= "" then + if access_tag_blacklist[access] then + node.bollard = true + else + node.bollard = false + end + elseif barrier and barrier ~= "" then + if barrier_whitelist[barrier] then + node.bollard = false + else + node.bollard = true + end + end - return 1 + return 1 end function way_function (way) - -- initial routability check, filters out buildings, boundaries, etc - local highway = way.tags:Find("highway") - local route = way.tags:Find("route") - local man_made = way.tags:Find("man_made") - local railway = way.tags:Find("railway") - local amenity = way.tags:Find("amenity") - local public_transport = way.tags:Find("public_transport") - if (not highway or highway == '') and - (not route or route == '') and - (not railway or railway=='') and - (not amenity or amenity=='') and - (not man_made or man_made=='') and - (not public_transport or public_transport=='') - then - return 0 + -- initial routability check, filters out buildings, boundaries, etc + local highway = way.tags:Find("highway") + local route = way.tags:Find("route") + local man_made = way.tags:Find("man_made") + local railway = way.tags:Find("railway") + local amenity = way.tags:Find("amenity") + local public_transport = way.tags:Find("public_transport") + if (not highway or highway == '') and + (not route or route == '') and + (not railway or railway=='') and + (not amenity or amenity=='') and + (not man_made or man_made=='') and + (not public_transport or public_transport=='') + then + return 0 + end + + -- don't route on ways or railways that are still under construction + if highway=='construction' or railway=='construction' then + return 0 + end + + -- access + local access = Access.find_access_tag(way, access_tags_hierachy) + if access_tag_blacklist[access] then + return 0 + end + + + -- other tags + local name = way.tags:Find("name") + local ref = way.tags:Find("ref") + local junction = way.tags:Find("junction") + local maxspeed = parseMaxspeed(way.tags:Find ( "maxspeed") ) + local maxspeed_forward = parseMaxspeed(way.tags:Find( "maxspeed:forward")) + local maxspeed_backward = parseMaxspeed(way.tags:Find( "maxspeed:backward")) + local barrier = way.tags:Find("barrier") + local oneway = way.tags:Find("oneway") + local onewayClass = way.tags:Find("oneway:bicycle") + local cycleway = way.tags:Find("cycleway") + local cycleway_left = way.tags:Find("cycleway:left") + local cycleway_right = way.tags:Find("cycleway:right") + local duration = way.tags:Find("duration") + local service = way.tags:Find("service") + local area = way.tags:Find("area") + local foot = way.tags:Find("foot") + local surface = way.tags:Find("surface") + + -- name + if "" ~= ref and "" ~= name then + way.name = name .. ' / ' .. ref + elseif "" ~= ref then + way.name = ref + elseif "" ~= name then + way.name = name + else + -- if no name exists, use way type + -- this encoding scheme is excepted to be a temporary solution + way.name = "{highway:"..highway.."}" + end + + -- roundabout handling + if "roundabout" == junction then + way.roundabout = true; + end + + -- speed + if route_speeds[route] then + -- ferries (doesn't cover routes tagged using relations) + way.direction = Way.bidirectional + way.ignore_in_grid = true + if durationIsValid(duration) then + way.duration = math.max( 1, parseDuration(duration) ) + else + way.speed = route_speeds[route] end - - -- don't route on ways or railways that are still under construction - if highway=='construction' or railway=='construction' then - return 0 - end - - -- access - local access = Access.find_access_tag(way, access_tags_hierachy) - if access_tag_blacklist[access] then - return 0 - end - - - -- other tags - local name = way.tags:Find("name") - local ref = way.tags:Find("ref") - local junction = way.tags:Find("junction") - local maxspeed = parseMaxspeed(way.tags:Find ( "maxspeed") ) - local maxspeed_forward = parseMaxspeed(way.tags:Find( "maxspeed:forward")) - local maxspeed_backward = parseMaxspeed(way.tags:Find( "maxspeed:backward")) - local barrier = way.tags:Find("barrier") - local oneway = way.tags:Find("oneway") - local onewayClass = way.tags:Find("oneway:bicycle") - local cycleway = way.tags:Find("cycleway") - local cycleway_left = way.tags:Find("cycleway:left") - local cycleway_right = way.tags:Find("cycleway:right") - local duration = way.tags:Find("duration") - local service = way.tags:Find("service") - local area = way.tags:Find("area") - local foot = way.tags:Find("foot") - local surface = way.tags:Find("surface") - - -- name - if "" ~= ref and "" ~= name then - way.name = name .. ' / ' .. ref - elseif "" ~= ref then - way.name = ref - elseif "" ~= name then - way.name = name - else - way.name = "{highway:"..highway.."}" -- if no name exists, use way type - -- this encoding scheme is excepted to be a temporary solution - end - - -- roundabout handling - if "roundabout" == junction then - way.roundabout = true; - end - - -- speed - if route_speeds[route] then - -- ferries (doesn't cover routes tagged using relations) - way.direction = Way.bidirectional - way.ignore_in_grid = true - if durationIsValid(duration) then - way.duration = math.max( 1, parseDuration(duration) ) - else - way.speed = route_speeds[route] - end - elseif railway and platform_speeds[railway] then - -- railway platforms (old tagging scheme) - way.speed = platform_speeds[railway] - elseif platform_speeds[public_transport] then - -- public_transport platforms (new tagging platform) - way.speed = platform_speeds[public_transport] + elseif railway and platform_speeds[railway] then + -- railway platforms (old tagging scheme) + way.speed = platform_speeds[railway] + elseif platform_speeds[public_transport] then + -- public_transport platforms (new tagging platform) + way.speed = platform_speeds[public_transport] elseif railway and railway_speeds[railway] then - -- railways - if access and access_tag_whitelist[access] then - way.speed = railway_speeds[railway] - way.direction = Way.bidirectional - end - elseif amenity and amenity_speeds[amenity] then - -- parking areas - way.speed = amenity_speeds[amenity] - elseif bicycle_speeds[highway] then - -- regular ways - way.speed = bicycle_speeds[highway] - elseif access and access_tag_whitelist[access] then - -- unknown way, but valid access tag - way.speed = default_speed - else - -- biking not allowed, maybe we can push our bike? - -- essentially requires pedestrian profiling, for example foot=no mean we can't push a bike - -- TODO: if we can push, the way should be marked as pedestrion mode, but there's no way to do it yet from lua.. - if foot ~= 'no' then - if pedestrian_speeds[highway] then - -- pedestrian-only ways and areas - way.speed = pedestrian_speeds[highway] - elseif man_made and man_made_speeds[man_made] then - -- man made structures - way.speed = man_made_speeds[man_made] - elseif foot == 'yes' then - way.speed = walking_speed - end - end + -- railways + if access and access_tag_whitelist[access] then + way.speed = railway_speeds[railway] + way.direction = Way.bidirectional end - - -- direction - way.direction = Way.bidirectional - local impliedOneway = false - if junction == "roundabout" or highway == "motorway_link" or highway == "motorway" then - way.direction = Way.oneway - impliedOneway = true - end - - if onewayClass == "yes" or onewayClass == "1" or onewayClass == "true" then - way.direction = Way.oneway - elseif onewayClass == "no" or onewayClass == "0" or onewayClass == "false" then - way.direction = Way.bidirectional - elseif onewayClass == "-1" then - way.direction = Way.opposite - elseif oneway == "no" or oneway == "0" or oneway == "false" then - way.direction = Way.bidirectional - elseif cycleway and string.find(cycleway, "opposite") == 1 then - if impliedOneway then - way.direction = Way.opposite - else - way.direction = Way.bidirectional - end - elseif cycleway_left and cycleway_tags[cycleway_left] and cycleway_right and cycleway_tags[cycleway_right] then - way.direction = Way.bidirectional - elseif cycleway_left and cycleway_tags[cycleway_left] then - if impliedOneway then - way.direction = Way.opposite - else - way.direction = Way.bidirectional - end - elseif cycleway_right and cycleway_tags[cycleway_right] then - if impliedOneway then - way.direction = Way.oneway - else - way.direction = Way.bidirectional - end - elseif oneway == "-1" then - way.direction = Way.opposite - elseif oneway == "yes" or oneway == "1" or oneway == "true" then - way.direction = Way.oneway - end - - -- pushing bikes - if bicycle_speeds[highway] or pedestrian_speeds[highway] then - if foot ~= 'no' then - if junction ~= "roundabout" then - if way.direction == Way.oneway then - way.backward_speed = walking_speed - elseif way.direction == Way.opposite then - way.backward_speed = walking_speed - way.speed = way.speed - end - end - end - if way.backward_speed == way.speed then - -- TODO: no way yet to mark a way as pedestrian mode if forward/backward speeds are equal - way.direction = Way.bidirectional - end + elseif amenity and amenity_speeds[amenity] then + -- parking areas + way.speed = amenity_speeds[amenity] + elseif bicycle_speeds[highway] then + -- regular ways + way.speed = bicycle_speeds[highway] + elseif access and access_tag_whitelist[access] then + -- unknown way, but valid access tag + way.speed = default_speed + else + -- biking not allowed, maybe we can push our bike? + -- essentially requires pedestrian profiling, for example foot=no mean we can't push a bike + -- TODO: if we can push, the way should be marked as pedestrion mode, but there's no way to do it yet from lua.. + if foot ~= 'no' then + if pedestrian_speeds[highway] then + -- pedestrian-only ways and areas + way.speed = pedestrian_speeds[highway] + elseif man_made and man_made_speeds[man_made] then + -- man made structures + way.speed = man_made_speeds[man_made] + elseif foot == 'yes' then + way.speed = walking_speed + end end + end + -- direction + way.direction = Way.bidirectional + local impliedOneway = false + if junction == "roundabout" or highway == "motorway_link" or highway == "motorway" then + way.direction = Way.oneway + impliedOneway = true + end - -- cycleways - if cycleway and cycleway_tags[cycleway] then - way.speed = bicycle_speeds["cycleway"] - elseif cycleway_left and cycleway_tags[cycleway_left] then - way.speed = bicycle_speeds["cycleway"] - elseif cycleway_right and cycleway_tags[cycleway_right] then - way.speed = bicycle_speeds["cycleway"] - end - - -- surfaces - if surface then - surface_speed = surface_speeds[surface] - if surface_speed then - if way.speed > 0 then - way.speed = surface_speed - end - if way.backward_speed > 0 then - way.backward_speed = surface_speed - end - end + if onewayClass == "yes" or onewayClass == "1" or onewayClass == "true" then + way.direction = Way.oneway + elseif onewayClass == "no" or onewayClass == "0" or onewayClass == "false" then + way.direction = Way.bidirectional + elseif onewayClass == "-1" then + way.direction = Way.opposite + elseif oneway == "no" or oneway == "0" or oneway == "false" then + way.direction = Way.bidirectional + elseif cycleway and string.find(cycleway, "opposite") == 1 then + if impliedOneway then + way.direction = Way.opposite + else + way.direction = Way.bidirectional end + elseif cycleway_left and cycleway_tags[cycleway_left] and cycleway_right and cycleway_tags[cycleway_right] then + way.direction = Way.bidirectional + elseif cycleway_left and cycleway_tags[cycleway_left] then + if impliedOneway then + way.direction = Way.opposite + else + way.direction = Way.bidirectional + end + elseif cycleway_right and cycleway_tags[cycleway_right] then + if impliedOneway then + way.direction = Way.oneway + else + way.direction = Way.bidirectional + end + elseif oneway == "-1" then + way.direction = Way.opposite + elseif oneway == "yes" or oneway == "1" or oneway == "true" then + way.direction = Way.oneway + end - -- maxspeed - -- TODO: maxspeed of backward direction - if take_minimum_of_speeds then - if maxspeed and maxspeed>0 then - way.speed = math.min(way.speed, maxspeed) - end - end + -- pushing bikes + if bicycle_speeds[highway] or pedestrian_speeds[highway] then + if foot ~= 'no' then + if junction ~= "roundabout" then + if way.direction == Way.oneway then + way.backward_speed = walking_speed + elseif way.direction == Way.opposite then + way.backward_speed = walking_speed + way.speed = way.speed + end + end + end + if way.backward_speed == way.speed then + -- TODO: no way yet to mark a way as pedestrian mode if forward/backward speeds are equal + way.direction = Way.bidirectional + end + end + + + -- cycleways + if cycleway and cycleway_tags[cycleway] then + way.speed = bicycle_speeds["cycleway"] + elseif cycleway_left and cycleway_tags[cycleway_left] then + way.speed = bicycle_speeds["cycleway"] + elseif cycleway_right and cycleway_tags[cycleway_right] then + way.speed = bicycle_speeds["cycleway"] + end + + -- surfaces + if surface then + surface_speed = surface_speeds[surface] + if surface_speed then + if way.speed > 0 then + way.speed = surface_speed + end + if way.backward_speed > 0 then + way.backward_speed = surface_speed + end + end + end + + -- maxspeed + -- TODO: maxspeed of backward direction + if take_minimum_of_speeds then + if maxspeed and maxspeed>0 then + way.speed = math.min(way.speed, maxspeed) + end + end -- Override speed settings if explicit forward/backward maxspeeds are given - if way.speed > 0 and maxspeed_forward ~= nil and maxspeed_forward > 0 then - if Way.bidirectional == way.direction then - way.backward_speed = way.speed - end - way.speed = maxspeed_forward - end - if maxspeed_backward ~= nil and maxspeed_backward > 0 then - way.backward_speed = maxspeed_backward + if way.speed > 0 and maxspeed_forward ~= nil and maxspeed_forward > 0 then + if Way.bidirectional == way.direction then + way.backward_speed = way.speed end + way.speed = maxspeed_forward + end + if maxspeed_backward ~= nil and maxspeed_backward > 0 then + way.backward_speed = maxspeed_backward + end - - - way.type = 1 - return 1 + way.type = 1 + return 1 end function turn_function (angle) - -- compute turn penalty as angle^2, with a left/right bias - k = turn_penalty/(90.0*90.0) - if angle>=0 then - return angle*angle*k/turn_bias - else - return angle*angle*k*turn_bias - end + -- compute turn penalty as angle^2, with a left/right bias + k = turn_penalty/(90.0*90.0) + if angle>=0 then + return angle*angle*k/turn_bias + else + return angle*angle*k*turn_bias + end end diff --git a/profiles/car.lua b/profiles/car.lua index d334b9153..05b8e7298 100644 --- a/profiles/car.lua +++ b/profiles/car.lua @@ -1,8 +1,8 @@ -- Begin of globals -require("lib/access") +--require("lib/access") --function temporarily inlined -barrier_whitelist = { ["cattle_grid"] = true, ["border_control"] = true, ["toll_booth"] = true, ["sally_port"] = true, ["gate"] = true, ["no"] = true, ["entrance"] = true} -access_tag_whitelist = { ["yes"] = true, ["motorcar"] = true, ["motor_vehicle"] = true, ["vehicle"] = true, ["permissive"] = true, ["designated"] = true } +barrier_whitelist = { ["cattle_grid"] = true, ["border_control"] = true, ["toll_booth"] = true, ["sally_port"] = true, ["gate"] = true, ["no"] = true, ["entrance"] = true } +access_tag_whitelist = { ["yes"] = true, ["motorcar"] = true, ["motor_vehicle"] = true, ["vehicle"] = true, ["permissive"] = true, ["designated"] = true } access_tag_blacklist = { ["no"] = true, ["private"] = true, ["agricultural"] = true, ["forestry"] = true, ["emergency"] = true } access_tag_restricted = { ["destination"] = true, ["delivery"] = true } access_tags = { "motorcar", "motor_vehicle", "vehicle" } @@ -32,67 +32,84 @@ speed_profile = { ["default"] = 10 } -take_minimum_of_speeds = false -obey_oneway = true -obey_bollards = true -use_restrictions = true -ignore_areas = true -- future feature -traffic_signal_penalty = 2 -u_turn_penalty = 20 +local take_minimum_of_speeds = false +local obey_oneway = true +local obey_bollards = true +local use_turn_restrictions = true +local ignore_areas = true -- future feature +local traffic_signal_penalty = 2 +local u_turn_penalty = 20 + +local abs = math.abs +local min = math.min +local max = math.max + +local maxspeed_reduction = 0.66 -- End of globals +local function find_access_tag(source,access_tags_hierachy) + for i,v in ipairs(access_tags_hierachy) do + local has_tag = source.tags:Holds(v) + if has_tag then + return source.tags:Find(v) + end + end + return nil +end function get_exceptions(vector) - for i,v in ipairs(restriction_exception_tags) do - vector:Add(v) - end + for i,v in ipairs(restriction_exception_tags) do + vector:Add(v) + end end local function parse_maxspeed(source) - if source == nil then - return 0 - end - local n = tonumber(source:match("%d*")) - if n == nil then - n = 0 - end - if string.match(source, "mph") or string.match(source, "mp/h") then - n = (n*1609)/1000; - end - return math.abs(n) + if not source then + return 0 + end + local n = tonumber(source:match("%d*")) + if not n then + n = 0 + end + if string.match(source, "mph") or string.match(source, "mp/h") then + n = (n*1609)/1000; + end + return n end function node_function (node) - local barrier = node.tags:Find("barrier") - local access = Access.find_access_tag(node, access_tags_hierachy) - local traffic_signal = node.tags:Find("highway") + local access = find_access_tag(node, access_tags_hierachy) --flag node if it carries a traffic light - - if traffic_signal == "traffic_signals" then - node.traffic_light = true; + if node.tags:Holds("highway") then + if node.tags:Find("highway") == "traffic_signals" then + node.traffic_light = true; + end end - -- parse access and barrier tags - if access and access ~= "" then - if access_tag_blacklist[access] then - node.bollard = true - end - elseif barrier and barrier ~= "" then - if barrier_whitelist[barrier] then - return - else - node.bollard = true - end - end + -- parse access and barrier tags + if access and access ~= "" then + if access_tag_blacklist[access] then + node.bollard = true + end + elseif node.tags:Holds("barrier") then + local barrier = node.tags:Find("barrier") + if barrier_whitelist[barrier] then + return + else + node.bollard = true + end + end end - function way_function (way) -- we dont route over areas - local area = way.tags:Find("area") - if ignore_areas and ("yes" == area) then - return + local is_area = way.tags:Holds("area") + if ignore_areas and is_area then + local area = way.tags:Find("area") + if "yes" == area then + return + end end -- check if oneway tag is unsupported @@ -101,81 +118,95 @@ function way_function (way) return end - local impassable = way.tags:Find("impassable") - if "yes" == impassable then - return + local is_impassable = way.tags:Holds("impassable") + if is_impassable then + local impassable = way.tags:Find("impassable") + if "yes" == impassable then + return + end end - local status = way.tags:Find("status") - if "impassable" == status then - return + local is_status = way.tags:Holds("status") + if is_status then + local status = way.tags:Find("status") + if "impassable" == status then + return + end end -- Check if we are allowed to access the way - local access = Access.find_access_tag(way, access_tags_hierachy) + local access = find_access_tag(way, access_tags_hierachy) if access_tag_blacklist[access] then return end -- Second, parse the way according to these properties local highway = way.tags:Find("highway") + local route = way.tags:Find("route") + + -- Handling ferries and piers + local route_speed = speed_profile[route] + if(route_speed and route_speed > 0) then + highway = route; + local duration = way.tags:Find("duration") + if durationIsValid(duration) then + way.duration = max( parseDuration(duration), 1 ); + end + way.direction = Way.bidirectional + way.speed = route_speed + end + + -- leave early of this way is not accessible + if "" == highway then + return + end + + if way.speed == -1 then + local highway_speed = speed_profile[highway] + local max_speed = parse_maxspeed( way.tags:Find("maxspeed") )*maxspeed_reduction + -- Set the avg speed on the way if it is accessible by road class + if highway_speed then + if max_speed > highway_speed then + way.speed = max_speed + -- max_speed = math.huge + else + way.speed = highway_speed + end + else + -- Set the avg speed on ways that are marked accessible + if access_tag_whitelist[access] then + way.speed = speed_profile["default"] + end + end + if 0 == max_speed then + max_speed = math.huge + end + way.speed = min(way.speed, max_speed) + end + + if -1 == way.speed then + return + end + + -- parse the remaining tags local name = way.tags:Find("name") local ref = way.tags:Find("ref") local junction = way.tags:Find("junction") - local route = way.tags:Find("route") - local maxspeed = parse_maxspeed(way.tags:Find ( "maxspeed") ) - local maxspeed_forward = parse_maxspeed(way.tags:Find( "maxspeed:forward")) - local maxspeed_backward = parse_maxspeed(way.tags:Find( "maxspeed:backward")) - local barrier = way.tags:Find("barrier") - local cycleway = way.tags:Find("cycleway") - local duration = way.tags:Find("duration") + -- local barrier = way.tags:Find("barrier") + -- local cycleway = way.tags:Find("cycleway") local service = way.tags:Find("service") -- Set the name that will be used for instructions - if "" ~= ref then - way.name = ref - elseif "" ~= name then - way.name = name --- else --- way.name = highway -- if no name exists, use way type - end - - if "roundabout" == junction then - way.roundabout = true; - end - - -- Handling ferries and piers - if (speed_profile[route] ~= nil and speed_profile[route] > 0) then - if durationIsValid(duration) then - way.duration = math.max( parseDuration(duration), 1 ); - end - way.direction = Way.bidirectional - if speed_profile[route] ~= nil then - highway = route; - end - if tonumber(way.duration) < 0 then - way.speed = speed_profile[highway] - end + if "" ~= ref then + way.name = ref + elseif "" ~= name then + way.name = name +-- else + -- way.name = highway -- if no name exists, use way type end - -- Set the avg speed on the way if it is accessible by road class - if (speed_profile[highway] ~= nil and way.speed == -1 ) then - if maxspeed > speed_profile[highway] then - way.speed = maxspeed - else - if 0 == maxspeed then - maxspeed = math.huge - end - way.speed = math.min(speed_profile[highway], maxspeed) - end - end - - -- Set the avg speed on ways that are marked accessible - if "" ~= highway and access_tag_whitelist[access] and way.speed == -1 then - if 0 == maxspeed then - maxspeed = math.huge - end - way.speed = math.min(speed_profile["default"], maxspeed) + if "roundabout" == junction then + way.roundabout = true; end -- Set access restriction flag if access is allowed under certain restrictions only @@ -185,48 +216,48 @@ function way_function (way) -- Set access restriction flag if service is allowed under certain restrictions only if service ~= "" and service_tag_restricted[service] then - way.is_access_restricted = true + way.is_access_restricted = true end -- Set direction according to tags on way way.direction = Way.bidirectional if obey_oneway then - if oneway == "-1" then - way.direction = Way.opposite + if oneway == "-1" then + way.direction = Way.opposite elseif oneway == "yes" or - oneway == "1" or - oneway == "true" or - junction == "roundabout" or - (highway == "motorway_link" and oneway ~="no") or - (highway == "motorway" and oneway ~= "no") - then - way.direction = Way.oneway + oneway == "1" or + oneway == "true" or + junction == "roundabout" or + (highway == "motorway_link" and oneway ~="no") or + (highway == "motorway" and oneway ~= "no") then + way.direction = Way.oneway end end -- Override speed settings if explicit forward/backward maxspeeds are given - if way.speed > 0 and maxspeed_forward ~= nil and maxspeed_forward > 0 then + local maxspeed_forward = parse_maxspeed(way.tags:Find( "maxspeed:forward"))*maxspeed_reduction + local maxspeed_backward = parse_maxspeed(way.tags:Find( "maxspeed:backward"))*maxspeed_reduction + if maxspeed_forward > 0 then if Way.bidirectional == way.direction then way.backward_speed = way.speed end way.speed = maxspeed_forward end - if maxspeed_backward ~= nil and maxspeed_backward > 0 then + if maxspeed_backward > 0 then way.backward_speed = maxspeed_backward end -- Override general direction settings of there is a specific one for our mode of travel - if ignore_in_grid[highway] ~= nil and ignore_in_grid[highway] then - way.ignore_in_grid = true - end - way.type = 1 + if ignore_in_grid[highway] then + way.ignore_in_grid = true + end + way.type = 1 return end -- These are wrappers to parse vectors of nodes and ways and thus to speed up any tracing JIT - function node_vector_function(vector) - for v in vector.nodes do - node_function(v) - end -end + for v in vector.nodes do + node_function(v) + end +end \ No newline at end of file diff --git a/profiles/foot.lua b/profiles/foot.lua index 724519046..ae0dd6083 100644 --- a/profiles/foot.lua +++ b/profiles/foot.lua @@ -114,7 +114,7 @@ function way_function (way) then return 0 end - + -- don't route on ways that are still under construction if highway=='construction' then return 0 @@ -125,7 +125,7 @@ function way_function (way) if access_tag_blacklist[access] then return 0 end - + local name = way.tags:Find("name") local ref = way.tags:Find("ref") local junction = way.tags:Find("junction") @@ -179,7 +179,7 @@ function way_function (way) -- unknown way, but valid access tag way.speed = walking_speed end - + -- oneway if onewayClass == "yes" or onewayClass == "1" or onewayClass == "true" then way.direction = Way.oneway diff --git a/profiles/testbot.lua b/profiles/testbot.lua index f934fead5..96bf71ef2 100644 --- a/profiles/testbot.lua +++ b/profiles/testbot.lua @@ -2,106 +2,106 @@ -- Moves at fixed, well-known speeds, practical for testing speed and travel times: --- Primary road: 36km/h = 36000m/3600s = 100m/10s --- Secondary road: 18km/h = 18000m/3600s = 100m/20s --- Tertiary road: 12km/h = 12000m/3600s = 100m/30s +-- Primary road: 36km/h = 36000m/3600s = 100m/10s +-- Secondary road: 18km/h = 18000m/3600s = 100m/20s +-- Tertiary road: 12km/h = 12000m/3600s = 100m/30s -speed_profile = { - ["primary"] = 36, - ["secondary"] = 18, - ["tertiary"] = 12, - ["default"] = 24 +speed_profile = { + ["primary"] = 36, + ["secondary"] = 18, + ["tertiary"] = 12, + ["default"] = 24 } -- these settings are read directly by osrm -take_minimum_of_speeds = true -obey_oneway = true -obey_bollards = true -use_restrictions = true -ignore_areas = true -- future feature -traffic_signal_penalty = 7 -- seconds -u_turn_penalty = 20 +take_minimum_of_speeds = true +obey_oneway = true +obey_barriers = true +use_turn_restrictions = true +ignore_areas = true -- future feature +traffic_signal_penalty = 7 -- seconds +u_turn_penalty = 20 function limit_speed(speed, limits) - -- don't use ipairs(), since it stops at the first nil value - for i=1, #limits do - limit = limits[i] - if limit ~= nil and limit > 0 then - if limit < speed then - return limit -- stop at first speedlimit that's smaller than speed - end - end + -- don't use ipairs(), since it stops at the first nil value + for i=1, #limits do + limit = limits[i] + if limit ~= nil and limit > 0 then + if limit < speed then + return limit -- stop at first speedlimit that's smaller than speed + end end - return speed + end + return speed end function node_function (node) - local traffic_signal = node.tags:Find("highway") + local traffic_signal = node.tags:Find("highway") - if traffic_signal == "traffic_signals" then - node.traffic_light = true; - -- TODO: a way to set the penalty value - end - return 1 + if traffic_signal == "traffic_signals" then + node.traffic_light = true; + -- TODO: a way to set the penalty value + end + return 1 end function way_function (way) - local highway = way.tags:Find("highway") - local name = way.tags:Find("name") - local oneway = way.tags:Find("oneway") - local route = way.tags:Find("route") - local duration = way.tags:Find("duration") - local maxspeed = tonumber(way.tags:Find ( "maxspeed")) - local maxspeed_forward = tonumber(way.tags:Find( "maxspeed:forward")) - local maxspeed_backward = tonumber(way.tags:Find( "maxspeed:backward")) - - way.name = name + local highway = way.tags:Find("highway") + local name = way.tags:Find("name") + local oneway = way.tags:Find("oneway") + local route = way.tags:Find("route") + local duration = way.tags:Find("duration") + local maxspeed = tonumber(way.tags:Find ( "maxspeed")) + local maxspeed_forward = tonumber(way.tags:Find( "maxspeed:forward")) + local maxspeed_backward = tonumber(way.tags:Find( "maxspeed:backward")) - if route ~= nil and durationIsValid(duration) then - way.duration = math.max( 1, parseDuration(duration) ) - else - local speed_forw = speed_profile[highway] or speed_profile['default'] - local speed_back = speed_forw + way.name = name - if highway == "river" then - local temp_speed = speed_forw; - speed_forw = temp_speed*1.5 - speed_back = temp_speed/1.5 - end - - if maxspeed_forward ~= nil and maxspeed_forward > 0 then - speed_forw = maxspeed_forward - else - if maxspeed ~= nil and maxspeed > 0 and speed_forw > maxspeed then - speed_forw = maxspeed - end - end - - if maxspeed_backward ~= nil and maxspeed_backward > 0 then - speed_back = maxspeed_backward - else - if maxspeed ~=nil and maxspeed > 0 and speed_back > maxspeed then - speed_back = maxspeed - end - end - - way.speed = speed_forw - if speed_back ~= way_forw then - way.backward_speed = speed_back - end - end - - if oneway == "no" or oneway == "0" or oneway == "false" then - way.direction = Way.bidirectional - elseif oneway == "-1" then - way.direction = Way.opposite - elseif oneway == "yes" or oneway == "1" or oneway == "true" then - way.direction = Way.oneway - else - way.direction = Way.bidirectional - end - - way.type = 1 - return 1 + if route ~= nil and durationIsValid(duration) then + way.duration = math.max( 1, parseDuration(duration) ) + else + local speed_forw = speed_profile[highway] or speed_profile['default'] + local speed_back = speed_forw + + if highway == "river" then + local temp_speed = speed_forw; + speed_forw = temp_speed*1.5 + speed_back = temp_speed/1.5 + end + + if maxspeed_forward ~= nil and maxspeed_forward > 0 then + speed_forw = maxspeed_forward + else + if maxspeed ~= nil and maxspeed > 0 and speed_forw > maxspeed then + speed_forw = maxspeed + end + end + + if maxspeed_backward ~= nil and maxspeed_backward > 0 then + speed_back = maxspeed_backward + else + if maxspeed ~=nil and maxspeed > 0 and speed_back > maxspeed then + speed_back = maxspeed + end + end + + way.speed = speed_forw + if speed_back ~= way_forw then + way.backward_speed = speed_back + end + end + + if oneway == "no" or oneway == "0" or oneway == "false" then + way.direction = Way.bidirectional + elseif oneway == "-1" then + way.direction = Way.opposite + elseif oneway == "yes" or oneway == "1" or oneway == "true" then + way.direction = Way.oneway + else + way.direction = Way.bidirectional + end + + way.type = 1 + return 1 end diff --git a/routed.cpp b/routed.cpp index 646b542f7..bd5f46373 100644 --- a/routed.cpp +++ b/routed.cpp @@ -31,20 +31,18 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "Util/GitDescription.h" #include "Util/InputFileUtil.h" -#include "Util/OpenMPWrapper.h" #include "Util/ProgramOptions.h" #include "Util/SimpleLogger.h" #include "Util/UUID.h" #ifdef __linux__ -#include "Util/LinuxStackTrace.h" #include #endif #include #include -#include +// #include #include #include @@ -68,61 +66,55 @@ BOOL WINAPI console_ctrl_handler(DWORD ctrl_type) } #endif -int main (int argc, const char * argv[]) { - try { +int main (int argc, const char * argv[]) +{ + try + { LogPolicy::GetInstance().Unmute(); -#ifdef __linux__ - if( -1 == mlockall(MCL_CURRENT | MCL_FUTURE) ) { - SimpleLogger().Write(logWARNING) << - "Process " << argv[0] << " could not be locked to RAM"; - } - installCrashHandler(argv[0]); -#endif - bool use_shared_memory = false; + + bool use_shared_memory = false, trial = false; std::string ip_address; - int ip_port, requested_num_threads; + int ip_port, requested_thread_num; ServerPaths server_paths; - if( !GenerateServerProgramOptions( - argc, - argv, - server_paths, - ip_address, - ip_port, - requested_num_threads, - use_shared_memory - ) - ) { + + const unsigned init_result = GenerateServerProgramOptions(argc, argv, server_paths, ip_address, ip_port, requested_thread_num, use_shared_memory, trial); + if (init_result == INIT_OK_DO_NOT_START_ENGINE) + { return 0; } + if (init_result == INIT_FAILED) + { + return 1; + } +#ifdef __linux__ + const int lock_flags = (MCL_CURRENT | MCL_FUTURE); + if (-1 == mlockall(lock_flags)) + { + SimpleLogger().Write(logWARNING) << "Process " << argv[0] << " could not be locked to RAM"; + } +#endif SimpleLogger().Write() << "starting up engines, " << g_GIT_DESCRIPTION << ", " << "compiled at " << __DATE__ << ", " __TIME__; - if( use_shared_memory ) { + if(use_shared_memory) + { SimpleLogger().Write(logDEBUG) << "Loading from shared memory"; - } else { - SimpleLogger().Write() << - "HSGR file:\t" << server_paths["hsgrdata"]; - SimpleLogger().Write(logDEBUG) << - "Nodes file:\t" << server_paths["nodesdata"]; - SimpleLogger().Write(logDEBUG) << - "Edges file:\t" << server_paths["edgesdata"]; - SimpleLogger().Write(logDEBUG) << - "RAM file:\t" << server_paths["ramindex"]; - SimpleLogger().Write(logDEBUG) << - "Index file:\t" << server_paths["fileindex"]; - SimpleLogger().Write(logDEBUG) << - "Names file:\t" << server_paths["namesdata"]; - SimpleLogger().Write(logDEBUG) << - "Timestamp file:\t" << server_paths["timestamp"]; - SimpleLogger().Write(logDEBUG) << - "Threads:\t" << requested_num_threads; - SimpleLogger().Write(logDEBUG) << - "IP address:\t" << ip_address; - SimpleLogger().Write(logDEBUG) << - "IP port:\t" << ip_port; + } + else + { + SimpleLogger().Write() << "HSGR file:\t" << server_paths["hsgrdata"]; + SimpleLogger().Write(logDEBUG) << "Nodes file:\t" << server_paths["nodesdata"]; + SimpleLogger().Write(logDEBUG) << "Edges file:\t" << server_paths["edgesdata"]; + SimpleLogger().Write(logDEBUG) << "RAM file:\t" << server_paths["ramindex"]; + SimpleLogger().Write(logDEBUG) << "Index file:\t" << server_paths["fileindex"]; + SimpleLogger().Write(logDEBUG) << "Names file:\t" << server_paths["namesdata"]; + SimpleLogger().Write(logDEBUG) << "Timestamp file:\t" << server_paths["timestamp"]; + SimpleLogger().Write(logDEBUG) << "Threads:\t" << requested_thread_num; + SimpleLogger().Write(logDEBUG) << "IP address:\t" << ip_address; + SimpleLogger().Write(logDEBUG) << "IP port:\t" << ip_port; } #ifndef _WIN32 int sig = 0; @@ -132,48 +124,58 @@ int main (int argc, const char * argv[]) { pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask); #endif - OSRM routing_machine(server_paths, use_shared_memory); - Server * s = ServerFactory::CreateServer( + OSRM osrm_lib(server_paths, use_shared_memory); + Server * routing_server = ServerFactory::CreateServer( ip_address, ip_port, - requested_num_threads + requested_thread_num ); - s->GetRequestHandlerPtr().RegisterRoutingMachine(&routing_machine); + routing_server->GetRequestHandlerPtr().RegisterRoutingMachine(&osrm_lib); - boost::thread t(boost::bind(&Server::Run, s)); + if( trial ) + { + SimpleLogger().Write() << "trial run, quitting after successful initialization"; + } + else + { + boost::thread server_thread(boost::bind(&Server::Run, routing_server)); #ifndef _WIN32 - sigset_t wait_mask; - pthread_sigmask(SIG_SETMASK, &old_mask, 0); - sigemptyset(&wait_mask); - sigaddset(&wait_mask, SIGINT); - sigaddset(&wait_mask, SIGQUIT); - sigaddset(&wait_mask, SIGTERM); - pthread_sigmask(SIG_BLOCK, &wait_mask, 0); - std::cout << "[server] running and waiting for requests" << std::endl; - sigwait(&wait_mask, &sig); + sigset_t wait_mask; + pthread_sigmask(SIG_SETMASK, &old_mask, 0); + sigemptyset(&wait_mask); + sigaddset(&wait_mask, SIGINT); + sigaddset(&wait_mask, SIGQUIT); + sigaddset(&wait_mask, SIGTERM); + pthread_sigmask(SIG_BLOCK, &wait_mask, 0); + SimpleLogger().Write() << "running and waiting for requests"; + sigwait(&wait_mask, &sig); #else - // Set console control handler to allow server to be stopped. - console_ctrl_function = boost::bind(&Server::Stop, s); - SetConsoleCtrlHandler(console_ctrl_handler, TRUE); - std::cout << "[server] running and waiting for requests" << std::endl; - s->Run(); + // Set console control handler to allow server to be stopped. + console_ctrl_function = boost::bind(&Server::Stop, routing_server); + SetConsoleCtrlHandler(console_ctrl_handler, TRUE); + SimpleLogger().Write() << "running and waiting for requests"; + routing_server->Run(); #endif - std::cout << "[server] initiating shutdown" << std::endl; - s->Stop(); - std::cout << "[server] stopping threads" << std::endl; + SimpleLogger().Write() << "initiating shutdown"; + routing_server->Stop(); + SimpleLogger().Write() << "stopping threads"; - if(!t.timed_join(boost::posix_time::seconds(2))) { - SimpleLogger().Write(logDEBUG) << - "Threads did not finish within 2 seconds. Hard abort!"; + if (!server_thread.timed_join(boost::posix_time::seconds(2))) + { + SimpleLogger().Write(logDEBUG) << "Threads did not finish within 2 seconds. Hard abort!"; + } } - std::cout << "[server] freeing objects" << std::endl; - delete s; - std::cout << "[server] shutdown completed" << std::endl; - } catch (std::exception& e) { - std::cerr << "[fatal error] exception: " << e.what() << std::endl; + SimpleLogger().Write() << "freeing objects"; + delete routing_server; + SimpleLogger().Write() << "shutdown completed"; + } + catch (const std::exception& e) + { + SimpleLogger().Write(logWARNING) << "exception: " << e.what(); + return 1; } #ifdef __linux__ munlockall(); diff --git a/typedefs.h b/typedefs.h index cfccf98fa..a3a6362fe 100644 --- a/typedefs.h +++ b/typedefs.h @@ -28,20 +28,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef TYPEDEFS_H_ #define TYPEDEFS_H_ -#include -#include - // To fix long and long long woes #include #include -#ifdef __APPLE__ -#include -#endif - -#include -#include - // Necessary workaround for Windows as VS doesn't implement C99 #ifdef _MSC_VER #ifndef M_PI