This change unblocks the osrm-extract debug build, which is currently failing on a maneuver override assertion. The processing of maneuver overrides currently has three issues - It assumes the via node(s) can't be compressed (the failing assertion) - It can't handle via-paths containing incompressible nodes - It doesn't interop with turn restriction on the same path Turn restrictions and maneuver overrides both use the same from-via-to path representation. Therefore, we can fix these issues by consolidating their structures and reusing the path representation for turn restrictions, which already is robust to the above issues. This also simplifies some of the codebase by removing maneuver override specific path processing. There are ~100 maneuver overrides in the OSM database, so the impact on processing and routing will be minimal.
141 lines
4.2 KiB
C++
141 lines
4.2 KiB
C++
#include "extractor/maneuver_override_relation_parser.hpp"
|
|
#include "extractor/maneuver_override.hpp"
|
|
|
|
#include <boost/optional/optional.hpp>
|
|
#include <boost/ref.hpp>
|
|
|
|
#include <osmium/osm.hpp>
|
|
#include <osmium/tags/filter.hpp>
|
|
#include <osmium/tags/taglist.hpp>
|
|
|
|
#include <algorithm>
|
|
#include <iterator>
|
|
|
|
namespace osrm
|
|
{
|
|
namespace extractor
|
|
{
|
|
|
|
ManeuverOverrideRelationParser::ManeuverOverrideRelationParser() {}
|
|
|
|
/**
|
|
* Parses the `type=maneuver` relation. Reads the fields, and puts data
|
|
* into an InputManeuverOverride object, if the relation is considered
|
|
* valid (i.e. has the minimum tags we expect).
|
|
*/
|
|
boost::optional<InputManeuverOverride>
|
|
ManeuverOverrideRelationParser::TryParse(const osmium::Relation &relation) const
|
|
{
|
|
|
|
// Support both American and British spellings of maneuver/manoeuvre
|
|
osmium::tags::KeyValueFilter filter{false};
|
|
filter.add(true, "type", "maneuver");
|
|
filter.add(true, "type", "manoeuvre");
|
|
|
|
const osmium::TagList &tag_list = relation.tags();
|
|
|
|
if (osmium::tags::match_none_of(tag_list, filter))
|
|
// if it's not a maneuver, continue;
|
|
{
|
|
return boost::none;
|
|
}
|
|
|
|
// we pretend every restriction is a conditional restriction. If we do not find any restriction,
|
|
// we can trim away the vector after parsing
|
|
InputManeuverOverride maneuver_override;
|
|
|
|
// Handle both spellings
|
|
if (relation.tags().has_key("manoeuvre"))
|
|
{
|
|
maneuver_override.maneuver = relation.tags().get_value_by_key("manoeuvre", "");
|
|
}
|
|
else
|
|
{
|
|
maneuver_override.maneuver = relation.tags().get_value_by_key("maneuver", "");
|
|
}
|
|
|
|
maneuver_override.direction = relation.tags().get_value_by_key("direction", "");
|
|
|
|
bool valid_relation = true;
|
|
OSMNodeID via_node = SPECIAL_OSM_NODEID;
|
|
OSMWayID from = SPECIAL_OSM_WAYID, to = SPECIAL_OSM_WAYID;
|
|
std::vector<OSMWayID> via_ways;
|
|
|
|
for (const auto &member : relation.members())
|
|
{
|
|
const char *role = member.role();
|
|
if (strcmp("from", role) != 0 && strcmp("to", role) != 0 && strcmp("via", role) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
switch (member.type())
|
|
{
|
|
case osmium::item_type::node:
|
|
{
|
|
|
|
// Make sure nodes appear only in the role if a via node
|
|
if (0 == strcmp("from", role) || 0 == strcmp("to", role))
|
|
{
|
|
continue;
|
|
}
|
|
BOOST_ASSERT(0 == strcmp("via", role));
|
|
// set via node id
|
|
valid_relation &= via_node == SPECIAL_OSM_NODEID;
|
|
via_node = OSMNodeID{static_cast<std::uint64_t>(member.ref())};
|
|
break;
|
|
}
|
|
case osmium::item_type::way:
|
|
BOOST_ASSERT(0 == strcmp("from", role) || 0 == strcmp("to", role) ||
|
|
0 == strcmp("via", role));
|
|
if (0 == strcmp("from", role))
|
|
{
|
|
valid_relation &= from == SPECIAL_OSM_WAYID;
|
|
from = OSMWayID{static_cast<std::uint64_t>(member.ref())};
|
|
}
|
|
else if (0 == strcmp("to", role))
|
|
{
|
|
valid_relation &= to == SPECIAL_OSM_WAYID;
|
|
to = OSMWayID{static_cast<std::uint64_t>(member.ref())};
|
|
}
|
|
else if (0 == strcmp("via", role))
|
|
{
|
|
via_ways.push_back(OSMWayID{static_cast<std::uint64_t>(member.ref())});
|
|
}
|
|
break;
|
|
case osmium::item_type::relation:
|
|
// not yet supported, but who knows what the future holds...
|
|
break;
|
|
default:
|
|
// shouldn't ever happen
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Check required roles
|
|
valid_relation &= from != SPECIAL_OSM_WAYID;
|
|
valid_relation &= to != SPECIAL_OSM_WAYID;
|
|
valid_relation &= via_node != SPECIAL_OSM_NODEID;
|
|
|
|
if (valid_relation)
|
|
{
|
|
if (via_ways.empty())
|
|
{
|
|
maneuver_override.turn_path.node_or_way = InputViaNodePath{{from}, {via_node}, {to}};
|
|
}
|
|
else
|
|
{
|
|
maneuver_override.turn_path.node_or_way =
|
|
InputViaWayPath{{from}, std::move(via_ways), {to}};
|
|
}
|
|
maneuver_override.via_node = via_node;
|
|
}
|
|
else
|
|
{
|
|
return boost::none;
|
|
}
|
|
return maneuver_override;
|
|
}
|
|
} // namespace extractor
|
|
} // namespace osrm
|