Split intersection analysis and guidance code
Intersection analysis occupy in osrm::extractor::intersection namespace and guidance code osrm::guidance
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
#ifndef OSRM_EXTRACTOR_INTERSECTION_CONSTANTS_HPP_
|
||||
#define OSRM_EXTRACTOR_INTERSECTION_CONSTANTS_HPP_
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
namespace intersection
|
||||
{
|
||||
|
||||
// what angle is interpreted as going straight
|
||||
const double constexpr STRAIGHT_ANGLE = 180.;
|
||||
const double constexpr ORTHOGONAL_ANGLE = 90.;
|
||||
// if a turn deviates this much from going straight, it will be kept straight
|
||||
const double constexpr MAXIMAL_ALLOWED_NO_TURN_DEVIATION = 3.;
|
||||
// angle that lies between two nearly indistinguishable roads
|
||||
const double constexpr NARROW_TURN_ANGLE = 40.;
|
||||
const double constexpr GROUP_ANGLE = 60;
|
||||
// angle difference that can be classified as straight, if its the only narrow turn
|
||||
const double constexpr FUZZY_ANGLE_DIFFERENCE = 25.;
|
||||
|
||||
// Road priorities give an idea of how obvious a turn is. If two priorities differ greatly (e.g.
|
||||
// service road over a primary road, the better priority can be seen as obvious due to its road
|
||||
// category).
|
||||
const double constexpr PRIORITY_DISTINCTION_FACTOR = 1.75;
|
||||
|
||||
// the lane width we assume for a single lane
|
||||
const auto constexpr ASSUMED_LANE_WIDTH = 3.25;
|
||||
|
||||
// how far apart can roads be at the most, when thinking about merging them?
|
||||
const auto constexpr MERGABLE_ANGLE_DIFFERENCE = 95.0;
|
||||
|
||||
} // namespace intersection
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
||||
#endif // OSRM_EXTRACTOR_INTERSECTION_CONSTANTS_HPP_
|
||||
@@ -0,0 +1,258 @@
|
||||
#ifndef OSRM_EXTRACTOR_INTERSECTION_COORDINATE_EXTRACTOR_HPP_
|
||||
#define OSRM_EXTRACTOR_INTERSECTION_COORDINATE_EXTRACTOR_HPP_
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "extractor/compressed_edge_container.hpp"
|
||||
#include "extractor/query_node.hpp"
|
||||
|
||||
#include "util/attributes.hpp"
|
||||
#include "util/coordinate.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
namespace intersection
|
||||
{
|
||||
|
||||
class CoordinateExtractor
|
||||
{
|
||||
public:
|
||||
CoordinateExtractor(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const extractor::CompressedEdgeContainer &compressed_geometries,
|
||||
const std::vector<util::Coordinate> &node_coordinates);
|
||||
|
||||
/* Find a interpolated coordinate a long the compressed geometries. The desired coordinate
|
||||
* should be in a certain distance. This method is dedicated to find representative coordinates
|
||||
* at turns.
|
||||
* Note: The segment between intersection and turn coordinate can be zero, if the OSM modelling
|
||||
* is unfortunate. See https://github.com/Project-OSRM/osrm-backend/issues/3470
|
||||
*/
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
util::Coordinate GetCoordinateAlongRoad(const NodeID intersection_node,
|
||||
const EdgeID turn_edge,
|
||||
const bool traversed_in_reverse,
|
||||
const NodeID to_node,
|
||||
const std::uint8_t number_of_in_lanes) const;
|
||||
|
||||
// Given a set of precomputed coordinates, select the representative coordinate along the road
|
||||
// that best describes the turn
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
util::Coordinate
|
||||
ExtractRepresentativeCoordinate(const NodeID intersection_node,
|
||||
const EdgeID turn_edge,
|
||||
const bool traversed_in_reverse,
|
||||
const NodeID to_node,
|
||||
const std::uint8_t intersection_lanes,
|
||||
std::vector<util::Coordinate> coordinates) const;
|
||||
|
||||
// instead of finding only a single coordinate, we can also list all coordinates along a
|
||||
// road.
|
||||
OSRM_ATTR_WARN_UNUSED std::vector<util::Coordinate>
|
||||
GetCoordinatesAlongRoad(const NodeID intersection_node,
|
||||
const EdgeID turn_edge,
|
||||
const bool traversed_in_reverse,
|
||||
const NodeID to_node) const;
|
||||
|
||||
// wrapper in case of normal forward edges (traversed_in_reverse = false, to_node =
|
||||
// node_based_graph.GetTarget(turn_edge)
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
std::vector<util::Coordinate> GetForwardCoordinatesAlongRoad(const NodeID from,
|
||||
const EdgeID turn_edge) const;
|
||||
|
||||
// a less precise way to compute coordinates along a route. Due to the heavy interaction of
|
||||
// graph traversal and turn instructions, we often don't care for high precision. We only want
|
||||
// to check for available connections in order, or find (with room for error) the straightmost
|
||||
// turn. This function will offer a bit more error potential but allow for much higher
|
||||
// performance
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
util::Coordinate GetCoordinateCloseToTurn(const NodeID from_node,
|
||||
const EdgeID turn_edge,
|
||||
const bool traversed_in_reverse,
|
||||
const NodeID to_node) const;
|
||||
|
||||
/* When extracting the coordinates, we first extract all coordinates. We don't care about most
|
||||
* of them, though.
|
||||
*
|
||||
* Our very first step trims the coordinates to a saller set, close to the intersection.. The
|
||||
* idea here is to filter all coordinates at the end of the road and consider only the formi
|
||||
* close to the intersection:
|
||||
*
|
||||
* a -------------- v ----------.
|
||||
* .
|
||||
* .
|
||||
* .
|
||||
* b
|
||||
*
|
||||
* For calculating the turn angle for the intersection at `a`, we do not care about the turn
|
||||
* between `v` and `b`. This calculation trims the coordinates to the ones immediately at the
|
||||
* intersection.
|
||||
*
|
||||
* The optional length cache needs to store the accumulated distance up to the respective
|
||||
* coordinate index [0,d(0,1),...]
|
||||
*/
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
std::vector<util::Coordinate>
|
||||
TrimCoordinatesToLength(std::vector<util::Coordinate> coordinates,
|
||||
const double desired_length,
|
||||
const std::vector<double> &length_cache = {}) const;
|
||||
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
std::vector<double> PrepareLengthCache(const std::vector<util::Coordinate> &coordinates,
|
||||
const double limit) const;
|
||||
|
||||
/* when looking at a set of coordinates, this function allows trimming the vector to a smaller,
|
||||
* only containing coordinates up to a given distance along the path. The last coordinate might
|
||||
* be interpolated
|
||||
*/
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
std::vector<util::Coordinate>
|
||||
TrimCoordinatesByLengthFront(std::vector<util::Coordinate> coordinates,
|
||||
const double desired_length) const;
|
||||
|
||||
/*
|
||||
* to correct for the initial offset, we move the lookahead coordinate close
|
||||
* to the original road. We do so by subtracting the difference between the
|
||||
* turn coordinate and the offset coordinate from the lookahead coordinge:
|
||||
*
|
||||
* a ------ b ------ c
|
||||
* |
|
||||
* d
|
||||
* \
|
||||
* \
|
||||
* e
|
||||
*
|
||||
* is converted to:
|
||||
*
|
||||
* a ------ b ------ c
|
||||
* \
|
||||
* \
|
||||
* e
|
||||
*
|
||||
* for fixpoint `b`, vector_base `d` and vector_head `e`
|
||||
*/
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
util::Coordinate GetCorrectedCoordinate(const util::Coordinate fixpoint,
|
||||
const util::Coordinate vector_base,
|
||||
const util::Coordinate vector_head) const;
|
||||
|
||||
/* generate a uniform vector of coordinates in same range distances
|
||||
*
|
||||
* Turns:
|
||||
* x ------------ x -- x - x
|
||||
*
|
||||
* Into:
|
||||
* x -- x -- x -- x -- x - x
|
||||
*/
|
||||
OSRM_ATTR_WARN_UNUSED
|
||||
std::vector<util::Coordinate>
|
||||
SampleCoordinates(const std::vector<util::Coordinate> &coordinates,
|
||||
const double length,
|
||||
const double rate) const;
|
||||
|
||||
// find the coordinate at a specific distance in the vector
|
||||
util::Coordinate
|
||||
ExtractCoordinateAtLength(const double distance,
|
||||
const std::vector<util::Coordinate> &coordinates) const;
|
||||
util::Coordinate ExtractCoordinateAtLength(const double distance,
|
||||
const std::vector<util::Coordinate> &coordinates,
|
||||
const std::vector<double> &length_cache) const;
|
||||
|
||||
private:
|
||||
const util::NodeBasedDynamicGraph &node_based_graph;
|
||||
const extractor::CompressedEdgeContainer &compressed_geometries;
|
||||
const std::vector<util::Coordinate> &node_coordinates;
|
||||
|
||||
double ComputeInterpolationFactor(const double desired_distance,
|
||||
const double distance_to_first,
|
||||
const double distance_to_second) const;
|
||||
|
||||
std::pair<util::Coordinate, util::Coordinate>
|
||||
RegressionLine(const std::vector<util::Coordinate> &coordinates) const;
|
||||
|
||||
/* In an ideal world, the road would only have two coordinates if it goes mainly straigt. Since
|
||||
* OSM is operating on noisy data, we have some variations going straight.
|
||||
*
|
||||
* b d
|
||||
* a ---------------------------------------------- e
|
||||
* c
|
||||
*
|
||||
* The road from a-e offers a lot of variation, even though it is mostly straight. Here we
|
||||
* calculate the distances of all nodes in between to the straight line between a and e. If the
|
||||
* distances inbetween are small, we assume a straight road. To calculate these distances, we
|
||||
* don't use the coordinates of the road itself but our just calculated regression vector
|
||||
*/
|
||||
double GetMaxDeviation(std::vector<util::Coordinate>::const_iterator range_begin,
|
||||
const std::vector<util::Coordinate>::const_iterator &range_end,
|
||||
const util::Coordinate straight_begin,
|
||||
const util::Coordinate straight_end) const;
|
||||
|
||||
/*
|
||||
* the curve is still best described as looking at the very first vector for the turn angle.
|
||||
* Consider:
|
||||
*
|
||||
* |
|
||||
* a - 1
|
||||
* | o
|
||||
* | 2
|
||||
* | o
|
||||
* | 3
|
||||
* | o
|
||||
* | 4
|
||||
*
|
||||
* The turn itself from a-1 would be considered as a 90 degree turn, even though the road is
|
||||
* taking a turn later.
|
||||
* In this situaiton we return the very first coordinate, describing the road just at the
|
||||
* turn.
|
||||
* As an added benefit, we get a straight turn at a curved road:
|
||||
*
|
||||
* o b o
|
||||
* o o
|
||||
* o o
|
||||
* o o
|
||||
* o o
|
||||
* a c
|
||||
*
|
||||
* The turn from a-b to b-c is straight. With every vector we go further down the road, the
|
||||
* turn
|
||||
* angle would get stronger. Therefore we consider the very first coordinate as our best
|
||||
* choice
|
||||
*/
|
||||
bool IsCurve(const std::vector<util::Coordinate> &coordinates,
|
||||
const std::vector<double> &segment_distances,
|
||||
const double segment_length,
|
||||
const double considered_lane_width,
|
||||
const extractor::NodeBasedEdgeClassification &edge_data) const;
|
||||
|
||||
/*
|
||||
* If the very first coordinate is within lane offsets and the rest offers a near straight line,
|
||||
* we use an offset coordinate.
|
||||
*
|
||||
* ----------------------------------------
|
||||
*
|
||||
* ----------------------------------------
|
||||
* a -
|
||||
* ----------------------------------------
|
||||
* \
|
||||
* ----------------------------------------
|
||||
* \
|
||||
* b --------------------c
|
||||
*
|
||||
* Will be considered a very slight turn, instead of the near 90 degree turn we see right here.
|
||||
*/
|
||||
bool IsDirectOffset(const std::vector<util::Coordinate> &coordinates,
|
||||
const std::size_t straight_index,
|
||||
const double straight_distance,
|
||||
const double segment_length,
|
||||
const std::vector<double> &segment_distances,
|
||||
const std::uint8_t considered_lanes) const;
|
||||
};
|
||||
|
||||
} // namespace intersection
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
||||
#endif // OSRM_EXTRACTOR_INTERSECTION_COORDINATE_EXTRACTOR_HPP_
|
||||
@@ -0,0 +1,27 @@
|
||||
#ifndef OSRM_EXTRACTOR_INTERSECTION_HAVE_IDENTICAL_NAMES_HPP_
|
||||
#define OSRM_EXTRACTOR_INTERSECTION_HAVE_IDENTICAL_NAMES_HPP_
|
||||
|
||||
#include "extractor/suffix_table.hpp"
|
||||
#include "guidance/constants.hpp"
|
||||
#include "util/name_table.hpp"
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
namespace intersection
|
||||
{
|
||||
|
||||
// check if two name ids can be seen as identical (in presence of refs/others)
|
||||
// in our case this translates into no name announcement in either direction (lhs->rhs and
|
||||
// rhs->lhs)
|
||||
bool HaveIdenticalNames(const NameID lhs,
|
||||
const NameID rhs,
|
||||
const util::NameTable &name_table,
|
||||
const SuffixTable &street_name_suffix_table);
|
||||
|
||||
} // namespace intersection
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
||||
#endif /*OSRM_EXTRACTOR_INTERSECTION_HAVE_IDENTICAL_NAMES_HPP_*/
|
||||
@@ -3,9 +3,10 @@
|
||||
|
||||
#include "extractor/compressed_edge_container.hpp"
|
||||
#include "extractor/intersection/intersection_edge.hpp"
|
||||
#include "extractor/intersection/intersection_view.hpp"
|
||||
#include "extractor/intersection/mergable_road_detector.hpp"
|
||||
#include "extractor/restriction_index.hpp"
|
||||
#include "guidance/mergable_road_detector.hpp"
|
||||
#include "guidance/turn_lane_types.hpp"
|
||||
#include "extractor/turn_lane_types.hpp"
|
||||
|
||||
#include "util/coordinate.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
@@ -31,7 +32,7 @@ bool isTurnAllowed(const util::NodeBasedDynamicGraph &graph,
|
||||
const RestrictionMap &restriction_map,
|
||||
const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const IntersectionEdgeGeometries &geometries,
|
||||
const guidance::TurnLanesIndexedArray &turn_lanes_data,
|
||||
const TurnLanesIndexedArray &turn_lanes_data,
|
||||
const IntersectionEdge &from,
|
||||
const IntersectionEdge &to);
|
||||
|
||||
@@ -43,33 +44,31 @@ std::pair<IntersectionEdgeGeometries, std::unordered_set<EdgeID>>
|
||||
getIntersectionGeometries(const util::NodeBasedDynamicGraph &graph,
|
||||
const extractor::CompressedEdgeContainer &compressed_geometries,
|
||||
const std::vector<util::Coordinate> &node_coordinates,
|
||||
const guidance::MergableRoadDetector &detector,
|
||||
const MergableRoadDetector &detector,
|
||||
const NodeID intersection);
|
||||
|
||||
guidance::IntersectionView
|
||||
convertToIntersectionView(const util::NodeBasedDynamicGraph &graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const RestrictionMap &restriction_map,
|
||||
const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const IntersectionEdgeGeometries &edge_geometries,
|
||||
const guidance::TurnLanesIndexedArray &turn_lanes_data,
|
||||
const IntersectionEdge &incoming_edge,
|
||||
const IntersectionEdges &outgoing_edges,
|
||||
const std::unordered_set<EdgeID> &merged_edges);
|
||||
IntersectionView convertToIntersectionView(const util::NodeBasedDynamicGraph &graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const RestrictionMap &restriction_map,
|
||||
const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const IntersectionEdgeGeometries &edge_geometries,
|
||||
const TurnLanesIndexedArray &turn_lanes_data,
|
||||
const IntersectionEdge &incoming_edge,
|
||||
const IntersectionEdges &outgoing_edges,
|
||||
const std::unordered_set<EdgeID> &merged_edges);
|
||||
|
||||
// Check for restrictions/barriers and generate a list of valid and invalid turns present at
|
||||
// the node reached from `incoming_edge`. The resulting candidates have to be analyzed
|
||||
// for their actual instructions later on.
|
||||
template <bool USE_CLOSE_COORDINATE>
|
||||
guidance::IntersectionView
|
||||
getConnectedRoads(const util::NodeBasedDynamicGraph &graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const std::vector<util::Coordinate> &node_coordinates,
|
||||
const extractor::CompressedEdgeContainer &compressed_geometries,
|
||||
const RestrictionMap &node_restriction_map,
|
||||
const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const guidance::TurnLanesIndexedArray &turn_lanes_data,
|
||||
const IntersectionEdge &incoming_edge);
|
||||
IntersectionView getConnectedRoads(const util::NodeBasedDynamicGraph &graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const std::vector<util::Coordinate> &node_coordinates,
|
||||
const extractor::CompressedEdgeContainer &compressed_geometries,
|
||||
const RestrictionMap &node_restriction_map,
|
||||
const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const TurnLanesIndexedArray &turn_lanes_data,
|
||||
const IntersectionEdge &incoming_edge);
|
||||
|
||||
// Graph Compression cannot compress every setting. For example any barrier/traffic light cannot
|
||||
// be compressed. As a result, a simple road of the form `a ----- b` might end up as having an
|
||||
|
||||
@@ -0,0 +1,256 @@
|
||||
#ifndef OSRM_EXTRACTOR_INTERSECTION_INTERSECTION_VIEW_HPP_
|
||||
#define OSRM_EXTRACTOR_INTERSECTION_INTERSECTION_VIEW_HPP_
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "util/bearing.hpp"
|
||||
#include "util/log.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
#include "util/typedefs.hpp" // EdgeID
|
||||
|
||||
#include "guidance/turn_instruction.hpp"
|
||||
|
||||
#include <boost/range/algorithm/count_if.hpp>
|
||||
#include <boost/range/algorithm/find_if.hpp>
|
||||
#include <boost/range/algorithm/min_element.hpp>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
namespace intersection
|
||||
{
|
||||
|
||||
// the shape of an intersection only knows about edge IDs and bearings
|
||||
// `bearing` is the direction in clockwise angle from true north after taking the turn:
|
||||
// 0 = heading north, 90 = east, 180 = south, 270 = west
|
||||
struct IntersectionShapeData
|
||||
{
|
||||
EdgeID eid;
|
||||
double bearing;
|
||||
double segment_length;
|
||||
};
|
||||
|
||||
inline auto makeCompareShapeDataByBearing(const double base_bearing)
|
||||
{
|
||||
return [base_bearing](const auto &lhs, const auto &rhs) {
|
||||
return util::angularDeviation(lhs.bearing, base_bearing) <
|
||||
util::angularDeviation(rhs.bearing, base_bearing);
|
||||
};
|
||||
}
|
||||
|
||||
inline auto makeCompareAngularDeviation(const double angle)
|
||||
{
|
||||
return [angle](const auto &lhs, const auto &rhs) {
|
||||
return util::angularDeviation(lhs.angle, angle) < util::angularDeviation(rhs.angle, angle);
|
||||
};
|
||||
}
|
||||
|
||||
inline auto makeExtractLanesForRoad(const util::NodeBasedDynamicGraph &node_based_graph)
|
||||
{
|
||||
return [&node_based_graph](const auto &road) {
|
||||
return node_based_graph.GetEdgeData(road.eid).road_classification.GetNumberOfLanes();
|
||||
};
|
||||
}
|
||||
|
||||
// When viewing an intersection from an incoming edge, we can transform a shape into a view which
|
||||
// gives additional information on angles and whether a turn is allowed
|
||||
struct IntersectionViewData : IntersectionShapeData
|
||||
{
|
||||
IntersectionViewData(const IntersectionShapeData &shape,
|
||||
const bool entry_allowed,
|
||||
const double angle)
|
||||
: IntersectionShapeData(shape), entry_allowed(entry_allowed), angle(angle)
|
||||
{
|
||||
}
|
||||
|
||||
bool entry_allowed;
|
||||
double angle;
|
||||
|
||||
bool CompareByAngle(const IntersectionViewData &other) const;
|
||||
};
|
||||
|
||||
// small helper function to print the content of a connected road
|
||||
std::string toString(const IntersectionShapeData &shape);
|
||||
std::string toString(const IntersectionViewData &view);
|
||||
|
||||
// Intersections are sorted roads: [0] being the UTurn road, then from sharp right to sharp left.
|
||||
// common operations shared amongst all intersection types
|
||||
template <typename Self> struct EnableShapeOps
|
||||
{
|
||||
// same as closest turn, but for bearings
|
||||
auto FindClosestBearing(double bearing) const
|
||||
{
|
||||
auto comp = makeCompareShapeDataByBearing(bearing);
|
||||
return std::min_element(self()->begin(), self()->end(), comp);
|
||||
}
|
||||
|
||||
// search a given eid in the intersection
|
||||
auto FindEid(const EdgeID eid) const
|
||||
{
|
||||
return boost::range::find_if(*self(), [eid](const auto &road) { return road.eid == eid; });
|
||||
}
|
||||
|
||||
// find the maximum value based on a conversion operator
|
||||
template <typename UnaryProjection> auto FindMaximum(UnaryProjection converter) const
|
||||
{
|
||||
BOOST_ASSERT(!self()->empty());
|
||||
auto initial = converter(self()->front());
|
||||
|
||||
const auto extract_maximal_value = [&initial, converter](const auto &road) {
|
||||
initial = std::max(initial, converter(road));
|
||||
return false;
|
||||
};
|
||||
|
||||
boost::range::find_if(*self(), extract_maximal_value);
|
||||
return initial;
|
||||
}
|
||||
|
||||
// find the maximum value based on a conversion operator and a predefined initial value
|
||||
template <typename UnaryPredicate> auto Count(UnaryPredicate detector) const
|
||||
{
|
||||
BOOST_ASSERT(!self()->empty());
|
||||
return boost::range::count_if(*self(), detector);
|
||||
}
|
||||
|
||||
private:
|
||||
auto self() { return static_cast<Self *>(this); }
|
||||
auto self() const { return static_cast<const Self *>(this); }
|
||||
};
|
||||
|
||||
struct IntersectionShape final : std::vector<IntersectionShapeData>, //
|
||||
EnableShapeOps<IntersectionShape> //
|
||||
{
|
||||
using Base = std::vector<IntersectionShapeData>;
|
||||
};
|
||||
|
||||
// Common operations shared among IntersectionView and Intersections.
|
||||
// Inherit to enable those operations on your compatible type. CRTP pattern.
|
||||
template <typename Self> struct EnableIntersectionOps
|
||||
{
|
||||
// Find the turn whose angle offers the least angular deviation to the specified angle
|
||||
// For turn angles [0, 90, 260] and a query of 180 we return the 260 degree turn.
|
||||
auto findClosestTurn(double angle) const
|
||||
{
|
||||
auto comp = makeCompareAngularDeviation(angle);
|
||||
return boost::range::min_element(*self(), comp);
|
||||
}
|
||||
// returns a non-const_interator
|
||||
auto findClosestTurn(double angle)
|
||||
{
|
||||
auto comp = makeCompareAngularDeviation(angle);
|
||||
return std::min_element(self()->begin(), self()->end(), comp);
|
||||
}
|
||||
|
||||
/* Check validity of the intersection object. We assume a few basic properties every set of
|
||||
* connected roads should follow throughout guidance pre-processing. This utility function
|
||||
* allows checking intersections for validity
|
||||
*/
|
||||
auto valid() const
|
||||
{
|
||||
if (self()->empty())
|
||||
return false;
|
||||
|
||||
auto comp = [](const auto &lhs, const auto &rhs) { return lhs.CompareByAngle(rhs); };
|
||||
|
||||
const auto ordered = std::is_sorted(self()->begin(), self()->end(), comp);
|
||||
|
||||
if (!ordered)
|
||||
return false;
|
||||
|
||||
const auto uturn = self()->operator[](0).angle < std::numeric_limits<double>::epsilon();
|
||||
|
||||
if (!uturn)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns the UTurn road we took to arrive at this intersection.
|
||||
const auto &getUTurnRoad() const { return self()->operator[](0); }
|
||||
|
||||
// Returns the right-most road at this intersection.
|
||||
const auto &getRightmostRoad() const
|
||||
{
|
||||
return self()->size() > 1 ? self()->operator[](1) : self()->getUTurnRoad();
|
||||
}
|
||||
|
||||
// Returns the left-most road at this intersection.
|
||||
const auto &getLeftmostRoad() const
|
||||
{
|
||||
return self()->size() > 1 ? self()->back() : self()->getUTurnRoad();
|
||||
}
|
||||
|
||||
// Can this be skipped over?
|
||||
auto isTrafficSignalOrBarrier() const { return self()->size() == 2; }
|
||||
|
||||
// Checks if there is at least one road available (except UTurn road) on which to continue.
|
||||
auto isDeadEnd() const
|
||||
{
|
||||
auto pred = [](const auto &road) { return road.entry_allowed; };
|
||||
return std::none_of(self()->begin() + 1, self()->end(), pred);
|
||||
}
|
||||
|
||||
// Returns the number of roads we can enter at this intersection, respectively.
|
||||
auto countEnterable() const
|
||||
{
|
||||
auto pred = [](const auto &road) { return road.entry_allowed; };
|
||||
return boost::range::count_if(*self(), pred);
|
||||
}
|
||||
|
||||
// Returns the number of roads we can not enter at this intersection, respectively.
|
||||
auto countNonEnterable() const { return self()->size() - self()->countEnterable(); }
|
||||
|
||||
// same as find closests turn but with an additional predicate to allow filtering
|
||||
// the filter has to return `true` for elements that should be ignored
|
||||
template <typename UnaryPredicate>
|
||||
auto findClosestTurn(const double angle, const UnaryPredicate filter) const
|
||||
{
|
||||
BOOST_ASSERT(!self()->empty());
|
||||
const auto candidate =
|
||||
boost::range::min_element(*self(), [angle, &filter](const auto &lhs, const auto &rhs) {
|
||||
const auto filtered_lhs = filter(lhs), filtered_rhs = filter(rhs);
|
||||
const auto deviation_lhs = util::angularDeviation(lhs.angle, angle),
|
||||
deviation_rhs = util::angularDeviation(rhs.angle, angle);
|
||||
return std::tie(filtered_lhs, deviation_lhs) <
|
||||
std::tie(filtered_rhs, deviation_rhs);
|
||||
});
|
||||
|
||||
// make sure only to return valid elements
|
||||
return filter(*candidate) ? self()->end() : candidate;
|
||||
}
|
||||
|
||||
// check if all roads between begin and end allow entry
|
||||
template <typename InputIt>
|
||||
bool hasAllValidEntries(const InputIt begin, const InputIt end) const
|
||||
{
|
||||
static_assert(
|
||||
std::is_base_of<std::input_iterator_tag,
|
||||
typename std::iterator_traits<InputIt>::iterator_category>::value,
|
||||
"hasAllValidEntries() only accepts input iterators");
|
||||
return std::all_of(
|
||||
begin, end, [](const IntersectionViewData &road) { return road.entry_allowed; });
|
||||
}
|
||||
|
||||
private:
|
||||
auto self() { return static_cast<Self *>(this); }
|
||||
auto self() const { return static_cast<const Self *>(this); }
|
||||
};
|
||||
|
||||
struct IntersectionView final : std::vector<IntersectionViewData>, //
|
||||
EnableShapeOps<IntersectionView>, //
|
||||
EnableIntersectionOps<IntersectionView> //
|
||||
{
|
||||
using Base = std::vector<IntersectionViewData>;
|
||||
};
|
||||
|
||||
} // namespace intersection
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
||||
#endif /* OSRM_EXTRACTOR_INTERSECTION_INTERSECTION_VIEW_HPP_*/
|
||||
@@ -0,0 +1,184 @@
|
||||
#ifndef OSRM_EXTRACTOR_GUIDANCE_MERGEABLE_ROADS
|
||||
#define OSRM_EXTRACTOR_GUIDANCE_MERGEABLE_ROADS
|
||||
|
||||
#include "extractor/compressed_edge_container.hpp"
|
||||
#include "extractor/intersection/coordinate_extractor.hpp"
|
||||
#include "extractor/intersection/have_identical_names.hpp"
|
||||
#include "extractor/restriction_index.hpp"
|
||||
#include "extractor/turn_lane_types.hpp"
|
||||
#include "guidance/intersection.hpp"
|
||||
#include "util/coordinate.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
|
||||
// FWD declarations
|
||||
namespace util
|
||||
{
|
||||
class NameTable;
|
||||
} // namespace util
|
||||
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
class SuffixTable;
|
||||
|
||||
namespace intersection
|
||||
{
|
||||
class IntersectionGenerator;
|
||||
class CoordinateExtractor;
|
||||
|
||||
class MergableRoadDetector
|
||||
{
|
||||
public:
|
||||
// in case we have to change the mode we are operating on
|
||||
using MergableRoadData = IntersectionShapeData;
|
||||
|
||||
MergableRoadDetector(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const std::vector<util::Coordinate> &node_coordinates,
|
||||
const extractor::CompressedEdgeContainer &compressed_geometries,
|
||||
const RestrictionMap &node_restriction_map,
|
||||
const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const TurnLanesIndexedArray &turn_lanes_data,
|
||||
const util::NameTable &name_table,
|
||||
const SuffixTable &street_name_suffix_table);
|
||||
|
||||
// OSM ways tend to be modelled as separate ways for different directions. This is often due to
|
||||
// small gras strips in the middle between the two directions or due to pedestrian islands at
|
||||
// intersections.
|
||||
//
|
||||
// To reduce unnecessary information due to these artificial intersections (which are not
|
||||
// actually perceived as such) we try and merge these for our internal representation to both
|
||||
// get better perceived turn angles and get a better reprsentation of our intersections in
|
||||
// general.
|
||||
//
|
||||
// i h i,h
|
||||
// | | |
|
||||
// | | |
|
||||
// b - - - v - - - g |
|
||||
// > a < is transformed into: b,c - - - a - - - g,f
|
||||
// c - - - ^ - - - f |
|
||||
// | | |
|
||||
// | | |
|
||||
// d e d,e
|
||||
bool CanMergeRoad(const NodeID intersection_node,
|
||||
const MergableRoadData &lhs,
|
||||
const MergableRoadData &rhs) const;
|
||||
|
||||
// check if a road cannot influence the merging of the other. This is necessary to prevent
|
||||
// situations with more than two roads that could participate in a merge
|
||||
bool IsDistinctFrom(const MergableRoadData &lhs, const MergableRoadData &rhs) const;
|
||||
|
||||
private:
|
||||
// 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 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
|
||||
// itself. We need to skip at least a single node in between.
|
||||
bool IsTrafficLoop(const NodeID intersection_node, const MergableRoadData &road) const;
|
||||
|
||||
// Detector to check if we are looking at roads splitting up just prior to entering an
|
||||
// intersection:
|
||||
//
|
||||
// c
|
||||
// / |
|
||||
// a -< |
|
||||
// \ |
|
||||
// b
|
||||
//
|
||||
// A common scheme in OSRM is that roads spit up in separate ways when approaching an
|
||||
// intersection. This detector tries to detect these narrow triangles which usually just offer a
|
||||
// small island for pedestrians in the middle.
|
||||
bool IsNarrowTriangle(const NodeID intersection_node,
|
||||
const MergableRoadData &lhs,
|
||||
const MergableRoadData &rhs) const;
|
||||
|
||||
// Detector to check for whether two roads are following the same direction.
|
||||
// If roads don't end up right at a connected intersection, we could look at a situation like
|
||||
//
|
||||
// __________________________
|
||||
// /
|
||||
// ---
|
||||
// \__________________________
|
||||
//
|
||||
// This detector tries to find out about whether two roads are parallel after the separation
|
||||
bool HaveSameDirection(const NodeID intersection_node,
|
||||
const MergableRoadData &lhs,
|
||||
const MergableRoadData &rhs) const;
|
||||
|
||||
// Detector for small traffic islands. If a road is splitting up, just to connect again later,
|
||||
// we don't wan't to have this information within our list of intersections/possible turn
|
||||
// locations.
|
||||
//
|
||||
// ___________
|
||||
// ---<___________>-----
|
||||
//
|
||||
//
|
||||
// Would feel just like a single straight road to a driver and should be represented as such in
|
||||
// our engine
|
||||
bool IsTrafficIsland(const NodeID intersection_node,
|
||||
const MergableRoadData &lhs,
|
||||
const MergableRoadData &rhs) const;
|
||||
|
||||
// A negative detector, preventing a merge, trying to detect link roads between two main roads.
|
||||
//
|
||||
// d - - - - - - - - e - f
|
||||
// . / '
|
||||
// a - - - b - - - - - - c
|
||||
//
|
||||
// The detector wants to prevent merges that are connected to `b-e`
|
||||
bool IsLinkRoad(const NodeID intersection_node, const MergableRoadData &road) const;
|
||||
|
||||
// The condition suppresses roads merging for intersections like
|
||||
// . .
|
||||
// . .
|
||||
// ---- ----
|
||||
// . .
|
||||
// . .
|
||||
// but will allow roads merging for intersections like
|
||||
// -------
|
||||
// / \
|
||||
// ---- ----
|
||||
// \ /
|
||||
// -------
|
||||
bool IsCircularShape(const NodeID intersection_node,
|
||||
const MergableRoadData &lhs,
|
||||
const MergableRoadData &rhs) const;
|
||||
|
||||
const util::NodeBasedDynamicGraph &node_based_graph;
|
||||
const EdgeBasedNodeDataContainer &node_data_container;
|
||||
const std::vector<util::Coordinate> &node_coordinates;
|
||||
const extractor::CompressedEdgeContainer &compressed_geometries;
|
||||
const RestrictionMap &node_restriction_map;
|
||||
const std::unordered_set<NodeID> &barrier_nodes;
|
||||
const TurnLanesIndexedArray &turn_lanes_data;
|
||||
|
||||
// name detection
|
||||
const util::NameTable &name_table;
|
||||
const SuffixTable &street_name_suffix_table;
|
||||
|
||||
const CoordinateExtractor coordinate_extractor;
|
||||
|
||||
// limit for detecting circles / parallel roads
|
||||
const static double constexpr distance_to_extract = 120;
|
||||
};
|
||||
|
||||
} // namespace guidance
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,318 @@
|
||||
#ifndef OSRM_EXTRACTOR_INTERSECTION_NODE_BASED_GRAPH_WALKER
|
||||
#define OSRM_EXTRACTOR_INTERSECTION_NODE_BASED_GRAPH_WALKER
|
||||
|
||||
#include "extractor/intersection/coordinate_extractor.hpp"
|
||||
#include "extractor/intersection/intersection_analysis.hpp"
|
||||
#include "extractor/intersection/intersection_view.hpp"
|
||||
#include "guidance/turn_lane_data.hpp"
|
||||
#include "util/coordinate.hpp"
|
||||
#include "util/coordinate_calculation.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
namespace intersection
|
||||
{
|
||||
|
||||
/*
|
||||
* The graph hopper is a utility that lets you find certain intersections with a node based graph,
|
||||
* accumulating information along the way
|
||||
*/
|
||||
class NodeBasedGraphWalker
|
||||
{
|
||||
public:
|
||||
NodeBasedGraphWalker(const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const std::vector<util::Coordinate> &node_coordinates,
|
||||
const extractor::CompressedEdgeContainer &compressed_geometries,
|
||||
const RestrictionMap &node_restriction_map,
|
||||
const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const TurnLanesIndexedArray &turn_lanes_data);
|
||||
|
||||
/*
|
||||
* the returned node-id, edge-id are either the last ones used, just prior accumulator
|
||||
* terminating or empty if the traversal ran into a dead end. For examples of the
|
||||
* selector/accumulator look below. You can find an example for both (and the required interface
|
||||
* description). The function returns the last used `NodeID` and `EdgeID` (node just prior to
|
||||
* the last intersection and the edge it was reached by), if it wasn't stopped early (e.g. the
|
||||
* selector not provinding any further edge to traverse)
|
||||
*/
|
||||
template <class accumulator_type, class selector_type>
|
||||
boost::optional<std::pair<NodeID, EdgeID>> TraverseRoad(NodeID starting_at_node_id,
|
||||
EdgeID following_edge_id,
|
||||
accumulator_type &accumulator,
|
||||
const selector_type &selector) const;
|
||||
|
||||
private:
|
||||
const util::NodeBasedDynamicGraph &node_based_graph;
|
||||
const EdgeBasedNodeDataContainer &node_data_container;
|
||||
const std::vector<util::Coordinate> &node_coordinates;
|
||||
const extractor::CompressedEdgeContainer &compressed_geometries;
|
||||
const RestrictionMap &node_restriction_map;
|
||||
const std::unordered_set<NodeID> &barrier_nodes;
|
||||
const TurnLanesIndexedArray &turn_lanes_data;
|
||||
};
|
||||
|
||||
/*
|
||||
* Accumulate all coordinates following a road until we
|
||||
* Example of a possible accumulator for walking a node-based graph
|
||||
*/
|
||||
struct LengthLimitedCoordinateAccumulator
|
||||
{
|
||||
LengthLimitedCoordinateAccumulator(
|
||||
const extractor::intersection::CoordinateExtractor &coordinate_extractor,
|
||||
const double max_length);
|
||||
|
||||
/*
|
||||
* !! REQUIRED - Function for the use of TraverseRoad in the graph walker.
|
||||
* Terminate should return true if the last intersection given to accumulator is supposed to
|
||||
* stop the search. A typical example would be to find the next intersection with degree larger
|
||||
* than 2 (an actual intersection). Here you should return true if the last intersection you
|
||||
* looked at was of degree larger than 2.
|
||||
*/
|
||||
bool terminate(); // true if the path has traversed enough distance
|
||||
|
||||
/*
|
||||
* !! REQUIRED - Function for the use of TraverseRoad in the graph walker.
|
||||
* starting with the very first provided node and edge, the graph walker will call `update` on
|
||||
* your accumulator. Here you can choose to accumulate any data that you might want to collect /
|
||||
* update your termination criteria. The accumulator described here will extract the coordinates
|
||||
* that we see traversing `via_edge` and store them for later usage.
|
||||
*/
|
||||
void update(const NodeID from_node, const EdgeID via_edge, const NodeID to_node);
|
||||
|
||||
double accumulated_length = 0;
|
||||
std::vector<util::Coordinate> coordinates;
|
||||
|
||||
private:
|
||||
const extractor::intersection::CoordinateExtractor &coordinate_extractor;
|
||||
const double max_length;
|
||||
};
|
||||
|
||||
/*
|
||||
* The SelectRoadByNameOnlyChoiceAndStraightness tries to follow a given name along a route. We
|
||||
* offer methods to skip
|
||||
* over bridges/similar situations if desired, following narrow turns
|
||||
* This struct offers an example implementation of a possible road selector for traversing the
|
||||
* node-based graph using the NodeBasedGraphWalker
|
||||
*/
|
||||
struct SelectRoadByNameOnlyChoiceAndStraightness
|
||||
{
|
||||
SelectRoadByNameOnlyChoiceAndStraightness(const NameID desired_name_id,
|
||||
const bool requires_entry);
|
||||
|
||||
/*
|
||||
* !! REQUIRED - Function for the use of TraverseRoad in the graph walker.
|
||||
* The operator() needs to return (if any is found) the next road to continue in the graph
|
||||
* traversal. If no such edge is found, return {} is allowed. Usually you want to choose some
|
||||
* form of obious turn to follow.
|
||||
*/
|
||||
boost::optional<EdgeID> operator()(const NodeID nid,
|
||||
const EdgeID via_edge_id,
|
||||
const IntersectionView &intersection,
|
||||
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container) const;
|
||||
|
||||
private:
|
||||
const NameID desired_name_id;
|
||||
const bool requires_entry;
|
||||
};
|
||||
|
||||
/* Following only a straight road
|
||||
* Follow only the straightmost turn, as long as its the only choice or has the desired name
|
||||
*/
|
||||
struct SelectStraightmostRoadByNameAndOnlyChoice
|
||||
{
|
||||
SelectStraightmostRoadByNameAndOnlyChoice(const NameID desired_name_id,
|
||||
const double initial_bearing,
|
||||
const bool requires_entry,
|
||||
const bool stop_on_ambiguous_turns);
|
||||
|
||||
/*
|
||||
* !! REQUIRED - Function for the use of TraverseRoad in the graph walker.
|
||||
* The operator() needs to return (if any is found) the next road to continue in the graph
|
||||
* traversal. If no such edge is found, return {} is allowed. Usually you want to choose some
|
||||
* form of obious turn to follow.
|
||||
*/
|
||||
boost::optional<EdgeID> operator()(const NodeID nid,
|
||||
const EdgeID via_edge_id,
|
||||
const IntersectionView &intersection,
|
||||
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container) const;
|
||||
|
||||
private:
|
||||
const NameID desired_name_id;
|
||||
const double initial_bearing;
|
||||
const bool requires_entry;
|
||||
const bool stop_on_ambiguous_turns;
|
||||
};
|
||||
|
||||
// find the next intersection given a hop limit
|
||||
struct IntersectionFinderAccumulator
|
||||
{
|
||||
IntersectionFinderAccumulator(const std::uint8_t hop_limit,
|
||||
const util::NodeBasedDynamicGraph &node_based_graph,
|
||||
const EdgeBasedNodeDataContainer &node_data_container,
|
||||
const std::vector<util::Coordinate> &node_coordinates,
|
||||
const extractor::CompressedEdgeContainer &compressed_geometries,
|
||||
const RestrictionMap &node_restriction_map,
|
||||
const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const TurnLanesIndexedArray &turn_lanes_data);
|
||||
// true if the path has traversed enough distance
|
||||
bool terminate();
|
||||
|
||||
// update the accumulator
|
||||
void update(const NodeID from_node, const EdgeID via_edge, const NodeID to_node);
|
||||
|
||||
std::uint8_t hops;
|
||||
const std::uint8_t hop_limit;
|
||||
|
||||
// the result we are looking for
|
||||
NodeID nid;
|
||||
EdgeID via_edge_id;
|
||||
IntersectionView intersection;
|
||||
|
||||
private:
|
||||
const util::NodeBasedDynamicGraph &node_based_graph;
|
||||
const EdgeBasedNodeDataContainer &node_data_container;
|
||||
const std::vector<util::Coordinate> &node_coordinates;
|
||||
const extractor::CompressedEdgeContainer &compressed_geometries;
|
||||
const RestrictionMap &node_restriction_map;
|
||||
const std::unordered_set<NodeID> &barrier_nodes;
|
||||
const TurnLanesIndexedArray &turn_lanes_data;
|
||||
};
|
||||
|
||||
template <class accumulator_type, class selector_type>
|
||||
boost::optional<std::pair<NodeID, EdgeID>>
|
||||
NodeBasedGraphWalker::TraverseRoad(NodeID current_node_id,
|
||||
EdgeID current_edge_id,
|
||||
accumulator_type &accumulator,
|
||||
const selector_type &selector) const
|
||||
{
|
||||
/*
|
||||
* since graph hopping is used in many ways, we don't generate an adjusted intersection
|
||||
* (otherwise we could end up in infinite recursion if we call the graph hopper during the
|
||||
* adjustment itself). Relying only on `GetConnectedRoads` (which itself does no graph hopping),
|
||||
* we prevent this from happening.
|
||||
*/
|
||||
const auto stop_node_id = current_node_id;
|
||||
/* we wan't to put out the last valid entries. To do so, we need to update within the following
|
||||
* loop. We use a for loop since traversal of the node-based-graph is expensive and we don't
|
||||
* want to look at many coordinates. If you require more than 2/3 intersections down the road,
|
||||
* you are doing something wrong/unsupported by OSRM. To not fail hard in cases that offer
|
||||
* strange loop contractions, we restrict ourselves to an extremely large number of possible
|
||||
* steps and simply warn in cases were extraction runs into these limits.
|
||||
*/
|
||||
for (std::size_t safety_hop_limit = 0; safety_hop_limit < 1000; ++safety_hop_limit)
|
||||
{
|
||||
accumulator.update(
|
||||
current_node_id, current_edge_id, node_based_graph.GetTarget(current_edge_id));
|
||||
|
||||
// we have looped back to our initial intersection
|
||||
if (node_based_graph.GetTarget(current_edge_id) == stop_node_id)
|
||||
return {};
|
||||
|
||||
// look at the next intersection
|
||||
const auto next_intersection =
|
||||
intersection::getConnectedRoads<true>(node_based_graph,
|
||||
node_data_container,
|
||||
node_coordinates,
|
||||
compressed_geometries,
|
||||
node_restriction_map,
|
||||
barrier_nodes,
|
||||
turn_lanes_data,
|
||||
{current_node_id, current_edge_id});
|
||||
|
||||
// don't follow u-turns or go past our initial intersection
|
||||
if (next_intersection.size() <= 1)
|
||||
return {};
|
||||
|
||||
auto next_edge_id = selector(current_node_id,
|
||||
current_edge_id,
|
||||
next_intersection,
|
||||
node_based_graph,
|
||||
node_data_container);
|
||||
|
||||
if (!next_edge_id)
|
||||
return {};
|
||||
|
||||
if (accumulator.terminate())
|
||||
return {std::make_pair(current_node_id, current_edge_id)};
|
||||
|
||||
current_node_id = node_based_graph.GetTarget(current_edge_id);
|
||||
current_edge_id = *next_edge_id;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(
|
||||
"Reached safety hop limit. Graph hopper seems to have been caught in an endless loop");
|
||||
return {};
|
||||
}
|
||||
|
||||
struct SkipTrafficSignalBarrierRoadSelector
|
||||
{
|
||||
boost::optional<EdgeID> operator()(const NodeID,
|
||||
const EdgeID,
|
||||
const IntersectionView &intersection,
|
||||
const util::NodeBasedDynamicGraph &,
|
||||
const EdgeBasedNodeDataContainer &) const
|
||||
{
|
||||
if (intersection.isTrafficSignalOrBarrier())
|
||||
{
|
||||
return boost::make_optional(intersection[1].eid);
|
||||
}
|
||||
else
|
||||
{
|
||||
return boost::none;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct DistanceToNextIntersectionAccumulator
|
||||
{
|
||||
DistanceToNextIntersectionAccumulator(
|
||||
const extractor::intersection::CoordinateExtractor &extractor_,
|
||||
const util::NodeBasedDynamicGraph &graph_,
|
||||
const double threshold)
|
||||
: extractor{extractor_}, graph{graph_}, threshold{threshold}
|
||||
{
|
||||
}
|
||||
|
||||
bool terminate()
|
||||
{
|
||||
if (distance > threshold)
|
||||
{
|
||||
too_far_away = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void update(const NodeID start, const EdgeID onto, const NodeID)
|
||||
{
|
||||
using namespace util::coordinate_calculation;
|
||||
|
||||
const auto coords = extractor.GetForwardCoordinatesAlongRoad(start, onto);
|
||||
distance += getLength(coords.begin(), coords.end(), &haversineDistance);
|
||||
}
|
||||
|
||||
const extractor::intersection::CoordinateExtractor &extractor;
|
||||
const util::NodeBasedDynamicGraph &graph;
|
||||
const double threshold;
|
||||
bool too_far_away = false;
|
||||
double distance = 0.;
|
||||
};
|
||||
|
||||
} // namespace guidance
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user