2016-10-29 15:38:10 -04:00
|
|
|
#include "extractor/guidance/node_based_graph_walker.hpp"
|
2016-12-06 07:22:51 -05:00
|
|
|
#include "util/bearing.hpp"
|
|
|
|
#include "util/coordinate_calculation.hpp"
|
|
|
|
|
2016-12-02 04:53:22 -05:00
|
|
|
#include <utility>
|
|
|
|
|
|
|
|
using osrm::util::angularDeviation;
|
2016-10-29 15:38:10 -04:00
|
|
|
|
|
|
|
namespace osrm
|
|
|
|
{
|
|
|
|
namespace extractor
|
|
|
|
{
|
|
|
|
namespace guidance
|
|
|
|
{
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------------
|
|
|
|
NodeBasedGraphWalker::NodeBasedGraphWalker(const util::NodeBasedDynamicGraph &node_based_graph,
|
2017-09-25 09:37:11 -04:00
|
|
|
const EdgeBasedNodeDataContainer &node_data_container,
|
2016-10-29 15:38:10 -04:00
|
|
|
const IntersectionGenerator &intersection_generator)
|
2017-09-25 09:37:11 -04:00
|
|
|
: node_based_graph(node_based_graph), node_data_container(node_data_container),
|
|
|
|
intersection_generator(intersection_generator)
|
2016-10-29 15:38:10 -04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
LengthLimitedCoordinateAccumulator::LengthLimitedCoordinateAccumulator(
|
2016-12-06 07:22:51 -05:00
|
|
|
const extractor::guidance::CoordinateExtractor &coordinate_extractor, const double max_length)
|
|
|
|
: accumulated_length(0), coordinate_extractor(coordinate_extractor), max_length(max_length)
|
2016-10-29 15:38:10 -04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
bool LengthLimitedCoordinateAccumulator::terminate() { return accumulated_length >= max_length; }
|
|
|
|
|
|
|
|
// update the accumulator
|
|
|
|
void LengthLimitedCoordinateAccumulator::update(const NodeID from_node,
|
|
|
|
const EdgeID via_edge,
|
2016-11-03 05:18:27 -04:00
|
|
|
const NodeID /*to_node*/)
|
2016-10-29 15:38:10 -04:00
|
|
|
|
|
|
|
{
|
2016-11-15 08:18:28 -05:00
|
|
|
auto current_coordinates =
|
2016-11-03 05:18:27 -04:00
|
|
|
coordinate_extractor.GetForwardCoordinatesAlongRoad(from_node, via_edge);
|
2016-10-29 15:38:10 -04:00
|
|
|
|
2016-12-06 07:22:51 -05:00
|
|
|
const auto length =
|
|
|
|
util::coordinate_calculation::getLength(current_coordinates.begin(),
|
|
|
|
current_coordinates.end(),
|
|
|
|
util::coordinate_calculation::haversineDistance);
|
2016-10-29 15:38:10 -04:00
|
|
|
|
|
|
|
// in case we get too many coordinates, we limit them to our desired length
|
|
|
|
if (length + accumulated_length > max_length)
|
2016-11-15 08:18:28 -05:00
|
|
|
current_coordinates = coordinate_extractor.TrimCoordinatesToLength(
|
|
|
|
std::move(current_coordinates), max_length - accumulated_length);
|
2016-10-29 15:38:10 -04:00
|
|
|
|
|
|
|
coordinates.insert(coordinates.end(), current_coordinates.begin(), current_coordinates.end());
|
|
|
|
|
|
|
|
accumulated_length += length;
|
2016-12-06 07:22:51 -05:00
|
|
|
accumulated_length = std::min(accumulated_length, max_length);
|
2016-10-29 15:38:10 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------------
|
|
|
|
SelectRoadByNameOnlyChoiceAndStraightness::SelectRoadByNameOnlyChoiceAndStraightness(
|
|
|
|
const NameID desired_name_id, const bool requires_entry)
|
|
|
|
: desired_name_id(desired_name_id), requires_entry(requires_entry)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
boost::optional<EdgeID> SelectRoadByNameOnlyChoiceAndStraightness::
|
|
|
|
operator()(const NodeID /*nid*/,
|
|
|
|
const EdgeID /*via_edge_id*/,
|
2016-12-06 07:22:51 -05:00
|
|
|
const IntersectionView &intersection,
|
2017-09-25 09:37:11 -04:00
|
|
|
const util::NodeBasedDynamicGraph &node_based_graph,
|
|
|
|
const EdgeBasedNodeDataContainer &node_data_container) const
|
2016-10-29 15:38:10 -04:00
|
|
|
{
|
|
|
|
BOOST_ASSERT(!intersection.empty());
|
2017-09-25 09:37:11 -04:00
|
|
|
const auto comparator = [&](const IntersectionViewData &lhs, const IntersectionViewData &rhs) {
|
2016-10-29 15:38:10 -04:00
|
|
|
// the score of an elemnt results in an ranking preferring valid entries, if required over
|
2016-12-06 07:22:51 -05:00
|
|
|
// invalid requested name_ids over non-requested narrow deviations over non-narrow
|
2017-09-25 09:37:11 -04:00
|
|
|
const auto score = [&](const IntersectionViewData &road) {
|
2016-10-29 15:38:10 -04:00
|
|
|
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
|
2017-09-25 09:37:11 -04:00
|
|
|
if (desired_name_id !=
|
|
|
|
node_data_container
|
|
|
|
.GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data)
|
|
|
|
.name_id)
|
2016-10-29 15:38:10 -04:00
|
|
|
result_score += 180;
|
|
|
|
|
2016-11-03 05:18:27 -04:00
|
|
|
return result_score + angularDeviation(road.angle, STRAIGHT_ANGLE);
|
2016-10-29 15:38:10 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
return score(lhs) < score(rhs);
|
|
|
|
};
|
|
|
|
|
|
|
|
const auto min_element =
|
|
|
|
std::min_element(std::next(std::begin(intersection)), std::end(intersection), comparator);
|
|
|
|
|
|
|
|
if (min_element == intersection.end() || (requires_entry && !min_element->entry_allowed))
|
|
|
|
return {};
|
|
|
|
else
|
2016-11-03 05:18:27 -04:00
|
|
|
return (*min_element).eid;
|
2016-10-29 15:38:10 -04:00
|
|
|
}
|
|
|
|
|
2016-12-06 07:22:51 -05:00
|
|
|
// ---------------------------------------------------------------------------------
|
|
|
|
SelectStraightmostRoadByNameAndOnlyChoice::SelectStraightmostRoadByNameAndOnlyChoice(
|
|
|
|
const NameID desired_name_id, const double initial_bearing, const bool requires_entry)
|
|
|
|
: desired_name_id(desired_name_id), initial_bearing(initial_bearing),
|
|
|
|
requires_entry(requires_entry)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
boost::optional<EdgeID> SelectStraightmostRoadByNameAndOnlyChoice::
|
|
|
|
operator()(const NodeID /*nid*/,
|
|
|
|
const EdgeID /*via_edge_id*/,
|
|
|
|
const IntersectionView &intersection,
|
2017-09-25 09:37:11 -04:00
|
|
|
const util::NodeBasedDynamicGraph &node_based_graph,
|
|
|
|
const EdgeBasedNodeDataContainer &node_data_container) const
|
2016-12-06 07:22:51 -05:00
|
|
|
{
|
|
|
|
BOOST_ASSERT(!intersection.empty());
|
|
|
|
if (intersection.size() == 1)
|
|
|
|
return {};
|
|
|
|
|
2017-09-25 09:37:11 -04:00
|
|
|
const auto comparator = [&](const IntersectionViewData &lhs, const IntersectionViewData &rhs) {
|
2016-12-06 07:22:51 -05:00
|
|
|
// 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
|
2017-09-25 09:37:11 -04:00
|
|
|
const auto score = [&](const IntersectionViewData &road) {
|
2016-12-06 07:22:51 -05:00
|
|
|
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
|
2017-09-25 09:37:11 -04:00
|
|
|
if (desired_name_id !=
|
|
|
|
node_data_container
|
|
|
|
.GetAnnotation(node_based_graph.GetEdgeData(road.eid).annotation_data)
|
|
|
|
.name_id)
|
2016-12-06 07:22:51 -05:00
|
|
|
result_score += 180;
|
|
|
|
|
|
|
|
return result_score + angularDeviation(road.angle, STRAIGHT_ANGLE);
|
|
|
|
};
|
|
|
|
|
|
|
|
return score(lhs) < score(rhs);
|
|
|
|
};
|
|
|
|
|
|
|
|
const auto count_desired_name =
|
2017-09-25 09:37:11 -04:00
|
|
|
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;
|
|
|
|
});
|
2016-12-06 07:22:51 -05:00
|
|
|
if (count_desired_name > 2)
|
|
|
|
return {};
|
|
|
|
|
|
|
|
const auto min_element =
|
|
|
|
std::min_element(std::next(std::begin(intersection)), std::end(intersection), comparator);
|
|
|
|
|
|
|
|
const auto is_valid_choice = !requires_entry || min_element->entry_allowed;
|
|
|
|
const auto is_only_choice_with_same_name =
|
2017-10-18 07:05:36 -04:00
|
|
|
count_desired_name <= 2 && // <= in case we come from a bridge, otherwise we have a u-turn
|
|
|
|
// and the outgoing edge
|
2017-09-25 09:37:11 -04:00
|
|
|
node_data_container
|
|
|
|
.GetAnnotation(node_based_graph.GetEdgeData(min_element->eid).annotation_data)
|
|
|
|
.name_id == desired_name_id &&
|
2016-12-06 07:22:51 -05:00
|
|
|
angularDeviation(min_element->angle, STRAIGHT_ANGLE) < 100; // don't do crazy turns
|
|
|
|
const auto has_valid_angle =
|
|
|
|
((intersection.size() == 2 ||
|
|
|
|
intersection.findClosestTurn(STRAIGHT_ANGLE) == min_element) &&
|
|
|
|
angularDeviation(min_element->angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE) &&
|
|
|
|
angularDeviation(initial_bearing, min_element->bearing) < NARROW_TURN_ANGLE;
|
|
|
|
|
2017-10-18 07:05:36 -04:00
|
|
|
// do not allow major turns in the road, if other similar turns are present
|
|
|
|
// e.g.a turn at the end of the road:
|
|
|
|
//
|
|
|
|
// a - - a - - a - b - b
|
|
|
|
// |
|
|
|
|
// a - - a
|
|
|
|
// |
|
|
|
|
// c
|
|
|
|
//
|
|
|
|
// Such a turn can never be part of a merge
|
|
|
|
// We check if there is a similar turn to the other side. If such a turn exists, we consider the
|
|
|
|
// continuation of the road not possible
|
|
|
|
if (util::angularDeviation(STRAIGHT_ANGLE, min_element->angle) > GROUP_ANGLE)
|
|
|
|
{
|
|
|
|
auto deviation = util::angularDeviation(STRAIGHT_ANGLE, min_element->angle);
|
|
|
|
auto opposite_angle = min_element->angle >= STRAIGHT_ANGLE ? (STRAIGHT_ANGLE - deviation)
|
|
|
|
: (STRAIGHT_ANGLE + deviation);
|
|
|
|
auto opposite = intersection.findClosestTurn(opposite_angle);
|
|
|
|
auto opposite_deviation = util::angularDeviation(STRAIGHT_ANGLE, opposite->angle);
|
|
|
|
if (opposite_deviation <= deviation || (deviation / opposite_deviation) < 1.5)
|
|
|
|
{
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
auto const best = intersection.findClosestTurn(STRAIGHT_ANGLE);
|
|
|
|
if (util::angularDeviation(best->angle, STRAIGHT_ANGLE) < NARROW_TURN_ANGLE)
|
|
|
|
{
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-06 07:22:51 -05:00
|
|
|
// in cases where we have two edges between roads, we can have quite severe angles due to the
|
|
|
|
// random split OSRM does to break up parallel edges at any coordinate
|
|
|
|
if (!is_valid_choice || !(is_only_choice_with_same_name || has_valid_angle))
|
|
|
|
return {};
|
|
|
|
else
|
|
|
|
return (*min_element).eid;
|
|
|
|
}
|
|
|
|
|
2016-11-04 07:04:07 -04:00
|
|
|
// ---------------------------------------------------------------------------------
|
|
|
|
IntersectionFinderAccumulator::IntersectionFinderAccumulator(
|
|
|
|
const std::uint8_t hop_limit, const IntersectionGenerator &intersection_generator)
|
|
|
|
: hops(0), hop_limit(hop_limit), intersection_generator(intersection_generator)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IntersectionFinderAccumulator::terminate()
|
|
|
|
{
|
|
|
|
if (intersection.size() > 2 || hops == hop_limit)
|
|
|
|
{
|
|
|
|
hops = 0;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void IntersectionFinderAccumulator::update(const NodeID from_node,
|
|
|
|
const EdgeID via_edge,
|
|
|
|
const NodeID /*to_node*/)
|
|
|
|
{
|
|
|
|
++hops;
|
|
|
|
nid = from_node;
|
|
|
|
via_edge_id = via_edge;
|
|
|
|
|
2016-12-06 07:22:51 -05:00
|
|
|
intersection = intersection_generator.GetConnectedRoads(from_node, via_edge, true);
|
2016-11-04 07:04:07 -04:00
|
|
|
}
|
|
|
|
|
2016-10-29 15:38:10 -04:00
|
|
|
} // namespace guidance
|
|
|
|
} // namespace extractor
|
|
|
|
} // namespace osrm
|