simplify passing annotation data through OSRM pipeline using the node-based datastore
- separates node-based graph creation and compression from edge-based graph creation - moves usage of edge-based node data-container to pre-processing as well, unifying access to node-based data - single struct instead of separate vectors for annotation data in engine (single place of modification)
This commit is contained in:
parent
9b044aaa42
commit
2ddd98ee6d
@ -11,6 +11,7 @@
|
||||
- Exposes `use_threads_number=Number` parameter of `EngineConfig` to limit a number of threads in a TBB internal pool
|
||||
- Internals
|
||||
- MLD uses a unidirectional Dijkstra for 1-to-N and N-to-1 matrices
|
||||
- BREAKING: Internal file formats have changed, requiring a new pre-processing run
|
||||
- Guidance
|
||||
- Fixed some cases of sliproads pre-processing (https://github.com/Project-OSRM/osrm-backend/issues/4348)
|
||||
- don't suppress name announcements via sliproad handler
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "customizer/edge_based_graph.hpp"
|
||||
|
||||
#include "extractor/datasources.hpp"
|
||||
#include "extractor/edge_based_node.hpp"
|
||||
#include "extractor/guidance/turn_instruction.hpp"
|
||||
#include "extractor/guidance/turn_lane_types.hpp"
|
||||
#include "extractor/intersection_bearings_container.hpp"
|
||||
@ -337,43 +338,21 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
|
||||
void InitializeEdgeBasedNodeDataInformationPointers(storage::DataLayout &layout,
|
||||
char *memory_ptr)
|
||||
{
|
||||
const auto via_geometry_list_ptr =
|
||||
layout.GetBlockPtr<GeometryID>(memory_ptr, storage::DataLayout::GEOMETRY_ID_LIST);
|
||||
util::vector_view<GeometryID> geometry_ids(
|
||||
via_geometry_list_ptr, layout.num_entries[storage::DataLayout::GEOMETRY_ID_LIST]);
|
||||
const auto edge_based_node_list_ptr = layout.GetBlockPtr<extractor::EdgeBasedNode>(
|
||||
memory_ptr, storage::DataLayout::EDGE_BASED_NODE_DATA_LIST);
|
||||
util::vector_view<extractor::EdgeBasedNode> edge_based_node_data_list(
|
||||
edge_based_node_list_ptr,
|
||||
layout.num_entries[storage::DataLayout::EDGE_BASED_NODE_DATA_LIST]);
|
||||
|
||||
const auto name_id_list_ptr =
|
||||
layout.GetBlockPtr<NameID>(memory_ptr, storage::DataLayout::NAME_ID_LIST);
|
||||
util::vector_view<NameID> name_ids(name_id_list_ptr,
|
||||
layout.num_entries[storage::DataLayout::NAME_ID_LIST]);
|
||||
const auto annotation_data_list_ptr =
|
||||
layout.GetBlockPtr<extractor::NodeBasedEdgeAnnotation>(
|
||||
memory_ptr, storage::DataLayout::ANNOTATION_DATA_LIST);
|
||||
util::vector_view<extractor::NodeBasedEdgeAnnotation> annotation_data(
|
||||
annotation_data_list_ptr,
|
||||
layout.num_entries[storage::DataLayout::ANNOTATION_DATA_LIST]);
|
||||
|
||||
const auto component_id_list_ptr =
|
||||
layout.GetBlockPtr<ComponentID>(memory_ptr, storage::DataLayout::COMPONENT_ID_LIST);
|
||||
util::vector_view<ComponentID> component_ids(
|
||||
component_id_list_ptr, layout.num_entries[storage::DataLayout::COMPONENT_ID_LIST]);
|
||||
|
||||
const auto travel_mode_list_ptr = layout.GetBlockPtr<extractor::TravelMode>(
|
||||
memory_ptr, storage::DataLayout::TRAVEL_MODE_LIST);
|
||||
util::vector_view<extractor::TravelMode> travel_modes(
|
||||
travel_mode_list_ptr, layout.num_entries[storage::DataLayout::TRAVEL_MODE_LIST]);
|
||||
|
||||
const auto classes_list_ptr =
|
||||
layout.GetBlockPtr<extractor::ClassData>(memory_ptr, storage::DataLayout::CLASSES_LIST);
|
||||
util::vector_view<extractor::ClassData> classes(
|
||||
classes_list_ptr, layout.num_entries[storage::DataLayout::CLASSES_LIST]);
|
||||
|
||||
auto is_left_hand_driving_ptr = layout.GetBlockPtr<unsigned>(
|
||||
memory_ptr, storage::DataLayout::IS_LEFT_HAND_DRIVING_LIST);
|
||||
util::vector_view<bool> is_left_hand_driving(
|
||||
is_left_hand_driving_ptr,
|
||||
layout.num_entries[storage::DataLayout::IS_LEFT_HAND_DRIVING_LIST]);
|
||||
|
||||
edge_based_node_data = extractor::EdgeBasedNodeDataView(std::move(geometry_ids),
|
||||
std::move(name_ids),
|
||||
std::move(component_ids),
|
||||
std::move(travel_modes),
|
||||
std::move(classes),
|
||||
std::move(is_left_hand_driving));
|
||||
edge_based_node_data = extractor::EdgeBasedNodeDataView(
|
||||
std::move(edge_based_node_data_list), std::move(annotation_data));
|
||||
}
|
||||
|
||||
void InitializeEdgeInformationPointers(storage::DataLayout &layout, char *memory_ptr)
|
||||
@ -465,7 +444,6 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
|
||||
geometries_index_ptr, data_layout.num_entries[storage::DataLayout::GEOMETRIES_INDEX]);
|
||||
|
||||
auto num_entries = data_layout.num_entries[storage::DataLayout::GEOMETRIES_NODE_LIST];
|
||||
|
||||
auto geometries_node_list_ptr = data_layout.GetBlockPtr<NodeID>(
|
||||
memory_block, storage::DataLayout::GEOMETRIES_NODE_LIST);
|
||||
util::vector_view<NodeID> geometry_node_list(geometries_node_list_ptr, num_entries);
|
||||
|
@ -14,8 +14,6 @@
|
||||
#include "extractor/nbg_to_ebg.hpp"
|
||||
#include "extractor/node_data_container.hpp"
|
||||
#include "extractor/original_edge_data.hpp"
|
||||
#include "extractor/packed_osm_ids.hpp"
|
||||
#include "extractor/profile_properties.hpp"
|
||||
#include "extractor/query_node.hpp"
|
||||
#include "extractor/restriction_index.hpp"
|
||||
#include "extractor/way_restriction_map.hpp"
|
||||
@ -26,7 +24,6 @@
|
||||
#include "util/guidance/entry_class.hpp"
|
||||
#include "util/name_table.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
#include "util/packed_vector.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include "storage/io.hpp"
|
||||
@ -71,13 +68,12 @@ class EdgeBasedGraphFactory
|
||||
EdgeBasedGraphFactory(const EdgeBasedGraphFactory &) = delete;
|
||||
EdgeBasedGraphFactory &operator=(const EdgeBasedGraphFactory &) = delete;
|
||||
|
||||
explicit EdgeBasedGraphFactory(std::shared_ptr<util::NodeBasedDynamicGraph> node_based_graph,
|
||||
CompressedEdgeContainer &compressed_edge_container,
|
||||
explicit EdgeBasedGraphFactory(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
EdgeBasedNodeDataContainer &node_data_container,
|
||||
const CompressedEdgeContainer &compressed_edge_container,
|
||||
const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const std::unordered_set<NodeID> &traffic_lights,
|
||||
const std::vector<util::Coordinate> &coordinates,
|
||||
const extractor::PackedOSMIDs &osm_node_ids,
|
||||
ProfileProperties profile_properties,
|
||||
const util::NameTable &name_table,
|
||||
guidance::LaneDescriptionMap &lane_description_map);
|
||||
|
||||
@ -95,7 +91,6 @@ class EdgeBasedGraphFactory
|
||||
|
||||
// The following get access functions destroy the content in the factory
|
||||
void GetEdgeBasedEdges(util::DeallocatingVector<EdgeBasedEdge> &edges);
|
||||
void GetEdgeBasedNodes(EdgeBasedNodeDataContainer &data_container);
|
||||
void GetEdgeBasedNodeSegments(std::vector<EdgeBasedNodeSegment> &nodes);
|
||||
void GetStartPointMarkers(std::vector<bool> &node_is_startpoint);
|
||||
void GetEdgeBasedNodeWeights(std::vector<EdgeWeight> &output_node_weights);
|
||||
@ -144,7 +139,7 @@ class EdgeBasedGraphFactory
|
||||
|
||||
//! list of edge based nodes (compressed segments)
|
||||
std::vector<EdgeBasedNodeSegment> m_edge_based_node_segments;
|
||||
EdgeBasedNodeDataContainer m_edge_based_node_container;
|
||||
EdgeBasedNodeDataContainer &m_edge_based_node_container;
|
||||
util::DeallocatingVector<EdgeBasedEdge> m_edge_based_edge_list;
|
||||
|
||||
// The number of edge-based nodes is mostly made up out of the edges in the node-based graph.
|
||||
@ -155,19 +150,20 @@ class EdgeBasedGraphFactory
|
||||
std::uint64_t m_number_of_edge_based_nodes;
|
||||
|
||||
const std::vector<util::Coordinate> &m_coordinates;
|
||||
const extractor::PackedOSMIDs &m_osm_node_ids;
|
||||
std::shared_ptr<util::NodeBasedDynamicGraph> m_node_based_graph;
|
||||
const util::NodeBasedDynamicGraph &m_node_based_graph;
|
||||
|
||||
const std::unordered_set<NodeID> &m_barrier_nodes;
|
||||
const std::unordered_set<NodeID> &m_traffic_lights;
|
||||
CompressedEdgeContainer &m_compressed_edge_container;
|
||||
|
||||
ProfileProperties profile_properties;
|
||||
const CompressedEdgeContainer &m_compressed_edge_container;
|
||||
|
||||
const util::NameTable &name_table;
|
||||
guidance::LaneDescriptionMap &lane_description_map;
|
||||
|
||||
unsigned RenumberEdges();
|
||||
// In the edge based graph, any traversable (non reversed) edge of the node-based graph forms a
|
||||
// node of the edge-based graph. To be able to name these nodes, we loop over the node-based
|
||||
// graph and create a mapping from edges (node-based) to nodes (edge-based). The mapping is
|
||||
// essentially a prefix-sum over all previous non-reversed edges of the node-based graph.
|
||||
unsigned LabelEdgeBasedNodes();
|
||||
|
||||
// During the generation of the edge-expanded nodes, we need to also generate duplicates that
|
||||
// represent state during via-way restrictions (see
|
||||
@ -194,6 +190,8 @@ class EdgeBasedGraphFactory
|
||||
std::size_t skipped_uturns_counter;
|
||||
std::size_t skipped_barrier_turns_counter;
|
||||
|
||||
// mapping of node-based edges to edge-based nodes
|
||||
std::vector<NodeID> nbe_to_ebn_mapping;
|
||||
util::ConcurrentIDMap<util::guidance::BearingClass, BearingClassID> bearing_class_hash;
|
||||
std::vector<BearingClassID> bearing_class_by_node_based_node;
|
||||
util::ConcurrentIDMap<util::guidance::EntryClass, EntryClassID> entry_class_hash;
|
||||
|
21
include/extractor/edge_based_node.hpp
Normal file
21
include/extractor/edge_based_node.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef OSRM_EXTRACTOR_EDGE_BASED_NODE_HPP_
|
||||
#define OSRM_EXTRACTOR_EDGE_BASED_NODE_HPP_
|
||||
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
struct EdgeBasedNode
|
||||
{
|
||||
GeometryID geometry_id;
|
||||
ComponentID component_id;
|
||||
AnnotationID annotation_id;
|
||||
};
|
||||
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
||||
#endif // OSRM_EXTRACTOR_EDGE_BASED_NODE_HPP_
|
@ -28,12 +28,14 @@ class ExtractionContainers
|
||||
|
||||
void WriteNodes(storage::io::FileWriter &file_out) const;
|
||||
void WriteEdges(storage::io::FileWriter &file_out) const;
|
||||
void WriteMetadata(storage::io::FileWriter &file_out) const;
|
||||
void WriteCharData(const std::string &file_name);
|
||||
|
||||
public:
|
||||
using NodeIDVector = std::vector<OSMNodeID>;
|
||||
using NodeVector = std::vector<QueryNode>;
|
||||
using EdgeVector = std::vector<InternalExtractorEdge>;
|
||||
using AnnotationDataVector = std::vector<NodeBasedEdgeAnnotation>;
|
||||
using WayIDStartEndVector = std::vector<FirstAndLastSegmentOfWay>;
|
||||
using NameCharData = std::vector<unsigned char>;
|
||||
using NameOffsets = std::vector<unsigned>;
|
||||
@ -43,6 +45,7 @@ class ExtractionContainers
|
||||
NodeIDVector used_node_id_list;
|
||||
NodeVector all_nodes_list;
|
||||
EdgeVector all_edges_list;
|
||||
AnnotationDataVector all_edges_annotation_data_list;
|
||||
NameCharData name_char_data;
|
||||
NameOffsets name_offsets;
|
||||
// an adjacency array containing all turn lane masks
|
||||
|
@ -32,6 +32,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "extractor/edge_based_graph_factory.hpp"
|
||||
#include "extractor/extractor_config.hpp"
|
||||
#include "extractor/graph_compressor.hpp"
|
||||
#include "extractor/packed_osm_ids.hpp"
|
||||
|
||||
#include "util/guidance/bearing_class.hpp"
|
||||
#include "util/guidance/entry_class.hpp"
|
||||
@ -61,19 +62,27 @@ class Extractor
|
||||
std::vector<ConditionalTurnRestriction>>
|
||||
ParseOSMData(ScriptingEnvironment &scripting_environment, const unsigned number_of_threads);
|
||||
|
||||
std::pair<std::size_t, EdgeID>
|
||||
BuildEdgeExpandedGraph(ScriptingEnvironment &scripting_environment,
|
||||
std::vector<util::Coordinate> &coordinates,
|
||||
extractor::PackedOSMIDs &osm_node_ids,
|
||||
EdgeBasedNodeDataContainer &edge_based_nodes_container,
|
||||
std::vector<EdgeBasedNodeSegment> &edge_based_node_segments,
|
||||
std::vector<bool> &node_is_startpoint,
|
||||
std::vector<EdgeWeight> &edge_based_node_weights,
|
||||
util::DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
|
||||
const std::string &intersection_class_output_file,
|
||||
std::vector<TurnRestriction> &turn_restrictions,
|
||||
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
|
||||
guidance::LaneDescriptionMap &turn_lane_map);
|
||||
EdgeID BuildEdgeExpandedGraph(
|
||||
// input data
|
||||
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
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 std::vector<TurnRestriction> &turn_restrictions,
|
||||
const std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
|
||||
// might have to be updated to add new lane combinations
|
||||
guidance::LaneDescriptionMap &turn_lane_map,
|
||||
// for calculating turn penalties
|
||||
ScriptingEnvironment &scripting_environment,
|
||||
// output data
|
||||
EdgeBasedNodeDataContainer &edge_based_nodes_container,
|
||||
std::vector<EdgeBasedNodeSegment> &edge_based_node_segments,
|
||||
std::vector<bool> &node_is_startpoint,
|
||||
std::vector<EdgeWeight> &edge_based_node_weights,
|
||||
util::DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
|
||||
const std::string &intersection_class_output_file);
|
||||
|
||||
void FindComponents(unsigned max_edge_id,
|
||||
const util::DeallocatingVector<EdgeBasedEdge> &input_edge_list,
|
||||
const std::vector<EdgeBasedNodeSegment> &input_node_segments,
|
||||
@ -82,11 +91,6 @@ class Extractor
|
||||
std::vector<bool> node_is_startpoint,
|
||||
const std::vector<util::Coordinate> &coordinates);
|
||||
std::shared_ptr<RestrictionMap> LoadRestrictionMap();
|
||||
std::shared_ptr<util::NodeBasedDynamicGraph>
|
||||
LoadNodeBasedGraph(std::unordered_set<NodeID> &barrier_nodes,
|
||||
std::unordered_set<NodeID> &traffic_lights,
|
||||
std::vector<util::Coordinate> &coordinates,
|
||||
extractor::PackedOSMIDs &osm_node_ids);
|
||||
|
||||
// Writes compressed node based graph and its embedding into a file for osrm-partition to use.
|
||||
static void WriteCompressedNodeBasedGraph(const std::string &path,
|
||||
|
@ -78,27 +78,27 @@ inline void writeProfileProperties(const boost::filesystem::path &path,
|
||||
|
||||
template <typename EdgeBasedEdgeVector>
|
||||
void writeEdgeBasedGraph(const boost::filesystem::path &path,
|
||||
EdgeID const max_edge_id,
|
||||
EdgeID const number_of_edge_based_nodes,
|
||||
const EdgeBasedEdgeVector &edge_based_edge_list)
|
||||
{
|
||||
static_assert(std::is_same<typename EdgeBasedEdgeVector::value_type, EdgeBasedEdge>::value, "");
|
||||
|
||||
storage::io::FileWriter writer(path, storage::io::FileWriter::GenerateFingerprint);
|
||||
|
||||
writer.WriteElementCount64(max_edge_id);
|
||||
writer.WriteElementCount64(number_of_edge_based_nodes);
|
||||
storage::serialization::write(writer, edge_based_edge_list);
|
||||
}
|
||||
|
||||
template <typename EdgeBasedEdgeVector>
|
||||
void readEdgeBasedGraph(const boost::filesystem::path &path,
|
||||
EdgeID &max_edge_id,
|
||||
EdgeID &number_of_edge_based_nodes,
|
||||
EdgeBasedEdgeVector &edge_based_edge_list)
|
||||
{
|
||||
static_assert(std::is_same<typename EdgeBasedEdgeVector::value_type, EdgeBasedEdge>::value, "");
|
||||
|
||||
storage::io::FileReader reader(path, storage::io::FileReader::VerifyFingerprint);
|
||||
|
||||
max_edge_id = reader.ReadElementCount64();
|
||||
number_of_edge_based_nodes = reader.ReadElementCount64();
|
||||
storage::serialization::read(reader, edge_based_edge_list);
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,7 @@ class GraphCompressor
|
||||
std::vector<TurnRestriction> &turn_restrictions,
|
||||
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
|
||||
util::NodeBasedDynamicGraph &graph,
|
||||
const std::vector<NodeBasedEdgeAnnotation> &node_data_container,
|
||||
CompressedEdgeContainer &geometry_compressor);
|
||||
|
||||
private:
|
||||
|
@ -225,7 +225,7 @@ class CoordinateExtractor
|
||||
const std::vector<double> &segment_distances,
|
||||
const double segment_length,
|
||||
const double considered_lane_width,
|
||||
const util::NodeBasedEdgeData &edge_data) const;
|
||||
const extractor::NodeBasedEdgeClassification &edge_data) const;
|
||||
|
||||
/*
|
||||
* If the very first coordinate is within lane offsets and the rest offers a near straight line,
|
||||
|
@ -16,6 +16,7 @@ class DrivewayHandler final : public IntersectionHandler
|
||||
public:
|
||||
DrivewayHandler(const IntersectionGenerator &intersection_generator,
|
||||
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const std::vector<util::Coordinate> &coordinates,
|
||||
const util::NameTable &name_table,
|
||||
const SuffixTable &street_name_suffix_table);
|
||||
|
@ -38,6 +38,7 @@ class IntersectionGenerator
|
||||
{
|
||||
public:
|
||||
IntersectionGenerator(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const RestrictionMap &restriction_map,
|
||||
const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const std::vector<util::Coordinate> &coordinates,
|
||||
@ -110,6 +111,7 @@ class IntersectionGenerator
|
||||
|
||||
private:
|
||||
const util::NodeBasedDynamicGraph &node_based_graph;
|
||||
const EdgeBasedNodeDataContainer &node_data_container;
|
||||
const RestrictionMap &restriction_map;
|
||||
const std::unordered_set<NodeID> &barrier_nodes;
|
||||
const std::vector<util::Coordinate> &coordinates;
|
||||
|
@ -33,6 +33,7 @@ class IntersectionHandler
|
||||
{
|
||||
public:
|
||||
IntersectionHandler(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const std::vector<util::Coordinate> &coordinates,
|
||||
const util::NameTable &name_table,
|
||||
const SuffixTable &street_name_suffix_table,
|
||||
@ -50,6 +51,7 @@ class IntersectionHandler
|
||||
|
||||
protected:
|
||||
const util::NodeBasedDynamicGraph &node_based_graph;
|
||||
const EdgeBasedNodeDataContainer &node_data_container;
|
||||
const std::vector<util::Coordinate> &coordinates;
|
||||
const util::NameTable &name_table;
|
||||
const SuffixTable &street_name_suffix_table;
|
||||
@ -124,7 +126,6 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
|
||||
const IntersectionType &intersection) const
|
||||
{
|
||||
using Road = typename IntersectionType::value_type;
|
||||
using EdgeData = osrm::util::NodeBasedDynamicGraph::EdgeData;
|
||||
using osrm::util::angularDeviation;
|
||||
|
||||
// no obvious road
|
||||
@ -135,7 +136,8 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
|
||||
if (intersection.size() == 2)
|
||||
return 1;
|
||||
|
||||
const EdgeData &in_way_data = node_based_graph.GetEdgeData(via_edge);
|
||||
const auto &in_way_edge = node_based_graph.GetEdgeData(via_edge);
|
||||
const auto &in_way_data = node_data_container.GetAnnotation(in_way_edge.annotation_data);
|
||||
|
||||
// the strategy for picking the most obvious turn involves deciding between
|
||||
// an overall best candidate and a best candidate that shares the same name
|
||||
@ -146,35 +148,35 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
|
||||
double best_continue_deviation = 180;
|
||||
|
||||
/* helper functions */
|
||||
const auto IsContinueRoad = [&](const EdgeData &way_data) {
|
||||
const auto IsContinueRoad = [&](const NodeBasedEdgeAnnotation &way_data) {
|
||||
return !util::guidance::requiresNameAnnounced(
|
||||
in_way_data.name_id, way_data.name_id, name_table, street_name_suffix_table);
|
||||
};
|
||||
auto sameOrHigherPriority = [&in_way_data](const auto &way_data) {
|
||||
return way_data.road_classification.GetPriority() <=
|
||||
in_way_data.road_classification.GetPriority();
|
||||
auto sameOrHigherPriority = [&](const auto &way_data) {
|
||||
return way_data.flags.road_classification.GetPriority() <=
|
||||
in_way_edge.flags.road_classification.GetPriority();
|
||||
};
|
||||
auto IsLowPriority = [](const auto &way_data) {
|
||||
return way_data.road_classification.IsLowPriorityRoadClass();
|
||||
return way_data.flags.road_classification.IsLowPriorityRoadClass();
|
||||
};
|
||||
// These two Compare functions are used for sifting out best option and continue
|
||||
// candidates by evaluating all the ways in an intersection by what they share
|
||||
// with the in way. Ideal candidates are of similar road class with the in way
|
||||
// and are require relatively straight turns.
|
||||
const auto RoadCompare = [&](const auto &lhs, const auto &rhs) {
|
||||
const EdgeData &lhs_data = node_based_graph.GetEdgeData(lhs.eid);
|
||||
const EdgeData &rhs_data = node_based_graph.GetEdgeData(rhs.eid);
|
||||
const auto &lhs_edge = node_based_graph.GetEdgeData(lhs.eid);
|
||||
const auto &rhs_edge = node_based_graph.GetEdgeData(rhs.eid);
|
||||
const auto lhs_deviation = angularDeviation(lhs.angle, STRAIGHT_ANGLE);
|
||||
const auto rhs_deviation = angularDeviation(rhs.angle, STRAIGHT_ANGLE);
|
||||
|
||||
const bool rhs_same_classification =
|
||||
rhs_data.road_classification == in_way_data.road_classification;
|
||||
rhs_edge.flags.road_classification == in_way_edge.flags.road_classification;
|
||||
const bool lhs_same_classification =
|
||||
lhs_data.road_classification == in_way_data.road_classification;
|
||||
const bool rhs_same_or_higher_priority = sameOrHigherPriority(rhs_data);
|
||||
const bool rhs_low_priority = IsLowPriority(rhs_data);
|
||||
const bool lhs_same_or_higher_priority = sameOrHigherPriority(lhs_data);
|
||||
const bool lhs_low_priority = IsLowPriority(lhs_data);
|
||||
lhs_edge.flags.road_classification == in_way_edge.flags.road_classification;
|
||||
const bool rhs_same_or_higher_priority = sameOrHigherPriority(rhs_edge);
|
||||
const bool rhs_low_priority = IsLowPriority(rhs_edge);
|
||||
const bool lhs_same_or_higher_priority = sameOrHigherPriority(lhs_edge);
|
||||
const bool lhs_low_priority = IsLowPriority(lhs_edge);
|
||||
auto left_tie = std::tie(lhs.entry_allowed,
|
||||
lhs_same_or_higher_priority,
|
||||
rhs_low_priority,
|
||||
@ -188,8 +190,10 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
|
||||
return left_tie > right_tie;
|
||||
};
|
||||
const auto RoadCompareSameName = [&](const auto &lhs, const auto &rhs) {
|
||||
const EdgeData &lhs_data = node_based_graph.GetEdgeData(lhs.eid);
|
||||
const EdgeData &rhs_data = node_based_graph.GetEdgeData(rhs.eid);
|
||||
const auto &lhs_data = node_data_container.GetAnnotation(
|
||||
node_based_graph.GetEdgeData(lhs.eid).annotation_data);
|
||||
const auto &rhs_data = node_data_container.GetAnnotation(
|
||||
node_based_graph.GetEdgeData(rhs.eid).annotation_data);
|
||||
const auto lhs_continues = IsContinueRoad(lhs_data);
|
||||
const auto rhs_continues = IsContinueRoad(rhs_data);
|
||||
const auto left_tie = std::tie(lhs.entry_allowed, lhs_continues);
|
||||
@ -204,12 +208,14 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
|
||||
|
||||
best_option = std::distance(begin(intersection), best_option_it);
|
||||
best_option_deviation = angularDeviation(intersection[best_option].angle, STRAIGHT_ANGLE);
|
||||
const auto &best_option_data = node_based_graph.GetEdgeData(intersection[best_option].eid);
|
||||
const auto &best_option_edge = node_based_graph.GetEdgeData(intersection[best_option].eid);
|
||||
const auto &best_option_data =
|
||||
node_data_container.GetAnnotation(best_option_edge.annotation_data);
|
||||
|
||||
// Unless the in way is also low priority, it is generally undesirable to
|
||||
// indicate that a low priority road is obvious
|
||||
if (IsLowPriority(best_option_data) &&
|
||||
best_option_data.road_classification != in_way_data.road_classification)
|
||||
if (IsLowPriority(best_option_edge) &&
|
||||
best_option_edge.flags.road_classification != in_way_edge.flags.road_classification)
|
||||
{
|
||||
best_option = 0;
|
||||
best_option_deviation = 180;
|
||||
@ -219,13 +225,13 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
|
||||
const auto straightest = intersection.findClosestTurn(STRAIGHT_ANGLE);
|
||||
if (straightest != best_option_it)
|
||||
{
|
||||
const EdgeData &straightest_data = node_based_graph.GetEdgeData(straightest->eid);
|
||||
const auto &straightest_edge = node_based_graph.GetEdgeData(straightest->eid);
|
||||
double straightest_data_deviation = angularDeviation(straightest->angle, STRAIGHT_ANGLE);
|
||||
const auto deviation_diff =
|
||||
std::abs(best_option_deviation - straightest_data_deviation) > FUZZY_ANGLE_DIFFERENCE;
|
||||
const auto not_ramp_class = !straightest_data.road_classification.IsRampClass();
|
||||
const auto not_link_class = !straightest_data.road_classification.IsLinkClass();
|
||||
if (deviation_diff && !IsLowPriority(straightest_data) && not_ramp_class &&
|
||||
const auto not_ramp_class = !straightest_edge.flags.road_classification.IsRampClass();
|
||||
const auto not_link_class = !straightest_edge.flags.road_classification.IsLinkClass();
|
||||
if (deviation_diff && !IsLowPriority(straightest_edge) && not_ramp_class &&
|
||||
not_link_class && !IsContinueRoad(best_option_data))
|
||||
{
|
||||
best_option = std::distance(begin(intersection), straightest);
|
||||
@ -240,7 +246,9 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
|
||||
|
||||
auto best_continue_it =
|
||||
std::min_element(begin(intersection), end(intersection), RoadCompareSameName);
|
||||
const auto best_continue_data = node_based_graph.GetEdgeData(best_continue_it->eid);
|
||||
const auto best_continue_edge = node_based_graph.GetEdgeData(best_continue_it->eid);
|
||||
const auto best_continue_data =
|
||||
node_data_container.GetAnnotation(best_continue_edge.annotation_data);
|
||||
if (IsContinueRoad(best_continue_data) ||
|
||||
(in_way_data.name_id == EMPTY_NAMEID && best_continue_data.name_id == EMPTY_NAMEID))
|
||||
{
|
||||
@ -252,8 +260,7 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
|
||||
// if the best angle is going straight but the road is turning, declare no obvious turn
|
||||
if (0 != best_continue && best_option != best_continue &&
|
||||
best_option_deviation < MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
|
||||
node_based_graph.GetEdgeData(intersection[best_continue].eid).road_classification ==
|
||||
best_option_data.road_classification)
|
||||
best_continue_edge.flags.road_classification == best_option_edge.flags.road_classification)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@ -262,17 +269,21 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
|
||||
// continue instruction because they share a name with the approaching way
|
||||
const std::int64_t continue_count =
|
||||
count_if(++begin(intersection), end(intersection), [&](const auto &way) {
|
||||
return IsContinueRoad(node_based_graph.GetEdgeData(way.eid));
|
||||
return IsContinueRoad(node_data_container.GetAnnotation(
|
||||
node_based_graph.GetEdgeData(way.eid).annotation_data));
|
||||
});
|
||||
const std::int64_t continue_count_valid =
|
||||
count_if(++begin(intersection), end(intersection), [&](const auto &way) {
|
||||
return IsContinueRoad(node_based_graph.GetEdgeData(way.eid)) && way.entry_allowed;
|
||||
return IsContinueRoad(node_data_container.GetAnnotation(
|
||||
node_based_graph.GetEdgeData(way.eid).annotation_data)) &&
|
||||
way.entry_allowed;
|
||||
});
|
||||
|
||||
// checks if continue candidates are sharp turns
|
||||
const bool all_continues_are_narrow = [&]() {
|
||||
return std::count_if(begin(intersection), end(intersection), [&](const Road &road) {
|
||||
const EdgeData &road_data = node_based_graph.GetEdgeData(road.eid);
|
||||
const auto &road_data = node_data_container.GetAnnotation(
|
||||
node_based_graph.GetEdgeData(road.eid).annotation_data);
|
||||
const double &road_angle = angularDeviation(road.angle, STRAIGHT_ANGLE);
|
||||
return IsContinueRoad(road_data) && (road_angle < NARROW_TURN_ANGLE);
|
||||
}) == continue_count;
|
||||
@ -296,32 +307,32 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
|
||||
return true;
|
||||
|
||||
// continue data now most certainly exists
|
||||
const auto &continue_data = node_based_graph.GetEdgeData(intersection[best_continue].eid);
|
||||
const auto &continue_edge = node_based_graph.GetEdgeData(intersection[best_continue].eid);
|
||||
|
||||
// best_continue is obvious by road class
|
||||
if (obviousByRoadClass(in_way_data.road_classification,
|
||||
continue_data.road_classification,
|
||||
best_option_data.road_classification))
|
||||
if (obviousByRoadClass(in_way_edge.flags.road_classification,
|
||||
continue_edge.flags.road_classification,
|
||||
best_option_edge.flags.road_classification))
|
||||
return false;
|
||||
|
||||
// best_option is obvious by road class
|
||||
if (obviousByRoadClass(in_way_data.road_classification,
|
||||
best_option_data.road_classification,
|
||||
continue_data.road_classification))
|
||||
if (obviousByRoadClass(in_way_edge.flags.road_classification,
|
||||
best_option_edge.flags.road_classification,
|
||||
continue_edge.flags.road_classification))
|
||||
return true;
|
||||
|
||||
// the best_option deviation is very straight and not a ramp
|
||||
if (best_option_deviation < best_continue_deviation &&
|
||||
best_option_deviation < FUZZY_ANGLE_DIFFERENCE &&
|
||||
!best_option_data.road_classification.IsRampClass())
|
||||
!best_option_edge.flags.road_classification.IsRampClass())
|
||||
return true;
|
||||
|
||||
// the continue road is of a lower priority, while the road continues on the same priority
|
||||
// with a better angle
|
||||
if (best_option_deviation < best_continue_deviation &&
|
||||
in_way_data.road_classification == best_option_data.road_classification &&
|
||||
continue_data.road_classification.GetPriority() >
|
||||
best_option_data.road_classification.GetPriority())
|
||||
in_way_edge.flags.road_classification == best_option_edge.flags.road_classification &&
|
||||
continue_edge.flags.road_classification.GetPriority() >
|
||||
best_option_edge.flags.road_classification.GetPriority())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@ -335,24 +346,25 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
|
||||
const auto in_through_candidate =
|
||||
intersection.FindClosestBearing(util::bearing::reverse(road.bearing));
|
||||
|
||||
const auto &in_data = node_based_graph.GetEdgeData(in_through_candidate->eid);
|
||||
const auto &out_data = node_based_graph.GetEdgeData(road.eid);
|
||||
const auto &in_edge = node_based_graph.GetEdgeData(in_through_candidate->eid);
|
||||
const auto &out_edge = node_based_graph.GetEdgeData(road.eid);
|
||||
|
||||
// by asking for the same class, we ensure that we do not overrule obvious by road-class
|
||||
// decisions
|
||||
const auto same_class = in_data.road_classification == out_data.road_classification;
|
||||
const auto same_class =
|
||||
in_edge.flags.road_classification == out_edge.flags.road_classification;
|
||||
|
||||
// only if the entry is allowed for one of the two, but not the other, we need to check.
|
||||
// Otherwise other handlers do it better
|
||||
const bool is_oneway = !in_through_candidate->entry_allowed && road.entry_allowed;
|
||||
|
||||
const bool not_roundabout =
|
||||
!(in_data.roundabout || in_data.circular || out_data.roundabout || out_data.circular);
|
||||
const bool not_roundabout = !(in_edge.flags.roundabout || in_edge.flags.circular ||
|
||||
out_edge.flags.roundabout || out_edge.flags.circular);
|
||||
|
||||
// for the purpose of this check, we do not care about low-priority roads (parking lots,
|
||||
// mostly). Since we postulate both classes to be the same, checking one of the two is
|
||||
// enough
|
||||
const bool not_low_priority = !in_data.road_classification.IsLowPriorityRoadClass();
|
||||
const bool not_low_priority = !in_edge.flags.road_classification.IsLowPriorityRoadClass();
|
||||
|
||||
const auto in_deviation = angularDeviation(in_through_candidate->angle, STRAIGHT_ANGLE);
|
||||
const auto out_deviaiton = angularDeviation(road.angle, STRAIGHT_ANGLE);
|
||||
@ -371,11 +383,11 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
|
||||
const auto index_candidate = (best_option + 1) % intersection.size();
|
||||
if (index_candidate == 0)
|
||||
return index_candidate;
|
||||
const auto &candidate_data =
|
||||
const auto &candidate_edge =
|
||||
node_based_graph.GetEdgeData(intersection[index_candidate].eid);
|
||||
if (obviousByRoadClass(in_way_data.road_classification,
|
||||
best_option_data.road_classification,
|
||||
candidate_data.road_classification))
|
||||
if (obviousByRoadClass(in_way_edge.flags.road_classification,
|
||||
best_option_edge.flags.road_classification,
|
||||
candidate_edge.flags.road_classification))
|
||||
return (index_candidate + 1) % intersection.size();
|
||||
else
|
||||
return index_candidate;
|
||||
@ -386,11 +398,11 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
|
||||
const auto index_candidate = best_option - 1;
|
||||
if (index_candidate == 0)
|
||||
return index_candidate;
|
||||
const auto candidate_data =
|
||||
const auto &candidate_edge =
|
||||
node_based_graph.GetEdgeData(intersection[index_candidate].eid);
|
||||
if (obviousByRoadClass(in_way_data.road_classification,
|
||||
best_option_data.road_classification,
|
||||
candidate_data.road_classification))
|
||||
if (obviousByRoadClass(in_way_edge.flags.road_classification,
|
||||
best_option_edge.flags.road_classification,
|
||||
candidate_edge.flags.road_classification))
|
||||
return index_candidate - 1;
|
||||
else
|
||||
return index_candidate;
|
||||
@ -407,17 +419,17 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
|
||||
std::min(left_deviation, right_deviation) > FUZZY_ANGLE_DIFFERENCE)
|
||||
return best_option;
|
||||
|
||||
const auto &left_data = node_based_graph.GetEdgeData(intersection[left_index].eid);
|
||||
const auto &right_data = node_based_graph.GetEdgeData(intersection[right_index].eid);
|
||||
const auto &left_edge = node_based_graph.GetEdgeData(intersection[left_index].eid);
|
||||
const auto &right_edge = node_based_graph.GetEdgeData(intersection[right_index].eid);
|
||||
|
||||
const bool obvious_to_left =
|
||||
left_index == 0 || obviousByRoadClass(in_way_data.road_classification,
|
||||
best_option_data.road_classification,
|
||||
left_data.road_classification);
|
||||
left_index == 0 || obviousByRoadClass(in_way_edge.flags.road_classification,
|
||||
best_option_edge.flags.road_classification,
|
||||
left_edge.flags.road_classification);
|
||||
const bool obvious_to_right =
|
||||
right_index == 0 || obviousByRoadClass(in_way_data.road_classification,
|
||||
best_option_data.road_classification,
|
||||
right_data.road_classification);
|
||||
right_index == 0 || obviousByRoadClass(in_way_edge.flags.road_classification,
|
||||
best_option_edge.flags.road_classification,
|
||||
right_edge.flags.road_classification);
|
||||
|
||||
// if the best_option turn isn't narrow, but there is a nearly straight turn, we don't
|
||||
// consider the turn obvious
|
||||
@ -447,14 +459,15 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
|
||||
distinction rate. If the road category is smaller, its also adjusted. Only
|
||||
roads of the same priority require the full distinction ratio.
|
||||
*/
|
||||
const auto &best_option_data =
|
||||
const auto &best_option_edge =
|
||||
node_based_graph.GetEdgeData(intersection[best_option].eid);
|
||||
const auto adjusted_distinction_ratio = [&]() {
|
||||
// obviousness by road classes
|
||||
if (in_way_data.road_classification == best_option_data.road_classification &&
|
||||
best_option_data.road_classification.GetPriority() <
|
||||
if (in_way_edge.flags.road_classification ==
|
||||
best_option_edge.flags.road_classification &&
|
||||
best_option_edge.flags.road_classification.GetPriority() <
|
||||
node_based_graph.GetEdgeData(intersection[index].eid)
|
||||
.road_classification.GetPriority())
|
||||
.flags.road_classification.GetPriority())
|
||||
return 0.8 * DISTINCTION_RATIO;
|
||||
// if road classes are the same, we use the full ratio
|
||||
else
|
||||
@ -472,7 +485,9 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto &continue_data = node_based_graph.GetEdgeData(intersection[best_continue].eid);
|
||||
const auto &continue_edge = node_based_graph.GetEdgeData(intersection[best_continue].eid);
|
||||
const auto &continue_data =
|
||||
node_data_container.GetAnnotation(continue_edge.annotation_data);
|
||||
if (std::abs(best_continue_deviation) < 1)
|
||||
return best_continue;
|
||||
|
||||
@ -488,11 +503,12 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
|
||||
if (i == best_continue || !intersection[i].entry_allowed)
|
||||
continue;
|
||||
|
||||
const auto &turn_data = node_based_graph.GetEdgeData(intersection[i].eid);
|
||||
const auto &turn_edge = node_based_graph.GetEdgeData(intersection[i].eid);
|
||||
const auto &turn_data = node_data_container.GetAnnotation(turn_edge.annotation_data);
|
||||
const bool is_obvious_by_road_class =
|
||||
obviousByRoadClass(in_way_data.road_classification,
|
||||
continue_data.road_classification,
|
||||
turn_data.road_classification);
|
||||
obviousByRoadClass(in_way_edge.flags.road_classification,
|
||||
continue_edge.flags.road_classification,
|
||||
turn_edge.flags.road_classification);
|
||||
|
||||
// if the main road is obvious by class, we ignore the current road as a potential
|
||||
// prevention of obviousness
|
||||
@ -500,9 +516,9 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
|
||||
continue;
|
||||
|
||||
// continuation could be grouped with a straight turn and the turning road is a ramp
|
||||
if (turn_data.road_classification.IsRampClass() &&
|
||||
if (turn_edge.flags.road_classification.IsRampClass() &&
|
||||
best_continue_deviation < GROUP_ANGLE &&
|
||||
!continue_data.road_classification.IsRampClass())
|
||||
!continue_edge.flags.road_classification.IsRampClass())
|
||||
continue;
|
||||
|
||||
// perfectly straight turns prevent obviousness
|
||||
@ -567,11 +583,13 @@ std::size_t IntersectionHandler::findObviousTurn(const EdgeID via_edge,
|
||||
// actually represents a near 180 degree different in bearings between the two
|
||||
// roads. So if there is a road that is enterable in the opposite direction just
|
||||
// prior, a turn is not obvious
|
||||
const auto &turn_data = node_based_graph.GetEdgeData(comparison_road.eid);
|
||||
const auto &turn_edge_data = node_based_graph.GetEdgeData(comparison_road.eid);
|
||||
const auto &turn_data =
|
||||
node_data_container.GetAnnotation(turn_edge_data.annotation_data);
|
||||
if (angularDeviation(comparison_road.angle, STRAIGHT_ANGLE) > GROUP_ANGLE &&
|
||||
angularDeviation(comparison_road.angle, continue_road.angle) <
|
||||
FUZZY_ANGLE_DIFFERENCE &&
|
||||
!turn_data.reversed && continue_data.CanCombineWith(turn_data))
|
||||
!turn_edge_data.reversed && continue_data.CanCombineWith(turn_data))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -43,6 +43,7 @@ class IntersectionNormalizer
|
||||
std::vector<IntersectionNormalizationOperation> performed_merges;
|
||||
};
|
||||
IntersectionNormalizer(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const std::vector<util::Coordinate> &node_coordinates,
|
||||
const util::NameTable &name_table,
|
||||
const SuffixTable &street_name_suffix_table,
|
||||
|
@ -37,6 +37,7 @@ class MergableRoadDetector
|
||||
using MergableRoadData = IntersectionShapeData;
|
||||
|
||||
MergableRoadDetector(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const std::vector<util::Coordinate> &node_coordinates,
|
||||
const IntersectionGenerator &intersection_generator,
|
||||
const CoordinateExtractor &coordinate_extractor,
|
||||
@ -77,8 +78,10 @@ class MergableRoadDetector
|
||||
|
||||
// When it comes to merging roads, we need to find out if two ways actually represent the
|
||||
// same road. This check tries to identify roads which are the same road in opposite directions
|
||||
bool EdgeDataSupportsMerge(const util::NodeBasedEdgeData &lhs_edge_data,
|
||||
const util::NodeBasedEdgeData &rhs_edge_data) const;
|
||||
bool EdgeDataSupportsMerge(const NodeBasedEdgeClassification &lhs_flags,
|
||||
const NodeBasedEdgeClassification &rhs_flags,
|
||||
const NodeBasedEdgeAnnotation &lhs_edge_annotation,
|
||||
const NodeBasedEdgeAnnotation &rhs_edge_annotation) const;
|
||||
|
||||
// Detect traffic loops.
|
||||
// Since OSRM cannot handle loop edges, we cannot directly see a connection between a node and
|
||||
@ -138,6 +141,7 @@ class MergableRoadDetector
|
||||
bool IsLinkRoad(const NodeID intersection_node, const MergableRoadData &road) const;
|
||||
|
||||
const util::NodeBasedDynamicGraph &node_based_graph;
|
||||
const EdgeBasedNodeDataContainer &node_data_container;
|
||||
const std::vector<util::Coordinate> &node_coordinates;
|
||||
const IntersectionGenerator &intersection_generator;
|
||||
const CoordinateExtractor &coordinate_extractor;
|
||||
|
@ -24,6 +24,7 @@ class MotorwayHandler : public IntersectionHandler
|
||||
{
|
||||
public:
|
||||
MotorwayHandler(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const std::vector<util::Coordinate> &coordinates,
|
||||
const util::NameTable &name_table,
|
||||
const SuffixTable &street_name_suffix_table,
|
||||
|
@ -28,6 +28,7 @@ class NodeBasedGraphWalker
|
||||
{
|
||||
public:
|
||||
NodeBasedGraphWalker(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const IntersectionGenerator &intersection_generator);
|
||||
|
||||
/*
|
||||
@ -46,6 +47,7 @@ class NodeBasedGraphWalker
|
||||
|
||||
private:
|
||||
const util::NodeBasedDynamicGraph &node_based_graph;
|
||||
const EdgeBasedNodeDataContainer &node_data_container;
|
||||
const IntersectionGenerator &intersection_generator;
|
||||
};
|
||||
|
||||
@ -106,7 +108,8 @@ struct SelectRoadByNameOnlyChoiceAndStraightness
|
||||
boost::optional<EdgeID> operator()(const NodeID nid,
|
||||
const EdgeID via_edge_id,
|
||||
const IntersectionView &intersection,
|
||||
const util::NodeBasedDynamicGraph &node_based_graph) const;
|
||||
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container) const;
|
||||
|
||||
private:
|
||||
const NameID desired_name_id;
|
||||
@ -131,7 +134,8 @@ struct SelectStraightmostRoadByNameAndOnlyChoice
|
||||
boost::optional<EdgeID> operator()(const NodeID nid,
|
||||
const EdgeID via_edge_id,
|
||||
const IntersectionView &intersection,
|
||||
const util::NodeBasedDynamicGraph &node_based_graph) const;
|
||||
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container) const;
|
||||
|
||||
private:
|
||||
const NameID desired_name_id;
|
||||
@ -201,8 +205,11 @@ NodeBasedGraphWalker::TraverseRoad(NodeID current_node_id,
|
||||
if (next_intersection.size() <= 1)
|
||||
return {};
|
||||
|
||||
auto next_edge_id =
|
||||
selector(current_node_id, current_edge_id, next_intersection, node_based_graph);
|
||||
auto next_edge_id = selector(current_node_id,
|
||||
current_edge_id,
|
||||
next_intersection,
|
||||
node_based_graph,
|
||||
node_data_container);
|
||||
|
||||
if (!next_edge_id)
|
||||
return {};
|
||||
@ -224,7 +231,8 @@ struct SkipTrafficSignalBarrierRoadSelector
|
||||
boost::optional<EdgeID> operator()(const NodeID,
|
||||
const EdgeID,
|
||||
const IntersectionView &intersection,
|
||||
const util::NodeBasedDynamicGraph &) const
|
||||
const util::NodeBasedDynamicGraph &,
|
||||
const EdgeBasedNodeDataContainer &) const
|
||||
{
|
||||
if (intersection.isTrafficSignalOrBarrier())
|
||||
{
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include "extractor/guidance/intersection_generator.hpp"
|
||||
#include "extractor/guidance/intersection_handler.hpp"
|
||||
#include "extractor/guidance/roundabout_type.hpp"
|
||||
#include "extractor/profile_properties.hpp"
|
||||
#include "extractor/query_node.hpp"
|
||||
|
||||
#include "util/name_table.hpp"
|
||||
@ -41,11 +40,11 @@ class RoundaboutHandler : public IntersectionHandler
|
||||
{
|
||||
public:
|
||||
RoundaboutHandler(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const std::vector<util::Coordinate> &coordinates,
|
||||
const CompressedEdgeContainer &compressed_edge_container,
|
||||
const util::NameTable &name_table,
|
||||
const SuffixTable &street_name_suffix_table,
|
||||
const ProfileProperties &profile_properties,
|
||||
const IntersectionGenerator &intersection_generator);
|
||||
|
||||
~RoundaboutHandler() override final = default;
|
||||
@ -86,8 +85,6 @@ class RoundaboutHandler : public IntersectionHandler
|
||||
qualifiesAsRoundaboutIntersection(const std::unordered_set<NodeID> &roundabout_nodes) const;
|
||||
|
||||
const CompressedEdgeContainer &compressed_edge_container;
|
||||
const ProfileProperties &profile_properties;
|
||||
|
||||
const CoordinateExtractor coordinate_extractor;
|
||||
};
|
||||
|
||||
|
@ -26,6 +26,7 @@ class SliproadHandler final : public IntersectionHandler
|
||||
public:
|
||||
SliproadHandler(const IntersectionGenerator &intersection_generator,
|
||||
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const std::vector<util::Coordinate> &coordinates,
|
||||
const util::NameTable &name_table,
|
||||
const SuffixTable &street_name_suffix_table);
|
||||
|
@ -23,6 +23,7 @@ class SuppressModeHandler final : public IntersectionHandler
|
||||
public:
|
||||
SuppressModeHandler(const IntersectionGenerator &intersection_generator,
|
||||
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const std::vector<util::Coordinate> &coordinates,
|
||||
const util::NameTable &name_table,
|
||||
const SuffixTable &street_name_suffix_table);
|
||||
|
@ -41,13 +41,13 @@ class TurnAnalysis
|
||||
{
|
||||
public:
|
||||
TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const std::vector<util::Coordinate> &coordinates,
|
||||
const RestrictionMap &restriction_map,
|
||||
const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const CompressedEdgeContainer &compressed_edge_container,
|
||||
const util::NameTable &name_table,
|
||||
const SuffixTable &street_name_suffix_table,
|
||||
const ProfileProperties &profile_properties);
|
||||
const SuffixTable &street_name_suffix_table);
|
||||
|
||||
/* Full Analysis Process for a single node/edge combination. Use with caution, as the process is
|
||||
* relatively expensive */
|
||||
|
@ -28,6 +28,7 @@ class TurnHandler : public IntersectionHandler
|
||||
{
|
||||
public:
|
||||
TurnHandler(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const std::vector<util::Coordinate> &coordinates,
|
||||
const util::NameTable &name_table,
|
||||
const SuffixTable &street_name_suffix_table,
|
||||
|
@ -73,6 +73,7 @@ class TurnLaneHandler
|
||||
typedef std::vector<TurnLaneData> LaneDataVector;
|
||||
|
||||
TurnLaneHandler(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
LaneDescriptionMap &lane_description_map,
|
||||
const TurnAnalysis &turn_analysis,
|
||||
util::guidance::LaneDataIdMap &id_map);
|
||||
@ -88,6 +89,7 @@ class TurnLaneHandler
|
||||
// we need to be able to look at previous intersections to, in some cases, find the correct turn
|
||||
// lanes for a turn
|
||||
const util::NodeBasedDynamicGraph &node_based_graph;
|
||||
const EdgeBasedNodeDataContainer &node_data_container;
|
||||
std::vector<std::uint32_t> turn_lane_offsets;
|
||||
std::vector<TurnLaneType::Mask> turn_lane_masks;
|
||||
LaneDescriptionMap &lane_description_map;
|
||||
|
@ -58,65 +58,24 @@ struct InternalExtractorEdge
|
||||
using WeightData = detail::ByEdgeOrByMeterValue;
|
||||
using DurationData = detail::ByEdgeOrByMeterValue;
|
||||
|
||||
explicit InternalExtractorEdge()
|
||||
: result(MIN_OSM_NODEID,
|
||||
MIN_OSM_NODEID,
|
||||
SPECIAL_NODEID,
|
||||
0,
|
||||
0,
|
||||
false, // forward
|
||||
false, // backward
|
||||
false, // roundabout
|
||||
false, // circular
|
||||
true, // can be startpoint
|
||||
false, // local access only
|
||||
false, // is_left_hand_driving
|
||||
false, // split edge
|
||||
TRAVEL_MODE_INACCESSIBLE,
|
||||
0,
|
||||
guidance::TurnLaneType::empty,
|
||||
guidance::RoadClassification()),
|
||||
weight_data(), duration_data()
|
||||
{
|
||||
}
|
||||
explicit InternalExtractorEdge() : weight_data(), duration_data() {}
|
||||
|
||||
explicit InternalExtractorEdge(OSMNodeID source,
|
||||
OSMNodeID target,
|
||||
NodeID name_id,
|
||||
WeightData weight_data,
|
||||
DurationData duration_data,
|
||||
bool forward,
|
||||
bool backward,
|
||||
bool roundabout,
|
||||
bool circular,
|
||||
bool startpoint,
|
||||
bool restricted,
|
||||
bool is_left_hand_driving,
|
||||
bool is_split,
|
||||
TravelMode travel_mode,
|
||||
ClassData classes,
|
||||
LaneDescriptionID lane_description,
|
||||
guidance::RoadClassification road_classification,
|
||||
util::Coordinate source_coordinate)
|
||||
: result(source,
|
||||
target,
|
||||
name_id,
|
||||
0,
|
||||
0,
|
||||
forward,
|
||||
backward,
|
||||
roundabout,
|
||||
circular,
|
||||
startpoint,
|
||||
restricted,
|
||||
is_left_hand_driving,
|
||||
is_split,
|
||||
travel_mode,
|
||||
classes,
|
||||
lane_description,
|
||||
std::move(road_classification)),
|
||||
weight_data(std::move(weight_data)), duration_data(std::move(duration_data)),
|
||||
source_coordinate(std::move(source_coordinate))
|
||||
: result(source, target, 0, 0, {}, -1, {}), weight_data(std::move(weight_data)),
|
||||
duration_data(std::move(duration_data)), source_coordinate(std::move(source_coordinate))
|
||||
{
|
||||
}
|
||||
|
||||
explicit InternalExtractorEdge(NodeBasedEdgeWithOSM edge,
|
||||
WeightData weight_data,
|
||||
DurationData duration_data,
|
||||
util::Coordinate source_coordinate)
|
||||
: result(std::move(edge)), weight_data(weight_data), duration_data(duration_data),
|
||||
source_coordinate(source_coordinate)
|
||||
{
|
||||
}
|
||||
|
||||
@ -132,45 +91,13 @@ struct InternalExtractorEdge
|
||||
// necessary static util functions for stxxl's sorting
|
||||
static InternalExtractorEdge min_osm_value()
|
||||
{
|
||||
return InternalExtractorEdge(MIN_OSM_NODEID,
|
||||
MIN_OSM_NODEID,
|
||||
SPECIAL_NODEID,
|
||||
WeightData(),
|
||||
DurationData(),
|
||||
false, // forward
|
||||
false, // backward
|
||||
false, // roundabout
|
||||
false, // circular
|
||||
true, // can be startpoint
|
||||
false, // local access only
|
||||
false, // is_left_hand_driving
|
||||
false, // split edge
|
||||
TRAVEL_MODE_INACCESSIBLE,
|
||||
0,
|
||||
INVALID_LANE_DESCRIPTIONID,
|
||||
guidance::RoadClassification(),
|
||||
util::Coordinate());
|
||||
return InternalExtractorEdge(
|
||||
MIN_OSM_NODEID, MIN_OSM_NODEID, WeightData(), DurationData(), util::Coordinate());
|
||||
}
|
||||
static InternalExtractorEdge max_osm_value()
|
||||
{
|
||||
return InternalExtractorEdge(MAX_OSM_NODEID,
|
||||
MAX_OSM_NODEID,
|
||||
SPECIAL_NODEID,
|
||||
WeightData(),
|
||||
DurationData(),
|
||||
false, // forward
|
||||
false, // backward
|
||||
false, // roundabout
|
||||
false, // circular
|
||||
true, // can be startpoint
|
||||
false, // local access only
|
||||
false, // is_left_hand_driving
|
||||
false, // split edge
|
||||
TRAVEL_MODE_INACCESSIBLE,
|
||||
0,
|
||||
INVALID_LANE_DESCRIPTIONID,
|
||||
guidance::RoadClassification(),
|
||||
util::Coordinate());
|
||||
return InternalExtractorEdge(
|
||||
MAX_OSM_NODEID, MAX_OSM_NODEID, WeightData(), DurationData(), util::Coordinate());
|
||||
}
|
||||
|
||||
static InternalExtractorEdge min_internal_value()
|
||||
|
@ -1,6 +1,9 @@
|
||||
#ifndef NODE_BASED_EDGE_HPP
|
||||
#define NODE_BASED_EDGE_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <tuple>
|
||||
|
||||
#include "extractor/class_data.hpp"
|
||||
#include "extractor/travel_mode.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
@ -12,68 +15,97 @@ namespace osrm
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
// Flags describing the class of the road. This data is used during creation of graphs/guidance
|
||||
// generation but is not available in annotation/navigation
|
||||
struct NodeBasedEdgeClassification
|
||||
{
|
||||
std::uint8_t forward : 1; // 1
|
||||
std::uint8_t backward : 1; // 1
|
||||
std::uint8_t is_split : 1; // 1
|
||||
std::uint8_t roundabout : 1; // 1
|
||||
std::uint8_t circular : 1; // 1
|
||||
std::uint8_t startpoint : 1; // 1
|
||||
std::uint8_t restricted : 1; // 1
|
||||
guidance::RoadClassification road_classification; // 16 2
|
||||
|
||||
NodeBasedEdgeClassification();
|
||||
|
||||
NodeBasedEdgeClassification(const bool forward,
|
||||
const bool backward,
|
||||
const bool is_split,
|
||||
const bool roundabout,
|
||||
const bool circular,
|
||||
const bool startpoint,
|
||||
const bool restricted,
|
||||
guidance::RoadClassification road_classification)
|
||||
: forward(forward), backward(backward), is_split(is_split), roundabout(roundabout),
|
||||
circular(circular), startpoint(startpoint), restricted(restricted),
|
||||
road_classification(road_classification)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator==(const NodeBasedEdgeClassification &other) const
|
||||
{
|
||||
return (road_classification == other.road_classification) && (forward == other.forward) &&
|
||||
(backward == other.backward) && (is_split) == (other.is_split) &&
|
||||
(roundabout == other.roundabout) && (circular == other.circular) &&
|
||||
(startpoint == other.startpoint) && (restricted == other.restricted);
|
||||
}
|
||||
};
|
||||
|
||||
// Annotative data, used in parts in guidance generation, in parts during navigation (classes) but
|
||||
// mostly for annotation of edges. The entry can be shared between multiple edges and usually
|
||||
// describes features present on OSM ways. This is the place to put specific data that you want to
|
||||
// see as part of the API output but that does not influence navigation
|
||||
struct NodeBasedEdgeAnnotation
|
||||
{
|
||||
NameID name_id; // 32 4
|
||||
LaneDescriptionID lane_description_id; // 16 2
|
||||
ClassData classes; // 8 1
|
||||
TravelMode travel_mode : 4; // 4
|
||||
bool is_left_hand_driving : 1; // 1
|
||||
|
||||
bool CanCombineWith(const NodeBasedEdgeAnnotation &other) const
|
||||
{
|
||||
return (std::tie(name_id, classes, travel_mode, is_left_hand_driving) ==
|
||||
std::tie(other.name_id, other.classes, other.travel_mode, is_left_hand_driving));
|
||||
}
|
||||
};
|
||||
|
||||
struct NodeBasedEdge
|
||||
{
|
||||
NodeBasedEdge();
|
||||
|
||||
NodeBasedEdge(NodeID source,
|
||||
NodeID target,
|
||||
NodeID name_id,
|
||||
EdgeWeight weight,
|
||||
EdgeDuration duration,
|
||||
bool forward,
|
||||
bool backward,
|
||||
bool roundabout,
|
||||
bool circular,
|
||||
bool startpoint,
|
||||
bool restricted,
|
||||
bool is_left_hand_driving,
|
||||
bool is_split,
|
||||
TravelMode travel_mode,
|
||||
ClassData classes,
|
||||
const LaneDescriptionID lane_description_id,
|
||||
guidance::RoadClassification road_classification);
|
||||
GeometryID geometry_id,
|
||||
AnnotationID annotation_data,
|
||||
NodeBasedEdgeClassification flags);
|
||||
|
||||
bool operator<(const NodeBasedEdge &other) const;
|
||||
|
||||
NodeID source; // 32 4
|
||||
NodeID target; // 32 4
|
||||
NodeID name_id; // 32 4
|
||||
EdgeWeight weight; // 32 4
|
||||
EdgeDuration duration; // 32 4
|
||||
std::uint8_t forward : 1; // 1
|
||||
std::uint8_t backward : 1; // 1
|
||||
std::uint8_t roundabout : 1; // 1
|
||||
std::uint8_t circular : 1; // 1
|
||||
std::uint8_t startpoint : 1; // 1
|
||||
std::uint8_t restricted : 1; // 1
|
||||
std::uint8_t is_left_hand_driving : 1; // 1
|
||||
std::uint8_t is_split : 1; // 1
|
||||
TravelMode travel_mode : 4; // 4
|
||||
ClassData classes; // 8 1
|
||||
LaneDescriptionID lane_description_id; // 16 2
|
||||
guidance::RoadClassification road_classification; // 16 2
|
||||
NodeID source; // 32 4
|
||||
NodeID target; // 32 4
|
||||
EdgeWeight weight; // 32 4
|
||||
EdgeDuration duration; // 32 4
|
||||
GeometryID geometry_id; // 32 4
|
||||
AnnotationID annotation_data; // 32 4
|
||||
NodeBasedEdgeClassification flags; // 32 4
|
||||
};
|
||||
|
||||
struct NodeBasedEdgeWithOSM : NodeBasedEdge
|
||||
{
|
||||
NodeBasedEdgeWithOSM();
|
||||
|
||||
NodeBasedEdgeWithOSM(OSMNodeID source,
|
||||
OSMNodeID target,
|
||||
NodeID name_id,
|
||||
EdgeWeight weight,
|
||||
EdgeDuration duration,
|
||||
bool forward,
|
||||
bool backward,
|
||||
bool roundabout,
|
||||
bool circular,
|
||||
bool startpoint,
|
||||
bool restricted,
|
||||
bool is_left_hand_driving,
|
||||
bool is_split,
|
||||
TravelMode travel_mode,
|
||||
ClassData classes,
|
||||
const LaneDescriptionID lane_description_id,
|
||||
guidance::RoadClassification road_classification);
|
||||
GeometryID geometry_id,
|
||||
AnnotationID annotation_data,
|
||||
NodeBasedEdgeClassification flags);
|
||||
|
||||
OSMNodeID osm_source_id;
|
||||
OSMNodeID osm_target_id;
|
||||
@ -81,36 +113,26 @@ struct NodeBasedEdgeWithOSM : NodeBasedEdge
|
||||
|
||||
// Impl.
|
||||
|
||||
inline NodeBasedEdgeClassification::NodeBasedEdgeClassification()
|
||||
: forward(false), backward(false), is_split(false), roundabout(false), circular(false),
|
||||
startpoint(false), restricted(false)
|
||||
{
|
||||
}
|
||||
|
||||
inline NodeBasedEdge::NodeBasedEdge()
|
||||
: source(SPECIAL_NODEID), target(SPECIAL_NODEID), name_id(0), weight(0), duration(0),
|
||||
forward(false), backward(false), roundabout(false), circular(false), startpoint(true),
|
||||
restricted(false), is_left_hand_driving(false), is_split(false),
|
||||
travel_mode(TRAVEL_MODE_INACCESSIBLE), lane_description_id(INVALID_LANE_DESCRIPTIONID)
|
||||
: source(SPECIAL_NODEID), target(SPECIAL_NODEID), weight(0), duration(0), annotation_data(-1)
|
||||
{
|
||||
}
|
||||
|
||||
inline NodeBasedEdge::NodeBasedEdge(NodeID source,
|
||||
NodeID target,
|
||||
NodeID name_id,
|
||||
EdgeWeight weight,
|
||||
EdgeDuration duration,
|
||||
bool forward,
|
||||
bool backward,
|
||||
bool roundabout,
|
||||
bool circular,
|
||||
bool startpoint,
|
||||
bool restricted,
|
||||
bool is_left_hand_driving,
|
||||
bool is_split,
|
||||
TravelMode travel_mode,
|
||||
ClassData classes,
|
||||
const LaneDescriptionID lane_description_id,
|
||||
guidance::RoadClassification road_classification)
|
||||
: source(source), target(target), name_id(name_id), weight(weight), duration(duration),
|
||||
forward(forward), backward(backward), roundabout(roundabout), circular(circular),
|
||||
startpoint(startpoint), restricted(restricted), is_left_hand_driving(is_left_hand_driving),
|
||||
is_split(is_split), travel_mode(travel_mode), classes(classes),
|
||||
lane_description_id(lane_description_id), road_classification(std::move(road_classification))
|
||||
GeometryID geometry_id,
|
||||
AnnotationID annotation_data,
|
||||
NodeBasedEdgeClassification flags)
|
||||
: source(source), target(target), weight(weight), duration(duration), geometry_id(geometry_id),
|
||||
annotation_data(annotation_data), flags(flags)
|
||||
{
|
||||
}
|
||||
|
||||
@ -122,7 +144,8 @@ inline bool NodeBasedEdge::operator<(const NodeBasedEdge &other) const
|
||||
{
|
||||
if (weight == other.weight)
|
||||
{
|
||||
return forward && backward && ((!other.forward) || (!other.backward));
|
||||
return flags.forward && flags.backward &&
|
||||
((!other.flags.forward) || (!other.flags.backward));
|
||||
}
|
||||
return weight < other.weight;
|
||||
}
|
||||
@ -133,42 +156,22 @@ inline bool NodeBasedEdge::operator<(const NodeBasedEdge &other) const
|
||||
|
||||
inline NodeBasedEdgeWithOSM::NodeBasedEdgeWithOSM(OSMNodeID source,
|
||||
OSMNodeID target,
|
||||
NodeID name_id,
|
||||
EdgeWeight weight,
|
||||
EdgeDuration duration,
|
||||
bool forward,
|
||||
bool backward,
|
||||
bool roundabout,
|
||||
bool circular,
|
||||
bool startpoint,
|
||||
bool restricted,
|
||||
bool is_left_hand_driving,
|
||||
bool is_split,
|
||||
TravelMode travel_mode,
|
||||
ClassData classes,
|
||||
const LaneDescriptionID lane_description_id,
|
||||
guidance::RoadClassification road_classification)
|
||||
: NodeBasedEdge(SPECIAL_NODEID,
|
||||
SPECIAL_NODEID,
|
||||
name_id,
|
||||
weight,
|
||||
duration,
|
||||
forward,
|
||||
backward,
|
||||
roundabout,
|
||||
circular,
|
||||
startpoint,
|
||||
restricted,
|
||||
is_left_hand_driving,
|
||||
is_split,
|
||||
travel_mode,
|
||||
classes,
|
||||
lane_description_id,
|
||||
std::move(road_classification)),
|
||||
GeometryID geometry_id,
|
||||
AnnotationID annotation_data,
|
||||
NodeBasedEdgeClassification flags)
|
||||
: NodeBasedEdge(
|
||||
SPECIAL_NODEID, SPECIAL_NODEID, weight, duration, geometry_id, annotation_data, flags),
|
||||
osm_source_id(std::move(source)), osm_target_id(std::move(target))
|
||||
{
|
||||
}
|
||||
|
||||
inline NodeBasedEdgeWithOSM::NodeBasedEdgeWithOSM()
|
||||
: osm_source_id(MIN_OSM_NODEID), osm_target_id(MIN_OSM_NODEID)
|
||||
{
|
||||
}
|
||||
|
||||
static_assert(sizeof(extractor::NodeBasedEdge) == 28,
|
||||
"Size of extractor::NodeBasedEdge type is "
|
||||
"bigger than expected. This will influence "
|
||||
|
101
include/extractor/node_based_graph_factory.hpp
Normal file
101
include/extractor/node_based_graph_factory.hpp
Normal file
@ -0,0 +1,101 @@
|
||||
#ifndef OSRM_EXTRACTOR_NODE_BASED_GRAPH_FACTORY_HPP_
|
||||
#define OSRM_EXTRACTOR_NODE_BASED_GRAPH_FACTORY_HPP_
|
||||
|
||||
#include "extractor/compressed_edge_container.hpp"
|
||||
#include "extractor/node_based_edge.hpp"
|
||||
#include "extractor/node_data_container.hpp"
|
||||
#include "extractor/packed_osm_ids.hpp"
|
||||
#include "extractor/scripting_environment.hpp"
|
||||
|
||||
#include "util/coordinate.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
// Turn the output of the extraction process into a graph that represents junctions as nodes and
|
||||
// ways as edges between these nodes. The graph forms the further input for OSRMs creation of the
|
||||
// edge-based graph and is also the basic concept for annotating paths. All information from ways
|
||||
// that is transferred into the API response is connected to the edges of the node-based graph.
|
||||
//
|
||||
// The input to the graph creation is the set of edges, traffic signals, barriers, meta-data,...
|
||||
// which is generated during extraction and stored within the extraction containers.
|
||||
class NodeBasedGraphFactory
|
||||
{
|
||||
public:
|
||||
// The node-based graph factory loads the *.osrm file and transforms the data within into the
|
||||
// node-based graph to represent the OSM network. This includes geometry compression, annotation
|
||||
// data optimisation and many other aspects. After this step, the edge-based graph factory can
|
||||
// turn the graph into the routing graph to be used with the navigation algorithms.
|
||||
NodeBasedGraphFactory(const boost::filesystem::path &input_file,
|
||||
ScriptingEnvironment &scripting_environment,
|
||||
std::vector<TurnRestriction> &turn_restrictions,
|
||||
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions);
|
||||
|
||||
auto const &GetGraph() const { return compressed_output_graph; }
|
||||
auto const &GetBarriers() const { return barriers; }
|
||||
auto const &GetTrafficSignals() const { return traffic_signals; }
|
||||
auto &GetCompressedEdges() { return compressed_edge_container; }
|
||||
auto &GetCoordinates() { return coordinates; }
|
||||
auto &GetAnnotationData() { return annotation_data; }
|
||||
auto &GetOsmNodes() { return osm_node_ids; }
|
||||
|
||||
// to reduce the memory footprint, the node-based graph factory allows releasing memory after it
|
||||
// might have been used for the last time:
|
||||
void ReleaseOsmNodes();
|
||||
|
||||
private:
|
||||
// Get the information from the *.osrm file (direct product of the extractor callback/extraction
|
||||
// containers) and prepare the graph creation process
|
||||
void LoadDataFromFile(const boost::filesystem::path &input_file);
|
||||
|
||||
// Compress the node-based graph into a compact representation of itself. This removes storing a
|
||||
// single edge for every part of the geometry and might also combine meta-data for multiple
|
||||
// edges into a single representative form
|
||||
void Compress(ScriptingEnvironment &scripting_environment,
|
||||
std::vector<TurnRestriction> &turn_restrictions,
|
||||
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions);
|
||||
|
||||
// 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
|
||||
// geometry around
|
||||
void CompressGeometry();
|
||||
|
||||
// After graph compression, some of the annotation entries might not be referenced anymore. We
|
||||
// compress the annotation data by relabeling the node-based graph references and removing all
|
||||
// unreferenced entries
|
||||
void CompressAnnotationData();
|
||||
|
||||
// After produce, this will contain a compresse version of the node-based graph
|
||||
util::NodeBasedDynamicGraph compressed_output_graph;
|
||||
// To store the meta-data for the graph that is purely annotative / not used for the navigation
|
||||
// itself. Since the edges of a node-based graph form the nodes of the edge based graphs, we
|
||||
// transform this data into the EdgeBasedNodeDataContainer as output storage.
|
||||
std::vector<NodeBasedEdgeAnnotation> annotation_data;
|
||||
|
||||
// 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;
|
||||
|
||||
// data to keep in sync with the node-based graph
|
||||
extractor::PackedOSMIDs osm_node_ids;
|
||||
|
||||
// for the compressed geometry
|
||||
extractor::CompressedEdgeContainer compressed_edge_container;
|
||||
};
|
||||
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
||||
#endif // OSRM_EXTRACTOR_NODE_BASED_GRAPH_FACTORY_HPP_
|
@ -2,6 +2,8 @@
|
||||
#define OSRM_EXTRACTOR_NODE_DATA_CONTAINER_HPP
|
||||
|
||||
#include "extractor/class_data.hpp"
|
||||
#include "extractor/edge_based_node.hpp"
|
||||
#include "extractor/node_based_edge.hpp"
|
||||
#include "extractor/travel_mode.hpp"
|
||||
|
||||
#include "storage/io_fwd.hpp"
|
||||
@ -15,6 +17,10 @@ namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
class Extractor;
|
||||
class EdgeBasedGraphFactory;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <storage::Ownership Ownership> class EdgeBasedNodeDataContainerImpl;
|
||||
@ -38,63 +44,47 @@ template <storage::Ownership Ownership> class EdgeBasedNodeDataContainerImpl
|
||||
template <typename T> using Vector = util::ViewOrVector<T, Ownership>;
|
||||
using TravelMode = extractor::TravelMode;
|
||||
|
||||
// to fill in data on edgeBasedNodes
|
||||
friend class osrm::extractor::Extractor;
|
||||
friend class osrm::extractor::EdgeBasedGraphFactory;
|
||||
|
||||
public:
|
||||
EdgeBasedNodeDataContainerImpl() = default;
|
||||
|
||||
EdgeBasedNodeDataContainerImpl(std::size_t size)
|
||||
: geometry_ids(size), name_ids(size), component_ids(size), travel_modes(size),
|
||||
classes(size), is_left_hand_driving(size)
|
||||
EdgeBasedNodeDataContainerImpl(const NodeID number_of_edge_based_nodes,
|
||||
const AnnotationID number_of_annotations)
|
||||
: nodes(number_of_edge_based_nodes), annotation_data(number_of_annotations)
|
||||
{
|
||||
}
|
||||
|
||||
EdgeBasedNodeDataContainerImpl(Vector<GeometryID> geometry_ids,
|
||||
Vector<NameID> name_ids,
|
||||
Vector<ComponentID> component_ids,
|
||||
Vector<TravelMode> travel_modes,
|
||||
Vector<ClassData> classes,
|
||||
Vector<bool> is_left_hand_driving)
|
||||
: geometry_ids(std::move(geometry_ids)), name_ids(std::move(name_ids)),
|
||||
component_ids(std::move(component_ids)), travel_modes(std::move(travel_modes)),
|
||||
classes(std::move(classes)), is_left_hand_driving(std::move(is_left_hand_driving))
|
||||
EdgeBasedNodeDataContainerImpl(Vector<EdgeBasedNode> nodes,
|
||||
Vector<NodeBasedEdgeAnnotation> annotation_data)
|
||||
: nodes(std::move(nodes)), annotation_data(std::move(annotation_data))
|
||||
{
|
||||
}
|
||||
|
||||
GeometryID GetGeometryID(const NodeID node_id) const { return geometry_ids[node_id]; }
|
||||
GeometryID GetGeometryID(const NodeID node_id) const { return nodes[node_id].geometry_id; }
|
||||
|
||||
TravelMode GetTravelMode(const NodeID node_id) const { return travel_modes[node_id]; }
|
||||
ComponentID GetComponentID(const NodeID node_id) const { return nodes[node_id].component_id; }
|
||||
|
||||
NameID GetNameID(const NodeID node_id) const { return name_ids[node_id]; }
|
||||
|
||||
ComponentID GetComponentID(const NodeID node_id) const { return component_ids[node_id]; }
|
||||
|
||||
ClassData GetClassData(const NodeID node_id) const { return classes[node_id]; }
|
||||
|
||||
ClassData IsLeftHandDriving(const NodeID node_id) const
|
||||
TravelMode GetTravelMode(const NodeID node_id) const
|
||||
{
|
||||
return is_left_hand_driving[node_id];
|
||||
return annotation_data[nodes[node_id].annotation_id].travel_mode;
|
||||
}
|
||||
|
||||
// Used by EdgeBasedGraphFactory to fill data structure
|
||||
template <typename = std::enable_if<Ownership == storage::Ownership::Container>>
|
||||
void SetData(NodeID node_id,
|
||||
GeometryID geometry_id,
|
||||
NameID name_id,
|
||||
TravelMode travel_mode,
|
||||
ClassData class_data,
|
||||
bool is_left_hand_driving_flag)
|
||||
bool IsLeftHandDriving(const NodeID node_id) const
|
||||
{
|
||||
geometry_ids[node_id] = geometry_id;
|
||||
name_ids[node_id] = name_id;
|
||||
travel_modes[node_id] = travel_mode;
|
||||
classes[node_id] = class_data;
|
||||
is_left_hand_driving[node_id] = is_left_hand_driving_flag;
|
||||
return annotation_data[nodes[node_id].annotation_id].is_left_hand_driving;
|
||||
}
|
||||
|
||||
// Used by EdgeBasedGraphFactory to fill data structure
|
||||
template <typename = std::enable_if<Ownership == storage::Ownership::Container>>
|
||||
void SetComponentID(NodeID node_id, ComponentID component_id)
|
||||
NameID GetNameID(const NodeID node_id) const
|
||||
{
|
||||
component_ids[node_id] = component_id;
|
||||
return annotation_data[nodes[node_id].annotation_id].name_id;
|
||||
}
|
||||
|
||||
ClassData GetClassData(const NodeID node_id) const
|
||||
{
|
||||
return annotation_data[nodes[node_id].annotation_id].classes;
|
||||
}
|
||||
|
||||
friend void serialization::read<Ownership>(storage::io::FileReader &reader,
|
||||
@ -106,33 +96,30 @@ template <storage::Ownership Ownership> class EdgeBasedNodeDataContainerImpl
|
||||
template <typename = std::enable_if<Ownership == storage::Ownership::Container>>
|
||||
void Renumber(const std::vector<std::uint32_t> &permutation)
|
||||
{
|
||||
util::inplacePermutation(geometry_ids.begin(), geometry_ids.end(), permutation);
|
||||
util::inplacePermutation(name_ids.begin(), name_ids.end(), permutation);
|
||||
util::inplacePermutation(component_ids.begin(), component_ids.end(), permutation);
|
||||
util::inplacePermutation(travel_modes.begin(), travel_modes.end(), permutation);
|
||||
util::inplacePermutation(classes.begin(), classes.end(), permutation);
|
||||
util::inplacePermutation(
|
||||
is_left_hand_driving.begin(), is_left_hand_driving.end(), permutation);
|
||||
util::inplacePermutation(nodes.begin(), nodes.end(), permutation);
|
||||
}
|
||||
|
||||
// all containers have the exact same size
|
||||
std::size_t Size() const
|
||||
NodeID NumberOfNodes() const { return nodes.size(); }
|
||||
|
||||
// the number of annotations differs from the number of nodes, since annotations can be shared
|
||||
// between a large set of nodes
|
||||
AnnotationID NumberOfAnnotations() const { return annotation_data.size(); }
|
||||
|
||||
EdgeBasedNode &GetNode(const NodeID node_id) { return nodes[node_id]; }
|
||||
EdgeBasedNode const &GetNode(const NodeID node_id) const { return nodes[node_id]; }
|
||||
|
||||
NodeBasedEdgeAnnotation &GetAnnotation(const AnnotationID annotation)
|
||||
{
|
||||
BOOST_ASSERT(geometry_ids.size() == name_ids.size());
|
||||
BOOST_ASSERT(geometry_ids.size() == component_ids.size());
|
||||
BOOST_ASSERT(geometry_ids.size() == travel_modes.size());
|
||||
BOOST_ASSERT(geometry_ids.size() == classes.size());
|
||||
BOOST_ASSERT(geometry_ids.size() == is_left_hand_driving.size());
|
||||
return geometry_ids.size();
|
||||
return annotation_data[annotation];
|
||||
}
|
||||
NodeBasedEdgeAnnotation const &GetAnnotation(const AnnotationID annotation) const
|
||||
{
|
||||
return annotation_data[annotation];
|
||||
}
|
||||
|
||||
private:
|
||||
Vector<GeometryID> geometry_ids;
|
||||
Vector<NameID> name_ids;
|
||||
Vector<ComponentID> component_ids;
|
||||
Vector<TravelMode> travel_modes;
|
||||
Vector<ClassData> classes;
|
||||
Vector<bool> is_left_hand_driving;
|
||||
Vector<EdgeBasedNode> nodes;
|
||||
Vector<NodeBasedEdgeAnnotation> annotation_data;
|
||||
};
|
||||
}
|
||||
|
||||
@ -141,7 +128,7 @@ using EdgeBasedNodeDataExternalContainer =
|
||||
using EdgeBasedNodeDataContainer =
|
||||
detail::EdgeBasedNodeDataContainerImpl<storage::Ownership::Container>;
|
||||
using EdgeBasedNodeDataView = detail::EdgeBasedNodeDataContainerImpl<storage::Ownership::View>;
|
||||
}
|
||||
}
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
||||
#endif
|
||||
|
@ -96,7 +96,7 @@ class Sol2ScriptingEnvironment final : public ScriptingEnvironment
|
||||
std::vector<std::pair<const osmium::Relation &, ExtractionRelation>> &resulting_relations,
|
||||
std::vector<InputConditionalTurnRestriction> &resulting_restrictions) override;
|
||||
|
||||
bool HasLocationDependentData() const { return !location_dependent_data.empty(); }
|
||||
bool HasLocationDependentData() const override { return !location_dependent_data.empty(); }
|
||||
|
||||
private:
|
||||
LuaScriptingContext &GetSol2Context();
|
||||
|
@ -120,24 +120,22 @@ template <storage::Ownership Ownership>
|
||||
inline void read(storage::io::FileReader &reader,
|
||||
detail::EdgeBasedNodeDataContainerImpl<Ownership> &node_data_container)
|
||||
{
|
||||
storage::serialization::read(reader, node_data_container.geometry_ids);
|
||||
storage::serialization::read(reader, node_data_container.name_ids);
|
||||
storage::serialization::read(reader, node_data_container.component_ids);
|
||||
storage::serialization::read(reader, node_data_container.travel_modes);
|
||||
storage::serialization::read(reader, node_data_container.classes);
|
||||
storage::serialization::read(reader, node_data_container.is_left_hand_driving);
|
||||
// read header (separate sizes for both vectors)
|
||||
reader.ReadElementCount64();
|
||||
reader.ReadElementCount64();
|
||||
// read actual data
|
||||
storage::serialization::read(reader, node_data_container.nodes);
|
||||
storage::serialization::read(reader, node_data_container.annotation_data);
|
||||
}
|
||||
|
||||
template <storage::Ownership Ownership>
|
||||
inline void write(storage::io::FileWriter &writer,
|
||||
const detail::EdgeBasedNodeDataContainerImpl<Ownership> &node_data_container)
|
||||
{
|
||||
storage::serialization::write(writer, node_data_container.geometry_ids);
|
||||
storage::serialization::write(writer, node_data_container.name_ids);
|
||||
storage::serialization::write(writer, node_data_container.component_ids);
|
||||
storage::serialization::write(writer, node_data_container.travel_modes);
|
||||
storage::serialization::write(writer, node_data_container.classes);
|
||||
storage::serialization::write(writer, node_data_container.is_left_hand_driving);
|
||||
writer.WriteElementCount64(node_data_container.NumberOfNodes());
|
||||
writer.WriteElementCount64(node_data_container.NumberOfAnnotations());
|
||||
storage::serialization::write(writer, node_data_container.nodes);
|
||||
storage::serialization::write(writer, node_data_container.annotation_data);
|
||||
}
|
||||
|
||||
inline void read(storage::io::FileReader &reader, NodeRestriction &restriction)
|
||||
|
@ -184,14 +184,14 @@ graphToEdges(const DynamicEdgeBasedGraph &edge_based_graph)
|
||||
|
||||
inline DynamicEdgeBasedGraph LoadEdgeBasedGraph(const boost::filesystem::path &path)
|
||||
{
|
||||
EdgeID max_node_id;
|
||||
EdgeID number_of_edge_based_nodes;
|
||||
std::vector<extractor::EdgeBasedEdge> edges;
|
||||
extractor::files::readEdgeBasedGraph(path, max_node_id, edges);
|
||||
extractor::files::readEdgeBasedGraph(path, number_of_edge_based_nodes, edges);
|
||||
|
||||
auto directed = splitBidirectionalEdges(edges);
|
||||
auto tidied = prepareEdgesForUsageInGraph<DynamicEdgeBasedGraphEdge>(std::move(directed));
|
||||
|
||||
return DynamicEdgeBasedGraph(max_node_id + 1, std::move(tidied));
|
||||
return DynamicEdgeBasedGraph(number_of_edge_based_nodes, std::move(tidied));
|
||||
}
|
||||
|
||||
} // ns partition
|
||||
|
@ -19,12 +19,8 @@ namespace storage
|
||||
const constexpr char CANARY[4] = {'O', 'S', 'R', 'M'};
|
||||
|
||||
const constexpr char *block_id_to_name[] = {"NAME_CHAR_DATA",
|
||||
"GEOMETRY_ID_LIST",
|
||||
"NAME_ID_LIST",
|
||||
"COMPONENT_ID_LIST",
|
||||
"TRAVEL_MODE_LIST",
|
||||
"CLASSES_LIST",
|
||||
"IS_LEFT_HAND_DRIVING_LIST",
|
||||
"EDGE_BASED_NODE_DATA",
|
||||
"ANNOTATION_DATA",
|
||||
"CH_GRAPH_NODE_LIST",
|
||||
"CH_GRAPH_EDGE_LIST",
|
||||
"CH_EDGE_FILTER_0",
|
||||
@ -107,12 +103,8 @@ struct DataLayout
|
||||
enum BlockID
|
||||
{
|
||||
NAME_CHAR_DATA = 0,
|
||||
GEOMETRY_ID_LIST,
|
||||
NAME_ID_LIST,
|
||||
COMPONENT_ID_LIST,
|
||||
TRAVEL_MODE_LIST,
|
||||
CLASSES_LIST,
|
||||
IS_LEFT_HAND_DRIVING_LIST,
|
||||
EDGE_BASED_NODE_DATA_LIST,
|
||||
ANNOTATION_DATA_LIST,
|
||||
CH_GRAPH_NODE_LIST,
|
||||
CH_GRAPH_EDGE_LIST,
|
||||
CH_EDGE_FILTER_0,
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include "extractor/guidance/intersection.hpp"
|
||||
#include "extractor/guidance/turn_lane_data.hpp"
|
||||
#include "extractor/node_data_container.hpp"
|
||||
#include "extractor/query_node.hpp"
|
||||
#include "engine/guidance/route_step.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
@ -77,7 +78,8 @@ inline void print(const NodeBasedDynamicGraph &node_based_graph,
|
||||
for (const auto &road : intersection)
|
||||
{
|
||||
std::cout << "\t" << toString(road) << "\n";
|
||||
std::cout << "\t\t" << node_based_graph.GetEdgeData(road.eid).road_classification.ToString()
|
||||
std::cout << "\t\t"
|
||||
<< node_based_graph.GetEdgeData(road.eid).flags.road_classification.ToString()
|
||||
<< "\n";
|
||||
}
|
||||
std::cout << std::flush;
|
||||
|
@ -223,6 +223,7 @@ template <typename EdgeDataT> class DynamicGraph
|
||||
unsigned GetNumberOfNodes() const { return number_of_nodes; }
|
||||
|
||||
unsigned GetNumberOfEdges() const { return number_of_edges; }
|
||||
auto GetEdgeCapacity() const { return edge_list.size(); }
|
||||
|
||||
unsigned GetOutDegree(const NodeIterator n) const { return node_array[n].edges; }
|
||||
|
||||
|
@ -77,7 +77,7 @@ NodeID loadNodesFromFile(storage::io::FileReader &file_reader,
|
||||
/**
|
||||
* Reads a .osrm file and produces the edges.
|
||||
*/
|
||||
inline NodeID loadEdgesFromFile(storage::io::FileReader &file_reader,
|
||||
inline EdgeID loadEdgesFromFile(storage::io::FileReader &file_reader,
|
||||
std::vector<extractor::NodeBasedEdge> &edge_list)
|
||||
{
|
||||
auto number_of_edges = file_reader.ReadElementCount64();
|
||||
@ -104,8 +104,7 @@ inline NodeID loadEdgesFromFile(storage::io::FileReader &file_reader,
|
||||
const auto &prev_edge = edge_list[i - 1];
|
||||
|
||||
BOOST_ASSERT_MSG(edge.weight > 0, "loaded null weight");
|
||||
BOOST_ASSERT_MSG(edge.forward, "edge must be oriented in forward direction");
|
||||
BOOST_ASSERT_MSG(edge.travel_mode != TRAVEL_MODE_INACCESSIBLE, "loaded non-accessible");
|
||||
BOOST_ASSERT_MSG(edge.flags.forward, "edge must be oriented in forward direction");
|
||||
|
||||
BOOST_ASSERT_MSG(edge.source != edge.target, "loaded edges contain a loop");
|
||||
BOOST_ASSERT_MSG(edge.source != prev_edge.source || edge.target != prev_edge.target,
|
||||
@ -117,6 +116,15 @@ inline NodeID loadEdgesFromFile(storage::io::FileReader &file_reader,
|
||||
|
||||
return number_of_edges;
|
||||
}
|
||||
|
||||
inline EdgeID loadAnnotationData(storage::io::FileReader &file_reader,
|
||||
std::vector<extractor::NodeBasedEdgeAnnotation> &metadata)
|
||||
{
|
||||
auto const meta_data_count = file_reader.ReadElementCount64();
|
||||
metadata.resize(meta_data_count);
|
||||
file_reader.ReadInto(metadata.data(), meta_data_count);
|
||||
return meta_data_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,7 +74,7 @@ std::vector<OutputEdgeT> directedEdgesFromCompressed(const std::vector<InputEdge
|
||||
for (const auto &input_edge : input_edge_list)
|
||||
{
|
||||
// edges that are not forward get converted by flipping the end points
|
||||
BOOST_ASSERT(input_edge.forward);
|
||||
BOOST_ASSERT(input_edge.flags.forward);
|
||||
|
||||
edge.source = input_edge.source;
|
||||
edge.target = input_edge.target;
|
||||
@ -86,10 +86,10 @@ std::vector<OutputEdgeT> directedEdgesFromCompressed(const std::vector<InputEdge
|
||||
|
||||
output_edge_list.push_back(edge);
|
||||
|
||||
if (!input_edge.is_split)
|
||||
if (!input_edge.flags.is_split)
|
||||
{
|
||||
std::swap(edge.source, edge.target);
|
||||
edge.data.reversed = !input_edge.backward;
|
||||
edge.data.reversed = !input_edge.flags.backward;
|
||||
output_edge_list.push_back(edge);
|
||||
}
|
||||
}
|
||||
|
@ -4,12 +4,14 @@
|
||||
#include "extractor/class_data.hpp"
|
||||
#include "extractor/guidance/road_classification.hpp"
|
||||
#include "extractor/node_based_edge.hpp"
|
||||
#include "extractor/node_data_container.hpp"
|
||||
#include "util/dynamic_graph.hpp"
|
||||
#include "util/graph_utils.hpp"
|
||||
|
||||
#include <tbb/parallel_sort.h>
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
@ -19,70 +21,57 @@ namespace util
|
||||
struct NodeBasedEdgeData
|
||||
{
|
||||
NodeBasedEdgeData()
|
||||
: weight(INVALID_EDGE_WEIGHT), duration(INVALID_EDGE_WEIGHT), edge_id(SPECIAL_NODEID),
|
||||
name_id(std::numeric_limits<unsigned>::max()), reversed(false), roundabout(false),
|
||||
circular(false), startpoint(false), restricted(false), is_left_hand_driving(false),
|
||||
travel_mode(TRAVEL_MODE_INACCESSIBLE), lane_description_id(INVALID_LANE_DESCRIPTIONID)
|
||||
: weight(INVALID_EDGE_WEIGHT), duration(INVALID_EDGE_WEIGHT), geometry_id({0, false}),
|
||||
reversed(false), annotation_data(-1)
|
||||
{
|
||||
}
|
||||
|
||||
NodeBasedEdgeData(EdgeWeight weight,
|
||||
EdgeWeight duration,
|
||||
unsigned edge_id,
|
||||
unsigned name_id,
|
||||
GeometryID geometry_id,
|
||||
bool reversed,
|
||||
bool roundabout,
|
||||
bool circular,
|
||||
bool startpoint,
|
||||
bool restricted,
|
||||
bool is_left_hand_driving,
|
||||
extractor::TravelMode travel_mode,
|
||||
extractor::ClassData classes,
|
||||
const LaneDescriptionID lane_description_id)
|
||||
: weight(weight), duration(duration), edge_id(edge_id), name_id(name_id),
|
||||
reversed(reversed), roundabout(roundabout), circular(circular), startpoint(startpoint),
|
||||
restricted(restricted), is_left_hand_driving(is_left_hand_driving),
|
||||
travel_mode(travel_mode), classes(classes), lane_description_id(lane_description_id)
|
||||
extractor::NodeBasedEdgeClassification flags,
|
||||
AnnotationID annotation_data)
|
||||
: weight(weight), duration(duration), geometry_id(geometry_id), reversed(reversed),
|
||||
flags(flags), annotation_data(annotation_data)
|
||||
{
|
||||
}
|
||||
|
||||
EdgeWeight weight;
|
||||
EdgeWeight duration;
|
||||
unsigned edge_id;
|
||||
unsigned name_id;
|
||||
GeometryID geometry_id;
|
||||
bool reversed : 1;
|
||||
bool roundabout : 1;
|
||||
bool circular : 1;
|
||||
bool startpoint : 1;
|
||||
bool restricted : 1;
|
||||
bool is_left_hand_driving : 1;
|
||||
extractor::TravelMode travel_mode : 4;
|
||||
extractor::ClassData classes;
|
||||
LaneDescriptionID lane_description_id;
|
||||
extractor::guidance::RoadClassification road_classification;
|
||||
|
||||
bool IsCompatibleTo(const NodeBasedEdgeData &other) const
|
||||
{
|
||||
return (reversed == other.reversed) && (roundabout == other.roundabout) &&
|
||||
(circular == other.circular) && (startpoint == other.startpoint) &&
|
||||
(travel_mode == other.travel_mode) && (classes == other.classes) &&
|
||||
(road_classification == other.road_classification) &&
|
||||
(restricted == other.restricted) &&
|
||||
(is_left_hand_driving == other.is_left_hand_driving);
|
||||
}
|
||||
|
||||
bool CanCombineWith(const NodeBasedEdgeData &other) const
|
||||
{
|
||||
return (name_id == other.name_id) && IsCompatibleTo(other);
|
||||
}
|
||||
extractor::NodeBasedEdgeClassification flags;
|
||||
AnnotationID annotation_data;
|
||||
};
|
||||
|
||||
// Check if two edge data elements can be compressed into a single edge (i.e. match in terms of
|
||||
// their meta-data).
|
||||
inline bool CanBeCompressed(const NodeBasedEdgeData &lhs,
|
||||
const NodeBasedEdgeData &rhs,
|
||||
const extractor::EdgeBasedNodeDataContainer &node_data_container)
|
||||
{
|
||||
if (!(lhs.flags == rhs.flags))
|
||||
return false;
|
||||
|
||||
auto const &lhs_annotation = node_data_container.GetAnnotation(lhs.annotation_data);
|
||||
auto const &rhs_annotation = node_data_container.GetAnnotation(rhs.annotation_data);
|
||||
|
||||
if (lhs_annotation.is_left_hand_driving != rhs_annotation.is_left_hand_driving)
|
||||
return false;
|
||||
|
||||
if (lhs_annotation.travel_mode != rhs_annotation.travel_mode)
|
||||
return false;
|
||||
|
||||
return lhs_annotation.classes == rhs_annotation.classes;
|
||||
}
|
||||
|
||||
using NodeBasedDynamicGraph = DynamicGraph<NodeBasedEdgeData>;
|
||||
|
||||
/// Factory method to create NodeBasedDynamicGraph from NodeBasedEdges
|
||||
/// Since DynamicGraph expects directed edges, we need to insert
|
||||
/// two edges for undirected edges.
|
||||
inline std::shared_ptr<NodeBasedDynamicGraph>
|
||||
inline NodeBasedDynamicGraph
|
||||
NodeBasedDynamicGraphFromEdges(NodeID number_of_nodes,
|
||||
const std::vector<extractor::NodeBasedEdge> &input_edge_list)
|
||||
{
|
||||
@ -92,16 +81,8 @@ NodeBasedDynamicGraphFromEdges(NodeID number_of_nodes,
|
||||
const extractor::NodeBasedEdge &input_edge) {
|
||||
output_edge.data.weight = input_edge.weight;
|
||||
output_edge.data.duration = input_edge.duration;
|
||||
output_edge.data.roundabout = input_edge.roundabout;
|
||||
output_edge.data.circular = input_edge.circular;
|
||||
output_edge.data.name_id = input_edge.name_id;
|
||||
output_edge.data.travel_mode = input_edge.travel_mode;
|
||||
output_edge.data.classes = input_edge.classes;
|
||||
output_edge.data.startpoint = input_edge.startpoint;
|
||||
output_edge.data.restricted = input_edge.restricted;
|
||||
output_edge.data.is_left_hand_driving = input_edge.is_left_hand_driving;
|
||||
output_edge.data.road_classification = input_edge.road_classification;
|
||||
output_edge.data.lane_description_id = input_edge.lane_description_id;
|
||||
output_edge.data.flags = input_edge.flags;
|
||||
output_edge.data.annotation_data = input_edge.annotation_data;
|
||||
|
||||
BOOST_ASSERT(output_edge.data.weight > 0);
|
||||
BOOST_ASSERT(output_edge.data.duration > 0);
|
||||
@ -109,9 +90,7 @@ NodeBasedDynamicGraphFromEdges(NodeID number_of_nodes,
|
||||
|
||||
tbb::parallel_sort(edges_list.begin(), edges_list.end());
|
||||
|
||||
auto graph = std::make_shared<NodeBasedDynamicGraph>(number_of_nodes, edges_list);
|
||||
|
||||
return graph;
|
||||
return NodeBasedDynamicGraph(number_of_nodes, edges_list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -450,6 +450,11 @@ template <typename T, std::size_t Bits, storage::Ownership Ownership> class Pack
|
||||
|
||||
friend void serialization::write<T, Bits, Ownership>(storage::io::FileWriter &writer,
|
||||
const PackedVector &vec);
|
||||
inline void swap(PackedVector &other) noexcept
|
||||
{
|
||||
std::swap(vec, other.vec);
|
||||
std::swap(num_elements, other.num_elements);
|
||||
}
|
||||
|
||||
private:
|
||||
void allocate_blocks(std::size_t num_blocks)
|
||||
|
@ -72,6 +72,7 @@ static const OSMWayID MIN_OSM_WAYID = OSMWayID{std::numeric_limits<OSMWayID::val
|
||||
using NodeID = std::uint32_t;
|
||||
using EdgeID = std::uint32_t;
|
||||
using NameID = std::uint32_t;
|
||||
using AnnotationID = std::uint32_t;
|
||||
using EdgeWeight = std::int32_t;
|
||||
using EdgeDuration = std::int32_t;
|
||||
using SegmentWeight = std::uint32_t;
|
||||
|
@ -68,7 +68,8 @@ int Contractor::Run()
|
||||
std::vector<extractor::EdgeBasedEdge> edge_based_edge_list;
|
||||
|
||||
updater::Updater updater(config.updater_config);
|
||||
EdgeID max_edge_id = updater.LoadAndUpdateEdgeExpandedGraph(edge_based_edge_list, node_weights);
|
||||
EdgeID number_of_edge_based_nodes =
|
||||
updater.LoadAndUpdateEdgeExpandedGraph(edge_based_edge_list, node_weights);
|
||||
|
||||
// Contracting the edge-expanded graph
|
||||
|
||||
@ -82,7 +83,8 @@ int Contractor::Run()
|
||||
extractor::ProfileProperties properties;
|
||||
extractor::files::readProfileProperties(config.GetPath(".osrm.properties"), properties);
|
||||
|
||||
node_filters = util::excludeFlagsToNodeFilter(max_edge_id + 1, node_data, properties);
|
||||
node_filters =
|
||||
util::excludeFlagsToNodeFilter(number_of_edge_based_nodes, node_data, properties);
|
||||
}
|
||||
|
||||
RangebasedCRC32 crc32_calculator;
|
||||
@ -91,11 +93,11 @@ int Contractor::Run()
|
||||
QueryGraph query_graph;
|
||||
std::vector<std::vector<bool>> edge_filters;
|
||||
std::vector<std::vector<bool>> cores;
|
||||
std::tie(query_graph, edge_filters, cores) =
|
||||
contractExcludableGraph(toContractorGraph(max_edge_id + 1, std::move(edge_based_edge_list)),
|
||||
std::move(node_weights),
|
||||
std::move(node_filters),
|
||||
config.core_factor);
|
||||
std::tie(query_graph, edge_filters, cores) = contractExcludableGraph(
|
||||
toContractorGraph(number_of_edge_based_nodes, std::move(edge_based_edge_list)),
|
||||
std::move(node_weights),
|
||||
std::move(node_filters),
|
||||
config.core_factor);
|
||||
TIMER_STOP(contraction);
|
||||
util::Log() << "Contracted graph has " << query_graph.GetNumberOfEdges() << " edges.";
|
||||
util::Log() << "Contraction took " << TIMER_SEC(contraction) << " sec";
|
||||
|
@ -264,6 +264,9 @@ void CompressedEdgeContainer::InitializeBothwayVector()
|
||||
|
||||
unsigned CompressedEdgeContainer::ZipEdges(const EdgeID f_edge_id, const EdgeID r_edge_id)
|
||||
{
|
||||
if (!segment_data)
|
||||
InitializeBothwayVector();
|
||||
|
||||
const auto &forward_bucket = GetBucketReference(f_edge_id);
|
||||
const auto &reverse_bucket = GetBucketReference(r_edge_id);
|
||||
|
||||
|
@ -60,19 +60,18 @@ namespace extractor
|
||||
|
||||
// Configuration to find representative candidate for turn angle calculations
|
||||
EdgeBasedGraphFactory::EdgeBasedGraphFactory(
|
||||
std::shared_ptr<util::NodeBasedDynamicGraph> node_based_graph,
|
||||
CompressedEdgeContainer &compressed_edge_container,
|
||||
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
EdgeBasedNodeDataContainer &node_data_container,
|
||||
const CompressedEdgeContainer &compressed_edge_container,
|
||||
const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const std::unordered_set<NodeID> &traffic_lights,
|
||||
const std::vector<util::Coordinate> &coordinates,
|
||||
const extractor::PackedOSMIDs &osm_node_ids,
|
||||
ProfileProperties profile_properties,
|
||||
const util::NameTable &name_table,
|
||||
guidance::LaneDescriptionMap &lane_description_map)
|
||||
: m_number_of_edge_based_nodes(0), m_coordinates(coordinates), m_osm_node_ids(osm_node_ids),
|
||||
m_node_based_graph(std::move(node_based_graph)), m_barrier_nodes(barrier_nodes),
|
||||
m_traffic_lights(traffic_lights), m_compressed_edge_container(compressed_edge_container),
|
||||
profile_properties(std::move(profile_properties)), name_table(name_table),
|
||||
: m_edge_based_node_container(node_data_container), m_number_of_edge_based_nodes(0),
|
||||
m_coordinates(coordinates), m_node_based_graph(std::move(node_based_graph)),
|
||||
m_barrier_nodes(barrier_nodes), m_traffic_lights(traffic_lights),
|
||||
m_compressed_edge_container(compressed_edge_container), name_table(name_table),
|
||||
lane_description_map(lane_description_map)
|
||||
{
|
||||
}
|
||||
@ -85,12 +84,6 @@ void EdgeBasedGraphFactory::GetEdgeBasedEdges(
|
||||
swap(m_edge_based_edge_list, output_edge_list);
|
||||
}
|
||||
|
||||
void EdgeBasedGraphFactory::GetEdgeBasedNodes(EdgeBasedNodeDataContainer &data_container)
|
||||
{
|
||||
using std::swap; // Koenig swap
|
||||
swap(data_container, m_edge_based_node_container);
|
||||
}
|
||||
|
||||
void EdgeBasedGraphFactory::GetEdgeBasedNodeSegments(std::vector<EdgeBasedNodeSegment> &nodes)
|
||||
{
|
||||
using std::swap; // Koenig swap
|
||||
@ -121,21 +114,23 @@ NBGToEBG EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const N
|
||||
BOOST_ASSERT(node_v != SPECIAL_NODEID);
|
||||
|
||||
// find forward edge id and
|
||||
const EdgeID edge_id_1 = m_node_based_graph->FindEdge(node_u, node_v);
|
||||
const EdgeID edge_id_1 = m_node_based_graph.FindEdge(node_u, node_v);
|
||||
BOOST_ASSERT(edge_id_1 != SPECIAL_EDGEID);
|
||||
|
||||
const EdgeData &forward_data = m_node_based_graph->GetEdgeData(edge_id_1);
|
||||
const EdgeData &forward_data = m_node_based_graph.GetEdgeData(edge_id_1);
|
||||
|
||||
// find reverse edge id and
|
||||
const EdgeID edge_id_2 = m_node_based_graph->FindEdge(node_v, node_u);
|
||||
const EdgeID edge_id_2 = m_node_based_graph.FindEdge(node_v, node_u);
|
||||
BOOST_ASSERT(edge_id_2 != SPECIAL_EDGEID);
|
||||
|
||||
const EdgeData &reverse_data = m_node_based_graph->GetEdgeData(edge_id_2);
|
||||
const EdgeData &reverse_data = m_node_based_graph.GetEdgeData(edge_id_2);
|
||||
|
||||
BOOST_ASSERT(forward_data.edge_id != SPECIAL_NODEID || reverse_data.edge_id != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(nbe_to_ebn_mapping[edge_id_1] != SPECIAL_NODEID ||
|
||||
nbe_to_ebn_mapping[edge_id_2] != SPECIAL_NODEID);
|
||||
|
||||
if (forward_data.edge_id != SPECIAL_NODEID && reverse_data.edge_id == SPECIAL_NODEID)
|
||||
m_edge_based_node_weights[forward_data.edge_id] = INVALID_EDGE_WEIGHT;
|
||||
if (nbe_to_ebn_mapping[edge_id_1] != SPECIAL_NODEID &&
|
||||
nbe_to_ebn_mapping[edge_id_2] == SPECIAL_NODEID)
|
||||
m_edge_based_node_weights[nbe_to_ebn_mapping[edge_id_1]] = INVALID_EDGE_WEIGHT;
|
||||
|
||||
BOOST_ASSERT(m_compressed_edge_container.HasEntryForID(edge_id_1) ==
|
||||
m_compressed_edge_container.HasEntryForID(edge_id_2));
|
||||
@ -149,7 +144,8 @@ NBGToEBG EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const N
|
||||
// There should always be some geometry
|
||||
BOOST_ASSERT(0 != segment_count);
|
||||
|
||||
const unsigned packed_geometry_id = m_compressed_edge_container.ZipEdges(edge_id_1, edge_id_2);
|
||||
// const unsigned packed_geometry_id = m_compressed_edge_container.ZipEdges(edge_id_1,
|
||||
// edge_id_2);
|
||||
|
||||
NodeID current_edge_source_coordinate_id = node_u;
|
||||
|
||||
@ -163,23 +159,18 @@ NBGToEBG EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const N
|
||||
};
|
||||
|
||||
// Add edge-based node data for forward and reverse nodes indexed by edge_id
|
||||
BOOST_ASSERT(forward_data.edge_id != SPECIAL_EDGEID);
|
||||
m_edge_based_node_container.SetData(forward_data.edge_id,
|
||||
GeometryID{packed_geometry_id, true},
|
||||
forward_data.name_id,
|
||||
forward_data.travel_mode,
|
||||
forward_data.classes,
|
||||
forward_data.is_left_hand_driving);
|
||||
if (reverse_data.edge_id != SPECIAL_EDGEID)
|
||||
BOOST_ASSERT(nbe_to_ebn_mapping[edge_id_1] != SPECIAL_EDGEID);
|
||||
m_edge_based_node_container.nodes[nbe_to_ebn_mapping[edge_id_1]].geometry_id =
|
||||
forward_data.geometry_id;
|
||||
m_edge_based_node_container.nodes[nbe_to_ebn_mapping[edge_id_1]].annotation_id =
|
||||
forward_data.annotation_data;
|
||||
if (nbe_to_ebn_mapping[edge_id_2] != SPECIAL_EDGEID)
|
||||
{
|
||||
m_edge_based_node_container.SetData(reverse_data.edge_id,
|
||||
GeometryID{packed_geometry_id, false},
|
||||
reverse_data.name_id,
|
||||
reverse_data.travel_mode,
|
||||
reverse_data.classes,
|
||||
reverse_data.is_left_hand_driving);
|
||||
m_edge_based_node_container.nodes[nbe_to_ebn_mapping[edge_id_2]].geometry_id =
|
||||
reverse_data.geometry_id;
|
||||
m_edge_based_node_container.nodes[nbe_to_ebn_mapping[edge_id_2]].annotation_id =
|
||||
reverse_data.annotation_data;
|
||||
}
|
||||
|
||||
// Add segments of edge-based nodes
|
||||
for (const auto i : util::irange(std::size_t{0}, segment_count))
|
||||
{
|
||||
@ -196,20 +187,21 @@ NBGToEBG EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const N
|
||||
BOOST_ASSERT(current_edge_target_coordinate_id != current_edge_source_coordinate_id);
|
||||
|
||||
// build edges
|
||||
m_edge_based_node_segments.emplace_back(edge_id_to_segment_id(forward_data.edge_id),
|
||||
edge_id_to_segment_id(reverse_data.edge_id),
|
||||
current_edge_source_coordinate_id,
|
||||
current_edge_target_coordinate_id,
|
||||
i);
|
||||
m_edge_based_node_segments.emplace_back(
|
||||
edge_id_to_segment_id(nbe_to_ebn_mapping[edge_id_1]),
|
||||
edge_id_to_segment_id(nbe_to_ebn_mapping[edge_id_2]),
|
||||
current_edge_source_coordinate_id,
|
||||
current_edge_target_coordinate_id,
|
||||
i);
|
||||
|
||||
m_edge_based_node_is_startpoint.push_back(
|
||||
(forward_data.startpoint || reverse_data.startpoint));
|
||||
m_edge_based_node_is_startpoint.push_back(forward_data.flags.startpoint ||
|
||||
reverse_data.flags.startpoint);
|
||||
current_edge_source_coordinate_id = current_edge_target_coordinate_id;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(current_edge_source_coordinate_id == node_v);
|
||||
|
||||
return NBGToEBG{node_u, node_v, forward_data.edge_id, reverse_data.edge_id};
|
||||
return NBGToEBG{node_u, node_v, nbe_to_ebn_mapping[edge_id_1], nbe_to_ebn_mapping[edge_id_2]};
|
||||
}
|
||||
|
||||
void EdgeBasedGraphFactory::Run(ScriptingEnvironment &scripting_environment,
|
||||
@ -225,9 +217,15 @@ void EdgeBasedGraphFactory::Run(ScriptingEnvironment &scripting_environment,
|
||||
const WayRestrictionMap &way_restriction_map)
|
||||
{
|
||||
TIMER_START(renumber);
|
||||
m_number_of_edge_based_nodes = RenumberEdges() + way_restriction_map.NumberOfDuplicatedNodes();
|
||||
m_number_of_edge_based_nodes =
|
||||
LabelEdgeBasedNodes() + way_restriction_map.NumberOfDuplicatedNodes();
|
||||
TIMER_STOP(renumber);
|
||||
|
||||
// Allocate memory for edge-based nodes
|
||||
// In addition to the normal edges, allocate enough space for copied edges from
|
||||
// via-way-restrictions, see calculation above
|
||||
m_edge_based_node_container.nodes.resize(m_number_of_edge_based_nodes);
|
||||
|
||||
TIMER_START(generate_nodes);
|
||||
{
|
||||
auto mapping = GenerateEdgeExpandedNodes(way_restriction_map);
|
||||
@ -258,19 +256,19 @@ void EdgeBasedGraphFactory::Run(ScriptingEnvironment &scripting_environment,
|
||||
/// Renumbers all _forward_ edges and sets the edge_id.
|
||||
/// A specific numbering is not important. Any unique ID will do.
|
||||
/// Returns the number of edge-based nodes.
|
||||
unsigned EdgeBasedGraphFactory::RenumberEdges()
|
||||
unsigned EdgeBasedGraphFactory::LabelEdgeBasedNodes()
|
||||
{
|
||||
// heuristic: node-based graph node is a simple intersection with four edges (edge-based nodes)
|
||||
m_edge_based_node_weights.reserve(4 * m_node_based_graph->GetNumberOfNodes());
|
||||
m_edge_based_node_weights.reserve(4 * m_node_based_graph.GetNumberOfNodes());
|
||||
nbe_to_ebn_mapping.resize(m_node_based_graph.GetEdgeCapacity(), SPECIAL_NODEID);
|
||||
|
||||
// renumber edge based node of outgoing edges
|
||||
unsigned numbered_edges_count = 0;
|
||||
for (const auto current_node : util::irange(0u, m_node_based_graph->GetNumberOfNodes()))
|
||||
for (const auto current_node : util::irange(0u, m_node_based_graph.GetNumberOfNodes()))
|
||||
{
|
||||
for (const auto current_edge : m_node_based_graph->GetAdjacentEdgeRange(current_node))
|
||||
for (const auto current_edge : m_node_based_graph.GetAdjacentEdgeRange(current_node))
|
||||
{
|
||||
EdgeData &edge_data = m_node_based_graph->GetEdgeData(current_edge);
|
||||
|
||||
const EdgeData &edge_data = m_node_based_graph.GetEdgeData(current_edge);
|
||||
// only number incoming edges
|
||||
if (edge_data.reversed)
|
||||
{
|
||||
@ -279,11 +277,9 @@ unsigned EdgeBasedGraphFactory::RenumberEdges()
|
||||
|
||||
m_edge_based_node_weights.push_back(edge_data.weight);
|
||||
|
||||
BOOST_ASSERT(numbered_edges_count < m_node_based_graph->GetNumberOfEdges());
|
||||
edge_data.edge_id = numbered_edges_count;
|
||||
BOOST_ASSERT(numbered_edges_count < m_node_based_graph.GetNumberOfEdges());
|
||||
nbe_to_ebn_mapping[current_edge] = numbered_edges_count;
|
||||
++numbered_edges_count;
|
||||
|
||||
BOOST_ASSERT(SPECIAL_NODEID != edge_data.edge_id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -296,31 +292,25 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedNodes(const WayRestrictionMap &way_re
|
||||
{
|
||||
std::vector<NBGToEBG> mapping;
|
||||
|
||||
// Allocate memory for edge-based nodes
|
||||
// In addition to the normal edges, allocate enough space for copied edges from
|
||||
// via-way-restrictions
|
||||
m_edge_based_node_container = EdgeBasedNodeDataContainer(m_number_of_edge_based_nodes);
|
||||
|
||||
util::Log() << "Generating edge expanded nodes ... ";
|
||||
// indicating a normal node within the edge-based graph. This node represents an edge in the
|
||||
// node-based graph
|
||||
{
|
||||
util::UnbufferedLog log;
|
||||
util::Percent progress(log, m_node_based_graph->GetNumberOfNodes());
|
||||
util::Percent progress(log, m_node_based_graph.GetNumberOfNodes());
|
||||
|
||||
m_compressed_edge_container.InitializeBothwayVector();
|
||||
// m_compressed_edge_container.InitializeBothwayVector();
|
||||
|
||||
// loop over all edges and generate new set of nodes
|
||||
for (const auto nbg_node_u : util::irange(0u, m_node_based_graph->GetNumberOfNodes()))
|
||||
for (const auto nbg_node_u : util::irange(0u, m_node_based_graph.GetNumberOfNodes()))
|
||||
{
|
||||
BOOST_ASSERT(nbg_node_u != SPECIAL_NODEID);
|
||||
progress.PrintStatus(nbg_node_u);
|
||||
for (EdgeID nbg_edge_id : m_node_based_graph->GetAdjacentEdgeRange(nbg_node_u))
|
||||
for (EdgeID nbg_edge_id : m_node_based_graph.GetAdjacentEdgeRange(nbg_node_u))
|
||||
{
|
||||
BOOST_ASSERT(nbg_edge_id != SPECIAL_EDGEID);
|
||||
|
||||
const EdgeData &nbg_edge_data = m_node_based_graph->GetEdgeData(nbg_edge_id);
|
||||
const NodeID nbg_node_v = m_node_based_graph->GetTarget(nbg_edge_id);
|
||||
const NodeID nbg_node_v = m_node_based_graph.GetTarget(nbg_edge_id);
|
||||
BOOST_ASSERT(nbg_node_v != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(nbg_node_u != nbg_node_v);
|
||||
|
||||
@ -332,7 +322,7 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedNodes(const WayRestrictionMap &way_re
|
||||
}
|
||||
|
||||
// if we found a non-forward edge reverse and try again
|
||||
if (nbg_edge_data.edge_id == SPECIAL_NODEID)
|
||||
if (nbe_to_ebn_mapping[nbg_edge_id] == SPECIAL_NODEID)
|
||||
{
|
||||
mapping.push_back(InsertEdgeBasedNode(nbg_node_v, nbg_node_u));
|
||||
}
|
||||
@ -360,28 +350,21 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedNodes(const WayRestrictionMap &way_re
|
||||
const auto node_u = way.from;
|
||||
const auto node_v = way.to;
|
||||
// we know that the edge exists as non-reversed edge
|
||||
const auto eid = m_node_based_graph->FindEdge(node_u, node_v);
|
||||
const auto eid = m_node_based_graph.FindEdge(node_u, node_v);
|
||||
|
||||
BOOST_ASSERT(m_node_based_graph->GetEdgeData(eid).edge_id != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(nbe_to_ebn_mapping[eid] != SPECIAL_NODEID);
|
||||
|
||||
// merge edges together into one EdgeBasedNode
|
||||
BOOST_ASSERT(node_u != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(node_v != SPECIAL_NODEID);
|
||||
|
||||
// find node in the edge based graph, we only require one id:
|
||||
const EdgeData &edge_data = m_node_based_graph->GetEdgeData(eid);
|
||||
// what is this ID all about? :(
|
||||
BOOST_ASSERT(edge_data.edge_id != SPECIAL_NODEID);
|
||||
|
||||
BOOST_ASSERT(edge_data.edge_id < m_edge_based_node_container.Size());
|
||||
m_edge_based_node_container.SetData(
|
||||
edge_based_node_id,
|
||||
// fetch the known geometry ID
|
||||
m_edge_based_node_container.GetGeometryID(static_cast<NodeID>(edge_data.edge_id)),
|
||||
edge_data.name_id,
|
||||
edge_data.travel_mode,
|
||||
edge_data.classes,
|
||||
edge_data.is_left_hand_driving);
|
||||
const EdgeData &edge_data = m_node_based_graph.GetEdgeData(eid);
|
||||
// BOOST_ASSERT(edge_data.edge_id < m_edge_based_node_container.Size());
|
||||
m_edge_based_node_container.nodes[edge_based_node_id].geometry_id =
|
||||
edge_data.geometry_id;
|
||||
m_edge_based_node_container.nodes[edge_based_node_id].annotation_id =
|
||||
edge_data.annotation_data;
|
||||
|
||||
m_edge_based_node_weights.push_back(m_edge_based_node_weights[eid]);
|
||||
|
||||
@ -431,20 +414,23 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
// Three nested loop look super-linear, but we are dealing with a (kind of)
|
||||
// linear number of turns only.
|
||||
SuffixTable street_name_suffix_table(scripting_environment);
|
||||
guidance::TurnAnalysis turn_analysis(*m_node_based_graph,
|
||||
guidance::TurnAnalysis turn_analysis(m_node_based_graph,
|
||||
m_edge_based_node_container,
|
||||
m_coordinates,
|
||||
node_restriction_map,
|
||||
m_barrier_nodes,
|
||||
m_compressed_edge_container,
|
||||
name_table,
|
||||
street_name_suffix_table,
|
||||
profile_properties);
|
||||
street_name_suffix_table);
|
||||
|
||||
util::guidance::LaneDataIdMap lane_data_map;
|
||||
guidance::lanes::TurnLaneHandler turn_lane_handler(
|
||||
*m_node_based_graph, lane_description_map, turn_analysis, lane_data_map);
|
||||
guidance::lanes::TurnLaneHandler turn_lane_handler(m_node_based_graph,
|
||||
m_edge_based_node_container,
|
||||
lane_description_map,
|
||||
turn_analysis,
|
||||
lane_data_map);
|
||||
|
||||
bearing_class_by_node_based_node.resize(m_node_based_graph->GetNumberOfNodes(),
|
||||
bearing_class_by_node_based_node.resize(m_node_based_graph.GetNumberOfNodes(),
|
||||
std::numeric_limits<std::uint32_t>::max());
|
||||
|
||||
// FIXME these need to be tuned in pre-allocated size
|
||||
@ -467,7 +453,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
{
|
||||
util::UnbufferedLog log;
|
||||
|
||||
const NodeID node_count = m_node_based_graph->GetNumberOfNodes();
|
||||
const NodeID node_count = m_node_based_graph.GetNumberOfNodes();
|
||||
util::Percent progress(log, node_count);
|
||||
// This counter is used to keep track of how far along we've made it
|
||||
std::uint64_t nodes_completed = 0;
|
||||
@ -550,7 +536,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
|
||||
const auto node_restricted = isRestricted(node_along_road_entering,
|
||||
node_at_center_of_intersection,
|
||||
m_node_based_graph->GetTarget(turn.eid),
|
||||
m_node_based_graph.GetTarget(turn.eid),
|
||||
conditional_restriction_map);
|
||||
|
||||
boost::optional<Conditional> conditional = boost::none;
|
||||
@ -565,10 +551,11 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
conditions}}};
|
||||
}
|
||||
|
||||
const EdgeData &edge_data1 = m_node_based_graph->GetEdgeData(node_based_edge_from);
|
||||
const EdgeData &edge_data2 = m_node_based_graph->GetEdgeData(node_based_edge_to);
|
||||
const auto &edge_data1 = m_node_based_graph.GetEdgeData(node_based_edge_from);
|
||||
const auto &edge_data2 = m_node_based_graph.GetEdgeData(node_based_edge_to);
|
||||
|
||||
BOOST_ASSERT(edge_data1.edge_id != edge_data2.edge_id);
|
||||
BOOST_ASSERT(nbe_to_ebn_mapping[node_based_edge_from] !=
|
||||
nbe_to_ebn_mapping[node_based_edge_to]);
|
||||
BOOST_ASSERT(!edge_data1.reversed);
|
||||
BOOST_ASSERT(!edge_data2.reversed);
|
||||
|
||||
@ -581,11 +568,13 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
|
||||
// compute weight and duration penalties
|
||||
auto is_traffic_light = m_traffic_lights.count(node_at_center_of_intersection);
|
||||
ExtractionTurn extracted_turn(turn,
|
||||
is_traffic_light,
|
||||
edge_data1.restricted,
|
||||
edge_data2.restricted,
|
||||
edge_data1.is_left_hand_driving);
|
||||
ExtractionTurn extracted_turn(
|
||||
turn,
|
||||
is_traffic_light,
|
||||
edge_data1.flags.restricted,
|
||||
edge_data2.flags.restricted,
|
||||
m_edge_based_node_container.GetAnnotation(edge_data1.annotation_data)
|
||||
.is_left_hand_driving);
|
||||
scripting_environment.ProcessTurn(extracted_turn);
|
||||
|
||||
// turn penalties are limited to [-2^15, 2^15) which roughly
|
||||
@ -594,8 +583,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
boost::numeric_cast<TurnPenalty>(extracted_turn.weight * weight_multiplier);
|
||||
auto duration_penalty = boost::numeric_cast<TurnPenalty>(extracted_turn.duration * 10.);
|
||||
|
||||
BOOST_ASSERT(SPECIAL_NODEID != edge_data1.edge_id);
|
||||
BOOST_ASSERT(SPECIAL_NODEID != edge_data2.edge_id);
|
||||
BOOST_ASSERT(SPECIAL_NODEID != nbe_to_ebn_mapping[node_based_edge_from]);
|
||||
BOOST_ASSERT(SPECIAL_NODEID != nbe_to_ebn_mapping[node_based_edge_to]);
|
||||
|
||||
// auto turn_id = m_edge_based_edge_list.size();
|
||||
auto weight = boost::numeric_cast<EdgeWeight>(edge_data1.weight + weight_penalty);
|
||||
@ -682,15 +671,15 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
// `b` by an outgoing edge. Therefore, we have to search all connected edges for
|
||||
// edges entering `b`
|
||||
for (const EdgeID outgoing_edge :
|
||||
m_node_based_graph->GetAdjacentEdgeRange(node_at_center_of_intersection))
|
||||
m_node_based_graph.GetAdjacentEdgeRange(node_at_center_of_intersection))
|
||||
{
|
||||
const NodeID node_along_road_entering =
|
||||
m_node_based_graph->GetTarget(outgoing_edge);
|
||||
m_node_based_graph.GetTarget(outgoing_edge);
|
||||
|
||||
const auto incoming_edge = m_node_based_graph->FindEdge(
|
||||
const auto incoming_edge = m_node_based_graph.FindEdge(
|
||||
node_along_road_entering, node_at_center_of_intersection);
|
||||
|
||||
if (m_node_based_graph->GetEdgeData(incoming_edge).reversed)
|
||||
if (m_node_based_graph.GetEdgeData(incoming_edge).reversed)
|
||||
continue;
|
||||
|
||||
++node_based_edge_counter;
|
||||
@ -743,10 +732,6 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
if (!turn.entry_allowed)
|
||||
continue;
|
||||
|
||||
const EdgeData &edge_data1 =
|
||||
m_node_based_graph->GetEdgeData(incoming_edge);
|
||||
const EdgeData &edge_data2 = m_node_based_graph->GetEdgeData(turn.eid);
|
||||
|
||||
// In case a way restriction starts at a given location, add a turn onto
|
||||
// every artificial node eminating here.
|
||||
//
|
||||
@ -764,18 +749,19 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
// artificial node, we simply have to find a single representative for
|
||||
// the turn. Here we check whether the turn in question is the start of
|
||||
// a via way restriction. If that should be the case, we switch
|
||||
// edge_data2.edge_id to the ID of the duplicated node associated with
|
||||
// the turn. (e.g. ab via bc switches bc to bc_dup)
|
||||
// the id of the edge-based-node for the target to the ID of the
|
||||
// duplicated node associated with the turn. (e.g. ab via bc switches bc
|
||||
// to bc_dup)
|
||||
auto const target_id = way_restriction_map.RemapIfRestricted(
|
||||
edge_data2.edge_id,
|
||||
nbe_to_ebn_mapping[turn.eid],
|
||||
node_along_road_entering,
|
||||
node_at_center_of_intersection,
|
||||
m_node_based_graph->GetTarget(turn.eid),
|
||||
m_node_based_graph.GetTarget(turn.eid),
|
||||
m_number_of_edge_based_nodes);
|
||||
|
||||
{ // scope to forget edge_with_data after
|
||||
const auto edge_with_data_and_condition =
|
||||
generate_edge(edge_data1.edge_id,
|
||||
generate_edge(nbe_to_ebn_mapping[incoming_edge],
|
||||
target_id,
|
||||
node_along_road_entering,
|
||||
incoming_edge,
|
||||
@ -822,14 +808,13 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
duplicated_node_id;
|
||||
|
||||
auto const node_at_end_of_turn =
|
||||
m_node_based_graph->GetTarget(turn.eid);
|
||||
m_node_based_graph.GetTarget(turn.eid);
|
||||
|
||||
const auto is_way_restricted = way_restriction_map.IsRestricted(
|
||||
duplicated_node_id, node_at_end_of_turn);
|
||||
|
||||
if (is_way_restricted)
|
||||
{
|
||||
|
||||
auto const restriction = way_restriction_map.GetRestriction(
|
||||
duplicated_node_id, node_at_end_of_turn);
|
||||
|
||||
@ -837,16 +822,16 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
continue;
|
||||
|
||||
// add into delayed data
|
||||
auto edge_with_data_and_condition = generate_edge(
|
||||
NodeID(from_id),
|
||||
m_node_based_graph->GetEdgeData(turn.eid).edge_id,
|
||||
node_along_road_entering,
|
||||
incoming_edge,
|
||||
node_at_center_of_intersection,
|
||||
turn.eid,
|
||||
intersection,
|
||||
turn,
|
||||
entry_class_id);
|
||||
auto edge_with_data_and_condition =
|
||||
generate_edge(NodeID(from_id),
|
||||
nbe_to_ebn_mapping[turn.eid],
|
||||
node_along_road_entering,
|
||||
incoming_edge,
|
||||
node_at_center_of_intersection,
|
||||
turn.eid,
|
||||
intersection,
|
||||
turn,
|
||||
entry_class_id);
|
||||
|
||||
buffer->delayed_data.push_back(
|
||||
std::move(edge_with_data_and_condition.first));
|
||||
@ -863,7 +848,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
// add a new conditional for the edge we just created
|
||||
buffer->conditionals.push_back(
|
||||
{NodeID(from_id),
|
||||
m_node_based_graph->GetEdgeData(turn.eid).edge_id,
|
||||
nbe_to_ebn_mapping[turn.eid],
|
||||
{static_cast<std::uint64_t>(-1),
|
||||
m_coordinates[node_at_center_of_intersection],
|
||||
restriction.condition}});
|
||||
@ -871,16 +856,16 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
}
|
||||
else
|
||||
{
|
||||
auto edge_with_data_and_condition = generate_edge(
|
||||
NodeID(from_id),
|
||||
m_node_based_graph->GetEdgeData(turn.eid).edge_id,
|
||||
node_along_road_entering,
|
||||
incoming_edge,
|
||||
node_at_center_of_intersection,
|
||||
turn.eid,
|
||||
intersection,
|
||||
turn,
|
||||
entry_class_id);
|
||||
auto edge_with_data_and_condition =
|
||||
generate_edge(NodeID(from_id),
|
||||
nbe_to_ebn_mapping[turn.eid],
|
||||
node_along_road_entering,
|
||||
incoming_edge,
|
||||
node_at_center_of_intersection,
|
||||
turn.eid,
|
||||
intersection,
|
||||
turn,
|
||||
entry_class_id);
|
||||
|
||||
buffer->delayed_data.push_back(
|
||||
std::move(edge_with_data_and_condition.first));
|
||||
|
@ -67,23 +67,26 @@ struct CmpEdgeByInternalSourceTargetAndName
|
||||
if (lhs.result.target == SPECIAL_NODEID)
|
||||
return false;
|
||||
|
||||
if (lhs.result.name_id == rhs.result.name_id)
|
||||
auto const lhs_name_id = edge_annotation_data[lhs.result.annotation_data].name_id;
|
||||
auto const rhs_name_id = edge_annotation_data[rhs.result.annotation_data].name_id;
|
||||
if (lhs_name_id == rhs_name_id)
|
||||
return false;
|
||||
|
||||
if (lhs.result.name_id == EMPTY_NAMEID)
|
||||
if (lhs_name_id == EMPTY_NAMEID)
|
||||
return false;
|
||||
|
||||
if (rhs.result.name_id == EMPTY_NAMEID)
|
||||
if (rhs_name_id == EMPTY_NAMEID)
|
||||
return true;
|
||||
|
||||
BOOST_ASSERT(!name_offsets.empty() && name_offsets.back() == name_data.size());
|
||||
const oe::ExtractionContainers::NameCharData::const_iterator data = name_data.begin();
|
||||
return std::lexicographical_compare(data + name_offsets[lhs.result.name_id],
|
||||
data + name_offsets[lhs.result.name_id + 1],
|
||||
data + name_offsets[rhs.result.name_id],
|
||||
data + name_offsets[rhs.result.name_id + 1]);
|
||||
return std::lexicographical_compare(data + name_offsets[lhs_name_id],
|
||||
data + name_offsets[lhs_name_id + 1],
|
||||
data + name_offsets[rhs_name_id],
|
||||
data + name_offsets[rhs_name_id + 1]);
|
||||
}
|
||||
|
||||
const oe::ExtractionContainers::AnnotationDataVector &edge_annotation_data;
|
||||
const oe::ExtractionContainers::NameCharData &name_data;
|
||||
const oe::ExtractionContainers::NameOffsets &name_offsets;
|
||||
};
|
||||
@ -136,6 +139,7 @@ void ExtractionContainers::PrepareData(ScriptingEnvironment &scripting_environme
|
||||
all_nodes_list.clear(); // free all_nodes_list before allocation of normal_edges
|
||||
all_nodes_list.shrink_to_fit();
|
||||
WriteEdges(file_out);
|
||||
WriteMetadata(file_out);
|
||||
|
||||
PrepareRestrictions();
|
||||
WriteCharData(name_file_name);
|
||||
@ -361,7 +365,7 @@ void ExtractionContainers::PrepareEdges(ScriptingEnvironment &scripting_environm
|
||||
util::Coordinate target_coord{node_iterator->lon, node_iterator->lat};
|
||||
|
||||
// flip source and target coordinates if segment is in backward direction only
|
||||
if (!edge_iterator->result.forward && edge_iterator->result.backward)
|
||||
if (!edge_iterator->result.flags.forward && edge_iterator->result.flags.backward)
|
||||
std::swap(source_coord, target_coord);
|
||||
|
||||
const auto distance =
|
||||
@ -389,9 +393,9 @@ void ExtractionContainers::PrepareEdges(ScriptingEnvironment &scripting_environm
|
||||
std::swap(edge.source, edge.target);
|
||||
|
||||
// std::swap does not work with bit-fields
|
||||
bool temp = edge.forward;
|
||||
edge.forward = edge.backward;
|
||||
edge.backward = temp;
|
||||
bool temp = edge.flags.forward;
|
||||
edge.flags.forward = edge.flags.backward;
|
||||
edge.flags.backward = temp;
|
||||
}
|
||||
++edge_iterator;
|
||||
}
|
||||
@ -415,7 +419,8 @@ void ExtractionContainers::PrepareEdges(ScriptingEnvironment &scripting_environm
|
||||
std::mutex name_data_mutex;
|
||||
tbb::parallel_sort(all_edges_list.begin(),
|
||||
all_edges_list.end(),
|
||||
CmpEdgeByInternalSourceTargetAndName{name_char_data, name_offsets});
|
||||
CmpEdgeByInternalSourceTargetAndName{
|
||||
all_edges_annotation_data_list, name_char_data, name_offsets});
|
||||
TIMER_STOP(sort_edges_by_renumbered_start);
|
||||
log << "ok, after " << TIMER_SEC(sort_edges_by_renumbered_start) << "s";
|
||||
}
|
||||
@ -452,12 +457,12 @@ void ExtractionContainers::PrepareEdges(ScriptingEnvironment &scripting_environm
|
||||
{
|
||||
const auto &result = all_edges_list[i].result;
|
||||
const auto value = std::make_pair(result.weight, result.duration);
|
||||
if (result.forward && value < min_forward)
|
||||
if (result.flags.forward && value < min_forward)
|
||||
{
|
||||
min_forward_idx = i;
|
||||
min_forward = value;
|
||||
}
|
||||
if (result.backward && value < min_backward)
|
||||
if (result.flags.backward && value < min_backward)
|
||||
{
|
||||
min_backward_idx = i;
|
||||
min_backward = value;
|
||||
@ -476,9 +481,9 @@ void ExtractionContainers::PrepareEdges(ScriptingEnvironment &scripting_environm
|
||||
|
||||
if (min_backward_idx == min_forward_idx)
|
||||
{
|
||||
all_edges_list[min_forward_idx].result.is_split = false;
|
||||
all_edges_list[min_forward_idx].result.forward = true;
|
||||
all_edges_list[min_forward_idx].result.backward = true;
|
||||
all_edges_list[min_forward_idx].result.flags.is_split = false;
|
||||
all_edges_list[min_forward_idx].result.flags.forward = true;
|
||||
all_edges_list[min_forward_idx].result.flags.backward = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -486,17 +491,17 @@ void ExtractionContainers::PrepareEdges(ScriptingEnvironment &scripting_environm
|
||||
bool has_backward = min_backward_idx != std::numeric_limits<std::size_t>::max();
|
||||
if (has_forward)
|
||||
{
|
||||
all_edges_list[min_forward_idx].result.forward = true;
|
||||
all_edges_list[min_forward_idx].result.backward = false;
|
||||
all_edges_list[min_forward_idx].result.is_split = has_backward;
|
||||
all_edges_list[min_forward_idx].result.flags.forward = true;
|
||||
all_edges_list[min_forward_idx].result.flags.backward = false;
|
||||
all_edges_list[min_forward_idx].result.flags.is_split = has_backward;
|
||||
}
|
||||
if (has_backward)
|
||||
{
|
||||
std::swap(all_edges_list[min_backward_idx].result.source,
|
||||
all_edges_list[min_backward_idx].result.target);
|
||||
all_edges_list[min_backward_idx].result.forward = true;
|
||||
all_edges_list[min_backward_idx].result.backward = false;
|
||||
all_edges_list[min_backward_idx].result.is_split = has_forward;
|
||||
all_edges_list[min_backward_idx].result.flags.forward = true;
|
||||
all_edges_list[min_backward_idx].result.flags.backward = false;
|
||||
all_edges_list[min_backward_idx].result.flags.is_split = has_forward;
|
||||
}
|
||||
}
|
||||
|
||||
@ -545,10 +550,25 @@ void ExtractionContainers::WriteEdges(storage::io::FileWriter &file_out) const
|
||||
|
||||
TIMER_STOP(write_edges);
|
||||
log << "ok, after " << TIMER_SEC(write_edges) << "s";
|
||||
log << "Processed " << normal_edges.size() << " edges";
|
||||
log << " -- Processed " << normal_edges.size() << " edges";
|
||||
}
|
||||
}
|
||||
|
||||
void ExtractionContainers::WriteMetadata(storage::io::FileWriter &file_out) const
|
||||
{
|
||||
util::UnbufferedLog log;
|
||||
log << "Writing way meta-data ... " << std::flush;
|
||||
TIMER_START(write_meta_data);
|
||||
|
||||
file_out.WriteElementCount64(all_edges_annotation_data_list.size());
|
||||
file_out.WriteFrom(all_edges_annotation_data_list.data(),
|
||||
all_edges_annotation_data_list.size());
|
||||
|
||||
TIMER_STOP(write_meta_data);
|
||||
log << "ok, after " << TIMER_SEC(write_meta_data) << "s";
|
||||
log << " -- Metadata contains << " << all_edges_annotation_data_list.size() << " entries.";
|
||||
}
|
||||
|
||||
void ExtractionContainers::WriteNodes(storage::io::FileWriter &file_out) const
|
||||
{
|
||||
{
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "extractor/extraction_way.hpp"
|
||||
#include "extractor/extractor_callbacks.hpp"
|
||||
#include "extractor/files.hpp"
|
||||
#include "extractor/node_based_graph_factory.hpp"
|
||||
#include "extractor/raster_source.hpp"
|
||||
#include "extractor/restriction_filter.hpp"
|
||||
#include "extractor/restriction_parser.hpp"
|
||||
@ -209,27 +210,80 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
|
||||
util::DeallocatingVector<EdgeBasedEdge> edge_based_edge_list;
|
||||
std::vector<bool> node_is_startpoint;
|
||||
std::vector<EdgeWeight> edge_based_node_weights;
|
||||
std::vector<util::Coordinate> coordinates;
|
||||
extractor::PackedOSMIDs osm_node_ids;
|
||||
|
||||
auto graph_size = BuildEdgeExpandedGraph(scripting_environment,
|
||||
coordinates,
|
||||
osm_node_ids,
|
||||
edge_based_nodes_container,
|
||||
edge_based_node_segments,
|
||||
node_is_startpoint,
|
||||
edge_based_node_weights,
|
||||
edge_based_edge_list,
|
||||
config.GetPath(".osrm.icd").string(),
|
||||
turn_restrictions,
|
||||
conditional_turn_restrictions,
|
||||
turn_lane_map);
|
||||
// Create a node-based graph from the OSRM file
|
||||
NodeBasedGraphFactory node_based_graph_factory(config.GetPath(".osrm"),
|
||||
scripting_environment,
|
||||
turn_restrictions,
|
||||
conditional_turn_restrictions);
|
||||
|
||||
auto number_of_node_based_nodes = graph_size.first;
|
||||
auto max_edge_id = graph_size.second - 1;
|
||||
util::Log() << "Writing nodes for nodes-based and edges-based graphs ...";
|
||||
auto const &coordinates = node_based_graph_factory.GetCoordinates();
|
||||
files::writeNodes(
|
||||
config.GetPath(".osrm.nbg_nodes"), coordinates, node_based_graph_factory.GetOsmNodes());
|
||||
node_based_graph_factory.ReleaseOsmNodes();
|
||||
|
||||
auto const &node_based_graph = node_based_graph_factory.GetGraph();
|
||||
|
||||
// The osrm-partition tool requires the compressed node based graph with an embedding.
|
||||
//
|
||||
// The `Run` function above re-numbers non-reverse compressed node based graph edges
|
||||
// to a continuous range so that the nodes in the edge based graph are continuous.
|
||||
//
|
||||
// Luckily node based node ids still coincide with the coordinate array.
|
||||
// That's the reason we can only here write out the final compressed node based graph.
|
||||
|
||||
// Dumps to file asynchronously and makes sure we wait for its completion.
|
||||
std::future<void> compressed_node_based_graph_writing;
|
||||
|
||||
BOOST_SCOPE_EXIT_ALL(&)
|
||||
{
|
||||
if (compressed_node_based_graph_writing.valid())
|
||||
compressed_node_based_graph_writing.wait();
|
||||
};
|
||||
|
||||
compressed_node_based_graph_writing = std::async(std::launch::async, [&] {
|
||||
WriteCompressedNodeBasedGraph(
|
||||
config.GetPath(".osrm.cnbg").string(), node_based_graph, coordinates);
|
||||
});
|
||||
|
||||
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()));
|
||||
|
||||
conditional_turn_restrictions =
|
||||
removeInvalidRestrictions(std::move(conditional_turn_restrictions), node_based_graph);
|
||||
|
||||
const auto number_of_node_based_nodes = node_based_graph.GetNumberOfNodes();
|
||||
|
||||
const auto number_of_edge_based_nodes =
|
||||
BuildEdgeExpandedGraph(node_based_graph,
|
||||
coordinates,
|
||||
node_based_graph_factory.GetCompressedEdges(),
|
||||
barrier_nodes,
|
||||
traffic_signals,
|
||||
turn_restrictions,
|
||||
conditional_turn_restrictions,
|
||||
turn_lane_map,
|
||||
scripting_environment,
|
||||
edge_based_nodes_container,
|
||||
edge_based_node_segments,
|
||||
node_is_startpoint,
|
||||
edge_based_node_weights,
|
||||
edge_based_edge_list,
|
||||
config.GetPath(".osrm.icd").string());
|
||||
|
||||
TIMER_STOP(expansion);
|
||||
|
||||
// output the geometry of the node-based graph, needs to be done after the last usage, since it
|
||||
// destroys internal containers
|
||||
files::writeSegmentData(config.GetPath(".osrm.geometry"),
|
||||
*node_based_graph_factory.GetCompressedEdges().ToSegmentData());
|
||||
|
||||
util::Log() << "Saving edge-based node weights to file.";
|
||||
TIMER_START(timer_write_node_weights);
|
||||
{
|
||||
@ -241,8 +295,10 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
|
||||
util::Log() << "Done writing. (" << TIMER_SEC(timer_write_node_weights) << ")";
|
||||
|
||||
util::Log() << "Computing strictly connected components ...";
|
||||
FindComponents(
|
||||
max_edge_id, edge_based_edge_list, edge_based_node_segments, edge_based_nodes_container);
|
||||
FindComponents(number_of_edge_based_nodes,
|
||||
edge_based_edge_list,
|
||||
edge_based_node_segments,
|
||||
edge_based_nodes_container);
|
||||
|
||||
util::Log() << "Building r-tree ...";
|
||||
TIMER_START(rtree);
|
||||
@ -250,13 +306,12 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
|
||||
|
||||
TIMER_STOP(rtree);
|
||||
|
||||
util::Log() << "Writing nodes for nodes-based and edges-based graphs ...";
|
||||
files::writeNodes(config.GetPath(".osrm.nbg_nodes"), coordinates, osm_node_ids);
|
||||
files::writeNodeData(config.GetPath(".osrm.ebg_nodes"), edge_based_nodes_container);
|
||||
|
||||
util::Log() << "Writing edge-based-graph edges ... " << std::flush;
|
||||
TIMER_START(write_edges);
|
||||
files::writeEdgeBasedGraph(config.GetPath(".osrm.ebg"), max_edge_id, edge_based_edge_list);
|
||||
files::writeEdgeBasedGraph(
|
||||
config.GetPath(".osrm.ebg"), number_of_edge_based_nodes, edge_based_edge_list);
|
||||
TIMER_STOP(write_edges);
|
||||
util::Log() << "ok, after " << TIMER_SEC(write_edges) << "s";
|
||||
|
||||
@ -265,7 +320,7 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
|
||||
const auto nodes_per_second =
|
||||
static_cast<std::uint64_t>(number_of_node_based_nodes / TIMER_SEC(expansion));
|
||||
const auto edges_per_second =
|
||||
static_cast<std::uint64_t>((max_edge_id + 1) / TIMER_SEC(expansion));
|
||||
static_cast<std::uint64_t>((number_of_edge_based_nodes) / TIMER_SEC(expansion));
|
||||
|
||||
util::Log() << "Expansion: " << nodes_per_second << " nodes/sec and " << edges_per_second
|
||||
<< " edges/sec";
|
||||
@ -492,7 +547,7 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
|
||||
std::move(extraction_containers.conditional_turn_restrictions));
|
||||
}
|
||||
|
||||
void Extractor::FindComponents(unsigned max_edge_id,
|
||||
void Extractor::FindComponents(unsigned number_of_edge_based_nodes,
|
||||
const util::DeallocatingVector<EdgeBasedEdge> &input_edge_list,
|
||||
const std::vector<EdgeBasedNodeSegment> &input_node_segments,
|
||||
EdgeBasedNodeDataContainer &nodes_container) const
|
||||
@ -506,8 +561,8 @@ void Extractor::FindComponents(unsigned max_edge_id,
|
||||
{
|
||||
BOOST_ASSERT_MSG(static_cast<unsigned int>(std::max(edge.data.weight, 1)) > 0,
|
||||
"edge distance < 1");
|
||||
BOOST_ASSERT(edge.source <= max_edge_id);
|
||||
BOOST_ASSERT(edge.target <= max_edge_id);
|
||||
BOOST_ASSERT(edge.source < number_of_edge_based_nodes);
|
||||
BOOST_ASSERT(edge.target < number_of_edge_based_nodes);
|
||||
if (edge.data.forward)
|
||||
{
|
||||
edges.push_back({edge.source, edge.target});
|
||||
@ -525,8 +580,8 @@ void Extractor::FindComponents(unsigned max_edge_id,
|
||||
{
|
||||
if (segment.reverse_segment_id.enabled)
|
||||
{
|
||||
BOOST_ASSERT(segment.forward_segment_id.id <= max_edge_id);
|
||||
BOOST_ASSERT(segment.reverse_segment_id.id <= max_edge_id);
|
||||
BOOST_ASSERT(segment.forward_segment_id.id < number_of_edge_based_nodes);
|
||||
BOOST_ASSERT(segment.reverse_segment_id.id < number_of_edge_based_nodes);
|
||||
edges.push_back({segment.forward_segment_id.id, segment.reverse_segment_id.id});
|
||||
edges.push_back({segment.reverse_segment_id.id, segment.forward_segment_id.id});
|
||||
}
|
||||
@ -535,98 +590,54 @@ void Extractor::FindComponents(unsigned max_edge_id,
|
||||
tbb::parallel_sort(edges.begin(), edges.end());
|
||||
edges.erase(std::unique(edges.begin(), edges.end()), edges.end());
|
||||
|
||||
auto uncontracted_graph = UncontractedGraph(max_edge_id + 1, edges);
|
||||
auto uncontracted_graph = UncontractedGraph(number_of_edge_based_nodes, edges);
|
||||
|
||||
TarjanSCC<UncontractedGraph> component_search(uncontracted_graph);
|
||||
component_search.Run();
|
||||
|
||||
for (NodeID node_id = 0; node_id <= max_edge_id; ++node_id)
|
||||
for (NodeID node_id = 0; node_id < number_of_edge_based_nodes; ++node_id)
|
||||
{
|
||||
const auto forward_component = component_search.GetComponentID(node_id);
|
||||
const auto component_size = component_search.GetComponentSize(forward_component);
|
||||
const auto is_tiny = component_size < config.small_component_size;
|
||||
nodes_container.SetComponentID(node_id, {1 + forward_component, is_tiny});
|
||||
BOOST_ASSERT(node_id < nodes_container.NumberOfNodes());
|
||||
nodes_container.nodes[node_id].component_id = {1 + forward_component, is_tiny};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Load node based graph from .osrm file
|
||||
*/
|
||||
std::shared_ptr<util::NodeBasedDynamicGraph>
|
||||
Extractor::LoadNodeBasedGraph(std::unordered_set<NodeID> &barriers,
|
||||
std::unordered_set<NodeID> &traffic_signals,
|
||||
std::vector<util::Coordinate> &coordiantes,
|
||||
extractor::PackedOSMIDs &osm_node_ids)
|
||||
{
|
||||
storage::io::FileReader file_reader(config.GetPath(".osrm"),
|
||||
storage::io::FileReader::VerifyFingerprint);
|
||||
|
||||
auto barriers_iter = inserter(barriers, end(barriers));
|
||||
auto traffic_signals_iter = inserter(traffic_signals, end(traffic_signals));
|
||||
|
||||
NodeID number_of_node_based_nodes = util::loadNodesFromFile(
|
||||
file_reader, barriers_iter, traffic_signals_iter, coordiantes, osm_node_ids);
|
||||
|
||||
util::Log() << " - " << barriers.size() << " bollard nodes, " << traffic_signals.size()
|
||||
<< " traffic lights";
|
||||
|
||||
std::vector<NodeBasedEdge> edge_list;
|
||||
util::loadEdgesFromFile(file_reader, edge_list);
|
||||
|
||||
if (edge_list.empty())
|
||||
{
|
||||
throw util::exception("Node-based-graph (" + config.GetPath(".osrm").string() +
|
||||
") contains no edges." + SOURCE_REF);
|
||||
}
|
||||
|
||||
return util::NodeBasedDynamicGraphFromEdges(number_of_node_based_nodes, edge_list);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Building an edge-expanded graph from node-based input and turn restrictions
|
||||
*/
|
||||
std::pair<std::size_t, EdgeID> Extractor::BuildEdgeExpandedGraph(
|
||||
|
||||
EdgeID Extractor::BuildEdgeExpandedGraph(
|
||||
// input data
|
||||
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
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 std::vector<TurnRestriction> &turn_restrictions,
|
||||
const std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
|
||||
// might have to be updated to add new lane combinations
|
||||
guidance::LaneDescriptionMap &turn_lane_map,
|
||||
// for calculating turn penalties
|
||||
ScriptingEnvironment &scripting_environment,
|
||||
std::vector<util::Coordinate> &coordinates,
|
||||
extractor::PackedOSMIDs &osm_node_ids,
|
||||
// output data
|
||||
EdgeBasedNodeDataContainer &edge_based_nodes_container,
|
||||
std::vector<EdgeBasedNodeSegment> &edge_based_node_segments,
|
||||
std::vector<bool> &node_is_startpoint,
|
||||
std::vector<EdgeWeight> &edge_based_node_weights,
|
||||
util::DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
|
||||
const std::string &intersection_class_output_file,
|
||||
std::vector<TurnRestriction> &turn_restrictions,
|
||||
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
|
||||
guidance::LaneDescriptionMap &turn_lane_map)
|
||||
const std::string &intersection_class_output_file)
|
||||
{
|
||||
std::unordered_set<NodeID> barrier_nodes;
|
||||
std::unordered_set<NodeID> traffic_signals;
|
||||
|
||||
auto node_based_graph =
|
||||
LoadNodeBasedGraph(barrier_nodes, traffic_signals, coordinates, osm_node_ids);
|
||||
|
||||
CompressedEdgeContainer compressed_edge_container;
|
||||
GraphCompressor graph_compressor;
|
||||
graph_compressor.Compress(barrier_nodes,
|
||||
traffic_signals,
|
||||
scripting_environment,
|
||||
turn_restrictions,
|
||||
conditional_turn_restrictions,
|
||||
*node_based_graph,
|
||||
compressed_edge_container);
|
||||
|
||||
conditional_turn_restrictions =
|
||||
removeInvalidRestrictions(std::move(conditional_turn_restrictions), *node_based_graph);
|
||||
|
||||
util::NameTable name_table(config.GetPath(".osrm.names").string());
|
||||
|
||||
EdgeBasedGraphFactory edge_based_graph_factory(node_based_graph,
|
||||
edge_based_nodes_container,
|
||||
compressed_edge_container,
|
||||
barrier_nodes,
|
||||
traffic_signals,
|
||||
coordinates,
|
||||
osm_node_ids,
|
||||
scripting_environment.GetProfileProperties(),
|
||||
name_table,
|
||||
turn_lane_map);
|
||||
|
||||
@ -646,8 +657,6 @@ std::pair<std::size_t, EdgeID> Extractor::BuildEdgeExpandedGraph(
|
||||
WayRestrictionMap via_way_restriction_map(conditional_turn_restrictions);
|
||||
ConditionalRestrictionMap conditional_node_restriction_map(conditional_node_restrictions,
|
||||
IndexNodeByFromAndVia());
|
||||
turn_restrictions.clear();
|
||||
turn_restrictions.shrink_to_fit();
|
||||
|
||||
edge_based_graph_factory.Run(scripting_environment,
|
||||
config.GetPath(".osrm.edges").string(),
|
||||
@ -664,29 +673,6 @@ std::pair<std::size_t, EdgeID> Extractor::BuildEdgeExpandedGraph(
|
||||
};
|
||||
|
||||
const auto number_of_edge_based_nodes = create_edge_based_edges();
|
||||
compressed_edge_container.PrintStatistics();
|
||||
|
||||
// The osrm-partition tool requires the compressed node based graph with an embedding.
|
||||
//
|
||||
// The `Run` function above re-numbers non-reverse compressed node based graph edges
|
||||
// to a continuous range so that the nodes in the edge based graph are continuous.
|
||||
//
|
||||
// Luckily node based node ids still coincide with the coordinate array.
|
||||
// That's the reason we can only here write out the final compressed node based graph.
|
||||
|
||||
// Dumps to file asynchronously and makes sure we wait for its completion.
|
||||
std::future<void> compressed_node_based_graph_writing;
|
||||
|
||||
BOOST_SCOPE_EXIT_ALL(&)
|
||||
{
|
||||
if (compressed_node_based_graph_writing.valid())
|
||||
compressed_node_based_graph_writing.wait();
|
||||
};
|
||||
|
||||
compressed_node_based_graph_writing = std::async(std::launch::async, [&] {
|
||||
WriteCompressedNodeBasedGraph(
|
||||
config.GetPath(".osrm.cnbg").string(), *node_based_graph, coordinates);
|
||||
});
|
||||
|
||||
{
|
||||
std::vector<std::uint32_t> turn_lane_offsets;
|
||||
@ -696,17 +682,12 @@ std::pair<std::size_t, EdgeID> Extractor::BuildEdgeExpandedGraph(
|
||||
files::writeTurnLaneDescriptions(
|
||||
config.GetPath(".osrm.tls"), turn_lane_offsets, turn_lane_masks);
|
||||
}
|
||||
files::writeSegmentData(config.GetPath(".osrm.geometry"),
|
||||
*compressed_edge_container.ToSegmentData());
|
||||
|
||||
edge_based_graph_factory.GetEdgeBasedEdges(edge_based_edge_list);
|
||||
edge_based_graph_factory.GetEdgeBasedNodes(edge_based_nodes_container);
|
||||
edge_based_graph_factory.GetEdgeBasedNodeSegments(edge_based_node_segments);
|
||||
edge_based_graph_factory.GetStartPointMarkers(node_is_startpoint);
|
||||
edge_based_graph_factory.GetEdgeBasedNodeWeights(edge_based_node_weights);
|
||||
|
||||
const std::size_t number_of_node_based_nodes = node_based_graph->GetNumberOfNodes();
|
||||
|
||||
util::Log() << "Writing Intersection Classification Data";
|
||||
TIMER_START(write_intersections);
|
||||
files::writeIntersections(
|
||||
@ -717,7 +698,7 @@ std::pair<std::size_t, EdgeID> Extractor::BuildEdgeExpandedGraph(
|
||||
TIMER_STOP(write_intersections);
|
||||
util::Log() << "ok, after " << TIMER_SEC(write_intersections) << "s";
|
||||
|
||||
return std::make_pair(number_of_node_based_nodes, number_of_edge_based_nodes);
|
||||
return number_of_edge_based_nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -390,57 +390,67 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
|
||||
|
||||
if (in_forward_direction)
|
||||
{ // add (forward) segments or (forward,backward) for non-split edges in backward direction
|
||||
const auto annotation_data_id = external_memory.all_edges_annotation_data_list.size();
|
||||
external_memory.all_edges_annotation_data_list.push_back({name_id,
|
||||
turn_lane_id_forward,
|
||||
forward_classes,
|
||||
parsed_way.forward_travel_mode,
|
||||
parsed_way.is_left_hand_driving});
|
||||
util::for_each_pair(
|
||||
nodes.cbegin(),
|
||||
nodes.cend(),
|
||||
[&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node) {
|
||||
external_memory.all_edges_list.push_back(
|
||||
InternalExtractorEdge(OSMNodeID{static_cast<std::uint64_t>(first_node.ref())},
|
||||
OSMNodeID{static_cast<std::uint64_t>(last_node.ref())},
|
||||
name_id,
|
||||
forward_weight_data,
|
||||
forward_duration_data,
|
||||
true,
|
||||
in_backward_direction && !split_edge,
|
||||
parsed_way.roundabout,
|
||||
parsed_way.circular,
|
||||
parsed_way.is_startpoint,
|
||||
parsed_way.forward_restricted,
|
||||
parsed_way.is_left_hand_driving,
|
||||
split_edge,
|
||||
parsed_way.forward_travel_mode,
|
||||
forward_classes,
|
||||
turn_lane_id_forward,
|
||||
road_classification,
|
||||
{}));
|
||||
NodeBasedEdgeWithOSM edge = {
|
||||
OSMNodeID{static_cast<std::uint64_t>(first_node.ref())},
|
||||
OSMNodeID{static_cast<std::uint64_t>(last_node.ref())},
|
||||
0, // weight
|
||||
0, // duration
|
||||
{}, // geometry id
|
||||
static_cast<AnnotationID>(annotation_data_id),
|
||||
{true,
|
||||
in_backward_direction && !split_edge,
|
||||
split_edge,
|
||||
parsed_way.roundabout,
|
||||
parsed_way.circular,
|
||||
parsed_way.is_startpoint,
|
||||
parsed_way.forward_restricted,
|
||||
road_classification}};
|
||||
|
||||
external_memory.all_edges_list.push_back(InternalExtractorEdge(
|
||||
std::move(edge), forward_weight_data, forward_duration_data, {}));
|
||||
});
|
||||
}
|
||||
|
||||
if (in_backward_direction && (!in_forward_direction || split_edge))
|
||||
{ // add (backward) segments for split edges or not in forward direction
|
||||
const auto annotation_data_id = external_memory.all_edges_annotation_data_list.size();
|
||||
external_memory.all_edges_annotation_data_list.push_back({name_id,
|
||||
turn_lane_id_backward,
|
||||
backward_classes,
|
||||
parsed_way.backward_travel_mode,
|
||||
parsed_way.is_left_hand_driving});
|
||||
util::for_each_pair(
|
||||
nodes.cbegin(),
|
||||
nodes.cend(),
|
||||
[&](const osmium::NodeRef &first_node, const osmium::NodeRef &last_node) {
|
||||
external_memory.all_edges_list.push_back(
|
||||
InternalExtractorEdge(OSMNodeID{static_cast<std::uint64_t>(first_node.ref())},
|
||||
OSMNodeID{static_cast<std::uint64_t>(last_node.ref())},
|
||||
name_id,
|
||||
backward_weight_data,
|
||||
backward_duration_data,
|
||||
false,
|
||||
true,
|
||||
parsed_way.roundabout,
|
||||
parsed_way.circular,
|
||||
parsed_way.is_startpoint,
|
||||
parsed_way.backward_restricted,
|
||||
parsed_way.is_left_hand_driving,
|
||||
split_edge,
|
||||
parsed_way.backward_travel_mode,
|
||||
backward_classes,
|
||||
turn_lane_id_backward,
|
||||
road_classification,
|
||||
{}));
|
||||
NodeBasedEdgeWithOSM edge = {
|
||||
OSMNodeID{static_cast<std::uint64_t>(first_node.ref())},
|
||||
OSMNodeID{static_cast<std::uint64_t>(last_node.ref())},
|
||||
0, // weight
|
||||
0, // duration
|
||||
{}, // geometry id
|
||||
static_cast<AnnotationID>(annotation_data_id),
|
||||
{false,
|
||||
true,
|
||||
split_edge,
|
||||
parsed_way.roundabout,
|
||||
parsed_way.circular,
|
||||
parsed_way.is_startpoint,
|
||||
parsed_way.backward_restricted,
|
||||
road_classification}};
|
||||
|
||||
external_memory.all_edges_list.push_back(InternalExtractorEdge(
|
||||
std::move(edge), backward_weight_data, backward_duration_data, {}));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@ void GraphCompressor::Compress(
|
||||
std::vector<TurnRestriction> &turn_restrictions,
|
||||
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
|
||||
util::NodeBasedDynamicGraph &graph,
|
||||
const std::vector<NodeBasedEdgeAnnotation> &node_data_container,
|
||||
CompressedEdgeContainer &geometry_compressor)
|
||||
{
|
||||
const unsigned original_number_of_nodes = graph.GetNumberOfNodes();
|
||||
@ -104,6 +105,7 @@ void GraphCompressor::Compress(
|
||||
BOOST_ASSERT(forward_e2 >= graph.BeginEdges(node_v) &&
|
||||
forward_e2 < graph.EndEdges(node_v));
|
||||
const EdgeID reverse_e2 = graph.BeginEdges(node_v) + 1 - reverse_edge_order;
|
||||
|
||||
BOOST_ASSERT(SPECIAL_EDGEID != reverse_e2);
|
||||
BOOST_ASSERT(reverse_e2 >= graph.BeginEdges(node_v) &&
|
||||
reverse_e2 < graph.EndEdges(node_v));
|
||||
@ -127,6 +129,10 @@ void GraphCompressor::Compress(
|
||||
|
||||
const EdgeData &fwd_edge_data1 = graph.GetEdgeData(forward_e1);
|
||||
const EdgeData &rev_edge_data1 = graph.GetEdgeData(reverse_e1);
|
||||
const auto fwd_annotation_data1 = node_data_container[fwd_edge_data1.annotation_data];
|
||||
const auto fwd_annotation_data2 = node_data_container[fwd_edge_data2.annotation_data];
|
||||
const auto rev_annotation_data1 = node_data_container[rev_edge_data1.annotation_data];
|
||||
const auto rev_annotation_data2 = node_data_container[rev_edge_data2.annotation_data];
|
||||
|
||||
if (graph.FindEdgeInEitherDirection(node_u, node_w) != SPECIAL_EDGEID)
|
||||
{
|
||||
@ -134,20 +140,22 @@ void GraphCompressor::Compress(
|
||||
}
|
||||
|
||||
// this case can happen if two ways with different names overlap
|
||||
if (fwd_edge_data1.name_id != rev_edge_data1.name_id ||
|
||||
fwd_edge_data2.name_id != rev_edge_data2.name_id)
|
||||
if ((fwd_annotation_data1.name_id != rev_annotation_data1.name_id) ||
|
||||
(fwd_annotation_data2.name_id != rev_annotation_data2.name_id))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fwd_edge_data1.CanCombineWith(fwd_edge_data2) &&
|
||||
rev_edge_data1.CanCombineWith(rev_edge_data2))
|
||||
if ((fwd_edge_data1.flags == fwd_edge_data2.flags) &&
|
||||
(rev_edge_data1.flags == rev_edge_data2.flags) &&
|
||||
(fwd_edge_data1.reversed == fwd_edge_data2.reversed) &&
|
||||
(rev_edge_data1.reversed == rev_edge_data2.reversed) &&
|
||||
// annotations need to match, except for the lane-id which can differ
|
||||
fwd_annotation_data1.CanCombineWith(fwd_annotation_data2) &&
|
||||
rev_annotation_data1.CanCombineWith(rev_annotation_data2))
|
||||
{
|
||||
BOOST_ASSERT(graph.GetEdgeData(forward_e1).name_id ==
|
||||
graph.GetEdgeData(reverse_e1).name_id);
|
||||
BOOST_ASSERT(graph.GetEdgeData(forward_e2).name_id ==
|
||||
graph.GetEdgeData(reverse_e2).name_id);
|
||||
|
||||
BOOST_ASSERT(!(graph.GetEdgeData(forward_e1).reversed &&
|
||||
graph.GetEdgeData(reverse_e1).reversed));
|
||||
/*
|
||||
* Remember Lane Data for compressed parts. This handles scenarios where lane-data
|
||||
* is
|
||||
@ -175,24 +183,26 @@ void GraphCompressor::Compress(
|
||||
* just
|
||||
* like a barrier.
|
||||
*/
|
||||
const auto selectLaneID = [](const LaneDescriptionID front,
|
||||
const LaneDescriptionID back) {
|
||||
const auto selectAnnotation = [&node_data_container](
|
||||
const AnnotationID front_annotation, const AnnotationID back_annotation) {
|
||||
// A lane has tags: u - (front) - v - (back) - w
|
||||
// During contraction, we keep only one of the tags. Usually the one closer to
|
||||
// the
|
||||
// intersection is preferred. If its empty, however, we keep the non-empty one
|
||||
if (back == INVALID_LANE_DESCRIPTIONID)
|
||||
return front;
|
||||
return back;
|
||||
// the intersection is preferred. If its empty, however, we keep the non-empty
|
||||
// one
|
||||
if (node_data_container[back_annotation].lane_description_id ==
|
||||
INVALID_LANE_DESCRIPTIONID)
|
||||
return front_annotation;
|
||||
return back_annotation;
|
||||
};
|
||||
graph.GetEdgeData(forward_e1).lane_description_id = selectLaneID(
|
||||
fwd_edge_data1.lane_description_id, fwd_edge_data2.lane_description_id);
|
||||
graph.GetEdgeData(reverse_e1).lane_description_id = selectLaneID(
|
||||
rev_edge_data1.lane_description_id, rev_edge_data2.lane_description_id);
|
||||
graph.GetEdgeData(forward_e2).lane_description_id = selectLaneID(
|
||||
fwd_edge_data2.lane_description_id, fwd_edge_data1.lane_description_id);
|
||||
graph.GetEdgeData(reverse_e2).lane_description_id = selectLaneID(
|
||||
rev_edge_data2.lane_description_id, rev_edge_data1.lane_description_id);
|
||||
|
||||
graph.GetEdgeData(forward_e1).annotation_data = selectAnnotation(
|
||||
fwd_edge_data1.annotation_data, fwd_edge_data2.annotation_data);
|
||||
graph.GetEdgeData(reverse_e1).annotation_data = selectAnnotation(
|
||||
rev_edge_data1.annotation_data, rev_edge_data2.annotation_data);
|
||||
graph.GetEdgeData(forward_e2).annotation_data = selectAnnotation(
|
||||
fwd_edge_data2.annotation_data, fwd_edge_data1.annotation_data);
|
||||
graph.GetEdgeData(reverse_e2).annotation_data = selectAnnotation(
|
||||
rev_edge_data2.annotation_data, rev_edge_data1.annotation_data);
|
||||
|
||||
/*
|
||||
// Do not compress edge if it crosses a traffic signal.
|
||||
@ -206,14 +216,15 @@ void GraphCompressor::Compress(
|
||||
if (has_node_penalty)
|
||||
{
|
||||
// we cannot handle this as node penalty, if it depends on turn direction
|
||||
if (fwd_edge_data1.restricted != fwd_edge_data2.restricted)
|
||||
if (fwd_edge_data1.flags.restricted != fwd_edge_data2.flags.restricted)
|
||||
continue;
|
||||
|
||||
// generate an artifical turn for the turn penalty generation
|
||||
ExtractionTurn extraction_turn(true,
|
||||
fwd_edge_data1.restricted,
|
||||
fwd_edge_data2.restricted,
|
||||
fwd_edge_data1.is_left_hand_driving);
|
||||
ExtractionTurn extraction_turn(
|
||||
true,
|
||||
fwd_edge_data1.flags.restricted,
|
||||
fwd_edge_data2.flags.restricted,
|
||||
node_data_container[fwd_edge_data1.annotation_data].is_left_hand_driving);
|
||||
|
||||
scripting_environment.ProcessTurn(extraction_turn);
|
||||
node_duration_penalty = extraction_turn.duration * 10;
|
||||
|
@ -122,7 +122,7 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
|
||||
// coordinate set to add a small level of fault tolerance
|
||||
const constexpr double skipping_inaccuracies_distance = 2;
|
||||
|
||||
const auto &turn_edge_data = node_based_graph.GetEdgeData(turn_edge);
|
||||
const auto &turn_edge_data = node_based_graph.GetEdgeData(turn_edge).flags;
|
||||
|
||||
// roundabouts, check early to avoid other costly checks
|
||||
if (turn_edge_data.roundabout || turn_edge_data.circular)
|
||||
@ -175,7 +175,7 @@ util::Coordinate CoordinateExtractor::ExtractRepresentativeCoordinate(
|
||||
// the lane count might not always be set. We need to assume a positive number, though. Here we
|
||||
// select the number of lanes to operate on
|
||||
const auto considered_lanes =
|
||||
GetOffsetCorrectionFactor(node_based_graph.GetEdgeData(turn_edge).road_classification) *
|
||||
GetOffsetCorrectionFactor(turn_edge_data.road_classification) *
|
||||
((intersection_lanes == 0) ? ASSUMED_LANE_COUNT : intersection_lanes);
|
||||
|
||||
/* if the very first coordinate along the road is reasonably far away from the road, we assume
|
||||
@ -644,7 +644,7 @@ bool CoordinateExtractor::IsCurve(const std::vector<util::Coordinate> &coordinat
|
||||
const std::vector<double> &segment_distances,
|
||||
const double segment_length,
|
||||
const double considered_lane_width,
|
||||
const util::NodeBasedEdgeData &edge_data) const
|
||||
const extractor::NodeBasedEdgeClassification &edge_data) const
|
||||
{
|
||||
BOOST_ASSERT(coordinates.size() > 2);
|
||||
|
||||
|
@ -14,10 +14,12 @@ namespace guidance
|
||||
|
||||
DrivewayHandler::DrivewayHandler(const IntersectionGenerator &intersection_generator,
|
||||
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const std::vector<util::Coordinate> &coordinates,
|
||||
const util::NameTable &name_table,
|
||||
const SuffixTable &street_name_suffix_table)
|
||||
: IntersectionHandler(node_based_graph,
|
||||
node_data_container,
|
||||
coordinates,
|
||||
name_table,
|
||||
street_name_suffix_table,
|
||||
@ -38,13 +40,13 @@ bool DrivewayHandler::canProcess(const NodeID /*nid*/,
|
||||
const auto from_eid = intersection.getUTurnRoad().eid;
|
||||
|
||||
if (intersection.size() <= 2 ||
|
||||
node_based_graph.GetEdgeData(from_eid).road_classification.IsLowPriorityRoadClass())
|
||||
node_based_graph.GetEdgeData(from_eid).flags.road_classification.IsLowPriorityRoadClass())
|
||||
return false;
|
||||
|
||||
auto low_priority_count =
|
||||
std::count_if(intersection.begin(), intersection.end(), [this](const auto &road) {
|
||||
return node_based_graph.GetEdgeData(road.eid)
|
||||
.road_classification.IsLowPriorityRoadClass();
|
||||
.flags.road_classification.IsLowPriorityRoadClass();
|
||||
});
|
||||
|
||||
// Process intersection if it has two edges with normal priority and one is the entry edge,
|
||||
@ -58,7 +60,7 @@ operator()(const NodeID nid, const EdgeID source_edge_id, Intersection intersect
|
||||
auto road =
|
||||
std::find_if(intersection.begin() + 1, intersection.end(), [this](const auto &road) {
|
||||
return !node_based_graph.GetEdgeData(road.eid)
|
||||
.road_classification.IsLowPriorityRoadClass();
|
||||
.flags.road_classification.IsLowPriorityRoadClass();
|
||||
});
|
||||
|
||||
(void)nid;
|
||||
|
@ -33,12 +33,13 @@ const constexpr bool USE_HIGH_PRECISION_MODE = !USE_LOW_PRECISION_MODE;
|
||||
|
||||
IntersectionGenerator::IntersectionGenerator(
|
||||
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const RestrictionMap &restriction_map,
|
||||
const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const std::vector<util::Coordinate> &coordinates,
|
||||
const CompressedEdgeContainer &compressed_edge_container)
|
||||
: node_based_graph(node_based_graph), restriction_map(restriction_map),
|
||||
barrier_nodes(barrier_nodes), coordinates(coordinates),
|
||||
: node_based_graph(node_based_graph), node_data_container(node_data_container),
|
||||
restriction_map(restriction_map), barrier_nodes(barrier_nodes), coordinates(coordinates),
|
||||
coordinate_extractor(node_based_graph, compressed_edge_container, coordinates)
|
||||
{
|
||||
}
|
||||
@ -69,15 +70,15 @@ IntersectionGenerator::ComputeIntersectionShape(const NodeID node_at_center_of_i
|
||||
|
||||
// number of lanes at the intersection changes how far we look down the road
|
||||
const auto edge_range = node_based_graph.GetAdjacentEdgeRange(node_at_center_of_intersection);
|
||||
const auto max_lanes_intersection = std::accumulate(
|
||||
edge_range.begin(),
|
||||
edge_range.end(),
|
||||
std::uint8_t{0},
|
||||
[this](const auto current_max, const auto current_eid) {
|
||||
return std::max(
|
||||
current_max,
|
||||
node_based_graph.GetEdgeData(current_eid).road_classification.GetNumberOfLanes());
|
||||
});
|
||||
const auto max_lanes_intersection =
|
||||
std::accumulate(edge_range.begin(),
|
||||
edge_range.end(),
|
||||
std::uint8_t{0},
|
||||
[this](const auto current_max, const auto current_eid) {
|
||||
return std::max(current_max,
|
||||
node_based_graph.GetEdgeData(current_eid)
|
||||
.flags.road_classification.GetNumberOfLanes());
|
||||
});
|
||||
|
||||
for (const EdgeID edge_connected_to_intersection :
|
||||
node_based_graph.GetAdjacentEdgeRange(node_at_center_of_intersection))
|
||||
@ -265,9 +266,11 @@ IntersectionGenerator::SkipDegreeTwoNodes(const NodeID starting_node, const Edge
|
||||
query_node = next_node;
|
||||
query_edge = next_edge;
|
||||
|
||||
if (!node_based_graph.GetEdgeData(query_edge)
|
||||
.IsCompatibleTo(node_based_graph.GetEdgeData(next_edge)) ||
|
||||
node_based_graph.GetTarget(next_edge) == starting_node)
|
||||
// check if there is a relevant change in the graph
|
||||
if (!CanBeCompressed(node_based_graph.GetEdgeData(query_edge),
|
||||
node_based_graph.GetEdgeData(next_edge),
|
||||
node_data_container) ||
|
||||
(node_based_graph.GetTarget(next_edge) == starting_node))
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -24,21 +24,38 @@ namespace guidance
|
||||
|
||||
namespace detail
|
||||
{
|
||||
inline bool requiresAnnouncement(const EdgeData &from, const EdgeData &to)
|
||||
// TODO check flags!
|
||||
inline bool requiresAnnouncement(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const EdgeID from,
|
||||
const EdgeID to)
|
||||
{
|
||||
return !from.CanCombineWith(to);
|
||||
}
|
||||
const auto &from_edge = node_based_graph.GetEdgeData(from);
|
||||
const auto &to_edge = node_based_graph.GetEdgeData(to);
|
||||
|
||||
if (from_edge.reversed != to_edge.reversed)
|
||||
return true;
|
||||
|
||||
if (!(from_edge.flags == to_edge.flags))
|
||||
return true;
|
||||
|
||||
const auto &annotation_from = node_data_container.GetAnnotation(from_edge.annotation_data);
|
||||
const auto &annotation_to = node_data_container.GetAnnotation(to_edge.annotation_data);
|
||||
return !annotation_from.CanCombineWith(annotation_to);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
IntersectionHandler::IntersectionHandler(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const std::vector<util::Coordinate> &coordinates,
|
||||
const util::NameTable &name_table,
|
||||
const SuffixTable &street_name_suffix_table,
|
||||
const IntersectionGenerator &intersection_generator)
|
||||
: node_based_graph(node_based_graph), coordinates(coordinates), name_table(name_table),
|
||||
: node_based_graph(node_based_graph), node_data_container(node_data_container),
|
||||
coordinates(coordinates), name_table(name_table),
|
||||
street_name_suffix_table(street_name_suffix_table),
|
||||
intersection_generator(intersection_generator),
|
||||
graph_walker(node_based_graph, intersection_generator)
|
||||
graph_walker(node_based_graph, node_data_container, intersection_generator)
|
||||
{
|
||||
}
|
||||
|
||||
@ -48,20 +65,23 @@ TurnType::Enum IntersectionHandler::findBasicTurnType(const EdgeID via_edge,
|
||||
const ConnectedRoad &road) const
|
||||
{
|
||||
|
||||
const auto &in_data = node_based_graph.GetEdgeData(via_edge);
|
||||
const auto &out_data = node_based_graph.GetEdgeData(road.eid);
|
||||
|
||||
bool on_ramp = in_data.road_classification.IsRampClass();
|
||||
|
||||
bool onto_ramp = out_data.road_classification.IsRampClass();
|
||||
bool on_ramp = node_based_graph.GetEdgeData(via_edge).flags.road_classification.IsRampClass();
|
||||
bool onto_ramp = node_based_graph.GetEdgeData(road.eid).flags.road_classification.IsRampClass();
|
||||
|
||||
if (!on_ramp && onto_ramp)
|
||||
return TurnType::OnRamp;
|
||||
|
||||
const auto same_name = !util::guidance::requiresNameAnnounced(
|
||||
in_data.name_id, out_data.name_id, name_table, street_name_suffix_table);
|
||||
const auto &in_name =
|
||||
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(via_edge).annotation_data)
|
||||
.name_id;
|
||||
const auto &out_name =
|
||||
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data)
|
||||
.name_id;
|
||||
|
||||
if (in_data.name_id != EMPTY_NAMEID && out_data.name_id != EMPTY_NAMEID && same_name)
|
||||
const auto same_name = !util::guidance::requiresNameAnnounced(
|
||||
in_name, out_name, name_table, street_name_suffix_table);
|
||||
|
||||
if (in_name != EMPTY_NAMEID && out_name != EMPTY_NAMEID && same_name)
|
||||
{
|
||||
return TurnType::Continue;
|
||||
}
|
||||
@ -86,14 +106,22 @@ TurnInstruction IntersectionHandler::getInstructionForObvious(const std::size_t
|
||||
}
|
||||
|
||||
// handle travel modes:
|
||||
const auto in_mode = node_based_graph.GetEdgeData(via_edge).travel_mode;
|
||||
const auto out_mode = node_based_graph.GetEdgeData(road.eid).travel_mode;
|
||||
const auto in_mode =
|
||||
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(via_edge).annotation_data)
|
||||
.travel_mode;
|
||||
const auto out_mode =
|
||||
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data)
|
||||
.travel_mode;
|
||||
const auto needs_notification = in_mode != out_mode;
|
||||
|
||||
if (type == TurnType::Turn)
|
||||
{
|
||||
const auto &in_data = node_based_graph.GetEdgeData(via_edge);
|
||||
const auto &out_data = node_based_graph.GetEdgeData(road.eid);
|
||||
const auto &in_classification = node_based_graph.GetEdgeData(via_edge).flags;
|
||||
const auto &in_data = node_data_container.GetAnnotation(
|
||||
node_based_graph.GetEdgeData(via_edge).annotation_data);
|
||||
const auto &out_classification = node_based_graph.GetEdgeData(road.eid).flags;
|
||||
const auto &out_data = node_data_container.GetAnnotation(
|
||||
node_based_graph.GetEdgeData(road.eid).annotation_data);
|
||||
|
||||
if (util::guidance::requiresNameAnnounced(
|
||||
in_data.name_id, out_data.name_id, name_table, street_name_suffix_table))
|
||||
@ -104,12 +132,12 @@ TurnInstruction IntersectionHandler::getInstructionForObvious(const std::size_t
|
||||
// We reserve merges for motorway types. All others are considered for simply going
|
||||
// straight onto a road. This avoids confusion about merge directions on streets
|
||||
// that could potentially also offer different choices
|
||||
if (out_data.road_classification.IsMotorwayClass())
|
||||
if (out_classification.road_classification.IsMotorwayClass())
|
||||
return {TurnType::Merge,
|
||||
road.angle > STRAIGHT_ANGLE ? DirectionModifier::SlightRight
|
||||
: DirectionModifier::SlightLeft};
|
||||
else if (in_data.road_classification.IsRampClass() &&
|
||||
out_data.road_classification.IsRampClass())
|
||||
else if (in_classification.road_classification.IsRampClass() &&
|
||||
out_classification.road_classification.IsRampClass())
|
||||
{
|
||||
// This check is more a precaution than anything else. Our current travel modes
|
||||
// cannot reach this, since all ramps are exposing the same travel type. But we
|
||||
@ -177,15 +205,20 @@ void IntersectionHandler::assignFork(const EdgeID via_edge,
|
||||
ConnectedRoad &left,
|
||||
ConnectedRoad &right) const
|
||||
{
|
||||
const auto &in_data = node_based_graph.GetEdgeData(via_edge);
|
||||
const bool low_priority_left =
|
||||
node_based_graph.GetEdgeData(left.eid).road_classification.IsLowPriorityRoadClass();
|
||||
const bool low_priority_right =
|
||||
node_based_graph.GetEdgeData(right.eid).road_classification.IsLowPriorityRoadClass();
|
||||
const auto same_mode_left =
|
||||
in_data.travel_mode == node_based_graph.GetEdgeData(left.eid).travel_mode;
|
||||
const auto same_mode_right =
|
||||
in_data.travel_mode == node_based_graph.GetEdgeData(right.eid).travel_mode;
|
||||
const auto &in_data =
|
||||
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(via_edge).annotation_data);
|
||||
const auto &lhs_classification =
|
||||
node_based_graph.GetEdgeData(left.eid).flags.road_classification;
|
||||
const auto &lhs_data =
|
||||
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(left.eid).annotation_data);
|
||||
const auto &rhs_classification =
|
||||
node_based_graph.GetEdgeData(right.eid).flags.road_classification;
|
||||
const auto &rhs_data =
|
||||
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(right.eid).annotation_data);
|
||||
const bool low_priority_left = lhs_classification.IsLowPriorityRoadClass();
|
||||
const bool low_priority_right = rhs_classification.IsLowPriorityRoadClass();
|
||||
const auto same_mode_left = in_data.travel_mode == lhs_data.travel_mode;
|
||||
const auto same_mode_right = in_data.travel_mode == rhs_data.travel_mode;
|
||||
const auto suppressed_left_type =
|
||||
same_mode_left ? TurnType::Suppressed : TurnType::Notification;
|
||||
const auto suppressed_right_type =
|
||||
@ -194,8 +227,7 @@ void IntersectionHandler::assignFork(const EdgeID via_edge,
|
||||
angularDeviation(right.angle, STRAIGHT_ANGLE) > FUZZY_ANGLE_DIFFERENCE))
|
||||
{
|
||||
// left side is actually straight
|
||||
const auto &out_data = node_based_graph.GetEdgeData(left.eid);
|
||||
if (detail::requiresAnnouncement(in_data, out_data))
|
||||
if (detail::requiresAnnouncement(node_based_graph, node_data_container, via_edge, left.eid))
|
||||
{
|
||||
if (low_priority_right && !low_priority_left)
|
||||
{
|
||||
@ -230,11 +262,11 @@ void IntersectionHandler::assignFork(const EdgeID via_edge,
|
||||
angularDeviation(left.angle, STRAIGHT_ANGLE) > FUZZY_ANGLE_DIFFERENCE)
|
||||
{
|
||||
// right side is actually straight
|
||||
const auto &out_data = node_based_graph.GetEdgeData(right.eid);
|
||||
if (angularDeviation(right.angle, STRAIGHT_ANGLE) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION &&
|
||||
angularDeviation(left.angle, STRAIGHT_ANGLE) > FUZZY_ANGLE_DIFFERENCE)
|
||||
{
|
||||
if (detail::requiresAnnouncement(in_data, out_data))
|
||||
if (detail::requiresAnnouncement(
|
||||
node_based_graph, node_data_container, via_edge, right.eid))
|
||||
{
|
||||
if (low_priority_left && !low_priority_right)
|
||||
{
|
||||
@ -304,8 +336,14 @@ void IntersectionHandler::assignFork(const EdgeID via_edge,
|
||||
{
|
||||
// TODO handle low priority road classes in a reasonable way
|
||||
const auto suppressed_type = [&](const ConnectedRoad &road) {
|
||||
const auto in_mode = node_based_graph.GetEdgeData(via_edge).travel_mode;
|
||||
const auto out_mode = node_based_graph.GetEdgeData(road.eid).travel_mode;
|
||||
const auto in_mode =
|
||||
node_data_container
|
||||
.GetAnnotation(node_based_graph.GetEdgeData(via_edge).annotation_data)
|
||||
.travel_mode;
|
||||
const auto out_mode =
|
||||
node_data_container
|
||||
.GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data)
|
||||
.travel_mode;
|
||||
return in_mode == out_mode ? TurnType::Suppressed : TurnType::Notification;
|
||||
};
|
||||
|
||||
@ -314,9 +352,8 @@ void IntersectionHandler::assignFork(const EdgeID via_edge,
|
||||
left.instruction = {TurnType::Fork, DirectionModifier::SlightLeft};
|
||||
if (angularDeviation(center.angle, 180) < MAXIMAL_ALLOWED_NO_TURN_DEVIATION)
|
||||
{
|
||||
const auto &in_data = node_based_graph.GetEdgeData(via_edge);
|
||||
const auto &out_data = node_based_graph.GetEdgeData(center.eid);
|
||||
if (detail::requiresAnnouncement(in_data, out_data))
|
||||
if (detail::requiresAnnouncement(
|
||||
node_based_graph, node_data_container, via_edge, center.eid))
|
||||
{
|
||||
center.instruction = {TurnType::Fork, DirectionModifier::Straight};
|
||||
}
|
||||
@ -371,7 +408,8 @@ void IntersectionHandler::assignTrivialTurns(const EdgeID via_eid,
|
||||
bool IntersectionHandler::isThroughStreet(const std::size_t index,
|
||||
const Intersection &intersection) const
|
||||
{
|
||||
const auto &data_at_index = node_based_graph.GetEdgeData(intersection[index].eid);
|
||||
const auto &data_at_index = node_data_container.GetAnnotation(
|
||||
node_based_graph.GetEdgeData(intersection[index].eid).annotation_data);
|
||||
|
||||
if (data_at_index.name_id == EMPTY_NAMEID)
|
||||
return false;
|
||||
@ -383,7 +421,8 @@ bool IntersectionHandler::isThroughStreet(const std::size_t index,
|
||||
continue;
|
||||
|
||||
const auto &road = intersection[road_index];
|
||||
const auto &road_data = node_based_graph.GetEdgeData(road.eid);
|
||||
const auto &road_data = node_data_container.GetAnnotation(
|
||||
node_based_graph.GetEdgeData(road.eid).annotation_data);
|
||||
|
||||
// roads have a near straight angle (180 degree)
|
||||
const bool is_nearly_straight = angularDeviation(road.angle, intersection[index].angle) >
|
||||
@ -395,7 +434,8 @@ bool IntersectionHandler::isThroughStreet(const std::size_t index,
|
||||
data_at_index.name_id, road_data.name_id, name_table, street_name_suffix_table);
|
||||
|
||||
const bool have_same_category =
|
||||
data_at_index.road_classification == road_data.road_classification;
|
||||
node_based_graph.GetEdgeData(intersection[index].eid).flags.road_classification ==
|
||||
node_based_graph.GetEdgeData(road.eid).flags.road_classification;
|
||||
|
||||
if (is_nearly_straight && have_same_name && have_same_category)
|
||||
return true;
|
||||
@ -443,8 +483,10 @@ IntersectionHandler::getNextIntersection(const NodeID at, const EdgeID via) cons
|
||||
|
||||
bool IntersectionHandler::isSameName(const EdgeID source_edge_id, const EdgeID target_edge_id) const
|
||||
{
|
||||
const auto &source_edge_data = node_based_graph.GetEdgeData(source_edge_id);
|
||||
const auto &target_edge_data = node_based_graph.GetEdgeData(target_edge_id);
|
||||
const auto &source_edge_data = node_data_container.GetAnnotation(
|
||||
node_based_graph.GetEdgeData(source_edge_id).annotation_data);
|
||||
const auto &target_edge_data = node_data_container.GetAnnotation(
|
||||
node_based_graph.GetEdgeData(target_edge_id).annotation_data);
|
||||
|
||||
return source_edge_data.name_id != EMPTY_NAMEID && //
|
||||
target_edge_data.name_id != EMPTY_NAMEID && //
|
||||
|
@ -14,13 +14,16 @@ namespace extractor
|
||||
namespace guidance
|
||||
{
|
||||
|
||||
IntersectionNormalizer::IntersectionNormalizer(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const std::vector<util::Coordinate> &coordinates,
|
||||
const util::NameTable &name_table,
|
||||
const SuffixTable &street_name_suffix_table,
|
||||
const IntersectionGenerator &intersection_generator)
|
||||
IntersectionNormalizer::IntersectionNormalizer(
|
||||
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const std::vector<util::Coordinate> &coordinates,
|
||||
const util::NameTable &name_table,
|
||||
const SuffixTable &street_name_suffix_table,
|
||||
const IntersectionGenerator &intersection_generator)
|
||||
: node_based_graph(node_based_graph), intersection_generator(intersection_generator),
|
||||
mergable_road_detector(node_based_graph,
|
||||
node_data_container,
|
||||
coordinates,
|
||||
intersection_generator,
|
||||
intersection_generator.GetCoordinateExtractor(),
|
||||
|
@ -25,13 +25,17 @@ namespace
|
||||
// check a connected road for equality of a name
|
||||
inline auto makeCheckRoadForName(const NameID name_id,
|
||||
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const util::NameTable &name_table,
|
||||
const SuffixTable &suffix_table)
|
||||
{
|
||||
return [name_id, &node_based_graph, &name_table, &suffix_table](
|
||||
return [name_id, &node_based_graph, &node_data_container, &name_table, &suffix_table](
|
||||
const MergableRoadDetector::MergableRoadData &road) {
|
||||
// since we filter here, we don't want any other name than the one we are looking for
|
||||
const auto road_name = node_based_graph.GetEdgeData(road.eid).name_id;
|
||||
const auto road_name =
|
||||
node_data_container
|
||||
.GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data)
|
||||
.name_id;
|
||||
if (name_id == EMPTY_NAMEID || road_name == EMPTY_NAMEID)
|
||||
return true;
|
||||
const auto requires_announcement =
|
||||
@ -44,14 +48,16 @@ inline auto makeCheckRoadForName(const NameID name_id,
|
||||
}
|
||||
|
||||
MergableRoadDetector::MergableRoadDetector(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const std::vector<util::Coordinate> &node_coordinates,
|
||||
const IntersectionGenerator &intersection_generator,
|
||||
const CoordinateExtractor &coordinate_extractor,
|
||||
const util::NameTable &name_table,
|
||||
const SuffixTable &street_name_suffix_table)
|
||||
: node_based_graph(node_based_graph), node_coordinates(node_coordinates),
|
||||
intersection_generator(intersection_generator), coordinate_extractor(coordinate_extractor),
|
||||
name_table(name_table), street_name_suffix_table(street_name_suffix_table)
|
||||
: node_based_graph(node_based_graph), node_data_container(node_data_container),
|
||||
node_coordinates(node_coordinates), intersection_generator(intersection_generator),
|
||||
coordinate_extractor(coordinate_extractor), name_table(name_table),
|
||||
street_name_suffix_table(street_name_suffix_table)
|
||||
{
|
||||
}
|
||||
|
||||
@ -63,11 +69,14 @@ bool MergableRoadDetector::CanMergeRoad(const NodeID intersection_node,
|
||||
if (angularDeviation(lhs.bearing, rhs.bearing) > MERGABLE_ANGLE_DIFFERENCE)
|
||||
return false;
|
||||
|
||||
const auto &lhs_edge_data = node_based_graph.GetEdgeData(lhs.eid);
|
||||
const auto &rhs_edge_data = node_based_graph.GetEdgeData(rhs.eid);
|
||||
const auto &lhs_edge = node_based_graph.GetEdgeData(lhs.eid);
|
||||
const auto &rhs_edge = node_based_graph.GetEdgeData(rhs.eid);
|
||||
const auto &lhs_edge_data = node_data_container.GetAnnotation(lhs_edge.annotation_data);
|
||||
const auto &rhs_edge_data = node_data_container.GetAnnotation(rhs_edge.annotation_data);
|
||||
|
||||
// and they need to describe the same road
|
||||
if (!EdgeDataSupportsMerge(lhs_edge_data, rhs_edge_data))
|
||||
if ((lhs_edge.reversed == rhs_edge.reversed) ||
|
||||
!EdgeDataSupportsMerge(lhs_edge.flags, rhs_edge.flags, lhs_edge_data, rhs_edge_data))
|
||||
return false;
|
||||
|
||||
/* don't use any circular links, since they mess up detection we jump out early.
|
||||
@ -120,36 +129,36 @@ bool MergableRoadDetector::IsDistinctFrom(const MergableRoadData &lhs,
|
||||
if (angularDeviation(lhs.bearing, rhs.bearing) > MERGABLE_ANGLE_DIFFERENCE)
|
||||
return true;
|
||||
else // or it cannot have the same name
|
||||
return !HaveIdenticalNames(node_based_graph.GetEdgeData(lhs.eid).name_id,
|
||||
node_based_graph.GetEdgeData(rhs.eid).name_id);
|
||||
return !HaveIdenticalNames(
|
||||
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(lhs.eid).annotation_data)
|
||||
.name_id,
|
||||
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(rhs.eid).annotation_data)
|
||||
.name_id);
|
||||
}
|
||||
|
||||
bool MergableRoadDetector::EdgeDataSupportsMerge(const util::NodeBasedEdgeData &lhs_edge_data,
|
||||
const util::NodeBasedEdgeData &rhs_edge_data) const
|
||||
bool MergableRoadDetector::EdgeDataSupportsMerge(
|
||||
const NodeBasedEdgeClassification &lhs_flags,
|
||||
const NodeBasedEdgeClassification &rhs_flags,
|
||||
const NodeBasedEdgeAnnotation &lhs_annotation,
|
||||
const NodeBasedEdgeAnnotation &rhs_annotation) const
|
||||
{
|
||||
// roundabouts are special, simply don't hurt them. We might not want to bear the
|
||||
// consequences
|
||||
if (lhs_edge_data.roundabout || rhs_edge_data.roundabout)
|
||||
return false;
|
||||
|
||||
/* to describe the same road, but in opposite directions (which is what we require for a
|
||||
* merge), the roads have to feature one reversed and one non-reversed edge
|
||||
*/
|
||||
if (lhs_edge_data.reversed == rhs_edge_data.reversed)
|
||||
if (lhs_flags.roundabout || rhs_flags.roundabout)
|
||||
return false;
|
||||
|
||||
/* The travel mode should be the same for both roads. If we were to merge different travel
|
||||
* modes, we would hide information/run the risk of loosing valid choices (e.g. short period
|
||||
* of pushing)
|
||||
*/
|
||||
if (lhs_edge_data.travel_mode != rhs_edge_data.travel_mode)
|
||||
if (lhs_annotation.travel_mode != rhs_annotation.travel_mode)
|
||||
return false;
|
||||
|
||||
// we require valid names
|
||||
if (!HaveIdenticalNames(lhs_edge_data.name_id, rhs_edge_data.name_id))
|
||||
if (!HaveIdenticalNames(lhs_annotation.name_id, rhs_annotation.name_id))
|
||||
return false;
|
||||
|
||||
return lhs_edge_data.road_classification == rhs_edge_data.road_classification;
|
||||
return lhs_flags.road_classification == rhs_flags.road_classification;
|
||||
}
|
||||
|
||||
bool MergableRoadDetector::IsTrafficLoop(const NodeID intersection_node,
|
||||
@ -172,9 +181,13 @@ bool MergableRoadDetector::IsNarrowTriangle(const NodeID intersection_node,
|
||||
* Since both items have the same id, we can `select` based on any setup
|
||||
*/
|
||||
SelectStraightmostRoadByNameAndOnlyChoice selector(
|
||||
node_based_graph.GetEdgeData(lhs.eid).name_id, lhs.bearing, /*requires entry=*/false);
|
||||
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(lhs.eid).annotation_data)
|
||||
.name_id,
|
||||
lhs.bearing,
|
||||
/*requires entry=*/false);
|
||||
|
||||
NodeBasedGraphWalker graph_walker(node_based_graph, intersection_generator);
|
||||
NodeBasedGraphWalker graph_walker(
|
||||
node_based_graph, node_data_container, intersection_generator);
|
||||
graph_walker.TraverseRoad(intersection_node, lhs.eid, left_accumulator, selector);
|
||||
/* if the intersection does not have a right turn, we continue onto the next one once
|
||||
* (skipping over a single small side street)
|
||||
@ -231,7 +244,7 @@ bool MergableRoadDetector::IsNarrowTriangle(const NodeID intersection_node,
|
||||
|
||||
const auto num_lanes = [this](const MergableRoadData &road) {
|
||||
return std::max<std::uint8_t>(
|
||||
node_based_graph.GetEdgeData(road.eid).road_classification.GetNumberOfLanes(), 1);
|
||||
node_based_graph.GetEdgeData(road.eid).flags.road_classification.GetNumberOfLanes(), 1);
|
||||
};
|
||||
|
||||
// the width we can bridge at the intersection
|
||||
@ -265,11 +278,15 @@ bool MergableRoadDetector::HaveSameDirection(const NodeID intersection_node,
|
||||
return false;
|
||||
|
||||
// Find a coordinate following a road that is far away
|
||||
NodeBasedGraphWalker graph_walker(node_based_graph, intersection_generator);
|
||||
NodeBasedGraphWalker graph_walker(
|
||||
node_based_graph, node_data_container, intersection_generator);
|
||||
const auto getCoordinatesAlongWay = [&](const EdgeID edge_id, const double max_length) {
|
||||
LengthLimitedCoordinateAccumulator accumulator(coordinate_extractor, max_length);
|
||||
SelectStraightmostRoadByNameAndOnlyChoice selector(
|
||||
node_based_graph.GetEdgeData(edge_id).name_id, lhs.bearing, /*requires_entry=*/false);
|
||||
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(edge_id).annotation_data)
|
||||
.name_id,
|
||||
lhs.bearing,
|
||||
/*requires_entry=*/false);
|
||||
graph_walker.TraverseRoad(intersection_node, edge_id, accumulator, selector);
|
||||
|
||||
return std::make_pair(accumulator.accumulated_length, accumulator.coordinates);
|
||||
@ -342,9 +359,9 @@ bool MergableRoadDetector::HaveSameDirection(const NodeID intersection_node,
|
||||
coordinates_to_the_right.end());
|
||||
|
||||
const auto lane_count_lhs = std::max<int>(
|
||||
1, node_based_graph.GetEdgeData(lhs.eid).road_classification.GetNumberOfLanes());
|
||||
1, node_based_graph.GetEdgeData(lhs.eid).flags.road_classification.GetNumberOfLanes());
|
||||
const auto lane_count_rhs = std::max<int>(
|
||||
1, node_based_graph.GetEdgeData(rhs.eid).road_classification.GetNumberOfLanes());
|
||||
1, node_based_graph.GetEdgeData(rhs.eid).flags.road_classification.GetNumberOfLanes());
|
||||
|
||||
const auto combined_road_width = 0.5 * (lane_count_lhs + lane_count_rhs) * ASSUMED_LANE_WIDTH;
|
||||
const auto constexpr MAXIMAL_ALLOWED_SEPARATION_WIDTH = 8;
|
||||
@ -380,10 +397,16 @@ bool MergableRoadDetector::IsTrafficIsland(const NodeID intersection_node,
|
||||
|
||||
// check if all items share a name
|
||||
const auto range = node_based_graph.GetAdjacentEdgeRange(nid);
|
||||
const auto required_name_id = node_based_graph.GetEdgeData(range.front()).name_id;
|
||||
const auto required_name_id =
|
||||
node_data_container
|
||||
.GetAnnotation(node_based_graph.GetEdgeData(range.front()).annotation_data)
|
||||
.name_id;
|
||||
|
||||
const auto has_required_name = [this, required_name_id](const auto edge_id) {
|
||||
const auto road_name = node_based_graph.GetEdgeData(edge_id).name_id;
|
||||
const auto road_name =
|
||||
node_data_container
|
||||
.GetAnnotation(node_based_graph.GetEdgeData(edge_id).annotation_data)
|
||||
.name_id;
|
||||
if (required_name_id == EMPTY_NAMEID || road_name == EMPTY_NAMEID)
|
||||
return false;
|
||||
return !util::guidance::requiresNameAnnounced(
|
||||
@ -428,14 +451,19 @@ bool MergableRoadDetector::IsLinkRoad(const NodeID intersection_node,
|
||||
const auto next_intersection_along_road = intersection_generator.GetConnectedRoads(
|
||||
next_intersection_parameters.nid, next_intersection_parameters.via_eid);
|
||||
const auto extract_name_id = [this](const MergableRoadData &road) {
|
||||
return node_based_graph.GetEdgeData(road.eid).name_id;
|
||||
return node_data_container
|
||||
.GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data)
|
||||
.name_id;
|
||||
};
|
||||
|
||||
const auto requested_name_id = extract_name_id(road);
|
||||
const auto next_road_along_path = next_intersection_along_road.findClosestTurn(
|
||||
STRAIGHT_ANGLE,
|
||||
makeCheckRoadForName(
|
||||
requested_name_id, node_based_graph, name_table, street_name_suffix_table));
|
||||
makeCheckRoadForName(requested_name_id,
|
||||
node_based_graph,
|
||||
node_data_container,
|
||||
name_table,
|
||||
street_name_suffix_table));
|
||||
|
||||
// we need to have a continuing road to successfully detect a link road
|
||||
if (next_road_along_path == next_intersection_along_road.end())
|
||||
@ -460,9 +488,16 @@ bool MergableRoadDetector::IsLinkRoad(const NodeID intersection_node,
|
||||
// near straight road that continues
|
||||
return angularDeviation(opposite_of_next_road_along_path->angle, next_road_along_path->angle) >=
|
||||
(STRAIGHT_ANGLE - FUZZY_ANGLE_DIFFERENCE) &&
|
||||
(node_based_graph.GetEdgeData(next_road_along_path->eid).reversed ==
|
||||
node_based_graph.GetEdgeData(opposite_of_next_road_along_path->eid).reversed) &&
|
||||
EdgeDataSupportsMerge(
|
||||
node_based_graph.GetEdgeData(next_road_along_path->eid),
|
||||
node_based_graph.GetEdgeData(opposite_of_next_road_along_path->eid));
|
||||
node_based_graph.GetEdgeData(next_road_along_path->eid).flags,
|
||||
node_based_graph.GetEdgeData(opposite_of_next_road_along_path->eid).flags,
|
||||
node_data_container.GetAnnotation(
|
||||
node_based_graph.GetEdgeData(next_road_along_path->eid).annotation_data),
|
||||
node_data_container.GetAnnotation(
|
||||
node_based_graph.GetEdgeData(opposite_of_next_road_along_path->eid)
|
||||
.annotation_data));
|
||||
}
|
||||
|
||||
} // namespace guidance
|
||||
|
@ -24,27 +24,29 @@ namespace
|
||||
|
||||
inline bool isMotorwayClass(EdgeID eid, const util::NodeBasedDynamicGraph &node_based_graph)
|
||||
{
|
||||
return node_based_graph.GetEdgeData(eid).road_classification.IsMotorwayClass();
|
||||
return node_based_graph.GetEdgeData(eid).flags.road_classification.IsMotorwayClass();
|
||||
}
|
||||
inline RoadClassification roadClass(const ConnectedRoad &road,
|
||||
const util::NodeBasedDynamicGraph &graph)
|
||||
{
|
||||
return graph.GetEdgeData(road.eid).road_classification;
|
||||
return graph.GetEdgeData(road.eid).flags.road_classification;
|
||||
}
|
||||
|
||||
inline bool isRampClass(EdgeID eid, const util::NodeBasedDynamicGraph &node_based_graph)
|
||||
{
|
||||
return node_based_graph.GetEdgeData(eid).road_classification.IsRampClass();
|
||||
return node_based_graph.GetEdgeData(eid).flags.road_classification.IsRampClass();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
MotorwayHandler::MotorwayHandler(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const std::vector<util::Coordinate> &coordinates,
|
||||
const util::NameTable &name_table,
|
||||
const SuffixTable &street_name_suffix_table,
|
||||
const IntersectionGenerator &intersection_generator)
|
||||
: IntersectionHandler(node_based_graph,
|
||||
node_data_container,
|
||||
coordinates,
|
||||
name_table,
|
||||
street_name_suffix_table,
|
||||
@ -101,7 +103,8 @@ operator()(const NodeID, const EdgeID via_eid, Intersection intersection) const
|
||||
|
||||
Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection intersection) const
|
||||
{
|
||||
const auto &in_data = node_based_graph.GetEdgeData(via_eid);
|
||||
const auto &in_data =
|
||||
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(via_eid).annotation_data);
|
||||
BOOST_ASSERT(isMotorwayClass(via_eid, node_based_graph));
|
||||
|
||||
const auto countExitingMotorways = [this](const Intersection &intersection) {
|
||||
@ -121,7 +124,8 @@ Intersection MotorwayHandler::fromMotorway(const EdgeID via_eid, Intersection in
|
||||
if (!road.entry_allowed)
|
||||
continue;
|
||||
|
||||
const auto &out_data = node_based_graph.GetEdgeData(road.eid);
|
||||
const auto &out_data = node_data_container.GetAnnotation(
|
||||
node_based_graph.GetEdgeData(road.eid).annotation_data);
|
||||
|
||||
const auto same_name = !util::guidance::requiresNameAnnounced(
|
||||
in_data.name_id, out_data.name_id, name_table, street_name_suffix_table);
|
||||
@ -353,8 +357,10 @@ Intersection MotorwayHandler::fromRamp(const EdgeID via_eid, Intersection inters
|
||||
}
|
||||
else if (intersection.size() == 3)
|
||||
{
|
||||
const auto &second_intersection_data = node_based_graph.GetEdgeData(intersection[2].eid);
|
||||
const auto &first_intersection_data = node_based_graph.GetEdgeData(intersection[1].eid);
|
||||
const auto &second_intersection_data = node_data_container.GetAnnotation(
|
||||
node_based_graph.GetEdgeData(intersection[2].eid).annotation_data);
|
||||
const auto &first_intersection_data = node_data_container.GetAnnotation(
|
||||
node_based_graph.GetEdgeData(intersection[1].eid).annotation_data);
|
||||
const auto first_second_same_name =
|
||||
!util::guidance::requiresNameAnnounced(second_intersection_data.name_id,
|
||||
first_intersection_data.name_id,
|
||||
|
@ -15,8 +15,10 @@ namespace guidance
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
NodeBasedGraphWalker::NodeBasedGraphWalker(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const IntersectionGenerator &intersection_generator)
|
||||
: node_based_graph(node_based_graph), intersection_generator(intersection_generator)
|
||||
: node_based_graph(node_based_graph), node_data_container(node_data_container),
|
||||
intersection_generator(intersection_generator)
|
||||
{
|
||||
}
|
||||
|
||||
@ -64,21 +66,24 @@ boost::optional<EdgeID> SelectRoadByNameOnlyChoiceAndStraightness::
|
||||
operator()(const NodeID /*nid*/,
|
||||
const EdgeID /*via_edge_id*/,
|
||||
const IntersectionView &intersection,
|
||||
const util::NodeBasedDynamicGraph &node_based_graph) const
|
||||
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container) const
|
||||
{
|
||||
BOOST_ASSERT(!intersection.empty());
|
||||
const auto comparator = [this, &node_based_graph](const IntersectionViewData &lhs,
|
||||
const IntersectionViewData &rhs) {
|
||||
const auto comparator = [&](const IntersectionViewData &lhs, const IntersectionViewData &rhs) {
|
||||
// the score of an elemnt results in an ranking preferring valid entries, if required over
|
||||
// invalid requested name_ids over non-requested narrow deviations over non-narrow
|
||||
const auto score = [this, &node_based_graph](const IntersectionViewData &road) {
|
||||
const auto score = [&](const IntersectionViewData &road) {
|
||||
double result_score = 0;
|
||||
// since angular deviation is limited by 0-180, we add 360 for invalid
|
||||
if (requires_entry && !road.entry_allowed)
|
||||
result_score += 360.;
|
||||
|
||||
// 180 for undesired name-ids
|
||||
if (desired_name_id != node_based_graph.GetEdgeData(road.eid).name_id)
|
||||
if (desired_name_id !=
|
||||
node_data_container
|
||||
.GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data)
|
||||
.name_id)
|
||||
result_score += 180;
|
||||
|
||||
return result_score + angularDeviation(road.angle, STRAIGHT_ANGLE);
|
||||
@ -108,24 +113,27 @@ boost::optional<EdgeID> SelectStraightmostRoadByNameAndOnlyChoice::
|
||||
operator()(const NodeID /*nid*/,
|
||||
const EdgeID /*via_edge_id*/,
|
||||
const IntersectionView &intersection,
|
||||
const util::NodeBasedDynamicGraph &node_based_graph) const
|
||||
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container) const
|
||||
{
|
||||
BOOST_ASSERT(!intersection.empty());
|
||||
if (intersection.size() == 1)
|
||||
return {};
|
||||
|
||||
const auto comparator = [this, &node_based_graph](const IntersectionViewData &lhs,
|
||||
const IntersectionViewData &rhs) {
|
||||
const auto comparator = [&](const IntersectionViewData &lhs, const IntersectionViewData &rhs) {
|
||||
// the score of an elemnt results in an ranking preferring valid entries, if required over
|
||||
// invalid requested name_ids over non-requested narrow deviations over non-narrow
|
||||
const auto score = [this, &node_based_graph](const IntersectionViewData &road) {
|
||||
const auto score = [&](const IntersectionViewData &road) {
|
||||
double result_score = 0;
|
||||
// since angular deviation is limited by 0-180, we add 360 for invalid
|
||||
if (requires_entry && !road.entry_allowed)
|
||||
result_score += 360.;
|
||||
|
||||
// 180 for undesired name-ids
|
||||
if (desired_name_id != node_based_graph.GetEdgeData(road.eid).name_id)
|
||||
if (desired_name_id !=
|
||||
node_data_container
|
||||
.GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data)
|
||||
.name_id)
|
||||
result_score += 180;
|
||||
|
||||
return result_score + angularDeviation(road.angle, STRAIGHT_ANGLE);
|
||||
@ -135,11 +143,11 @@ operator()(const NodeID /*nid*/,
|
||||
};
|
||||
|
||||
const auto count_desired_name =
|
||||
std::count_if(std::begin(intersection),
|
||||
std::end(intersection),
|
||||
[this, &node_based_graph](const auto &road) {
|
||||
return node_based_graph.GetEdgeData(road.eid).name_id == desired_name_id;
|
||||
});
|
||||
std::count_if(std::begin(intersection), std::end(intersection), [&](const auto &road) {
|
||||
return node_data_container
|
||||
.GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data)
|
||||
.name_id == desired_name_id;
|
||||
});
|
||||
if (count_desired_name > 2)
|
||||
return {};
|
||||
|
||||
@ -149,7 +157,9 @@ operator()(const NodeID /*nid*/,
|
||||
const auto is_valid_choice = !requires_entry || min_element->entry_allowed;
|
||||
const auto is_only_choice_with_same_name =
|
||||
count_desired_name <= 2 && // <= in case we come from a bridge
|
||||
node_based_graph.GetEdgeData(min_element->eid).name_id == desired_name_id &&
|
||||
node_data_container
|
||||
.GetAnnotation(node_based_graph.GetEdgeData(min_element->eid).annotation_data)
|
||||
.name_id == desired_name_id &&
|
||||
angularDeviation(min_element->angle, STRAIGHT_ANGLE) < 100; // don't do crazy turns
|
||||
const auto has_valid_angle =
|
||||
((intersection.size() == 2 ||
|
||||
|
@ -24,18 +24,19 @@ namespace guidance
|
||||
{
|
||||
|
||||
RoundaboutHandler::RoundaboutHandler(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const std::vector<util::Coordinate> &coordinates,
|
||||
const CompressedEdgeContainer &compressed_edge_container,
|
||||
const util::NameTable &name_table,
|
||||
const SuffixTable &street_name_suffix_table,
|
||||
const ProfileProperties &profile_properties,
|
||||
const IntersectionGenerator &intersection_generator)
|
||||
: IntersectionHandler(node_based_graph,
|
||||
node_data_container,
|
||||
coordinates,
|
||||
name_table,
|
||||
street_name_suffix_table,
|
||||
intersection_generator),
|
||||
compressed_edge_container(compressed_edge_container), profile_properties(profile_properties),
|
||||
compressed_edge_container(compressed_edge_container),
|
||||
coordinate_extractor(node_based_graph, compressed_edge_container, coordinates)
|
||||
{
|
||||
}
|
||||
@ -70,22 +71,24 @@ detail::RoundaboutFlags RoundaboutHandler::getRoundaboutFlags(
|
||||
const NodeID from_nid, const EdgeID via_eid, const Intersection &intersection) const
|
||||
{
|
||||
const auto &in_edge_data = node_based_graph.GetEdgeData(via_eid);
|
||||
bool on_roundabout = in_edge_data.roundabout || in_edge_data.circular;
|
||||
const auto &in_edge_class = in_edge_data.flags;
|
||||
bool on_roundabout = in_edge_class.roundabout || in_edge_class.circular;
|
||||
bool can_enter_roundabout = false;
|
||||
bool can_exit_roundabout_separately = false;
|
||||
|
||||
const bool lhs = in_edge_data.is_left_hand_driving;
|
||||
const bool lhs =
|
||||
node_data_container.GetAnnotation(in_edge_data.annotation_data).is_left_hand_driving;
|
||||
const int step = lhs ? -1 : 1;
|
||||
for (std::size_t cnt = 0, idx = lhs ? intersection.size() - 1 : 0; cnt < intersection.size();
|
||||
++cnt, idx += step)
|
||||
{
|
||||
const auto &road = intersection[idx];
|
||||
const auto &edge_data = node_based_graph.GetEdgeData(road.eid);
|
||||
const auto &edge = node_based_graph.GetEdgeData(road.eid);
|
||||
// only check actual outgoing edges
|
||||
if (edge_data.reversed || !road.entry_allowed)
|
||||
if (edge.reversed || !road.entry_allowed)
|
||||
continue;
|
||||
|
||||
if (edge_data.roundabout || edge_data.circular)
|
||||
if (edge.flags.roundabout || edge.flags.circular)
|
||||
{
|
||||
can_enter_roundabout = true;
|
||||
}
|
||||
@ -108,8 +111,8 @@ void RoundaboutHandler::invalidateExitAgainstDirection(const NodeID from_nid,
|
||||
const EdgeID via_eid,
|
||||
Intersection &intersection) const
|
||||
{
|
||||
const auto &in_edge_data = node_based_graph.GetEdgeData(via_eid);
|
||||
if (in_edge_data.roundabout || in_edge_data.circular)
|
||||
const auto &in_edge_class = node_based_graph.GetEdgeData(via_eid).flags;
|
||||
if (in_edge_class.roundabout || in_edge_class.circular)
|
||||
return;
|
||||
|
||||
// Find range in which exits that must be invalidated (shaded areas):
|
||||
@ -136,10 +139,10 @@ void RoundaboutHandler::invalidateExitAgainstDirection(const NodeID from_nid,
|
||||
auto invalidate_from = intersection.end(), invalidate_to = intersection.end();
|
||||
for (auto road = intersection.begin(); road != intersection.end(); ++road)
|
||||
{
|
||||
const auto &edge_data = node_based_graph.GetEdgeData(road->eid);
|
||||
if (edge_data.roundabout || edge_data.circular)
|
||||
const auto &edge = node_based_graph.GetEdgeData(road->eid);
|
||||
if (edge.flags.roundabout || edge.flags.circular)
|
||||
{
|
||||
if (edge_data.reversed)
|
||||
if (edge.reversed)
|
||||
{
|
||||
if (roundabout_entry_first)
|
||||
{ // invalidate turns in range exit..end
|
||||
@ -166,8 +169,8 @@ void RoundaboutHandler::invalidateExitAgainstDirection(const NodeID from_nid,
|
||||
// u-turn against the roundabout direction is invalidated.
|
||||
for (; invalidate_from != invalidate_to; ++invalidate_from)
|
||||
{
|
||||
const auto &edge_data = node_based_graph.GetEdgeData(invalidate_from->eid);
|
||||
if (!edge_data.roundabout && !edge_data.circular &&
|
||||
const auto &edge = node_based_graph.GetEdgeData(invalidate_from->eid);
|
||||
if (!edge.flags.roundabout && !edge.flags.circular &&
|
||||
node_based_graph.GetTarget(invalidate_from->eid) != from_nid)
|
||||
{
|
||||
invalidate_from->entry_allowed = false;
|
||||
@ -207,8 +210,8 @@ bool RoundaboutHandler::qualifiesAsRoundaboutIntersection(
|
||||
// can only contain a single further road
|
||||
for (const auto edge : node_based_graph.GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const auto edge_data = node_based_graph.GetEdgeData(edge);
|
||||
if (edge_data.roundabout || edge_data.circular)
|
||||
const auto &edge_data = node_based_graph.GetEdgeData(edge);
|
||||
if (edge_data.flags.roundabout || edge_data.flags.circular)
|
||||
continue;
|
||||
|
||||
// there is a single non-roundabout edge
|
||||
@ -222,7 +225,7 @@ bool RoundaboutHandler::qualifiesAsRoundaboutIntersection(
|
||||
[this](const auto current_max, const auto current_eid) {
|
||||
return std::max(current_max,
|
||||
node_based_graph.GetEdgeData(current_eid)
|
||||
.road_classification.GetNumberOfLanes());
|
||||
.flags.road_classification.GetNumberOfLanes());
|
||||
});
|
||||
|
||||
const auto next_coordinate =
|
||||
@ -279,11 +282,12 @@ RoundaboutType RoundaboutHandler::getRoundaboutType(const NodeID nid) const
|
||||
const NodeID node, const bool roundabout, const bool circular) {
|
||||
BOOST_ASSERT(roundabout != circular);
|
||||
EdgeID continue_edge = SPECIAL_EDGEID;
|
||||
for (const auto edge : node_based_graph.GetAdjacentEdgeRange(node))
|
||||
for (const auto edge_id : node_based_graph.GetAdjacentEdgeRange(node))
|
||||
{
|
||||
const auto &edge_data = node_based_graph.GetEdgeData(edge);
|
||||
if (!edge_data.reversed && (edge_data.circular == circular) &&
|
||||
(edge_data.roundabout == roundabout))
|
||||
const auto &edge = node_based_graph.GetEdgeData(edge_id);
|
||||
const auto &edge_data = node_data_container.GetAnnotation(edge.annotation_data);
|
||||
if (!edge.reversed && (edge.flags.circular == circular) &&
|
||||
(edge.flags.roundabout == roundabout))
|
||||
{
|
||||
if (SPECIAL_EDGEID != continue_edge)
|
||||
{
|
||||
@ -303,9 +307,9 @@ RoundaboutType RoundaboutHandler::getRoundaboutType(const NodeID nid) const
|
||||
roundabout_name_ids.insert(edge_data.name_id);
|
||||
}
|
||||
|
||||
continue_edge = edge;
|
||||
continue_edge = edge_id;
|
||||
}
|
||||
else if (!edge_data.roundabout && !edge_data.circular)
|
||||
else if (!edge.flags.roundabout && !edge.flags.circular)
|
||||
{
|
||||
// remember all connected road names
|
||||
connected_names.insert(edge_data.name_id);
|
||||
@ -322,7 +326,7 @@ RoundaboutType RoundaboutHandler::getRoundaboutType(const NodeID nid) const
|
||||
for (const auto edge : node_based_graph.GetAdjacentEdgeRange(at_node))
|
||||
{
|
||||
const auto &edge_data = node_based_graph.GetEdgeData(edge);
|
||||
if (edge_data.roundabout || edge_data.circular)
|
||||
if (edge_data.flags.roundabout || edge_data.flags.circular)
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
@ -353,7 +357,7 @@ RoundaboutType RoundaboutHandler::getRoundaboutType(const NodeID nid) const
|
||||
bool roundabout = false, circular = false;
|
||||
for (const auto eid : node_based_graph.GetAdjacentEdgeRange(nid))
|
||||
{
|
||||
const auto data = node_based_graph.GetEdgeData(eid);
|
||||
const auto data = node_based_graph.GetEdgeData(eid).flags;
|
||||
roundabout |= data.roundabout;
|
||||
circular |= data.circular;
|
||||
}
|
||||
@ -435,7 +439,8 @@ Intersection RoundaboutHandler::handleRoundabouts(const RoundaboutType roundabou
|
||||
NodeID node_at_center_of_intersection = node_based_graph.GetTarget(via_eid);
|
||||
const auto &in_edge_data = node_based_graph.GetEdgeData(via_eid);
|
||||
|
||||
const bool lhs = in_edge_data.is_left_hand_driving;
|
||||
const bool lhs =
|
||||
node_data_container.GetAnnotation(in_edge_data.annotation_data).is_left_hand_driving;
|
||||
const int step = lhs ? -1 : 1;
|
||||
|
||||
if (on_roundabout)
|
||||
@ -448,7 +453,8 @@ Intersection RoundaboutHandler::handleRoundabouts(const RoundaboutType roundabou
|
||||
{
|
||||
auto &road = intersection[idx];
|
||||
auto &turn = road;
|
||||
const auto &out_data = node_based_graph.GetEdgeData(road.eid);
|
||||
const auto &out_data = node_based_graph.GetEdgeData(road.eid).flags;
|
||||
;
|
||||
if (out_data.roundabout || out_data.circular)
|
||||
{
|
||||
// TODO can forks happen in roundabouts? E.g. required lane changes
|
||||
@ -471,11 +477,10 @@ Intersection RoundaboutHandler::handleRoundabouts(const RoundaboutType roundabou
|
||||
for (const auto eid :
|
||||
node_based_graph.GetAdjacentEdgeRange(node_at_center_of_intersection))
|
||||
{
|
||||
const auto &data_of_leaving_edge = node_based_graph.GetEdgeData(eid);
|
||||
if (!data_of_leaving_edge.reversed &&
|
||||
!data_of_leaving_edge.roundabout &&
|
||||
!data_of_leaving_edge.circular &&
|
||||
!data_of_leaving_edge.road_classification.IsLowPriorityRoadClass())
|
||||
const auto &leaving_edge = node_based_graph.GetEdgeData(eid);
|
||||
if (!leaving_edge.reversed && !leaving_edge.flags.roundabout &&
|
||||
!leaving_edge.flags.circular &&
|
||||
!leaving_edge.flags.road_classification.IsLowPriorityRoadClass())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -511,7 +516,7 @@ Intersection RoundaboutHandler::handleRoundabouts(const RoundaboutType roundabou
|
||||
++cnt, idx += step)
|
||||
{
|
||||
auto &turn = intersection[idx];
|
||||
const auto &out_data = node_based_graph.GetEdgeData(turn.eid);
|
||||
const auto &out_data = node_based_graph.GetEdgeData(turn.eid).flags;
|
||||
|
||||
// A roundabout consists of exactly two roads at an intersection. by toggeling this
|
||||
// flag, we can switch between roads crossing the roundabout and roads that are on the
|
||||
|
@ -23,10 +23,12 @@ namespace guidance
|
||||
|
||||
SliproadHandler::SliproadHandler(const IntersectionGenerator &intersection_generator,
|
||||
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const std::vector<util::Coordinate> &coordinates,
|
||||
const util::NameTable &name_table,
|
||||
const SuffixTable &street_name_suffix_table)
|
||||
: IntersectionHandler(node_based_graph,
|
||||
node_data_container,
|
||||
coordinates,
|
||||
name_table,
|
||||
street_name_suffix_table,
|
||||
@ -109,7 +111,7 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto &road_data = node_based_graph.GetEdgeData(road.eid);
|
||||
const auto &road_data = node_based_graph.GetEdgeData(road.eid).flags;
|
||||
|
||||
auto is_roundabout = road_data.roundabout;
|
||||
|
||||
@ -156,7 +158,8 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter
|
||||
|
||||
for (const auto &road : main_road_intersection->intersection)
|
||||
{
|
||||
const auto &target_data = node_based_graph.GetEdgeData(road.eid);
|
||||
const auto target_annotation_id = node_based_graph.GetEdgeData(road.eid).annotation_data;
|
||||
const auto &target_data = node_data_container.GetAnnotation(target_annotation_id);
|
||||
target_road_name_ids.push_back(target_data.name_id);
|
||||
}
|
||||
|
||||
@ -173,7 +176,7 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter
|
||||
continue;
|
||||
|
||||
auto &sliproad = intersection[road_index]; // this is what we're checking and assigning to
|
||||
const auto &sliproad_data = node_based_graph.GetEdgeData(sliproad.eid);
|
||||
const auto &sliproad_edge_data = node_based_graph.GetEdgeData(sliproad.eid);
|
||||
|
||||
// Intersection is orderd: 0 is UTurn, then from sharp right to sharp left.
|
||||
// We already have an obvious index (bc) for going straight-ish.
|
||||
@ -199,13 +202,13 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter
|
||||
}
|
||||
|
||||
// Discard service and other low priority roads - never Sliproad candidate
|
||||
if (sliproad_data.road_classification.IsLowPriorityRoadClass())
|
||||
if (sliproad_edge_data.flags.road_classification.IsLowPriorityRoadClass())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Incoming-only can never be a Sliproad
|
||||
if (sliproad_data.reversed)
|
||||
if (sliproad_edge_data.reversed)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@ -350,7 +353,7 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto &onto_data = node_based_graph.GetEdgeData(onto.eid);
|
||||
const auto &onto_data = node_based_graph.GetEdgeData(onto.eid).flags;
|
||||
|
||||
if (onto_data.roundabout)
|
||||
{
|
||||
@ -434,7 +437,8 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter
|
||||
|
||||
// Check sliproads with skew main intersections
|
||||
if (deviation_from_straight > 180. - minimal_crossroad_angle_of_intersection &&
|
||||
!node_based_graph.GetEdgeData(sliproad.eid).road_classification.IsLinkClass())
|
||||
!node_based_graph.GetEdgeData(sliproad.eid)
|
||||
.flags.road_classification.IsLinkClass())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@ -449,9 +453,10 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter
|
||||
// ` .
|
||||
// d
|
||||
//
|
||||
const auto area_threshold = std::pow(
|
||||
scaledThresholdByRoadClass(MAX_SLIPROAD_THRESHOLD, sliproad_data.road_classification),
|
||||
2.);
|
||||
const auto area_threshold =
|
||||
std::pow(scaledThresholdByRoadClass(MAX_SLIPROAD_THRESHOLD,
|
||||
sliproad_edge_data.flags.road_classification),
|
||||
2.);
|
||||
|
||||
if (!isValidSliproadArea(area_threshold,
|
||||
intersection_node_id,
|
||||
@ -464,7 +469,8 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter
|
||||
// Check all roads at `d` if one is connected to `c`, is so `bd` is Sliproad.
|
||||
for (const auto &candidate_road : target_intersection)
|
||||
{
|
||||
const auto &candidate_data = node_based_graph.GetEdgeData(candidate_road.eid);
|
||||
const auto &candidate_data = node_data_container.GetAnnotation(
|
||||
node_based_graph.GetEdgeData(candidate_road.eid).annotation_data);
|
||||
|
||||
// Name mismatch: check roads at `c` and `d` for same name
|
||||
const auto name_mismatch = [&](const NameID road_name_id) {
|
||||
@ -489,15 +495,20 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter
|
||||
|
||||
// Check if main road -> sliproad (non-link) -> candidate road requires two name
|
||||
// announcements then don't suppress one announcement via sliproad handler
|
||||
const auto main_road_name_id = node_based_graph.GetEdgeData(main_road.eid).name_id;
|
||||
if (!sliproad_data.road_classification.IsLinkClass() &&
|
||||
sliproad_data.name_id != EMPTY_NAMEID && main_road_name_id != EMPTY_NAMEID &&
|
||||
const auto main_road_name_id =
|
||||
node_data_container
|
||||
.GetAnnotation(node_based_graph.GetEdgeData(main_road.eid).annotation_data)
|
||||
.name_id;
|
||||
const auto &sliproad_annotation =
|
||||
node_data_container.GetAnnotation(sliproad_edge_data.annotation_data);
|
||||
if (!sliproad_edge_data.flags.road_classification.IsLinkClass() &&
|
||||
sliproad_annotation.name_id != EMPTY_NAMEID && main_road_name_id != EMPTY_NAMEID &&
|
||||
candidate_data.name_id != EMPTY_NAMEID &&
|
||||
util::guidance::requiresNameAnnounced(main_road_name_id,
|
||||
sliproad_data.name_id,
|
||||
sliproad_annotation.name_id,
|
||||
name_table,
|
||||
street_name_suffix_table) &&
|
||||
util::guidance::requiresNameAnnounced(sliproad_data.name_id,
|
||||
util::guidance::requiresNameAnnounced(sliproad_annotation.name_id,
|
||||
candidate_data.name_id,
|
||||
name_table,
|
||||
street_name_suffix_table))
|
||||
@ -553,6 +564,8 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter
|
||||
// In those cases the obvious non-Sliproad is now obvious and we discard the Fork turn type.
|
||||
if (sliproad_found && main_road.instruction.type == TurnType::Fork)
|
||||
{
|
||||
const auto &main_data = node_based_graph.GetEdgeData(main_road.eid);
|
||||
const auto &main_annotation = node_data_container.GetAnnotation(main_data.annotation_data);
|
||||
if (isSameName(source_edge_id, main_road.eid))
|
||||
{
|
||||
if (angularDeviation(main_road.angle, STRAIGHT_ANGLE) < 5)
|
||||
@ -562,7 +575,7 @@ operator()(const NodeID /*nid*/, const EdgeID source_edge_id, Intersection inter
|
||||
intersection[*obvious].instruction.direction_modifier =
|
||||
getTurnDirection(intersection[*obvious].angle);
|
||||
}
|
||||
else if (node_based_graph.GetEdgeData(main_road.eid).name_id != EMPTY_NAMEID)
|
||||
else if (main_annotation.name_id != EMPTY_NAMEID)
|
||||
{
|
||||
intersection[*obvious].instruction.type = TurnType::NewName;
|
||||
intersection[*obvious].instruction.direction_modifier =
|
||||
@ -644,7 +657,7 @@ bool SliproadHandler::nextIntersectionIsTooFarAway(const NodeID start, const Edg
|
||||
const auto &coordinate_extractor = intersection_generator.GetCoordinateExtractor();
|
||||
|
||||
// Base max distance threshold on the current road class we're on
|
||||
const auto &data = node_based_graph.GetEdgeData(onto);
|
||||
const auto &data = node_based_graph.GetEdgeData(onto).flags;
|
||||
const auto threshold = scaledThresholdByRoadClass(MAX_SLIPROAD_THRESHOLD, // <- scales down
|
||||
data.road_classification);
|
||||
|
||||
@ -662,13 +675,15 @@ bool SliproadHandler::isThroughStreet(const EdgeID from, const IntersectionView
|
||||
BOOST_ASSERT(from != SPECIAL_EDGEID);
|
||||
BOOST_ASSERT(!intersection.empty());
|
||||
|
||||
const auto &edge_name_id = node_based_graph.GetEdgeData(from).name_id;
|
||||
const auto from_annotation_id = node_based_graph.GetEdgeData(from).annotation_data;
|
||||
const auto &edge_name_id = node_data_container.GetAnnotation(from_annotation_id).name_id;
|
||||
|
||||
auto first = begin(intersection) + 1; // Skip UTurn road
|
||||
auto last = end(intersection);
|
||||
|
||||
auto same_name = [&](const auto &road) {
|
||||
const auto &road_name_id = node_based_graph.GetEdgeData(road.eid).name_id;
|
||||
const auto annotation_id = node_based_graph.GetEdgeData(road.eid).annotation_data;
|
||||
const auto &road_name_id = node_data_container.GetAnnotation(annotation_id).name_id;
|
||||
|
||||
return edge_name_id != EMPTY_NAMEID && //
|
||||
road_name_id != EMPTY_NAMEID && //
|
||||
@ -683,10 +698,13 @@ bool SliproadHandler::isThroughStreet(const EdgeID from, const IntersectionView
|
||||
|
||||
bool SliproadHandler::roadContinues(const EdgeID current, const EdgeID next) const
|
||||
{
|
||||
const auto ¤t_data = node_based_graph.GetEdgeData(current);
|
||||
const auto &next_data = node_based_graph.GetEdgeData(next);
|
||||
const auto ¤t_data =
|
||||
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(current).annotation_data);
|
||||
const auto &next_data =
|
||||
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(next).annotation_data);
|
||||
|
||||
auto same_road_category = current_data.road_classification == next_data.road_classification;
|
||||
auto same_road_category = node_based_graph.GetEdgeData(current).flags.road_classification ==
|
||||
node_based_graph.GetEdgeData(next).flags.road_classification;
|
||||
auto same_travel_mode = current_data.travel_mode == next_data.travel_mode;
|
||||
|
||||
auto same_name = current_data.name_id != EMPTY_NAMEID && //
|
||||
@ -730,22 +748,18 @@ bool SliproadHandler::isValidSliproadArea(const double max_area,
|
||||
}
|
||||
|
||||
bool SliproadHandler::isValidSliproadLink(const IntersectionViewData &sliproad,
|
||||
const IntersectionViewData &first,
|
||||
const IntersectionViewData & /*first*/,
|
||||
const IntersectionViewData &second) const
|
||||
{
|
||||
// If the sliproad is not a link we don't care
|
||||
const auto &sliproad_data = node_based_graph.GetEdgeData(sliproad.eid);
|
||||
// If the Sliproad is not a link we don't care
|
||||
const auto &sliproad_data = node_based_graph.GetEdgeData(sliproad.eid).flags;
|
||||
if (!sliproad_data.road_classification.IsLinkClass())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// otherwise the first road leading to the intersection we shortcut
|
||||
// can be a link or a usual road (ignore the check at this place)
|
||||
(void)first;
|
||||
|
||||
// and the second road coming from the intersection we shortcut must be a non-link
|
||||
const auto &second_road_data = node_based_graph.GetEdgeData(second.eid);
|
||||
const auto &second_road_data = node_based_graph.GetEdgeData(second.eid).flags;
|
||||
if (second_road_data.road_classification.IsLinkClass())
|
||||
{
|
||||
return false;
|
||||
@ -758,10 +772,15 @@ bool SliproadHandler::allSameMode(const EdgeID from,
|
||||
const EdgeID sliproad_candidate,
|
||||
const EdgeID target_road) const
|
||||
{
|
||||
return node_based_graph.GetEdgeData(from).travel_mode ==
|
||||
node_based_graph.GetEdgeData(sliproad_candidate).travel_mode &&
|
||||
node_based_graph.GetEdgeData(sliproad_candidate).travel_mode ==
|
||||
node_based_graph.GetEdgeData(target_road).travel_mode;
|
||||
const auto &from_annotation =
|
||||
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(from).annotation_data);
|
||||
const auto &sliproad_annotation = node_data_container.GetAnnotation(
|
||||
node_based_graph.GetEdgeData(sliproad_candidate).annotation_data);
|
||||
const auto &target_annotation = node_data_container.GetAnnotation(
|
||||
node_based_graph.GetEdgeData(target_road).annotation_data);
|
||||
|
||||
return (from_annotation.travel_mode == sliproad_annotation.travel_mode) &&
|
||||
(target_annotation.travel_mode == sliproad_annotation.travel_mode);
|
||||
}
|
||||
|
||||
bool SliproadHandler::canBeTargetOfSliproad(const IntersectionView &intersection)
|
||||
|
@ -13,10 +13,12 @@ namespace guidance
|
||||
|
||||
SuppressModeHandler::SuppressModeHandler(const IntersectionGenerator &intersection_generator,
|
||||
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const std::vector<util::Coordinate> &coordinates,
|
||||
const util::NameTable &name_table,
|
||||
const SuffixTable &street_name_suffix_table)
|
||||
: IntersectionHandler(node_based_graph,
|
||||
node_data_container,
|
||||
coordinates,
|
||||
name_table,
|
||||
street_name_suffix_table,
|
||||
@ -36,14 +38,18 @@ bool SuppressModeHandler::canProcess(const NodeID,
|
||||
|
||||
// If the approach way is not on the suppression blacklist, and not all the exit ways share that
|
||||
// mode, there are no ways to suppress by this criteria.
|
||||
const auto in_mode = node_based_graph.GetEdgeData(via_eid).travel_mode;
|
||||
const auto in_mode =
|
||||
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(via_eid).annotation_data)
|
||||
.travel_mode;
|
||||
const auto suppress_in_mode = std::find(begin(suppressed), end(suppressed), in_mode);
|
||||
|
||||
const auto first = begin(intersection);
|
||||
const auto last = end(intersection);
|
||||
|
||||
const auto all_share_mode = std::all_of(first, last, [this, &in_mode](const auto &road) {
|
||||
return node_based_graph.GetEdgeData(road.eid).travel_mode == in_mode;
|
||||
return node_data_container
|
||||
.GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data)
|
||||
.travel_mode == in_mode;
|
||||
});
|
||||
|
||||
return (suppress_in_mode != end(suppressed)) && all_share_mode;
|
||||
|
@ -21,56 +21,61 @@ namespace guidance
|
||||
|
||||
using EdgeData = util::NodeBasedDynamicGraph::EdgeData;
|
||||
|
||||
bool requiresAnnouncement(const EdgeData &from, const EdgeData &to)
|
||||
{
|
||||
return !from.CanCombineWith(to);
|
||||
}
|
||||
|
||||
TurnAnalysis::TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const std::vector<util::Coordinate> &coordinates,
|
||||
const RestrictionMap &restriction_map,
|
||||
const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const CompressedEdgeContainer &compressed_edge_container,
|
||||
const util::NameTable &name_table,
|
||||
const SuffixTable &street_name_suffix_table,
|
||||
const ProfileProperties &profile_properties)
|
||||
: node_based_graph(node_based_graph),
|
||||
intersection_generator(
|
||||
node_based_graph, restriction_map, barrier_nodes, coordinates, compressed_edge_container),
|
||||
const SuffixTable &street_name_suffix_table)
|
||||
: node_based_graph(node_based_graph), intersection_generator(node_based_graph,
|
||||
node_data_container,
|
||||
restriction_map,
|
||||
barrier_nodes,
|
||||
coordinates,
|
||||
compressed_edge_container),
|
||||
intersection_normalizer(node_based_graph,
|
||||
node_data_container,
|
||||
coordinates,
|
||||
name_table,
|
||||
street_name_suffix_table,
|
||||
intersection_generator),
|
||||
roundabout_handler(node_based_graph,
|
||||
node_data_container,
|
||||
coordinates,
|
||||
compressed_edge_container,
|
||||
name_table,
|
||||
street_name_suffix_table,
|
||||
profile_properties,
|
||||
intersection_generator),
|
||||
motorway_handler(node_based_graph,
|
||||
node_data_container,
|
||||
|
||||
coordinates,
|
||||
name_table,
|
||||
street_name_suffix_table,
|
||||
intersection_generator),
|
||||
turn_handler(node_based_graph,
|
||||
node_data_container,
|
||||
coordinates,
|
||||
name_table,
|
||||
street_name_suffix_table,
|
||||
intersection_generator),
|
||||
sliproad_handler(intersection_generator,
|
||||
node_based_graph,
|
||||
node_data_container,
|
||||
coordinates,
|
||||
name_table,
|
||||
street_name_suffix_table),
|
||||
suppress_mode_handler(intersection_generator,
|
||||
node_based_graph,
|
||||
node_data_container,
|
||||
coordinates,
|
||||
name_table,
|
||||
street_name_suffix_table),
|
||||
driveway_handler(intersection_generator,
|
||||
node_based_graph,
|
||||
node_data_container,
|
||||
coordinates,
|
||||
name_table,
|
||||
street_name_suffix_table)
|
||||
@ -163,7 +168,7 @@ Intersection TurnAnalysis::AssignTurnTypes(const NodeID node_prior_to_intersecti
|
||||
node_prior_to_intersection, entering_via_edge, std::move(intersection));
|
||||
|
||||
// Turn On Ramps Into Off Ramps, if we come from a motorway-like road
|
||||
if (node_based_graph.GetEdgeData(entering_via_edge).road_classification.IsMotorwayClass())
|
||||
if (node_based_graph.GetEdgeData(entering_via_edge).flags.road_classification.IsMotorwayClass())
|
||||
{
|
||||
std::for_each(intersection.begin(), intersection.end(), [](ConnectedRoad &road) {
|
||||
if (road.instruction.type == TurnType::OnRamp)
|
||||
|
@ -111,11 +111,13 @@ std::size_t TurnHandler::Fork::getLeftIndex() const
|
||||
}
|
||||
|
||||
TurnHandler::TurnHandler(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const std::vector<util::Coordinate> &coordinates,
|
||||
const util::NameTable &name_table,
|
||||
const SuffixTable &street_name_suffix_table,
|
||||
const IntersectionGenerator &intersection_generator)
|
||||
: IntersectionHandler(node_based_graph,
|
||||
node_data_container,
|
||||
coordinates,
|
||||
name_table,
|
||||
street_name_suffix_table,
|
||||
@ -174,12 +176,16 @@ bool TurnHandler::isObviousOfTwo(const EdgeID via_edge,
|
||||
const ConnectedRoad &road,
|
||||
const ConnectedRoad &other) const
|
||||
{
|
||||
const auto &via_data = node_based_graph.GetEdgeData(via_edge);
|
||||
const auto &road_data = node_based_graph.GetEdgeData(road.eid);
|
||||
const auto &other_data = node_based_graph.GetEdgeData(other.eid);
|
||||
const auto &via_classification = via_data.road_classification;
|
||||
const auto &road_classification = road_data.road_classification;
|
||||
const auto &other_classification = other_data.road_classification;
|
||||
const auto &via_data =
|
||||
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(via_edge).annotation_data);
|
||||
const auto &road_data =
|
||||
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data);
|
||||
const auto &via_classification =
|
||||
node_based_graph.GetEdgeData(via_edge).flags.road_classification;
|
||||
const auto &road_classification =
|
||||
node_based_graph.GetEdgeData(road.eid).flags.road_classification;
|
||||
const auto &other_classification =
|
||||
node_based_graph.GetEdgeData(other.eid).flags.road_classification;
|
||||
|
||||
// if one of the given roads is obvious by class, obviousness is trivial
|
||||
if (obviousByRoadClass(via_classification, road_classification, other_classification))
|
||||
@ -335,9 +341,9 @@ Intersection TurnHandler::handleComplexTurn(const EdgeID via_edge, Intersection
|
||||
if (fork->size == 2)
|
||||
{
|
||||
const auto left_classification =
|
||||
node_based_graph.GetEdgeData(fork->getLeft().eid).road_classification;
|
||||
node_based_graph.GetEdgeData(fork->getLeft().eid).flags.road_classification;
|
||||
const auto right_classification =
|
||||
node_based_graph.GetEdgeData(fork->getRight().eid).road_classification;
|
||||
node_based_graph.GetEdgeData(fork->getRight().eid).flags.road_classification;
|
||||
if (canBeSeenAsFork(left_classification, right_classification))
|
||||
{
|
||||
assignFork(via_edge, fork->getLeft(), fork->getRight());
|
||||
@ -615,26 +621,27 @@ TurnHandler::findForkCandidatesByGeometry(Intersection &intersection) const
|
||||
// incoming edge are compatible by class
|
||||
bool TurnHandler::isCompatibleByRoadClass(const Intersection &intersection, const Fork fork) const
|
||||
{
|
||||
const auto via_class = node_based_graph.GetEdgeData(intersection[0].eid).road_classification;
|
||||
const auto via_class =
|
||||
node_based_graph.GetEdgeData(intersection[0].eid).flags.road_classification;
|
||||
|
||||
// if any of the considered roads is a link road, it cannot be a fork
|
||||
// except if rightmost fork candidate is also a link road
|
||||
const auto is_right_link_class =
|
||||
node_based_graph.GetEdgeData(fork.getRight().eid).road_classification.IsLinkClass();
|
||||
node_based_graph.GetEdgeData(fork.getRight().eid).flags.road_classification.IsLinkClass();
|
||||
if (!std::all_of(fork.begin + 1, fork.end, [&](ConnectedRoad &road) {
|
||||
return is_right_link_class ==
|
||||
node_based_graph.GetEdgeData(road.eid).road_classification.IsLinkClass();
|
||||
node_based_graph.GetEdgeData(road.eid).flags.road_classification.IsLinkClass();
|
||||
}))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return std::all_of(fork.begin, fork.end, [&](ConnectedRoad &base) {
|
||||
const auto base_class = node_based_graph.GetEdgeData(base.eid).road_classification;
|
||||
const auto base_class = node_based_graph.GetEdgeData(base.eid).flags.road_classification;
|
||||
// check that there is no turn obvious == check that all turns are non-onvious
|
||||
return std::all_of(fork.begin, fork.end, [&](ConnectedRoad &compare) {
|
||||
const auto compare_class =
|
||||
node_based_graph.GetEdgeData(compare.eid).road_classification;
|
||||
node_based_graph.GetEdgeData(compare.eid).flags.road_classification;
|
||||
return compare.eid == base.eid ||
|
||||
!(obviousByRoadClass(via_class, base_class, compare_class));
|
||||
});
|
||||
@ -670,8 +677,12 @@ boost::optional<TurnHandler::Fork> TurnHandler::findFork(const EdgeID via_edge,
|
||||
|
||||
const auto has_compatible_modes =
|
||||
std::all_of(fork->begin, fork->end, [&](const auto &road) {
|
||||
return node_based_graph.GetEdgeData(road.eid).travel_mode ==
|
||||
node_based_graph.GetEdgeData(via_edge).travel_mode;
|
||||
return node_data_container
|
||||
.GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data)
|
||||
.travel_mode ==
|
||||
node_data_container
|
||||
.GetAnnotation(node_based_graph.GetEdgeData(via_edge).annotation_data)
|
||||
.travel_mode;
|
||||
});
|
||||
|
||||
if (separated_at_left_side && separated_at_right_side && !has_obvious &&
|
||||
@ -703,9 +714,10 @@ void TurnHandler::handleDistinctConflict(const EdgeID via_edge,
|
||||
getTurnDirection(left.angle) == DirectionModifier::SlightLeft ||
|
||||
getTurnDirection(right.angle) == DirectionModifier::SlightRight)
|
||||
{
|
||||
const auto left_classification = node_based_graph.GetEdgeData(left.eid).road_classification;
|
||||
const auto left_classification =
|
||||
node_based_graph.GetEdgeData(left.eid).flags.road_classification;
|
||||
const auto right_classification =
|
||||
node_based_graph.GetEdgeData(right.eid).road_classification;
|
||||
node_based_graph.GetEdgeData(right.eid).flags.road_classification;
|
||||
|
||||
if (left_classification.GetPriority() > right_classification.GetPriority())
|
||||
{
|
||||
|
@ -34,11 +34,12 @@ std::size_t getNumberOfTurns(const Intersection &intersection)
|
||||
} // namespace
|
||||
|
||||
TurnLaneHandler::TurnLaneHandler(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
LaneDescriptionMap &lane_description_map,
|
||||
const TurnAnalysis &turn_analysis,
|
||||
util::guidance::LaneDataIdMap &id_map)
|
||||
: node_based_graph(node_based_graph), lane_description_map(lane_description_map),
|
||||
turn_analysis(turn_analysis), id_map(id_map)
|
||||
: node_based_graph(node_based_graph), node_data_container(node_data_container),
|
||||
lane_description_map(lane_description_map), turn_analysis(turn_analysis), id_map(id_map)
|
||||
{
|
||||
std::tie(turn_lane_offsets, turn_lane_masks) =
|
||||
transformTurnLaneMapIntoArrays(lane_description_map);
|
||||
@ -149,7 +150,7 @@ TurnLaneScenario TurnLaneHandler::deduceScenario(const NodeID at,
|
||||
LaneDescriptionID &previous_description_id)
|
||||
{
|
||||
// as long as we don't want to emit lanes on roundabout, don't assign them
|
||||
if (node_based_graph.GetEdgeData(via_edge).roundabout)
|
||||
if (node_based_graph.GetEdgeData(via_edge).flags.roundabout)
|
||||
return TurnLaneScenario::NONE;
|
||||
|
||||
// really don't touch roundabouts (#2626)
|
||||
@ -179,7 +180,9 @@ TurnLaneScenario TurnLaneHandler::deduceScenario(const NodeID at,
|
||||
(intersection.size() == 2 &&
|
||||
((lane_description_id != INVALID_LANE_DESCRIPTIONID &&
|
||||
lane_description_id ==
|
||||
node_based_graph.GetEdgeData(intersection[1].eid).lane_description_id) &&
|
||||
node_data_container
|
||||
.GetAnnotation(node_based_graph.GetEdgeData(intersection[1].eid).annotation_data)
|
||||
.lane_description_id) &&
|
||||
angularDeviation(intersection[1].angle, STRAIGHT_ANGLE) < FUZZY_ANGLE_DIFFERENCE));
|
||||
|
||||
if (is_going_straight_and_turns_continue)
|
||||
@ -367,7 +370,8 @@ void TurnLaneHandler::extractLaneData(const EdgeID via_edge,
|
||||
LaneDescriptionID &lane_description_id,
|
||||
LaneDataVector &lane_data) const
|
||||
{
|
||||
const auto &edge_data = node_based_graph.GetEdgeData(via_edge);
|
||||
const auto &edge_data =
|
||||
node_data_container.GetAnnotation(node_based_graph.GetEdgeData(via_edge).annotation_data);
|
||||
lane_description_id = edge_data.lane_description_id;
|
||||
// create an empty lane data
|
||||
if (INVALID_LANE_DESCRIPTIONID != lane_description_id)
|
||||
@ -719,9 +723,13 @@ Intersection TurnLaneHandler::handleSliproadTurn(Intersection intersection,
|
||||
return previous_intersection[sliproad_index + 1];
|
||||
}();
|
||||
const auto main_description_id =
|
||||
node_based_graph.GetEdgeData(main_road.eid).lane_description_id;
|
||||
node_data_container
|
||||
.GetAnnotation(node_based_graph.GetEdgeData(main_road.eid).annotation_data)
|
||||
.lane_description_id;
|
||||
const auto sliproad_description_id =
|
||||
node_based_graph.GetEdgeData(sliproad.eid).lane_description_id;
|
||||
node_data_container
|
||||
.GetAnnotation(node_based_graph.GetEdgeData(sliproad.eid).annotation_data)
|
||||
.lane_description_id;
|
||||
|
||||
if (main_description_id == INVALID_LANE_DESCRIPTIONID ||
|
||||
sliproad_description_id == INVALID_LANE_DESCRIPTIONID)
|
||||
|
205
src/extractor/node_based_graph_factory.cpp
Normal file
205
src/extractor/node_based_graph_factory.cpp
Normal file
@ -0,0 +1,205 @@
|
||||
#include "extractor/node_based_graph_factory.hpp"
|
||||
#include "extractor/graph_compressor.hpp"
|
||||
#include "storage/io.hpp"
|
||||
#include "util/graph_loader.hpp"
|
||||
|
||||
#include "util/log.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
NodeBasedGraphFactory::NodeBasedGraphFactory(
|
||||
const boost::filesystem::path &input_file,
|
||||
ScriptingEnvironment &scripting_environment,
|
||||
std::vector<TurnRestriction> &turn_restrictions,
|
||||
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions)
|
||||
{
|
||||
LoadDataFromFile(input_file);
|
||||
Compress(scripting_environment, turn_restrictions, conditional_turn_restrictions);
|
||||
CompressGeometry();
|
||||
CompressAnnotationData();
|
||||
}
|
||||
|
||||
// load the data serialised during the extraction run
|
||||
void NodeBasedGraphFactory::LoadDataFromFile(const boost::filesystem::path &input_file)
|
||||
{
|
||||
// the extraction_containers serialise all data necessary to create the node-based graph into a
|
||||
// single file, the *.osrm file. It contains nodes, basic information about which of these nodes
|
||||
// are traffic signals/stop signs. It also contains Edges and purely annotative meta-data
|
||||
storage::io::FileReader file_reader(input_file, storage::io::FileReader::VerifyFingerprint);
|
||||
|
||||
auto barriers_iter = inserter(barriers, end(barriers));
|
||||
auto traffic_signals_iter = inserter(traffic_signals, end(traffic_signals));
|
||||
|
||||
const auto number_of_node_based_nodes = util::loadNodesFromFile(
|
||||
file_reader, barriers_iter, traffic_signals_iter, coordinates, osm_node_ids);
|
||||
|
||||
std::vector<NodeBasedEdge> edge_list;
|
||||
util::loadEdgesFromFile(file_reader, edge_list);
|
||||
|
||||
if (edge_list.empty())
|
||||
{
|
||||
throw util::exception("Node-based-graph (" + input_file.string() + ") contains no edges." +
|
||||
SOURCE_REF);
|
||||
}
|
||||
|
||||
util::loadAnnotationData(file_reader, annotation_data);
|
||||
|
||||
// at this point, the data isn't compressed, but since we update the graph in-place, we assign
|
||||
// it here.
|
||||
compressed_output_graph =
|
||||
util::NodeBasedDynamicGraphFromEdges(number_of_node_based_nodes, edge_list);
|
||||
|
||||
// check whether the graph is sane
|
||||
BOOST_ASSERT([this]() {
|
||||
for (const auto nbg_node_u : util::irange(0u, compressed_output_graph.GetNumberOfNodes()))
|
||||
{
|
||||
for (EdgeID nbg_edge_id : compressed_output_graph.GetAdjacentEdgeRange(nbg_node_u))
|
||||
{
|
||||
// we cannot have invalid edge-ids in the graph
|
||||
if (nbg_edge_id == SPECIAL_EDGEID)
|
||||
return false;
|
||||
|
||||
const auto nbg_node_v = compressed_output_graph.GetTarget(nbg_edge_id);
|
||||
|
||||
auto reverse = compressed_output_graph.FindEdge(nbg_node_v, nbg_node_u);
|
||||
|
||||
// found an edge that is reversed in both directions, should be two distinct edges
|
||||
if (compressed_output_graph.GetEdgeData(nbg_edge_id).reversed &&
|
||||
compressed_output_graph.GetEdgeData(reverse).reversed)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}());
|
||||
}
|
||||
|
||||
void NodeBasedGraphFactory::Compress(
|
||||
ScriptingEnvironment &scripting_environment,
|
||||
std::vector<TurnRestriction> &turn_restrictions,
|
||||
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions)
|
||||
{
|
||||
GraphCompressor graph_compressor;
|
||||
graph_compressor.Compress(barriers,
|
||||
traffic_signals,
|
||||
scripting_environment,
|
||||
turn_restrictions,
|
||||
conditional_turn_restrictions,
|
||||
compressed_output_graph,
|
||||
annotation_data,
|
||||
compressed_edge_container);
|
||||
}
|
||||
|
||||
void NodeBasedGraphFactory::CompressGeometry()
|
||||
{
|
||||
for (const auto nbg_node_u : util::irange(0u, compressed_output_graph.GetNumberOfNodes()))
|
||||
{
|
||||
for (EdgeID nbg_edge_id : compressed_output_graph.GetAdjacentEdgeRange(nbg_node_u))
|
||||
{
|
||||
BOOST_ASSERT(nbg_edge_id != SPECIAL_EDGEID);
|
||||
|
||||
const auto &nbg_edge_data = compressed_output_graph.GetEdgeData(nbg_edge_id);
|
||||
const auto nbg_node_v = compressed_output_graph.GetTarget(nbg_edge_id);
|
||||
BOOST_ASSERT(nbg_node_v != SPECIAL_NODEID);
|
||||
BOOST_ASSERT(nbg_node_u != nbg_node_v);
|
||||
|
||||
// pick only every other edge, since we have every edge as an outgoing
|
||||
// and incoming egde
|
||||
if (nbg_node_u >= nbg_node_v)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
auto from = nbg_node_u, to = nbg_node_v;
|
||||
// if we found a non-forward edge reverse and try again
|
||||
if (nbg_edge_data.reversed)
|
||||
std::swap(from, to);
|
||||
|
||||
// find forward edge id and
|
||||
const EdgeID edge_id_1 = compressed_output_graph.FindEdge(from, to);
|
||||
BOOST_ASSERT(edge_id_1 != SPECIAL_EDGEID);
|
||||
|
||||
// find reverse edge id and
|
||||
const EdgeID edge_id_2 = compressed_output_graph.FindEdge(to, from);
|
||||
BOOST_ASSERT(edge_id_2 != SPECIAL_EDGEID);
|
||||
|
||||
auto packed_geometry_id = compressed_edge_container.ZipEdges(edge_id_1, edge_id_2);
|
||||
|
||||
// remember the geometry ID for both edges in the node-based graph
|
||||
compressed_output_graph.GetEdgeData(edge_id_1).geometry_id = {packed_geometry_id, true};
|
||||
compressed_output_graph.GetEdgeData(edge_id_2).geometry_id = {packed_geometry_id,
|
||||
false};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NodeBasedGraphFactory::CompressAnnotationData()
|
||||
{
|
||||
const constexpr AnnotationID INVALID_ANNOTATIONID = -1;
|
||||
// remap all entries to find which are used
|
||||
std::vector<AnnotationID> annotation_mapping(annotation_data.size(), INVALID_ANNOTATIONID);
|
||||
|
||||
// first we mark entries, by setting their mapping to 0
|
||||
for (const auto nbg_node_u : util::irange(0u, compressed_output_graph.GetNumberOfNodes()))
|
||||
{
|
||||
BOOST_ASSERT(nbg_node_u != SPECIAL_NODEID);
|
||||
for (EdgeID nbg_edge_id : compressed_output_graph.GetAdjacentEdgeRange(nbg_node_u))
|
||||
{
|
||||
auto const &edge = compressed_output_graph.GetEdgeData(nbg_edge_id);
|
||||
annotation_mapping[edge.annotation_data] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// now compute a prefix sum on all entries that are 0 to find the new mapping
|
||||
AnnotationID prefix_sum = 0;
|
||||
for (std::size_t i = 0; i < annotation_mapping.size(); ++i)
|
||||
{
|
||||
if (annotation_mapping[i] == 0)
|
||||
annotation_mapping[i] = prefix_sum++;
|
||||
else
|
||||
{
|
||||
// flag for removal
|
||||
annotation_data[i].name_id = INVALID_NAMEID;
|
||||
}
|
||||
}
|
||||
|
||||
// apply the mapping
|
||||
for (const auto nbg_node_u : util::irange(0u, compressed_output_graph.GetNumberOfNodes()))
|
||||
{
|
||||
BOOST_ASSERT(nbg_node_u != SPECIAL_NODEID);
|
||||
for (EdgeID nbg_edge_id : compressed_output_graph.GetAdjacentEdgeRange(nbg_node_u))
|
||||
{
|
||||
auto &edge = compressed_output_graph.GetEdgeData(nbg_edge_id);
|
||||
edge.annotation_data = annotation_mapping[edge.annotation_data];
|
||||
BOOST_ASSERT(edge.annotation_data != INVALID_ANNOTATIONID);
|
||||
}
|
||||
}
|
||||
|
||||
// remove unreferenced entries, shifting other entries to the front
|
||||
const auto new_end =
|
||||
std::remove_if(annotation_data.begin(), annotation_data.end(), [&](auto const &data) {
|
||||
// both elements are considered equal (to remove the second
|
||||
// one) if the annotation mapping of the second one is
|
||||
// invalid
|
||||
return data.name_id == INVALID_NAMEID;
|
||||
});
|
||||
|
||||
const auto old_size = annotation_data.size();
|
||||
// remove all remaining elements
|
||||
annotation_data.erase(new_end, annotation_data.end());
|
||||
util::Log() << " graoh compression removed " << (old_size - annotation_data.size())
|
||||
<< " annotations of " << old_size;
|
||||
}
|
||||
|
||||
void NodeBasedGraphFactory::ReleaseOsmNodes()
|
||||
{
|
||||
// replace with a new vector to release old memory
|
||||
extractor::PackedOSMIDs().swap(osm_node_ids);
|
||||
}
|
||||
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
@ -218,7 +218,7 @@ int Partitioner::Run(const PartitionConfig &config)
|
||||
files::writePartition(config.GetPath(".osrm.partition"), mlp);
|
||||
files::writeCells(config.GetPath(".osrm.cells"), storage);
|
||||
extractor::files::writeEdgeBasedGraph(config.GetPath(".osrm.ebg"),
|
||||
edge_based_graph.GetNumberOfNodes() - 1,
|
||||
edge_based_graph.GetNumberOfNodes(),
|
||||
graphToEdges(edge_based_graph));
|
||||
TIMER_STOP(writing_mld_data);
|
||||
util::Log() << "MLD data writing took " << TIMER_SEC(writing_mld_data) << " seconds";
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "extractor/class_data.hpp"
|
||||
#include "extractor/compressed_edge_container.hpp"
|
||||
#include "extractor/edge_based_edge.hpp"
|
||||
#include "extractor/edge_based_node.hpp"
|
||||
#include "extractor/files.hpp"
|
||||
#include "extractor/guidance/turn_instruction.hpp"
|
||||
#include "extractor/original_edge_data.hpp"
|
||||
@ -253,13 +254,11 @@ void Storage::PopulateLayout(DataLayout &layout)
|
||||
io::FileReader nodes_data_file(config.GetPath(".osrm.ebg_nodes"),
|
||||
io::FileReader::VerifyFingerprint);
|
||||
const auto nodes_number = nodes_data_file.ReadElementCount64();
|
||||
|
||||
layout.SetBlockSize<NodeID>(DataLayout::GEOMETRY_ID_LIST, nodes_number);
|
||||
layout.SetBlockSize<NameID>(DataLayout::NAME_ID_LIST, nodes_number);
|
||||
layout.SetBlockSize<ComponentID>(DataLayout::COMPONENT_ID_LIST, nodes_number);
|
||||
layout.SetBlockSize<extractor::TravelMode>(DataLayout::TRAVEL_MODE_LIST, nodes_number);
|
||||
layout.SetBlockSize<extractor::ClassData>(DataLayout::CLASSES_LIST, nodes_number);
|
||||
layout.SetBlockSize<unsigned>(DataLayout::IS_LEFT_HAND_DRIVING_LIST, nodes_number);
|
||||
const auto annotations_number = nodes_data_file.ReadElementCount64();
|
||||
layout.SetBlockSize<extractor::EdgeBasedNode>(DataLayout::EDGE_BASED_NODE_DATA_LIST,
|
||||
nodes_number);
|
||||
layout.SetBlockSize<extractor::NodeBasedEdgeAnnotation>(DataLayout::ANNOTATION_DATA_LIST,
|
||||
annotations_number);
|
||||
}
|
||||
|
||||
if (boost::filesystem::exists(config.GetPath(".osrm.hsgr")))
|
||||
@ -709,43 +708,21 @@ void Storage::PopulateData(const DataLayout &layout, char *memory_ptr)
|
||||
|
||||
// Load edge-based nodes data
|
||||
{
|
||||
auto geometry_id_list_ptr =
|
||||
layout.GetBlockPtr<GeometryID, true>(memory_ptr, storage::DataLayout::GEOMETRY_ID_LIST);
|
||||
util::vector_view<GeometryID> geometry_ids(
|
||||
geometry_id_list_ptr, layout.num_entries[storage::DataLayout::GEOMETRY_ID_LIST]);
|
||||
auto edge_based_node_data_list_ptr = layout.GetBlockPtr<extractor::EdgeBasedNode, true>(
|
||||
memory_ptr, storage::DataLayout::EDGE_BASED_NODE_DATA_LIST);
|
||||
util::vector_view<extractor::EdgeBasedNode> edge_based_node_data(
|
||||
edge_based_node_data_list_ptr,
|
||||
layout.num_entries[storage::DataLayout::EDGE_BASED_NODE_DATA_LIST]);
|
||||
|
||||
auto name_id_list_ptr =
|
||||
layout.GetBlockPtr<NameID, true>(memory_ptr, storage::DataLayout::NAME_ID_LIST);
|
||||
util::vector_view<NameID> name_ids(name_id_list_ptr,
|
||||
layout.num_entries[storage::DataLayout::NAME_ID_LIST]);
|
||||
auto annotation_data_list_ptr =
|
||||
layout.GetBlockPtr<extractor::NodeBasedEdgeAnnotation, true>(
|
||||
memory_ptr, storage::DataLayout::ANNOTATION_DATA_LIST);
|
||||
util::vector_view<extractor::NodeBasedEdgeAnnotation> annotation_data(
|
||||
annotation_data_list_ptr,
|
||||
layout.num_entries[storage::DataLayout::ANNOTATION_DATA_LIST]);
|
||||
|
||||
auto component_ids_ptr = layout.GetBlockPtr<ComponentID, true>(
|
||||
memory_ptr, storage::DataLayout::COMPONENT_ID_LIST);
|
||||
util::vector_view<ComponentID> component_ids(
|
||||
component_ids_ptr, layout.num_entries[storage::DataLayout::COMPONENT_ID_LIST]);
|
||||
|
||||
auto travel_mode_list_ptr = layout.GetBlockPtr<extractor::TravelMode, true>(
|
||||
memory_ptr, storage::DataLayout::TRAVEL_MODE_LIST);
|
||||
util::vector_view<extractor::TravelMode> travel_modes(
|
||||
travel_mode_list_ptr, layout.num_entries[storage::DataLayout::TRAVEL_MODE_LIST]);
|
||||
|
||||
auto classes_list_ptr = layout.GetBlockPtr<extractor::ClassData, true>(
|
||||
memory_ptr, storage::DataLayout::CLASSES_LIST);
|
||||
util::vector_view<extractor::ClassData> classes(
|
||||
classes_list_ptr, layout.num_entries[storage::DataLayout::CLASSES_LIST]);
|
||||
|
||||
auto is_left_hand_driving_ptr = layout.GetBlockPtr<unsigned, true>(
|
||||
memory_ptr, storage::DataLayout::IS_LEFT_HAND_DRIVING_LIST);
|
||||
util::vector_view<bool> is_left_hand_driving(
|
||||
is_left_hand_driving_ptr,
|
||||
layout.num_entries[storage::DataLayout::IS_LEFT_HAND_DRIVING_LIST]);
|
||||
|
||||
extractor::EdgeBasedNodeDataView node_data(std::move(geometry_ids),
|
||||
std::move(name_ids),
|
||||
std::move(component_ids),
|
||||
std::move(travel_modes),
|
||||
std::move(classes),
|
||||
std::move(is_left_hand_driving));
|
||||
extractor::EdgeBasedNodeDataView node_data(std::move(edge_based_node_data),
|
||||
std::move(annotation_data));
|
||||
|
||||
extractor::files::readNodeData(config.GetPath(".osrm.ebg_nodes"), node_data);
|
||||
}
|
||||
|
@ -55,12 +55,12 @@ std::size_t loadGraph(const std::string &path,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (input_edge.forward)
|
||||
if (input_edge.flags.forward)
|
||||
{
|
||||
graph_edge_list.emplace_back(input_edge.source, input_edge.target);
|
||||
}
|
||||
|
||||
if (input_edge.backward)
|
||||
if (input_edge.flags.backward)
|
||||
{
|
||||
graph_edge_list.emplace_back(input_edge.target, input_edge.source);
|
||||
}
|
||||
|
@ -524,8 +524,9 @@ Updater::NumNodesAndEdges Updater::LoadAndUpdateEdgeExpandedGraph() const
|
||||
{
|
||||
std::vector<EdgeWeight> node_weights;
|
||||
std::vector<extractor::EdgeBasedEdge> edge_based_edge_list;
|
||||
auto max_edge_id = Updater::LoadAndUpdateEdgeExpandedGraph(edge_based_edge_list, node_weights);
|
||||
return std::make_tuple(max_edge_id + 1, std::move(edge_based_edge_list));
|
||||
auto number_of_edge_based_nodes =
|
||||
Updater::LoadAndUpdateEdgeExpandedGraph(edge_based_edge_list, node_weights);
|
||||
return std::make_tuple(number_of_edge_based_nodes, std::move(edge_based_edge_list));
|
||||
}
|
||||
|
||||
EdgeID
|
||||
@ -534,12 +535,12 @@ Updater::LoadAndUpdateEdgeExpandedGraph(std::vector<extractor::EdgeBasedEdge> &e
|
||||
{
|
||||
TIMER_START(load_edges);
|
||||
|
||||
EdgeID max_edge_id = 0;
|
||||
EdgeID number_of_edge_based_nodes = 0;
|
||||
std::vector<util::Coordinate> coordinates;
|
||||
extractor::PackedOSMIDs osm_node_ids;
|
||||
|
||||
extractor::files::readEdgeBasedGraph(
|
||||
config.GetPath(".osrm.ebg"), max_edge_id, edge_based_edge_list);
|
||||
config.GetPath(".osrm.ebg"), number_of_edge_based_nodes, edge_based_edge_list);
|
||||
extractor::files::readNodes(config.GetPath(".osrm.nbg_nodes"), coordinates, osm_node_ids);
|
||||
|
||||
const bool update_conditional_turns =
|
||||
@ -550,7 +551,7 @@ Updater::LoadAndUpdateEdgeExpandedGraph(std::vector<extractor::EdgeBasedEdge> &e
|
||||
if (!update_edge_weights && !update_turn_penalties && !update_conditional_turns)
|
||||
{
|
||||
saveDatasourcesNames(config);
|
||||
return max_edge_id;
|
||||
return number_of_edge_based_nodes;
|
||||
}
|
||||
|
||||
if (config.segment_speed_lookup_paths.size() + config.turn_penalty_lookup_paths.size() > 255)
|
||||
@ -838,7 +839,7 @@ Updater::LoadAndUpdateEdgeExpandedGraph(std::vector<extractor::EdgeBasedEdge> &e
|
||||
|
||||
TIMER_STOP(load_edges);
|
||||
util::Log() << "Done reading edges in " << TIMER_MSEC(load_edges) << "ms.";
|
||||
return max_edge_id;
|
||||
return number_of_edge_based_nodes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,23 +28,33 @@ inline InputEdge MakeUnitEdge(const NodeID from, const NodeID to)
|
||||
{
|
||||
// src, tgt, dist, edge_id, name_id, fwd, bkwd, roundabout, circular, startpoint, local access,
|
||||
// split edge, travel_mode
|
||||
return {
|
||||
from, // source
|
||||
to, // target
|
||||
1, // weight
|
||||
1, // duration
|
||||
SPECIAL_EDGEID, // edge_id
|
||||
0, // name_id
|
||||
false, // reversed
|
||||
false, // roundabout
|
||||
false, // circular
|
||||
false, // startpoint
|
||||
false, // is_left_hand_driving
|
||||
true, // split edge
|
||||
TRAVEL_MODE_INACCESSIBLE, // travel_mode
|
||||
0, // classes
|
||||
INVALID_LANE_DESCRIPTIONID // lane_description_id
|
||||
};
|
||||
return {from,
|
||||
to,
|
||||
1, // weight
|
||||
1, // duration
|
||||
GeometryID{0, false}, // geometry_id
|
||||
false, // reversed
|
||||
NodeBasedEdgeClassification(), // default flags
|
||||
0}; // AnnotationID
|
||||
}
|
||||
|
||||
bool compatible(Graph const &graph,
|
||||
const std::vector<NodeBasedEdgeAnnotation> &node_data_container,
|
||||
EdgeID const first,
|
||||
EdgeID second)
|
||||
{
|
||||
auto const &first_flags = graph.GetEdgeData(first).flags;
|
||||
auto const &second_flags = graph.GetEdgeData(second).flags;
|
||||
if (!(first_flags == second_flags))
|
||||
return false;
|
||||
|
||||
if (graph.GetEdgeData(first).reversed != graph.GetEdgeData(second).reversed)
|
||||
return false;
|
||||
|
||||
auto const &first_annotation = node_data_container[graph.GetEdgeData(first).annotation_data];
|
||||
auto const &second_annotation = node_data_container[graph.GetEdgeData(second).annotation_data];
|
||||
|
||||
return first_annotation.CanCombineWith(second_annotation);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@ -60,6 +70,7 @@ BOOST_AUTO_TEST_CASE(long_road_test)
|
||||
std::unordered_set<NodeID> traffic_lights;
|
||||
std::vector<TurnRestriction> restrictions;
|
||||
std::vector<ConditionalTurnRestriction> conditional_restrictions;
|
||||
std::vector<NodeBasedEdgeAnnotation> annotations(1);
|
||||
CompressedEdgeContainer container;
|
||||
test::MockScriptingEnvironment scripting_environment;
|
||||
|
||||
@ -72,19 +83,19 @@ BOOST_AUTO_TEST_CASE(long_road_test)
|
||||
MakeUnitEdge(3, 4),
|
||||
MakeUnitEdge(4, 3)};
|
||||
|
||||
BOOST_ASSERT(edges[0].data.IsCompatibleTo(edges[2].data));
|
||||
BOOST_ASSERT(edges[2].data.IsCompatibleTo(edges[4].data));
|
||||
BOOST_ASSERT(edges[4].data.IsCompatibleTo(edges[6].data));
|
||||
|
||||
Graph graph(5, edges);
|
||||
BOOST_ASSERT(compatible(graph, annotations, 0, 2));
|
||||
BOOST_ASSERT(compatible(graph, annotations, 2, 4));
|
||||
BOOST_ASSERT(compatible(graph, annotations, 4, 6));
|
||||
|
||||
compressor.Compress(barrier_nodes,
|
||||
traffic_lights,
|
||||
scripting_environment,
|
||||
restrictions,
|
||||
conditional_restrictions,
|
||||
graph,
|
||||
annotations,
|
||||
container);
|
||||
|
||||
BOOST_CHECK_EQUAL(graph.FindEdge(0, 1), SPECIAL_EDGEID);
|
||||
BOOST_CHECK_EQUAL(graph.FindEdge(1, 2), SPECIAL_EDGEID);
|
||||
BOOST_CHECK_EQUAL(graph.FindEdge(2, 3), SPECIAL_EDGEID);
|
||||
@ -106,6 +117,7 @@ BOOST_AUTO_TEST_CASE(loop_test)
|
||||
std::vector<TurnRestriction> restrictions;
|
||||
std::vector<ConditionalTurnRestriction> conditional_restrictions;
|
||||
CompressedEdgeContainer container;
|
||||
std::vector<NodeBasedEdgeAnnotation> annotations(1);
|
||||
test::MockScriptingEnvironment scripting_environment;
|
||||
|
||||
std::vector<InputEdge> edges = {MakeUnitEdge(0, 1),
|
||||
@ -121,26 +133,28 @@ BOOST_AUTO_TEST_CASE(loop_test)
|
||||
MakeUnitEdge(5, 0),
|
||||
MakeUnitEdge(5, 4)};
|
||||
|
||||
BOOST_ASSERT(edges.size() == 12);
|
||||
BOOST_ASSERT(edges[0].data.IsCompatibleTo(edges[1].data));
|
||||
BOOST_ASSERT(edges[1].data.IsCompatibleTo(edges[2].data));
|
||||
BOOST_ASSERT(edges[2].data.IsCompatibleTo(edges[3].data));
|
||||
BOOST_ASSERT(edges[3].data.IsCompatibleTo(edges[4].data));
|
||||
BOOST_ASSERT(edges[4].data.IsCompatibleTo(edges[5].data));
|
||||
BOOST_ASSERT(edges[5].data.IsCompatibleTo(edges[6].data));
|
||||
BOOST_ASSERT(edges[6].data.IsCompatibleTo(edges[7].data));
|
||||
BOOST_ASSERT(edges[7].data.IsCompatibleTo(edges[8].data));
|
||||
BOOST_ASSERT(edges[8].data.IsCompatibleTo(edges[9].data));
|
||||
BOOST_ASSERT(edges[9].data.IsCompatibleTo(edges[10].data));
|
||||
BOOST_ASSERT(edges[10].data.IsCompatibleTo(edges[11].data));
|
||||
|
||||
Graph graph(6, edges);
|
||||
BOOST_ASSERT(edges.size() == 12);
|
||||
BOOST_ASSERT(compatible(graph, annotations, 0, 1));
|
||||
BOOST_ASSERT(compatible(graph, annotations, 1, 2));
|
||||
BOOST_ASSERT(compatible(graph, annotations, 2, 3));
|
||||
BOOST_ASSERT(compatible(graph, annotations, 3, 4));
|
||||
BOOST_ASSERT(compatible(graph, annotations, 4, 5));
|
||||
BOOST_ASSERT(compatible(graph, annotations, 5, 6));
|
||||
BOOST_ASSERT(compatible(graph, annotations, 6, 7));
|
||||
BOOST_ASSERT(compatible(graph, annotations, 7, 8));
|
||||
BOOST_ASSERT(compatible(graph, annotations, 8, 9));
|
||||
BOOST_ASSERT(compatible(graph, annotations, 9, 10));
|
||||
BOOST_ASSERT(compatible(graph, annotations, 10, 11));
|
||||
BOOST_ASSERT(compatible(graph, annotations, 11, 0));
|
||||
|
||||
compressor.Compress(barrier_nodes,
|
||||
traffic_lights,
|
||||
scripting_environment,
|
||||
restrictions,
|
||||
conditional_restrictions,
|
||||
graph,
|
||||
annotations,
|
||||
container);
|
||||
|
||||
BOOST_CHECK_EQUAL(graph.FindEdge(5, 0), SPECIAL_EDGEID);
|
||||
@ -163,6 +177,7 @@ BOOST_AUTO_TEST_CASE(t_intersection)
|
||||
|
||||
std::unordered_set<NodeID> barrier_nodes;
|
||||
std::unordered_set<NodeID> traffic_lights;
|
||||
std::vector<NodeBasedEdgeAnnotation> annotations(1);
|
||||
std::vector<TurnRestriction> restrictions;
|
||||
std::vector<ConditionalTurnRestriction> conditional_restrictions;
|
||||
CompressedEdgeContainer container;
|
||||
@ -175,19 +190,20 @@ BOOST_AUTO_TEST_CASE(t_intersection)
|
||||
MakeUnitEdge(2, 1),
|
||||
MakeUnitEdge(3, 1)};
|
||||
|
||||
BOOST_ASSERT(edges[0].data.IsCompatibleTo(edges[1].data));
|
||||
BOOST_ASSERT(edges[1].data.IsCompatibleTo(edges[2].data));
|
||||
BOOST_ASSERT(edges[2].data.IsCompatibleTo(edges[3].data));
|
||||
BOOST_ASSERT(edges[3].data.IsCompatibleTo(edges[4].data));
|
||||
BOOST_ASSERT(edges[4].data.IsCompatibleTo(edges[5].data));
|
||||
|
||||
Graph graph(4, edges);
|
||||
BOOST_ASSERT(compatible(graph, annotations, 0, 1));
|
||||
BOOST_ASSERT(compatible(graph, annotations, 1, 2));
|
||||
BOOST_ASSERT(compatible(graph, annotations, 2, 3));
|
||||
BOOST_ASSERT(compatible(graph, annotations, 3, 4));
|
||||
BOOST_ASSERT(compatible(graph, annotations, 4, 5));
|
||||
|
||||
compressor.Compress(barrier_nodes,
|
||||
traffic_lights,
|
||||
scripting_environment,
|
||||
restrictions,
|
||||
conditional_restrictions,
|
||||
graph,
|
||||
annotations,
|
||||
container);
|
||||
|
||||
BOOST_CHECK(graph.FindEdge(0, 1) != SPECIAL_EDGEID);
|
||||
@ -204,6 +220,7 @@ BOOST_AUTO_TEST_CASE(street_name_changes)
|
||||
|
||||
std::unordered_set<NodeID> barrier_nodes;
|
||||
std::unordered_set<NodeID> traffic_lights;
|
||||
std::vector<NodeBasedEdgeAnnotation> annotations(2);
|
||||
std::vector<TurnRestriction> restrictions;
|
||||
std::vector<ConditionalTurnRestriction> conditional_restrictions;
|
||||
CompressedEdgeContainer container;
|
||||
@ -211,18 +228,21 @@ BOOST_AUTO_TEST_CASE(street_name_changes)
|
||||
|
||||
std::vector<InputEdge> edges = {
|
||||
MakeUnitEdge(0, 1), MakeUnitEdge(1, 0), MakeUnitEdge(1, 2), MakeUnitEdge(2, 1)};
|
||||
edges[2].data.name_id = edges[3].data.name_id = 1;
|
||||
|
||||
BOOST_ASSERT(edges[0].data.IsCompatibleTo(edges[1].data));
|
||||
BOOST_ASSERT(edges[2].data.IsCompatibleTo(edges[3].data));
|
||||
annotations[1].name_id = 1;
|
||||
edges[2].data.annotation_data = edges[3].data.annotation_data = 1;
|
||||
|
||||
Graph graph(5, edges);
|
||||
BOOST_ASSERT(compatible(graph, annotations, 0, 1));
|
||||
BOOST_ASSERT(compatible(graph, annotations, 2, 3));
|
||||
|
||||
compressor.Compress(barrier_nodes,
|
||||
traffic_lights,
|
||||
scripting_environment,
|
||||
restrictions,
|
||||
conditional_restrictions,
|
||||
graph,
|
||||
annotations,
|
||||
container);
|
||||
|
||||
BOOST_CHECK(graph.FindEdge(0, 1) != SPECIAL_EDGEID);
|
||||
@ -238,6 +258,7 @@ BOOST_AUTO_TEST_CASE(direction_changes)
|
||||
|
||||
std::unordered_set<NodeID> barrier_nodes;
|
||||
std::unordered_set<NodeID> traffic_lights;
|
||||
std::vector<NodeBasedEdgeAnnotation> annotations(1);
|
||||
std::vector<TurnRestriction> restrictions;
|
||||
std::vector<ConditionalTurnRestriction> conditional_restrictions;
|
||||
CompressedEdgeContainer container;
|
||||
@ -255,6 +276,7 @@ BOOST_AUTO_TEST_CASE(direction_changes)
|
||||
restrictions,
|
||||
conditional_restrictions,
|
||||
graph,
|
||||
annotations,
|
||||
container);
|
||||
|
||||
BOOST_CHECK(graph.FindEdge(0, 1) != SPECIAL_EDGEID);
|
||||
|
Loading…
Reference in New Issue
Block a user