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);
|
2016-02-25 08:40:26 -05:00
|
|
|
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_
|