osrm-backend/include/extractor/guidance/turn_classification.hpp

123 lines
4.0 KiB
C++
Raw Normal View History

2016-02-24 04:29:23 -05:00
#ifndef OSRM_GUIDANCE_TURN_CLASSIFICATION_HPP_
#define OSRM_GUIDANCE_TURN_CLASSIFICATION_HPP_
2016-03-01 16:30:31 -05:00
#include "extractor/guidance/toolkit.hpp"
2016-02-24 04:29:23 -05:00
#include "util/coordinate.hpp"
#include "util/node_based_graph.hpp"
2016-04-11 06:51:06 -04:00
#include "util/typedefs.hpp"
2016-02-24 04:29:23 -05:00
#include "extractor/compressed_edge_container.hpp"
#include "extractor/query_node.hpp"
#include <algorithm>
#include <cstddef>
#include <vector>
namespace osrm
{
2016-03-01 16:30:31 -05:00
namespace extractor
2016-02-24 04:29:23 -05:00
{
namespace guidance
{
struct TurnPossibility
{
TurnPossibility(DiscreteAngle angle, EdgeID edge_id)
: angle(std::move(angle)), edge_id(std::move(edge_id))
{
}
TurnPossibility() : angle(0), edge_id(SPECIAL_EDGEID) {}
DiscreteAngle angle;
EdgeID edge_id;
};
2016-03-01 16:30:31 -05:00
struct CompareTurnPossibilities
{
bool operator()(const std::vector<TurnPossibility> &left,
const std::vector<TurnPossibility> &right) const
{
if (left.size() < right.size())
return true;
if (left.size() > right.size())
return false;
for (std::size_t i = 0; i < left.size(); ++i)
{
if ((((int)left[i].angle + 16) % 256) / 32 < (((int)right[i].angle + 16) % 256) / 32)
return true;
if ((((int)left[i].angle + 16) % 256) / 32 > (((int)right[i].angle + 16) % 256) / 32)
return false;
}
return false;
}
};
2016-02-24 04:29:23 -05:00
inline std::vector<TurnPossibility>
classifyIntersection(NodeID nid,
const util::NodeBasedDynamicGraph &graph,
const extractor::CompressedEdgeContainer &compressed_geometries,
const std::vector<extractor::QueryNode> &query_nodes)
{
std::vector<TurnPossibility> turns;
if (graph.BeginEdges(nid) == graph.EndEdges(nid))
return std::vector<TurnPossibility>();
const EdgeID base_id = graph.BeginEdges(nid);
const auto base_coordinate = getRepresentativeCoordinate(nid, graph.GetTarget(base_id), base_id,
graph.GetEdgeData(base_id).reversed,
compressed_geometries, query_nodes);
const auto node_coordinate = util::Coordinate(query_nodes[nid].lon, query_nodes[nid].lat);
2016-02-24 04:29:23 -05:00
// generate a list of all turn angles between a base edge, the node and a current edge
for (const EdgeID eid : graph.GetAdjacentEdgeRange(nid))
{
const auto edge_coordinate = getRepresentativeCoordinate(
nid, graph.GetTarget(eid), eid, false, compressed_geometries, query_nodes);
double angle = util::coordinate_calculation::computeAngle(base_coordinate, node_coordinate,
edge_coordinate);
turns.emplace_back(discretizeAngle(angle), eid);
}
std::sort(turns.begin(), turns.end(),
2016-04-11 06:51:06 -04:00
[](const TurnPossibility left, const TurnPossibility right) {
2016-02-24 04:29:23 -05:00
return left.angle < right.angle;
});
turns.push_back(turns.front()); // sentinel
for (std::size_t turn_nr = 0; turn_nr + 1 < turns.size(); ++turn_nr)
{
turns[turn_nr].angle = (256 + static_cast<uint32_t>(turns[turn_nr + 1].angle) -
static_cast<uint32_t>(turns[turn_nr].angle)) %
256; // calculate the difference to the right
}
turns.pop_back(); // remove sentinel again
// find largest:
std::size_t best_id = 0;
DiscreteAngle largest_turn_angle = turns.front().angle;
for (std::size_t current_turn_id = 1; current_turn_id < turns.size(); ++current_turn_id)
{
if (turns[current_turn_id].angle > largest_turn_angle)
{
largest_turn_angle = turns[current_turn_id].angle;
best_id = current_turn_id;
}
}
// rotate all angles so the largest angle comes first
std::rotate(turns.begin(), turns.begin() + best_id, turns.end());
return turns;
}
} // namespace guidance
2016-03-01 16:30:31 -05:00
} // namespace extractor
2016-02-24 04:29:23 -05:00
} // namespace osrm
#endif // OSRM_GUIDANCE_TURN_CLASSIFICATION_HPP_