Merge branch 'develop'

This commit is contained in:
Patrick Niklaus 2015-06-22 13:06:50 +02:00
commit 300d901618
91 changed files with 2540 additions and 2267 deletions

4
.gitignore vendored
View File

@ -1,3 +1,7 @@
# pre compiled dependencies #
#############################
osrm-deps
# Compiled source #
###################
*.com

View File

@ -30,6 +30,7 @@ script:
- make
- make tests
- make benchmarks
- ./algorithm-tests
- ./datastructure-tests
- cd ..
- cucumber -p verify
@ -58,7 +59,7 @@ notifications:
skip_join: false
recipients:
- dennis@mapbox.com
- patrick@mapbox.com
email:
on_success: change
on_failure: always

View File

@ -90,7 +90,7 @@ set(
add_library(COORDINATE OBJECT ${CoordinateGlob})
add_library(GITDESCRIPTION OBJECT util/git_sha.cpp)
add_library(OSRM ${OSRMSources} $<TARGET_OBJECTS:ANGLE> $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:GITDESCRIPTION> $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:PHANTOMNODE> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:MERCATOR>)
add_library(OSRM ${OSRMSources} $<TARGET_OBJECTS:ANGLE> $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:GITDESCRIPTION> $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:PHANTOMNODE> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:MERCATOR> $<TARGET_OBJECTS:IMPORT>)
add_library(FINGERPRINT OBJECT util/fingerprint.cpp)
add_dependencies(FINGERPRINT FingerPrintConfigure)
@ -328,12 +328,10 @@ if(WITH_TOOLS OR BUILD_TOOLS)
if(UNIX AND NOT APPLE)
target_link_libraries(osrm-unlock-all rt)
endif()
add_executable(osrm-check-hsgr tools/check-hsgr.cpp $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:LOGGER>)
target_link_libraries(osrm-check-hsgr ${Boost_LIBRARIES})
add_executable(osrm-check-hsgr tools/check-hsgr.cpp $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:IMPORT>)
target_link_libraries(osrm-check-hsgr ${Boost_LIBRARIES} ${TBB_LIBRARIES})
add_executable(osrm-springclean tools/springclean.cpp $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:GITDESCRIPTION> $<TARGET_OBJECTS:EXCEPTION>)
target_link_libraries(osrm-springclean ${Boost_LIBRARIES})
add_executable(osrm-graph-compare tools/graph_compare.cpp $<TARGET_OBJECTS:FINGERPRINT> $<TARGET_OBJECTS:IMPORT> $<TARGET_OBJECTS:COORDINATE> $<TARGET_OBJECTS:LOGGER> $<TARGET_OBJECTS:RESTRICTION> $<TARGET_OBJECTS:EXCEPTION> $<TARGET_OBJECTS:MERCATOR>)
target_link_libraries(osrm-graph-compare ${Boost_LIBRARIES} ${TBB_LIBRARIES})
install(TARGETS osrm-cli DESTINATION bin)
install(TARGETS osrm-io-benchmark DESTINATION bin)

View File

@ -2,22 +2,27 @@ GEM
remote: http://rubygems.org/
specs:
builder (3.2.2)
cucumber (1.3.8)
cucumber (2.0.0)
builder (>= 2.1.2)
cucumber-core (~> 1.1.3)
diff-lcs (>= 1.1.3)
gherkin (~> 2.12.1)
gherkin (~> 2.12)
multi_json (>= 1.7.5, < 2.0)
multi_test (>= 0.0.2)
diff-lcs (1.2.4)
gherkin (2.12.1)
multi_test (>= 0.1.2)
cucumber-core (1.1.3)
gherkin (~> 2.12.0)
diff-lcs (1.2.5)
gherkin (2.12.2)
multi_json (~> 1.3)
multi_json (1.8.0)
multi_test (0.0.2)
multi_json (1.11.0)
multi_test (0.1.2)
osmlib-base (0.1.4)
rake (10.1.0)
rspec-expectations (2.14.3)
diff-lcs (>= 1.1.3, < 2.0)
sys-proctable (0.9.3)
rake (10.4.2)
rspec-expectations (3.2.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.2.0)
rspec-support (3.2.2)
sys-proctable (0.9.8)
PLATFORMS
ruby

View File

@ -1,12 +1,25 @@
# Readme
## About
For instructions on how to compile and run OSRM, please consult the Wiki at
The Open Source Routing Machine is a high performance routing engine written in C++11 designed to run on OpenStreetMap data.
https://github.com/Project-OSRM/osrm-backend/wiki
## Current build status
or use our free and daily updated online service at
| build config | branch | status |
|:-------------|:--------|:------------|
| Linux | master | [![Build Status](https://travis-ci.org/Project-OSRM/osrm-backend.png?branch=master)](https://travis-ci.org/Project-OSRM/osrm-backend) |
| Linux | develop | [![Build Status](https://travis-ci.org/Project-OSRM/osrm-backend.png?branch=develop)](https://travis-ci.org/Project-OSRM/osrm-backend) |
| Windows | master/develop | [![Build status](https://ci.appveyor.com/api/projects/status/4iuo3s9gxprmcjjh)](https://ci.appveyor.com/project/DennisOSRM/osrm-backend) |
| LUAbind fork | master | [![Build Status](https://travis-ci.org/DennisOSRM/luabind.png?branch=master)](https://travis-ci.org/DennisOSRM/luabind) |
http://map.project-osrm.org
## Building
For instructions on how to [build](https://github.com/Project-OSRM/osrm-backend/wiki/Building-OSRM) and [run OSRM](https://github.com/Project-OSRM/osrm-backend/wiki/Running-OSRM), please consult [the Wiki](https://github.com/Project-OSRM/osrm-backend/wiki).
To quickly try OSRM use our [free and daily updated online service](http://map.project-osrm.org)
## Documentation
See the Wiki's [server API documentation](https://github.com/Project-OSRM/osrm-backend/wiki/Server-api) as well as the [library API documentation](https://github.com/Project-OSRM/osrm-backend/wiki/Library-api)
## References in publications
@ -31,11 +44,3 @@ When using the code in a (scientific) publication, please cite
}
```
## Current build status
| build config | branch | status |
|:-------------|:--------|:------------|
| Linux | master | [![Build Status](https://travis-ci.org/Project-OSRM/osrm-backend.png?branch=master)](https://travis-ci.org/DennisOSRM/Project-OSRM) |
| Linux | develop | [![Build Status](https://travis-ci.org/Project-OSRM/osrm-backend.png?branch=develop)](https://travis-ci.org/DennisOSRM/Project-OSRM) |
| Windows | master/develop | [![Build status](https://ci.appveyor.com/api/projects/status/4iuo3s9gxprmcjjh)](https://ci.appveyor.com/project/DennisOSRM/osrm-backend) |
| LUAbind fork | master | [![Build Status](https://travis-ci.org/DennisOSRM/luabind.png?branch=master)](https://travis-ci.org/DennisOSRM/luabind) |

View File

@ -88,3 +88,41 @@ PolylineCompressor::get_encoded_string(const std::vector<SegmentInformation> &po
}
return encode_vector(delta_numbers);
}
std::vector<FixedPointCoordinate> PolylineCompressor::decode_string(const std::string &geometry_string) const
{
std::vector<FixedPointCoordinate> new_coordinates;
int index = 0, len = geometry_string.size();
int lat = 0, lng = 0;
while (index < len)
{
int b, shift = 0, result = 0;
do
{
b = geometry_string.at(index++) - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
lat += dlat;
shift = 0;
result = 0;
do
{
b = geometry_string.at(index++) - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
lng += dlng;
FixedPointCoordinate p;
p.lat = COORDINATE_PRECISION * (((double) lat / 1E6));
p.lon = COORDINATE_PRECISION * (((double) lng / 1E6));
new_coordinates.push_back(p);
}
return new_coordinates;
}

View File

@ -30,6 +30,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
struct SegmentInformation;
#include <osrm/coordinate.hpp>
#include <string>
#include <vector>
@ -42,6 +44,8 @@ class PolylineCompressor
public:
std::string get_encoded_string(const std::vector<SegmentInformation> &polyline) const;
std::vector<FixedPointCoordinate> decode_string(const std::string &geometry_string) const;
};
#endif /* POLYLINECOMPRESSOR_H_ */

View File

@ -150,7 +150,7 @@ template <typename GraphT> class TarjanSCC
// Traverse outgoing edges
if (barrier_node_set.find(v) != barrier_node_set.end() && u != vprime)
{
// continue;
continue;
}
if (to_node_of_only_restriction != std::numeric_limits<unsigned>::max() &&

113
appveyor-build.bat Normal file
View File

@ -0,0 +1,113 @@
@ECHO OFF
SETLOCAL
SET EL=0
ECHO platform^: %platform%
:: HARDCODE "x64" as it is uppercase on AppVeyor and download from S3 is case sensitive
SET DEPSPKG=osrm-deps-win-x64-14.0.7z
:: local development
IF "%computername%"=="MB" GOTO SKIPDL
IF EXIST %DEPSPKG% DEL %DEPSPKG%
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
ECHO downloading %DEPSPKG%
powershell Invoke-WebRequest https://mapbox.s3.amazonaws.com/windows-builds/windows-deps/$env:DEPSPKG -OutFile C:\projects\osrm\$env:DEPSPKG
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
7z -y x %DEPSPKG% | %windir%\system32\FIND "ing archive"
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
:SKIPDL
IF EXIST build rd /s /q build
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
mkdir build
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
cd build
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
SET OSRMDEPSDIR=c:\projects\osrm\osrm-deps
set PREFIX=%OSRMDEPSDIR%/libs
set BOOST_ROOT=%OSRMDEPSDIR%/boost
set TBB_INSTALL_DIR=%OSRMDEPSDIR%/tbb
set TBB_ARCH_PLATFORM=intel64/vc14
ECHO calling cmake ....
cmake .. ^
-G "Visual Studio 14 Win64" ^
-DBOOST_ROOT=%BOOST_ROOT% ^
-DBoost_ADDITIONAL_VERSIONS=1.57 ^
-DBoost_USE_MULTITHREADED=ON ^
-DBoost_USE_STATIC_LIBS=ON ^
-DCMAKE_BUILD_TYPE=%CONFIGURATION% ^
-DCMAKE_INSTALL_PREFIX=%PREFIX%
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
ECHO building ...
msbuild OSRM.sln ^
/p:Configuration=%Configuration% ^
/p:Platform=x64 ^
/t:rebuild ^
/p:BuildInParallel=true ^
/m:%NUMBER_OF_PROCESSORS% ^
/toolsversion:14.0 ^
/p:PlatformToolset=v140 ^
/clp:Verbosity=normal ^
/nologo ^
/flp1:logfile=build_errors.txt;errorsonly ^
/flp2:logfile=build_warnings.txt;warningsonly
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
ECHO ========= TODO^: CREATE PACKAGES ==========
CD c:\projects\osrm\build\%Configuration%
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
SET PATH=c:\projects\osrm\osrm-deps\libs\bin;%PATH%
ECHO running datastructure-tests.exe ...
datastructure-tests.exe
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
ECHO running algorithm-tests.exe ...
algorithm-tests.exe
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
GOTO DONE
:ERROR
SET EL=%ERRORLEVEL%
ECHO ============== ERROR ===============
:DONE
ECHO ============= DONE ===============
CD C:\projects\osrm
EXIT /b %EL%
- cd c:/projects/osrm
- mkdir build
- cd build
- echo Running cmake...
- call "%VS120COMNTOOLS%\..\..\VC\vcvarsall.bat" x86_amd64
- SET PATH=C:\Program Files (x86)\MSBuild\12.0\bin\;%PATH%
- SET P=c:/projects/osrm
- set TBB_INSTALL_DIR=%P%/tbb
- set TBB_ARCH_PLATFORM=intel64/vc12
- cmake .. -G "Visual Studio 14 Win64" -DCMAKE_BUILD_TYPE=%Configuration% -DCMAKE_INSTALL_PREFIX=%P%/libs -DBOOST_ROOT=%P%/boost_min -DBoost_ADDITIONAL_VERSIONS=1.57 -DBoost_USE_STATIC_LIBS=ON
- SET PLATFORM_TOOLSET=v140
- SET TOOLS_VERSION=14.0
- msbuild /p:Platform=x64 /clp:Verbosity=minimal /toolsversion:%TOOLS_VERSION% /p:PlatformToolset=%PLATFORM_TOOLSET% /nologo OSRM.sln
- msbuild /p:Platform=x64 /clp:Verbosity=minimal /toolsversion:%TOOLS_VERSION% /p:PlatformToolset=%PLATFORM_TOOLSET% /nologo tests.vcxproj
- cd %Configuration%
- if "%APPVEYOR_REPO_BRANCH%"=="develop" (7z a %P%/osrm_%Configuration%.zip *.exe *.pdb %P%/libs/bin/*.dll -tzip)
- cd ..\..\profiles
- echo disk=c:\temp\stxxl,10000,wincall > .stxxl.txt
- if "%APPVEYOR_REPO_BRANCH%"=="develop" (7z a %P%/osrm_%Configuration%.zip * -tzip)
- set PATH=%PATH%;c:/projects/osrm/libs/bin
- cd c:/projects/osrm/build/%Configuration%
- datastructure-tests.exe
- algorithm-tests.exe

View File

@ -1,60 +1,33 @@
environment:
matrix:
- configuration: Debug
- configuration: Release
# branches to build
branches:
# whitelist
only:
- develop
# - configuration: Debug
# scripts that are called at very beginning, before repo cloning
init:
- git config --global core.autocrlf input
os: Visual Studio 2015 RC
# clone directory
clone_folder: c:\projects\osrm
platform: x64
install:
# by default, all script lines are interpreted as batch
- nuget install protobuf
- cd c:\projects\osrm
- curl -O http://build.project-osrm.org/libs_osrm_%Configuration%.7z
- 7z x libs_osrm_%Configuration%.7z | find ":"
- set PATH=C:\Program Files (x86)\MSBuild\14.0\Bin;%PATH%
- CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64
build_script:
- cd c:/projects/osrm
- mkdir build
- cd build
- echo Running cmake...
- call "%VS120COMNTOOLS%\..\..\VC\vcvarsall.bat" x86_amd64
- SET PATH=C:\Program Files (x86)\MSBuild\12.0\bin\;%PATH%
- SET P=c:/projects/osrm
- set TBB_INSTALL_DIR=%P%/tbb
- set TBB_ARCH_PLATFORM=intel64/vc12
- cmake .. -G "Visual Studio 12 Win64" -DCMAKE_BUILD_TYPE=%Configuration% -DCMAKE_INSTALL_PREFIX=%P%/libs -DBOOST_ROOT=%P%/boost_min -DBoost_ADDITIONAL_VERSIONS=1.57 -DBoost_USE_STATIC_LIBS=ON -T CTP_Nov2013
- msbuild /clp:Verbosity=minimal /nologo OSRM.sln
- msbuild /clp:Verbosity=minimal /nologo tests.vcxproj
- cd %Configuration%
- if "%APPVEYOR_REPO_BRANCH%"=="develop" (7z a %P%/osrm_%Configuration%.zip *.exe *.pdb %P%/libs/bin/*.dll -tzip)
- cd ..\..\profiles
- echo disk=c:\temp\stxxl,10000,wincall > .stxxl.txt
- if "%APPVEYOR_REPO_BRANCH%"=="develop" (7z a %P%/osrm_%Configuration%.zip * -tzip)
- set PATH=%PATH%;c:/projects/osrm/libs/bin
- cd c:/projects/osrm/build/%Configuration%
- datastructure-tests.exe
- algorithm-tests.exe
- CALL appveyor-build.bat
test: off
artifacts:
- path: osrm_Debug.zip
name: osrm_Debug.zip
- path: osrm_Release.zip
name: osrm_Release.zip
# - path: osrm_Debug.zip
# name: osrm_Debug.zip
deploy:
provider: FTP

19
build-local.bat Normal file
View File

@ -0,0 +1,19 @@
@ECHO OFF
SET PLATFORM=x64
SET CONFIGURATION=Release
WHERE msbuild
IF %ERRORLEVEL% EQU 0 GOTO RUNBUILD
SET PATH=C:\mb\windows-builds-64\tmp-bin\cmake-3.1.0-win32-x86\bin;%PATH%
SET PATH=C:\Program Files\7-Zip;%PATH%
ECHO activating VS command prompt ...
SET PATH=C:\Program Files (x86)\MSBuild\14.0\Bin;%PATH%
CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64
:RUNBUILD
powershell Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Unrestricted -Force
CALL appveyor-build.bat
EXIT /b %ERRORLEVEL%

View File

@ -171,7 +171,8 @@ class Contractor
{
SimpleLogger().Write(logWARNING)
<< "Edge weight large -> "
<< static_cast<unsigned int>(std::max(diter->weight, 1));
<< static_cast<unsigned int>(std::max(diter->weight, 1)) << " : "
<< static_cast<unsigned int>(diter->source) << " -> " << static_cast<unsigned int>(diter->target);
}
#endif
edges.emplace_back(diter->source, diter->target,
@ -186,6 +187,7 @@ class Contractor
}
// clear input vector
input_edge_list.clear();
// FIXME not sure if we need this
edges.shrink_to_fit();
tbb::parallel_sort(edges.begin(), edges.end());
@ -953,7 +955,6 @@ class Contractor
}
std::shared_ptr<ContractorGraph> contractor_graph;
std::vector<ContractorGraph::InputEdge> contracted_edge_list;
stxxl::vector<QueryEdge> external_edge_list;
std::vector<NodeID> orig_node_id_to_new_id_map;
XORFastHash fast_hash;

View File

@ -0,0 +1,135 @@
/*
Copyright (c) 2015, Project OSRM contributors
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 "contractor_options.hpp"
#include "../util/git_sha.hpp"
#include "../util/simple_logger.hpp"
#include <boost/filesystem.hpp>
#include <boost/program_options.hpp>
#include <tbb/task_scheduler_init.h>
return_code
ContractorOptions::ParseArguments(int argc, char *argv[], ContractorConfig &contractor_config)
{
// 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<boost::filesystem::path>(&contractor_config.config_file_path)
->default_value("contractor.ini"),
"Path to a configuration file.");
// declare a group of options that will be allowed both on command line and in config file
boost::program_options::options_description config_options("Configuration");
config_options.add_options()(
"restrictions,r",
boost::program_options::value<boost::filesystem::path>(&contractor_config.restrictions_path),
"Restrictions file in .osrm.restrictions format")(
"profile,p", boost::program_options::value<boost::filesystem::path>(&contractor_config.profile_path)
->default_value("profile.lua"),
"Path to LUA routing profile")(
"threads,t", boost::program_options::value<unsigned int>(&contractor_config.requested_num_threads)
->default_value(tbb::task_scheduler_init::default_num_threads()),
"Number of threads to use");
// 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()(
"input,i", boost::program_options::value<boost::filesystem::path>(&contractor_config.osrm_input_path),
"Input file in .osm, .osm.bz2 or .osm.pbf format");
// positional option
boost::program_options::positional_options_description positional_options;
positional_options.add("input", 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(
"Usage: " + boost::filesystem::basename(argv[0]) + " <input.osrm> [options]");
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);
const auto &temp_config_path = option_variables["config"].as<boost::filesystem::path>();
if (boost::filesystem::is_regular_file(temp_config_path))
{
boost::program_options::store(boost::program_options::parse_config_file<char>(
temp_config_path.string().c_str(), cmdline_options, true),
option_variables);
}
if (option_variables.count("version"))
{
SimpleLogger().Write() << g_GIT_DESCRIPTION;
return return_code::exit;
}
if (option_variables.count("help"))
{
SimpleLogger().Write() << "\n" << visible_options;
return return_code::exit;
}
boost::program_options::notify(option_variables);
if (!option_variables.count("restrictions"))
{
contractor_config.restrictions_path = contractor_config.osrm_input_path.string() + ".restrictions";
}
if (!option_variables.count("input"))
{
SimpleLogger().Write() << "\n" << visible_options;
return return_code::fail;
}
return return_code::ok;
}
void ContractorOptions::GenerateOutputFilesNames(ContractorConfig &contractor_config)
{
contractor_config.node_output_path = contractor_config.osrm_input_path.string() + ".nodes";
contractor_config.edge_output_path = contractor_config.osrm_input_path.string() + ".edges";
contractor_config.geometry_output_path = contractor_config.osrm_input_path.string() + ".geometry";
contractor_config.graph_output_path = contractor_config.osrm_input_path.string() + ".hsgr";
contractor_config.rtree_nodes_output_path = contractor_config.osrm_input_path.string() + ".ramIndex";
contractor_config.rtree_leafs_output_path = contractor_config.osrm_input_path.string() + ".fileIndex";
}

View File

@ -0,0 +1,68 @@
/*
Copyright (c) 2015, Project OSRM contributors
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 CONTRACTOR_OPTIONS_HPP
#define CONTRACTOR_OPTIONS_HPP
#include <boost/filesystem/path.hpp>
#include <string>
enum class return_code : unsigned
{
ok,
fail,
exit
};
struct ContractorConfig
{
ContractorConfig() noexcept : requested_num_threads(0) {}
boost::filesystem::path config_file_path;
boost::filesystem::path osrm_input_path;
boost::filesystem::path restrictions_path;
boost::filesystem::path profile_path;
std::string node_output_path;
std::string edge_output_path;
std::string geometry_output_path;
std::string graph_output_path;
std::string rtree_nodes_output_path;
std::string rtree_leafs_output_path;
unsigned requested_num_threads;
};
struct ContractorOptions
{
static return_code ParseArguments(int argc, char *argv[], ContractorConfig &extractor_config);
static void GenerateOutputFilesNames(ContractorConfig &extractor_config);
};
#endif // EXTRACTOR_OPTIONS_HPP

View File

@ -40,21 +40,21 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <iomanip>
#include <limits>
EdgeBasedGraphFactory::EdgeBasedGraphFactory(
const std::shared_ptr<NodeBasedDynamicGraph> &node_based_graph,
std::unique_ptr<RestrictionMap> restriction_map,
std::vector<NodeID> &barrier_node_list,
std::vector<NodeID> &traffic_light_node_list,
std::vector<QueryNode> &node_info_list,
SpeedProfileProperties &speed_profile)
EdgeBasedGraphFactory::EdgeBasedGraphFactory(std::shared_ptr<NodeBasedDynamicGraph> node_based_graph,
std::shared_ptr<RestrictionMap> restriction_map,
std::unique_ptr<std::vector<NodeID>> barrier_node_list,
std::unique_ptr<std::vector<NodeID>> traffic_light_node_list,
const std::vector<QueryNode> &node_info_list,
const SpeedProfileProperties &speed_profile)
: speed_profile(speed_profile),
m_number_of_edge_based_nodes(std::numeric_limits<unsigned>::max()),
m_node_info_list(node_info_list), m_node_based_graph(node_based_graph),
m_node_info_list(node_info_list),
m_node_based_graph(std::move(node_based_graph)),
m_restriction_map(std::move(restriction_map)), max_id(0), removed_node_count(0)
{
// insert into unordered sets for fast lookup
m_barrier_nodes.insert(barrier_node_list.begin(), barrier_node_list.end());
m_traffic_lights.insert(traffic_light_node_list.begin(), traffic_light_node_list.end());
m_barrier_nodes.insert(barrier_node_list->begin(), barrier_node_list->end());
m_traffic_lights.insert(traffic_light_node_list->begin(), traffic_light_node_list->end());
}
void EdgeBasedGraphFactory::GetEdgeBasedEdges(DeallocatingVector<EdgeBasedEdge> &output_edge_list)
@ -193,15 +193,16 @@ void EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u,
{
BOOST_ASSERT(forward_data.forward);
}
else
{
BOOST_ASSERT(!forward_data.forward);
}
if (reverse_data.edgeBasedNodeID != SPECIAL_NODEID)
{
BOOST_ASSERT(reverse_data.forward);
}
if (forward_data.edgeBasedNodeID == SPECIAL_NODEID)
{
BOOST_ASSERT(!forward_data.forward);
}
if (reverse_data.edgeBasedNodeID == SPECIAL_NODEID)
else
{
BOOST_ASSERT(!reverse_data.forward);
}
@ -233,7 +234,6 @@ void EdgeBasedGraphFactory::Run(const std::string &original_edge_data_filename,
const std::string &geometry_filename,
lua_State *lua_state)
{
TIMER_START(geometry);
CompressGeometry();
TIMER_STOP(geometry);
@ -290,12 +290,33 @@ void EdgeBasedGraphFactory::CompressGeometry()
continue;
}
/*
* reverse_e2 forward_e2
* u <---------- v -----------> w
* ----------> <-----------
* forward_e1 reverse_e1
*
* Will be compressed to:
*
* reverse_e1
* u <---------- w
* ---------->
* forward_e1
*
* If the edges are compatible.
*
*/
const bool reverse_edge_order =
!(m_node_based_graph->GetEdgeData(m_node_based_graph->BeginEdges(node_v)).forward);
const EdgeID forward_e2 = m_node_based_graph->BeginEdges(node_v) + reverse_edge_order;
BOOST_ASSERT(SPECIAL_EDGEID != forward_e2);
BOOST_ASSERT(forward_e2 >= m_node_based_graph->BeginEdges(node_v) &&
forward_e2 < m_node_based_graph->EndEdges(node_v));
const EdgeID reverse_e2 = m_node_based_graph->BeginEdges(node_v) + 1 - reverse_edge_order;
BOOST_ASSERT(SPECIAL_EDGEID != reverse_e2);
BOOST_ASSERT(reverse_e2 >= m_node_based_graph->BeginEdges(node_v) &&
reverse_e2 < m_node_based_graph->EndEdges(node_v));
const EdgeData &fwd_edge_data2 = m_node_based_graph->GetEdgeData(forward_e2);
const EdgeData &rev_edge_data2 = m_node_based_graph->GetEdgeData(reverse_e2);
@ -322,9 +343,20 @@ void EdgeBasedGraphFactory::CompressGeometry()
continue;
}
if ( // TODO: rename to IsCompatibleTo
fwd_edge_data1.IsEqualTo(fwd_edge_data2) && rev_edge_data1.IsEqualTo(rev_edge_data2))
// this case can happen if two ways with different names overlap
if (fwd_edge_data1.nameID != rev_edge_data1.nameID ||
fwd_edge_data2.nameID != rev_edge_data2.nameID)
{
continue;
}
if (fwd_edge_data1.IsCompatibleTo(fwd_edge_data2) && rev_edge_data1.IsCompatibleTo(rev_edge_data2))
{
BOOST_ASSERT(m_node_based_graph->GetEdgeData(forward_e1).nameID ==
m_node_based_graph->GetEdgeData(reverse_e1).nameID);
BOOST_ASSERT(m_node_based_graph->GetEdgeData(forward_e2).nameID ==
m_node_based_graph->GetEdgeData(reverse_e2).nameID);
// Get distances before graph is modified
const int forward_weight1 = m_node_based_graph->GetEdgeData(forward_e1).distance;
const int forward_weight2 = m_node_based_graph->GetEdgeData(forward_e2).distance;
@ -336,7 +368,7 @@ void EdgeBasedGraphFactory::CompressGeometry()
const int reverse_weight2 = m_node_based_graph->GetEdgeData(reverse_e2).distance;
BOOST_ASSERT(0 != reverse_weight1);
BOOST_ASSERT(0 != forward_weight2);
BOOST_ASSERT(0 != reverse_weight2);
const bool has_node_penalty = m_traffic_lights.find(node_v) != m_traffic_lights.end();
@ -362,11 +394,11 @@ void EdgeBasedGraphFactory::CompressGeometry()
// update any involved turn restrictions
m_restriction_map->FixupStartingTurnRestriction(node_u, node_v, node_w);
m_restriction_map->FixupArrivingTurnRestriction(node_u, node_v, node_w,
m_node_based_graph);
*m_node_based_graph);
m_restriction_map->FixupStartingTurnRestriction(node_w, node_v, node_u);
m_restriction_map->FixupArrivingTurnRestriction(node_w, node_v, node_u,
m_node_based_graph);
*m_node_based_graph);
// store compressed geometry in container
m_geometry_compressor.CompressEdge(
@ -378,8 +410,7 @@ void EdgeBasedGraphFactory::CompressGeometry()
reverse_weight2 + (has_node_penalty ? speed_profile.traffic_signal_penalty : 0));
++removed_node_count;
BOOST_ASSERT(m_node_based_graph->GetEdgeData(forward_e1).nameID ==
m_node_based_graph->GetEdgeData(reverse_e1).nameID);
}
}
SimpleLogger().Write() << "removed " << removed_node_count << " nodes";
@ -403,18 +434,19 @@ void EdgeBasedGraphFactory::CompressGeometry()
<< new_edge_count / (double)original_number_of_edges;
}
/**
* Writes the id of the edge in the edge expanded graph (into the edge in the node based graph)
*/
/// Renumbers all _forward_ edges and sets the edgeBasedNodeID.
/// A specific numbering is not important. Any unique ID will do.
void EdgeBasedGraphFactory::RenumberEdges()
{
// renumber edge based node IDs
// renumber edge based node of outgoing edges
unsigned numbered_edges_count = 0;
for (const auto current_node : osrm::irange(0u, m_node_based_graph->GetNumberOfNodes()))
{
for (const auto current_edge : m_node_based_graph->GetAdjacentEdgeRange(current_node))
{
EdgeData &edge_data = m_node_based_graph->GetEdgeData(current_edge);
// this edge is an incoming edge
if (!edge_data.forward)
{
continue;
@ -466,7 +498,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedNodes()
const NodeID node_v = m_node_based_graph->GetTarget(e1);
BOOST_ASSERT(SPECIAL_NODEID != node_v);
// pick only every other edge
// pick only every other edge, since we have every edge as an outgoing
// and incoming egde
if (node_u > node_v)
{
continue;
@ -492,6 +525,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedNodes()
const bool component_is_tiny = size_of_component < 1000;
// we only set edgeBasedNodeID for forward edges
if (edge_data.edgeBasedNodeID == SPECIAL_NODEID)
{
InsertEdgeBasedNode(node_v, node_u,

View File

@ -59,12 +59,12 @@ class EdgeBasedGraphFactory
struct SpeedProfileProperties;
explicit EdgeBasedGraphFactory(const std::shared_ptr<NodeBasedDynamicGraph> &node_based_graph,
std::unique_ptr<RestrictionMap> restricion_map,
std::vector<NodeID> &barrier_node_list,
std::vector<NodeID> &traffic_light_node_list,
std::vector<QueryNode> &node_info_list,
SpeedProfileProperties &speed_profile);
explicit EdgeBasedGraphFactory(std::shared_ptr<NodeBasedDynamicGraph> node_based_graph,
std::shared_ptr<RestrictionMap> restricion_map,
std::unique_ptr<std::vector<NodeID>> barrier_node_list,
std::unique_ptr<std::vector<NodeID>> traffic_light_node_list,
const std::vector<QueryNode> &node_info_list,
const SpeedProfileProperties &speed_profile);
void Run(const std::string &original_edge_data_filename,
const std::string &geometry_filename,
@ -97,15 +97,16 @@ class EdgeBasedGraphFactory
unsigned m_number_of_edge_based_nodes;
std::vector<QueryNode> m_node_info_list;
std::vector<EdgeBasedNode> m_edge_based_node_list;
DeallocatingVector<EdgeBasedEdge> m_edge_based_edge_list;
const std::vector<QueryNode>& m_node_info_list;
std::shared_ptr<NodeBasedDynamicGraph> m_node_based_graph;
std::shared_ptr<RestrictionMap> m_restriction_map;
std::unordered_set<NodeID> m_barrier_nodes;
std::unordered_set<NodeID> m_traffic_lights;
std::unique_ptr<RestrictionMap> m_restriction_map;
GeometryCompressor m_geometry_compressor;

View File

@ -48,7 +48,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <boost/filesystem/fstream.hpp>
#include <boost/program_options.hpp>
#include <tbb/task_scheduler_init.h>
#include <tbb/parallel_sort.h>
#include <chrono>
@ -57,166 +56,98 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <thread>
#include <vector>
Prepare::Prepare() : requested_num_threads(1) {}
Prepare::~Prepare() {}
int Prepare::Process(int argc, char *argv[])
int Prepare::Run()
{
LogPolicy::GetInstance().Unmute();
TIMER_START(preparing);
TIMER_START(expansion);
if (!ParseArguments(argc, argv))
{
return 0;
}
if (!boost::filesystem::is_regular_file(input_path))
{
SimpleLogger().Write(logWARNING) << "Input file " << input_path.string() << " not found!";
return 1;
}
if (!boost::filesystem::is_regular_file(profile_path))
{
SimpleLogger().Write(logWARNING) << "Profile " << profile_path.string() << " not found!";
return 1;
}
if (1 > requested_num_threads)
{
SimpleLogger().Write(logWARNING) << "Number of threads must be 1 or larger";
return 1;
}
const unsigned recommended_num_threads = tbb::task_scheduler_init::default_num_threads();
SimpleLogger().Write() << "Input file: " << input_path.filename().string();
SimpleLogger().Write() << "Restrictions file: " << restrictions_path.filename().string();
SimpleLogger().Write() << "Profile: " << profile_path.filename().string();
SimpleLogger().Write() << "Threads: " << requested_num_threads;
if (recommended_num_threads != requested_num_threads)
{
SimpleLogger().Write(logWARNING) << "The recommended number of threads is "
<< recommended_num_threads
<< "! This setting may have performance side-effects.";
}
tbb::task_scheduler_init init(requested_num_threads);
LogPolicy::GetInstance().Unmute();
FingerPrint fingerprint_orig;
CheckRestrictionsFile(fingerprint_orig);
boost::filesystem::ifstream input_stream(input_path, std::ios::in | std::ios::binary);
node_filename = input_path.string() + ".nodes";
edge_out = input_path.string() + ".edges";
geometry_filename = input_path.string() + ".geometry";
graph_out = input_path.string() + ".hsgr";
rtree_nodes_path = input_path.string() + ".ramIndex";
rtree_leafs_path = input_path.string() + ".fileIndex";
/*** Setup Scripting Environment ***/
// Create a new lua state
lua_State *lua_state = luaL_newstate();
// Connect LuaBind to this lua state
luabind::open(lua_state);
EdgeBasedGraphFactory::SpeedProfileProperties speed_profile;
if (!SetupScriptingEnvironment(lua_state, speed_profile))
{
return 1;
}
#ifdef WIN32
#pragma message("Memory consumption on Windows can be higher due to different bit packing")
#else
static_assert(sizeof(ImportEdge) == 20,
"changing ImportEdge type has influence on memory consumption!");
static_assert(sizeof(NodeBasedEdge) == 20,
"changing NodeBasedEdge type has influence on memory consumption!");
static_assert(sizeof(EdgeBasedEdge) == 16,
"changing EdgeBasedEdge type has influence on memory consumption!");
#endif
NodeID number_of_node_based_nodes = readBinaryOSRMGraphFromStream(
input_stream, edge_list, barrier_node_list, traffic_light_list,
&internal_to_external_node_map, restriction_list);
input_stream.close();
if (edge_list.empty())
{
SimpleLogger().Write(logWARNING) << "The input data is empty, exiting.";
return 1;
}
TIMER_START(preparing);
SimpleLogger().Write() << restriction_list.size() << " restrictions, "
<< barrier_node_list.size() << " bollard nodes, "
<< traffic_light_list.size() << " traffic lights";
// Create a new lua state
std::vector<EdgeBasedNode> node_based_edge_list;
unsigned number_of_edge_based_nodes = 0;
SimpleLogger().Write() << "Generating edge-expanded graph representation";
TIMER_START(expansion);
auto node_based_edge_list = osrm::make_unique<std::vector<EdgeBasedNode>>();;
DeallocatingVector<EdgeBasedEdge> edge_based_edge_list;
auto internal_to_external_node_map = osrm::make_unique<std::vector<QueryNode>>();
auto graph_size =
BuildEdgeExpandedGraph(*internal_to_external_node_map,
*node_based_edge_list, edge_based_edge_list);
// init node_based_edge_list, edge_based_edge_list by edgeList
number_of_edge_based_nodes =
BuildEdgeExpandedGraph(lua_state, number_of_node_based_nodes, node_based_edge_list,
edge_based_edge_list, speed_profile);
lua_close(lua_state);
auto number_of_node_based_nodes = graph_size.first;
auto number_of_edge_based_nodes = graph_size.second;
TIMER_STOP(expansion);
BuildRTree(node_based_edge_list);
SimpleLogger().Write() << "building r-tree ...";
TIMER_START(rtree);
RangebasedCRC32 crc32;
if (crc32.using_hardware())
{
SimpleLogger().Write() << "using hardware based CRC32 computation";
}
else
{
SimpleLogger().Write() << "using software based CRC32 computation";
}
BuildRTree(*node_based_edge_list, *internal_to_external_node_map);
const unsigned crc32_value = crc32(node_based_edge_list);
node_based_edge_list.clear();
node_based_edge_list.shrink_to_fit();
SimpleLogger().Write() << "CRC32: " << crc32_value;
TIMER_STOP(rtree);
WriteNodeMapping();
SimpleLogger().Write() << "writing node map ...";
WriteNodeMapping(std::move(internal_to_external_node_map));
/***
* Contracting the edge-expanded graph
*/
SimpleLogger().Write() << "initializing contractor";
auto contractor =
osrm::make_unique<Contractor>(number_of_edge_based_nodes, edge_based_edge_list);
// Contracting the edge-expanded graph
TIMER_START(contraction);
contractor->Run();
auto contracted_edge_list = osrm::make_unique<DeallocatingVector<QueryEdge>>();
ContractGraph(number_of_edge_based_nodes, edge_based_edge_list, *contracted_edge_list);
TIMER_STOP(contraction);
SimpleLogger().Write() << "Contraction took " << TIMER_SEC(contraction) << " sec";
DeallocatingVector<QueryEdge> contracted_edge_list;
contractor->GetEdges(contracted_edge_list);
contractor.reset();
std::size_t number_of_used_edges = WriteContractedGraph(number_of_edge_based_nodes,
std::move(node_based_edge_list),
std::move(contracted_edge_list));
/***
* Sorting contracted edges in a way that the static query graph can read some in in-place.
*/
TIMER_STOP(preparing);
tbb::parallel_sort(contracted_edge_list.begin(), contracted_edge_list.end());
const unsigned contracted_edge_count = contracted_edge_list.size();
SimpleLogger().Write() << "Preprocessing : " << TIMER_SEC(preparing) << " seconds";
SimpleLogger().Write() << "Expansion : " << (number_of_node_based_nodes / TIMER_SEC(expansion))
<< " nodes/sec and "
<< (number_of_edge_based_nodes / TIMER_SEC(expansion)) << " edges/sec";
SimpleLogger().Write() << "Contraction: "
<< (number_of_edge_based_nodes / TIMER_SEC(contraction))
<< " nodes/sec and " << number_of_used_edges / TIMER_SEC(contraction)
<< " edges/sec";
SimpleLogger().Write() << "finished preprocessing";
return 0;
}
std::size_t Prepare::WriteContractedGraph(unsigned number_of_edge_based_nodes,
std::unique_ptr<std::vector<EdgeBasedNode>> node_based_edge_list,
std::unique_ptr<DeallocatingVector<QueryEdge>> contracted_edge_list)
{
const unsigned crc32_value = CalculateEdgeChecksum(std::move(node_based_edge_list));
// Sorting contracted edges in a way that the static query graph can read some in in-place.
tbb::parallel_sort(contracted_edge_list->begin(), contracted_edge_list->end());
const unsigned contracted_edge_count = contracted_edge_list->size();
SimpleLogger().Write() << "Serializing compacted graph of " << contracted_edge_count
<< " edges";
boost::filesystem::ofstream hsgr_output_stream(graph_out, std::ios::binary);
hsgr_output_stream.write((char *)&fingerprint_orig, sizeof(FingerPrint));
const FingerPrint fingerprint = FingerPrint::GetValid();
boost::filesystem::ofstream hsgr_output_stream(config.graph_output_path, std::ios::binary);
hsgr_output_stream.write((char *)&fingerprint, sizeof(FingerPrint));
const unsigned max_used_node_id = 1 + [&contracted_edge_list]
{
unsigned tmp_max = 0;
for (const QueryEdge &edge : contracted_edge_list)
for (const QueryEdge &edge : *contracted_edge_list)
{
BOOST_ASSERT(SPECIAL_NODEID != edge.source);
BOOST_ASSERT(SPECIAL_NODEID != edge.target);
@ -241,7 +172,7 @@ int Prepare::Process(int argc, char *argv[])
for (const auto node : osrm::irange(0u, max_used_node_id))
{
last_edge = edge;
while ((edge < contracted_edge_count) && (contracted_edge_list[edge].source == node))
while ((edge < contracted_edge_count) && ((*contracted_edge_list)[edge].source == node))
{
++edge;
}
@ -270,19 +201,19 @@ int Prepare::Process(int argc, char *argv[])
hsgr_output_stream.write((char *)&node_array[0],
sizeof(StaticGraph<EdgeData>::NodeArrayEntry) * node_array_size);
}
// serialize all edges
// serialize all edges
SimpleLogger().Write() << "Building edge array";
edge = 0;
int number_of_used_edges = 0;
StaticGraph<EdgeData>::EdgeArrayEntry current_edge;
for (const auto edge : osrm::irange<std::size_t>(0, contracted_edge_list.size()))
for (const auto edge : osrm::irange<std::size_t>(0, contracted_edge_list->size()))
{
// no eigen loops
BOOST_ASSERT(contracted_edge_list[edge].source != contracted_edge_list[edge].target);
current_edge.target = contracted_edge_list[edge].target;
current_edge.data = contracted_edge_list[edge].data;
BOOST_ASSERT((*contracted_edge_list)[edge].source != (*contracted_edge_list)[edge].target);
current_edge.target = (*contracted_edge_list)[edge].target;
current_edge.data = (*contracted_edge_list)[edge].data;
// every target needs to be valid
BOOST_ASSERT(current_edge.target < max_used_node_id);
@ -290,12 +221,12 @@ int Prepare::Process(int argc, char *argv[])
if (current_edge.data.distance <= 0)
{
SimpleLogger().Write(logWARNING) << "Edge: " << edge
<< ",source: " << contracted_edge_list[edge].source
<< ", target: " << contracted_edge_list[edge].target
<< ",source: " << (*contracted_edge_list)[edge].source
<< ", target: " << (*contracted_edge_list)[edge].target
<< ", dist: " << current_edge.data.distance;
SimpleLogger().Write(logWARNING) << "Failed at adjacency list of node "
<< contracted_edge_list[edge].source << "/"
<< (*contracted_edge_list)[edge].source << "/"
<< node_array.size() - 1;
return 1;
}
@ -305,170 +236,54 @@ int Prepare::Process(int argc, char *argv[])
++number_of_used_edges;
}
hsgr_output_stream.close();
TIMER_STOP(preparing);
SimpleLogger().Write() << "Preprocessing : " << TIMER_SEC(preparing) << " seconds";
SimpleLogger().Write() << "Expansion : " << (number_of_node_based_nodes / TIMER_SEC(expansion))
<< " nodes/sec and "
<< (number_of_edge_based_nodes / TIMER_SEC(expansion)) << " edges/sec";
SimpleLogger().Write() << "Contraction: "
<< (number_of_edge_based_nodes / TIMER_SEC(contraction))
<< " nodes/sec and " << number_of_used_edges / TIMER_SEC(contraction)
<< " edges/sec";
node_array.clear();
SimpleLogger().Write() << "finished preprocessing";
return 0;
return number_of_used_edges;
}
/**
\brief Parses command line arguments
\param argc count of arguments
\param argv array of arguments
\param result [out] value for exit return value
\return true if everything is ok, false if need to terminate execution
*/
bool Prepare::ParseArguments(int argc, char *argv[])
unsigned Prepare::CalculateEdgeChecksum(std::unique_ptr<std::vector<EdgeBasedNode>> node_based_edge_list)
{
// 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<boost::filesystem::path>(&config_file_path)
->default_value("contractor.ini"),
"Path to a configuration file.");
// declare a group of options that will be allowed both on command line and in config file
boost::program_options::options_description config_options("Configuration");
config_options.add_options()(
"restrictions,r",
boost::program_options::value<boost::filesystem::path>(&restrictions_path),
"Restrictions file in .osrm.restrictions format")(
"profile,p", boost::program_options::value<boost::filesystem::path>(&profile_path)
->default_value("profile.lua"),
"Path to LUA routing profile")(
"threads,t", boost::program_options::value<unsigned int>(&requested_num_threads)
->default_value(tbb::task_scheduler_init::default_num_threads()),
"Number of threads to use");
// 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()(
"input,i", boost::program_options::value<boost::filesystem::path>(&input_path),
"Input file in .osm, .osm.bz2 or .osm.pbf format");
// positional option
boost::program_options::positional_options_description positional_options;
positional_options.add("input", 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(
"Usage: " + boost::filesystem::basename(argv[0]) + " <input.osrm> [options]");
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);
const auto &temp_config_path = option_variables["config"].as<boost::filesystem::path>();
if (boost::filesystem::is_regular_file(temp_config_path))
RangebasedCRC32 crc32;
if (crc32.using_hardware())
{
boost::program_options::store(boost::program_options::parse_config_file<char>(
temp_config_path.string().c_str(), cmdline_options, true),
option_variables);
SimpleLogger().Write() << "using hardware based CRC32 computation";
}
else
{
SimpleLogger().Write() << "using software based CRC32 computation";
}
if (option_variables.count("version"))
{
SimpleLogger().Write() << g_GIT_DESCRIPTION;
return false;
}
const unsigned crc32_value = crc32(*node_based_edge_list);
SimpleLogger().Write() << "CRC32: " << crc32_value;
if (option_variables.count("help"))
{
SimpleLogger().Write() << "\n" << visible_options;
return false;
}
boost::program_options::notify(option_variables);
if (!option_variables.count("restrictions"))
{
restrictions_path = std::string(input_path.string() + ".restrictions");
}
if (!option_variables.count("input"))
{
SimpleLogger().Write() << "\n" << visible_options;
return false;
}
return true;
}
/**
\brief Loads and checks file UUIDs
*/
void Prepare::CheckRestrictionsFile(FingerPrint &fingerprint_orig)
{
boost::filesystem::ifstream restriction_stream(restrictions_path, std::ios::binary);
FingerPrint fingerprint_loaded;
unsigned number_of_usable_restrictions = 0;
restriction_stream.read((char *)&fingerprint_loaded, sizeof(FingerPrint));
if (!fingerprint_loaded.TestPrepare(fingerprint_orig))
{
SimpleLogger().Write(logWARNING) << ".restrictions was prepared with different build.\n"
"Reprocess to get rid of this warning.";
}
restriction_stream.read((char *)&number_of_usable_restrictions, sizeof(unsigned));
restriction_list.resize(number_of_usable_restrictions);
if (number_of_usable_restrictions > 0)
{
restriction_stream.read((char *)&(restriction_list[0]),
number_of_usable_restrictions * sizeof(TurnRestriction));
}
restriction_stream.close();
return crc32_value;
}
/**
\brief Setups scripting environment (lua-scripting)
Also initializes speed profile.
*/
bool Prepare::SetupScriptingEnvironment(
void Prepare::SetupScriptingEnvironment(
lua_State *lua_state, EdgeBasedGraphFactory::SpeedProfileProperties &speed_profile)
{
// open utility libraries string library;
luaL_openlibs(lua_state);
// adjust lua load path
luaAddScriptFolderToLoadPath(lua_state, profile_path.string().c_str());
luaAddScriptFolderToLoadPath(lua_state, config.profile_path.string().c_str());
// Now call our function in a lua script
if (0 != luaL_dofile(lua_state, profile_path.string().c_str()))
if (0 != luaL_dofile(lua_state, config.profile_path.string().c_str()))
{
std::cerr << lua_tostring(lua_state, -1) << " occured in scripting block" << std::endl;
return false;
std::stringstream msg;
msg << lua_tostring(lua_state, -1) << " occured in scripting block";
throw osrm::exception(msg.str());
}
if (0 != luaL_dostring(lua_state, "return traffic_signal_penalty\n"))
{
std::cerr << lua_tostring(lua_state, -1) << " occured in scripting block" << std::endl;
return false;
std::stringstream msg;
msg << lua_tostring(lua_state, -1) << " occured in scripting block";
throw osrm::exception(msg.str());
}
speed_profile.traffic_signal_penalty = 10 * lua_tointeger(lua_state, -1);
SimpleLogger().Write(logDEBUG)
@ -476,92 +291,140 @@ bool Prepare::SetupScriptingEnvironment(
if (0 != luaL_dostring(lua_state, "return u_turn_penalty\n"))
{
std::cerr << lua_tostring(lua_state, -1) << " occured in scripting block" << std::endl;
return false;
std::stringstream msg;
msg << lua_tostring(lua_state, -1) << " occured in scripting block";
throw osrm::exception(msg.str());
}
speed_profile.u_turn_penalty = 10 * lua_tointeger(lua_state, -1);
speed_profile.has_turn_penalty_function = lua_function_exists(lua_state, "turn_function");
return true;
}
/**
\brief Build load restrictions from .restriction file
*/
std::shared_ptr<RestrictionMap> Prepare::LoadRestrictionMap()
{
boost::filesystem::ifstream input_stream(config.restrictions_path, std::ios::in | std::ios::binary);
std::vector<TurnRestriction> restriction_list;
loadRestrictionsFromFile(input_stream, restriction_list);
SimpleLogger().Write() << " - " << restriction_list.size() << " restrictions.";
return std::make_shared<RestrictionMap>(restriction_list);
}
/**
\brief Load node based graph from .osrm file
*/
std::shared_ptr<NodeBasedDynamicGraph>
Prepare::LoadNodeBasedGraph(std::vector<NodeID> &barrier_node_list,
std::vector<NodeID> &traffic_light_list,
std::vector<QueryNode>& internal_to_external_node_map)
{
std::vector<NodeBasedEdge> edge_list;
boost::filesystem::ifstream input_stream(config.osrm_input_path, std::ios::in | std::ios::binary);
NodeID number_of_node_based_nodes = loadNodesFromFile(input_stream,
barrier_node_list, traffic_light_list,
internal_to_external_node_map);
SimpleLogger().Write() << " - " << barrier_node_list.size() << " bollard nodes, "
<< traffic_light_list.size() << " traffic lights";
loadEdgesFromFile(input_stream, edge_list);
if (edge_list.empty())
{
SimpleLogger().Write(logWARNING) << "The input data is empty, exiting.";
return std::shared_ptr<NodeBasedDynamicGraph>();
}
return NodeBasedDynamicGraphFromImportEdges(number_of_node_based_nodes, edge_list);
}
/**
\brief Building an edge-expanded graph from node-based input and turn restrictions
*/
std::size_t
Prepare::BuildEdgeExpandedGraph(lua_State *lua_state,
NodeID number_of_node_based_nodes,
std::pair<std::size_t, std::size_t>
Prepare::BuildEdgeExpandedGraph(std::vector<QueryNode> &internal_to_external_node_map,
std::vector<EdgeBasedNode> &node_based_edge_list,
DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
EdgeBasedGraphFactory::SpeedProfileProperties &speed_profile)
DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list)
{
SimpleLogger().Write() << "Generating edge-expanded graph representation";
std::shared_ptr<NodeBasedDynamicGraph> node_based_graph =
NodeBasedDynamicGraphFromImportEdges(number_of_node_based_nodes, edge_list);
std::unique_ptr<RestrictionMap> restriction_map =
osrm::make_unique<RestrictionMap>(restriction_list);
std::shared_ptr<EdgeBasedGraphFactory> edge_based_graph_factory =
std::make_shared<EdgeBasedGraphFactory>(node_based_graph, std::move(restriction_map),
barrier_node_list, traffic_light_list,
internal_to_external_node_map, speed_profile);
edge_list.clear();
edge_list.shrink_to_fit();
lua_State *lua_state = luaL_newstate();
luabind::open(lua_state);
edge_based_graph_factory->Run(edge_out, geometry_filename, lua_state);
EdgeBasedGraphFactory::SpeedProfileProperties speed_profile;
restriction_list.clear();
restriction_list.shrink_to_fit();
barrier_node_list.clear();
barrier_node_list.shrink_to_fit();
traffic_light_list.clear();
traffic_light_list.shrink_to_fit();
SetupScriptingEnvironment(lua_state, speed_profile);
auto barrier_node_list = osrm::make_unique<std::vector<NodeID>>();
auto traffic_light_list = osrm::make_unique<std::vector<NodeID>>();
auto restriction_map = LoadRestrictionMap();
auto node_based_graph = LoadNodeBasedGraph(*barrier_node_list, *traffic_light_list, internal_to_external_node_map);
const std::size_t number_of_node_based_nodes = node_based_graph->GetNumberOfNodes();
EdgeBasedGraphFactory edge_based_graph_factory(node_based_graph,
restriction_map,
std::move(barrier_node_list),
std::move(traffic_light_list),
internal_to_external_node_map,
speed_profile);
edge_based_graph_factory.Run(config.edge_output_path, config.geometry_output_path, lua_state);
lua_close(lua_state);
const std::size_t number_of_edge_based_nodes =
edge_based_graph_factory->GetNumberOfEdgeBasedNodes();
edge_based_graph_factory.GetNumberOfEdgeBasedNodes();
BOOST_ASSERT(number_of_edge_based_nodes != std::numeric_limits<unsigned>::max());
#ifndef WIN32
static_assert(sizeof(EdgeBasedEdge) == 16,
"changing ImportEdge type has influence on memory consumption!");
#endif
edge_based_graph_factory->GetEdgeBasedEdges(edge_based_edge_list);
edge_based_graph_factory->GetEdgeBasedNodes(node_based_edge_list);
edge_based_graph_factory.GetEdgeBasedEdges(edge_based_edge_list);
edge_based_graph_factory.GetEdgeBasedNodes(node_based_edge_list);
edge_based_graph_factory.reset();
node_based_graph.reset();
return std::make_pair(number_of_node_based_nodes, number_of_edge_based_nodes);
}
return number_of_edge_based_nodes;
/**
\brief Build contracted graph.
*/
void Prepare::ContractGraph(const std::size_t number_of_edge_based_nodes,
DeallocatingVector<EdgeBasedEdge>& edge_based_edge_list,
DeallocatingVector<QueryEdge>& contracted_edge_list)
{
Contractor contractor(number_of_edge_based_nodes, edge_based_edge_list);
contractor.Run();
contractor.GetEdges(contracted_edge_list);
}
/**
\brief Writing info on original (node-based) nodes
*/
void Prepare::WriteNodeMapping()
void Prepare::WriteNodeMapping(std::unique_ptr<std::vector<QueryNode>> internal_to_external_node_map)
{
SimpleLogger().Write() << "writing node map ...";
boost::filesystem::ofstream node_stream(node_filename, std::ios::binary);
const unsigned size_of_mapping = internal_to_external_node_map.size();
boost::filesystem::ofstream node_stream(config.node_output_path, std::ios::binary);
const unsigned size_of_mapping = internal_to_external_node_map->size();
node_stream.write((char *)&size_of_mapping, sizeof(unsigned));
if (size_of_mapping > 0)
{
node_stream.write((char *)&(internal_to_external_node_map[0]),
node_stream.write((char *) internal_to_external_node_map->data(),
size_of_mapping * sizeof(QueryNode));
}
node_stream.close();
internal_to_external_node_map.clear();
internal_to_external_node_map.shrink_to_fit();
}
/**
\brief Building rtree-based nearest-neighbor data structure
Saves info to files: '.ramIndex' and '.fileIndex'.
Saves tree into '.ramIndex' and leaves into '.fileIndex'.
*/
void Prepare::BuildRTree(std::vector<EdgeBasedNode> &node_based_edge_list)
void Prepare::BuildRTree(const std::vector<EdgeBasedNode> &node_based_edge_list, const std::vector<QueryNode>& internal_to_external_node_map)
{
SimpleLogger().Write() << "building r-tree ...";
StaticRTree<EdgeBasedNode>(node_based_edge_list, rtree_nodes_path.c_str(),
rtree_leafs_path.c_str(), internal_to_external_node_map);
StaticRTree<EdgeBasedNode>(node_based_edge_list, config.rtree_nodes_output_path.c_str(),
config.rtree_leafs_output_path.c_str(), internal_to_external_node_map);
}

View File

@ -28,11 +28,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef PROCESSING_CHAIN_HPP
#define PROCESSING_CHAIN_HPP
#include "contractor_options.hpp"
#include "edge_based_graph_factory.hpp"
#include "../data_structures/query_edge.hpp"
#include "../data_structures/static_graph.hpp"
class FingerPrint;
struct EdgeBasedNode;
struct lua_State;
@ -50,46 +50,36 @@ class Prepare
using InputEdge = DynamicGraph<EdgeData>::InputEdge;
using StaticEdge = StaticGraph<EdgeData>::InputEdge;
explicit Prepare();
explicit Prepare(const ContractorConfig& contractor_config)
: config(contractor_config) {}
Prepare(const Prepare &) = delete;
~Prepare();
int Process(int argc, char *argv[]);
int Run();
protected:
bool ParseArguments(int argc, char *argv[]);
void CheckRestrictionsFile(FingerPrint &fingerprint_orig);
bool SetupScriptingEnvironment(lua_State *myLuaState,
void SetupScriptingEnvironment(lua_State *myLuaState,
EdgeBasedGraphFactory::SpeedProfileProperties &speed_profile);
std::size_t BuildEdgeExpandedGraph(lua_State *myLuaState,
NodeID nodeBasedNodeNumber,
std::vector<EdgeBasedNode> &nodeBasedEdgeList,
DeallocatingVector<EdgeBasedEdge> &edgeBasedEdgeList,
EdgeBasedGraphFactory::SpeedProfileProperties &speed_profile);
void WriteNodeMapping();
void BuildRTree(std::vector<EdgeBasedNode> &node_based_edge_list);
std::shared_ptr<RestrictionMap> LoadRestrictionMap();
unsigned CalculateEdgeChecksum(std::unique_ptr<std::vector<EdgeBasedNode>> node_based_edge_list);
void ContractGraph(const std::size_t number_of_edge_based_nodes,
DeallocatingVector<EdgeBasedEdge>& edge_based_edge_list,
DeallocatingVector<QueryEdge>& contracted_edge_list);
std::size_t WriteContractedGraph(unsigned number_of_edge_based_nodes,
std::unique_ptr<std::vector<EdgeBasedNode>> node_based_edge_list,
std::unique_ptr<DeallocatingVector<QueryEdge>> contracted_edge_list);
std::shared_ptr<NodeBasedDynamicGraph> LoadNodeBasedGraph(std::vector<NodeID> &barrier_node_list,
std::vector<NodeID> &traffic_light_list,
std::vector<QueryNode>& internal_to_external_node_map);
std::pair<std::size_t, std::size_t>
BuildEdgeExpandedGraph(std::vector<QueryNode> &internal_to_external_node_map,
std::vector<EdgeBasedNode> &node_based_edge_list,
DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list);
void WriteNodeMapping(std::unique_ptr<std::vector<QueryNode>> internal_to_external_node_map);
void BuildRTree(const std::vector<EdgeBasedNode> &node_based_edge_list,
const std::vector<QueryNode> &internal_to_external_node_map);
private:
std::vector<QueryNode> internal_to_external_node_map;
std::vector<TurnRestriction> restriction_list;
std::vector<NodeID> barrier_node_list;
std::vector<NodeID> traffic_light_list;
std::vector<ImportEdge> edge_list;
unsigned requested_num_threads;
boost::filesystem::path config_file_path;
boost::filesystem::path input_path;
boost::filesystem::path restrictions_path;
boost::filesystem::path preinfo_path;
boost::filesystem::path profile_path;
std::string node_filename;
std::string edge_out;
std::string info_out;
std::string geometry_filename;
std::string graph_out;
std::string rtree_nodes_path;
std::string rtree_leafs_path;
ContractorConfig config;
};
#endif // PROCESSING_CHAIN_HPP

View File

@ -85,6 +85,9 @@ template <typename EdgeDataT> class DynamicGraph
edge_list.resize(number_of_nodes);
}
/**
* Constructs a DynamicGraph from a list of edges sorted by source node id.
*/
template <class ContainerT> DynamicGraph(const NodeIterator nodes, const ContainerT &graph)
{
number_of_nodes = nodes;

View File

@ -47,6 +47,13 @@ bool NodeBasedEdge::operator<(const NodeBasedEdge &other) const
return source < other.source;
}
NodeBasedEdge::NodeBasedEdge()
: source(SPECIAL_NODEID), target(SPECIAL_NODEID), name_id(0), weight(0), forward(false),
backward(false), roundabout(false), in_tiny_cc(false),
access_restricted(false), is_split(false), travel_mode(false)
{
}
NodeBasedEdge::NodeBasedEdge(NodeID source,
NodeID target,
NodeID name_id,

View File

@ -35,6 +35,7 @@ struct NodeBasedEdge
{
bool operator<(const NodeBasedEdge &e) const;
NodeBasedEdge();
explicit NodeBasedEdge(NodeID source,
NodeID target,
NodeID name_id,
@ -58,8 +59,6 @@ struct NodeBasedEdge
bool access_restricted : 1;
bool is_split : 1;
TravelMode travel_mode : 4;
NodeBasedEdge() = delete;
};
struct EdgeBasedEdge
@ -86,6 +85,4 @@ struct EdgeBasedEdge
bool backward : 1;
};
using ImportEdge = NodeBasedEdge;
#endif /* IMPORT_EDGE_HPP */

View File

@ -64,7 +64,7 @@ struct NodeBasedEdgeData
backward = temp_flag;
}
bool IsEqualTo(const NodeBasedEdgeData &other) const
bool IsCompatibleTo(const NodeBasedEdgeData &other) const
{
return (forward == other.forward) && (backward == other.backward) &&
(nameID == other.nameID) && (ignore_in_grid == other.ignore_in_grid) &&
@ -72,26 +72,123 @@ struct NodeBasedEdgeData
}
};
struct SimpleEdgeData
{
SimpleEdgeData() : capacity(0) {}
EdgeWeight capacity;
};
using NodeBasedDynamicGraph = DynamicGraph<NodeBasedEdgeData>;
using SimpleNodeBasedDynamicGraph = DynamicGraph<SimpleEdgeData>;
// Factory method to create NodeBasedDynamicGraph from ImportEdges
inline bool validateNeighborHood(const NodeBasedDynamicGraph& graph, const NodeID source)
{
for (auto edge = graph.BeginEdges(source); edge < graph.EndEdges(source); ++edge)
{
const auto& data = graph.GetEdgeData(edge);
if (!data.forward && !data.backward)
{
SimpleLogger().Write(logWARNING) << "Invalid edge directions";
return false;
}
auto target = graph.GetTarget(edge);
if (target == SPECIAL_NODEID)
{
SimpleLogger().Write(logWARNING) << "Invalid edge target";
return false;
}
bool found_reverse = false;
for (auto rev_edge = graph.BeginEdges(target); rev_edge < graph.EndEdges(target); ++rev_edge)
{
auto rev_target = graph.GetTarget(rev_edge);
if (rev_target == SPECIAL_NODEID)
{
SimpleLogger().Write(logWARNING) << "Invalid reverse edge target";
return false;
}
if (rev_target != source)
{
continue;
}
if (found_reverse)
{
SimpleLogger().Write(logWARNING) << "Found more than one reverse edge";
return false;
}
const auto& rev_data = graph.GetEdgeData(rev_edge);
// edge is incoming, this must be an outgoing edge
if (data.backward && !rev_data.forward)
{
SimpleLogger().Write(logWARNING) << "Found no outgoing edge to an incoming edge!";
return false;
}
// edge is bi-directional, reverse must be as well
if (data.forward && data.backward && (!rev_data.forward || !rev_data.backward))
{
SimpleLogger().Write(logWARNING) << "Found bi-directional edge that is not bi-directional to both ends";
return false;
}
found_reverse = true;
}
if (!found_reverse)
{
SimpleLogger().Write(logWARNING) << "Could not find reverse edge";
return false;
}
}
return true;
}
// This function checks if the overal graph is undirected (has an edge in each direction).
inline bool validateNodeBasedGraph(const NodeBasedDynamicGraph& graph)
{
for (auto source = 0u; source < graph.GetNumberOfNodes(); ++source)
{
if (!validateNeighborHood(graph, source))
{
return false;
}
}
return true;
}
// Factory method to create NodeBasedDynamicGraph from NodeBasedEdges
// The since DynamicGraph expects directed edges, we need to insert
// two edges for undirected edges.
inline std::shared_ptr<NodeBasedDynamicGraph>
NodeBasedDynamicGraphFromImportEdges(int number_of_nodes, std::vector<ImportEdge> &input_edge_list)
NodeBasedDynamicGraphFromImportEdges(int number_of_nodes, std::vector<NodeBasedEdge> &input_edge_list)
{
static_assert(sizeof(NodeBasedEdgeData) == 16,
"changing node based edge data size changes memory consumption");
DeallocatingVector<NodeBasedDynamicGraph::InputEdge> edges_list;
NodeBasedDynamicGraph::InputEdge edge;
for (const ImportEdge &import_edge : input_edge_list)
// Since DynamicGraph assumes directed edges we have to make sure we transformed
// the compressed edge format into single directed edges. We do this to make sure
// every node also knows its incoming edges, not only its outgoing edges and use the backward=true
// flag to indicate which is which.
//
// We do the transformation in the following way:
//
// if the edge (a, b) is split:
// 1. this edge must be in only one direction, so its a --> b
// 2. there must be another directed edge b --> a somewhere in the data
// if the edge (a, b) is not split:
// 1. this edge be on of a --> b od a <-> b
// (a <-- b gets reducted to b --> a)
// 2. a --> b will be transformed to a --> b and b <-- a
// 3. a <-> b will be transformed to a <-> b and b <-> a (I think a --> b and b <-- a would work as well though)
for (const NodeBasedEdge &import_edge : input_edge_list)
{
// edges that are not forward get converted by flipping the end points
BOOST_ASSERT(import_edge.forward);
if (import_edge.forward)
{
edge.source = import_edge.source;
@ -99,20 +196,10 @@ NodeBasedDynamicGraphFromImportEdges(int number_of_nodes, std::vector<ImportEdge
edge.data.forward = import_edge.forward;
edge.data.backward = import_edge.backward;
}
else
{
edge.source = import_edge.target;
edge.target = import_edge.source;
edge.data.backward = import_edge.forward;
edge.data.forward = import_edge.backward;
}
if (edge.source == edge.target)
{
continue;
}
BOOST_ASSERT(edge.source != edge.target);
edge.data.distance = (std::max)(static_cast<int>(import_edge.weight), 1);
edge.data.distance = static_cast<int>(import_edge.weight);
BOOST_ASSERT(edge.data.distance > 0);
edge.data.shortcut = false;
edge.data.roundabout = import_edge.roundabout;
@ -132,147 +219,16 @@ NodeBasedDynamicGraphFromImportEdges(int number_of_nodes, std::vector<ImportEdge
}
}
// remove duplicate edges
tbb::parallel_sort(edges_list.begin(), edges_list.end());
NodeID edge_count = 0;
for (NodeID i = 0; i < edges_list.size();)
{
const NodeID source = edges_list[i].source;
const NodeID target = edges_list[i].target;
// remove eigenloops
if (source == target)
{
i++;
continue;
}
NodeBasedDynamicGraph::InputEdge forward_edge;
NodeBasedDynamicGraph::InputEdge reverse_edge;
forward_edge = reverse_edge = edges_list[i];
forward_edge.data.forward = reverse_edge.data.backward = true;
forward_edge.data.backward = reverse_edge.data.forward = false;
forward_edge.data.shortcut = reverse_edge.data.shortcut = false;
forward_edge.data.distance = reverse_edge.data.distance = std::numeric_limits<int>::max();
// remove parallel edges
while (i < edges_list.size() && edges_list[i].source == source &&
edges_list[i].target == target)
{
if (edges_list[i].data.forward)
{
forward_edge.data.distance =
std::min(edges_list[i].data.distance, forward_edge.data.distance);
}
if (edges_list[i].data.backward)
{
reverse_edge.data.distance =
std::min(edges_list[i].data.distance, reverse_edge.data.distance);
}
++i;
}
// merge edges (s,t) and (t,s) into bidirectional edge
if (forward_edge.data.distance == reverse_edge.data.distance)
{
if (static_cast<int>(forward_edge.data.distance) != std::numeric_limits<int>::max())
{
forward_edge.data.backward = true;
edges_list[edge_count++] = forward_edge;
}
}
else
{ // insert seperate edges
if (static_cast<int>(forward_edge.data.distance) != std::numeric_limits<int>::max())
{
edges_list[edge_count++] = forward_edge;
}
if (static_cast<int>(reverse_edge.data.distance) != std::numeric_limits<int>::max())
{
edges_list[edge_count++] = reverse_edge;
}
}
}
edges_list.resize(edge_count);
SimpleLogger().Write() << "merged " << edges_list.size() - edge_count << " edges out of "
<< edges_list.size();
auto graph = std::make_shared<NodeBasedDynamicGraph>(
static_cast<NodeBasedDynamicGraph::NodeIterator>(number_of_nodes), edges_list);
return graph;
}
template <class SimpleEdgeT>
inline std::shared_ptr<SimpleNodeBasedDynamicGraph>
SimpleNodeBasedDynamicGraphFromEdges(int number_of_nodes, std::vector<SimpleEdgeT> &input_edge_list)
{
static_assert(sizeof(NodeBasedEdgeData) == 16,
"changing node based edge data size changes memory consumption");
tbb::parallel_sort(input_edge_list.begin(), input_edge_list.end());
DeallocatingVector<SimpleNodeBasedDynamicGraph::InputEdge> edges_list;
SimpleNodeBasedDynamicGraph::InputEdge edge;
edge.data.capacity = 1;
for (const SimpleEdgeT &import_edge : input_edge_list)
{
if (import_edge.source == import_edge.target)
{
continue;
}
edge.source = import_edge.source;
edge.target = import_edge.target;
edges_list.push_back(edge);
std::swap(edge.source, edge.target);
edges_list.push_back(edge);
}
#ifndef NDEBUG
BOOST_ASSERT(validateNodeBasedGraph(*graph));
#endif
// remove duplicate edges
tbb::parallel_sort(edges_list.begin(), edges_list.end());
NodeID edge_count = 0;
for (NodeID i = 0; i < edges_list.size();)
{
const NodeID source = edges_list[i].source;
const NodeID target = edges_list[i].target;
// remove eigenloops
if (source == target)
{
i++;
continue;
}
SimpleNodeBasedDynamicGraph::InputEdge forward_edge;
SimpleNodeBasedDynamicGraph::InputEdge reverse_edge;
forward_edge = reverse_edge = edges_list[i];
forward_edge.data.capacity = reverse_edge.data.capacity = INVALID_EDGE_WEIGHT;
// remove parallel edges
while (i < edges_list.size() && edges_list[i].source == source &&
edges_list[i].target == target)
{
forward_edge.data.capacity =
std::min(edges_list[i].data.capacity, forward_edge.data.capacity);
reverse_edge.data.capacity =
std::min(edges_list[i].data.capacity, reverse_edge.data.capacity);
++i;
}
// merge edges (s,t) and (t,s) into bidirectional edge
if (forward_edge.data.capacity == reverse_edge.data.capacity)
{
if (static_cast<int>(forward_edge.data.capacity) != INVALID_EDGE_WEIGHT)
{
edges_list[edge_count++] = forward_edge;
}
}
else
{ // insert seperate edges
if (static_cast<int>(forward_edge.data.capacity) != INVALID_EDGE_WEIGHT)
{
edges_list[edge_count++] = forward_edge;
}
if (static_cast<int>(reverse_edge.data.capacity) != INVALID_EDGE_WEIGHT)
{
edges_list[edge_count++] = reverse_edge;
}
}
}
SimpleLogger().Write() << "merged " << edges_list.size() - edge_count << " edges out of "
<< edges_list.size();
auto graph = std::make_shared<SimpleNodeBasedDynamicGraph>(number_of_nodes, edges_list);
return graph;
}

View File

@ -91,6 +91,7 @@ template <> struct hash<RestrictionTarget>
class RestrictionMap
{
public:
RestrictionMap() : m_count(0) {};
RestrictionMap(const std::vector<TurnRestriction> &restriction_list);
// Replace end v with w in each turn restriction containing u as via node
@ -98,7 +99,7 @@ class RestrictionMap
void FixupArrivingTurnRestriction(const NodeID node_u,
const NodeID node_v,
const NodeID node_w,
const std::shared_ptr<GraphT> &graph)
const GraphT &graph)
{
BOOST_ASSERT(node_u != SPECIAL_NODEID);
BOOST_ASSERT(node_v != SPECIAL_NODEID);
@ -112,9 +113,9 @@ class RestrictionMap
// find all potential start edges. It is more efficent to get a (small) list
// of potential start edges than iterating over all buckets
std::vector<NodeID> predecessors;
for (const EdgeID current_edge_id : graph->GetAdjacentEdgeRange(node_u))
for (const EdgeID current_edge_id : graph.GetAdjacentEdgeRange(node_u))
{
const NodeID target = graph->GetTarget(current_edge_id);
const NodeID target = graph.GetTarget(current_edge_id);
if (node_v != target)
{
predecessors.push_back(target);

View File

@ -31,6 +31,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <osrm/route_parameters.hpp>
#include "../algorithms/polyline_compressor.hpp"
RouteParameters::RouteParameters()
: zoom_level(18), print_instructions(false), alternate_route(true), geometry(true),
compression(true), deprecatedAPI(false), uturn_default(false), classify(false),
@ -131,3 +133,9 @@ void RouteParameters::addCoordinate(
static_cast<int>(COORDINATE_PRECISION * boost::fusion::at_c<0>(received_coordinates)),
static_cast<int>(COORDINATE_PRECISION * boost::fusion::at_c<1>(received_coordinates)));
}
void RouteParameters::getCoordinatesFromGeometry(const std::string geometry_string)
{
PolylineCompressor pc;
coordinates = pc.decode_string(geometry_string);
}

View File

@ -344,7 +344,7 @@ class StaticRTree
StaticRTree(const StaticRTree &) = delete;
// Construct a packed Hilbert-R-Tree with Kamel-Faloutsos algorithm [1]
explicit StaticRTree(std::vector<EdgeDataT> &input_data_vector,
explicit StaticRTree(const std::vector<EdgeDataT> &input_data_vector,
const std::string tree_node_filename,
const std::string leaf_node_filename,
const std::vector<QueryNode> &coordinate_list)
@ -646,22 +646,16 @@ class StaticRTree
const FixedPointCoordinate &input_coordinate,
std::vector<PhantomNode> &result_phantom_node_vector,
const unsigned max_number_of_phantom_nodes,
const unsigned max_checked_elements = 4 * LEAF_NODE_SIZE)
const float max_distance = 1100)
{
unsigned inspected_elements = 0;
unsigned number_of_elements_from_big_cc = 0;
unsigned number_of_elements_from_tiny_cc = 0;
#ifdef NDEBUG
unsigned pruned_elements = 0;
#endif
std::pair<double, double> projected_coordinate = {
mercator::lat2y(input_coordinate.lat / COORDINATE_PRECISION),
input_coordinate.lon / COORDINATE_PRECISION};
// upper bound pruning technique
upper_bound<float> pruning_bound(max_number_of_phantom_nodes);
// initialize queue with root element
std::priority_queue<IncrementalQueryCandidate> traversal_queue;
traversal_queue.emplace(0.f, m_search_tree[0]);
@ -669,6 +663,10 @@ class StaticRTree
while (!traversal_queue.empty())
{
const IncrementalQueryCandidate current_query_node = traversal_queue.top();
if (current_query_node.min_dist > max_distance)
{
break;
}
traversal_queue.pop();
if (current_query_node.node.template is<TreeNode>())
@ -692,19 +690,8 @@ class StaticRTree
// distance must be non-negative
BOOST_ASSERT(0.f <= current_perpendicular_distance);
if (pruning_bound.get() >= current_perpendicular_distance ||
current_edge.is_in_tiny_cc())
{
pruning_bound.insert(current_perpendicular_distance);
traversal_queue.emplace(current_perpendicular_distance, current_edge);
}
#ifdef NDEBUG
else
{
++pruned_elements;
}
#endif
}
}
else
{
@ -771,9 +758,8 @@ class StaticRTree
}
// stop the search by flushing the queue
if ((result_phantom_node_vector.size() >= max_number_of_phantom_nodes &&
number_of_elements_from_big_cc > 0) ||
inspected_elements >= max_checked_elements)
if (result_phantom_node_vector.size() >= max_number_of_phantom_nodes &&
number_of_elements_from_big_cc > 0)
{
traversal_queue = std::priority_queue<IncrementalQueryCandidate>{};
}
@ -809,6 +795,10 @@ class StaticRTree
unsigned number_of_elements_from_big_cc = 0;
unsigned number_of_elements_from_tiny_cc = 0;
// is true if a big cc was added to the queue to we also have a lower bound
// for them. it actives pruning for big components
bool has_big_cc = false;
unsigned pruned_elements = 0;
std::pair<double, double> projected_coordinate = {
@ -849,10 +839,11 @@ class StaticRTree
BOOST_ASSERT(0.f <= current_perpendicular_distance);
if (pruning_bound.get() >= current_perpendicular_distance ||
current_edge.is_in_tiny_cc())
(!has_big_cc && !current_edge.is_in_tiny_cc()))
{
pruning_bound.insert(current_perpendicular_distance);
traversal_queue.emplace(current_perpendicular_distance, current_edge);
has_big_cc = has_big_cc || !current_edge.is_in_tiny_cc();
}
else
{

View File

@ -264,9 +264,10 @@ int main(const int argc, const char *argv[])
boost::filesystem::ifstream hsgr_input_stream(hsgr_path, std::ios::binary);
FingerPrint fingerprint_loaded, fingerprint_orig;
FingerPrint fingerprint_valid = FingerPrint::GetValid();
FingerPrint fingerprint_loaded;
hsgr_input_stream.read((char *)&fingerprint_loaded, sizeof(FingerPrint));
if (fingerprint_loaded.TestGraphUtil(fingerprint_orig))
if (fingerprint_loaded.TestGraphUtil(fingerprint_valid))
{
SimpleLogger().Write(logDEBUG) << "Fingerprint checked out ok";
}

View File

@ -173,6 +173,7 @@ void DescriptionFactory::Run(const unsigned zoom_level)
// }
// string0 = string1;
// }
//
float segment_length = 0.;
EdgeWeight segment_duration = 0;
@ -197,7 +198,8 @@ void DescriptionFactory::Run(const unsigned zoom_level)
// Post-processing to remove empty or nearly empty path segments
if (path_description.size() > 2 &&
std::numeric_limits<float>::epsilon() > path_description.back().length)
std::numeric_limits<float>::epsilon() > path_description.back().length &&
!(path_description.end() - 2)->is_via_location)
{
path_description.pop_back();
path_description.back().necessary = true;
@ -206,7 +208,8 @@ void DescriptionFactory::Run(const unsigned zoom_level)
}
if (path_description.size() > 2 &&
std::numeric_limits<float>::epsilon() > path_description.front().length)
std::numeric_limits<float>::epsilon() > path_description.front().length &&
!(path_description.begin() + 1)->is_via_location)
{
path_description.erase(path_description.begin());
path_description.front().turn_instruction = TurnInstruction::HeadOn;

View File

@ -73,7 +73,7 @@ int main(int argc, char *argv[])
<< " not found!";
return 1;
}
return extractor().run(extractor_config);
return extractor(extractor_config).run();
}
catch (const std::exception &e)
{

View File

@ -35,6 +35,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "../util/osrm_exception.hpp"
#include "../util/simple_logger.hpp"
#include "../util/timing_util.hpp"
#include "../util/fingerprint.hpp"
#include <boost/assert.hpp>
#include <boost/filesystem.hpp>
@ -54,6 +55,7 @@ ExtractionContainers::ExtractionContainers()
ExtractionContainers::~ExtractionContainers()
{
// FIXME isn't this done implicitly of the stxxl::vectors go out of scope?
used_node_id_list.clear();
all_nodes_list.clear();
all_edges_list.clear();
@ -71,16 +73,72 @@ ExtractionContainers::~ExtractionContainers()
* - filter nodes list to nodes that are referenced by ways
* - merge edges with nodes to include location of start/end points and serialize
*
* FIXME: Each of this step should be an own function for readability.
*/
void ExtractionContainers::PrepareData(const std::string &output_file_name,
const std::string &restrictions_file_name)
const std::string &restrictions_file_name,
const std::string &name_file_name)
{
try
{
unsigned number_of_used_nodes = 0;
unsigned number_of_used_edges = 0;
std::ofstream file_out_stream;
file_out_stream.open(output_file_name.c_str(), std::ios::binary);
const FingerPrint fingerprint = FingerPrint::GetValid();
file_out_stream.write((char *)&fingerprint, sizeof(FingerPrint));
PrepareNodes();
WriteNodes(file_out_stream);
PrepareEdges();
WriteEdges(file_out_stream);
file_out_stream.close();
PrepareRestrictions();
WriteRestrictions(restrictions_file_name);
WriteNames(name_file_name);
}
catch (const std::exception &e)
{
std::cerr << "Caught Execption:" << e.what() << std::endl;
}
}
void ExtractionContainers::WriteNames(const std::string& names_file_name) const
{
std::cout << "[extractor] writing street name index ... " << std::flush;
TIMER_START(write_name_index);
boost::filesystem::ofstream name_file_stream(names_file_name, std::ios::binary);
unsigned total_length = 0;
std::vector<unsigned> name_lengths;
for (const std::string &temp_string : name_list)
{
const unsigned string_length =
std::min(static_cast<unsigned>(temp_string.length()), 255u);
name_lengths.push_back(string_length);
total_length += string_length;
}
// builds and writes the index
RangeTable<> name_index_range(name_lengths);
name_file_stream << name_index_range;
name_file_stream.write((char *)&total_length, sizeof(unsigned));
// write all chars consecutively
for (const std::string &temp_string : name_list)
{
const unsigned string_length =
std::min(static_cast<unsigned>(temp_string.length()), 255u);
name_file_stream.write(temp_string.c_str(), string_length);
}
name_file_stream.close();
TIMER_STOP(write_name_index);
std::cout << "ok, after " << TIMER_SEC(write_name_index) << "s" << std::endl;
}
void ExtractionContainers::PrepareNodes()
{
std::cout << "[extractor] Sorting used nodes ... " << std::flush;
TIMER_START(sorting_used_nodes);
stxxl::sort(used_node_id_list.begin(), used_node_id_list.end(), Cmp(), stxxl_memory);
@ -94,138 +152,282 @@ void ExtractionContainers::PrepareData(const std::string &output_file_name,
TIMER_STOP(erasing_dups);
std::cout << "ok, after " << TIMER_SEC(erasing_dups) << "s" << std::endl;
std::cout << "[extractor] Building node id map ... " << std::flush;
TIMER_START(id_map);
external_to_internal_node_id_map.reserve(used_node_id_list.size());
for (NodeID i = 0u; i < used_node_id_list.size(); ++i)
external_to_internal_node_id_map[used_node_id_list[i]] = i;
TIMER_STOP(id_map);
std::cout << "ok, after " << TIMER_SEC(id_map) << "s" << std::endl;
std::cout << "[extractor] Sorting all nodes ... " << std::flush;
TIMER_START(sorting_nodes);
stxxl::sort(all_nodes_list.begin(), all_nodes_list.end(), ExternalMemoryNodeSTXXLCompare(),
stxxl_memory);
TIMER_STOP(sorting_nodes);
std::cout << "ok, after " << TIMER_SEC(sorting_nodes) << "s" << std::endl;
}
std::cout << "[extractor] Sorting used ways ... " << std::flush;
TIMER_START(sort_ways);
stxxl::sort(way_start_end_id_list.begin(), way_start_end_id_list.end(),
FirstAndLastSegmentOfWayStxxlCompare(), stxxl_memory);
TIMER_STOP(sort_ways);
std::cout << "ok, after " << TIMER_SEC(sort_ways) << "s" << std::endl;
std::cout << "[extractor] Sorting " << restrictions_list.size()
<< " restrictions. by from... " << std::flush;
TIMER_START(sort_restrictions);
stxxl::sort(restrictions_list.begin(), restrictions_list.end(),
CmpRestrictionContainerByFrom(), stxxl_memory);
TIMER_STOP(sort_restrictions);
std::cout << "ok, after " << TIMER_SEC(sort_restrictions) << "s" << std::endl;
std::cout << "[extractor] Fixing restriction starts ... " << std::flush;
TIMER_START(fix_restriction_starts);
auto restrictions_iterator = restrictions_list.begin();
auto way_start_and_end_iterator = way_start_end_id_list.cbegin();
while (way_start_and_end_iterator != way_start_end_id_list.cend() &&
restrictions_iterator != restrictions_list.end())
void ExtractionContainers::PrepareEdges()
{
if (way_start_and_end_iterator->way_id < restrictions_iterator->restriction.from.way)
// Sort edges by start.
std::cout << "[extractor] Sorting edges by start ... " << std::flush;
TIMER_START(sort_edges_by_start);
stxxl::sort(all_edges_list.begin(), all_edges_list.end(), CmpEdgeByStartID(), stxxl_memory);
TIMER_STOP(sort_edges_by_start);
std::cout << "ok, after " << TIMER_SEC(sort_edges_by_start) << "s" << std::endl;
std::cout << "[extractor] Setting start coords ... " << std::flush;
TIMER_START(set_start_coords);
// Traverse list of edges and nodes in parallel and set start coord
auto node_iterator = all_nodes_list.begin();
auto edge_iterator = all_edges_list.begin();
while (edge_iterator != all_edges_list.end() && node_iterator != all_nodes_list.end())
{
++way_start_and_end_iterator;
if (edge_iterator->result.source < node_iterator->node_id)
{
edge_iterator->result.source = SPECIAL_NODEID;
++edge_iterator;
continue;
}
if (edge_iterator->result.source > node_iterator->node_id)
{
node_iterator++;
continue;
}
if (way_start_and_end_iterator->way_id > restrictions_iterator->restriction.from.way)
// remove loops
if (edge_iterator->result.source == edge_iterator->result.target)
{
++restrictions_iterator;
edge_iterator->result.source = SPECIAL_NODEID;
edge_iterator->result.target = SPECIAL_NODEID;
++edge_iterator;
continue;
}
BOOST_ASSERT(way_start_and_end_iterator->way_id ==
restrictions_iterator->restriction.from.way);
const NodeID via_node_id = restrictions_iterator->restriction.via.node;
BOOST_ASSERT(edge_iterator->result.source == node_iterator->node_id);
if (way_start_and_end_iterator->first_segment_source_id == via_node_id)
{
restrictions_iterator->restriction.from.node =
way_start_and_end_iterator->first_segment_target_id;
}
else if (way_start_and_end_iterator->last_segment_target_id == via_node_id)
{
restrictions_iterator->restriction.from.node =
way_start_and_end_iterator->last_segment_source_id;
}
++restrictions_iterator;
// assign new node id
auto id_iter = external_to_internal_node_id_map.find(node_iterator->node_id);
BOOST_ASSERT(id_iter != external_to_internal_node_id_map.end());
edge_iterator->result.source = id_iter->second;
edge_iterator->source_coordinate.lat = node_iterator->lat;
edge_iterator->source_coordinate.lon = node_iterator->lon;
++edge_iterator;
}
TIMER_STOP(set_start_coords);
std::cout << "ok, after " << TIMER_SEC(set_start_coords) << "s" << std::endl;
TIMER_STOP(fix_restriction_starts);
std::cout << "ok, after " << TIMER_SEC(fix_restriction_starts) << "s" << std::endl;
// Sort Edges by target
std::cout << "[extractor] Sorting edges by target ... " << std::flush;
TIMER_START(sort_edges_by_target);
stxxl::sort(all_edges_list.begin(), all_edges_list.end(), CmpEdgeByTargetID(),
stxxl_memory);
TIMER_STOP(sort_edges_by_target);
std::cout << "ok, after " << TIMER_SEC(sort_edges_by_target) << "s" << std::endl;
std::cout << "[extractor] Sorting restrictions. by to ... " << std::flush;
TIMER_START(sort_restrictions_to);
stxxl::sort(restrictions_list.begin(), restrictions_list.end(),
CmpRestrictionContainerByTo(), stxxl_memory);
TIMER_STOP(sort_restrictions_to);
std::cout << "ok, after " << TIMER_SEC(sort_restrictions_to) << "s" << std::endl;
std::cout << "[extractor] Fixing restriction ends ... " << std::flush;
TIMER_START(fix_restriction_ends);
restrictions_iterator = restrictions_list.begin();
way_start_and_end_iterator = way_start_end_id_list.cbegin();
while (way_start_and_end_iterator != way_start_end_id_list.cend() &&
restrictions_iterator != restrictions_list.end())
// Compute edge weights
std::cout << "[extractor] Computing edge weights ... " << std::flush;
TIMER_START(compute_weights);
node_iterator = all_nodes_list.begin();
edge_iterator = all_edges_list.begin();
while (edge_iterator != all_edges_list.end() && node_iterator != all_nodes_list.end())
{
if (way_start_and_end_iterator->way_id < restrictions_iterator->restriction.to.way)
// skip all invalid edges
if (edge_iterator->result.source == SPECIAL_NODEID)
{
++way_start_and_end_iterator;
++edge_iterator;
continue;
}
if (way_start_and_end_iterator->way_id > restrictions_iterator->restriction.to.way)
if (edge_iterator->result.target < node_iterator->node_id)
{
++restrictions_iterator;
edge_iterator->result.target = SPECIAL_NODEID;
++edge_iterator;
continue;
}
BOOST_ASSERT(way_start_and_end_iterator->way_id ==
restrictions_iterator->restriction.to.way);
const NodeID via_node_id = restrictions_iterator->restriction.via.node;
if (way_start_and_end_iterator->first_segment_source_id == via_node_id)
if (edge_iterator->result.target > node_iterator->node_id)
{
restrictions_iterator->restriction.to.node =
way_start_and_end_iterator->first_segment_target_id;
++node_iterator;
continue;
}
else if (way_start_and_end_iterator->last_segment_target_id == via_node_id)
BOOST_ASSERT(edge_iterator->result.target == node_iterator->node_id);
BOOST_ASSERT(edge_iterator->weight_data.speed >= 0);
BOOST_ASSERT(edge_iterator->source_coordinate.lat != std::numeric_limits<int>::min());
BOOST_ASSERT(edge_iterator->source_coordinate.lon != std::numeric_limits<int>::min());
const double distance = coordinate_calculation::euclidean_distance(
edge_iterator->source_coordinate.lat, edge_iterator->source_coordinate.lon,
node_iterator->lat, node_iterator->lon);
const double weight = [distance](const InternalExtractorEdge::WeightData& data) {
switch (data.type)
{
restrictions_iterator->restriction.to.node =
way_start_and_end_iterator->last_segment_source_id;
case InternalExtractorEdge::WeightType::EDGE_DURATION:
case InternalExtractorEdge::WeightType::WAY_DURATION:
return data.duration * 10.;
break;
case InternalExtractorEdge::WeightType::SPEED:
return (distance * 10.) / (data.speed / 3.6);
break;
case InternalExtractorEdge::WeightType::INVALID:
osrm::exception("invalid weight type");
}
++restrictions_iterator;
}
TIMER_STOP(fix_restriction_ends);
std::cout << "ok, after " << TIMER_SEC(fix_restriction_ends) << "s" << std::endl;
return -1.0;
}(edge_iterator->weight_data);
// serialize restrictions
std::ofstream restrictions_out_stream;
unsigned written_restriction_count = 0;
restrictions_out_stream.open(restrictions_file_name.c_str(), std::ios::binary);
restrictions_out_stream.write((char *)&fingerprint, sizeof(FingerPrint));
const auto count_position = restrictions_out_stream.tellp();
restrictions_out_stream.write((char *)&written_restriction_count, sizeof(unsigned));
auto& edge = edge_iterator->result;
edge.weight = std::max(1, static_cast<int>(std::floor(weight + .5)));
for (const auto &restriction_container : restrictions_list)
// assign new node id
auto id_iter = external_to_internal_node_id_map.find(node_iterator->node_id);
BOOST_ASSERT(id_iter != external_to_internal_node_id_map.end());
edge.target = id_iter->second;
// orient edges consistently: source id < target id
// important for multi-edge removal
if (edge.source > edge.target)
{
if (SPECIAL_NODEID != restriction_container.restriction.from.node &&
SPECIAL_NODEID != restriction_container.restriction.to.node)
std::swap(edge.source, edge.target);
// std::swap does not work with bit-fields
bool temp = edge.forward;
edge.forward = edge.backward;
edge.backward = temp;
}
++edge_iterator;
}
TIMER_STOP(compute_weights);
std::cout << "ok, after " << TIMER_SEC(compute_weights) << "s" << std::endl;
// Sort edges by start.
std::cout << "[extractor] Sorting edges by renumbered start ... " << std::flush;
TIMER_START(sort_edges_by_renumbered_start);
stxxl::sort(all_edges_list.begin(), all_edges_list.end(), CmpEdgeByStartThenTargetID(), stxxl_memory);
TIMER_STOP(sort_edges_by_renumbered_start);
std::cout << "ok, after " << TIMER_SEC(sort_edges_by_renumbered_start) << "s" << std::endl;
BOOST_ASSERT(all_edges_list.size() > 0);
for (unsigned i = 0; i < all_edges_list.size();)
{
restrictions_out_stream.write((char *)&(restriction_container.restriction),
sizeof(TurnRestriction));
++written_restriction_count;
// only invalid edges left
if (all_edges_list[i].result.source == SPECIAL_NODEID)
{
break;
}
// skip invalid edges
if (all_edges_list[i].result.target == SPECIAL_NODEID)
{
continue;
}
unsigned start_idx = i;
NodeID source = all_edges_list[i].result.source;
NodeID target = all_edges_list[i].result.target;
int min_forward_weight = std::numeric_limits<int>::max();
int min_backward_weight = std::numeric_limits<int>::max();
unsigned min_forward_idx = std::numeric_limits<unsigned>::max();
unsigned min_backward_idx = std::numeric_limits<unsigned>::max();
// find minimal edge in both directions
while (all_edges_list[i].result.source == source &&
all_edges_list[i].result.target == target)
{
if (all_edges_list[i].result.forward && all_edges_list[i].result.weight < min_forward_weight)
{
min_forward_idx = i;
}
if (all_edges_list[i].result.backward && all_edges_list[i].result.weight < min_backward_weight)
{
min_backward_idx = i;
}
// this also increments the outer loop counter!
i++;
}
BOOST_ASSERT(min_forward_idx == std::numeric_limits<unsigned>::max() || min_forward_idx < i);
BOOST_ASSERT(min_backward_idx == std::numeric_limits<unsigned>::max() || min_backward_idx < i);
BOOST_ASSERT(min_backward_idx != std::numeric_limits<unsigned>::max() ||
min_forward_idx != std::numeric_limits<unsigned>::max());
if (min_backward_idx == min_forward_idx)
{
all_edges_list[min_forward_idx].result.is_split = false;
all_edges_list[min_forward_idx].result.forward = true;
all_edges_list[min_forward_idx].result.backward = true;
}
else
{
bool has_forward = min_forward_idx != std::numeric_limits<unsigned>::max();
bool has_backward = min_backward_idx != std::numeric_limits<unsigned>::max();
if (has_forward)
{
all_edges_list[min_forward_idx].result.forward = true;
all_edges_list[min_forward_idx].result.backward = false;
all_edges_list[min_forward_idx].result.is_split = has_backward;
}
if (has_backward)
{
std::swap(all_edges_list[min_backward_idx].result.source,
all_edges_list[min_backward_idx].result.target);
all_edges_list[min_backward_idx].result.forward = true;
all_edges_list[min_backward_idx].result.backward = false;
all_edges_list[min_backward_idx].result.is_split = has_forward;
}
}
restrictions_out_stream.seekp(count_position);
restrictions_out_stream.write((char *)&written_restriction_count, sizeof(unsigned));
restrictions_out_stream.close();
SimpleLogger().Write() << "usable restrictions: " << written_restriction_count;
// invalidate all unused edges
for (unsigned j = start_idx; j < i; j++)
{
if (j == min_forward_idx || j == min_backward_idx)
{
continue;
}
all_edges_list[j].result.source = SPECIAL_NODEID;
all_edges_list[j].result.target = SPECIAL_NODEID;
}
}
}
std::ofstream file_out_stream;
file_out_stream.open(output_file_name.c_str(), std::ios::binary);
file_out_stream.write((char *)&fingerprint, sizeof(FingerPrint));
void ExtractionContainers::WriteEdges(std::ofstream& file_out_stream) const
{
std::cout << "[extractor] Writing used egdes ... " << std::flush;
TIMER_START(write_edges);
// Traverse list of edges and nodes in parallel and set target coord
unsigned number_of_used_edges = 0;
auto start_position = file_out_stream.tellp();
file_out_stream.write((char *)&number_of_used_edges, sizeof(unsigned));
for (const auto& edge : all_edges_list)
{
if (edge.result.source == SPECIAL_NODEID || edge.result.target == SPECIAL_NODEID)
{
continue;
}
file_out_stream.write((char*) &edge.result, sizeof(NodeBasedEdge));
number_of_used_edges++;
}
TIMER_STOP(write_edges);
std::cout << "ok, after " << TIMER_SEC(write_edges) << "s" << std::endl;
std::cout << "[extractor] setting number of edges ... " << std::flush;
file_out_stream.seekp(start_position);
file_out_stream.write((char *)&number_of_used_edges, sizeof(unsigned));
std::cout << "ok" << std::endl;
SimpleLogger().Write() << "Processed " << number_of_used_edges << " edges";
}
void ExtractionContainers::WriteNodes(std::ofstream& file_out_stream) const
{
unsigned number_of_used_nodes = 0;
// write dummy value, will be overwritten later
file_out_stream.write((char *)&number_of_used_nodes, sizeof(unsigned));
std::cout << "[extractor] Confirming/Writing used nodes ... " << std::flush;
TIMER_START(write_nodes);
@ -252,7 +454,6 @@ void ExtractionContainers::PrepareData(const std::string &output_file_name,
++node_id_iterator;
++node_iterator;
}
TIMER_STOP(write_nodes);
std::cout << "ok, after " << TIMER_SEC(write_nodes) << "s" << std::endl;
@ -261,204 +462,172 @@ void ExtractionContainers::PrepareData(const std::string &output_file_name,
file_out_stream.seekp(std::ios::beg + sizeof(FingerPrint));
file_out_stream.write((char *)&number_of_used_nodes, sizeof(unsigned));
file_out_stream.seekp(previous_file_position);
std::cout << "ok" << std::endl;
// Sort edges by start.
std::cout << "[extractor] Sorting edges by start ... " << std::flush;
TIMER_START(sort_edges_by_start);
stxxl::sort(all_edges_list.begin(), all_edges_list.end(), CmpEdgeByStartID(), stxxl_memory);
TIMER_STOP(sort_edges_by_start);
std::cout << "ok, after " << TIMER_SEC(sort_edges_by_start) << "s" << std::endl;
std::cout << "[extractor] Setting start coords ... " << std::flush;
TIMER_START(set_start_coords);
file_out_stream.write((char *)&number_of_used_edges, sizeof(unsigned));
// Traverse list of edges and nodes in parallel and set start coord
node_iterator = all_nodes_list.begin();
auto edge_iterator = all_edges_list.begin();
while (edge_iterator != all_edges_list.end() && node_iterator != all_nodes_list.end())
{
if (edge_iterator->start < node_iterator->node_id)
{
++edge_iterator;
continue;
SimpleLogger().Write() << "Processed " << number_of_used_nodes << " nodes";
}
if (edge_iterator->start > node_iterator->node_id)
void ExtractionContainers::WriteRestrictions(const std::string& path) const
{
node_iterator++;
// serialize restrictions
std::ofstream restrictions_out_stream;
unsigned written_restriction_count = 0;
restrictions_out_stream.open(path.c_str(), std::ios::binary);
const FingerPrint fingerprint = FingerPrint::GetValid();
restrictions_out_stream.write((char *)&fingerprint, sizeof(FingerPrint));
const auto count_position = restrictions_out_stream.tellp();
restrictions_out_stream.write((char *)&written_restriction_count, sizeof(unsigned));
for (const auto &restriction_container : restrictions_list)
{
if (SPECIAL_NODEID != restriction_container.restriction.from.node &&
SPECIAL_NODEID != restriction_container.restriction.via.node &&
SPECIAL_NODEID != restriction_container.restriction.to.node)
{
restrictions_out_stream.write((char *)&(restriction_container.restriction),
sizeof(TurnRestriction));
++written_restriction_count;
}
}
restrictions_out_stream.seekp(count_position);
restrictions_out_stream.write((char *)&written_restriction_count, sizeof(unsigned));
restrictions_out_stream.close();
SimpleLogger().Write() << "usable restrictions: " << written_restriction_count;
}
void ExtractionContainers::PrepareRestrictions()
{
std::cout << "[extractor] Sorting used ways ... " << std::flush;
TIMER_START(sort_ways);
stxxl::sort(way_start_end_id_list.begin(), way_start_end_id_list.end(),
FirstAndLastSegmentOfWayStxxlCompare(), stxxl_memory);
TIMER_STOP(sort_ways);
std::cout << "ok, after " << TIMER_SEC(sort_ways) << "s" << std::endl;
std::cout << "[extractor] Sorting " << restrictions_list.size()
<< " restriction. by from... " << std::flush;
TIMER_START(sort_restrictions);
stxxl::sort(restrictions_list.begin(), restrictions_list.end(),
CmpRestrictionContainerByFrom(), stxxl_memory);
TIMER_STOP(sort_restrictions);
std::cout << "ok, after " << TIMER_SEC(sort_restrictions) << "s" << std::endl;
std::cout << "[extractor] Fixing restriction starts ... " << std::flush;
TIMER_START(fix_restriction_starts);
auto restrictions_iterator = restrictions_list.begin();
auto way_start_and_end_iterator = way_start_end_id_list.cbegin();
while (way_start_and_end_iterator != way_start_end_id_list.cend() &&
restrictions_iterator != restrictions_list.end())
{
if (way_start_and_end_iterator->way_id < restrictions_iterator->restriction.from.way)
{
++way_start_and_end_iterator;
continue;
}
BOOST_ASSERT(edge_iterator->start == node_iterator->node_id);
edge_iterator->source_coordinate.lat = node_iterator->lat;
edge_iterator->source_coordinate.lon = node_iterator->lon;
++edge_iterator;
}
TIMER_STOP(set_start_coords);
std::cout << "ok, after " << TIMER_SEC(set_start_coords) << "s" << std::endl;
// Sort Edges by target
std::cout << "[extractor] Sorting edges by target ... " << std::flush;
TIMER_START(sort_edges_by_target);
stxxl::sort(all_edges_list.begin(), all_edges_list.end(), CmpEdgeByTargetID(),
stxxl_memory);
TIMER_STOP(sort_edges_by_target);
std::cout << "ok, after " << TIMER_SEC(sort_edges_by_target) << "s" << std::endl;
std::cout << "[extractor] Setting target coords ... " << std::flush;
TIMER_START(set_target_coords);
// Traverse list of edges and nodes in parallel and set target coord
node_iterator = all_nodes_list.begin();
edge_iterator = all_edges_list.begin();
// Also serializes the edges
while (edge_iterator != all_edges_list.end() && node_iterator != all_nodes_list.end())
if (way_start_and_end_iterator->way_id > restrictions_iterator->restriction.from.way)
{
if (edge_iterator->target < node_iterator->node_id)
{
++edge_iterator;
SimpleLogger().Write(LogLevel::logDEBUG) << "Restriction references invalid way: " << restrictions_iterator->restriction.from.way;
restrictions_iterator->restriction.from.node = SPECIAL_NODEID;
++restrictions_iterator;
continue;
}
if (edge_iterator->target > node_iterator->node_id)
BOOST_ASSERT(way_start_and_end_iterator->way_id ==
restrictions_iterator->restriction.from.way);
// we do not remap the via id yet, since we will need it for the to node as well
const NodeID via_node_id = restrictions_iterator->restriction.via.node;
// check if via is actually valid, if not invalidate
auto via_id_iter = external_to_internal_node_id_map.find(via_node_id);
if(via_id_iter == external_to_internal_node_id_map.end())
{
++node_iterator;
SimpleLogger().Write(LogLevel::logDEBUG) << "Restriction references invalid node: " << restrictions_iterator->restriction.via.node;
restrictions_iterator->restriction.via.node = SPECIAL_NODEID;
++restrictions_iterator;
continue;
}
BOOST_ASSERT(edge_iterator->target == node_iterator->node_id);
if (edge_iterator->source_coordinate.lat != std::numeric_limits<int>::min() &&
edge_iterator->source_coordinate.lon != std::numeric_limits<int>::min())
if (way_start_and_end_iterator->first_segment_source_id == via_node_id)
{
BOOST_ASSERT(edge_iterator->speed != -1);
edge_iterator->target_coordinate.lat = node_iterator->lat;
edge_iterator->target_coordinate.lon = node_iterator->lon;
const double distance = coordinate_calculation::euclidean_distance(
edge_iterator->source_coordinate.lat, edge_iterator->source_coordinate.lon,
node_iterator->lat, node_iterator->lon);
const double weight = (distance * 10.) / (edge_iterator->speed / 3.6);
int integer_weight = std::max(
1, (int)std::floor(
(edge_iterator->is_duration_set ? edge_iterator->speed : weight) + .5));
// FIXME: This means we have a _minimum_ edge length of 1m
// maybe use dm as base unit?
const int integer_distance = std::max(1, (int)distance);
const short zero = 0;
const short one = 1;
const bool yes = true;
const bool no = false;
file_out_stream.write((char *)&edge_iterator->start, sizeof(unsigned));
file_out_stream.write((char *)&edge_iterator->target, sizeof(unsigned));
file_out_stream.write((char *)&integer_distance, sizeof(int));
switch (edge_iterator->direction)
// assign new from node id
auto id_iter = external_to_internal_node_id_map.find(
way_start_and_end_iterator->first_segment_target_id);
BOOST_ASSERT(id_iter != external_to_internal_node_id_map.end());
restrictions_iterator->restriction.from.node = id_iter->second;
}
else if (way_start_and_end_iterator->last_segment_target_id == via_node_id)
{
case ExtractionWay::notSure:
file_out_stream.write((char *)&zero, sizeof(short));
break;
case ExtractionWay::oneway:
file_out_stream.write((char *)&one, sizeof(short));
break;
case ExtractionWay::bidirectional:
file_out_stream.write((char *)&zero, sizeof(short));
break;
case ExtractionWay::opposite:
file_out_stream.write((char *)&one, sizeof(short));
break;
default:
throw osrm::exception("edge has broken direction");
// assign new from node id
auto id_iter = external_to_internal_node_id_map.find(
way_start_and_end_iterator->last_segment_source_id);
BOOST_ASSERT(id_iter != external_to_internal_node_id_map.end());
restrictions_iterator->restriction.from.node = id_iter->second;
}
++restrictions_iterator;
}
file_out_stream.write((char *)&integer_weight, sizeof(int));
file_out_stream.write((char *)&edge_iterator->name_id, sizeof(unsigned));
if (edge_iterator->is_roundabout)
{
file_out_stream.write((char *)&yes, sizeof(bool));
}
else
{
file_out_stream.write((char *)&no, sizeof(bool));
}
if (edge_iterator->is_in_tiny_cc)
{
file_out_stream.write((char *)&yes, sizeof(bool));
}
else
{
file_out_stream.write((char *)&no, sizeof(bool));
}
if (edge_iterator->is_access_restricted)
{
file_out_stream.write((char *)&yes, sizeof(bool));
}
else
{
file_out_stream.write((char *)&no, sizeof(bool));
}
TIMER_STOP(fix_restriction_starts);
std::cout << "ok, after " << TIMER_SEC(fix_restriction_starts) << "s" << std::endl;
// cannot take adress of bit field, so use local
const TravelMode travel_mode = edge_iterator->travel_mode;
file_out_stream.write((char *)&travel_mode, sizeof(TravelMode));
std::cout << "[extractor] Sorting restrictions. by to ... " << std::flush;
TIMER_START(sort_restrictions_to);
stxxl::sort(restrictions_list.begin(), restrictions_list.end(),
CmpRestrictionContainerByTo(), stxxl_memory);
TIMER_STOP(sort_restrictions_to);
std::cout << "ok, after " << TIMER_SEC(sort_restrictions_to) << "s" << std::endl;
if (edge_iterator->is_split)
std::cout << "[extractor] Fixing restriction ends ... " << std::flush;
TIMER_START(fix_restriction_ends);
restrictions_iterator = restrictions_list.begin();
way_start_and_end_iterator = way_start_end_id_list.cbegin();
while (way_start_and_end_iterator != way_start_end_id_list.cend() &&
restrictions_iterator != restrictions_list.end())
{
file_out_stream.write((char *)&yes, sizeof(bool));
}
else
if (way_start_and_end_iterator->way_id < restrictions_iterator->restriction.to.way)
{
file_out_stream.write((char *)&no, sizeof(bool));
++way_start_and_end_iterator;
continue;
}
++number_of_used_edges;
}
++edge_iterator;
}
TIMER_STOP(set_target_coords);
std::cout << "ok, after " << TIMER_SEC(set_target_coords) << "s" << std::endl;
std::cout << "[extractor] setting number of edges ... " << std::flush;
file_out_stream.seekp(previous_file_position);
file_out_stream.write((char *)&number_of_used_edges, sizeof(unsigned));
file_out_stream.close();
std::cout << "ok" << std::endl;
std::cout << "[extractor] writing street name index ... " << std::flush;
TIMER_START(write_name_index);
std::string name_file_streamName = (output_file_name + ".names");
boost::filesystem::ofstream name_file_stream(name_file_streamName, std::ios::binary);
unsigned total_length = 0;
std::vector<unsigned> name_lengths;
for (const std::string &temp_string : name_list)
if (restrictions_iterator->restriction.from.node == SPECIAL_NODEID ||
restrictions_iterator->restriction.via.node == SPECIAL_NODEID)
{
const unsigned string_length =
std::min(static_cast<unsigned>(temp_string.length()), 255u);
name_lengths.push_back(string_length);
total_length += string_length;
++restrictions_iterator;
continue;
}
RangeTable<> table(name_lengths);
name_file_stream << table;
name_file_stream.write((char *)&total_length, sizeof(unsigned));
// write all chars consecutively
for (const std::string &temp_string : name_list)
if (way_start_and_end_iterator->way_id > restrictions_iterator->restriction.to.way)
{
const unsigned string_length =
std::min(static_cast<unsigned>(temp_string.length()), 255u);
name_file_stream.write(temp_string.c_str(), string_length);
SimpleLogger().Write(LogLevel::logDEBUG) << "Restriction references invalid way: " << restrictions_iterator->restriction.to.way;
restrictions_iterator->restriction.to.way = SPECIAL_NODEID;
++restrictions_iterator;
continue;
}
BOOST_ASSERT(way_start_and_end_iterator->way_id ==
restrictions_iterator->restriction.to.way);
const NodeID via_node_id = restrictions_iterator->restriction.via.node;
name_file_stream.close();
TIMER_STOP(write_name_index);
std::cout << "ok, after " << TIMER_SEC(write_name_index) << "s" << std::endl;
// assign new via node id
auto via_id_iter = external_to_internal_node_id_map.find(via_node_id);
BOOST_ASSERT(via_id_iter != external_to_internal_node_id_map.end());
restrictions_iterator->restriction.via.node = via_id_iter->second;
SimpleLogger().Write() << "Processed " << number_of_used_nodes << " nodes and "
<< number_of_used_edges << " edges";
}
catch (const std::exception &e)
if (way_start_and_end_iterator->first_segment_source_id == via_node_id)
{
std::cerr << "Caught Execption:" << e.what() << std::endl;
auto to_id_iter = external_to_internal_node_id_map.find(
way_start_and_end_iterator->first_segment_target_id);
BOOST_ASSERT(to_id_iter != external_to_internal_node_id_map.end());
restrictions_iterator->restriction.to.node = to_id_iter->second;
}
else if (way_start_and_end_iterator->last_segment_target_id == via_node_id)
{
auto to_id_iter = external_to_internal_node_id_map.find(
way_start_and_end_iterator->last_segment_source_id);
BOOST_ASSERT(to_id_iter != external_to_internal_node_id_map.end());
restrictions_iterator->restriction.to.node = to_id_iter->second;
}
++restrictions_iterator;
}
TIMER_STOP(fix_restriction_ends);
std::cout << "ok, after " << TIMER_SEC(fix_restriction_ends) << "s" << std::endl;
}

View File

@ -32,13 +32,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "first_and_last_segment_of_way.hpp"
#include "../data_structures/external_memory_node.hpp"
#include "../data_structures/restriction.hpp"
#include "../util/fingerprint.hpp"
#include <stxxl/vector>
#include <unordered_map>
/**
* Uses external memory containers from stxxl to store all the data that
* is collected by the extractor callbacks.
*
* The data is the filtered, aggregated and finally written to disk.
*/
class ExtractionContainers
{
@ -49,6 +51,14 @@ class ExtractionContainers
#else
const static unsigned stxxl_memory = ((sizeof(std::size_t) == 4) ? INT_MAX : UINT_MAX);
#endif
void PrepareNodes();
void PrepareRestrictions();
void PrepareEdges();
void WriteNodes(std::ofstream& file_out_stream) const;
void WriteRestrictions(const std::string& restrictions_file_name) const;
void WriteEdges(std::ofstream& file_out_stream) const;
void WriteNames(const std::string& names_file_name) const;
public:
using STXXLNodeIDVector = stxxl::vector<NodeID>;
using STXXLNodeVector = stxxl::vector<ExternalMemoryNode>;
@ -63,14 +73,15 @@ class ExtractionContainers
STXXLStringVector name_list;
STXXLRestrictionsVector restrictions_list;
STXXLWayIDStartEndVector way_start_end_id_list;
const FingerPrint fingerprint;
std::unordered_map<NodeID, NodeID> external_to_internal_node_id_map;
ExtractionContainers();
~ExtractionContainers();
void PrepareData(const std::string &output_file_name,
const std::string &restrictions_file_name);
const std::string &restrictions_file_name,
const std::string &names_file_name);
};
#endif /* EXTRACTION_CONTAINERS_HPP */

View File

@ -102,7 +102,7 @@ unsigned parseDuration(const std::string &s)
minutes = cast::string_to_int(result[1]);
hours = cast::string_to_int(result[0]);
}
return 10 * (3600 * hours + 60 * minutes + seconds);
return (3600 * hours + 60 * minutes + seconds);
}
}
else if (iso_8601_duration_is_valid(s))

View File

@ -82,7 +82,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* .restrictions : Turn restrictions that are used my osrm-prepare to construct the edge-expanded graph
*
*/
int extractor::run(const ExtractorConfig &extractor_config)
int extractor::run()
{
try
{
@ -91,20 +91,20 @@ int extractor::run(const ExtractorConfig &extractor_config)
const unsigned recommended_num_threads = tbb::task_scheduler_init::default_num_threads();
const auto number_of_threads =
std::min(recommended_num_threads, extractor_config.requested_num_threads);
std::min(recommended_num_threads, config.requested_num_threads);
tbb::task_scheduler_init init(number_of_threads);
SimpleLogger().Write() << "Input file: " << extractor_config.input_path.filename().string();
SimpleLogger().Write() << "Profile: " << extractor_config.profile_path.filename().string();
SimpleLogger().Write() << "Input file: " << config.input_path.filename().string();
SimpleLogger().Write() << "Profile: " << config.profile_path.filename().string();
SimpleLogger().Write() << "Threads: " << number_of_threads;
// setup scripting environment
ScriptingEnvironment scripting_environment(extractor_config.profile_path.string().c_str());
ScriptingEnvironment scripting_environment(config.profile_path.string().c_str());
ExtractionContainers extraction_containers;
auto extractor_callbacks = osrm::make_unique<ExtractorCallbacks>(extraction_containers);
const osmium::io::File input_file(extractor_config.input_path.string());
const osmium::io::File input_file(config.input_path.string());
osmium::io::Reader reader(input_file);
const osmium::io::Header header = reader.header();
@ -131,7 +131,7 @@ int extractor::run(const ExtractorConfig &extractor_config)
}
SimpleLogger().Write() << "timestamp: " << timestamp;
boost::filesystem::ofstream timestamp_out(extractor_config.timestamp_file_name);
boost::filesystem::ofstream timestamp_out(config.timestamp_file_name);
timestamp_out.write(timestamp.c_str(), timestamp.length());
timestamp_out.close();
@ -236,12 +236,13 @@ int extractor::run(const ExtractorConfig &extractor_config)
return 1;
}
extraction_containers.PrepareData(extractor_config.output_file_name,
extractor_config.restriction_file_name);
extraction_containers.PrepareData(config.output_file_name,
config.restriction_file_name,
config.names_file_name);
TIMER_STOP(extracting);
SimpleLogger().Write() << "extraction finished after " << TIMER_SEC(extracting) << "s";
SimpleLogger().Write() << "To prepare the data for routing, run: "
<< "./osrm-prepare " << extractor_config.output_file_name
<< "./osrm-prepare " << config.output_file_name
<< std::endl;
}
catch (std::exception &e)

View File

@ -30,8 +30,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "extractor_options.hpp"
struct extractor
class extractor
{
int run(const ExtractorConfig &extractor_config);
public:
extractor(const ExtractorConfig &extractor_config)
: config(extractor_config) {}
int run();
private:
ExtractorConfig config;
};
#endif /* EXTRACTOR_HPP */

View File

@ -108,17 +108,40 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
<< " of size " << input_way.nodes().size();
return;
}
InternalExtractorEdge::WeightData forward_weight_data;
InternalExtractorEdge::WeightData backward_weight_data;
if (0 < parsed_way.duration)
{
// TODO: iterate all way segments and set duration corresponding to the length of each
// segment
const_cast<ExtractionWay &>(parsed_way).forward_speed =
parsed_way.duration / (input_way.nodes().size() - 1);
const_cast<ExtractionWay &>(parsed_way).backward_speed =
parsed_way.duration / (input_way.nodes().size() - 1);
const unsigned num_edges = (input_way.nodes().size() - 1);
// FIXME We devide by the numer of nodes here, but should rather consider
// the length of each segment. We would eigther have to compute the length
// of the whole way here (we can't: no node coordinates) or push that back
// to the container and keep a reference to the way.
forward_weight_data.duration = parsed_way.duration / num_edges;
forward_weight_data.type = InternalExtractorEdge::WeightType::WAY_DURATION;
backward_weight_data.duration = parsed_way.duration / num_edges;
backward_weight_data.type = InternalExtractorEdge::WeightType::WAY_DURATION;
}
else
{
if (parsed_way.forward_speed > 0 &&
parsed_way.forward_travel_mode != TRAVEL_MODE_INACCESSIBLE)
{
forward_weight_data.speed = parsed_way.forward_speed;
forward_weight_data.type = InternalExtractorEdge::WeightType::SPEED;
}
if (parsed_way.backward_speed > 0 &&
parsed_way.backward_travel_mode != TRAVEL_MODE_INACCESSIBLE)
{
backward_weight_data.speed = parsed_way.backward_speed;
backward_weight_data.type = InternalExtractorEdge::WeightType::SPEED;
}
}
if (std::numeric_limits<double>::epsilon() >= std::abs(-1. - parsed_way.forward_speed))
if (forward_weight_data.type == InternalExtractorEdge::WeightType::INVALID
&& backward_weight_data.type == InternalExtractorEdge::WeightType::INVALID)
{
SimpleLogger().Write(logDEBUG) << "found way with bogus speed, id: " << input_way.id();
return;
@ -144,36 +167,34 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
((parsed_way.forward_speed != parsed_way.backward_speed) ||
(parsed_way.forward_travel_mode != parsed_way.backward_travel_mode));
auto pair_wise_segment_split =
// lambda to add edge to container
auto pair_wise_segment_split_forward =
[&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node)
{
// SimpleLogger().Write() << "adding edge (" << first_node.ref() << "," <<
// last_node.ref() << "), fwd speed: " << parsed_way.forward_speed;
const bool forward_only = split_edge || TRAVEL_MODE_INACCESSIBLE == parsed_way.backward_travel_mode;
external_memory.all_edges_list.push_back(InternalExtractorEdge(
first_node.ref(), last_node.ref(),
((split_edge || TRAVEL_MODE_INACCESSIBLE == parsed_way.backward_travel_mode)
? ExtractionWay::oneway
: ExtractionWay::bidirectional),
parsed_way.forward_speed, name_id, parsed_way.roundabout, parsed_way.ignore_in_grid,
(0 < parsed_way.duration), parsed_way.is_access_restricted,
parsed_way.forward_travel_mode, split_edge));
first_node.ref(), last_node.ref(), name_id, forward_weight_data,
true, !forward_only, parsed_way.roundabout, parsed_way.ignore_in_grid,
parsed_way.is_access_restricted, parsed_way.forward_travel_mode, split_edge));
external_memory.used_node_id_list.push_back(first_node.ref());
};
const bool is_opposite_way = TRAVEL_MODE_INACCESSIBLE == parsed_way.forward_travel_mode;
// traverse way in reverse in this case
if (is_opposite_way)
{
// why don't we have to swap the parsed_way.forward/backward speed here as well
const_cast<ExtractionWay &>(parsed_way).forward_travel_mode =
parsed_way.backward_travel_mode;
const_cast<ExtractionWay &>(parsed_way).backward_travel_mode = TRAVEL_MODE_INACCESSIBLE;
osrm::for_each_pair(input_way.nodes().crbegin(), input_way.nodes().crend(),
pair_wise_segment_split);
pair_wise_segment_split_forward);
external_memory.used_node_id_list.push_back(input_way.nodes().front().ref());
}
else
{
osrm::for_each_pair(input_way.nodes().cbegin(), input_way.nodes().cend(),
pair_wise_segment_split);
pair_wise_segment_split_forward);
external_memory.used_node_id_list.push_back(input_way.nodes().back().ref());
}
@ -187,22 +208,19 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
if (split_edge)
{ // Only true if the way should be split
BOOST_ASSERT(parsed_way.backward_travel_mode > 0);
BOOST_ASSERT(parsed_way.backward_travel_mode != TRAVEL_MODE_INACCESSIBLE);
auto pair_wise_segment_split_2 =
[&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node)
{
// SimpleLogger().Write() << "adding edge (" << last_node.ref() << "," <<
// first_node.ref() << "), bwd speed: " << parsed_way.backward_speed;
external_memory.all_edges_list.push_back(InternalExtractorEdge(
last_node.ref(), first_node.ref(), ExtractionWay::oneway, parsed_way.backward_speed,
name_id, parsed_way.roundabout, parsed_way.ignore_in_grid,
(0 < parsed_way.duration), parsed_way.is_access_restricted,
parsed_way.backward_travel_mode, split_edge));
last_node.ref(), first_node.ref(), name_id, backward_weight_data,
true, false, parsed_way.roundabout, parsed_way.ignore_in_grid,
parsed_way.is_access_restricted, parsed_way.backward_travel_mode, split_edge));
external_memory.used_node_id_list.push_back(last_node.ref());
};
if (is_opposite_way)
{
// SimpleLogger().Write() << "opposite2";
osrm::for_each_pair(input_way.nodes().crbegin(), input_way.nodes().crend(),
pair_wise_segment_split_2);
external_memory.used_node_id_list.push_back(input_way.nodes().front().ref());
@ -211,7 +229,7 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
{
osrm::for_each_pair(input_way.nodes().cbegin(), input_way.nodes().cend(),
pair_wise_segment_split_2);
external_memory.used_node_id_list.push_back(input_way.nodes().back().ref());
external_memory.used_node_id_list.push_back(input_way.nodes().front().ref());
}
external_memory.way_start_end_id_list.push_back(

View File

@ -135,6 +135,7 @@ void ExtractorOptions::GenerateOutputFilesNames(ExtractorConfig &extractor_confi
boost::filesystem::path &input_path = extractor_config.input_path;
extractor_config.output_file_name = input_path.string();
extractor_config.restriction_file_name = input_path.string();
extractor_config.names_file_name = input_path.string();
extractor_config.timestamp_file_name = input_path.string();
std::string::size_type pos = extractor_config.output_file_name.find(".osm.bz2");
if (pos == std::string::npos)
@ -156,12 +157,14 @@ void ExtractorOptions::GenerateOutputFilesNames(ExtractorConfig &extractor_confi
{
extractor_config.output_file_name.append(".osrm");
extractor_config.restriction_file_name.append(".osrm.restrictions");
extractor_config.names_file_name.append(".osrm.names");
extractor_config.timestamp_file_name.append(".osrm.timestamp");
}
else
{
extractor_config.output_file_name.replace(pos, 5, ".osrm");
extractor_config.restriction_file_name.replace(pos, 5, ".osrm.restrictions");
extractor_config.names_file_name.replace(pos, 5, ".osrm.names");
extractor_config.timestamp_file_name.replace(pos, 5, ".osrm.timestamp");
}
}
@ -169,6 +172,7 @@ void ExtractorOptions::GenerateOutputFilesNames(ExtractorConfig &extractor_confi
{
extractor_config.output_file_name.replace(pos, 8, ".osrm");
extractor_config.restriction_file_name.replace(pos, 8, ".osrm.restrictions");
extractor_config.names_file_name.replace(pos, 8, ".osrm.names");
extractor_config.timestamp_file_name.replace(pos, 8, ".osrm.timestamp");
}
}

View File

@ -48,6 +48,7 @@ struct ExtractorConfig
std::string output_file_name;
std::string restriction_file_name;
std::string names_file_name;
std::string timestamp_file_name;
unsigned requested_num_threads;

View File

@ -30,6 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "../typedefs.h"
#include "../data_structures/travel_mode.hpp"
#include "../data_structures/import_edge.hpp"
#include <boost/assert.hpp>
@ -37,83 +38,108 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
struct InternalExtractorEdge
{
InternalExtractorEdge()
: start(0), target(0), speed(0), name_id(0), direction(0), is_roundabout(false),
is_in_tiny_cc(false), is_duration_set(false), is_access_restricted(false),
is_split(false), travel_mode(TRAVEL_MODE_INACCESSIBLE)
// specify the type of the weight data
enum class WeightType : char {
INVALID,
SPEED,
EDGE_DURATION,
WAY_DURATION,
};
struct WeightData
{
WeightData() : duration(0.0), type(WeightType::INVALID)
{
}
explicit InternalExtractorEdge(NodeID start,
NodeID target,
short direction,
double speed,
unsigned name_id,
bool is_roundabout,
bool is_in_tiny_cc,
bool is_duration_set,
bool is_access_restricted,
TravelMode travel_mode,
bool is_split)
: start(start), target(target), speed(speed), name_id(name_id), direction(direction),
is_roundabout(is_roundabout), is_in_tiny_cc(is_in_tiny_cc),
is_duration_set(is_duration_set), is_access_restricted(is_access_restricted),
is_split(is_split), travel_mode(travel_mode)
union
{
double duration;
double speed;
};
WeightType type;
};
explicit InternalExtractorEdge()
: result(0, 0, 0, 0, false, false, false, false, false,
TRAVEL_MODE_INACCESSIBLE, false)
{
}
explicit InternalExtractorEdge(NodeID source,
NodeID target,
NodeID name_id,
const WeightData& weight_data,
bool forward,
bool backward,
bool roundabout,
bool in_tiny_cc,
bool access_restricted,
TravelMode travel_mode,
bool is_split)
: result(source, target, name_id, 0, forward, backward, roundabout,
in_tiny_cc, access_restricted, travel_mode, is_split),
weight_data(weight_data)
{
}
// data that will be written to disk
NodeBasedEdge result;
// intermediate edge weight
WeightData weight_data;
// coordinate of the source node
FixedPointCoordinate source_coordinate;
// necessary static util functions for stxxl's sorting
static InternalExtractorEdge min_value()
{
return InternalExtractorEdge(0, 0, 0, 0, 0, false, false, false, false,
TRAVEL_MODE_INACCESSIBLE, false);
return InternalExtractorEdge(0, 0, 0, WeightData(), false, false, false,
false, false, TRAVEL_MODE_INACCESSIBLE, false);
}
static InternalExtractorEdge max_value()
{
return InternalExtractorEdge(SPECIAL_NODEID, SPECIAL_NODEID, 0, 0, 0, false, false, false,
false, TRAVEL_MODE_INACCESSIBLE, false);
return InternalExtractorEdge(SPECIAL_NODEID, SPECIAL_NODEID, 0, WeightData(), false, false,
false, false, false, TRAVEL_MODE_INACCESSIBLE, false);
}
};
struct CmpEdgeByStartThenTargetID
{
using value_type = InternalExtractorEdge;
bool operator()(const InternalExtractorEdge &lhs, const InternalExtractorEdge &rhs) const
{
return (lhs.result.source < rhs.result.source) ||
((lhs.result.source == rhs.result.source) &&
(lhs.result.target < rhs.result.target));
}
NodeID start;
NodeID target;
double speed;
unsigned name_id;
short direction;
bool is_roundabout : 1;
bool is_in_tiny_cc : 1;
bool is_duration_set : 1;
bool is_access_restricted : 1;
bool is_split : 1;
TravelMode travel_mode : 4;
FixedPointCoordinate source_coordinate;
FixedPointCoordinate target_coordinate;
value_type max_value() { return InternalExtractorEdge::max_value(); }
value_type min_value() { return InternalExtractorEdge::min_value(); }
};
struct CmpEdgeByStartID
{
using value_type = InternalExtractorEdge;
bool operator()(const InternalExtractorEdge &a, const InternalExtractorEdge &b) const
bool operator()(const InternalExtractorEdge &lhs, const InternalExtractorEdge &rhs) const
{
return a.start < b.start;
return lhs.result.source < rhs.result.source;
}
value_type max_value() { return InternalExtractorEdge::max_value(); }
value_type min_value() { return InternalExtractorEdge::min_value(); }
};
struct CmpEdgeByTargetID
{
using value_type = InternalExtractorEdge;
bool operator()(const InternalExtractorEdge &a, const InternalExtractorEdge &b) const
bool operator()(const InternalExtractorEdge &lhs, const InternalExtractorEdge &rhs) const
{
return a.target < b.target;
return lhs.result.target < rhs.result.target;
}
value_type max_value() { return InternalExtractorEdge::max_value(); }
value_type min_value() { return InternalExtractorEdge::min_value(); }
};

View File

@ -44,7 +44,7 @@ namespace
{
int lua_error_callback(lua_State *lua_state)
{
luabind::object error_msg(luabind::from_stack(lua_state, -1));
std::string error_msg = lua_tostring(lua_state, -1);
std::ostringstream error_stream;
error_stream << error_msg;
throw osrm::exception("ERROR occured in profile script:\n" + error_stream.str());

View File

@ -53,7 +53,7 @@ auto get_value_by_key(T const &object, const char *key) -> decltype(object.get_v
int lua_error_callback(lua_State *L) // This is so I can use my own function as an
// exception handler, pcall_log()
{
luabind::object error_msg(luabind::from_stack(L, -1));
std::string error_msg = lua_tostring(L, -1);
std::ostringstream error_stream;
error_stream << error_msg;
throw osrm::exception("ERROR occured in profile script:\n" + error_stream.str());

View File

@ -120,7 +120,7 @@ Feature: Bike - Access tags on ways
| no | | | |
| private | | | |
| agricultural | | | |
| forestery | | | |
| forestry | | | |
| | yes | | x |
| | permissive | | x |
| | designated | | x |
@ -128,7 +128,7 @@ Feature: Bike - Access tags on ways
| | no | | |
| | private | | |
| | agricultural | | |
| | forestery | | |
| | forestry | | |
| | | yes | x |
| | | permissive | x |
| | | designated | x |
@ -136,7 +136,7 @@ Feature: Bike - Access tags on ways
| | | no | |
| | | private | |
| | | agricultural | |
| | | forestery | |
| | | forestry | |
Scenario: Bike - Access tags on both node and way
Then routability should be

View File

@ -7,20 +7,21 @@ Feature: Bike - Access tags on nodes
Scenario: Bike - Access tag hierachy on nodes
Then routability should be
| node/access | node/vehicle | node/bicycle | bothw |
| | | | x |
| yes | | | x |
| no | | | |
| | yes | | x |
| | no | | |
| no | yes | | x |
| yes | no | | |
| | | yes | x |
| | | no | |
| no | | yes | x |
| yes | | no | |
| | no | yes | x |
| | yes | no | |
| node/access | node/vehicle | node/bicycle | node/highway | bothw |
| | | | | x |
| yes | | | | x |
| no | | | | |
| | yes | | | x |
| | no | | | |
| no | yes | | | x |
| yes | no | | | |
| | | yes | | x |
| | | no | | |
| | | no | crossing | x |
| no | | yes | | x |
| yes | | no | | |
| | no | yes | | x |
| | yes | no | | |
Scenario: Bike - Overwriting implied acccess on nodes doesn't overwrite way
Then routability should be
@ -45,7 +46,7 @@ Feature: Bike - Access tags on nodes
| no | | | |
| private | | | |
| agricultural | | | |
| forestery | | | |
| forestry | | | |
| | yes | | x |
| | permissive | | x |
| | designated | | x |
@ -53,7 +54,7 @@ Feature: Bike - Access tags on nodes
| | no | | |
| | private | | |
| | agricultural | | |
| | forestery | | |
| | forestry | | |
| | | yes | x |
| | | permissive | x |
| | | designated | x |
@ -61,4 +62,4 @@ Feature: Bike - Access tags on nodes
| | | no | |
| | | private | |
| | | agricultural | |
| | | forestery | |
| | | forestry | |

View File

@ -16,7 +16,7 @@ Feature: Bike - Surfaces
| cycleway | unpaved | 120s |
| cycleway | fine_gravel | 120s |
| cycleway | gravel | 120s |
| cycleway | pebbelstone | 120s |
| cycleway | pebblestone | 120s |
| cycleway | dirt | 120s |
| cycleway | earth | 120s |
| cycleway | grass | 120s |

View File

@ -93,3 +93,22 @@ OSRM will use 4/5 of the projected free-flow speed.
| primary | 15 | | 30 | 60 | 34 km/h | 59 km/h |
| primary | 15 | 3 | 30 | 60 | 15 km/h | 30 km/h |
Scenario: Car - Single lane streets be ignored or incur a penalty
Then routability should be
| highway | maxspeed | lanes | maxspeed:forward | maxspeed:backward | forw | backw |
| primary | | | | | 63 km/h | 63 km/h |
| primary | | 1 | | | 32 km/h | 32 km/h |
| primary | 60 | | | | 59 km/h | 59 km/h |
| primary | 60 | 1 | | | 30 km/h | 30 km/h |
| primary | | | 60 | | 59 km/h | 63 km/h |
| primary | | 1 | 60 | | 30 km/h | 32 km/h |
| primary | | | | 60 | 63 km/h | 59 km/h |
| primary | | 1 | | 60 | 32 km/h | 30 km/h |
| primary | 15 | | 60 | | 59 km/h | 23 km/h |
| primary | 15 | 1 | 60 | | 30 km/h | 7 km/h |
| primary | 15 | | | 60 | 23 km/h | 59 km/h |
| primary | 15 | 1 | | 60 | 7 km/h | 30 km/h |
| primary | 15 | | 30 | 60 | 34 km/h | 59 km/h |
| primary | 15 | 1 | 30 | 60 | 15 km/h | 30 km/h |

View File

@ -10,13 +10,13 @@ Feature: Car - Street names in instructions
| | c |
And the ways
| nodes | name |
| ab | My Way |
| bc | Your Way |
| nodes | name | ref |
| ab | My Way | |
| bc | Your Way | A1 |
When I route I should get
| from | to | route |
| a | c | My Way,Your Way |
| a | c | My Way,Your Way (A1) |
@todo
Scenario: Car - Use way type to describe unnamed ways

View File

@ -51,7 +51,7 @@ Feature: Foot - Access tags on ways
| no | | |
| private | | |
| agricultural | | |
| forestery | | |
| forestry | | |
| | yes | x |
| | permissive | x |
| | designated | x |
@ -59,7 +59,7 @@ Feature: Foot - Access tags on ways
| | no | |
| | private | |
| | agricultural | |
| | forestery | |
| | forestry | |
Scenario: Foot - Access tags on both node and way
Then routability should be

View File

@ -39,7 +39,7 @@ Feature: Foot - Access tags on nodes
| no | | |
| private | | |
| agricultural | | |
| forestery | | |
| forestry | | |
| no | yes | x |
| no | permissive | x |
| no | designated | x |
@ -47,4 +47,4 @@ Feature: Foot - Access tags on nodes
| yes | no | |
| yes | private | |
| yes | agricultural | |
| yes | forestery | |
| yes | forestry | |

View File

@ -10,6 +10,6 @@ Feature: Foot - Surfaces
| footway | | 145s ~10% |
| footway | fine_gravel | 193s ~10% |
| footway | gravel | 193s ~10% |
| footway | pebbelstone | 193s ~10% |
| footway | pebblestone | 193s ~10% |
| footway | mud | 289s ~10% |
| footway | sand | 289s ~10% |

View File

@ -30,3 +30,9 @@ Feature: Foot - Accessability of different way types
| pier | x |
| cycleway | |
| bridleway | |
Scenario: Foot - Basic access
Then routability should be
| highway | leisure | forw |
| (nil) | track | x |

View File

@ -61,10 +61,9 @@ Feature: Locating Nearest node on a Way - pick closest way
| a | -85 | -180 |
| b | -85 | -160 |
| c | -85 | -140 |
| x | 75 | -180 |
| y | 75 | -180 |
| v | 1 | 1 |
| w | -1 | -1 |
| x | -84.999 | -180 |
| y | -84.999 | -160 |
| z | -84.999 | -140 |
And the ways
| nodes |
@ -73,6 +72,5 @@ Feature: Locating Nearest node on a Way - pick closest way
When I request nearest I should get
| in | out |
| x | a |
| y | a |
| v | c |
| w | c |
| y | b |
| z | c |

View File

@ -17,7 +17,7 @@ Feature: osrm-prepare command line options: help
And stdout should contain "--profile"
And stdout should contain "--threads"
And stdout should contain 15 lines
And it should exit with code 0
And it should exit with code 1
Scenario: osrm-prepare - Help, short
When I run "osrm-prepare -h"

View File

@ -174,3 +174,7 @@ end
Given /^data is loaded with datastore$/ do
@load_method = 'datastore'
end
Given /^the HTTP method "([^"]*)"$/ do |method|
@http_method = method
end

View File

@ -52,5 +52,5 @@ When /^I request a travel time matrix I should get$/ do |table|
actual << r
end
end
table.routing_diff! actual
table.diff! actual
end

View File

@ -9,7 +9,7 @@ When /^I request locate I should get$/ do |table|
out_node = find_node_by_name row['out']
raise "*** unknown out-node '#{row['out']}" unless out_node
response = request_locate("#{in_node.lat},#{in_node.lon}")
response = request_locate(in_node)
if response.code == "200" && response.body.empty? == false
json = JSON.parse response.body
if json['status'] == 0
@ -39,7 +39,7 @@ When /^I request locate I should get$/ do |table|
actual << got
end
end
table.routing_diff! actual
table.diff! actual
end
When /^I request locate (\d+) times I should get$/ do |n,table|

View File

@ -91,6 +91,6 @@ When /^I match I should get$/ do |table|
actual << got
end
end
table.routing_diff! actual
table.diff! actual
end

View File

@ -9,7 +9,7 @@ When /^I request nearest I should get$/ do |table|
out_node = find_node_by_name row['out']
raise "*** unknown out-node '#{row['out']}" unless out_node
response = request_nearest("#{in_node.lat},#{in_node.lon}")
response = request_nearest(in_node)
if response.code == "200" && response.body.empty? == false
json = JSON.parse response.body
if json['status'] == 0
@ -39,7 +39,7 @@ When /^I request nearest I should get$/ do |table|
actual << got
end
end
table.routing_diff! actual
table.diff! actual
end
When /^I request nearest (\d+) times I should get$/ do |n,table|

View File

@ -74,5 +74,5 @@ Then /^routability should be$/ do |table|
actual << output_row
end
end
table.routing_diff! actual
table.diff! actual
end

View File

@ -140,7 +140,7 @@ When /^I route I should get$/ do |table|
actual << got
end
end
table.routing_diff! actual
table.diff! actual
end
When /^I route (\d+) times I should get$/ do |n,table|

View File

@ -1,76 +0,0 @@
#monkey patch cucumber table class to reorder output.
#we always want failed rows to be shown right below the expected row.
class Cucumber::Ast::Table
def routing_diff!(other_table, options={})
options = {:missing_row => true, :surplus_row => true, :missing_col => true, :surplus_col => false}.merge(options)
other_table = ensure_table(other_table)
other_table.convert_headers!
other_table.convert_columns!
ensure_green!
convert_headers!
convert_columns!
original_width = cell_matrix[0].length
other_table_cell_matrix = pad!(other_table.cell_matrix)
padded_width = cell_matrix[0].length
missing_col = cell_matrix[0].detect{|cell| cell.status == :undefined}
surplus_col = padded_width > original_width
require_diff_lcs
cell_matrix.extend(Diff::LCS)
changes = cell_matrix.diff(other_table_cell_matrix).flatten
inserted = 0
missing = 0
row_indices = Array.new(other_table_cell_matrix.length) {|n| n}
last_change = nil
missing_row_pos = nil
insert_row_pos = nil
changes.each do |change|
if(change.action == '-')
missing_row_pos = change.position + inserted
cell_matrix[missing_row_pos].each{|cell| cell.status = :undefined}
row_indices.insert(missing_row_pos, nil)
missing += 1
else # '+'
#change index so we interleave instead
insert_row_pos = change.position + inserted + 1
#insert_row_pos = change.position + missing #original
inserted_row = change.element
inserted_row.each{|cell| cell.status = :comment}
cell_matrix.insert(insert_row_pos, inserted_row)
row_indices[insert_row_pos] = nil
inspect_rows(cell_matrix[missing_row_pos], inserted_row) if last_change && last_change.action == '-'
inserted += 1
end
last_change = change
end
other_table_cell_matrix.each_with_index do |other_row, i|
row_index = row_indices.index(i)
row = cell_matrix[row_index] if row_index
if row
(original_width..padded_width).each do |col_index|
surplus_cell = other_row[col_index]
row[col_index].value = surplus_cell.value if row[col_index]
end
end
end
clear_cache!
should_raise =
missing_row_pos && options[:missing_row] ||
insert_row_pos && options[:surplus_row] ||
missing_col && options[:missing_col] ||
surplus_col && options[:surplus_col]
raise Different.new(self) if should_raise
end
end

View File

@ -22,10 +22,10 @@ SHUTDOWN_TIMEOUT = 10
DEFAULT_LOAD_METHOD = 'datastore'
OSRM_ROUTED_LOG_FILE = 'osrm-routed.log'
if ENV['OS']==/Windows.*/ then
TERMSIGNAL='TERM'
else
if ENV['OS']=~/Windows.*/ then
TERMSIGNAL=9
else
TERMSIGNAL='TERM'
end
@ -72,8 +72,8 @@ end
def verify_existance_of_binaries
["osrm-extract", "osrm-prepare", "osrm-routed"].each do |bin|
unless File.exists? "#{BIN_PATH}/#{bin}"
raise "*** #{BIN_PATH}/#{bin} is missing. Build failed?"
unless File.exists? "#{BIN_PATH}/#{bin}#{EXE}"
raise "*** #{BIN_PATH}/#{bin}#{EXE} is missing. Build failed?"
end
end
end

View File

@ -4,19 +4,13 @@ STRESS_TIMEOUT = 300
Before do |scenario|
# feature name
# fetch scenario and feature name, so we can use it in log files if needed
case scenario
when Cucumber::Ast::Scenario
when Cucumber::RunningTestCase::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
when Cucumber::RunningTestCase::ExampleRow
@feature_name = scenario.scenario_outline.feature.name
@scenario_title = scenario.scenario_outline.name
end

34
features/support/http.rb Normal file
View File

@ -0,0 +1,34 @@
require 'net/http'
def generate_request_url path
if @http_method.eql? "POST"
pos = path.index('?') - 1
service = path[0..pos]
uri = URI.parse "#{HOST}/#{service}"
else
uri = URI.parse "#{HOST}/#{path}"
end
end
def send_request uri, waypoints=[], options={}, timestamps=[]
@query = uri.to_s
Timeout.timeout(OSRM_TIMEOUT) do
if @http_method.eql? "POST"
datas = {}
if waypoints.length > 0
datas[:loc] = waypoints.compact.map { |w| "#{w.lat},#{w.lon}" }
end
if timestamps.length > 0
datas[:t] = timestamps.compact.map { |t| "#{t}" }
end
datas.merge! options
response = Net::HTTP.post_form uri, datas
else
response = Net::HTTP.get_response uri
end
end
rescue Errno::ECONNREFUSED => e
raise "*** osrm-routed is not running."
rescue Timeout::Error
raise "*** osrm-routed did not respond."
end

View File

@ -1,17 +1,12 @@
require 'net/http'
def request_locate_url path
def request_locate_url path, node
@query = path
uri = URI.parse "#{HOST}/#{path}"
Timeout.timeout(OSRM_TIMEOUT) do
Net::HTTP.get_response uri
end
rescue Errno::ECONNREFUSED => e
raise "*** osrm-routed is not running."
rescue Timeout::Error
raise "*** osrm-routed did not respond."
uri = generate_request_url path
response = send_request uri, [node]
end
def request_locate a
request_locate_url "locate?loc=#{a}"
def request_locate node
request_locate_url "locate?loc=#{node.lat},#{node.lon}", node
end

View File

@ -13,14 +13,8 @@ def request_matching trace=[], timestamps=[], options={}
end
params = (trace_params + defaults.merge(options).to_param).join('&')
params = nil if params==""
uri = URI.parse ["#{HOST}/match", params].compact.join('?')
@query = uri.to_s
Timeout.timeout(OSRM_TIMEOUT) do
Net::HTTP.get_response uri
end
rescue Errno::ECONNREFUSED => e
raise "*** osrm-routed is not running."
rescue Timeout::Error
raise "*** osrm-routed did not respond."
uri = generate_request_url ("match" + '?' + params)
response = send_request uri, trace, options, timestamps
end

View File

@ -1,17 +1,12 @@
require 'net/http'
def request_nearest_url path
def request_nearest_url path, node
@query = path
uri = URI.parse "#{HOST}/#{path}"
Timeout.timeout(OSRM_TIMEOUT) do
Net::HTTP.get_response uri
end
rescue Errno::ECONNREFUSED => e
raise "*** osrm-routed is not running."
rescue Timeout::Error
raise "*** osrm-routed did not respond."
uri = generate_request_url path
response = send_request uri, [node]
end
def request_nearest a
request_nearest_url "nearest?loc=#{a}"
def request_nearest node
request_nearest_url "nearest?loc=#{node.lat},#{node.lon}", node
end

View File

@ -15,15 +15,13 @@ def request_path path, waypoints=[], options={}
locs = waypoints.compact.map { |w| "loc=#{w.lat},#{w.lon}" }
params = (locs + options.to_param).join('&')
params = nil if params==""
uri = URI.parse ["#{HOST}/#{path}", params].compact.join('?')
@query = uri.to_s
Timeout.timeout(OSRM_TIMEOUT) do
Net::HTTP.get_response uri
if params == nil
uri = generate_request_url (path)
else
uri = generate_request_url (path + '?' + params)
end
rescue Errno::ECONNREFUSED => e
raise "*** osrm-routed is not running."
rescue Timeout::Error
raise "*** osrm-routed did not respond."
response = send_request uri, waypoints, options
end
def request_url path

View File

@ -173,3 +173,33 @@ Feature: Testbot - Handle ferry routes
| from | to | route | time |
| a | g | abcdefg | 23400s +-2 |
| g | a | abcdefg | 23400s +-2 |
@todo
Scenario: Testbot - Ferry duration formats
Given the node map
| a | c | e | g | i | k | m | o | q | s |
| b | d | f | h | j | l | n | p | r | t |
And the ways
| nodes | route | duration |
| ab | ferry | 0:01 |
| cd | ferry | 00:01 |
| ef | ferry | 1:00 |
| gh | ferry | 01:00 |
| ij | ferry | 02:20 |
| kl | ferry | 10:00 |
| mn | ferry | 100:00 |
| op | ferry | 1000:00 |
| qr | ferry | 10000:00 |
When I route I should get
| from | to | route | time |
| a | b | ab | 60s +-1 |
| c | d | cd | 60s +-1 |
| e | f | ef | 3600s +-1 |
| g | h | gh | 3600s +-1 |
| i | j | ij | 8400s +-1 |
| k | l | kl | 36000s +-1 |
| m | n | mn | 360000s +-1 |
| o | p | mn | 3600000s +-1 |
| q | r | mn | 36000000s +-1 |

View File

@ -4,6 +4,25 @@ Feature: Avoid weird loops caused by rounding errors
Background:
Given the profile "testbot"
Scenario: Weired sidestreet loops
Given the node map
| a | 1 | b | 2 | c | 3 | d |
| | | | | | | |
| e | | f | | g | | h |
And the ways
| nodes |
| aefghd |
| abcd |
| bf |
| cg |
When I route I should get
| waypoints | route | turns |
| a,1,d | abcd,abcd | head,via,destination |
| a,2,d | abcd,abcd | head,via,destination |
| a,3,d | abcd,abcd | head,via,destination |
Scenario: Avoid weird loops 1
Given the node locations
| node | lat | lon |

View File

@ -0,0 +1,100 @@
@post @testbot
Feature: POST request
Background:
Given the profile "testbot"
And the HTTP method "POST"
Scenario: Testbot - viaroute POST request
Given the node locations
| node | lat | lon |
| a | 55.68740 | 12.52430 |
| b | 55.68745 | 12.52409 |
| c | 55.68711 | 12.52383 |
| x | -55.68740 | 12.52430 |
| y | -55.68745 | 12.52409 |
| z | -55.68711 | 12.52383 |
And the ways
| nodes |
| ab |
| bc |
| xy |
| yz |
When I route I should get
| from | to | route | turns |
| a | c | ab,bc | head,left,destination |
| c | a | bc,ab | head,right,destination |
| x | z | xy,yz | head,right,destination |
| z | x | yz,xy | head,left,destination |
Scenario: Testbot - match POST request
Given the node map
| a | b | c | d |
| e | f | g | h |
And the ways
| nodes | oneway |
| abcd | yes |
| hgfe | yes |
When I match I should get
| trace | matchings |
| dcba | hgfe |
Scenario: Testbot - table POST request
Given the node map
| x | a | b | y |
| | d | e | |
And the ways
| nodes | oneway |
| abeda | yes |
| xa | |
| by | |
When I request a travel time matrix I should get
| | x | y | d | e |
| x | 0 | 300 | 400 | 300 |
| y | 500 | 0 | 300 | 200 |
| d | 200 | 300 | 0 | 300 |
| e | 300 | 400 | 100 | 0 |
Scenario: Testbot - locate POST request
Given the node locations
| node | lat | lon |
| a | -85 | -180 |
| b | 0 | 0 |
| c | 85 | 180 |
| x | -84 | -180 |
| y | 84 | 180 |
And the ways
| nodes |
| abc |
When I request locate I should get
| in | out |
| x | a |
| y | c |
Scenario: Testbot - nearest POST request
Given the node locations
| node | lat | lon |
| a | -85 | -180 |
| b | -85 | -160 |
| c | -85 | -140 |
| x | -84.999 | -180 |
| y | -84.999 | -160 |
| z | -84.999 | -140 |
And the ways
| nodes |
| abc |
When I request nearest I should get
| in | out |
| x | a |
| y | b |
| z | c |

View File

@ -98,30 +98,26 @@ Feature: Snap start/end point to the nearest way
| b | x | xb |
| c | x | xc |
Scenario: Find edges within 1km, and the same from 10km
Given a grid size of 1000 meters
Scenario: Find edges within 100m, and the same from 1km
Given a grid size of 100 meters
Given the node map
| p | | | | | | | | | | | i | | | | | | | | | | | j |
| | | | | | | | | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | | | | | | | | |
| | | | | | | | | | 8 | | 1 | | 2 | | | | | | | | | |
| | | | | | | | | | | h | a | b | | | | | | | | | | |
| o | | | | | | | | | 7 | g | x | c | 3 | | | | | | | | | k |
| | | | | | | | | | | f | e | d | | | | | | | | | | |
| | | | | | | | | | 6 | | 5 | | 4 | | | | | | | | | |
| | | | | | | | | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | | | | | | | | |
| n | | | | | | | | | | | m | | | | | | | | | | | l |
| p | | | | | | | | i | | | | | | | | j |
| | | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | | |
| | | | | | | 8 | | 1 | | 2 | | | | | | |
| | | | | | | | h | a | b | | | | | | | |
| o | | | | | | 7 | g | x | c | 3 | | | | | | k |
| | | | | | | | f | e | d | | | | | | | |
| | | | | | | 6 | | 5 | | 4 | | | | | | |
| | | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | | |
| n | | | | | | | | m | | | | | | | | l |
Given the ways
| nodes |

View File

@ -52,6 +52,21 @@ Feature: Via points
| a,c,f | ab,bcd,bcd,de,efg |
| a,c,f,h | ab,bcd,bcd,de,efg,efg,gh |
Scenario: Duplicate via point
Given the node map
| x | | | | | |
| a | 1 | 2 | 3 | 4 | b |
| | | | | | |
And the ways
| nodes |
| xa |
| ab |
When I route I should get
| waypoints | route | turns |
| 1,1,4 | ab,ab | head,via,destination |
Scenario: Via points on ring of oneways
# xa it to avoid only having a single ring, which cna trigger edge cases
Given the node map
@ -77,7 +92,6 @@ Feature: Via points
| 1,3,2 | ab,bc,cd,cd,de,ef,fa,ab,bc | 1600m +-1 | head,straight,straight,via,right,right,right,right,straight,destination |
| 3,2,1 | cd,de,ef,fa,ab,bc,bc,cd,de,ef,fa,ab | 2400m +-1 | head,right,right,right,right,straight,via,straight,right,right,right,right,destination |
@bug
Scenario: Via points on ring on the same oneway
# xa it to avoid only having a single ring, which cna trigger edge cases
Given the node map
@ -97,6 +111,6 @@ Feature: Via points
| waypoints | route | distance | turns |
| 1,3 | ab | 200m +-1 | head,destination |
| 3,1 | ab,bc,cd,da,ab | 800m +-1 | head,right,right,right,right,destination |
| 1,2,3 | ab | 200m +-1 | head,destination |
| 1,3,2 | ab,bc,cd,da,ab | 1100m +-1 | head,right,right,right,right,destination |
| 3,2,1 | ab,bc,cd,da,ab,bc,cd,da,ab | 1600m +-1 | head,right,right,right,right,right,right,right,right,destination |
| 1,2,3 | ab,ab | 200m +-1 | head,via,destination |
| 1,3,2 | ab,ab,bc,cd,da,ab | 1100m +-1 | head,via,right,right,right,right,destination |
| 3,2,1 | ab,bc,cd,da,ab,ab,bc,cd,da,ab | 1800m | head,right,right,right,right,via,right,right,right,right,destination |

View File

@ -79,6 +79,8 @@ struct RouteParameters
void addCoordinate(const boost::fusion::vector<double, double> &received_coordinates);
void getCoordinatesFromGeometry(const std::string geometry_string);
short zoom_level;
bool print_instructions;
bool alternate_route;

View File

@ -26,10 +26,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "contractor/processing_chain.hpp"
#include "contractor/contractor_options.hpp"
#include "util/simple_logger.hpp"
#include <boost/program_options/errors.hpp>
#include <tbb/task_scheduler_init.h>
#include <exception>
#include <ostream>
@ -37,21 +40,64 @@ int main(int argc, char *argv[])
{
try
{
return Prepare().Process(argc, argv);
}
catch (boost::program_options::too_many_positional_options_error &)
LogPolicy::GetInstance().Unmute();
ContractorConfig contractor_config;
const return_code result = ContractorOptions::ParseArguments(argc, argv, contractor_config);
if (return_code::fail == result)
{
SimpleLogger().Write(logWARNING) << "Only one file can be specified";
return 1;
}
catch (boost::program_options::error &e)
if (return_code::exit == result)
{
SimpleLogger().Write(logWARNING) << e.what();
return 0;
}
ContractorOptions::GenerateOutputFilesNames(contractor_config);
if (1 > contractor_config.requested_num_threads)
{
SimpleLogger().Write(logWARNING) << "Number of threads must be 1 or larger";
return 1;
}
const unsigned recommended_num_threads = tbb::task_scheduler_init::default_num_threads();
if (recommended_num_threads != contractor_config.requested_num_threads)
{
SimpleLogger().Write(logWARNING) << "The recommended number of threads is "
<< recommended_num_threads
<< "! This setting may have performance side-effects.";
}
if (!boost::filesystem::is_regular_file(contractor_config.osrm_input_path))
{
SimpleLogger().Write(logWARNING)
<< "Input file " << contractor_config.osrm_input_path.string() << " not found!";
return 1;
}
if (!boost::filesystem::is_regular_file(contractor_config.profile_path))
{
SimpleLogger().Write(logWARNING) << "Profile " << contractor_config.profile_path.string()
<< " not found!";
return 1;
}
SimpleLogger().Write() << "Input file: " << contractor_config.osrm_input_path.filename().string();
SimpleLogger().Write() << "Restrictions file: " << contractor_config.restrictions_path.filename().string();
SimpleLogger().Write() << "Profile: " << contractor_config.profile_path.filename().string();
SimpleLogger().Write() << "Threads: " << contractor_config.requested_num_threads;
tbb::task_scheduler_init init(contractor_config.requested_num_threads);
return Prepare(contractor_config).Run();
}
catch (const std::exception &e)
{
SimpleLogger().Write(logWARNING) << "Exception occured: " << e.what() << std::endl;
SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
return 1;
}
}

View File

@ -1,19 +1,21 @@
require("lib/access")
require("lib/maxspeed")
-- Bicycle profile
local find_access_tag = require("lib/access").find_access_tag
local limit = require("lib/maxspeed").limit
-- 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 }
access_tag_blacklist = { ["no"] = true, ["private"] = true, ["agricultural"] = true, ["forestery"] = true }
access_tag_blacklist = { ["no"] = true, ["private"] = true, ["agricultural"] = true, ["forestry"] = true }
access_tag_restricted = { ["destination"] = true, ["delivery"] = true }
access_tags_hierachy = { "bicycle", "vehicle", "access" }
cycleway_tags = {["track"]=true,["lane"]=true,["opposite"]=true,["opposite_lane"]=true,["opposite_track"]=true,["share_busway"]=true,["sharrow"]=true,["shared"]=true }
service_tag_restricted = { ["parking_aisle"] = true }
restriction_exception_tags = { "bicycle", "vehicle", "access" }
unsafe_highway_list = { ["primary"] = true, ["secondary"] = true, ["tertiary"] = true, ["primary_link"] = true, ["secondary_link"] = true, ["tertiary_link"] = true}
default_speed = 15
walking_speed = 6
local default_speed = 15
local walking_speed = 6
bicycle_speeds = {
["cycleway"] = default_speed,
@ -79,8 +81,7 @@ surface_speeds = {
["unpaved"] = 6,
["fine_gravel"] = 6,
["gravel"] = 6,
["fine_gravel"] = 6,
["pebbelstone"] = 6,
["pebblestone"] = 6,
["ground"] = 6,
["dirt"] = 6,
["earth"] = 6,
@ -89,24 +90,27 @@ surface_speeds = {
["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
traffic_signal_penalty = 2
use_turn_restrictions = false
turn_penalty = 60
turn_bias = 1.4
local obey_oneway = true
local obey_bollards = false
local ignore_areas = true
local u_turn_penalty = 20
local turn_penalty = 60
local turn_bias = 1.4
-- reduce the driving speed by 30% for unsafe roads
-- local safety_penalty = 0.7
local safety_penalty = 1.0
local use_public_transport = true
local fallback_names = true
--modes
mode_normal = 1
mode_pushing = 2
mode_ferry = 3
mode_train = 4
mode_movable_bridge = 5
local mode_normal = 1
local mode_pushing = 2
local mode_ferry = 3
local mode_train = 4
local mode_movable_bridge = 5
local function parse_maxspeed(source)
if not source then
@ -122,7 +126,6 @@ local function parse_maxspeed(source)
return n
end
function get_exceptions(vector)
for i,v in ipairs(restriction_exception_tags) do
vector:Add(v)
@ -130,28 +133,30 @@ function get_exceptions(vector)
end
function node_function (node, result)
local barrier = node:get_value_by_key("barrier")
local access = Access.find_access_tag(node, access_tags_hierachy)
local traffic_signal = node:get_value_by_key("highway")
-- flag node if it carries a traffic light
if traffic_signal and traffic_signal == "traffic_signals" then
result.traffic_lights = true
end
-- parse access and barrier tags
local highway = node:get_value_by_key("highway")
local is_crossing = highway and highway == "crossing"
local access = find_access_tag(node, access_tags_hierachy)
if access and access ~= "" then
if access_tag_blacklist[access] then
result.barrier = true
else
result.barrier = false
end
elseif barrier and barrier ~= "" then
if barrier_whitelist[barrier] then
result.barrier = false
else
-- access restrictions on crossing nodes are not relevant for
-- the traffic on the road
if access_tag_blacklist[access] and not is_crossing then
result.barrier = true
end
else
local barrier = node:get_value_by_key("barrier")
if barrier and "" ~= barrier then
if not barrier_whitelist[barrier] then
result.barrier = true
end
end
end
-- check if node is a traffic light
local tag = node:get_value_by_key("highway")
if tag and "traffic_signals" == tag then
result.traffic_lights = true;
end
end
@ -165,8 +170,8 @@ function way_function (way, result)
local public_transport = way:get_value_by_key("public_transport")
local bridge = way:get_value_by_key("bridge")
if (not highway or highway == '') and
(not route or route == '') and
(not railway or railway=='') and
(not use_public_transport or not route or route == '') and
(not use_public_transport or not railway or railway=='') and
(not amenity or amenity=='') and
(not man_made or man_made=='') and
(not public_transport or public_transport=='') and
@ -181,7 +186,7 @@ function way_function (way, result)
end
-- access
local access = Access.find_access_tag(way, access_tags_hierachy)
local access = find_access_tag(way, access_tags_hierachy)
if access and access_tag_blacklist[access] then
return
end
@ -213,7 +218,8 @@ function way_function (way, result)
result.name = ref
elseif name and "" ~= name then
result.name = name
elseif highway then
-- TODO find a better solution for encoding way type
elseif fallback_names and highway then
-- if no name exists, use way type
-- this encoding scheme is excepted to be a temporary solution
result.name = "{highway:"..highway.."}"
@ -246,15 +252,16 @@ function way_function (way, result)
result.forward_speed = route_speeds[route]
result.backward_speed = route_speeds[route]
end
elseif railway and platform_speeds[railway] then
-- public transport
elseif use_public_transport and railway and platform_speeds[railway] then
-- railway platforms (old tagging scheme)
result.forward_speed = platform_speeds[railway]
result.backward_speed = platform_speeds[railway]
elseif platform_speeds[public_transport] then
elseif use_public_transport and platform_speeds[public_transport] then
-- public_transport platforms (new tagging platform)
result.forward_speed = platform_speeds[public_transport]
result.backward_speed = platform_speeds[public_transport]
elseif railway and railway_speeds[railway] then
elseif use_public_transport and railway and railway_speeds[railway] then
result.forward_mode = mode_train
result.backward_mode = mode_train
-- railways
@ -270,6 +277,10 @@ function way_function (way, result)
-- regular ways
result.forward_speed = bicycle_speeds[highway]
result.backward_speed = bicycle_speeds[highway]
if safety_penalty < 1 and unsafe_highway_list[highway] then
result.forward_speed = result.forward_speed * safety_penalty
result.backward_speed = result.backward_speed * safety_penalty
end
elseif access and access_tag_whitelist[access] then
-- unknown way, but valid access tag
result.forward_speed = default_speed
@ -391,7 +402,7 @@ function way_function (way, result)
end
-- maxspeed
MaxSpeed.limit( result, maxspeed, maxspeed_forward, maxspeed_backward )
limit( result, maxspeed, maxspeed_forward, maxspeed_backward )
end
function turn_function (angle)

View File

@ -1,6 +1,8 @@
-- Begin of globals
--require("lib/access") --function temporarily inlined
-- Car profile
local find_access_tag = require("lib/access").find_access_tag
-- Begin of globals
barrier_whitelist = { ["cattle_grid"] = true, ["border_control"] = true, ["checkpoint"] = true, ["toll_booth"] = true, ["sally_port"] = true, ["gate"] = true, ["lift_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, ["psv"] = true }
@ -130,10 +132,9 @@ maxspeed_table = {
traffic_signal_penalty = 2
use_turn_restrictions = true
local take_minimum_of_speeds = false
local obey_oneway = true
local obey_bollards = true
local ignore_areas = true -- future feature
local ignore_areas = true
local u_turn_penalty = 20
local abs = math.abs
@ -147,16 +148,6 @@ local mode_normal = 1
local mode_ferry = 2
local mode_movable_bridge = 3
local function find_access_tag(source, access_tags_hierachy)
for i,v in ipairs(access_tags_hierachy) do
local access_tag = source:get_value_by_key(v)
if access_tag and "" ~= access_tag then
return access_tag
end
end
return ""
end
function get_exceptions(vector)
for i,v in ipairs(restriction_exception_tags) do
vector:Add(v)
@ -187,6 +178,7 @@ local function parse_maxspeed(source)
return n
end
-- FIXME Why was this commented out?
-- function turn_function (angle)
-- -- print ("called at angle " .. angle )
-- local index = math.abs(math.floor(angle/10+0.5))+1 -- +1 'coz LUA starts as idx 1
@ -198,7 +190,7 @@ end
function node_function (node, result)
-- parse access and barrier tags
local access = find_access_tag(node, access_tags_hierachy)
if access ~= "" then
if access and access ~= "" then
if access_tag_blacklist[access] then
result.barrier = true
end
@ -249,12 +241,6 @@ function way_function (way, result)
return
end
local width = math.huge
local width_string = way:get_value_by_key("width")
if width_string and tonumber(width_string:match("%d*")) then
width = tonumber(width_string:match("%d*"))
end
-- Check if we are allowed to access the way
local access = find_access_tag(way, access_tags_hierachy)
if access_tag_blacklist[access] then
@ -353,9 +339,14 @@ function way_function (way, result)
local service = way:get_value_by_key("service")
-- Set the name that will be used for instructions
if ref and "" ~= ref then
local has_ref = ref and "" ~= ref
local has_name = name and "" ~= name
if has_name and has_ref then
result.name = name .. " (" .. ref .. ")"
elseif has_ref then
result.name = ref
elseif name and "" ~= name then
elseif has_name then
result.name = name
-- else
-- result.name = highway -- if no name exists, use way type
@ -407,12 +398,25 @@ function way_function (way, result)
result.ignore_in_grid = true
end
local width = math.huge
local lanes = math.huge
if result.forward_speed > 0 or result.backward_speed > 0 then
local width_string = way:get_value_by_key("width")
if width_string and tonumber(width_string:match("%d*")) then
width = tonumber(width_string:match("%d*"))
end
local lanes_string = way:get_value_by_key("lanes")
if lanes_string and tonumber(lanes_string:match("%d*")) then
lanes = tonumber(lanes_string:match("%d*"))
end
end
-- scale speeds to get better avg driving times
if result.forward_speed > 0 then
local scaled_speed = result.forward_speed*speed_reduction + 11;
local penalized_speed = math.huge
if width <= 3 then
if width <= 3 or lanes <= 1 then
penalized_speed = result.forward_speed / 2;
end
result.forward_speed = math.min(penalized_speed, scaled_speed)
@ -421,16 +425,10 @@ function way_function (way, result)
if result.backward_speed > 0 then
local scaled_speed = result.backward_speed*speed_reduction + 11;
local penalized_speed = math.huge
if width <= 3 then
if width <= 3 or lanes <= 1 then
penalized_speed = result.backward_speed / 2;
end
result.backward_speed = math.min(penalized_speed, scaled_speed)
end
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

View File

@ -1,10 +1,11 @@
-- Foot profile
require("lib/access")
local find_access_tag = require("lib/access").find_access_tag
-- 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, ["foot"] = true, ["permissive"] = true, ["designated"] = true }
access_tag_blacklist = { ["no"] = true, ["private"] = true, ["agricultural"] = true, ["forestery"] = true }
access_tag_blacklist = { ["no"] = true, ["private"] = true, ["agricultural"] = true, ["forestry"] = true }
access_tag_restricted = { ["destination"] = true, ["delivery"] = true }
access_tags_hierachy = { "foot", "access" }
service_tag_restricted = { ["parking_aisle"] = true }
@ -54,11 +55,15 @@ man_made_speeds = {
surface_speeds = {
["fine_gravel"] = walking_speed*0.75,
["gravel"] = walking_speed*0.75,
["pebbelstone"] = walking_speed*0.75,
["pebblestone"] = walking_speed*0.75,
["mud"] = walking_speed*0.5,
["sand"] = walking_speed*0.5
}
leisure_speeds = {
["track"] = walking_speed
}
traffic_signal_penalty = 2
u_turn_penalty = 2
use_turn_restrictions = false
@ -75,7 +80,7 @@ end
function node_function (node, result)
local barrier = node:get_value_by_key("barrier")
local access = Access.find_access_tag(node, access_tags_hierachy)
local access = find_access_tag(node, access_tags_hierachy)
local traffic_signal = node:get_value_by_key("highway")
-- flag node if it carries a traffic light
@ -104,12 +109,14 @@ end
function way_function (way, result)
-- initial routability check, filters out buildings, boundaries, etc
local highway = way:get_value_by_key("highway")
local leisure = way:get_value_by_key("leisure")
local route = way:get_value_by_key("route")
local man_made = way:get_value_by_key("man_made")
local railway = way:get_value_by_key("railway")
local amenity = way:get_value_by_key("amenity")
local public_transport = way:get_value_by_key("public_transport")
if (not highway or highway == '') and
(not leisure or leisure == '') and
(not route or route == '') and
(not railway or railway=='') and
(not amenity or amenity=='') and
@ -125,7 +132,7 @@ function way_function (way, result)
end
-- access
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
@ -181,6 +188,10 @@ function way_function (way, result)
-- parking areas
result.forward_speed = amenity_speeds[amenity]
result.backward_speed = amenity_speeds[amenity]
elseif leisure and leisure_speeds[leisure] then
-- running tracks
result.forward_speed = leisure_speeds[leisure]
result.backward_speed = leisure_speeds[leisure]
elseif speeds[highway] then
-- regular ways
result.forward_speed = speeds[highway]

View File

@ -1,13 +1,15 @@
local ipairs = ipairs
module "Access"
local Access = {}
function find_access_tag(source,access_tags_hierachy)
function Access.find_access_tag(source,access_tags_hierachy)
for i,v in ipairs(access_tags_hierachy) do
local tag = source:get_value_by_key(v)
if tag and tag ~= '' then
return tag
end
end
return nil
return ""
end
return Access

View File

@ -1,8 +1,8 @@
local math = math
module "MaxSpeed"
local MaxSpeed = {}
function limit(way,max,maxf,maxb)
function MaxSpeed.limit(way,max,maxf,maxb)
if maxf and maxf>0 then
way.forward_speed = math.min(way.forward_speed, maxf)
elseif max and max>0 then
@ -15,3 +15,5 @@ function limit(way,max,maxf,maxb)
way.backward_speed = math.min(way.backward_speed, max)
end
end
return MaxSpeed

View File

@ -103,8 +103,8 @@ class AlternativeRouting final
int upper_bound_to_shortest_path_distance = INVALID_EDGE_WEIGHT;
NodeID middle_node = SPECIAL_NODEID;
const EdgeWeight min_edge_offset =
std::min(phantom_node_pair.source_phantom.GetForwardWeightPlusOffset(),
phantom_node_pair.source_phantom.GetReverseWeightPlusOffset());
std::min(-phantom_node_pair.source_phantom.GetForwardWeightPlusOffset(),
-phantom_node_pair.source_phantom.GetReverseWeightPlusOffset());
if (phantom_node_pair.source_phantom.forward_node_id != SPECIAL_NODEID)
{

View File

@ -93,8 +93,8 @@ class ShortestPathRouting final
const bool allow_u_turn = current_leg > 0 && uturn_indicators.size() > current_leg &&
uturn_indicators[current_leg - 1];
const EdgeWeight min_edge_offset =
std::min(phantom_node_pair.source_phantom.GetForwardWeightPlusOffset(),
phantom_node_pair.source_phantom.GetReverseWeightPlusOffset());
std::min(-phantom_node_pair.source_phantom.GetForwardWeightPlusOffset(),
-phantom_node_pair.source_phantom.GetReverseWeightPlusOffset());
// insert new starting nodes into forward heap, adjusted by previous distances.
if ((allow_u_turn || search_from_1st_node) &&
@ -272,11 +272,13 @@ class ShortestPathRouting final
if (start_id_of_leg1 != last_id_of_packed_legs1)
{
packed_legs1 = packed_legs2;
distance1 = distance2;
BOOST_ASSERT(start_id_of_leg1 == temporary_packed_leg1.front());
}
else if (start_id_of_leg2 != last_id_of_packed_legs2)
{
packed_legs2 = packed_legs1;
distance2 = distance1;
BOOST_ASSERT(start_id_of_leg2 == temporary_packed_leg2.front());
}
}

View File

@ -42,7 +42,7 @@ template <typename Iterator, class HandlerT> struct APIGrammar : qi::grammar<Ite
*(query) >> -(uturns);
query = ('?') >> (+(zoom | output | jsonp | checksum | location | hint | timestamp | u | cmp |
language | instruction | geometry | alt_route | old_API | num_results |
matching_beta | gps_precision | classify));
matching_beta | gps_precision | classify | locs));
zoom = (-qi::lit('&')) >> qi::lit('z') >> '=' >>
qi::short_[boost::bind(&HandlerT::setZoomLevel, handler, ::_1)];
@ -83,17 +83,20 @@ template <typename Iterator, class HandlerT> struct APIGrammar : qi::grammar<Ite
qi::short_[boost::bind(&HandlerT::setGPSPrecision, handler, ::_1)];
classify = (-qi::lit('&')) >> qi::lit("classify") >> '=' >>
qi::bool_[boost::bind(&HandlerT::setClassify, handler, ::_1)];
locs = (-qi::lit('&')) >> qi::lit("locs") >> '=' >>
stringforPolyline[boost::bind(&HandlerT::getCoordinatesFromGeometry, handler, ::_1)];
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")));
stringforPolyline = +(qi::char_("a-zA-Z0-9_.-[]{}@?|\\%~`^"));
}
qi::rule<Iterator> api_call, query;
qi::rule<Iterator, std::string()> service, zoom, output, string, jsonp, checksum, location,
hint, timestamp, stringwithDot, stringwithPercent, language, instruction, geometry, cmp, alt_route, u,
uturns, old_API, num_results, matching_beta, gps_precision, classify;
uturns, old_API, num_results, matching_beta, gps_precision, classify, locs, stringforPolyline;
HandlerT *handler;
};

View File

@ -42,7 +42,8 @@ namespace http
RequestParser::RequestParser()
: state(internal_state::method_start), current_header({"", ""}),
selected_compression(no_compression)
selected_compression(no_compression), is_post_header(false),
content_length(0)
{
}
@ -58,6 +59,11 @@ RequestParser::parse(request &current_request, char *begin, char *end)
}
}
osrm::tribool result = osrm::tribool::indeterminate;
if(state == internal_state::post_request && content_length <= 0)
{
result = osrm::tribool::yes;
}
return std::make_tuple(result, selected_compression);
}
@ -70,8 +76,39 @@ osrm::tribool RequestParser::consume(request &current_request, const char input)
{
return osrm::tribool::no;
}
if(input == 'P')
{
state = internal_state::post_O;
return osrm::tribool::indeterminate;
}
state = internal_state::method;
return osrm::tribool::indeterminate;
case internal_state::post_O:
if(input == 'O')
{
state = internal_state::post_S;
return osrm::tribool::indeterminate;
}
return osrm::tribool::no;
case internal_state::post_S:
if(input == 'S')
{
state = internal_state::post_T;
return osrm::tribool::indeterminate;
}
return osrm::tribool::no;
case internal_state::post_T:
if(input == 'T')
{
is_post_header = true;
state = internal_state::method;
return osrm::tribool::indeterminate;
}
return osrm::tribool::no;
case internal_state::post_request:
current_request.uri.push_back(input);
--content_length;
return osrm::tribool::indeterminate;
case internal_state::method:
if (input == ' ')
{
@ -204,6 +241,24 @@ osrm::tribool RequestParser::consume(request &current_request, const char input)
{
current_request.agent = current_header.value;
}
if (boost::iequals(current_header.name, "Content-Length"))
{
try
{
content_length = std::stoi(current_header.value);
}
catch (const std::exception &e)
{
// Ignore the header if the parameter isn't an int
}
}
if (boost::iequals(current_header.name, "Content-Type"))
{
if (!boost::icontains(current_header.value, "application/x-www-form-urlencoded"))
{
return osrm::tribool::no;
}
}
if (input == '\r')
{
@ -272,7 +327,19 @@ osrm::tribool RequestParser::consume(request &current_request, const char input)
return osrm::tribool::indeterminate;
}
return osrm::tribool::no;
default: // expecting_newline_3
case internal_state::expecting_newline_3:
if(input == '\n')
{
if(is_post_header)
{
current_request.uri.push_back('?');
state = internal_state::post_request;
return osrm::tribool::indeterminate;
}
return osrm::tribool::yes;
}
return osrm::tribool::no;
default: // should never be reached
return input == '\n' ? osrm::tribool::yes : osrm::tribool::no;
}
}

View File

@ -80,11 +80,17 @@ class RequestParser
space_before_header_value,
header_value,
expecting_newline_2,
expecting_newline_3
expecting_newline_3,
post_O,
post_S,
post_T,
post_request
} state;
header current_header;
compression_type selected_compression;
bool is_post_header;
int content_length;
};
} // namespace http

View File

@ -76,80 +76,41 @@ void DeleteFileIfExists(const std::string &file_name)
}
}
int main(int argc, char *argv[])
void LoadRestrictions(const char* path, std::vector<TurnRestriction>& restriction_list)
{
std::vector<QueryNode> coordinate_list;
std::vector<TurnRestriction> restriction_list;
std::vector<NodeID> bollard_node_list;
std::vector<NodeID> traffic_lights_list;
LogPolicy::GetInstance().Unmute();
try
std::ifstream input_stream(path, std::ios::binary);
if (!input_stream.is_open())
{
// enable logging
if (argc < 3)
{
SimpleLogger().Write(logWARNING) << "usage:\n" << argv[0]
<< " <osrm> <osrm.restrictions>";
return -1;
throw osrm::exception("Cannot open restriction file");
}
loadRestrictionsFromFile(input_stream, restriction_list);
}
SimpleLogger().Write() << "Using restrictions from file: " << argv[2];
std::ifstream restriction_ifstream(argv[2], std::ios::binary);
const FingerPrint fingerprint_orig;
FingerPrint fingerprint_loaded;
restriction_ifstream.read(reinterpret_cast<char *>(&fingerprint_loaded),
sizeof(FingerPrint));
// check fingerprint and warn if necessary
if (!fingerprint_loaded.TestGraphUtil(fingerprint_orig))
std::size_t LoadGraph(const char* path,
std::vector<QueryNode>& coordinate_list,
std::vector<NodeID>& barrier_node_list,
std::vector<TarjanEdge>& graph_edge_list)
{
SimpleLogger().Write(logWARNING) << argv[2] << " was prepared with a different build. "
"Reprocess to get rid of this warning.";
}
if (!restriction_ifstream.good())
{
throw osrm::exception("Could not access <osrm-restrictions> files");
}
uint32_t usable_restrictions = 0;
restriction_ifstream.read(reinterpret_cast<char *>(&usable_restrictions), sizeof(uint32_t));
restriction_list.resize(usable_restrictions);
// load restrictions
if (usable_restrictions > 0)
{
restriction_ifstream.read(reinterpret_cast<char *>(&restriction_list[0]),
usable_restrictions * sizeof(TurnRestriction));
}
restriction_ifstream.close();
std::ifstream input_stream(argv[1], std::ifstream::in | std::ifstream::binary);
std::ifstream input_stream(path, std::ifstream::in | std::ifstream::binary);
if (!input_stream.is_open())
{
throw osrm::exception("Cannot open osrm file");
}
// load graph data
std::vector<ImportEdge> edge_list;
const NodeID number_of_nodes =
readBinaryOSRMGraphFromStream(input_stream, edge_list, bollard_node_list,
traffic_lights_list, &coordinate_list, restriction_list);
input_stream.close();
std::vector<NodeBasedEdge> edge_list;
std::vector<NodeID> traffic_light_node_list;
BOOST_ASSERT_MSG(restriction_list.size() == usable_restrictions,
"size of restriction_list changed");
auto number_of_nodes = loadNodesFromFile(input_stream, barrier_node_list,
traffic_light_node_list,
coordinate_list);
SimpleLogger().Write() << restriction_list.size() << " restrictions, "
<< bollard_node_list.size() << " bollard nodes, "
<< traffic_lights_list.size() << " traffic lights";
loadEdgesFromFile(input_stream, edge_list);
traffic_lights_list.clear();
traffic_lights_list.shrink_to_fit();
traffic_light_node_list.clear();
traffic_light_node_list.shrink_to_fit();
// Building an node-based graph
std::vector<TarjanEdge> graph_edge_list;
// DeallocatingVector<TarjanEdge> graph_edge_list;
for (const auto &input_edge : edge_list)
{
if (input_edge.source == input_edge.target)
@ -168,10 +129,32 @@ int main(int argc, char *argv[])
(std::max)(input_edge.weight, 1), input_edge.name_id);
}
}
edge_list.clear();
edge_list.shrink_to_fit();
BOOST_ASSERT_MSG(0 == edge_list.size() && 0 == edge_list.capacity(),
"input edge vector not properly deallocated");
return number_of_nodes;
}
int main(int argc, char *argv[])
{
std::vector<QueryNode> coordinate_list;
std::vector<TurnRestriction> restriction_list;
std::vector<NodeID> barrier_node_list;
LogPolicy::GetInstance().Unmute();
try
{
// enable logging
if (argc < 3)
{
SimpleLogger().Write(logWARNING) << "usage:\n" << argv[0]
<< " <osrm> <osrm.restrictions>";
return -1;
}
SimpleLogger().Write() << "Using restrictions from file: " << argv[2];
std::vector<TarjanEdge> graph_edge_list;
auto number_of_nodes = LoadGraph(argv[1], coordinate_list, barrier_node_list, graph_edge_list);
LoadRestrictions(argv[2], restriction_list);
tbb::parallel_sort(graph_edge_list.begin(), graph_edge_list.end());
const auto graph = std::make_shared<TarjanGraph>(number_of_nodes, graph_edge_list);
@ -181,9 +164,8 @@ int main(int argc, char *argv[])
SimpleLogger().Write() << "Starting SCC graph traversal";
RestrictionMap restriction_map(restriction_list);
auto tarjan = osrm::make_unique<TarjanSCC<TarjanGraph>>(graph,
restriction_map,
bollard_node_list);
auto tarjan = osrm::make_unique<TarjanSCC<TarjanGraph>>(graph, restriction_map,
barrier_node_list);
tarjan->run();
SimpleLogger().Write() << "identified: " << tarjan->get_number_of_components()
<< " many components";

View File

@ -1,199 +0,0 @@
#include "../data_structures/dynamic_graph.hpp"
#include "../data_structures/import_edge.hpp"
#include "../data_structures/query_node.hpp"
#include "../data_structures/restriction.hpp"
#include "../data_structures/static_graph.hpp"
#include "../util/fingerprint.hpp"
#include "../util/graph_loader.hpp"
#include "../util/integer_range.hpp"
#include "../util/make_unique.hpp"
#include "../util/osrm_exception.hpp"
#include "../util/simple_logger.hpp"
#include "../typedefs.h"
#include <algorithm>
#include <fstream>
struct TarjanEdgeData
{
TarjanEdgeData() : distance(INVALID_EDGE_WEIGHT), name_id(INVALID_NAMEID) {}
TarjanEdgeData(unsigned distance, unsigned name_id) : distance(distance), name_id(name_id) {}
unsigned distance;
unsigned name_id;
};
using StaticTestGraph = StaticGraph<TarjanEdgeData>;
using DynamicTestGraph = StaticGraph<TarjanEdgeData>;
using StaticEdge = StaticTestGraph::InputEdge;
using DynamicEdge = DynamicTestGraph::InputEdge;
int main(int argc, char *argv[])
{
std::vector<QueryNode> coordinate_list;
std::vector<TurnRestriction> restriction_list;
std::vector<NodeID> bollard_node_list;
std::vector<NodeID> traffic_lights_list;
LogPolicy::GetInstance().Unmute();
try
{
// enable logging
if (argc < 3)
{
SimpleLogger().Write(logWARNING) << "usage:\n" << argv[0]
<< " <osrm> <osrm.restrictions>";
return -1;
}
SimpleLogger().Write() << "Using restrictions from file: " << argv[2];
std::ifstream restriction_ifstream(argv[2], std::ios::binary);
const FingerPrint fingerprint_orig;
FingerPrint fingerprint_loaded;
restriction_ifstream.read(reinterpret_cast<char *>(&fingerprint_loaded),
sizeof(FingerPrint));
// check fingerprint and warn if necessary
if (!fingerprint_loaded.TestGraphUtil(fingerprint_orig))
{
SimpleLogger().Write(logWARNING) << argv[2] << " was prepared with a different build. "
"Reprocess to get rid of this warning.";
}
if (!restriction_ifstream.good())
{
throw osrm::exception("Could not access <osrm-restrictions> files");
}
uint32_t usable_restrictions = 0;
restriction_ifstream.read(reinterpret_cast<char *>(&usable_restrictions), sizeof(uint32_t));
restriction_list.resize(usable_restrictions);
// load restrictions
if (usable_restrictions > 0)
{
restriction_ifstream.read(reinterpret_cast<char *>(&restriction_list[0]),
usable_restrictions * sizeof(TurnRestriction));
}
restriction_ifstream.close();
std::ifstream input_stream(argv[1], std::ifstream::in | std::ifstream::binary);
if (!input_stream.is_open())
{
throw osrm::exception("Cannot open osrm file");
}
// load graph data
std::vector<ImportEdge> edge_list;
const NodeID number_of_nodes =
readBinaryOSRMGraphFromStream(input_stream, edge_list, bollard_node_list,
traffic_lights_list, &coordinate_list, restriction_list);
input_stream.close();
BOOST_ASSERT_MSG(restriction_list.size() == usable_restrictions,
"size of restriction_list changed");
SimpleLogger().Write() << restriction_list.size() << " restrictions, "
<< bollard_node_list.size() << " bollard nodes, "
<< traffic_lights_list.size() << " traffic lights";
traffic_lights_list.clear();
traffic_lights_list.shrink_to_fit();
// Building an node-based graph
std::vector<StaticEdge> static_graph_edge_list;
std::vector<DynamicEdge> dynamic_graph_edge_list;
for (const auto &input_edge : edge_list)
{
if (input_edge.source == input_edge.target)
{
continue;
}
if (input_edge.forward)
{
static_graph_edge_list.emplace_back(input_edge.source, input_edge.target,
(std::max)(input_edge.weight, 1),
input_edge.name_id);
dynamic_graph_edge_list.emplace_back(input_edge.source, input_edge.target,
(std::max)(input_edge.weight, 1),
input_edge.name_id);
}
if (input_edge.backward)
{
dynamic_graph_edge_list.emplace_back(input_edge.target, input_edge.source,
(std::max)(input_edge.weight, 1),
input_edge.name_id);
static_graph_edge_list.emplace_back(input_edge.target, input_edge.source,
(std::max)(input_edge.weight, 1),
input_edge.name_id);
}
}
edge_list.clear();
edge_list.shrink_to_fit();
BOOST_ASSERT_MSG(0 == edge_list.size() && 0 == edge_list.capacity(),
"input edge vector not properly deallocated");
tbb::parallel_sort(static_graph_edge_list.begin(), static_graph_edge_list.end());
tbb::parallel_sort(dynamic_graph_edge_list.begin(), dynamic_graph_edge_list.end());
auto static_graph =
osrm::make_unique<StaticTestGraph>(number_of_nodes, static_graph_edge_list);
auto dynamic_graph =
osrm::make_unique<DynamicTestGraph>(number_of_nodes, dynamic_graph_edge_list);
SimpleLogger().Write() << "Starting static/dynamic graph comparison";
BOOST_ASSERT(static_graph->GetNumberOfNodes() == dynamic_graph->GetNumberOfNodes());
BOOST_ASSERT(static_graph->GetNumberOfEdges() == dynamic_graph->GetNumberOfEdges());
for (const auto node : osrm::irange(0u, static_graph->GetNumberOfNodes()))
{
const auto static_range = static_graph->GetAdjacentEdgeRange(node);
const auto dynamic_range = dynamic_graph->GetAdjacentEdgeRange(node);
SimpleLogger().Write() << "checking node " << node << "/"
<< static_graph->GetNumberOfNodes();
BOOST_ASSERT(static_range.size() == dynamic_range.size());
const auto static_begin = static_graph->BeginEdges(node);
const auto dynamic_begin = dynamic_graph->BeginEdges(node);
// check raw interface
for (const auto i : osrm::irange(0u, static_range.size()))
{
const auto static_target = static_graph->GetTarget(static_begin + i);
const auto dynamic_target = dynamic_graph->GetTarget(dynamic_begin + i);
BOOST_ASSERT(static_target == dynamic_target);
const auto static_data = static_graph->GetEdgeData(static_begin + i);
const auto dynamic_data = dynamic_graph->GetEdgeData(dynamic_begin + i);
BOOST_ASSERT(static_data.distance == dynamic_data.distance);
BOOST_ASSERT(static_data.name_id == dynamic_data.name_id);
}
// check range interface
std::vector<EdgeID> static_target_ids, dynamic_target_ids;
std::vector<TarjanEdgeData> static_edge_data, dynamic_edge_data;
for (const auto static_id : static_range)
{
static_target_ids.push_back(static_graph->GetTarget(static_id));
static_edge_data.push_back(static_graph->GetEdgeData(static_id));
}
for (const auto dynamic_id : dynamic_range)
{
dynamic_target_ids.push_back(dynamic_graph->GetTarget(dynamic_id));
dynamic_edge_data.push_back(dynamic_graph->GetEdgeData(dynamic_id));
}
BOOST_ASSERT(static_target_ids.size() == dynamic_target_ids.size());
BOOST_ASSERT(std::equal(std::begin(static_target_ids), std::end(static_target_ids),
std::begin(dynamic_target_ids)));
}
SimpleLogger().Write() << "Graph comparison finished successfully";
}
catch (const std::exception &e)
{
SimpleLogger().Write(logWARNING) << "[exception] " << e.what();
}
return 0;
}

View File

@ -41,24 +41,24 @@ BOOST_AUTO_TEST_CASE(all_necessary_test)
BOOST_AUTO_TEST_CASE(common_durations_get_translated)
{
BOOST_CHECK_EQUAL(parseDuration("00:01"), 600);
BOOST_CHECK_EQUAL(parseDuration("00:01:01"), 610);
BOOST_CHECK_EQUAL(parseDuration("01:01"), 36600);
BOOST_CHECK_EQUAL(parseDuration("00:01"), 60);
BOOST_CHECK_EQUAL(parseDuration("00:01:01"), 61);
BOOST_CHECK_EQUAL(parseDuration("01:01"), 3660);
// check all combinations of iso duration tokens
BOOST_CHECK_EQUAL(parseDuration("PT1M1S"), 610);
BOOST_CHECK_EQUAL(parseDuration("PT1H1S"), 36010);
BOOST_CHECK_EQUAL(parseDuration("PT15M"), 9000);
BOOST_CHECK_EQUAL(parseDuration("PT15S"), 150);
BOOST_CHECK_EQUAL(parseDuration("PT15H"), 540000);
BOOST_CHECK_EQUAL(parseDuration("PT1H15M"), 45000);
BOOST_CHECK_EQUAL(parseDuration("PT1H15M1S"), 45010);
BOOST_CHECK_EQUAL(parseDuration("PT1M1S"), 61);
BOOST_CHECK_EQUAL(parseDuration("PT1H1S"), 3601);
BOOST_CHECK_EQUAL(parseDuration("PT15M"), 900);
BOOST_CHECK_EQUAL(parseDuration("PT15S"), 15);
BOOST_CHECK_EQUAL(parseDuration("PT15H"), 54000);
BOOST_CHECK_EQUAL(parseDuration("PT1H15M"), 4500);
BOOST_CHECK_EQUAL(parseDuration("PT1H15M1S"), 4501);
}
BOOST_AUTO_TEST_CASE(iso_8601_durations_case_insensitive)
{
BOOST_CHECK_EQUAL(parseDuration("PT15m"), 9000);
BOOST_CHECK_EQUAL(parseDuration("PT1h15m"), 45000);
BOOST_CHECK_EQUAL(parseDuration("PT15m"), 900);
BOOST_CHECK_EQUAL(parseDuration("PT1h15m"), 4500);
}
BOOST_AUTO_TEST_SUITE_END()

View File

@ -0,0 +1,74 @@
/*
Copyright (c) 2015, Project OSRM contributors
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 <boost/test/floating_point_comparison.hpp>
#include <boost/test/unit_test.hpp>
#include "../../algorithms/polyline_compressor.hpp"
#include "../../data_structures/coordinate_calculation.hpp"
#include <osrm/coordinate.hpp>
#include <cmath>
#include <vector>
BOOST_AUTO_TEST_CASE(geometry_string)
{
// Polyline string for the 5 coordinates
const std::string polyline = "_gjaR_gjaR_pR_ibE_pR_ibE_pR_ibE_pR_ibE";
PolylineCompressor pc;
std::vector<FixedPointCoordinate> coords = pc.decode_string(polyline);
// Test coordinates; these would be the coordinates we give the loc parameter,
// e.g. loc=10.00,10.0&loc=10.01,10.1...
FixedPointCoordinate coord1(10.00 * COORDINATE_PRECISION, 10.0 * COORDINATE_PRECISION);
FixedPointCoordinate coord2(10.01 * COORDINATE_PRECISION, 10.1 * COORDINATE_PRECISION);
FixedPointCoordinate coord3(10.02 * COORDINATE_PRECISION, 10.2 * COORDINATE_PRECISION);
FixedPointCoordinate coord4(10.03 * COORDINATE_PRECISION, 10.3 * COORDINATE_PRECISION);
FixedPointCoordinate coord5(10.04 * COORDINATE_PRECISION, 10.4 * COORDINATE_PRECISION);
// Put the test coordinates into the vector for comparison
std::vector<FixedPointCoordinate> cmp_coords;
cmp_coords.emplace_back(coord1);
cmp_coords.emplace_back(coord2);
cmp_coords.emplace_back(coord3);
cmp_coords.emplace_back(coord4);
cmp_coords.emplace_back(coord5);
BOOST_CHECK_EQUAL(cmp_coords.size(), coords.size());
for(unsigned i = 0; i < cmp_coords.size(); ++i)
{
const double cmp1_lat = coords.at(i).lat;
const double cmp2_lat = cmp_coords.at(i).lat;
BOOST_CHECK_CLOSE(cmp1_lat, cmp2_lat, 0.0001);
const double cmp1_lon = coords.at(i).lon;
const double cmp2_lon = cmp_coords.at(i).lon;
BOOST_CHECK_CLOSE(cmp1_lon, cmp2_lon, 0.0001);
}
}

View File

@ -29,23 +29,22 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define FINGERPRINT_H
#include <boost/uuid/uuid.hpp>
#include <type_traits>
// implements a singleton, i.e. there is one and only one conviguration object
class FingerPrint
{
public:
FingerPrint();
FingerPrint(const FingerPrint &) = delete;
~FingerPrint();
static FingerPrint GetValid();
const boost::uuids::uuid &GetFingerPrint() const;
bool IsMagicNumberOK() const;
bool IsMagicNumberOK(const FingerPrint &other) const;
bool TestGraphUtil(const FingerPrint &other) const;
bool TestPrepare(const FingerPrint &other) const;
bool TestRTree(const FingerPrint &other) const;
bool TestQueryObjects(const FingerPrint &other) const;
private:
const unsigned magic_number;
unsigned magic_number;
char md5_prepare[33];
char md5_tree[33];
char md5_graph[33];
@ -54,6 +53,10 @@ class FingerPrint
// initialize to {6ba7b810-9dad-11d1-80b4-00c04fd430c8}
boost::uuids::uuid named_uuid;
bool has_64_bits;
};
static_assert(std::is_trivial<FingerPrint>::value, "FingerPrint needs to be trivial.");
#endif /* FingerPrint_H */

View File

@ -40,35 +40,38 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#cmakedefine MD5GRAPH "${MD5GRAPH}"
#cmakedefine MD5OBJECTS "${MD5OBJECTS}"
FingerPrint::FingerPrint() : magic_number(1297240911)
FingerPrint FingerPrint::GetValid()
{
md5_prepare[32] = md5_tree[32] = md5_graph[32] = md5_objects[32] = '\0';
FingerPrint fingerprint;
boost::uuids::name_generator gen(named_uuid);
fingerprint.magic_number = 1297240911;
fingerprint.md5_prepare[32] = fingerprint.md5_tree[32] = fingerprint.md5_graph[32] = fingerprint.md5_objects[32] = '\0';
boost::uuids::name_generator gen(fingerprint.named_uuid);
std::string temp_string;
std::memcpy(md5_prepare, MD5PREPARE, strlen(MD5PREPARE));
temp_string += md5_prepare;
std::memcpy(md5_tree, MD5RTREE, 32);
temp_string += md5_tree;
std::memcpy(md5_graph, MD5GRAPH, 32);
temp_string += md5_graph;
std::memcpy(md5_objects, MD5OBJECTS, 32);
temp_string += md5_objects;
std::memcpy(fingerprint.md5_prepare, MD5PREPARE, 32);
temp_string += fingerprint.md5_prepare;
std::memcpy(fingerprint.md5_tree, MD5RTREE, 32);
temp_string += fingerprint.md5_tree;
std::memcpy(fingerprint.md5_graph, MD5GRAPH, 32);
temp_string += fingerprint.md5_graph;
std::memcpy(fingerprint.md5_objects, MD5OBJECTS, 32);
temp_string += fingerprint.md5_objects;
named_uuid = gen(temp_string);
has_64_bits = HAS64BITS;
fingerprint.named_uuid = gen(temp_string);
fingerprint.has_64_bits = HAS64BITS;
return fingerprint;
}
FingerPrint::~FingerPrint() {}
const boost::uuids::uuid &FingerPrint::GetFingerPrint() const { return named_uuid; }
bool FingerPrint::IsMagicNumberOK() const { return 1297240911 == magic_number; }
bool FingerPrint::IsMagicNumberOK(const FingerPrint& other) const { return other.magic_number == magic_number; }
bool FingerPrint::TestGraphUtil(const FingerPrint &other) const
{
if (!other.IsMagicNumberOK())
if (!IsMagicNumberOK(other))
{
throw osrm::exception("hsgr input file misses magic number. Check or reprocess the file");
}
@ -77,7 +80,7 @@ bool FingerPrint::TestGraphUtil(const FingerPrint &other) const
bool FingerPrint::TestPrepare(const FingerPrint &other) const
{
if (!other.IsMagicNumberOK())
if (!IsMagicNumberOK(other))
{
throw osrm::exception("osrm input file misses magic number. Check or reprocess the file");
}
@ -86,7 +89,7 @@ bool FingerPrint::TestPrepare(const FingerPrint &other) const
bool FingerPrint::TestRTree(const FingerPrint &other) const
{
if (!other.IsMagicNumberOK())
if (!IsMagicNumberOK(other))
{
throw osrm::exception("r-tree input file misses magic number. Check or reprocess the file");
}
@ -95,7 +98,7 @@ bool FingerPrint::TestRTree(const FingerPrint &other) const
bool FingerPrint::TestQueryObjects(const FingerPrint &other) const
{
if (!other.IsMagicNumberOK())
if (!IsMagicNumberOK(other))
{
throw osrm::exception("missing magic number. Check or reprocess the file");
}

View File

@ -52,243 +52,57 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <unordered_map>
#include <vector>
template <typename EdgeT>
NodeID read_undirected_osrm_stream(std::istream &input_stream,
std::vector<EdgeT> &edge_list,
std::vector<FixedPointCoordinate> &coordinate_list)
{
const FingerPrint fingerprint_orig;
FingerPrint fingerprint_loaded;
input_stream.read(reinterpret_cast<char *>(&fingerprint_loaded), sizeof(FingerPrint));
if (!fingerprint_loaded.TestGraphUtil(fingerprint_orig))
{
SimpleLogger().Write(logWARNING) << ".osrm was prepared with different build.\n"
"Reprocess to get rid of this warning.";
}
std::unordered_map<NodeID, NodeID> ext_to_int_id_map;
NodeID n;
input_stream.read(reinterpret_cast<char *>(&n), sizeof(NodeID));
SimpleLogger().Write() << "Importing n = " << n << " nodes ";
ExternalMemoryNode current_node;
for (NodeID i = 0; i < n; ++i)
{
input_stream.read(reinterpret_cast<char *>(&current_node), sizeof(ExternalMemoryNode));
coordinate_list.emplace_back(current_node.lat, current_node.lon);
ext_to_int_id_map.emplace(current_node.node_id, i);
// if (current_node.barrier)
// {
// barrier_node_list.emplace_back(i);
// }
// if (current_node.traffic_lights)
// {
// traffic_light_node_list.emplace_back(i);
// }
}
// tighten vector sizes
// barrier_node_list.shrink_to_fit();
// traffic_light_node_list.shrink_to_fit();
// renumber nodes in turn restrictions
// for (TurnRestriction &current_restriction : restriction_list)
// {
// auto internal_id_iter = ext_to_int_id_map.find(current_restriction.from.node);
// if (internal_id_iter == ext_to_int_id_map.end())
// {
// SimpleLogger().Write(logDEBUG) << "Unmapped from node " <<
// current_restriction.from.node
// << " of restriction";
// continue;
// }
// current_restriction.from.node = internal_id_iter->second;
// internal_id_iter = ext_to_int_id_map.find(current_restriction.via.node);
// if (internal_id_iter == ext_to_int_id_map.end())
// {
// SimpleLogger().Write(logDEBUG) << "Unmapped via node " <<
// current_restriction.via.node
// << " of restriction";
// continue;
// }
// current_restriction.via.node = internal_id_iter->second;
// internal_id_iter = ext_to_int_id_map.find(current_restriction.to.node);
// if (internal_id_iter == ext_to_int_id_map.end())
// {
// SimpleLogger().Write(logDEBUG) << "Unmapped to node " << current_restriction.to.node
// << " of restriction";
// continue;
// }
// current_restriction.to.node = internal_id_iter->second;
// }
EdgeWeight weight;
NodeID source, target;
unsigned nameID;
int length;
short dir; // direction (0 = open, 1 = forward, 2+ = open)
bool is_roundabout, ignore_in_grid, is_access_restricted, is_split;
TravelMode travel_mode;
EdgeID m;
input_stream.read(reinterpret_cast<char *>(&m), sizeof(unsigned));
edge_list.reserve(m);
SimpleLogger().Write() << " and " << m << " edges ";
for (EdgeID i = 0; i < m; ++i)
{
input_stream.read(reinterpret_cast<char *>(&source), sizeof(unsigned));
input_stream.read(reinterpret_cast<char *>(&target), sizeof(unsigned));
input_stream.read(reinterpret_cast<char *>(&length), sizeof(int));
input_stream.read(reinterpret_cast<char *>(&dir), sizeof(short));
input_stream.read(reinterpret_cast<char *>(&weight), sizeof(int));
input_stream.read(reinterpret_cast<char *>(&nameID), sizeof(unsigned));
input_stream.read(reinterpret_cast<char *>(&is_roundabout), sizeof(bool));
input_stream.read(reinterpret_cast<char *>(&ignore_in_grid), sizeof(bool));
input_stream.read(reinterpret_cast<char *>(&is_access_restricted), sizeof(bool));
input_stream.read(reinterpret_cast<char *>(&travel_mode), sizeof(TravelMode));
input_stream.read(reinterpret_cast<char *>(&is_split), sizeof(bool));
BOOST_ASSERT_MSG(length > 0, "loaded null length edge");
BOOST_ASSERT_MSG(weight > 0, "loaded null weight");
BOOST_ASSERT_MSG(0 <= dir && dir <= 2, "loaded bogus direction");
// bool forward = true;
// bool backward = true;
// if (1 == dir)
// {
// backward = false;
// }
// if (2 == dir)
// {
// forward = false;
// }
// translate the external NodeIDs to internal IDs
auto internal_id_iter = ext_to_int_id_map.find(source);
if (ext_to_int_id_map.find(source) == ext_to_int_id_map.end())
{
#ifndef NDEBUG
SimpleLogger().Write(logWARNING) << " unresolved source NodeID: " << source;
#endif
continue;
}
source = internal_id_iter->second;
internal_id_iter = ext_to_int_id_map.find(target);
if (ext_to_int_id_map.find(target) == ext_to_int_id_map.end())
{
#ifndef NDEBUG
SimpleLogger().Write(logWARNING) << "unresolved target NodeID : " << target;
#endif
continue;
}
target = internal_id_iter->second;
BOOST_ASSERT_MSG(source != SPECIAL_NODEID && target != SPECIAL_NODEID,
"nonexisting source or target");
if (source > target)
{
std::swap(source, target);
// std::swap(forward, backward);
}
edge_list.emplace_back(source, target);
}
ext_to_int_id_map.clear();
tbb::parallel_sort(edge_list.begin(), edge_list.end());
// for (unsigned i = 1; i < edge_list.size(); ++i)
// {
// if ((edge_list[i - 1].target == edge_list[i].target) &&
// (edge_list[i - 1].source == edge_list[i].source))
// {
// const bool edge_flags_equivalent = (edge_list[i - 1].forward == edge_list[i].forward)
// &&
// (edge_list[i - 1].backward ==
// edge_list[i].backward);
// const bool edge_flags_are_superset1 =
// (edge_list[i - 1].forward && edge_list[i - 1].backward) &&
// (edge_list[i].forward != edge_list[i].backward);
// const bool edge_flags_are_superset_2 =
// (edge_list[i].forward && edge_list[i].backward) &&
// (edge_list[i - 1].forward != edge_list[i - 1].backward);
// if (edge_flags_equivalent)
// {
// edge_list[i].weight = std::min(edge_list[i - 1].weight, edge_list[i].weight);
// edge_list[i - 1].source = SPECIAL_NODEID;
// }
// else if (edge_flags_are_superset1)
// {
// if (edge_list[i - 1].weight <= edge_list[i].weight)
// {
// // edge i-1 is smaller and goes in both directions. Throw away the other edge
// edge_list[i].source = SPECIAL_NODEID;
// }
// else
// {
// // edge i-1 is open in both directions, but edge i is smaller in one
// direction.
// // Close edge i-1 in this direction
// edge_list[i - 1].forward = !edge_list[i].forward;
// edge_list[i - 1].backward = !edge_list[i].backward;
// }
// }
// else if (edge_flags_are_superset_2)
// {
// if (edge_list[i - 1].weight <= edge_list[i].weight)
// {
// // edge i-1 is smaller for one direction. edge i is open in both. close edge
// i
// // in the other direction
// edge_list[i].forward = !edge_list[i - 1].forward;
// edge_list[i].backward = !edge_list[i - 1].backward;
// }
// else
// {
// // edge i is smaller and goes in both direction. Throw away edge i-1
// edge_list[i - 1].source = SPECIAL_NODEID;
// }
// }
// }
// }
// const auto new_end_iter =
// std::remove_if(edge_list.begin(), edge_list.end(), [](const EdgeT &edge)
// {
// return edge.source == SPECIAL_NODEID || edge.target == SPECIAL_NODEID;
// });
// edge_list.erase(new_end_iter, edge_list.end()); // remove excess candidates.
// edge_list.shrink_to_fit();
SimpleLogger().Write() << "Graph loaded ok and has " << edge_list.size() << " edges";
return n;
}
template <typename EdgeT>
NodeID readBinaryOSRMGraphFromStream(std::istream &input_stream,
std::vector<EdgeT> &edge_list,
std::vector<NodeID> &barrier_node_list,
std::vector<NodeID> &traffic_light_node_list,
std::vector<QueryNode> *int_to_ext_node_id_map,
/**
* Reads the .restrictions file and loads it to a vector.
* The since the restrictions reference nodes using their external node id,
* we need to renumber it to the new internal id.
*/
unsigned loadRestrictionsFromFile(std::istream& input_stream,
std::vector<TurnRestriction>& restriction_list)
{
const FingerPrint fingerprint_orig;
const FingerPrint fingerprint_valid = FingerPrint::GetValid();
FingerPrint fingerprint_loaded;
unsigned number_of_usable_restrictions = 0;
input_stream.read((char *)&fingerprint_loaded, sizeof(FingerPrint));
if (!fingerprint_loaded.TestPrepare(fingerprint_valid))
{
SimpleLogger().Write(logWARNING) << ".restrictions was prepared with different build.\n"
"Reprocess to get rid of this warning.";
}
input_stream.read((char *)&number_of_usable_restrictions, sizeof(unsigned));
restriction_list.resize(number_of_usable_restrictions);
if (number_of_usable_restrictions > 0)
{
input_stream.read((char *) restriction_list.data(),
number_of_usable_restrictions * sizeof(TurnRestriction));
}
return number_of_usable_restrictions;
}
/**
* Reads the beginning of an .osrm file and produces:
* - list of barrier nodes
* - list of traffic lights
* - nodes indexed by their internal (non-osm) id
*/
NodeID loadNodesFromFile(std::istream &input_stream,
std::vector<NodeID> &barrier_node_list,
std::vector<NodeID> &traffic_light_node_list,
std::vector<QueryNode> &node_array)
{
const FingerPrint fingerprint_valid = FingerPrint::GetValid();
FingerPrint fingerprint_loaded;
input_stream.read(reinterpret_cast<char *>(&fingerprint_loaded), sizeof(FingerPrint));
if (!fingerprint_loaded.TestGraphUtil(fingerprint_orig))
if (!fingerprint_loaded.TestPrepare(fingerprint_valid))
{
SimpleLogger().Write(logWARNING) << ".osrm was prepared with different build.\n"
"Reprocess to get rid of this warning.";
}
std::unordered_map<NodeID, NodeID> ext_to_int_id_map;
NodeID n;
input_stream.read(reinterpret_cast<char *>(&n), sizeof(NodeID));
SimpleLogger().Write() << "Importing n = " << n << " nodes ";
@ -297,9 +111,7 @@ NodeID readBinaryOSRMGraphFromStream(std::istream &input_stream,
for (NodeID i = 0; i < n; ++i)
{
input_stream.read(reinterpret_cast<char *>(&current_node), sizeof(ExternalMemoryNode));
int_to_ext_node_id_map->emplace_back(current_node.lat, current_node.lon,
current_node.node_id);
ext_to_int_id_map.emplace(current_node.node_id, i);
node_array.emplace_back(current_node.lat, current_node.lon, current_node.node_id);
if (current_node.barrier)
{
barrier_node_list.emplace_back(i);
@ -314,175 +126,48 @@ NodeID readBinaryOSRMGraphFromStream(std::istream &input_stream,
barrier_node_list.shrink_to_fit();
traffic_light_node_list.shrink_to_fit();
// renumber nodes in turn restrictions
for (TurnRestriction &current_restriction : restriction_list)
{
auto internal_id_iter = ext_to_int_id_map.find(current_restriction.from.node);
if (internal_id_iter == ext_to_int_id_map.end())
{
SimpleLogger().Write(logDEBUG) << "Unmapped from node " << current_restriction.from.node
<< " of restriction";
continue;
}
current_restriction.from.node = internal_id_iter->second;
internal_id_iter = ext_to_int_id_map.find(current_restriction.via.node);
if (internal_id_iter == ext_to_int_id_map.end())
{
SimpleLogger().Write(logDEBUG) << "Unmapped via node " << current_restriction.via.node
<< " of restriction";
continue;
return n;
}
current_restriction.via.node = internal_id_iter->second;
internal_id_iter = ext_to_int_id_map.find(current_restriction.to.node);
if (internal_id_iter == ext_to_int_id_map.end())
/**
* Reads a .osrm file and produces the edges.
*/
NodeID loadEdgesFromFile(std::istream &input_stream,
std::vector<NodeBasedEdge> &edge_list)
{
SimpleLogger().Write(logDEBUG) << "Unmapped to node " << current_restriction.to.node
<< " of restriction";
continue;
}
current_restriction.to.node = internal_id_iter->second;
}
EdgeWeight weight;
NodeID source, target;
unsigned nameID;
int length;
short dir; // direction (0 = open, 1 = forward, 2+ = open)
bool is_roundabout, ignore_in_grid, is_access_restricted, is_split;
TravelMode travel_mode;
EdgeID m;
input_stream.read(reinterpret_cast<char *>(&m), sizeof(unsigned));
edge_list.reserve(m);
edge_list.resize(m);
SimpleLogger().Write() << " and " << m << " edges ";
for (EdgeID i = 0; i < m; ++i)
{
input_stream.read(reinterpret_cast<char *>(&source), sizeof(unsigned));
input_stream.read(reinterpret_cast<char *>(&target), sizeof(unsigned));
input_stream.read(reinterpret_cast<char *>(&length), sizeof(int));
input_stream.read(reinterpret_cast<char *>(&dir), sizeof(short));
input_stream.read(reinterpret_cast<char *>(&weight), sizeof(int));
input_stream.read(reinterpret_cast<char *>(&nameID), sizeof(unsigned));
input_stream.read(reinterpret_cast<char *>(&is_roundabout), sizeof(bool));
input_stream.read(reinterpret_cast<char *>(&ignore_in_grid), sizeof(bool));
input_stream.read(reinterpret_cast<char *>(&is_access_restricted), sizeof(bool));
input_stream.read(reinterpret_cast<char *>(&travel_mode), sizeof(TravelMode));
input_stream.read(reinterpret_cast<char *>(&is_split), sizeof(bool));
input_stream.read((char *) edge_list.data(), m * sizeof(NodeBasedEdge));
BOOST_ASSERT_MSG(length > 0, "loaded null length edge");
BOOST_ASSERT_MSG(weight > 0, "loaded null weight");
BOOST_ASSERT_MSG(0 <= dir && dir <= 2, "loaded bogus direction");
BOOST_ASSERT(edge_list.size() > 0);
bool forward = true;
bool backward = true;
if (1 == dir)
{
backward = false;
}
if (2 == dir)
{
forward = false;
}
// translate the external NodeIDs to internal IDs
auto internal_id_iter = ext_to_int_id_map.find(source);
if (ext_to_int_id_map.find(source) == ext_to_int_id_map.end())
{
#ifndef NDEBUG
SimpleLogger().Write(logWARNING) << " unresolved source NodeID: " << source;
#endif
continue;
}
source = internal_id_iter->second;
internal_id_iter = ext_to_int_id_map.find(target);
if (ext_to_int_id_map.find(target) == ext_to_int_id_map.end())
SimpleLogger().Write() << "Validating loaded edges...";
std::sort(edge_list.begin(), edge_list.end(),
[](const NodeBasedEdge& lhs, const NodeBasedEdge& rhs)
{
#ifndef NDEBUG
SimpleLogger().Write(logWARNING) << "unresolved target NodeID : " << target;
#endif
continue;
}
target = internal_id_iter->second;
BOOST_ASSERT_MSG(source != SPECIAL_NODEID && target != SPECIAL_NODEID,
"nonexisting source or target");
if (source > target)
{
std::swap(source, target);
std::swap(forward, backward);
}
edge_list.emplace_back(source, target, nameID, weight, forward, backward, is_roundabout,
ignore_in_grid, is_access_restricted, travel_mode, is_split);
}
ext_to_int_id_map.clear();
tbb::parallel_sort(edge_list.begin(), edge_list.end());
for (unsigned i = 1; i < edge_list.size(); ++i)
{
if ((edge_list[i - 1].target == edge_list[i].target) &&
(edge_list[i - 1].source == edge_list[i].source))
{
const bool edge_flags_equivalent = (edge_list[i - 1].forward == edge_list[i].forward) &&
(edge_list[i - 1].backward == edge_list[i].backward);
const bool edge_flags_are_superset1 =
(edge_list[i - 1].forward && edge_list[i - 1].backward) &&
(edge_list[i].forward != edge_list[i].backward);
const bool edge_flags_are_superset_2 =
(edge_list[i].forward && edge_list[i].backward) &&
(edge_list[i - 1].forward != edge_list[i - 1].backward);
if (edge_flags_equivalent)
{
edge_list[i].weight = std::min(edge_list[i - 1].weight, edge_list[i].weight);
edge_list[i - 1].source = SPECIAL_NODEID;
}
else if (edge_flags_are_superset1)
{
if (edge_list[i - 1].weight <= edge_list[i].weight)
{
// edge i-1 is smaller and goes in both directions. Throw away the other edge
edge_list[i].source = SPECIAL_NODEID;
}
else
{
// edge i-1 is open in both directions, but edge i is smaller in one direction.
// Close edge i-1 in this direction
edge_list[i - 1].forward = !edge_list[i].forward;
edge_list[i - 1].backward = !edge_list[i].backward;
}
}
else if (edge_flags_are_superset_2)
{
if (edge_list[i - 1].weight <= edge_list[i].weight)
{
// edge i-1 is smaller for one direction. edge i is open in both. close edge i
// in the other direction
edge_list[i].forward = !edge_list[i - 1].forward;
edge_list[i].backward = !edge_list[i - 1].backward;
}
else
{
// edge i is smaller and goes in both direction. Throw away edge i-1
edge_list[i - 1].source = SPECIAL_NODEID;
}
}
}
}
const auto new_end_iter =
std::remove_if(edge_list.begin(), edge_list.end(), [](const EdgeT &edge)
{
return edge.source == SPECIAL_NODEID || edge.target == SPECIAL_NODEID;
return (lhs.source < rhs.source) || (lhs.source == rhs.source && lhs.target < rhs.target);
});
edge_list.erase(new_end_iter, edge_list.end()); // remove excess candidates.
edge_list.shrink_to_fit();
for (auto i = 1u; i < edge_list.size(); ++i)
{
const auto& edge = edge_list[i];
const auto& prev_edge = edge_list[i-1];
BOOST_ASSERT_MSG(edge.weight > 0, "loaded null weight");
BOOST_ASSERT_MSG(edge.forward, "edge must be oriented in forward direction");
BOOST_ASSERT_MSG(edge.travel_mode != TRAVEL_MODE_INACCESSIBLE, "loaded non-accessible");
BOOST_ASSERT_MSG(edge.source != edge.target, "loaded edges contain a loop");
BOOST_ASSERT_MSG(edge.source != prev_edge.source || edge.target != prev_edge.target, "loaded edges contain a multi edge");
}
#endif
SimpleLogger().Write() << "Graph loaded ok and has " << edge_list.size() << " edges";
return n;
return m;
}
template <typename NodeT, typename EdgeT>
@ -502,9 +187,10 @@ unsigned readHSGRFromStream(const boost::filesystem::path &hsgr_file,
boost::filesystem::ifstream hsgr_input_stream(hsgr_file, std::ios::binary);
FingerPrint fingerprint_loaded, fingerprint_orig;
const FingerPrint fingerprint_valid = FingerPrint::GetValid();
FingerPrint fingerprint_loaded;
hsgr_input_stream.read(reinterpret_cast<char *>(&fingerprint_loaded), sizeof(FingerPrint));
if (!fingerprint_loaded.TestGraphUtil(fingerprint_orig))
if (!fingerprint_loaded.TestGraphUtil(fingerprint_valid))
{
SimpleLogger().Write(logWARNING) << ".hsgr was prepared with different build.\n"
"Reprocess to get rid of this warning.";

View File

@ -90,7 +90,7 @@ template <typename Iterator> struct iso_8601_grammar : qi::grammar<Iterator>
unsigned get_duration() const
{
unsigned temp = 10 * (3600 * hours + 60 * minutes + seconds);
unsigned temp = (3600 * hours + 60 * minutes + seconds);
if (temp == 0)
{
temp = std::numeric_limits<unsigned>::max();

View File

@ -55,11 +55,10 @@ inline bool lua_function_exists(lua_State *lua_state, const char *name)
// See http://lua-users.org/wiki/PackagePath for details on the package.path syntax.
inline void luaAddScriptFolderToLoadPath(lua_State *lua_state, const char *file_name)
{
const boost::filesystem::path profile_path(file_name);
boost::filesystem::path profile_path = boost::filesystem::canonical(file_name);
std::string folder = profile_path.parent_path().string();
// TODO: This code is most probably not Windows safe since it uses UNIX'ish path delimiters
const std::string lua_code =
"package.path = \"" + folder + "/?.lua;profiles/?.lua;\" .. package.path";
const std::string lua_code = "package.path = \"" + folder + "/?.lua;\" .. package.path";
luaL_dostring(lua_state, lua_code.c_str());
}