Merge branch 'master' into sf-restriction-parser

This commit is contained in:
Siarhei Fedartsou 2022-08-30 16:30:48 +02:00
commit 94495b50a8
32 changed files with 705 additions and 183 deletions

View File

@ -26,7 +26,7 @@ jobs:
continue-on-error: false
steps:
- uses: actions/checkout@v3
- run: pip install conan==1.50.0
- run: pip install conan==1.51.3
- run: conan --version
- run: cmake --version
- uses: actions/setup-node@v3
@ -138,7 +138,8 @@ jobs:
runs-on: ubuntu-20.04
BUILD_TOOLS: ON
BUILD_TYPE: Debug
CLANG_VERSION: 6.0.0
CCOMPILER: clang-6.0
CXXCOMPILER: clang++-6.0
CUCUMBER_TIMEOUT: 60000
- name: clang-11.0-debug-clang-tidy
@ -147,7 +148,8 @@ jobs:
runs-on: ubuntu-20.04
BUILD_TOOLS: ON
BUILD_TYPE: Debug
CLANG_VERSION: 11.0.0
CCOMPILER: clang-11
CXXCOMPILER: clang++-11
CUCUMBER_TIMEOUT: 60000
ENABLE_CLANG_TIDY: ON
@ -157,7 +159,8 @@ jobs:
runs-on: ubuntu-20.04
BUILD_TOOLS: ON
BUILD_TYPE: Release
CLANG_VERSION: 11.0.0
CCOMPILER: clang-11
CXXCOMPILER: clang++-11
ENABLE_CONAN: ON
ENABLE_SANITIZER: ON
@ -167,7 +170,8 @@ jobs:
runs-on: ubuntu-20.04
BUILD_TOOLS: ON
BUILD_TYPE: Release
CLANG_VERSION: 6.0.0
CCOMPILER: clang-6.0
CXXCOMPILER: clang++-6.0
ENABLE_CONAN: ON
- name: gcc-11-release
@ -285,7 +289,8 @@ jobs:
node: 12
runs-on: ubuntu-20.04
BUILD_TYPE: Release
CLANG_VERSION: 6.0.0
CCOMPILER: clang-6.0
CXXCOMPILER: clang++-6.0
ENABLE_GLIBC_WORKAROUND: ON
ENABLE_CONAN: ON
NODE_PACKAGE_TESTS_ONLY: ON
@ -296,7 +301,8 @@ jobs:
node: 12
runs-on: ubuntu-20.04
BUILD_TYPE: Debug
CLANG_VERSION: 6.0.0
CCOMPILER: clang-6.0
CXXCOMPILER: clang++-6.0
ENABLE_GLIBC_WORKAROUND: ON
ENABLE_CONAN: ON
NODE_PACKAGE_TESTS_ONLY: ON
@ -307,7 +313,8 @@ jobs:
node: 14
runs-on: ubuntu-20.04
BUILD_TYPE: Release
CLANG_VERSION: 6.0.0
CCOMPILER: clang-6.0
CXXCOMPILER: clang++-6.0
ENABLE_GLIBC_WORKAROUND: ON
ENABLE_CONAN: ON
NODE_PACKAGE_TESTS_ONLY: ON
@ -318,7 +325,8 @@ jobs:
node: 14
runs-on: ubuntu-20.04
BUILD_TYPE: Debug
CLANG_VERSION: 6.0.0
CCOMPILER: clang-6.0
CXXCOMPILER: clang++-6.0
ENABLE_GLIBC_WORKAROUND: ON
ENABLE_CONAN: ON
NODE_PACKAGE_TESTS_ONLY: ON
@ -330,7 +338,8 @@ jobs:
node: 16
runs-on: ubuntu-20.04
BUILD_TYPE: Release
CLANG_VERSION: 6.0.0
CCOMPILER: clang-6.0
CXXCOMPILER: clang++-6.0
ENABLE_GLIBC_WORKAROUND: ON
ENABLE_CONAN: ON
NODE_PACKAGE_TESTS_ONLY: ON
@ -341,7 +350,8 @@ jobs:
node: 16
runs-on: ubuntu-20.04
BUILD_TYPE: Debug
CLANG_VERSION: 6.0.0
CCOMPILER: clang-6.0
CXXCOMPILER: clang++-6.0
ENABLE_GLIBC_WORKAROUND: ON
ENABLE_CONAN: ON
NODE_PACKAGE_TESTS_ONLY: ON
@ -364,7 +374,8 @@ jobs:
node: latest
runs-on: ubuntu-20.04
BUILD_TYPE: Release
CLANG_VERSION: 6.0.0
CCOMPILER: clang-6.0
CXXCOMPILER: clang++-6.0
ENABLE_GLIBC_WORKAROUND: ON
ENABLE_CONAN: ON
NODE_PACKAGE_TESTS_ONLY: ON
@ -375,7 +386,8 @@ jobs:
node: latest
runs-on: ubuntu-20.04
BUILD_TYPE: Debug
CLANG_VERSION: 6.0.0
CCOMPILER: clang-6.0
CXXCOMPILER: clang++-6.0
ENABLE_GLIBC_WORKAROUND: ON
ENABLE_CONAN: ON
NODE_PACKAGE_TESTS_ONLY: ON
@ -398,7 +410,8 @@ jobs:
node: "lts/*"
runs-on: ubuntu-20.04
BUILD_TYPE: Release
CLANG_VERSION: 6.0.0
CCOMPILER: clang-6.0
CXXCOMPILER: clang++-6.0
ENABLE_GLIBC_WORKAROUND: ON
ENABLE_CONAN: ON
NODE_PACKAGE_TESTS_ONLY: ON
@ -409,7 +422,8 @@ jobs:
node: "lts/*"
runs-on: ubuntu-20.04
BUILD_TYPE: Debug
CLANG_VERSION: 6.0.0
CCOMPILER: clang-6.0
CXXCOMPILER: clang++-6.0
ENABLE_GLIBC_WORKAROUND: ON
ENABLE_CONAN: ON
NODE_PACKAGE_TESTS_ONLY: ON
@ -423,7 +437,6 @@ jobs:
BUILD_SHARED_LIBS: ${{ matrix.BUILD_SHARED_LIBS }}
CCOMPILER: ${{ matrix.CCOMPILER }}
CFLAGS: ${{ matrix.CFLAGS }}
CLANG_VERSION: ${{ matrix.CLANG_VERSION }}
CUCUMBER_TIMEOUT: ${{ matrix.CUCUMBER_TIMEOUT }}
CXXCOMPILER: ${{ matrix.CXXCOMPILER }}
CXXFLAGS: ${{ matrix.CXXFLAGS }}
@ -515,26 +528,23 @@ jobs:
echo "$(${MASON} prefix ccache ${CCACHE_VERSION})/bin" >> $GITHUB_PATH
# clang
if [[ -n ${CLANG_VERSION} ]]; then
echo "CCOMPILER=clang" >> $GITHUB_ENV
echo "CXXCOMPILER=clang++" >> $GITHUB_ENV
${MASON} install clang++ ${CLANG_VERSION}
echo "$(${MASON} prefix clang++ ${CLANG_VERSION})/bin" >> $GITHUB_PATH
# we only enable lto for release builds
# and therefore don't need to us ld.gold or llvm tools for linking
# for debug builds
if [[ ${BUILD_TYPE} == 'Release' ]]; then
${MASON} install binutils 2.27
echo "$(${MASON} prefix binutils 2.27)/bin" >> $GITHUB_PATH
fi
if [[ "${CCOMPILER}" == "clang-6.0" ]]; then
sudo apt-get update -y && sudo apt-get install clang++-6
fi
# we only enable lto for release builds
# and therefore don't need to us ld.gold or llvm tools for linking
# for debug builds
if [[ "${CCOMPILER}" == clang-* ]] && [[ ${BUILD_TYPE} == 'Release' ]]; then
${MASON} install binutils 2.27
echo "$(${MASON} prefix binutils 2.27)/bin" >> $GITHUB_PATH
fi
# Linux dev packages
if [ "${TARGET_ARCH}" != "i686" ] && [ "${ENABLE_CONAN}" != "ON" ]; then
sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
sudo apt-get update -y
sudo apt-get install -y libbz2-dev libxml2-dev libzip-dev liblua5.2-dev libboost-all-dev
if [[ -z "${CLANG_VERSION}" ]]; then
if [[ "${CCOMPILER}" != clang-* ]]; then
sudo apt-get install -y ${CXXCOMPILER}
fi
if [[ "${ENABLE_COVERAGE}" == "ON" ]]; then

View File

@ -10,6 +10,7 @@
- FIXED: Support `skip_waypoints` in Node bindings [#6060](https://github.com/Project-OSRM/osrm-backend/pull/6060)
- Misc:
- CHANGED: Optimize RestrictionParser performance. [#6344](https://github.com/Project-OSRM/osrm-backend/pull/6344)
- ADDED: Support floats for speed value in traffic updates CSV. [#6327](https://github.com/Project-OSRM/osrm-backend/pull/6327)
- CHANGED: Use Lua 5.4 in Docker image. [#6346](https://github.com/Project-OSRM/osrm-backend/pull/6346)
- CHANGED: Remove redundant nullptr check. [#6326](https://github.com/Project-OSRM/osrm-backend/pull/6326)
- CHANGED: missing files list is included in exception message. [#5360](https://github.com/Project-OSRM/osrm-backend/pull/5360)
@ -21,6 +22,7 @@
- FIXED: Bug in bicycle profile that caused exceptions if there is a highway=bicycle in the data. [#6296](https://github.com/Project-OSRM/osrm-backend/pull/6296)
- FIXED: Internal refactoring of identifier types used in data facade [#6044](https://github.com/Project-OSRM/osrm-backend/pull/6044)
- Build:
- CHANGED: Use apt-get to install Clang on CI. [#6345](https://github.com/Project-OSRM/osrm-backend/pull/6345)
- CHANGED: Fix TBB in case of Conan + NodeJS build. [#6333](https://github.com/Project-OSRM/osrm-backend/pull/6333)
- CHANGED: Migrate to modern TBB version. [#6300](https://github.com/Project-OSRM/osrm-backend/pull/6300)
- CHANGED: Enable performance-move-const-arg clang-tidy check. [#6319](https://github.com/Project-OSRM/osrm-backend/pull/6319)
@ -54,6 +56,7 @@
- FIXED: Improvements to maneuver override processing [#6125](https://github.com/Project-OSRM/osrm-backend/pull/6125)
- ADDED: Support snapping to multiple ways at an input location. [#5953](https://github.com/Project-OSRM/osrm-backend/pull/5953)
- FIXED: Fix snapping target locations to ways used in turn restrictions. [#6339](https://github.com/Project-OSRM/osrm-backend/pull/6339)
- ADDED: Support OSM traffic signal directions. [#6153](https://github.com/Project-OSRM/osrm-backend/pull/6153)
# 5.26.0
- Changes from 5.25.0

View File

@ -39,7 +39,113 @@ Feature: Car - Handle traffic lights
| k | n | 20.7s | turn with traffic light |
Scenario: Tarrif Signal Geometry
Scenario: Car - Traffic signal direction
Given the node map
"""
a-1-b-2-c
d-3-e-4-f
g-5-h-6-i
j-7-k-8-l
"""
And the ways
| nodes | highway |
| abc | primary |
| def | primary |
| ghi | primary |
| jkl | primary |
And the nodes
| node | highway | traffic_signals:direction |
| e | traffic_signals | |
| h | traffic_signals | forward |
| k | traffic_signals | backward |
When I route I should get
| from | to | time | # |
| 1 | 2 | 11.1s | no turn with no traffic light |
| 2 | 1 | 11.1s | no turn with no traffic light |
| 3 | 4 | 13.1s | no turn with traffic light |
| 4 | 3 | 13.1s | no turn with traffic light |
| 5 | 6 | 13.1s | no turn with traffic light |
| 6 | 5 | 11.1s | no turn with no traffic light |
| 7 | 8 | 11.1s | no turn with no traffic light |
| 8 | 7 | 13.1s | no turn with traffic light |
Scenario: Car - Encounters a traffic light
Given the node map
"""
a f k
| | |
b-c-d h-g-i l-m-n
| | |
e j o
"""
And the ways
| nodes | highway |
| bcd | primary |
| ace | primary |
| hgi | primary |
| fgj | primary |
| lmn | primary |
| kmo | primary |
And the nodes
| node | highway | traffic_signals:direction |
| g | traffic_signals | forward |
| m | traffic_signals | backward |
When I route I should get
| from | to | time | # |
| a | d | 21.9s | no turn with no traffic light |
| a | e | 22.2s | no turn with traffic light |
| a | b | 18.7s | turn with no traffic light |
| e | b | 21.9s | no turn with no traffic light |
| e | a | 22.2s | no turn with traffic light |
| e | d | 18.7s | turn with no traffic light |
| d | e | 21.9s | no turn with no traffic light |
| d | b | 11s | no turn with traffic light |
| d | a | 18.7s | turn with no traffic light |
| b | a | 21.9s | no turn with no traffic light |
| b | d | 11s | no turn with traffic light |
| b | e | 18.7s | turn with no traffic light |
| f | i | 23.9s | no turn with no traffic light |
| f | j | 24.2s | no turn with traffic light |
| f | h | 20.7s | turn with no traffic light |
| j | h | 21.9s | no turn with no traffic light |
| j | f | 22.2s | no turn with traffic light |
| j | i | 18.7s | turn with no traffic light |
| i | j | 21.9s | no turn with no traffic light |
| i | h | 11s | no turn with traffic light |
| i | f | 18.7s | turn with no traffic light |
| h | f | 23.9s | no turn with no traffic light |
| h | i | 13s | no turn with traffic light |
| h | j | 20.7s | turn with no traffic light |
| k | n | 21.9s | no turn with no traffic light |
| k | o | 22.2s | no turn with traffic light |
| k | l | 18.7s | turn with no traffic light |
| o | l | 23.9s | no turn with no traffic light |
| o | k | 24.2s | no turn with traffic light |
| o | n | 20.7s | turn with no traffic light |
| n | o | 23.9s | no turn with no traffic light |
| n | l | 13s | no turn with traffic light |
| n | k | 20.7s | turn with no traffic light |
| l | k | 21.9s | no turn with no traffic light |
| l | n | 11s | no turn with traffic light |
| l | o | 18.7s | turn with no traffic light |
Scenario: Traffic Signal Geometry
Given the query options
| overview | full |
| geometries | polyline |
@ -61,6 +167,53 @@ Feature: Car - Handle traffic lights
| from | to | route | geometry |
| a | c | abc,abc | _ibE_ibE?gJ?eJ |
Scenario: Traffic Signal Geometry - forward signal
Given the query options
| overview | full |
| geometries | polyline |
Given the node map
"""
a - b - c
"""
And the ways
| nodes | highway |
| abc | primary |
And the nodes
| node | highway | traffic_signals:direction |
| b | traffic_signals | forward |
When I route I should get
| from | to | route | geometry |
| a | c | abc,abc | _ibE_ibE?gJ?eJ |
Scenario: Traffic Signal Geometry - reverse signal
Given the query options
| overview | full |
| geometries | polyline |
Given the node map
"""
a - b - c
"""
And the ways
| nodes | highway |
| abc | primary |
And the nodes
| node | highway | traffic_signals:direction |
| b | traffic_signals | reverse |
When I route I should get
| from | to | route | geometry |
| a | c | abc,abc | _ibE_ibE?gJ?eJ |
@traffic
Scenario: Traffic update on the edge with a traffic signal
Given the node map
@ -91,3 +244,67 @@ Feature: Car - Handle traffic lights
| from | to | route | speed | weights | time | distances | a:datasources | a:nodes | a:speed | a:duration | a:weight |
| a | c | abc,abc | 60 km/h | 24.2,0 | 24.2s | 400m,0m | 1:0 | 1:2:3 | 18:18 | 11.1:11.1 | 11.1:11.1 |
| c | a | abc,abc | 60 km/h | 24.2,0 | 24.2s | 400m,0m | 0:1 | 3:2:1 | 18:18 | 11.1:11.1 | 11.1:11.1 |
@traffic
Scenario: Traffic update on the edge with a traffic signal - forward
Given the node map
"""
a - b - c
"""
And the ways
| nodes | highway |
| abc | primary |
And the nodes
| node | highway | traffic_signals:direction |
| b | traffic_signals | forward |
And the contract extra arguments "--segment-speed-file {speeds_file}"
And the customize extra arguments "--segment-speed-file {speeds_file}"
And the speed file
"""
1,2,65
2,1,65
"""
And the query options
| annotations | datasources,nodes,speed,duration,weight |
When I route I should get
| from | to | route | speed | weights | time | distances | a:datasources | a:nodes | a:speed | a:duration | a:weight |
| a | c | abc,abc | 60 km/h | 24.2,0 | 24.2s | 400m,0m | 1:0 | 1:2:3 | 18:18 | 11.1:11.1 | 11.1:11.1 |
| c | a | abc,abc | 65 km/h | 22.2,0 | 22.2s | 400m,0m | 0:1 | 3:2:1 | 18:18 | 11.1:11.1 | 11.1:11.1 |
@traffic
Scenario: Traffic update on the edge with a traffic signal - backward
Given the node map
"""
a - b - c
"""
And the ways
| nodes | highway |
| abc | primary |
And the nodes
| node | highway | traffic_signals:direction |
| b | traffic_signals | backward |
And the contract extra arguments "--segment-speed-file {speeds_file}"
And the customize extra arguments "--segment-speed-file {speeds_file}"
And the speed file
"""
1,2,65
2,1,65
"""
And the query options
| annotations | datasources,nodes,speed,duration,weight |
When I route I should get
| from | to | route | speed | weights | time | distances | a:datasources | a:nodes | a:speed | a:duration | a:weight |
| a | c | abc,abc | 65 km/h | 22.2,0 | 22.2s | 400m,0m | 1:0 | 1:2:3 | 18:18 | 11.1:11.1 | 11.1:11.1 |
| c | a | abc,abc | 60 km/h | 24.2,0 | 24.2s | 400m,0m | 0:1 | 3:2:1 | 18:18 | 11.1:11.1 | 11.1:11.1 |

View File

@ -329,7 +329,7 @@ Feature: Weight tests
| ce |
And the speed file
"""
1,2,36,42
1,2,36.999,42
2,1,36,42
"""
And the turn penalty file
@ -341,8 +341,8 @@ Feature: Weight tests
When I route I should get
| waypoints | route | distance | weights | times |
| a,d | , | 60m | 20.5,0 | 24s,0s |
| a,e | ,, | 60m | 27.2,10,0 | 38.5s,11s,0s |
| a,d | , | 60m | 20.5,0 | 23.9s,0s |
| a,e | ,, | 60m | 27.2,10,0 | 38.4s,11s,0s |
| d,e | ,, | 40m | 10,10,0 | 11s,11s,0s |
@traffic @speed

View File

@ -23,6 +23,7 @@
#include "util/typedefs.hpp"
#include "storage/io.hpp"
#include "traffic_signals.hpp"
#include <algorithm>
#include <cstddef>
@ -68,7 +69,7 @@ class EdgeBasedGraphFactory
EdgeBasedNodeDataContainer &node_data_container,
const CompressedEdgeContainer &compressed_edge_container,
const std::unordered_set<NodeID> &barrier_nodes,
const std::unordered_set<NodeID> &traffic_lights,
const TrafficSignals &traffic_signals,
const std::vector<util::Coordinate> &coordinates,
const NameTable &name_table,
const std::unordered_set<EdgeID> &segregated_edges,
@ -134,7 +135,7 @@ class EdgeBasedGraphFactory
const util::NodeBasedDynamicGraph &m_node_based_graph;
const std::unordered_set<NodeID> &m_barrier_nodes;
const std::unordered_set<NodeID> &m_traffic_lights;
const TrafficSignals &m_traffic_signals;
const CompressedEdgeContainer &m_compressed_edge_container;
const NameTable &name_table;

View File

@ -8,8 +8,11 @@
#include "extractor/scripting_environment.hpp"
#include "storage/tar_fwd.hpp"
#include "traffic_lights.hpp"
#include "traffic_signals.hpp"
#include <unordered_map>
#include <unordered_set>
namespace osrm
{
@ -25,15 +28,19 @@ namespace extractor
class ExtractionContainers
{
using ReferencedWays = std::unordered_map<OSMWayID, NodesOfWay>;
using ReferencedTrafficSignals =
std::pair<std::unordered_set<OSMNodeID>, std::unordered_multimap<OSMNodeID, OSMNodeID>>;
// The relationship between way and nodes is lost during node preparation.
// We identify the ways and nodes relevant to restrictions/overrides prior to
// We identify the ways and nodes relevant to restrictions/overrides/signals prior to
// node processing so that they can be referenced in the preparation phase.
ReferencedWays IdentifyRestrictionWays();
ReferencedWays IdentifyManeuverOverrideWays();
ReferencedTrafficSignals IdentifyTrafficSignals();
void PrepareNodes();
void PrepareManeuverOverrides(const ReferencedWays &maneuver_override_ways);
void PrepareRestrictions(const ReferencedWays &restriction_ways);
void PrepareTrafficSignals(const ReferencedTrafficSignals &referenced_traffic_signals);
void PrepareEdges(ScriptingEnvironment &scripting_environment);
void WriteNodes(storage::tar::FileWriter &file_out) const;
@ -50,9 +57,9 @@ class ExtractionContainers
using NameOffsets = std::vector<size_t>;
using WayIDVector = std::vector<OSMWayID>;
using WayNodeIDOffsets = std::vector<size_t>;
using InputTrafficSignal = std::pair<OSMNodeID, TrafficLightClass::Direction>;
std::vector<OSMNodeID> barrier_nodes;
std::vector<OSMNodeID> traffic_signals;
NodeIDVector used_node_id_list;
NodeVector all_nodes_list;
EdgeVector all_edges_list;
@ -65,6 +72,9 @@ class ExtractionContainers
unsigned max_internal_node_id;
std::vector<InputTrafficSignal> external_traffic_signals;
TrafficSignals internal_traffic_signals;
// List of restrictions (conditional and unconditional) before we transform them into the
// output types. Input containers reference OSMNodeIDs. We can only transform them to the
// correct internal IDs after we've read everything. Without a multi-parse approach,

View File

@ -1,6 +1,8 @@
#ifndef EXTRACTION_NODE_HPP
#define EXTRACTION_NODE_HPP
#include "traffic_lights.hpp"
namespace osrm
{
namespace extractor
@ -8,9 +10,13 @@ namespace extractor
struct ExtractionNode
{
ExtractionNode() : traffic_lights(false), barrier(false) {}
void clear() { traffic_lights = barrier = false; }
bool traffic_lights;
ExtractionNode() : traffic_lights(TrafficLightClass::NONE), barrier(false) {}
void clear()
{
traffic_lights = TrafficLightClass::NONE;
barrier = false;
}
TrafficLightClass::Direction traffic_lights;
bool barrier;
};
} // namespace extractor

View File

@ -43,6 +43,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "util/guidance/turn_lanes.hpp"
#include "restriction_graph.hpp"
#include "traffic_signals.hpp"
#include "util/typedefs.hpp"
namespace osrm
@ -64,7 +65,8 @@ class Extractor
std::tuple<LaneDescriptionMap,
std::vector<TurnRestriction>,
std::vector<UnresolvedManeuverOverride>>
std::vector<UnresolvedManeuverOverride>,
TrafficSignals>
ParseOSMData(ScriptingEnvironment &scripting_environment, const unsigned number_of_threads);
EdgeID BuildEdgeExpandedGraph(
@ -73,7 +75,7 @@ class Extractor
const std::vector<util::Coordinate> &coordinates,
const CompressedEdgeContainer &compressed_edge_container,
const std::unordered_set<NodeID> &barrier_nodes,
const std::unordered_set<NodeID> &traffic_lights,
const TrafficSignals &traffic_signals,
const RestrictionGraph &restriction_graph,
const std::unordered_set<EdgeID> &segregated_edges,
const NameTable &name_table,

View File

@ -444,10 +444,9 @@ inline void readConditionalRestrictions(const boost::filesystem::path &path,
}
// reads .osrm file which is a temporary file of osrm-extract
template <typename BarrierOutIter, typename TrafficSignalsOutIter, typename PackedOSMIDsT>
template <typename BarrierOutIter, typename PackedOSMIDsT>
void readRawNBGraph(const boost::filesystem::path &path,
BarrierOutIter barriers,
TrafficSignalsOutIter traffic_signals,
std::vector<util::Coordinate> &coordinates,
PackedOSMIDsT &osm_node_ids,
std::vector<extractor::NodeBasedEdge> &edge_list,
@ -471,8 +470,6 @@ void readRawNBGraph(const boost::filesystem::path &path,
reader.ReadStreaming<NodeID>("/extractor/barriers", barriers);
reader.ReadStreaming<NodeID>("/extractor/traffic_lights", traffic_signals);
storage::serialization::read(reader, "/extractor/edges", edge_list);
storage::serialization::read(reader, "/extractor/annotations", annotations);
}

View File

@ -4,6 +4,7 @@
#include "extractor/scripting_environment.hpp"
#include "util/typedefs.hpp"
#include "traffic_signals.hpp"
#include "util/node_based_graph.hpp"
#include <memory>
@ -25,7 +26,7 @@ class GraphCompressor
public:
void Compress(const std::unordered_set<NodeID> &barrier_nodes,
const std::unordered_set<NodeID> &traffic_lights,
const TrafficSignals &traffic_signals,
ScriptingEnvironment &scripting_environment,
std::vector<TurnRestriction> &turn_restrictions,
std::vector<UnresolvedManeuverOverride> &maneuver_overrides,

View File

@ -8,6 +8,7 @@
#include "extractor/packed_osm_ids.hpp"
#include "extractor/scripting_environment.hpp"
#include "traffic_signals.hpp"
#include "util/coordinate.hpp"
#include "util/node_based_graph.hpp"
@ -40,11 +41,11 @@ class NodeBasedGraphFactory
NodeBasedGraphFactory(const boost::filesystem::path &input_file,
ScriptingEnvironment &scripting_environment,
std::vector<TurnRestriction> &turn_restrictions,
std::vector<UnresolvedManeuverOverride> &maneuver_overrides);
std::vector<UnresolvedManeuverOverride> &maneuver_overrides,
const TrafficSignals &traffic_signals);
auto const &GetGraph() const { return compressed_output_graph; }
auto const &GetBarriers() const { return barriers; }
auto const &GetTrafficSignals() const { return traffic_signals; }
auto const &GetCompressedEdges() const { return compressed_edge_container; }
auto const &GetCoordinates() const { return coordinates; }
auto const &GetAnnotationData() const { return annotation_data; }
@ -68,7 +69,8 @@ class NodeBasedGraphFactory
// edges into a single representative form
void Compress(ScriptingEnvironment &scripting_environment,
std::vector<TurnRestriction> &turn_restrictions,
std::vector<UnresolvedManeuverOverride> &maneuver_overrides);
std::vector<UnresolvedManeuverOverride> &maneuver_overrides,
const TrafficSignals &traffic_signals);
// Most ways are bidirectional, making the geometry in forward and backward direction the same,
// except for reversal. We make use of this fact by keeping only one representation of the
@ -89,7 +91,6 @@ class NodeBasedGraphFactory
// General Information about the graph, not used outside of extractor
std::unordered_set<NodeID> barriers;
std::unordered_set<NodeID> traffic_signals;
std::vector<util::Coordinate> coordinates;

View File

@ -5,7 +5,7 @@
#include <boost/optional/optional.hpp>
#include <osmium/tags/tags_filter.hpp>
#include <osmium/tags/filter.hpp>
#include <set>
#include <string>
#include <vector>
@ -54,7 +54,7 @@ class RestrictionParser
bool use_turn_restrictions;
bool parse_conditionals;
std::set<std::string> restrictions;
osmium::TagsFilter filter;
osmium::tags::KeyFilter filter;
};
} // namespace extractor
} // namespace osrm

View File

@ -0,0 +1,25 @@
#ifndef OSRM_EXTRACTOR_TRAFFIC_LIGHTS_DATA_HPP_
#define OSRM_EXTRACTOR_TRAFFIC_LIGHTS_DATA_HPP_
namespace osrm
{
namespace extractor
{
namespace TrafficLightClass
{
// The traffic light annotation is extracted from node tags.
// The directions in which the traffic light applies are relative to the way containing the node.
enum Direction
{
NONE = 0,
DIRECTION_ALL = 1,
DIRECTION_FORWARD = 2,
DIRECTION_REVERSE = 3
};
} // namespace TrafficLightClass
} // namespace extractor
} // namespace osrm
#endif // OSRM_EXTRACTOR_TRAFFIC_LIGHTS_DATA_HPP_

View File

@ -0,0 +1,28 @@
#ifndef OSRM_EXTRACTOR_TRAFFIC_SIGNALS_HPP
#define OSRM_EXTRACTOR_TRAFFIC_SIGNALS_HPP
#include "util/typedefs.hpp"
#include <unordered_set>
#include <boost/unordered_set.hpp>
namespace osrm
{
namespace extractor
{
struct TrafficSignals
{
std::unordered_set<NodeID> bidirectional_nodes;
std::unordered_set<std::pair<NodeID, NodeID>, boost::hash<std::pair<NodeID, NodeID>>>
unidirectional_segments;
inline bool HasSignal(NodeID from, NodeID to) const
{
return bidirectional_nodes.count(to) > 0 || unidirectional_segments.count({from, to}) > 0;
}
};
} // namespace extractor
} // namespace osrm
#endif // OSRM_EXTRACTOR_TRAFFIC_SIGNALS_HPP

View File

@ -49,8 +49,8 @@ struct Segment final
struct SpeedSource final
{
SpeedSource() : speed(0), rate() {}
unsigned speed;
SpeedSource() : speed(0.), rate() {}
double speed;
boost::optional<double> rate;
std::uint8_t source;
};

View File

@ -5,6 +5,7 @@ api_version = 4
Set = require('lib/set')
Sequence = require('lib/sequence')
Handlers = require("lib/way_handlers")
TrafficSignal = require("lib/traffic_signal")
find_access_tag = require("lib/access").find_access_tag
limit = require("lib/maxspeed").limit
Measure = require("lib/measure")
@ -235,10 +236,7 @@ function process_node(profile, node, result)
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
result.traffic_lights = TrafficSignal.get_value(node)
end
function handle_bicycle_tags(profile,way,result,data)

View File

@ -6,6 +6,7 @@ Set = require('lib/set')
Sequence = require('lib/sequence')
Handlers = require("lib/way_handlers")
Relations = require("lib/relations")
TrafficSignal = require("lib/traffic_signal")
find_access_tag = require("lib/access").find_access_tag
limit = require("lib/maxspeed").limit
Utils = require("lib/utils")
@ -360,10 +361,7 @@ function process_node(profile, node, result, relations)
end
-- check if node is a traffic light
local tag = node:get_value_by_key("highway")
if "traffic_signals" == tag then
result.traffic_lights = true
end
result.traffic_lights = TrafficSignal.get_value(node)
end
function process_way(profile, way, result, relations)

View File

@ -157,6 +157,7 @@ function process_node(profile, node, result)
-- check if node is a traffic light
local tag = node:get_value_by_key("highway")
if "traffic_signals" == tag then
-- Direction should only apply to vehicles
result.traffic_lights = true
end
end

View File

@ -0,0 +1,26 @@
-- Assigns traffic light value to node as defined by
-- include/extractor/traffic_lights.hpp
local TrafficSignal = {}
function TrafficSignal.get_value(node)
local tag = node:get_value_by_key("highway")
if "traffic_signals" == tag then
local direction = node:get_value_by_key("traffic_signals:direction")
if direction then
if "forward" == direction then
return traffic_lights.direction_forward
end
if "backward" == direction then
return traffic_lights.direction_reverse
end
end
-- return traffic_lights.direction_all
return true
end
-- return traffic_lights.none
return false
end
return TrafficSignal

View File

@ -4,6 +4,7 @@
-- Primary road: 36km/h = 36000m/3600s = 100m/10s
-- Secondary road: 18km/h = 18000m/3600s = 100m/20s
-- Tertiary road: 12km/h = 12000m/3600s = 100m/30s
TrafficSignal = require("lib/traffic_signal")
api_version = 4
@ -38,12 +39,9 @@ function setup()
end
function process_node (profile, node, result)
local traffic_signal = node:get_value_by_key("highway")
if traffic_signal and traffic_signal == "traffic_signals" then
result.traffic_lights = true
-- TODO: a way to set the penalty value
end
-- check if node is a traffic light
result.traffic_lights = TrafficSignal.get_value(node)
-- TODO: a way to set the penalty value
end
function process_way (profile, way, result)

View File

@ -59,7 +59,7 @@ EdgeBasedGraphFactory::EdgeBasedGraphFactory(
EdgeBasedNodeDataContainer &node_data_container,
const CompressedEdgeContainer &compressed_edge_container,
const std::unordered_set<NodeID> &barrier_nodes,
const std::unordered_set<NodeID> &traffic_lights,
const TrafficSignals &traffic_signals,
const std::vector<util::Coordinate> &coordinates,
const NameTable &name_table,
const std::unordered_set<EdgeID> &segregated_edges,
@ -67,7 +67,7 @@ EdgeBasedGraphFactory::EdgeBasedGraphFactory(
: m_edge_based_node_container(node_data_container), m_connectivity_checksum(0),
m_number_of_edge_based_nodes(0), m_coordinates(coordinates),
m_node_based_graph(node_based_graph), m_barrier_nodes(barrier_nodes),
m_traffic_lights(traffic_lights), m_compressed_edge_container(compressed_edge_container),
m_traffic_signals(traffic_signals), m_compressed_edge_container(compressed_edge_container),
name_table(name_table), segregated_edges(segregated_edges),
lane_description_map(lane_description_map)
{
@ -623,8 +623,26 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
BOOST_ASSERT(!edge_data1.reversed);
BOOST_ASSERT(!edge_data2.reversed);
// We write out the mapping between the edge-expanded edges and the original nodes.
// Since each edge represents a possible maneuver, external programs can use this to
// quickly perform updates to edge weights in order to penalize certain turns.
// If this edge is 'trivial' -- where the compressed edge corresponds exactly to an
// original OSM segment -- we can pull the turn's preceding node ID directly with
// `node_along_road_entering`;
// otherwise, we need to look up the node immediately preceding the turn from the
// compressed edge container.
const bool isTrivial = m_compressed_edge_container.IsTrivial(node_based_edge_from);
const auto &from_node =
isTrivial ? node_along_road_entering
: m_compressed_edge_container.GetLastEdgeSourceID(node_based_edge_from);
// compute weight and duration penalties
const auto is_traffic_light = m_traffic_lights.count(intersection_node);
// In theory we shouldn't get a directed traffic light on a turn, as it indicates that
// the traffic signal direction was potentially ambiguously annotated on the junction
// node But we'll check anyway.
const auto is_traffic_light = m_traffic_signals.HasSignal(from_node, intersection_node);
const auto is_uturn =
guidance::getTurnDirection(turn_angle) == guidance::DirectionModifier::UTurn;
@ -690,20 +708,6 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
true,
false};
// We write out the mapping between the edge-expanded edges and the original nodes.
// Since each edge represents a possible maneuver, external programs can use this to
// quickly perform updates to edge weights in order to penalize certain turns.
// If this edge is 'trivial' -- where the compressed edge corresponds exactly to an
// original OSM segment -- we can pull the turn's preceding node ID directly with
// `node_along_road_entering`;
// otherwise, we need to look up the node immediately preceding the turn from the
// compressed edge container.
const bool isTrivial = m_compressed_edge_container.IsTrivial(node_based_edge_from);
const auto &from_node =
isTrivial ? node_along_road_entering
: m_compressed_edge_container.GetLastEdgeSourceID(node_based_edge_from);
const auto &to_node =
m_compressed_edge_container.GetFirstEdgeTargetID(node_based_edge_to);

View File

@ -11,6 +11,7 @@
#include "util/exception.hpp"
#include "util/exception_utils.hpp"
#include "util/for_each_indexed.hpp"
#include "util/for_each_pair.hpp"
#include "util/log.hpp"
#include "util/timing_util.hpp"
@ -413,6 +414,7 @@ void ExtractionContainers::PrepareData(ScriptingEnvironment &scripting_environme
const auto restriction_ways = IdentifyRestrictionWays();
const auto maneuver_override_ways = IdentifyManeuverOverrideWays();
const auto traffic_signals = IdentifyTrafficSignals();
PrepareNodes();
WriteNodes(writer);
@ -422,6 +424,7 @@ void ExtractionContainers::PrepareData(ScriptingEnvironment &scripting_environme
WriteEdges(writer);
WriteMetadata(writer);
PrepareTrafficSignals(traffic_signals);
PrepareManeuverOverrides(maneuver_override_ways);
PrepareRestrictions(restriction_ways);
WriteCharData(name_file_name);
@ -911,25 +914,6 @@ void ExtractionContainers::WriteNodes(storage::tar::FileWriter &writer) const
log << "ok, after " << TIMER_SEC(write_nodes) << "s";
}
{
util::UnbufferedLog log;
log << "Writing traffic light nodes ... ";
TIMER_START(write_nodes);
std::vector<NodeID> internal_traffic_signals;
for (const auto osm_id : traffic_signals)
{
const auto node_id = mapExternalToInternalNodeID(
used_node_id_list.begin(), used_node_id_list.end(), osm_id);
if (node_id != SPECIAL_NODEID)
{
internal_traffic_signals.push_back(node_id);
}
}
storage::serialization::write(
writer, "/extractor/traffic_lights", internal_traffic_signals);
log << "ok, after " << TIMER_SEC(write_nodes) << "s";
}
util::Log() << "Processed " << max_internal_node_id << " nodes";
}
@ -983,6 +967,50 @@ ExtractionContainers::ReferencedWays ExtractionContainers::IdentifyManeuverOverr
return maneuver_override_ways;
}
void ExtractionContainers::PrepareTrafficSignals(
const ExtractionContainers::ReferencedTrafficSignals &referenced_traffic_signals)
{
const auto &bidirectional_signal_nodes = referenced_traffic_signals.first;
const auto &unidirectional_signal_segments = referenced_traffic_signals.second;
util::UnbufferedLog log;
log << "Preparing traffic light signals for " << bidirectional_signal_nodes.size()
<< " bidirectional, " << unidirectional_signal_segments.size()
<< " unidirectional nodes ...";
TIMER_START(prepare_traffic_signals);
std::unordered_set<NodeID> bidirectional;
std::unordered_set<std::pair<NodeID, NodeID>, boost::hash<std::pair<NodeID, NodeID>>>
unidirectional;
for (const auto &osm_node : bidirectional_signal_nodes)
{
const auto node_id = mapExternalToInternalNodeID(
used_node_id_list.begin(), used_node_id_list.end(), osm_node);
if (node_id != SPECIAL_NODEID)
{
bidirectional.insert(node_id);
}
}
for (const auto &to_from : unidirectional_signal_segments)
{
const auto to_node_id = mapExternalToInternalNodeID(
used_node_id_list.begin(), used_node_id_list.end(), to_from.first);
const auto from_node_id = mapExternalToInternalNodeID(
used_node_id_list.begin(), used_node_id_list.end(), to_from.second);
if (from_node_id != SPECIAL_NODEID && to_node_id != SPECIAL_NODEID)
{
unidirectional.insert({from_node_id, to_node_id});
}
}
internal_traffic_signals.bidirectional_nodes = std::move(bidirectional);
internal_traffic_signals.unidirectional_segments = std::move(unidirectional);
TIMER_STOP(prepare_traffic_signals);
log << "ok, after " << TIMER_SEC(prepare_traffic_signals) << "s";
}
void ExtractionContainers::PrepareManeuverOverrides(const ReferencedWays &maneuver_override_ways)
{
auto const osm_node_to_internal_nbn = [&](auto const osm_node) {
@ -1163,6 +1191,93 @@ ExtractionContainers::ReferencedWays ExtractionContainers::IdentifyRestrictionWa
return restriction_ways;
}
ExtractionContainers::ReferencedTrafficSignals ExtractionContainers::IdentifyTrafficSignals()
{
util::UnbufferedLog log;
log << "Collecting traffic signal information on " << external_traffic_signals.size()
<< " signals...";
TIMER_START(identify_traffic_signals);
// Temporary store for nodes containing a unidirectional signal.
std::unordered_map<OSMNodeID, TrafficLightClass::Direction> unidirectional_signals;
// For each node that has a unidirectional traffic signal, we store the node(s)
// that lead up to the signal.
std::unordered_multimap<OSMNodeID, OSMNodeID> signal_segments;
std::unordered_set<OSMNodeID> bidirectional_signals;
const auto mark_signals = [&](auto const &traffic_signal) {
if (traffic_signal.second == TrafficLightClass::DIRECTION_FORWARD ||
traffic_signal.second == TrafficLightClass::DIRECTION_REVERSE)
{
unidirectional_signals.insert({traffic_signal.first, traffic_signal.second});
}
else
{
BOOST_ASSERT(traffic_signal.second == TrafficLightClass::DIRECTION_ALL);
bidirectional_signals.insert(traffic_signal.first);
}
};
std::for_each(external_traffic_signals.begin(), external_traffic_signals.end(), mark_signals);
// Extract all the segments that lead up to unidirectional traffic signals.
const auto set_segments = [&](const size_t way_list_idx, auto const & /*unused*/) {
const auto node_start_offset =
used_node_id_list.begin() + way_node_id_offsets[way_list_idx];
const auto node_end_offset =
used_node_id_list.begin() + way_node_id_offsets[way_list_idx + 1];
for (auto node_it = node_start_offset; node_it < node_end_offset; node_it++)
{
const auto sig = unidirectional_signals.find(*node_it);
if (sig != unidirectional_signals.end())
{
if (sig->second == TrafficLightClass::DIRECTION_FORWARD)
{
if (node_it != node_start_offset)
{
// Previous node leads to signal
signal_segments.insert({*node_it, *(node_it - 1)});
}
}
else
{
BOOST_ASSERT(sig->second == TrafficLightClass::DIRECTION_REVERSE);
if (node_it + 1 != node_end_offset)
{
// Next node leads to signal
signal_segments.insert({*node_it, *(node_it + 1)});
}
}
}
}
};
util::for_each_indexed(ways_list.cbegin(), ways_list.cend(), set_segments);
util::for_each_pair(
signal_segments, [](const auto pair_a, const auto pair_b) {
if (pair_a.first == pair_b.first)
{
// If a node is appearing multiple times in this map, then it's ambiguous.
// The node is an intersection and the traffic direction is being use for multiple
// ways. We can't be certain of the original intent. See:
// https://wiki.openstreetmap.org/wiki/Key:traffic_signals:direction
// OSRM will include the signal for all intersecting ways in the specified
// direction, but let's flag this as a concern.
util::Log(logWARNING)
<< "OSM node " << pair_a.first
<< " has a unidirectional traffic signal ambiguously applied to multiple ways";
}
});
TIMER_STOP(identify_traffic_signals);
log << "ok, after " << TIMER_SEC(identify_traffic_signals) << "s";
return {std::move(bidirectional_signals), std::move(signal_segments)};
}
void ExtractionContainers::PrepareRestrictions(const ReferencedWays &restriction_ways)
{

View File

@ -75,7 +75,7 @@ void SetClassNames(const std::vector<std::string> &class_names,
if (!class_names.empty())
{
// add class names that were never used explicitly on a way
// this makes sure we can correctly validate unkown class names later
// this makes sure we can correctly validate unknown class names later
for (const auto &name : class_names)
{
if (!isValidClassName(name))
@ -207,7 +207,8 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
LaneDescriptionMap turn_lane_map;
std::vector<TurnRestriction> turn_restrictions;
std::vector<UnresolvedManeuverOverride> unresolved_maneuver_overrides;
std::tie(turn_lane_map, turn_restrictions, unresolved_maneuver_overrides) =
TrafficSignals traffic_signals;
std::tie(turn_lane_map, turn_restrictions, unresolved_maneuver_overrides, traffic_signals) =
ParseOSMData(scripting_environment, number_of_threads);
// Transform the node-based graph that OSM is based on into an edge-based graph
@ -229,7 +230,8 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
NodeBasedGraphFactory node_based_graph_factory(config.GetPath(".osrm"),
scripting_environment,
turn_restrictions,
unresolved_maneuver_overrides);
unresolved_maneuver_overrides,
traffic_signals);
NameTable name_table;
files::readNames(config.GetPath(".osrm.names"), name_table);
@ -264,7 +266,6 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
node_based_graph_factory.GetCompressedEdges().PrintStatistics();
const auto &barrier_nodes = node_based_graph_factory.GetBarriers();
const auto &traffic_signals = node_based_graph_factory.GetTrafficSignals();
// stealing the annotation data from the node-based graph
edge_based_nodes_container =
EdgeBasedNodeDataContainer({}, std::move(node_based_graph_factory.GetAnnotationData()));
@ -360,10 +361,12 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
return 0;
}
std::
tuple<LaneDescriptionMap, std::vector<TurnRestriction>, std::vector<UnresolvedManeuverOverride>>
Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
const unsigned number_of_threads)
std::tuple<LaneDescriptionMap,
std::vector<TurnRestriction>,
std::vector<UnresolvedManeuverOverride>,
TrafficSignals>
Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
const unsigned number_of_threads)
{
TIMER_START(extracting);
@ -628,7 +631,8 @@ std::
return std::make_tuple(std::move(turn_lane_map),
std::move(extraction_containers.turn_restrictions),
std::move(extraction_containers.internal_maneuver_overrides));
std::move(extraction_containers.internal_maneuver_overrides),
std::move(extraction_containers.internal_traffic_signals));
}
void Extractor::FindComponents(unsigned number_of_edge_based_nodes,
@ -699,7 +703,7 @@ EdgeID Extractor::BuildEdgeExpandedGraph(
const std::vector<util::Coordinate> &coordinates,
const CompressedEdgeContainer &compressed_edge_container,
const std::unordered_set<NodeID> &barrier_nodes,
const std::unordered_set<NodeID> &traffic_signals,
const TrafficSignals &traffic_signals,
const RestrictionGraph &restriction_graph,
const std::unordered_set<EdgeID> &segregated_edges,
const NameTable &name_table,

View File

@ -78,9 +78,9 @@ void ExtractorCallbacks::ProcessNode(const osmium::Node &input_node,
{
external_memory.barrier_nodes.push_back(id);
}
if (result_node.traffic_lights)
if (result_node.traffic_lights != TrafficLightClass::NONE)
{
external_memory.traffic_signals.push_back(id);
external_memory.external_traffic_signals.push_back({id, result_node.traffic_lights});
}
}

View File

@ -19,8 +19,10 @@ namespace osrm
namespace extractor
{
static constexpr int SECOND_TO_DECISECOND = 10;
void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
const std::unordered_set<NodeID> &traffic_signals,
const TrafficSignals &traffic_signals,
ScriptingEnvironment &scripting_environment,
std::vector<TurnRestriction> &turn_restrictions,
std::vector<UnresolvedManeuverOverride> &maneuver_overrides,
@ -207,16 +209,20 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
rev_edge_data2.annotation_data, rev_edge_data1.annotation_data);
// Add node penalty when compress edge crosses a traffic signal
const bool has_node_penalty = traffic_signals.find(node_v) != traffic_signals.end();
EdgeDuration node_duration_penalty = MAXIMAL_EDGE_DURATION;
EdgeWeight node_weight_penalty = INVALID_EDGE_WEIGHT;
if (has_node_penalty)
const bool has_forward_signal = traffic_signals.HasSignal(node_u, node_v);
const bool has_reverse_signal = traffic_signals.HasSignal(node_w, node_v);
EdgeDuration forward_node_duration_penalty = MAXIMAL_EDGE_DURATION;
EdgeWeight forward_node_weight_penalty = INVALID_EDGE_WEIGHT;
EdgeDuration reverse_node_duration_penalty = MAXIMAL_EDGE_DURATION;
EdgeWeight reverse_node_weight_penalty = INVALID_EDGE_WEIGHT;
if (has_forward_signal || has_reverse_signal)
{
// we cannot handle this as node penalty, if it depends on turn direction
if (fwd_edge_data1.flags.restricted != fwd_edge_data2.flags.restricted)
continue;
// generate an artifical turn for the turn penalty generation
// generate an artificial turn for the turn penalty generation
std::vector<ExtractionTurnLeg> roads_on_the_right;
std::vector<ExtractionTurnLeg> roads_on_the_left;
ExtractionTurn extraction_turn(0,
@ -245,8 +251,24 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
roads_on_the_right,
roads_on_the_left);
scripting_environment.ProcessTurn(extraction_turn);
node_duration_penalty = extraction_turn.duration * 10;
node_weight_penalty = extraction_turn.weight * weight_multiplier;
auto update_direction_penalty =
[&extraction_turn, weight_multiplier](bool signal,
EdgeDuration &duration_penalty,
EdgeWeight &weight_penalty) {
if (signal)
{
duration_penalty = extraction_turn.duration * SECOND_TO_DECISECOND;
weight_penalty = extraction_turn.weight * weight_multiplier;
}
};
update_direction_penalty(has_forward_signal,
forward_node_duration_penalty,
forward_node_weight_penalty);
update_direction_penalty(has_reverse_signal,
reverse_node_duration_penalty,
reverse_node_weight_penalty);
}
// Get weights before graph is modified
@ -278,27 +300,37 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
BOOST_ASSERT(0 != reverse_weight1);
BOOST_ASSERT(0 != reverse_weight2);
// add weight of e2's to e1
graph.GetEdgeData(forward_e1).weight += forward_weight2;
graph.GetEdgeData(reverse_e1).weight += reverse_weight2;
auto apply_e2_to_e1 = [&graph](EdgeID edge,
EdgeWeight weight,
EdgeDuration duration,
EdgeDistance distance,
EdgeDuration &duration_penalty,
EdgeWeight &weight_penalty) {
auto &edge_data = graph.GetEdgeData(edge);
edge_data.weight += weight;
edge_data.duration += duration;
edge_data.distance += distance;
if (weight_penalty != INVALID_EDGE_WEIGHT &&
duration_penalty != MAXIMAL_EDGE_DURATION)
{
edge_data.weight += weight_penalty;
edge_data.duration += duration_penalty;
// Note: no penalties for distances
}
};
// add duration of e2's to e1
graph.GetEdgeData(forward_e1).duration += forward_duration2;
graph.GetEdgeData(reverse_e1).duration += reverse_duration2;
// add distance of e2's to e1
graph.GetEdgeData(forward_e1).distance += forward_distance2;
graph.GetEdgeData(reverse_e1).distance += reverse_distance2;
if (node_weight_penalty != INVALID_EDGE_WEIGHT &&
node_duration_penalty != MAXIMAL_EDGE_DURATION)
{
graph.GetEdgeData(forward_e1).weight += node_weight_penalty;
graph.GetEdgeData(reverse_e1).weight += node_weight_penalty;
graph.GetEdgeData(forward_e1).duration += node_duration_penalty;
graph.GetEdgeData(reverse_e1).duration += node_duration_penalty;
// Note: no penalties for distances
}
apply_e2_to_e1(forward_e1,
forward_weight2,
forward_duration2,
forward_distance2,
forward_node_weight_penalty,
forward_node_duration_penalty);
apply_e2_to_e1(reverse_e1,
reverse_weight2,
reverse_duration2,
reverse_distance2,
reverse_node_weight_penalty,
reverse_node_duration_penalty);
// extend e1's to targets of e2's
graph.SetTarget(forward_e1, node_w);
@ -311,6 +343,25 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
// update any involved turn relations
turn_path_compressor.Compress(node_u, node_v, node_w);
// Forward and reversed compressed edge lengths need to match.
// Set a dummy empty penalty weight if opposite value exists.
auto set_dummy_penalty = [](EdgeWeight &weight_penalty,
EdgeDuration &duration_penalty,
EdgeWeight &other_weight_penalty) {
if (weight_penalty == INVALID_EDGE_WEIGHT &&
other_weight_penalty != INVALID_EDGE_WEIGHT)
{
weight_penalty = 0;
duration_penalty = 0;
}
};
set_dummy_penalty(forward_node_weight_penalty,
forward_node_duration_penalty,
reverse_node_weight_penalty);
set_dummy_penalty(reverse_node_weight_penalty,
reverse_node_duration_penalty,
forward_node_weight_penalty);
// store compressed geometry in container
geometry_compressor.CompressEdge(forward_e1,
forward_e2,
@ -320,8 +371,8 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
forward_weight2,
forward_duration1,
forward_duration2,
node_weight_penalty,
node_duration_penalty);
forward_node_weight_penalty,
forward_node_duration_penalty);
geometry_compressor.CompressEdge(reverse_e1,
reverse_e2,
node_v,
@ -330,8 +381,8 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
reverse_weight2,
reverse_duration1,
reverse_duration2,
node_weight_penalty,
node_duration_penalty);
reverse_node_weight_penalty,
reverse_node_duration_penalty);
}
}
}

View File

@ -19,10 +19,11 @@ NodeBasedGraphFactory::NodeBasedGraphFactory(
const boost::filesystem::path &input_file,
ScriptingEnvironment &scripting_environment,
std::vector<TurnRestriction> &turn_restrictions,
std::vector<UnresolvedManeuverOverride> &maneuver_overrides)
std::vector<UnresolvedManeuverOverride> &maneuver_overrides,
const TrafficSignals &traffic_signals)
{
LoadDataFromFile(input_file);
Compress(scripting_environment, turn_restrictions, maneuver_overrides);
Compress(scripting_environment, turn_restrictions, maneuver_overrides, traffic_signals);
CompressGeometry();
CompressAnnotationData();
}
@ -31,16 +32,10 @@ NodeBasedGraphFactory::NodeBasedGraphFactory(
void NodeBasedGraphFactory::LoadDataFromFile(const boost::filesystem::path &input_file)
{
auto barriers_iter = inserter(barriers, end(barriers));
auto traffic_signals_iter = inserter(traffic_signals, end(traffic_signals));
std::vector<NodeBasedEdge> edge_list;
files::readRawNBGraph(input_file,
barriers_iter,
traffic_signals_iter,
coordinates,
osm_node_ids,
edge_list,
annotation_data);
files::readRawNBGraph(
input_file, barriers_iter, coordinates, osm_node_ids, edge_list, annotation_data);
const auto number_of_node_based_nodes = coordinates.size();
if (edge_list.empty())
@ -80,7 +75,8 @@ void NodeBasedGraphFactory::LoadDataFromFile(const boost::filesystem::path &inpu
void NodeBasedGraphFactory::Compress(ScriptingEnvironment &scripting_environment,
std::vector<TurnRestriction> &turn_restrictions,
std::vector<UnresolvedManeuverOverride> &maneuver_overrides)
std::vector<UnresolvedManeuverOverride> &maneuver_overrides,
const TrafficSignals &traffic_signals)
{
GraphCompressor graph_compressor;
graph_compressor.Compress(barriers,

View File

@ -44,13 +44,13 @@ RestrictionParser::RestrictionParser(bool use_turn_restrictions_,
using namespace std::string_literals;
filter.add_rule(true, "restriction"s);
filter.add(true, "restriction"s);
if (parse_conditionals)
{
filter.add_rule(true, "restriction:conditional"s);
filter.add(true, "restriction:conditional"s);
for (const auto &namespaced : restrictions_)
{
filter.add_rule(true, "restriction:" + namespaced + ":conditional");
filter.add(true, "restriction:" + namespaced + ":conditional");
}
}
@ -58,7 +58,7 @@ RestrictionParser::RestrictionParser(bool use_turn_restrictions_,
// Include restriction:{mode}:conditional if flagged
for (const auto &namespaced : restrictions_)
{
filter.add_rule(true, "restriction:" + namespaced);
filter.add(true, "restriction:" + namespaced);
}
}
@ -81,8 +81,8 @@ RestrictionParser::TryParse(const osmium::Relation &relation) const
const osmium::TagList &tag_list = relation.tags();
osmium::TagsFilter::iterator fi_begin(filter, tag_list.begin(), tag_list.end());
osmium::TagsFilter::iterator fi_end(filter, tag_list.end(), tag_list.end());
osmium::tags::KeyFilter::iterator fi_begin(filter, tag_list.begin(), tag_list.end());
osmium::tags::KeyFilter::iterator fi_end(filter, tag_list.end(), tag_list.end());
// if it's not a restriction, continue;
if (fi_begin == fi_end)

View File

@ -285,11 +285,41 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
return get_location_tag(context, node.location(), key);
});
context.state.new_usertype<ExtractionNode>("ResultNode",
"traffic_lights",
&ExtractionNode::traffic_lights,
"barrier",
&ExtractionNode::barrier);
context.state.new_enum("traffic_lights",
"none",
extractor::TrafficLightClass::NONE,
"direction_all",
extractor::TrafficLightClass::DIRECTION_ALL,
"direction_forward",
extractor::TrafficLightClass::DIRECTION_FORWARD,
"direction_reverse",
extractor::TrafficLightClass::DIRECTION_REVERSE);
context.state.new_usertype<ExtractionNode>(
"ResultNode",
"traffic_lights",
sol::property([](const ExtractionNode &node) { return node.traffic_lights; },
[](ExtractionNode &node, const sol::object &obj) {
if (obj.is<bool>())
{
// The old approach of assigning a boolean traffic light
// state to the node is converted to the class enum
// TODO: Make a breaking API change and remove this option.
bool val = obj.as<bool>();
node.traffic_lights = (val) ? TrafficLightClass::DIRECTION_ALL
: TrafficLightClass::NONE;
return;
}
BOOST_ASSERT(obj.is<TrafficLightClass::Direction>());
{
TrafficLightClass::Direction val =
obj.as<TrafficLightClass::Direction>();
node.traffic_lights = val;
}
}),
"barrier",
&ExtractionNode::barrier);
context.state.new_usertype<RoadClassification>(
"RoadClassification",

View File

@ -44,7 +44,7 @@ std::size_t loadGraph(const std::string &path,
auto nop = boost::make_function_output_iterator([](auto) {});
extractor::files::readRawNBGraph(
path, nop, nop, coordinate_list, osm_node_ids, edge_list, annotation_data);
path, nop, coordinate_list, osm_node_ids, edge_list, annotation_data);
// Building a node-based graph
for (const auto &input_edge : edge_list)

View File

@ -34,10 +34,11 @@ namespace csv
SegmentLookupTable readSegmentValues(const std::vector<std::string> &paths)
{
static const auto value_if_blank = std::numeric_limits<double>::quiet_NaN();
const qi::real_parser<double, qi::ureal_policies<double>> unsigned_double;
CSVFilesParser<Segment, SpeedSource> parser(
1,
qi::ulong_long >> ',' >> qi::ulong_long,
qi::uint_ >> -(',' >> (qi::double_ | qi::attr(value_if_blank))));
unsigned_double >> -(',' >> (qi::double_ | qi::attr(value_if_blank))));
// Check consistency of keys in the result lookup table
auto result = parser(paths);

View File

@ -9,7 +9,6 @@
#include <boost/test/unit_test.hpp>
#include <iostream>
#include <unordered_set>
#include <vector>
@ -66,7 +65,7 @@ BOOST_AUTO_TEST_CASE(long_road_test)
GraphCompressor compressor;
std::unordered_set<NodeID> barrier_nodes;
std::unordered_set<NodeID> traffic_lights;
TrafficSignals traffic_lights;
std::vector<TurnRestriction> restrictions;
std::vector<NodeBasedEdgeAnnotation> annotations(1);
CompressedEdgeContainer container;
@ -112,7 +111,7 @@ BOOST_AUTO_TEST_CASE(loop_test)
GraphCompressor compressor;
std::unordered_set<NodeID> barrier_nodes;
std::unordered_set<NodeID> traffic_lights;
TrafficSignals traffic_lights;
std::vector<TurnRestriction> restrictions;
CompressedEdgeContainer container;
std::vector<NodeBasedEdgeAnnotation> annotations(1);
@ -175,7 +174,7 @@ BOOST_AUTO_TEST_CASE(t_intersection)
GraphCompressor compressor;
std::unordered_set<NodeID> barrier_nodes;
std::unordered_set<NodeID> traffic_lights;
TrafficSignals traffic_lights;
std::vector<NodeBasedEdgeAnnotation> annotations(1);
std::vector<TurnRestriction> restrictions;
CompressedEdgeContainer container;
@ -218,7 +217,7 @@ BOOST_AUTO_TEST_CASE(street_name_changes)
GraphCompressor compressor;
std::unordered_set<NodeID> barrier_nodes;
std::unordered_set<NodeID> traffic_lights;
TrafficSignals traffic_lights;
std::vector<NodeBasedEdgeAnnotation> annotations(2);
std::vector<TurnRestriction> restrictions;
CompressedEdgeContainer container;
@ -256,7 +255,7 @@ BOOST_AUTO_TEST_CASE(direction_changes)
GraphCompressor compressor;
std::unordered_set<NodeID> barrier_nodes;
std::unordered_set<NodeID> traffic_lights;
TrafficSignals traffic_lights;
std::vector<NodeBasedEdgeAnnotation> annotations(1);
std::vector<TurnRestriction> restrictions;
CompressedEdgeContainer container;

View File

@ -19,7 +19,7 @@ using Graph = util::NodeBasedDynamicGraph;
BOOST_AUTO_TEST_CASE(simple_intersection_connectivity)
{
std::unordered_set<NodeID> barrier_nodes{6};
std::unordered_set<NodeID> traffic_lights;
TrafficSignals traffic_lights;
std::vector<NodeBasedEdgeAnnotation> annotations{
{EMPTY_NAMEID, 0, INAVLID_CLASS_DATA, TRAVEL_MODE_DRIVING, false},
{EMPTY_NAMEID, 1, INAVLID_CLASS_DATA, TRAVEL_MODE_DRIVING, false}};
@ -152,7 +152,7 @@ BOOST_AUTO_TEST_CASE(simple_intersection_connectivity)
BOOST_AUTO_TEST_CASE(roundabout_intersection_connectivity)
{
std::unordered_set<NodeID> barrier_nodes;
std::unordered_set<NodeID> traffic_lights;
TrafficSignals traffic_lights;
std::vector<NodeBasedEdgeAnnotation> annotations;
std::vector<TurnRestriction> restrictions;
CompressedEdgeContainer container;
@ -259,7 +259,7 @@ BOOST_AUTO_TEST_CASE(roundabout_intersection_connectivity)
BOOST_AUTO_TEST_CASE(skip_degree_two_nodes)
{
std::unordered_set<NodeID> barrier_nodes{1};
std::unordered_set<NodeID> traffic_lights{2};
TrafficSignals traffic_lights = {{2}, {}};
std::vector<NodeBasedEdgeAnnotation> annotations(1);
std::vector<TurnRestriction> restrictions;
CompressedEdgeContainer container;