intersection classes with variable degree of discretization

This commit is contained in:
Moritz Kobitzsch 2016-05-10 08:37:45 +02:00 committed by Patrick Niklaus
parent 0f3942558f
commit 4d9aa65e78
No known key found for this signature in database
GPG Key ID: E426891B5F978B1B
23 changed files with 724 additions and 702 deletions

View File

@ -12,6 +12,7 @@
- Better support for osrm-routed binary upgrade on the fly [UNIX specific]:
- Open sockets with SO_REUSEPORT to allow multiple osrm-routed processes serving requests from the same port.
- Add SIGNAL_PARENT_WHEN_READY environment variable to enable osrm-routed signal its parent with USR1 when it's running and waiting for requests.
- BREAKING: Intersection Classification adds a new file to the mix (osrm.icd). This breaks the fileformat for older versions.
- Guidance:
- improved detection of turning streets, not reporting new-name in wrong situations

View File

@ -0,0 +1,134 @@
@routing @guidance @intersections
Feature: Intersections Data
Background:
Given the profile "car"
Given a grid size of 10 meters
Scenario: Passing Three Way South
Given the node map
| a | | b | | c |
| | | d | | |
And the ways
| nodes | name |
| ab | through |
| bc | through |
| bd | corner |
When I route I should get
| waypoints | route | turns | intersections |
| a,c | through,through | depart,arrive | true:90 true:270 false:0,true:90 true:180 false:270;true:90 true:270 false:0 |
Scenario: Passing Three Way North
Given the node map
| | | d | | |
| a | | b | | c |
And the ways
| nodes | name |
| ab | through |
| bc | through |
| bd | corner |
When I route I should get
| waypoints | route | turns | intersections |
| a,c | through,through | depart,arrive | true:90 true:270 false:0,true:0 true:90 false:270;true:90 true:270 false:0 |
Scenario: Passing Oneway Street In
Given the node map
| | | d | | |
| a | | b | | c |
And the ways
| nodes | name | oneway |
| ab | through | no |
| bc | through | no |
| db | corner | yes |
When I route I should get
| waypoints | route | turns | intersections |
| a,c | through,through | depart,arrive | true:90 true:270 false:0,false:0 true:90 false:270;true:90 true:270 false:0 |
Scenario: Passing Oneway Street Out
Given the node map
| | | d | | |
| a | | b | | c |
And the ways
| nodes | name | oneway |
| ab | through | no |
| bc | through | no |
| bd | corner | yes |
When I route I should get
| waypoints | route | turns | intersections |
| a,c | through,through | depart,arrive | true:90 true:270 false:0,true:0 true:90 false:270;true:90 true:270 false:0 |
Scenario: Passing Two Intersections
Given the node map
| | | e | | | | |
| a | | b | | c | | d |
| | | | | f | | |
And the ways
| nodes | name |
| ab | through |
| bc | through |
| cd | through |
| be | corner |
| cf | corner |
When I route I should get
| waypoints | route | turns | intersections |
| a,d | through,through | depart,arrive | true:90 true:270 false:0,true:0 true:90 false:270,true:90 true:180 false:270;true:90 true:270 false:0 |
Scenario: Passing Two Intersections, Collapsing
Given the node map
| | | e | | | | |
| a | | b | | c | | d |
| | | | | f | | |
And the ways
| nodes | name |
| ab | through |
| bc | throughbridge |
| cd | through |
| be | corner |
| cf | corner |
When I route I should get
| waypoints | route | turns | intersections |
| a,d | through,through | depart,arrive | true:90 true:270 false:0,true:0 true:90 false:270,true:90 true:180 false:270;true:90 true:270 false:0 |
| f,a | corner,throughbridge,through | depart,end of road left,arrive | true:0 true:180;true:90 false:180 true:270,true:0 false:90 true:270;true:90 true:270 false:0 |
Scenario: Roundabouts
Given the node map
| | | | | e | | | | |
| | | | | | | | | |
| | | | | a | | | | |
| | | | 1 | | 4 | | | |
| | | | | | | | | |
| f | | b | | | | d | | h |
| | | | | | | | | |
| | | | 2 | | 3 | | | |
| | | | | c | | | | |
| | | | | | | | | |
| | | | | g | | | | |
And the ways
| nodes | junction |
| abcda | roundabout |
| ea | |
| fb | |
| gc | |
| hd | |
When I route I should get
| waypoints | route | turns | intersections |
| e,f | ea,fb,fb | depart,abcda-exit-1,arrive | true:0 true:180;false:0 false:150 true:210,false:30 true:150 true:270;true:90 true:270 false:0 |
| e,g | ea,gc,gc | depart,abcda-exit-2,arrive | true:0 true:180;false:0 false:150 true:210,false:30 true:150 true:270,true:30 true:180 false:330;true:0 true:180 |
| e,h | ea,hd,hd | depart,abcda-exit-3,arrive | true:0 true:180;false:0 false:150 true:210,false:30 true:150 true:270,true:30 true:180 false:330,true:90 false:210 true:330;true:90 true:270 false:0 |
| e,2 | ea,abcda,abcda | depart,abcda-exit-undefined,arrive | true:0 true:180;false:0 false:150 true:210,false:30 true:150 true:270;true:146 false:326 false:0 |
| 1,g | abcda,gc,gc | depart,abcda-exit-2,arrive | false:34 true:214 false:0;false:34 true:214,false:30 true:150 true:270,true:30 true:180 false:330;true:0 true:180 |
| 1,3 | abcda,abcda | depart,arrive | false:34 true:214 false:0,false:30 true:150 true:270,true:30 true:180 false:330;true:34 false:214 false:0 |

View File

@ -46,8 +46,8 @@ module.exports = function () {
if (headers.has('trips')) {
subTrips = json.trips.filter(t => !!t).map(t => t.legs).map(tl => Array.prototype.concat.apply([], tl.map((sl, i) => {
var toAdd = [];
if (i === 0) toAdd.push(sl.steps[0].maneuver.location);
toAdd.push(sl.steps[sl.steps.length-1].maneuver.location);
if (i === 0) toAdd.push(sl.steps[0].intersections[0].location);
toAdd.push(sl.steps[sl.steps.length-1].intersections[0].location);
return toAdd;
})));
}

View File

@ -222,7 +222,7 @@ module.exports = function () {
});
};
['osrm','osrm.names','osrm.restrictions','osrm.ebg','osrm.enw','osrm.edges','osrm.fileIndex','osrm.geometry','osrm.nodes','osrm.ramIndex','osrm.properties'].forEach(file => {
['osrm','osrm.names','osrm.restrictions','osrm.ebg','osrm.enw','osrm.edges','osrm.fileIndex','osrm.geometry','osrm.nodes','osrm.ramIndex','osrm.properties','osrm.icd'].forEach(file => {
q.defer(rename, file);
});
@ -273,7 +273,7 @@ module.exports = function () {
var q = d3.queue();
['osrm.hsgr','osrm.fileIndex','osrm.geometry','osrm.nodes','osrm.ramIndex','osrm.core','osrm.edges','osrm.datasource_indexes','osrm.datasource_names','osrm.level'].forEach((file) => {
['osrm.hsgr','osrm.fileIndex','osrm.geometry','osrm.nodes','osrm.ramIndex','osrm.core','osrm.edges','osrm.datasource_indexes','osrm.datasource_names','osrm.level','osrm.icd'].forEach((file) => {
q.defer(rename, file);
});

View File

@ -138,7 +138,7 @@ module.exports = function () {
};
this.bearingList = (instructions) => {
return this.extractInstructionList(instructions, s => s.maneuver.bearing_after);
return this.extractInstructionList(instructions, s => s.intersections[0].bearings[s.intersections[0].bearing_after]);
};
this.annotationList = (instructions) => {
@ -178,6 +178,19 @@ module.exports = function () {
.join(',');
};
this.intersectionList = (instructions) => {
return instructions.legs.reduce((m, v) => m.concat(v.steps), [])
.map( v => {
return v.intersections
.map( intersection => {
var string = intersection.entry[0]+':'+intersection.bearings[0], i;
for( i = 1; i < intersection.bearings.length; ++i )
string = string + ' ' + intersection.entry[i]+':'+intersection.bearings[i];
return string;
}).join(',')
}).join(';')
};
this.modeList = (instructions) => {
return this.extractInstructionList(instructions, s => s.mode);
};

View File

@ -31,7 +31,7 @@ module.exports = function () {
var afterRequest = (err, res, body) => {
if (err) return cb(err);
if (body && body.length) {
var instructions, bearings, turns, modes, times, distances, summary;
var instructions, bearings, turns, modes, times, distances, summary, intersections;
var json = JSON.parse(body);
@ -41,6 +41,7 @@ module.exports = function () {
instructions = this.wayList(json.routes[0]);
bearings = this.bearingList(json.routes[0]);
turns = this.turnList(json.routes[0]);
intersections = this.intersectionList(json.routes[0]);
modes = this.modeList(json.routes[0]);
times = this.timeList(json.routes[0]);
distances = this.distanceList(json.routes[0]);
@ -108,6 +109,10 @@ module.exports = function () {
}
}
if (headers.has('intersections')) {
got.intersections = (intersections || '').trim();
}
var putValue = (key, value) => {
if (headers.has(key)) got[key] = instructions ? value : '';
};

View File

@ -9,12 +9,12 @@
#include "util/guidance/bearing_class.hpp"
#include "util/guidance/entry_class.hpp"
#include "storage/storage_config.hpp"
#include "engine/geospatial_query.hpp"
#include "extractor/compressed_edge_container.hpp"
#include "extractor/original_edge_data.hpp"
#include "extractor/profile_properties.hpp"
#include "extractor/query_node.hpp"
#include "storage/storage_config.hpp"
#include "util/graph_loader.hpp"
#include "util/io.hpp"
#include "util/range_table.hpp"
@ -23,6 +23,7 @@
#include "util/simple_logger.hpp"
#include "util/static_graph.hpp"
#include "util/static_rtree.hpp"
#include "util/typedefs.hpp"
#include "osrm/coordinate.hpp"
@ -100,7 +101,8 @@ class InternalDataFacade final : public BaseDataFacade
util::ShM<util::guidance::EntryClass, false>::vector m_entry_class_table;
// the look-up table for distinct bearing classes. A bearing class lists the available bearings
// at an intersection
util::ShM<util::guidance::BearingClass, false>::vector m_bearing_class_table;
util::RangeTable<16, false> m_bearing_ranges_table;
util::ShM<DiscreteBearing, false>::vector m_bearing_values_table;
void LoadProfileProperties(const boost::filesystem::path &properties_path)
{
@ -299,34 +301,43 @@ class InternalDataFacade final : public BaseDataFacade
{
std::ifstream intersection_stream(intersection_class_file.string(), std::ios::binary);
if (!intersection_stream)
util::SimpleLogger().Write(logWARNING) << "Failed to open " << intersection_class_file
<< " for reading.";
throw util::exception("Could not open " + intersection_class_file.string() +
" for reading.");
if (!util::readAndCheckFingerprint(intersection_stream))
{
util::SimpleLogger().Write(logWARNING)
<< "Fingerprint does not match or reading failed";
exit(-1);
}
throw util::exception("Fingeprint does not match in " +
intersection_class_file.string());
{
util::SimpleLogger().Write(logINFO) << "Loading Bearing Class IDs";
std::vector<BearingClassID> bearing_class_id;
util::deserializeVector(intersection_stream, bearing_class_id);
if (!util::deserializeVector(intersection_stream, bearing_class_id))
throw util::exception("Reading from " + intersection_class_file.string() + " failed.");
m_bearing_class_id_table.resize(bearing_class_id.size());
std::copy(bearing_class_id.begin(), bearing_class_id.end(),
&m_bearing_class_id_table[0]);
}
{
util::SimpleLogger().Write(logINFO) << "Loading Bearing Classes";
// read the range table
intersection_stream >> m_bearing_ranges_table;
std::vector<util::guidance::BearingClass> bearing_classes;
util::deserializeVector(intersection_stream, bearing_classes);
m_bearing_class_table.resize(bearing_classes.size());
std::copy(bearing_classes.begin(), bearing_classes.end(), &m_bearing_class_table[0]);
// and the actual bearing values
std::uint64_t num_bearings;
intersection_stream >> num_bearings;
m_bearing_values_table.resize(num_bearings);
intersection_stream.read(reinterpret_cast<char *>(&m_bearing_values_table[0]),
sizeof(m_bearing_values_table[0]) * num_bearings);
if (!static_cast<bool>(intersection_stream))
throw util::exception("Reading from " + intersection_class_file.string() + " failed.");
}
{
util::SimpleLogger().Write(logINFO) << "Loading Entry Classes";
std::vector<util::guidance::EntryClass> entry_classes;
util::deserializeVector(intersection_stream, entry_classes);
if (!util::deserializeVector(intersection_stream, entry_classes))
throw util::exception("Reading from " + intersection_class_file.string() + " failed.");
m_entry_class_table.resize(entry_classes.size());
std::copy(entry_classes.begin(), entry_classes.end(), &m_entry_class_table[0]);
}
@ -509,9 +520,8 @@ class InternalDataFacade final : public BaseDataFacade
bearing, bearing_range);
}
std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const double max_distance) const override final
std::pair<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
const util::Coordinate input_coordinate, const double max_distance) const override final
{
BOOST_ASSERT(m_geospatial_query.get());
@ -676,7 +686,15 @@ class InternalDataFacade final : public BaseDataFacade
GetBearingClass(const BearingClassID bearing_class_id) const override final
{
BOOST_ASSERT(bearing_class_id != INVALID_BEARING_CLASSID);
return m_bearing_class_table.at(bearing_class_id);
auto range = m_bearing_ranges_table.GetRange(bearing_class_id);
util::guidance::BearingClass result;
for (auto itr = m_bearing_values_table.begin() + range.front();
itr != m_bearing_values_table.begin() + range.back() + 1; ++itr)
result.add(*itr);
return result;
}
EntryClassID GetEntryClassID(const EdgeID eid) const override final
@ -686,7 +704,6 @@ class InternalDataFacade final : public BaseDataFacade
util::guidance::EntryClass GetEntryClass(const EntryClassID entry_class_id) const override final
{
BOOST_ASSERT(entry_class_id != INVALID_ENTRY_CLASSID);
return m_entry_class_table.at(entry_class_id);
}
};

View File

@ -7,9 +7,9 @@
#include "storage/shared_datatype.hpp"
#include "storage/shared_memory.hpp"
#include "extractor/compressed_edge_container.hpp"
#include "extractor/guidance/turn_instruction.hpp"
#include "extractor/profile_properties.hpp"
#include "extractor/compressed_edge_container.hpp"
#include "util/guidance/bearing_class.hpp"
#include "util/guidance/entry_class.hpp"
@ -20,6 +20,7 @@
#include "util/simple_logger.hpp"
#include "util/static_graph.hpp"
#include "util/static_rtree.hpp"
#include "util/typedefs.hpp"
#include <cstddef>
@ -51,7 +52,7 @@ class SharedDataFacade final : public BaseDataFacade
using QueryGraph = util::StaticGraph<EdgeData, true>;
using GraphNode = QueryGraph::NodeArrayEntry;
using GraphEdge = QueryGraph::EdgeArrayEntry;
using NameIndexBlock = util::RangeTable<16, true>::BlockT;
using IndexBlock = util::RangeTable<16, true>::BlockT;
using InputEdge = QueryGraph::InputEdge;
using RTreeLeaf = super::RTreeLeaf;
using SharedRTree =
@ -105,7 +106,8 @@ class SharedDataFacade final : public BaseDataFacade
util::ShM<util::guidance::EntryClass, true>::vector m_entry_class_table;
// the look-up table for distinct bearing classes. A bearing class lists the available bearings
// at an intersection
util::ShM<util::guidance::BearingClass, true>::vector m_bearing_class_table;
std::shared_ptr<util::RangeTable<16, true>> m_bearing_ranges_table;
util::ShM<DiscreteBearing, true>::vector m_bearing_values_table;
void LoadChecksum()
{
@ -206,11 +208,11 @@ class SharedDataFacade final : public BaseDataFacade
{
auto offsets_ptr = data_layout->GetBlockPtr<unsigned>(
shared_memory, storage::SharedDataLayout::NAME_OFFSETS);
auto blocks_ptr = data_layout->GetBlockPtr<NameIndexBlock>(
auto blocks_ptr = data_layout->GetBlockPtr<IndexBlock>(
shared_memory, storage::SharedDataLayout::NAME_BLOCKS);
util::ShM<unsigned, true>::vector name_offsets(
offsets_ptr, data_layout->num_entries[storage::SharedDataLayout::NAME_OFFSETS]);
util::ShM<NameIndexBlock, true>::vector name_blocks(
util::ShM<IndexBlock, true>::vector name_blocks(
blocks_ptr, data_layout->num_entries[storage::SharedDataLayout::NAME_BLOCKS]);
auto names_list_ptr = data_layout->GetBlockPtr<char>(
@ -283,7 +285,7 @@ class SharedDataFacade final : public BaseDataFacade
m_datasource_name_lengths = std::move(datasource_name_lengths);
}
void LoadIntersecionClasses()
void LoadIntersectionClasses()
{
auto bearing_class_id_ptr = data_layout->GetBlockPtr<BearingClassID>(
shared_memory, storage::SharedDataLayout::BEARING_CLASSID);
@ -292,11 +294,23 @@ class SharedDataFacade final : public BaseDataFacade
data_layout->num_entries[storage::SharedDataLayout::BEARING_CLASSID]);
m_bearing_class_id_table = std::move(bearing_class_id_table);
auto bearing_class_ptr = data_layout->GetBlockPtr<util::guidance::BearingClass>(
shared_memory, storage::SharedDataLayout::BEARING_CLASS);
typename util::ShM<util::guidance::BearingClass, true>::vector bearing_class_table(
bearing_class_ptr, data_layout->num_entries[storage::SharedDataLayout::BEARING_CLASS]);
m_bearing_class_table = std::move(bearing_class_table);
auto bearing_class_ptr = data_layout->GetBlockPtr<DiscreteBearing>(
shared_memory, storage::SharedDataLayout::BEARING_VALUES);
typename util::ShM<DiscreteBearing, true>::vector bearing_class_table(
bearing_class_ptr, data_layout->num_entries[storage::SharedDataLayout::BEARING_VALUES]);
m_bearing_values_table = std::move(bearing_class_table);
auto offsets_ptr = data_layout->GetBlockPtr<unsigned>(
shared_memory, storage::SharedDataLayout::BEARING_OFFSETS);
auto blocks_ptr = data_layout->GetBlockPtr<IndexBlock>(
shared_memory, storage::SharedDataLayout::BEARING_BLOCKS);
util::ShM<unsigned, true>::vector bearing_offsets(
offsets_ptr, data_layout->num_entries[storage::SharedDataLayout::BEARING_OFFSETS]);
util::ShM<IndexBlock, true>::vector bearing_blocks(
blocks_ptr, data_layout->num_entries[storage::SharedDataLayout::BEARING_BLOCKS]);
m_bearing_ranges_table = util::make_unique<util::RangeTable<16, true>>(
bearing_offsets, bearing_blocks, static_cast<unsigned>(m_bearing_values_table.size()));
auto entry_class_ptr = data_layout->GetBlockPtr<util::guidance::EntryClass>(
shared_memory, storage::SharedDataLayout::ENTRY_CLASS);
@ -392,7 +406,7 @@ class SharedDataFacade final : public BaseDataFacade
LoadCoreInformation();
LoadProfileProperties();
LoadRTree();
LoadIntersecionClasses();
LoadIntersectionClasses();
util::SimpleLogger().Write() << "number of geometries: "
<< m_coordinate_list.size();
@ -702,8 +716,6 @@ class SharedDataFacade final : public BaseDataFacade
{
return m_profile_properties->continue_straight_at_waypoint;
}
<<<<<<< HEAD
=======
BearingClassID GetBearingClassID(const NodeID id) const override final
{
@ -714,7 +726,12 @@ class SharedDataFacade final : public BaseDataFacade
GetBearingClass(const BearingClassID bearing_class_id) const override final
{
BOOST_ASSERT(bearing_class_id != INVALID_BEARING_CLASSID);
return m_bearing_class_table.at(bearing_class_id);
auto range = m_bearing_ranges_table->GetRange(bearing_class_id);
util::guidance::BearingClass result;
for (auto itr = m_bearing_values_table.begin() + range.front();
itr != m_bearing_values_table.begin() + range.back() + 1; ++itr)
result.add(*itr);
return result;
}
EntryClassID GetEntryClassID(const EdgeID eid) const override final
@ -724,10 +741,8 @@ class SharedDataFacade final : public BaseDataFacade
util::guidance::EntryClass GetEntryClass(const EntryClassID entry_class_id) const override final
{
BOOST_ASSERT(entry_class_id != INVALID_ENTRY_CLASSID);
return m_entry_class_table.at(entry_class_id);
}
>>>>>>> a5cb6a1... initial version of intersection classification
};
}
}

View File

@ -12,7 +12,7 @@
#include "util/bearing.hpp"
#include "util/coordinate.hpp"
#include "util/coordinate_calculation.hpp"
#include "util/guidance/bearing_class.hpp"
#include "util/guidance/toolkit.hpp"
#include "util/guidance/entry_class.hpp"
#include "util/typedefs.hpp"
@ -28,15 +28,12 @@ namespace guidance
{
namespace detail
{
StepManeuver stepManeuverFromGeometry(extractor::guidance::TurnInstruction instruction,
const LegGeometry &leg_geometry,
const std::size_t segment_index,
util::guidance::EntryClass entry_class,
util::guidance::BearingClass bearing_class);
StepManeuver stepManeuverFromGeometry(extractor::guidance::TurnInstruction instruction,
const WaypointType waypoint_type,
const LegGeometry &leg_geometry);
Intersection intersectionFromGeometry(const WaypointType waypoint_type,
const double segment_duration,
const LegGeometry &leg_geometry,
const std::size_t segment_index);
} // ns detail
template <typename DataFacadeT>
@ -70,10 +67,13 @@ std::vector<RouteStep> assembleSteps(const DataFacadeT &facade,
if (leg_data.size() > 0)
{
StepManeuver maneuver = {extractor::guidance::TurnInstruction::NO_TURN(),
WaypointType::Depart, 0};
StepManeuver maneuver = detail::stepManeuverFromGeometry(
extractor::guidance::TurnInstruction::NO_TURN(), WaypointType::Depart, leg_geometry);
maneuver.location = source_node.location;
auto intersection =
detail::intersectionFromGeometry(WaypointType::Depart, 0, leg_geometry, 0);
intersection = util::guidance::setIntersectionClasses(std::move(intersection), source_node);
// maneuver.location = source_node.location;
// PathData saves the information we need of the segment _before_ the turn,
// but a RouteStep is with regard to the segment after the turn.
@ -95,19 +95,25 @@ std::vector<RouteStep> assembleSteps(const DataFacadeT &facade,
BOOST_ASSERT(segment_duration >= 0);
const auto name = facade.GetNameForID(step_name_id);
const auto distance = leg_geometry.segment_distances[segment_index];
steps.push_back(RouteStep{step_name_id, name, NO_ROTARY_NAME,
segment_duration / 10.0, distance, path_point.travel_mode,
maneuver, leg_geometry.FrontIndex(segment_index),
leg_geometry.BackIndex(segment_index) + 1});
if (leg_data_index + 1 < leg_data.size()){
std::vector<Intersection> intersections(1, intersection);
intersection = detail::intersectionFromGeometry(
WaypointType::None, segment_duration / 10., leg_geometry, segment_index);
intersection.entry_class = facade.GetEntryClass(path_point.entry_classid);
intersection.bearing_class =
facade.GetBearingClass(facade.GetBearingClassID(path_point.turn_via_node));
steps.push_back(RouteStep{
step_name_id, name, NO_ROTARY_NAME, segment_duration / 10.0, distance,
path_point.travel_mode, maneuver, leg_geometry.FrontIndex(segment_index),
leg_geometry.BackIndex(segment_index) + 1, std::move(intersections)});
if (leg_data_index + 1 < leg_data.size())
{
step_name_id = leg_data[leg_data_index + 1].name_id;
} else {
}
else
{
step_name_id = target_node.name_id;
}
maneuver = detail::stepManeuverFromGeometry(
path_point.turn_instruction, leg_geometry, segment_index,
facade.GetEntryClass(path_point.entry_classid),
facade.GetBearingClass(facade.GetBearingClassID(path_point.turn_via_node)));
maneuver = {path_point.turn_instruction, WaypointType::None, 0};
segment_index++;
segment_duration = 0;
}
@ -115,10 +121,10 @@ std::vector<RouteStep> assembleSteps(const DataFacadeT &facade,
const auto distance = leg_geometry.segment_distances[segment_index];
const int duration = segment_duration + target_duration;
BOOST_ASSERT(duration >= 0);
steps.push_back(RouteStep{step_name_id, facade.GetNameForID(step_name_id),
NO_ROTARY_NAME, duration / 10., distance, target_mode, maneuver,
leg_geometry.FrontIndex(segment_index),
leg_geometry.BackIndex(segment_index) + 1});
steps.push_back(RouteStep{
step_name_id, facade.GetNameForID(step_name_id), NO_ROTARY_NAME, duration / 10.,
distance, target_mode, maneuver, leg_geometry.FrontIndex(segment_index),
leg_geometry.BackIndex(segment_index) + 1, std::vector<Intersection>(1, intersection)});
}
// In this case the source + target are on the same edge segment
else
@ -129,28 +135,37 @@ std::vector<RouteStep> assembleSteps(const DataFacadeT &facade,
// |---| source_duration
// |---------| target_duration
StepManeuver maneuver = detail::stepManeuverFromGeometry(
extractor::guidance::TurnInstruction::NO_TURN(), WaypointType::Depart, leg_geometry);
StepManeuver maneuver = {extractor::guidance::TurnInstruction::NO_TURN(),
WaypointType::Depart, 0};
int duration = target_duration - source_duration;
BOOST_ASSERT(duration >= 0);
steps.push_back(RouteStep{source_node.name_id, facade.GetNameForID(source_node.name_id),
NO_ROTARY_NAME, duration / 10.,
leg_geometry.segment_distances[segment_index], source_mode,
std::move(maneuver), leg_geometry.FrontIndex(segment_index),
leg_geometry.BackIndex(segment_index) + 1});
auto intersection = detail::intersectionFromGeometry(WaypointType::Depart, duration / 10.,
leg_geometry, segment_index);
intersection = util::guidance::setIntersectionClasses(std::move(intersection), source_node);
steps.push_back(RouteStep{
source_node.name_id, facade.GetNameForID(source_node.name_id), NO_ROTARY_NAME,
duration / 10., leg_geometry.segment_distances[segment_index], source_mode,
std::move(maneuver), leg_geometry.FrontIndex(segment_index),
leg_geometry.BackIndex(segment_index) + 1, std::vector<Intersection>(1, intersection)});
}
BOOST_ASSERT(segment_index == number_of_segments - 1);
// This step has length zero, the only reason we need it is the target location
auto final_maneuver = detail::stepManeuverFromGeometry(
extractor::guidance::TurnInstruction::NO_TURN(), WaypointType::Arrive, leg_geometry);
StepManeuver final_maneuver = {extractor::guidance::TurnInstruction::NO_TURN(),
WaypointType::Arrive, 0};
auto intersection =
detail::intersectionFromGeometry(WaypointType::Arrive, 0, leg_geometry, segment_index);
intersection = util::guidance::setIntersectionClasses(std::move(intersection), target_node);
BOOST_ASSERT(!leg_geometry.locations.empty());
steps.push_back(RouteStep{target_node.name_id, facade.GetNameForID(target_node.name_id),
NO_ROTARY_NAME, ZERO_DURATION, ZERO_DISTANCE, target_mode,
final_maneuver, leg_geometry.locations.size() - 1,
leg_geometry.locations.size()});
std::move(final_maneuver), leg_geometry.locations.size() - 1,
leg_geometry.locations.size(),
std::vector<Intersection>(1, intersection)});
return steps;
}

View File

@ -3,6 +3,9 @@
#include "engine/guidance/step_maneuver.hpp"
#include "extractor/travel_mode.hpp"
#include "util/coordinate.hpp"
#include "util/guidance/bearing_class.hpp"
#include "util/guidance/entry_class.hpp"
#include <cstddef>
@ -21,6 +24,30 @@ namespace guidance
// Notable exceptions are Departure and Arrival steps.
// Departue: s --> a --> b. Represents the segment s,a with location being s.
// Arrive: a --> b --> t. The segment (b,t) is already covered by the previous segment.
// A represenetation of intermediate intersections
struct Intersection
{
double duration;
double distance;
util::Coordinate location;
double bearing_before;
double bearing_after;
util::guidance::EntryClass entry_class;
util::guidance::BearingClass bearing_class;
};
inline Intersection getInvalidIntersection()
{
return {0,
0,
util::Coordinate{util::FloatLongitude{0.0}, util::FloatLatitude{0.0}},
0,
0,
util::guidance::EntryClass(),
util::guidance::BearingClass()};
}
struct RouteStep
{
unsigned name_id;
@ -33,11 +60,21 @@ struct RouteStep
// indices into the locations array stored the LegGeometry
std::size_t geometry_begin;
std::size_t geometry_end;
std::vector<Intersection> intersections;
};
inline RouteStep getInvalidRouteStep()
{
return {0, "", "", 0, 0, TRAVEL_MODE_INACCESSIBLE, getInvalidStepManeuver(), 0, 0};
return {0,
"",
"",
0,
0,
TRAVEL_MODE_INACCESSIBLE,
getInvalidStepManeuver(),
0,
0,
std::vector<Intersection>(1, getInvalidIntersection())};
}
}
}

View File

@ -3,8 +3,6 @@
#include "extractor/guidance/turn_instruction.hpp"
#include "util/coordinate.hpp"
#include "util/guidance/bearing_class.hpp"
#include "util/guidance/entry_class.hpp"
#include <cstdint>
#include <vector>
@ -23,38 +21,16 @@ enum class WaypointType : std::uint8_t
Depart,
};
// A represenetation of intermediate intersections
struct IntermediateIntersection
{
double duration;
double distance;
util::Coordinate location;
util::guidance::EntryClass entry_class;
util::guidance::BearingClass bearing_class;
};
struct StepManeuver
{
util::Coordinate location;
double bearing_before;
double bearing_after;
extractor::guidance::TurnInstruction instruction;
WaypointType waypoint_type;
unsigned exit;
util::guidance::EntryClass entry_class;
util::guidance::BearingClass bearing_class;
std::vector<IntermediateIntersection> intersections;
};
inline StepManeuver getInvalidStepManeuver()
{
return {util::Coordinate{util::FloatLongitude{0.0}, util::FloatLatitude{0.0}},
0,
0,
extractor::guidance::TurnInstruction::NO_TURN(),
WaypointType::None,
0,
{}};
return {extractor::guidance::TurnInstruction::NO_TURN(), WaypointType::None, 0};
}
} // namespace guidance

View File

@ -44,8 +44,10 @@ struct SharedDataLayout
DATASOURCE_NAME_LENGTHS,
PROPERTIES,
BEARING_CLASSID,
BEARING_OFFSETS,
BEARING_BLOCKS,
BEARING_VALUES,
ENTRY_CLASS,
BEARING_CLASS,
NUM_BLOCKS
};

View File

@ -6,6 +6,10 @@
#include <functional>
#include <vector>
#include <boost/functional/hash.hpp>
#include "util/typedefs.hpp"
namespace osrm
{
namespace util
@ -35,24 +39,8 @@ namespace guidance
class BearingClass
{
public:
using FlagBaseType = std::uint32_t;
const static constexpr double discrete_angle_step_size = 360. / 32;
BearingClass();
// add a continuous angle to the, returns true if no item existed that uses the same discrete
// angle
bool addContinuous(const double bearing);
// add a discrete ID, returns true if no item existed that uses the same discrete angle
bool addDiscreteID(const std::uint8_t id);
//remove a bearing from the list
void resetContinuous(const double bearing);
void resetDiscreteID(const std::uint8_t id);
//is available
bool hasContinuous(const double bearing) const;
bool hasDiscrete(const std::uint8_t id) const;
// Add a bearing to the set
void add(const DiscreteBearing bearing);
// hashing
bool operator==(const BearingClass &other) const;
@ -60,19 +48,15 @@ class BearingClass
// sorting
bool operator<(const BearingClass &other) const;
std::vector<double> getAvailableBearings() const;
const std::vector<DiscreteBearing> &getAvailableBearings() const;
// get a discrete representation of an angle. Required to map a bearing/angle to the discrete
// ones stored within the class
static std::uint8_t angleToDiscreteID(double angle);
static double discreteIDToAngle( const std::uint8_t );
std::size_t findMatchingBearing(const double bearing) const;
const constexpr static double discrete_step_size = 360. / 24.;
static DiscreteBearing getDiscreteBearing(const double bearing);
// we are hiding the access to the flags behind a protection wall, to make sure the bit logic
// isn't tempered with
private:
// given a list of possible discrete angles, the available angles flag indicates the presence of
// a given turn at the intersection
FlagBaseType available_bearings_mask;
std::vector<DiscreteBearing> available_bearings;
// allow hash access to internal representation
friend std::size_t std::hash<BearingClass>::operator()(const BearingClass &) const;
@ -88,8 +72,7 @@ namespace std
inline size_t hash<::osrm::util::guidance::BearingClass>::
operator()(const ::osrm::util::guidance::BearingClass &bearing_class) const
{
return hash<::osrm::util::guidance::BearingClass::FlagBaseType>()(
bearing_class.available_bearings_mask);
return boost::hash_value(bearing_class.available_bearings);
}
} // namespace std

View File

@ -5,6 +5,9 @@
#include <cstdint>
#include <functional>
#include <iostream>
#include <bitset>
namespace osrm
{
namespace util
@ -51,6 +54,11 @@ class EntryClass
// sorting
bool operator<(const EntryClass &) const;
inline void print() const
{
std::cout << "Flags: " << std::bitset<16>(enabled_entries_flags) << std::endl;
}
private:
// given a list of possible discrete angles, the available angles flag indicates the presence of
// a given turn at the intersection

View File

@ -3,6 +3,8 @@
/* A set of tools required for guidance in both pre and post-processing */
#include "engine/guidance/route_step.hpp"
#include "engine/phantom_node.hpp"
#include "extractor/guidance/turn_instruction.hpp"
#include "util/guidance/bearing_class.hpp"
#include "util/guidance/entry_class.hpp"
@ -47,74 +49,36 @@ inline extractor::guidance::DirectionModifier getTurnDirection(const double angl
return extractor::guidance::DirectionModifier::UTurn;
}
inline double getMatchingDiscreteBearing(const bool requires_entry,
const double bearing,
const EntryClass entry_class,
const std::vector<double> existing_bearings)
inline engine::guidance::Intersection
setIntersectionClasses(engine::guidance::Intersection intersection,
const engine::PhantomNode &phantom)
{
if (existing_bearings.empty())
return 0;
BOOST_ASSERT(intersection.bearing_before == 0 || intersection.bearing_after == 0);
const double bearing = std::max(intersection.bearing_before, intersection.bearing_after);
const double discrete_bearing =
BearingClass::discreteIDToAngle(BearingClass::angleToDiscreteID(bearing));
// it they are very close to the turn, the discrete bearing should be fine
if (std::abs(bearing - discrete_bearing) < 0.25 * BearingClass::discrete_angle_step_size)
intersection.bearing_class = {};
intersection.entry_class = {};
if (bearing >= 180.)
{
const auto isValidEntry = [&]() {
const auto bound = std::upper_bound(existing_bearings.begin(), existing_bearings.end(),
(discrete_bearing - 0.001));
const auto index = bound == existing_bearings.end()
? 0
: std::distance(existing_bearings.begin(), bound);
return entry_class.allowsEntry(index);
};
BOOST_ASSERT(!requires_entry || isValidEntry());
return discrete_bearing;
intersection.bearing_class.add(std::round(bearing - 180.));
if (phantom.forward_segment_id.id != SPECIAL_SEGMENTID &&
phantom.reverse_segment_id.id != SPECIAL_SEGMENTID)
intersection.entry_class.activate(0);
intersection.bearing_class.add(std::round(bearing));
intersection.entry_class.activate(1);
}
else
{
// the next larger bearing or first if we are wrapping around at zero
const auto next_index =
std::distance(existing_bearings.begin(),
std::lower_bound(existing_bearings.begin(), existing_bearings.end(),
discrete_bearing)) %
existing_bearings.size();
// next smaller bearing or last if we are wrapping around at zero
const auto previous_index =
(next_index + existing_bearings.size() - 1) % existing_bearings.size();
const auto difference = [](const double first, const double second) {
return std::min(std::abs(first - second), 360.0 - std::abs(first - second));
};
const auto next_bearing = existing_bearings[next_index];
const auto previous_bearing = existing_bearings[previous_index];
const auto decideOnBearing = [&](
const std::size_t preferred_index, const double preferred_bearing,
const std::size_t alternative_index, const double alternative_bearing) {
if (!requires_entry || entry_class.allowsEntry(preferred_index))
return preferred_bearing;
else if (entry_class.allowsEntry(alternative_index))
return alternative_bearing;
else
{
SimpleLogger().Write(logDEBUG)
<< "Cannot find a valid entry for a discrete Bearing in Turn Classificiation";
return 0.;
}
};
if (difference(bearing, next_bearing) < difference(bearing, previous_index))
return decideOnBearing(next_index, next_bearing, previous_index, previous_bearing);
else
return decideOnBearing(previous_index, previous_bearing, next_index, next_bearing);
intersection.bearing_class.add(std::round(bearing));
intersection.entry_class.activate(0);
intersection.bearing_class.add(std::round(bearing + 180.));
if (phantom.forward_segment_id.id != SPECIAL_SEGMENTID &&
phantom.reverse_segment_id.id != SPECIAL_SEGMENTID)
intersection.entry_class.activate(1);
}
return 0;
return intersection;
}
} // namespace guidance
} // namespace util
} // namespace osrm

View File

@ -61,6 +61,8 @@ using EdgeWeight = int;
using BearingClassID = std::uint32_t;
static const BearingClassID INVALID_BEARING_CLASSID = std::numeric_limits<std::uint32_t>::max();
using DiscreteBearing = std::uint16_t;
using EntryClassID = std::uint16_t;
static const EntryClassID INVALID_ENTRY_CLASSID = std::numeric_limits<std::uint16_t>::max();

View File

@ -37,31 +37,12 @@ const constexpr char *modifier_names[] = {"uturn", "sharp right", "right", "s
// translations of TurnTypes. Not all types are exposed to the outside world.
// invalid types should never be returned as part of the API
const constexpr char *turn_type_names[] = {"invalid",
"new name",
"continue",
"turn",
"merge",
"on ramp",
"off ramp",
"fork",
"end of road",
"notification",
"roundabout",
"roundabout",
"rotary",
"rotary",
"roundabout turn",
"roundabout turn",
"invalid",
"invalid",
"invalid",
"invalid",
"invalid",
"invalid",
"invalid",
"invalid",
"invalid"};
const constexpr char *turn_type_names[] = {
"invalid", "new name", "continue", "turn", "merge",
"on ramp", "off ramp", "fork", "end of road", "notification",
"roundabout", "roundabout", "rotary", "rotary", "roundabout turn",
"roundabout turn", "invalid", "invalid", "invalid", "invalid",
"invalid", "invalid", "invalid", "invalid", "invalid"};
const constexpr char *waypoint_type_names[] = {"invalid", "arrive", "depart"};
@ -97,47 +78,80 @@ util::json::Array coordinateToLonLat(const util::Coordinate coordinate)
return array;
}
util::json::Object getConnection(const bool entry_allowed, const double bearing)
util::json::Object
getIntersection(const guidance::Intersection &intersection, bool locate_before, bool locate_after)
{
util::json::Object result;
result.values["entry_allowed"] = entry_allowed ? "true" : "false";
result.values["bearing"] = bearing;
util::json::Array bearings;
util::json::Array entry;
const auto &available_bearings = intersection.bearing_class.getAvailableBearings();
for (std::size_t i = 0; i < available_bearings.size(); ++i)
{
bearings.values.push_back(std::to_string(available_bearings[i]));
entry.values.push_back(intersection.entry_class.allowsEntry(i) ? "true" : "false");
}
result.values["location"] = detail::coordinateToLonLat(intersection.location);
bool requires_correction = false;
if (locate_before || (!available_bearings.empty() && available_bearings.front()==0))
{
// bearings are oriented in the direction of driving. For the in-bearing, we actually need
// to
// find the bearing from the view of the intersection. This means we have to rotate the
// bearing
// by 180 degree.
const auto rotated_bearing_before = (intersection.bearing_before >= 180.0)
? (intersection.bearing_before - 180.0)
: (intersection.bearing_before + 180.0);
result.values["bearing_before"] =
intersection.bearing_class.findMatchingBearing(rotated_bearing_before);
}
else
{
result.values["bearing_before"] = available_bearings.size();
requires_correction = true;
}
if (locate_after || (!available_bearings.empty() && available_bearings.front()==0))
{
result.values["bearing_after"] =
intersection.bearing_class.findMatchingBearing(intersection.bearing_after);
}
else
{
result.values["bearing_after"] = available_bearings.size();
requires_correction = true;
}
if (requires_correction)
{
bearings.values.push_back("0");
entry.values.push_back("false");
}
result.values["bearings"] = bearings;
result.values["entry"] = entry;
return result;
}
util::json::Array getConnections(const util::guidance::EntryClass entry_class,
const util::guidance::BearingClass bearing_class)
util::json::Array getIntersection(const guidance::RouteStep &step)
{
util::json::Array result;
const auto bearings = bearing_class.getAvailableBearings();
for (size_t connection = 0; connection < bearings.size(); ++connection)
bool first = true;
for (const auto &intersection : step.intersections)
{
result.values.push_back(
getConnection(entry_class.allowsEntry(connection), bearings[connection]));
// on waypoints, the first/second bearing is invalid. In these cases, we cannot locate the
// bearing as part of the available bearings at the intersection.
result.values.push_back(getIntersection(
intersection, !first || step.maneuver.waypoint_type != guidance::WaypointType::Depart,
!first || step.maneuver.waypoint_type != guidance::WaypointType::Arrive));
first = false;
}
return result;
}
util::json::Object getIntersection(const guidance::StepManeuver maneuver)
{
util::json::Object result;
// bearings are oriented in the direction of driving. For the in-bearing, we actually need to
// find the bearing from the view of the intersection. This means we have to rotate the bearing
// by 180 degree.
const auto rotated_bearing_before = (maneuver.bearing_before >= 180.0)
? (maneuver.bearing_before - 180.0)
: (maneuver.bearing_before + 180.0);
result.values["from_bearing"] =
getMatchingDiscreteBearing(false, rotated_bearing_before, maneuver.entry_class,
maneuver.bearing_class.getAvailableBearings());
result.values["to_bearing"] =
getMatchingDiscreteBearing(true, maneuver.bearing_after, maneuver.entry_class,
maneuver.bearing_class.getAvailableBearings());
result.values["connections"] = getConnections(maneuver.entry_class, maneuver.bearing_class);
return result;
}
// FIXME this actually needs to be configurable from the profiles
std::string modeToString(const extractor::TravelMode mode)
{
@ -193,10 +207,7 @@ util::json::Object makeStepManeuver(const guidance::StepManeuver &maneuver)
{
util::json::Object step_maneuver;
if (maneuver.waypoint_type == guidance::WaypointType::None)
{
step_maneuver.values["type"] = detail::instructionTypeToString(maneuver.instruction.type);
step_maneuver.values["intersection"] = detail::getIntersection(maneuver);
}
else
step_maneuver.values["type"] = detail::waypointTypeToString(maneuver.waypoint_type);
@ -204,18 +215,9 @@ util::json::Object makeStepManeuver(const guidance::StepManeuver &maneuver)
step_maneuver.values["modifier"] =
detail::instructionModifierToString(maneuver.instruction.direction_modifier);
step_maneuver.values["location"] = detail::coordinateToLonLat(maneuver.location);
step_maneuver.values["bearing_before"] = std::round(maneuver.bearing_before);
step_maneuver.values["bearing_after"] = std::round(maneuver.bearing_after);
if (maneuver.exit != 0)
step_maneuver.values["exit"] = maneuver.exit;
// TODO currently we need this to comply with the api.
// We should move this to an additional entry, the moment we
// actually compute the correct locations of the intersections
if (!maneuver.intersections.empty() && maneuver.exit == 0)
step_maneuver.values["exit"] = maneuver.intersections.size();
return step_maneuver;
}
@ -231,6 +233,7 @@ util::json::Object makeRouteStep(guidance::RouteStep step, util::json::Value geo
route_step.values["mode"] = detail::modeToString(std::move(step.mode));
route_step.values["maneuver"] = makeStepManeuver(std::move(step.maneuver));
route_step.values["geometry"] = std::move(geometry);
route_step.values["intersections"] = detail::getIntersection(step);
return route_step;
}

View File

@ -2,6 +2,7 @@
#include <boost/assert.hpp>
#include <cmath>
#include <cstddef>
namespace osrm
@ -12,48 +13,11 @@ namespace guidance
{
namespace detail
{
StepManeuver stepManeuverFromGeometry(extractor::guidance::TurnInstruction instruction,
const WaypointType waypoint_type,
const LegGeometry &leg_geometry)
namespace
{
BOOST_ASSERT(waypoint_type != WaypointType::None);
BOOST_ASSERT(leg_geometry.locations.size() >= 2);
double pre_turn_bearing = 0, post_turn_bearing = 0;
Coordinate turn_coordinate;
if (waypoint_type == WaypointType::Depart)
{
turn_coordinate = leg_geometry.locations.front();
const auto post_turn_coordinate = *(leg_geometry.locations.begin() + 1);
post_turn_bearing =
util::coordinate_calculation::bearing(turn_coordinate, post_turn_coordinate);
}
else
{
BOOST_ASSERT(waypoint_type == WaypointType::Arrive);
turn_coordinate = leg_geometry.locations.back();
const auto pre_turn_coordinate = *(leg_geometry.locations.end() - 2);
pre_turn_bearing =
util::coordinate_calculation::bearing(pre_turn_coordinate, turn_coordinate);
}
return StepManeuver{std::move(turn_coordinate),
pre_turn_bearing,
post_turn_bearing,
std::move(instruction),
waypoint_type,
INVALID_EXIT_NR,
// BearingClass,EntryClass, and Intermediate intersections are unknown yet
{},
{},
{}};
}
StepManeuver stepManeuverFromGeometry(extractor::guidance::TurnInstruction instruction,
const LegGeometry &leg_geometry,
const std::size_t segment_index,
util::guidance::EntryClass entry_class,
util::guidance::BearingClass bearing_class)
void fillInIntermediate(Intersection &intersection,
const LegGeometry &leg_geometry,
const std::size_t segment_index)
{
auto turn_index = leg_geometry.BackIndex(segment_index);
BOOST_ASSERT(turn_index > 0);
@ -64,15 +28,60 @@ StepManeuver stepManeuverFromGeometry(extractor::guidance::TurnInstruction instr
const auto turn_coordinate = leg_geometry.locations[turn_index];
const auto post_turn_coordinate = leg_geometry.locations[turn_index + 1];
const double pre_turn_bearing =
intersection.bearing_before =
util::coordinate_calculation::bearing(pre_turn_coordinate, turn_coordinate);
const double post_turn_bearing =
intersection.bearing_after =
util::coordinate_calculation::bearing(turn_coordinate, post_turn_coordinate);
// add a step without intermediate intersections
return StepManeuver{std::move(turn_coordinate), pre_turn_bearing, post_turn_bearing,
std::move(instruction), WaypointType::None, INVALID_EXIT_NR,
std::move(entry_class), std::move(bearing_class), {}};
intersection.location = turn_coordinate;
}
void fillInDepart(Intersection &intersection, const LegGeometry &leg_geometry)
{
BOOST_ASSERT(leg_geometry.locations.size() >= 2);
const auto turn_coordinate = leg_geometry.locations.front();
const auto post_turn_coordinate = *(leg_geometry.locations.begin() + 1);
intersection.location = turn_coordinate;
intersection.bearing_before = 0;
intersection.bearing_after =
util::coordinate_calculation::bearing(turn_coordinate, post_turn_coordinate);
std::cout << "Depart: " << intersection.bearing_before << " " << intersection.bearing_after << std::endl;
}
void fillInArrive(Intersection &intersection, const LegGeometry &leg_geometry)
{
BOOST_ASSERT(leg_geometry.locations.size() >= 2);
const auto turn_coordinate = leg_geometry.locations.back();
const auto pre_turn_coordinate = *(leg_geometry.locations.end() - 2);
intersection.location = turn_coordinate;
intersection.bearing_before =
util::coordinate_calculation::bearing(pre_turn_coordinate, turn_coordinate);
intersection.bearing_after = 0;
std::cout << "Arrive: " << intersection.bearing_before << " " << intersection.bearing_after << std::endl;
}
} // namespace
Intersection intersectionFromGeometry(const WaypointType waypoint_type,
const double segment_duration,
const LegGeometry &leg_geometry,
const std::size_t segment_index)
{
Intersection intersection;
intersection.duration = segment_duration;
intersection.distance = leg_geometry.segment_distances[segment_index];
switch (waypoint_type)
{
case WaypointType::None:
fillInIntermediate(intersection, leg_geometry, segment_index);
break;
case WaypointType::Depart:
fillInDepart(intersection, leg_geometry);
break;
case WaypointType::Arrive:
fillInArrive(intersection, leg_geometry);
break;
}
return intersection;
}
} // ns detail
} // ns engine

View File

@ -50,14 +50,16 @@ void print(const std::vector<RouteStep> &steps)
<< " Duration: " << step.duration << " Distance: " << step.distance
<< " Geometry: " << step.geometry_begin << " " << step.geometry_end
<< " exit: " << step.maneuver.exit
<< " Intersections: " << step.maneuver.intersections.size() << " [";
<< " Intersections: " << step.intersections.size() << " [";
for (const auto &intersection : step.maneuver.intersections)
std::cout << "(" << intersection.duration << " " << intersection.distance << ")";
for (const auto &intersection : step.intersections)
{
std::cout << "(" << intersection.duration << " " << intersection.distance << " "
<< " Bearings: " << intersection.bearing_before << " "
<< intersection.bearing_after << ")";
}
std::cout << "] name[" << step.name_id << "]: " << step.name
<< " Bearings: " << step.maneuver.bearing_before << " "
<< step.maneuver.bearing_after << std::endl;
std::cout << "] name[" << step.name_id << "]: " << step.name << std::endl;
}
}
@ -67,8 +69,21 @@ RouteStep forwardInto(RouteStep destination, const RouteStep &source)
// Overwrites turn instruction and increases exit NR
destination.duration += source.duration;
destination.distance += source.distance;
if (destination.geometry_begin < source.geometry_begin)
{
destination.intersections.insert(destination.intersections.end(),
source.intersections.begin(), source.intersections.end());
}
else
{
destination.intersections.insert(destination.intersections.begin(),
source.intersections.begin(), source.intersections.end());
}
destination.geometry_begin = std::min(destination.geometry_begin, source.geometry_begin);
destination.geometry_end = std::max(destination.geometry_end, source.geometry_end);
return destination;
}
@ -185,7 +200,8 @@ void closeOffRoundabout(const bool on_roundabout,
// Normal exit from the roundabout, or exit from a previously fixed roundabout. Propagate the
// index back to the entering location and prepare the current silent set of instructions for
// removal.
const auto exit_bearing = steps[step_index].maneuver.bearing_after;
std::vector<std::size_t> intermediate_steps;
const auto exit_bearing = steps[step_index].intersections.back().bearing_after;
if (step_index > 1)
{
// The very first route-step is head, so we cannot iterate past that one
@ -198,6 +214,7 @@ void closeOffRoundabout(const bool on_roundabout,
{
propagation_step.maneuver.exit = step.maneuver.exit;
propagation_step.geometry_end = step.geometry_end;
// remember rotary name
if (propagation_step.maneuver.instruction.type == TurnType::EnterRotary ||
propagation_step.maneuver.instruction.type == TurnType::EnterRotaryAtExit)
@ -237,7 +254,7 @@ void closeOffRoundabout(const bool on_roundabout,
const auto angle = 540 - rotated_exit;
return angle > 360 ? angle - 360 : angle;
}(propagation_step.maneuver.bearing_before, exit_bearing);
}(propagation_step.intersections.back().bearing_before, exit_bearing);
propagation_step.maneuver.instruction.direction_modifier =
::osrm::util::guidance::getTurnDirection(angle);
@ -274,9 +291,8 @@ RouteStep elongate(RouteStep step, const RouteStep &by_step)
// if we elongate in the back, we only need to copy the intersections to the beginning.
// the bearings remain the same, as the location of the turn doesn't change
step.maneuver.intersections.insert(step.maneuver.intersections.end(),
by_step.maneuver.intersections.begin(),
by_step.maneuver.intersections.end());
step.intersections.insert(step.intersections.end(), by_step.intersections.begin(),
by_step.intersections.end());
}
else
{
@ -286,14 +302,10 @@ RouteStep elongate(RouteStep step, const RouteStep &by_step)
step.geometry_begin = by_step.geometry_begin;
// elongating in the front changes the location of the maneuver
step.maneuver.location = by_step.maneuver.location;
step.maneuver.bearing_before = by_step.maneuver.bearing_before;
step.maneuver.bearing_after = by_step.maneuver.bearing_after;
step.maneuver.instruction = by_step.maneuver.instruction;
step.maneuver = by_step.maneuver;
step.maneuver.intersections.insert(step.maneuver.intersections.begin(),
by_step.maneuver.intersections.begin(),
by_step.maneuver.intersections.end());
step.intersections.insert(step.intersections.begin(), by_step.intersections.begin(),
by_step.intersections.end());
}
return step;
}
@ -359,8 +371,8 @@ void collapseTurnAt(std::vector<RouteStep> &steps,
}
}
// Potential U-Turn
else if (bearingsAreReversed(one_back_step.maneuver.bearing_before,
current_step.maneuver.bearing_after))
else if (bearingsAreReversed(one_back_step.intersections.front().bearing_before,
current_step.intersections.front().bearing_after))
{
BOOST_ASSERT(two_back_index < steps.size());
@ -438,18 +450,6 @@ std::vector<RouteStep> postProcess(std::vector<RouteStep> steps)
bool on_roundabout = false;
bool has_entered_roundabout = false;
// adds an intersection to the initial route step
// It includes the length of the last step, until the intersection
// Also updates the length of the respective segment
auto addIntersection = [](RouteStep into, const RouteStep &last_step,
const RouteStep &intersection) {
into.maneuver.intersections.push_back(
{last_step.duration, last_step.distance, intersection.maneuver.location,
intersection.maneuver.entry_class, intersection.maneuver.bearing_class});
return forwardInto(std::move(into), intersection);
};
// count the exits forward. if enter/exit roundabout happen both, no further treatment is
// required. We might end up with only one of them (e.g. starting within a roundabout)
// or having a via-point in the roundabout.
@ -492,8 +492,9 @@ std::vector<RouteStep> postProcess(std::vector<RouteStep> steps)
{
// count intersections. We cannot use exit, since intersections can follow directly
// after a roundabout
steps[last_valid_instruction] = addIntersection(
std::move(steps[last_valid_instruction]), steps[step_index - 1], step);
steps[last_valid_instruction].intersections.insert(
steps[last_valid_instruction].intersections.end(), step.intersections.begin(),
step.intersections.end());
step.maneuver.instruction = TurnInstruction::NO_TURN();
}
else if (!isSilent(instruction))
@ -664,8 +665,7 @@ void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
// update initial turn direction/bearings. Due to the duplicated first coordinate,
// the initial bearing is invalid
designated_depart.maneuver = detail::stepManeuverFromGeometry(
TurnInstruction::NO_TURN(), WaypointType::Depart, geometry);
designated_depart.maneuver = {TurnInstruction::NO_TURN(), WaypointType::Depart, 0};
// finally remove the initial (now duplicated move)
steps.erase(steps.begin());
@ -678,8 +678,8 @@ void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
geometry.segment_offsets.begin(),
[](const std::size_t val) { return val - 1; });
steps.front().maneuver = detail::stepManeuverFromGeometry(
TurnInstruction::NO_TURN(), WaypointType::Depart, geometry);
steps.front().maneuver = {TurnInstruction::NO_TURN(), WaypointType::Depart, 0};
std::cout << "Removed coordinate: " << std::endl;
}
// and update the leg geometry indices for the removed entry
@ -705,8 +705,8 @@ void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
BOOST_ASSERT(geometry.segment_distances.back() < 1);
geometry.segment_distances.pop_back();
next_to_last_step.maneuver = detail::stepManeuverFromGeometry(
TurnInstruction::NO_TURN(), WaypointType::Arrive, geometry);
next_to_last_step.maneuver = {TurnInstruction::NO_TURN(), WaypointType::Arrive, 0};
next_to_last_step.intersections.front().bearing_after = 0;
steps.pop_back();
// Because we eliminated a really short segment, it was probably
@ -736,8 +736,7 @@ void trimShortSegments(std::vector<RouteStep> &steps, LegGeometry &geometry)
next_to_last_step.geometry_end--;
steps.back().geometry_begin--;
steps.back().geometry_end--;
steps.back().maneuver = detail::stepManeuverFromGeometry(TurnInstruction::NO_TURN(),
WaypointType::Arrive, geometry);
steps.back().maneuver = {TurnInstruction::NO_TURN(), WaypointType::Arrive, 0};
}
}
@ -762,6 +761,11 @@ std::vector<RouteStep> assignRelativeLocations(std::vector<RouteStep> steps,
: extractor::guidance::DirectionModifier::UTurn;
steps.front().maneuver.instruction.direction_modifier = initial_modifier;
steps.front().intersections.front().bearing_before = 0;
steps.front().intersections.front().bearing_after =
util::coordinate_calculation::bearing(leg_geometry.locations[0], leg_geometry.locations[1]);
steps.front().intersections.front() = util::guidance::setIntersectionClasses(
std::move(steps.front().intersections.front()), source_node);
const auto distance_from_end = util::coordinate_calculation::haversineDistance(
target_node.input_location, leg_geometry.locations.back());
@ -775,6 +779,14 @@ std::vector<RouteStep> assignRelativeLocations(std::vector<RouteStep> steps,
: extractor::guidance::DirectionModifier::UTurn;
steps.back().maneuver.instruction.direction_modifier = final_modifier;
BOOST_ASSERT(steps.back().intersections.size() == 1);
steps.back().intersections.front().bearing_before = util::coordinate_calculation::bearing(
leg_geometry.locations[leg_geometry.locations.size() - 2],
leg_geometry.locations[leg_geometry.locations.size() - 1]);
steps.back().intersections.front().bearing_after = 0;
steps.back().intersections.front() = util::guidance::setIntersectionClasses(
std::move(steps.back().intersections.front()), target_node);
return steps;
}

View File

@ -14,6 +14,7 @@
#include "util/lua_util.hpp"
#include "util/make_unique.hpp"
#include "util/name_table.hpp"
#include "util/range_table.hpp"
#include "util/simple_logger.hpp"
#include "util/timing_util.hpp"
@ -624,10 +625,24 @@ void Extractor::WriteIntersectionClassificationData(
util::writeFingerprint(file_out_stream);
util::serializeVector(file_out_stream, node_based_intersection_classes);
static_assert(std::is_trivially_copyable<util::guidance::BearingClass>::value,
"BearingClass Serialization requires trivial copyable bearing classes");
// create range table for vectors:
std::vector<unsigned> bearing_counts;
bearing_counts.reserve(bearing_classes.size());
std::uint64_t total_bearings = 0;
for (const auto &bearing_class : bearing_classes){
bearing_counts.push_back(static_cast<unsigned>(bearing_class.getAvailableBearings().size()));
total_bearings += bearing_class.getAvailableBearings().size();
}
util::serializeVector(file_out_stream, bearing_classes);
util::RangeTable<> bearing_class_range_table(bearing_counts);
file_out_stream << bearing_class_range_table;
file_out_stream << total_bearings;
for( const auto &bearing_class : bearing_classes)
{
const auto &bearings = bearing_class.getAvailableBearings();
file_out_stream.write( reinterpret_cast<const char*>(&bearings[0]), sizeof(bearings[0]) * bearings.size() );
}
static_assert(std::is_trivially_copyable<util::guidance::EntryClass>::value,
"EntryClass Serialization requires trivial copyable entry classes");

View File

@ -15,234 +15,17 @@ namespace guidance
struct TurnPossibility
{
TurnPossibility(bool entry_allowed, double bearing, std::uint8_t discrete_id)
: entry_allowed(entry_allowed), bearing(std::move(bearing)),
discrete_id(std::move(discrete_id))
TurnPossibility(bool entry_allowed, double bearing)
: entry_allowed(entry_allowed), bearing(std::move(bearing))
{
}
TurnPossibility() : entry_allowed(false), bearing(0), discrete_id(0) {}
TurnPossibility() : entry_allowed(false), bearing(0) {}
bool entry_allowed;
double bearing;
std::uint8_t discrete_id;
};
namespace
{
bool hasConflicts(const std::vector<TurnPossibility> &turns)
{
if (turns.size() <= 1)
return false;
for (std::size_t pos = 0; pos < turns.size(); ++pos)
{
if (turns[pos].discrete_id == turns[(pos + 1) % turns.size()].discrete_id)
return true;
}
return false;
}
// Fix cases with nearly identical turns. If the difference between turns is just to small to be
// visible, we will not report the angle twice
std::vector<TurnPossibility> fixIdenticalTurns(std::vector<TurnPossibility> intersection)
{
BOOST_ASSERT(intersection.size() > 1);
for (auto itr = intersection.begin(); itr != intersection.end(); ++itr)
{
const auto next = [&]() {
auto next_itr = std::next(itr);
if (next_itr != intersection.end())
return next_itr;
return intersection.begin();
}();
// conflict here?
if (itr->discrete_id == next->discrete_id)
{
if (angularDeviation(itr->bearing, next->bearing) < 0.5) // very small angular difference
{
if (!itr->entry_allowed || next->entry_allowed)
{
itr = intersection.erase(itr);
}
else
{
intersection.erase(next);
}
if (itr == intersection.end())
break;
}
}
}
return intersection;
}
std::vector<TurnPossibility> fixAroundBorder(std::vector<TurnPossibility> intersection)
{
BOOST_ASSERT(intersection.size() > 1);
// We can solve a conflict by reporting different bearing availabilities, as long as
// both conflicting turns are on different sides of the bearing separator.
//
// Consider this example:
// ID(0)
// . b
// a .... (ID 1)
// . c
// ID(2)
//
// Both b and c map to the ID 1. Due to the split, we can set ID 0 and 2. In
// deducing the best available bearing for a turn, we can now find 0 to be closest
// to b and 2 to be closest to c. This only works when there are no other bearings
// close to the conflicting assignment, though.
for (std::size_t current_index = 0; current_index < intersection.size(); ++current_index)
{
const auto next_index = (current_index + 1) % intersection.size();
if (intersection[current_index].discrete_id == intersection[next_index].discrete_id)
{
const double border = util::guidance::BearingClass::discreteIDToAngle(
util::guidance::BearingClass::angleToDiscreteID(
intersection[current_index].bearing));
// if both are on different sides of the separation, we can check for possible
// resolution
if (intersection[current_index].bearing < border &&
intersection[next_index].bearing > border)
{
const auto shift_angle = [](const double bearing, const double delta) {
auto shifted_angle = bearing + delta;
if (shifted_angle < 0)
return shifted_angle + 360.;
if (shifted_angle > 360)
return shifted_angle - 360.;
return shifted_angle;
};
// conflict resolution is possible, if both bearings are available
const auto left_id = util::guidance::BearingClass::angleToDiscreteID(
shift_angle(intersection[current_index].bearing,
-util::guidance::BearingClass::discrete_angle_step_size));
const auto right_id = util::guidance::BearingClass::angleToDiscreteID(
shift_angle(intersection[next_index].bearing,
util::guidance::BearingClass::discrete_angle_step_size));
const bool resolvable = [&]() {
if (intersection.size() == 2)
return true;
// cannot shift to the left without generating another conflict
if (intersection[current_index + intersection.size() - 1].discrete_id ==
left_id)
return false;
// cannot shift to the right without generating another conflict
if (intersection[(next_index + 1) % intersection.size()].discrete_id ==
right_id)
return false;
return true;
}();
if (resolvable)
{
intersection[current_index].discrete_id = left_id;
intersection[next_index].discrete_id = right_id;
}
}
}
}
return intersection;
}
// return an empty set of turns, if the conflict is not possible to be handled
std::vector<TurnPossibility> handleConflicts(std::vector<TurnPossibility> intersection)
{
intersection = fixIdenticalTurns(std::move(intersection));
if (!hasConflicts(intersection))
return intersection;
intersection = fixAroundBorder(intersection);
// if the intersection still has conflicts, we cannot handle it correctly
if (hasConflicts(intersection))
intersection.clear();
return intersection;
#if 0
const auto border = util::guidance::BearingClass::discreteIDToAngle(
util::guidance::BearingClass::angleToDiscreteID(intersection[0].bearing));
// at least two turns
auto previous_id = util::guidance::BearingClass::angleToDiscreteID(turns.back().bearing);
for (std::size_t i = 0; i < turns.size(); ++i)
{
if (turns[i].entry_allowed)
entry_class.activate(turn_index);
const auto discrete_id =
util::guidance::BearingClass::angleToDiscreteID(turns[i].bearing);
const auto prev_index = (i + turns.size() - 1) % turns.size();
if (discrete_id != previous_id)
{
// if we go back in IDs, conflict resolution has to deal with multiple conflicts
if (previous_id > discrete_id &&
previous_id != (util::guidance::BearingClass::angleToDiscreteID(
turns[prev_index].bearing)))
{
std::cout << "Previous ID conflict " << (int)previous_id << " "
<< (int)discrete_id << std::endl;
break;
}
++turn_index;
bearing_class.addDiscreteID(discrete_id);
previous_id = discrete_id;
}
else
{
// the previous turn was handled into a conflict. Such a conflict cannot be
// correctly expressed.
// We have to report a unclassified setting.
if (util::guidance::BearingClass::angleToDiscreteID(turns[prev_index].bearing) !=
previous_id)
break;
if (turns[i].bearing >= border && turns[prev_index].bearing < border)
{
const auto shift_angle = [](const double bearing, const double delta) {
auto shifted_angle = bearing + delta;
if (shifted_angle < 0)
return shifted_angle + 360.;
if (shifted_angle > 360)
return shifted_angle - 360.;
return shifted_angle;
};
// conflict resolution is possible, if both bearings are available
const auto left_id = util::guidance::BearingClass::angleToDiscreteID(
shift_angle(turns[prev_index].bearing,
-util::guidance::BearingClass::discrete_angle_step_size));
const auto right_id = util::guidance::BearingClass::angleToDiscreteID(
shift_angle(turns[i].bearing,
util::guidance::BearingClass::discrete_angle_step_size));
if (!bearing_class.hasDiscrete(left_id) && !bearing_class.hasDiscrete(right_id))
{
bearing_class.resetDiscreteID(discrete_id);
bearing_class.addDiscreteID(left_id);
bearing_class.addDiscreteID(right_id);
++turn_index;
previous_id = right_id;
}
}
}
}
#endif
return intersection;
};
} // namespace
std::pair<util::guidance::EntryClass, util::guidance::BearingClass>
classifyIntersection(NodeID nid,
const Intersection &intersection,
@ -266,63 +49,63 @@ classifyIntersection(NodeID nid,
const double bearing =
util::coordinate_calculation::bearing(node_coordinate, edge_coordinate);
turns.push_back({road.entry_allowed, bearing,
util::guidance::BearingClass::angleToDiscreteID(bearing)});
turns.push_back({road.entry_allowed, bearing});
}
std::sort(turns.begin(), turns.end(),
[](const TurnPossibility left, const TurnPossibility right) {
return left.bearing < right.bearing;
return util::guidance::BearingClass::getDiscreteBearing(left.bearing) <
util::guidance::BearingClass::getDiscreteBearing(right.bearing) ||
(util::guidance::BearingClass::getDiscreteBearing(left.bearing) ==
util::guidance::BearingClass::getDiscreteBearing(right.bearing) &&
left.bearing < right.bearing);
});
// check for conflicts
const bool has_conflicts = hasConflicts(turns);
if (has_conflicts)
{ // try to handle conflicts, if possible
turns = handleConflicts(std::move(turns));
}
util::guidance::EntryClass entry_class;
util::guidance::BearingClass bearing_class;
const bool canBeDiscretized = [&]() {
if (turns.size() <= 1)
return true;
DiscreteBearing last_discrete_bearing =
util::guidance::BearingClass::getDiscreteBearing(std::round(turns.back().bearing));
for (const auto turn : turns)
{
const DiscreteBearing discrete_bearing =
util::guidance::BearingClass::getDiscreteBearing(std::round(turn.bearing));
if (discrete_bearing == last_discrete_bearing)
return false;
last_discrete_bearing = discrete_bearing;
}
return true;
}();
// finally transfer data to the entry/bearing classes
std::size_t number = 0;
for (const auto turn : turns)
if (canBeDiscretized)
{
if (turn.entry_allowed)
entry_class.activate(number);
bearing_class.addDiscreteID(turn.discrete_id);
++number;
}
static std::size_t mapping_failure_count = 0;
if (turns.empty())
{
++mapping_failure_count;
util::SimpleLogger().Write(logDEBUG)
<< "Failed to provide full turn list for intersection ( " << mapping_failure_count
<< " ) for " << intersection.size() << " roads";
std::cout << std::endl;
for (const auto &road : intersection)
for (const auto turn : turns)
{
const auto eid = road.turn.eid;
const auto edge_coordinate =
getRepresentativeCoordinate(nid, node_based_graph.GetTarget(eid), eid, false,
compressed_geometries, query_nodes);
const double bearing =
util::coordinate_calculation::bearing(node_coordinate, edge_coordinate);
std::cout << " " << bearing << "("
<< (int)util::guidance::BearingClass::angleToDiscreteID(bearing) << ")";
if (turn.entry_allowed)
entry_class.activate(number);
auto discrete_bearing_class =
util::guidance::BearingClass::getDiscreteBearing(std::round(turn.bearing));
bearing_class.add(std::round(discrete_bearing_class *
util::guidance::BearingClass::discrete_step_size));
++number;
}
}
else
{
for (const auto turn : turns)
{
if (turn.entry_allowed)
entry_class.activate(number);
bearing_class.add(std::round(turn.bearing));
++number;
}
std::cout << std::endl;
std::cout << "Location of intersection: " << std::setprecision(12) << " "
<< util::toFloating(query_nodes[nid].lat) << " "
<< util::toFloating(query_nodes[nid].lon) << std::endl;
return {};
}
return std::make_pair(entry_class, bearing_class);
}

View File

@ -31,6 +31,7 @@
#include <cstdint>
#include <fstream>
#include <iostream>
#include <iterator>
#include <new>
#include <string>
@ -574,36 +575,75 @@ int Storage::Run()
{
boost::filesystem::ifstream intersection_stream(config.intersection_class_path,
std::ios::binary);
if (!static_cast<bool>(intersection_stream))
throw util::exception("Could not open " + config.intersection_class_path.string() +
" for reading.");
if (!util::readAndCheckFingerprint(intersection_stream))
{
util::SimpleLogger().Write(logWARNING)
<< "Fingerprint does not match or reading failed";
}
throw util::exception("Fingerprint of " + config.intersection_class_path.string() +
" does not match or could not read from file");
std::vector<BearingClassID> bearing_class_id_table;
util::deserializeVector(intersection_stream, bearing_class_id_table);
if (!util::deserializeVector(intersection_stream, bearing_class_id_table))
throw util::exception("Failed to read from " + config.names_data_path.string());
shared_layout_ptr->SetBlockSize<BearingClassID>(SharedDataLayout::BEARING_CLASSID,
bearing_class_id_table.size());
auto bearing_id_ptr = shared_layout_ptr->GetBlockPtr<BearingClassID, true>(
shared_memory_ptr, SharedDataLayout::BEARING_CLASSID);
std::copy(bearing_class_id_table.begin(), bearing_class_id_table.end(), bearing_id_ptr);
auto bearing_class_ptr =
shared_layout_ptr->GetBlockPtr<util::guidance::BearingClass, true>(
shared_memory_ptr, SharedDataLayout::BEARING_CLASS);
std::vector<util::guidance::BearingClass> bearing_class_table;
util::deserializeVector(intersection_stream, bearing_class_table);
shared_layout_ptr->SetBlockSize<util::guidance::BearingClass>(
SharedDataLayout::BEARING_CLASS, bearing_class_table.size());
unsigned bearing_blocks = 0;
intersection_stream.read((char *)&bearing_blocks, sizeof(unsigned));
unsigned sum_lengths = 0;
intersection_stream.read((char *)&sum_lengths, sizeof(unsigned));
shared_layout_ptr->SetBlockSize<unsigned>(SharedDataLayout::BEARING_OFFSETS,
bearing_blocks);
shared_layout_ptr->SetBlockSize<typename util::RangeTable<16, true>::BlockT>(
SharedDataLayout::BEARING_BLOCKS, bearing_blocks);
unsigned *bearing_offsets_ptr = shared_layout_ptr->GetBlockPtr<unsigned, true>(
shared_memory_ptr, SharedDataLayout::BEARING_OFFSETS);
if (shared_layout_ptr->GetBlockSize(SharedDataLayout::BEARING_OFFSETS) > 0)
{
intersection_stream.read(
reinterpret_cast<char *>(bearing_offsets_ptr),
shared_layout_ptr->GetBlockSize(SharedDataLayout::BEARING_OFFSETS));
}
unsigned *bearing_blocks_ptr = shared_layout_ptr->GetBlockPtr<unsigned, true>(
shared_memory_ptr, SharedDataLayout::BEARING_BLOCKS);
if (shared_layout_ptr->GetBlockSize(SharedDataLayout::BEARING_BLOCKS) > 0)
{
intersection_stream.read(
reinterpret_cast<char *>(bearing_blocks_ptr),
shared_layout_ptr->GetBlockSize(SharedDataLayout::BEARING_BLOCKS));
}
std::uint64_t num_bearings;
intersection_stream >> num_bearings;
std::vector<DiscreteBearing> bearing_class_table(num_bearings);
intersection_stream.read(reinterpret_cast<char *>(&bearing_class_table[0]),
sizeof(bearing_class_table[0]) * num_bearings);
shared_layout_ptr->SetBlockSize<DiscreteBearing>(SharedDataLayout::BEARING_VALUES,
num_bearings);
auto bearing_class_ptr = shared_layout_ptr->GetBlockPtr<DiscreteBearing, true>(
shared_memory_ptr, SharedDataLayout::BEARING_VALUES);
std::copy(bearing_class_table.begin(), bearing_class_table.end(), bearing_class_ptr);
auto entry_class_ptr =
shared_layout_ptr->GetBlockPtr<util::guidance::EntryClass, true>(
shared_memory_ptr, SharedDataLayout::ENTRY_CLASS);
if (!static_cast<bool>(intersection_stream))
throw util::exception("Failed to read from " + config.names_data_path.string());
std::vector<util::guidance::EntryClass> entry_class_table;
util::deserializeVector(intersection_stream, entry_class_table);
shared_layout_ptr->SetBlockSize<util::guidance::EntryClass>(
SharedDataLayout::ENTRY_CLASS, entry_class_table.size());
if(!util::deserializeVector(intersection_stream, entry_class_table))
throw util::exception("Failed to read from " + config.names_data_path.string());
shared_layout_ptr->SetBlockSize<util::guidance::EntryClass>(SharedDataLayout::ENTRY_CLASS,
entry_class_table.size());
auto entry_class_ptr = shared_layout_ptr->GetBlockPtr<util::guidance::EntryClass, true>(
shared_memory_ptr, SharedDataLayout::ENTRY_CLASS);
std::copy(entry_class_table.begin(), entry_class_table.end(), entry_class_ptr);
}

View File

@ -1,6 +1,8 @@
#include "extractor/guidance/discrete_angle.hpp"
#include "util/guidance/bearing_class.hpp"
#include "util/guidance/toolkit.hpp"
#include <algorithm>
#include <boost/assert.hpp>
namespace osrm
@ -10,83 +12,69 @@ namespace util
namespace guidance
{
static_assert(
360 / BearingClass::discrete_angle_step_size <= 8 * sizeof(BearingClass::FlagBaseType),
"The number of expressable bearings does not fit into the datatype used for storage.");
std::uint8_t BearingClass::angleToDiscreteID(double angle)
{
BOOST_ASSERT(angle >= 0. && angle <= 360.);
// shift angle by half the step size to have the class be located around the center
angle = (angle + 0.5 * BearingClass::discrete_angle_step_size);
if (angle > 360)
angle -= 360;
return std::uint8_t(angle / BearingClass::discrete_angle_step_size);
}
double BearingClass::discreteIDToAngle(std::uint8_t id)
{
BOOST_ASSERT(0 <= id && id <= 360. / discrete_angle_step_size);
return discrete_angle_step_size * id;
}
void BearingClass::resetContinuous(const double bearing) {
const auto id = angleToDiscreteID(bearing);
resetDiscreteID(id);
}
void BearingClass::resetDiscreteID(const std::uint8_t id) {
available_bearings_mask &= ~(1<<id);
}
bool BearingClass::hasContinuous(const double bearing) const
{
const auto id = angleToDiscreteID(bearing);
return hasDiscrete(id);
}
bool BearingClass::hasDiscrete(const std::uint8_t id) const
{
return 0 != (available_bearings_mask & (1<<id));
}
BearingClass::BearingClass() : available_bearings_mask(0) {}
bool BearingClass::operator==(const BearingClass &other) const
{
return other.available_bearings_mask == available_bearings_mask;
BOOST_ASSERT(std::is_sorted(available_bearings.begin(), available_bearings.end()));
BOOST_ASSERT(std::is_sorted(other.available_bearings.begin(), other.available_bearings.end()));
if (other.available_bearings.size() != available_bearings.size())
return false;
for (std::size_t i = 0; i < available_bearings.size(); ++i)
if (available_bearings[i] != other.available_bearings[i])
return false;
return true;
}
bool BearingClass::operator<(const BearingClass &other) const
{
return available_bearings_mask < other.available_bearings_mask;
}
BOOST_ASSERT(std::is_sorted(available_bearings.begin(), available_bearings.end()));
BOOST_ASSERT(std::is_sorted(other.available_bearings.begin(), other.available_bearings.end()));
if (available_bearings.size() < other.available_bearings.size())
return true;
if (available_bearings.size() > other.available_bearings.size())
return false;
bool BearingClass::addContinuous(const double angle)
{
return addDiscreteID(angleToDiscreteID(angle));
}
bool BearingClass::addDiscreteID(const std::uint8_t discrete_id)
{
const auto mask = (1 << discrete_id);
const auto is_new = (0 == (available_bearings_mask & mask));
available_bearings_mask |= mask;
return is_new;
}
std::vector<double> BearingClass::getAvailableBearings() const
{
std::vector<double> result;
// account for some basic inaccuracries of double
for (std::size_t discrete_id = 0; discrete_id * discrete_angle_step_size <= 361; ++discrete_id)
for (std::size_t i = 0; i < available_bearings.size(); ++i)
{
// ervery set bit indicates a bearing
if (available_bearings_mask & (1 << discrete_id))
result.push_back(discrete_id * discrete_angle_step_size);
if (available_bearings[i] < other.available_bearings[i])
return true;
if (available_bearings[i] > other.available_bearings[i])
return false;
}
return result;
return false;
}
void BearingClass::add(const DiscreteBearing bearing)
{
available_bearings.push_back(bearing);
}
const std::vector<DiscreteBearing> &BearingClass::getAvailableBearings() const
{
return available_bearings;
}
DiscreteBearing BearingClass::getDiscreteBearing(const double bearing)
{
BOOST_ASSERT(0. <= bearing && bearing <= 360.);
auto shifted_bearing = (bearing + 0.5 * discrete_step_size);
if (shifted_bearing > 360.)
shifted_bearing -= 360;
return static_cast<DiscreteBearing>(shifted_bearing / discrete_step_size);
}
std::size_t BearingClass::findMatchingBearing(const double bearing) const
{
// the small size of the intersections allows a linear compare
auto discrete_bearing = static_cast<DiscreteBearing>(bearing);
auto max_element =
std::max_element(available_bearings.begin(), available_bearings.end(),
[&](const DiscreteBearing first, const DiscreteBearing second) {
return angularDeviation(first, discrete_bearing) >
angularDeviation(second, discrete_bearing);
});
return std::distance(available_bearings.begin(), max_element);
}
} // namespace guidance