refactor of turn analysis into turn handlers

This commit is contained in:
Moritz Kobitzsch
2016-04-08 12:49:14 +02:00
committed by Patrick Niklaus
parent dfd180a292
commit fcbf527ba5
14 changed files with 2985 additions and 2612 deletions
@@ -0,0 +1,66 @@
#ifndef OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_HPP_
#define OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_HPP_
#include <string>
#include <vector>
#include "extractor/guidance/turn_instruction.hpp"
#include "util/typedefs.hpp" // EdgeID
namespace osrm
{
namespace extractor
{
namespace guidance
{
// Every Turn Operation describes a way of switching onto a segment, indicated by an EdgeID. The
// associated turn is described by an angle and an instruction that is used to announce it.
// The Turn Operation indicates what is exposed to the outside of the turn analysis.
struct TurnOperation final
{
EdgeID eid;
double angle;
TurnInstruction instruction;
};
// A Connected Road is the internal representation of a potential turn. Internally, we require
// full list of all connected roads to determine the outcome.
// The reasoning behind is that even invalid turns can influence the perceived angles, or even
// instructions themselves. An pososible example can be described like this:
//
// aaa(2)aa
// a - bbbbb
// aaa(1)aa
//
// will not be perceived as a turn from (1) -> b, and as a U-turn from (1) -> (2).
// In addition, they can influence whether a turn is obvious or not. b->(2) would also be no
// turn-operation,
// but rather a name change.
//
// If this were a normal intersection with
//
// cccccccc
// o bbbbb
// aaaaaaaa
//
// We would perceive a->c as a sharp turn, a->b as a slight turn, and b->c as a slight turn.
struct ConnectedRoad final
{
ConnectedRoad(const TurnOperation turn, const bool entry_allowed = false);
// a turn may be relevant to good instructions, even if we cannot enter the road
bool entry_allowed;
TurnOperation turn;
};
// small helper function to print the content of a connected road
std::string toString(const ConnectedRoad &road);
typedef std::vector<ConnectedRoad> Intersection;
} // namespace guidance
} // namespace extractor
} // namespace osrm
#endif /*OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_HPP_*/
@@ -0,0 +1,68 @@
#ifndef OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_GENERATOR_HPP_
#define OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_GENERATOR_HPP_
#include "extractor/compressed_edge_container.hpp"
#include "extractor/guidance/intersection.hpp"
#include "extractor/query_node.hpp"
#include "extractor/restriction_map.hpp"
#include "util/node_based_graph.hpp"
#include "util/typedefs.hpp"
#include <unordered_set>
#include <vector>
namespace osrm
{
namespace extractor
{
namespace guidance
{
// The Intersection Generator is given a turn location and generates an intersection representation
// from it. For this all turn possibilities are analysed.
// We consider turn restrictions to indicate possible turns. U-turns are generated based on profile
// decisions.
class IntersectionGenerator
{
public:
IntersectionGenerator(const util::NodeBasedDynamicGraph &node_based_graph,
const RestrictionMap &restriction_map,
const std::unordered_set<NodeID> &barrier_nodes,
const std::vector<QueryNode> &node_info_list,
const CompressedEdgeContainer &compressed_edge_container);
Intersection operator()(const NodeID nid, const EdgeID via_eid) const;
private:
const util::NodeBasedDynamicGraph &node_based_graph;
const RestrictionMap &restriction_map;
const std::unordered_set<NodeID> &barrier_nodes;
const std::vector<QueryNode> &node_info_list;
const CompressedEdgeContainer &compressed_edge_container;
// Check for restrictions/barriers and generate a list of valid and invalid turns present at
// the
// node reached
// from `from_node` via `via_eid`
// The resulting candidates have to be analysed for their actual instructions later on.
Intersection getConnectedRoads(const NodeID from_node, const EdgeID via_eid) const;
// Merge segregated roads to omit invalid turns in favor of treating segregated roads as
// one.
// This function combines roads the following way:
//
// * *
// * is converted to *
// v ^ +
// v ^ +
//
// The treatment results in a straight turn angle of 180º rather than a turn angle of approx
// 160
Intersection mergeSegregatedRoads(Intersection intersection) const;
};
} // namespace guidance
} // namespace extractor
} // namespace osrm
#endif /* OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_GENERATOR_HPP_ */
@@ -0,0 +1,71 @@
#ifndef OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_HANDLER_HPP_
#define OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_HANDLER_HPP_
#include "extractor/guidance/intersection.hpp"
#include "extractor/query_node.hpp"
#include "util/name_table.hpp"
#include "util/node_based_graph.hpp"
#include <cstddef>
#include <vector>
namespace osrm
{
namespace extractor
{
namespace guidance
{
// Intersection handlers deal with all issues related to intersections.
// They assign appropriate turn operations to the TurnOperations.
// This base class provides both the interface and implementations for
// common functions.
class IntersectionHandler
{
public:
IntersectionHandler(const util::NodeBasedDynamicGraph &node_based_graph,
const std::vector<QueryNode> &node_info_list,
const util::NameTable &name_table);
virtual ~IntersectionHandler();
// check whether the handler can actually handle the intersection
virtual bool
canProcess(const NodeID nid, const EdgeID via_eid, const Intersection &intersection) const = 0;
// process the intersection
virtual Intersection
operator()(const NodeID nid, const EdgeID via_eid, Intersection intersection) const = 0;
protected:
const util::NodeBasedDynamicGraph &node_based_graph;
const std::vector<QueryNode> &node_info_list;
const util::NameTable &name_table;
// counts the number on allowed entry roads
std::size_t countValid(const Intersection &intersection) const;
// Decide on a basic turn types
TurnType findBasicTurnType(const EdgeID via_edge, const ConnectedRoad &candidate) const;
// Get the Instruction for an obvious turn
TurnInstruction getInstructionForObvious(const std::size_t number_of_candidates,
const EdgeID via_edge,
const bool through_street,
const ConnectedRoad &candidate) const;
// Treating potential forks
void assignFork(const EdgeID via_edge, ConnectedRoad &left, ConnectedRoad &right) const;
void assignFork(const EdgeID via_edge,
ConnectedRoad &left,
ConnectedRoad &center,
ConnectedRoad &right) const;
bool isThroughStreet(const std::size_t index, const Intersection &intersection) const;
};
} // namespace guidance
} // namespace extractor
} // namespace osrm
#endif /*OSRM_EXTRACTOR_GUIDANCE_INTERSECTION_HANDLER_HPP_*/
@@ -0,0 +1,51 @@
#ifndef OSRM_EXTRACTOR_GUIDANCE_MOTORWAY_HANDLER_HPP_
#define OSRM_EXTRACTOR_GUIDANCE_MOTORWAY_HANDLER_HPP_
#include "extractor/guidance/intersection_handler.hpp"
#include "extractor/guidance/intersection.hpp"
#include "extractor/query_node.hpp"
#include "util/name_table.hpp"
#include "util/node_based_graph.hpp"
#include <vector>
namespace osrm
{
namespace extractor
{
namespace guidance
{
// Intersection handlers deal with all issues related to intersections.
// They assign appropriate turn operations to the TurnOperations.
class MotorwayHandler : public IntersectionHandler
{
public:
MotorwayHandler(const util::NodeBasedDynamicGraph &node_based_graph,
const std::vector<QueryNode> &node_info_list,
const util::NameTable &name_table);
~MotorwayHandler() override final;
// check whether the handler can actually handle the intersection
bool canProcess(const NodeID nid,
const EdgeID via_eid,
const Intersection &intersection) const override final;
// process the intersection
Intersection operator()(const NodeID nid,
const EdgeID via_eid,
Intersection intersection) const override final;
private:
Intersection fromMotorway(const EdgeID via_edge, Intersection intersection) const;
Intersection fromRamp(const EdgeID via_edge, Intersection intersection) const;
Intersection fallback(Intersection intersection) const;
};
} // namespace guidance
} // namespace extractor
} // namespace osrm
#endif /*OSRM_EXTRACTOR_GUIDANCE_MOTORWAY_HANDLER_HPP_*/
@@ -0,0 +1,71 @@
#ifndef OSRM_EXTRACTOR_GUIDANCE_ROUNDABOUT_HANDLER_HPP_
#define OSRM_EXTRACTOR_GUIDANCE_ROUNDABOUT_HANDLER_HPP_
#include "extractor/guidance/intersection.hpp"
#include "extractor/guidance/intersection_handler.hpp"
#include "extractor/query_node.hpp"
#include "util/name_table.hpp"
#include "util/node_based_graph.hpp"
#include "util/typedefs.hpp"
#include <utility>
#include <vector>
namespace osrm
{
namespace extractor
{
namespace guidance
{
namespace detail
{
struct RoundaboutFlags
{
bool on_roundabout;
bool can_enter;
bool can_exit_separately;
};
} // namespace detail
// The roundabout handler processes all roundabout related instructions.
// It performs both the distinction between rotaries and roundabouts and
// assigns appropriate entry/exit instructions.
class RoundaboutHandler : public IntersectionHandler
{
public:
RoundaboutHandler(const util::NodeBasedDynamicGraph &node_based_graph,
const std::vector<QueryNode> &node_info_list,
const util::NameTable &name_table);
~RoundaboutHandler() override final;
// check whether the handler can actually handle the intersection
bool canProcess(const NodeID from_nid, const EdgeID via_eid, const Intersection &intersection) const override final;
// process the intersection
Intersection operator()(const NodeID from_nid, const EdgeID via_eid, Intersection intersection) const override final;
private:
detail::RoundaboutFlags getRoundaboutFlags(const NodeID from_nid, const EdgeID via_eid, const Intersection &intersection) const;
// decide whether we lookk at a roundabout or a rotary
bool isRotary(const NodeID nid) const;
// TODO handle bike/walk cases that allow crossing a roundabout!
// Processing of roundabouts
// Produces instructions to enter/exit a roundabout or to stay on it.
// Performs the distinction between roundabout and rotaries.
Intersection handleRoundabouts(const bool is_rotary,
const EdgeID via_edge,
const bool on_roundabout,
const bool can_exit_roundabout,
Intersection intersection) const;
};
} // namespace guidance
} // namespace extractor
} // namespace osrm
#endif /*OSRM_EXTRACTOR_GUIDANCE_ROUNDABOUT_HANDLER_HPP_*/
+13 -155
View File
@@ -2,11 +2,18 @@
#define OSRM_EXTRACTOR_TURN_ANALYSIS
#include "extractor/compressed_edge_container.hpp"
#include "extractor/guidance/intersection.hpp"
#include "extractor/guidance/intersection_generator.hpp"
#include "extractor/guidance/toolkit.hpp"
#include "extractor/guidance/turn_classification.hpp"
#include "extractor/guidance/roundabout_handler.hpp"
#include "extractor/guidance/motorway_handler.hpp"
#include "extractor/guidance/turn_handler.hpp"
#include "extractor/query_node.hpp"
#include "extractor/restriction_map.hpp"
#include "util/name_table.hpp"
#include "util/node_based_graph.hpp"
#include <cstdint>
@@ -23,46 +30,6 @@ namespace extractor
namespace guidance
{
// What is exposed to the outside
struct TurnOperation final
{
EdgeID eid;
double angle;
TurnInstruction instruction;
};
// For the turn analysis, we require a full list of all connected roads to determine the outcome.
// Invalid turns can influence the perceived angles
//
// aaa(2)aa
// a - bbbbb
// aaa(1)aa
//
// will not be perceived as a turn from (1) -> b, and as a U-turn from (1) -> (2).
// In addition, they can influence whether a turn is obvious or not.
struct ConnectedRoad final
{
ConnectedRoad(const TurnOperation turn, const bool entry_allowed = false);
TurnOperation turn;
bool entry_allowed; // a turn may be relevant to good instructions, even if we cannot take
// the road
std::string toString() const
{
std::string result = "[connection] ";
result += std::to_string(turn.eid);
result += " allows entry: ";
result += std::to_string(entry_allowed);
result += " angle: ";
result += std::to_string(turn.angle);
result += " instruction: ";
result += std::to_string(static_cast<std::int32_t>(turn.instruction.type)) + " " +
std::to_string(static_cast<std::int32_t>(turn.instruction.direction_modifier));
return result;
}
};
class TurnAnalysis
{
@@ -79,123 +46,14 @@ class TurnAnalysis
private:
const util::NodeBasedDynamicGraph &node_based_graph;
const std::vector<QueryNode> &node_info_list;
const RestrictionMap &restriction_map;
const std::unordered_set<NodeID> &barrier_nodes;
const CompressedEdgeContainer &compressed_edge_container;
const util::NameTable &name_table;
// Check for restrictions/barriers and generate a list of valid and invalid turns present at
// the
// node reached
// from `from_node` via `via_eid`
// The resulting candidates have to be analysed for their actual instructions later on.
std::vector<ConnectedRoad> getConnectedRoads(const NodeID from_node,
const EdgeID via_eid) const;
// Merge segregated roads to omit invalid turns in favor of treating segregated roads as
// one.
// This function combines roads the following way:
//
// * *
// * is converted to *
// v ^ +
// v ^ +
//
// The treatment results in a straight turn angle of 180º rather than a turn angle of approx
// 160
std::vector<ConnectedRoad> mergeSegregatedRoads(std::vector<ConnectedRoad> intersection) const;
// TODO distinguish roundabouts and rotaries
// TODO handle bike/walk cases that allow crossing a roundabout!
// Processing of roundabouts
// Produces instructions to enter/exit a roundabout or to stay on it.
// Performs the distinction between roundabout and rotaries.
std::vector<ConnectedRoad> handleRoundabouts(const bool is_rotary,
const EdgeID via_edge,
const bool on_roundabout,
const bool can_exit_roundabout,
std::vector<ConnectedRoad> intersection) const;
// Indicates a Junction containing a motoryway
bool isMotorwayJunction(const EdgeID via_edge,
const std::vector<ConnectedRoad> &intersection) const;
// Decide whether a turn is a turn or a ramp access
TurnType findBasicTurnType(const EdgeID via_edge, const ConnectedRoad &candidate) const;
// Get the Instruction for an obvious turn
// Instruction will be a silent instruction
TurnInstruction getInstructionForObvious(const std::size_t number_of_candidates,
const EdgeID via_edge,
const bool through_street,
const ConnectedRoad &candidate) const;
// Helper Function that decides between NoTurn or NewName
TurnInstruction
noTurnOrNewName(const NodeID from, const EdgeID via_edge, const ConnectedRoad &candidate) const;
// Basic Turn Handling
// Dead end.
std::vector<ConnectedRoad> handleOneWayTurn(std::vector<ConnectedRoad> intersection) const;
// Mode Changes, new names...
std::vector<ConnectedRoad> handleTwoWayTurn(const EdgeID via_edge,
std::vector<ConnectedRoad> intersection) const;
// Forks, T intersections and similar
std::vector<ConnectedRoad> handleThreeWayTurn(const EdgeID via_edge,
std::vector<ConnectedRoad> intersection) const;
// Handling of turns larger then degree three
std::vector<ConnectedRoad> handleComplexTurn(const EdgeID via_edge,
std::vector<ConnectedRoad> intersection) const;
// Any Junction containing motorways
std::vector<ConnectedRoad>
handleMotorwayJunction(const EdgeID via_edge, std::vector<ConnectedRoad> intersection) const;
std::vector<ConnectedRoad> handleFromMotorway(const EdgeID via_edge,
std::vector<ConnectedRoad> intersection) const;
std::vector<ConnectedRoad> handleMotorwayRamp(const EdgeID via_edge,
std::vector<ConnectedRoad> intersection) const;
const IntersectionGenerator intersection_generator;
const RoundaboutHandler roundabout_handler;
const MotorwayHandler motorway_handler;
const TurnHandler turn_handler;
// Utility function, setting basic turn types. Prepares for normal turn handling.
std::vector<ConnectedRoad> setTurnTypes(const NodeID from,
const EdgeID via_edge,
std::vector<ConnectedRoad> intersection) const;
// Assignment of specific turn types
void assignFork(const EdgeID via_edge, ConnectedRoad &left, ConnectedRoad &right) const;
void assignFork(const EdgeID via_edge,
ConnectedRoad &left,
ConnectedRoad &center,
ConnectedRoad &right) const;
void
handleDistinctConflict(const EdgeID via_edge, ConnectedRoad &left, ConnectedRoad &right) const;
// Type specific fallbacks
std::vector<ConnectedRoad>
fallbackTurnAssignmentMotorway(std::vector<ConnectedRoad> intersection) const;
// Classification
std::size_t findObviousTurn(const EdgeID via_edge,
const std::vector<ConnectedRoad> &intersection) const;
std::pair<std::size_t, std::size_t>
findFork(const std::vector<ConnectedRoad> &intersection) const;
std::vector<ConnectedRoad> assignLeftTurns(const EdgeID via_edge,
std::vector<ConnectedRoad> intersection,
const std::size_t starting_at) const;
std::vector<ConnectedRoad> assignRightTurns(const EdgeID via_edge,
std::vector<ConnectedRoad> intersection,
const std::size_t up_to) const;
bool isRotary(const NodeID nid) const;
Intersection
setTurnTypes(const NodeID from, const EdgeID via_edge, Intersection intersection) const;
}; // class TurnAnalysis
} // namespace guidance
@@ -0,0 +1,74 @@
#ifndef OSRM_EXTRACTOR_GUIDANCE_TURN_HANDLER_HPP_
#define OSRM_EXTRACTOR_GUIDANCE_TURN_HANDLER_HPP_
#include "extractor/guidance/intersection_handler.hpp"
#include "extractor/guidance/intersection.hpp"
#include "extractor/query_node.hpp"
#include "util/name_table.hpp"
#include "util/node_based_graph.hpp"
#include <cstddef>
#include <vector>
#include <utility>
namespace osrm
{
namespace extractor
{
namespace guidance
{
// Intersection handlers deal with all issues related to intersections.
// They assign appropriate turn operations to the TurnOperations.
class TurnHandler : public IntersectionHandler
{
public:
TurnHandler(const util::NodeBasedDynamicGraph &node_based_graph,
const std::vector<QueryNode> &node_info_list,
const util::NameTable &name_table);
~TurnHandler() override final;
// check whether the handler can actually handle the intersection
bool canProcess(const NodeID nid,
const EdgeID via_eid,
const Intersection &intersection) const override final;
// process the intersection
Intersection operator()(const NodeID nid,
const EdgeID via_eid,
Intersection intersection) const override final;
private:
// Dead end.
Intersection handleOneWayTurn(Intersection intersection) const;
// Mode Changes, new names...
Intersection handleTwoWayTurn(const EdgeID via_edge, Intersection intersection) const;
// Forks, T intersections and similar
Intersection handleThreeWayTurn(const EdgeID via_edge, Intersection intersection) const;
// Handling of turns larger then degree three
Intersection handleComplexTurn(const EdgeID via_edge, Intersection intersection) const;
void
handleDistinctConflict(const EdgeID via_edge, ConnectedRoad &left, ConnectedRoad &right) const;
// Classification
std::size_t findObviousTurn(const EdgeID via_edge, const Intersection &intersection) const;
std::pair<std::size_t, std::size_t> findFork(const Intersection &intersection) const;
Intersection assignLeftTurns(const EdgeID via_edge,
Intersection intersection,
const std::size_t starting_at) const;
Intersection assignRightTurns(const EdgeID via_edge,
Intersection intersection,
const std::size_t up_to) const;
};
} // namespace guidance
} // namespace extractor
} // namespace osrm
#endif /*OSRM_EXTRACTOR_GUIDANCE_TURN_HANDLER_HPP_*/