Merge branch 'develop'
This commit is contained in:
commit
300d901618
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,3 +1,7 @@
|
||||
# pre compiled dependencies #
|
||||
#############################
|
||||
osrm-deps
|
||||
|
||||
# Compiled source #
|
||||
###################
|
||||
*.com
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
27
Gemfile.lock
27
Gemfile.lock
@ -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
|
||||
|
31
README.md
31
README.md
@ -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 | [](https://travis-ci.org/Project-OSRM/osrm-backend) |
|
||||
| Linux | develop | [](https://travis-ci.org/Project-OSRM/osrm-backend) |
|
||||
| Windows | master/develop | [](https://ci.appveyor.com/project/DennisOSRM/osrm-backend) |
|
||||
| LUAbind fork | 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 | [](https://travis-ci.org/DennisOSRM/Project-OSRM) |
|
||||
| Linux | develop | [](https://travis-ci.org/DennisOSRM/Project-OSRM) |
|
||||
| Windows | master/develop | [](https://ci.appveyor.com/project/DennisOSRM/osrm-backend) |
|
||||
| LUAbind fork | master | [](https://travis-ci.org/DennisOSRM/luabind) |
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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_ */
|
||||
|
@ -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
113
appveyor-build.bat
Normal 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
|
43
appveyor.yml
43
appveyor.yml
@ -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
19
build-local.bat
Normal 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%
|
@ -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;
|
||||
|
135
contractor/contractor_options.cpp
Normal file
135
contractor/contractor_options.cpp
Normal 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";
|
||||
}
|
68
contractor/contractor_options.hpp
Normal file
68
contractor/contractor_options.hpp
Normal 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
|
@ -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,
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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";
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
void ExtractionContainers::PrepareEdges()
|
||||
{
|
||||
// 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] 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())
|
||||
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())
|
||||
{
|
||||
if (way_start_and_end_iterator->way_id < restrictions_iterator->restriction.from.way)
|
||||
if (edge_iterator->result.source < node_iterator->node_id)
|
||||
{
|
||||
++way_start_and_end_iterator;
|
||||
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;
|
||||
}
|
||||
if (edge_iterator->start > node_iterator->node_id)
|
||||
{
|
||||
node_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 (edge_iterator->target < node_iterator->node_id)
|
||||
{
|
||||
++edge_iterator;
|
||||
continue;
|
||||
}
|
||||
if (edge_iterator->target > node_iterator->node_id)
|
||||
{
|
||||
++node_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())
|
||||
{
|
||||
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)
|
||||
{
|
||||
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");
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
// 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));
|
||||
|
||||
if (edge_iterator->is_split)
|
||||
{
|
||||
file_out_stream.write((char *)&yes, sizeof(bool));
|
||||
}
|
||||
else
|
||||
{
|
||||
file_out_stream.write((char *)&no, sizeof(bool));
|
||||
}
|
||||
++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)
|
||||
{
|
||||
const unsigned string_length =
|
||||
std::min(static_cast<unsigned>(temp_string.length()), 255u);
|
||||
name_lengths.push_back(string_length);
|
||||
total_length += string_length;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
SimpleLogger().Write() << "Processed " << number_of_used_nodes << " nodes and "
|
||||
<< number_of_used_edges << " edges";
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
std::cerr << "Caught Execption:" << e.what() << std::endl;
|
||||
}
|
||||
SimpleLogger().Write() << "Processed " << number_of_used_nodes << " nodes";
|
||||
}
|
||||
|
||||
void ExtractionContainers::WriteRestrictions(const std::string& path) const
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
if (way_start_and_end_iterator->way_id > restrictions_iterator->restriction.from.way)
|
||||
{
|
||||
SimpleLogger().Write(LogLevel::logDEBUG) << "Restriction references invalid way: " << restrictions_iterator->restriction.from.way;
|
||||
restrictions_iterator->restriction.from.node = SPECIAL_NODEID;
|
||||
++restrictions_iterator;
|
||||
continue;
|
||||
}
|
||||
|
||||
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())
|
||||
{
|
||||
SimpleLogger().Write(LogLevel::logDEBUG) << "Restriction references invalid node: " << restrictions_iterator->restriction.via.node;
|
||||
restrictions_iterator->restriction.via.node = SPECIAL_NODEID;
|
||||
++restrictions_iterator;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (way_start_and_end_iterator->first_segment_source_id == via_node_id)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
TIMER_STOP(fix_restriction_starts);
|
||||
std::cout << "ok, after " << TIMER_SEC(fix_restriction_starts) << "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())
|
||||
{
|
||||
if (way_start_and_end_iterator->way_id < restrictions_iterator->restriction.to.way)
|
||||
{
|
||||
++way_start_and_end_iterator;
|
||||
continue;
|
||||
}
|
||||
if (restrictions_iterator->restriction.from.node == SPECIAL_NODEID ||
|
||||
restrictions_iterator->restriction.via.node == SPECIAL_NODEID)
|
||||
{
|
||||
++restrictions_iterator;
|
||||
continue;
|
||||
}
|
||||
if (way_start_and_end_iterator->way_id > restrictions_iterator->restriction.to.way)
|
||||
{
|
||||
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;
|
||||
|
||||
// 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;
|
||||
|
||||
if (way_start_and_end_iterator->first_segment_source_id == via_node_id)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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))
|
||||
|
@ -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)
|
||||
|
@ -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 */
|
||||
|
@ -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(
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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(); }
|
||||
};
|
||||
|
||||
|
@ -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());
|
||||
|
@ -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());
|
||||
|
@ -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
|
||||
|
@ -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 | |
|
||||
|
@ -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 |
|
||||
|
@ -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 |
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 | |
|
||||
|
@ -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% |
|
||||
|
@ -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 |
|
||||
|
||||
|
@ -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 |
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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|
|
||||
|
@ -91,6 +91,6 @@ When /^I match I should get$/ do |table|
|
||||
actual << got
|
||||
end
|
||||
end
|
||||
table.routing_diff! actual
|
||||
table.diff! actual
|
||||
end
|
||||
|
||||
|
@ -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|
|
||||
|
@ -74,5 +74,5 @@ Then /^routability should be$/ do |table|
|
||||
actual << output_row
|
||||
end
|
||||
end
|
||||
table.routing_diff! actual
|
||||
table.diff! actual
|
||||
end
|
||||
|
@ -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|
|
||||
|
@ -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
|
@ -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
|
||||
|
@ -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
34
features/support/http.rb
Normal 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
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 |
|
||||
|
@ -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 |
|
||||
|
100
features/testbot/post.feature
Normal file
100
features/testbot/post.feature
Normal 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 |
|
@ -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 |
|
||||
|
@ -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 |
|
||||
|
@ -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;
|
||||
|
60
prepare.cpp
60
prepare.cpp
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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]
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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 ¤t_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 ¤t_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 ¤t_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 ¤t_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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
{
|
||||
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::size_t LoadGraph(const char* path,
|
||||
std::vector<QueryNode>& coordinate_list,
|
||||
std::vector<NodeID>& barrier_node_list,
|
||||
std::vector<TarjanEdge>& graph_edge_list)
|
||||
{
|
||||
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";
|
||||
|
@ -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;
|
||||
}
|
@ -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()
|
||||
|
74
unit_tests/algorithms/geometry_string.cpp
Normal file
74
unit_tests/algorithms/geometry_string.cpp
Normal 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);
|
||||
}
|
||||
}
|
@ -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 */
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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)
|
||||
/**
|
||||
* 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;
|
||||
input_stream.read(reinterpret_cast<char *>(&fingerprint_loaded), sizeof(FingerPrint));
|
||||
|
||||
if (!fingerprint_loaded.TestGraphUtil(fingerprint_orig))
|
||||
unsigned number_of_usable_restrictions = 0;
|
||||
input_stream.read((char *)&fingerprint_loaded, sizeof(FingerPrint));
|
||||
if (!fingerprint_loaded.TestPrepare(fingerprint_valid))
|
||||
{
|
||||
SimpleLogger().Write(logWARNING) << ".osrm was prepared with different build.\n"
|
||||
SimpleLogger().Write(logWARNING) << ".restrictions 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((char *)&number_of_usable_restrictions, sizeof(unsigned));
|
||||
restriction_list.resize(number_of_usable_restrictions);
|
||||
if (number_of_usable_restrictions > 0)
|
||||
{
|
||||
input_stream.read(reinterpret_cast<char *>(¤t_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);
|
||||
// }
|
||||
input_stream.read((char *) restriction_list.data(),
|
||||
number_of_usable_restrictions * sizeof(TurnRestriction));
|
||||
}
|
||||
|
||||
// tighten vector sizes
|
||||
// barrier_node_list.shrink_to_fit();
|
||||
// traffic_light_node_list.shrink_to_fit();
|
||||
|
||||
// renumber nodes in turn restrictions
|
||||
// for (TurnRestriction ¤t_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;
|
||||
return number_of_usable_restrictions;
|
||||
}
|
||||
|
||||
template <typename EdgeT>
|
||||
NodeID readBinaryOSRMGraphFromStream(std::istream &input_stream,
|
||||
std::vector<EdgeT> &edge_list,
|
||||
|
||||
/**
|
||||
* 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> *int_to_ext_node_id_map,
|
||||
std::vector<TurnRestriction> &restriction_list)
|
||||
std::vector<QueryNode> &node_array)
|
||||
{
|
||||
const FingerPrint fingerprint_orig;
|
||||
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 *>(¤t_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 ¤t_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;
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a .osrm file and produces the edges.
|
||||
*/
|
||||
NodeID loadEdgesFromFile(std::istream &input_stream,
|
||||
std::vector<NodeBasedEdge> &edge_list)
|
||||
{
|
||||
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.";
|
||||
|
@ -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();
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user