Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support manual instruction type override relations #4676

Merged
merged 1 commit into from
Feb 9, 2018

Conversation

danpat
Copy link
Member

@danpat danpat commented Nov 9, 2017

This is an experimental PR to tinker with the idea of data-driven instruction generation.

Rationale: sometimes, you want a specific instruction at a particular location, and the heuristics we're using just aren't fancy enough to make the right decision, or the OSM tagging scheme is incomplete for the structure of the map at that location and doesn't supply enough information to make a good decision about which instruction to issue.

This PR adds support for a new, totally made up relation we're calling a maneuver relation. They look like this:

<relation>
  <tag k="type" v="maneuver"/>
  <member type="way" ref="1234" role="from"/>
  <member type="way" ref="5678" role="to"/>
  <member type="node" ref="9999" role="via"/>
  <tag k="maneuver" v="turn"/>
  <tag k="direction" v="slight_right"/>
</relation>

The basic process is that after a route is found, we scan along the path and find maneuver relations that match (they pass through from, via, and to in that order). If a match is found, the type value for the via point is replaced with the value from the relation (same for the direction).

We will come up with a rough mapping of reasonable-looking type values to OSRM turn types - the intent is for the OSM data to be relatively routing-engine agnostic. The intent of this relation type is to be a hint to the navigation engine in locations where heuristics have trouble.

TODO:

  • Complete the RestrictionCompressor work so that it also updates the ManeuverOverride from/to IDs @karenzshea
  • Implement the lookup to find matching ManeuverOverrides in the EdgeBasedGraphFactory (currently stubbed out)
  • Serialize the ManeuverOverride list at the end of extraction @danpat
  • Fully implement the facade.GetOverridesThatStartAt method
  • Extend this so that from/to ways don't need to be directly connected **

Multi-via-way support

  • Fix relation compressor for multi-nodes
  • Verify which nodes are needed `
  • File saving for multi-nodes
  • Edge case test scenarios

** Do this bit after we have directly-connected overrides working

/cc @karenzshea

Tasklist

  • update relevant Wiki pages
  • add regression / cucumber cases (see docs/testing.md)
  • review
  • adjust for comments

}
};

const auto string_to_turn_direction = [](const std::string &direction_string) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think here we will also need to pass in the turn_string to be able to set a uturn direction modifier

@karenzshea
Copy link
Contributor

@danpat Do you have some unpushed additions to the IO operations for reading/writing maneuver overrides? Locally and on every travis build I'm seeing a

/home/travis/build/Project-OSRM/osrm-backend/include/extractor/serialization.hpp:339:39:   required from here
/home/travis/build/Project-OSRM/osrm-backend/include/storage/io.hpp:101:9: error: static assertion failed: bytewise reading requires trivially copyable type

error, where it looks like we're missing the read methods for the ManeuverOverride type.

Copy link
Contributor

@karenzshea karenzshea left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also see the comment about the missing overrides io methods!

# Testing disconnected via ways (first turn is only modified if you end up
# on a particular way)
# | h,a | J Street,C Street,A Street,A Street | depart,turn left,turn left,arrive |
# | h,e | J Street,C Street,B Street,B Street | depart,turn sharp left,turn left,arrive |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should these tests pass? Should we add a test that makes sure the first turn is not modified when the ending street is not in the maneuver? e.g. j -> e should return depart,turn right,arrive

@@ -101,6 +104,27 @@ class RouteAPI : public BaseAPI
const std::vector<bool> &source_traversed_in_reverse,
const std::vector<bool> &target_traversed_in_reverse) const
{
for (const auto &a : unpacked_path_segments)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this logging be wrapped into debug output only?

++route_iter;
continue;
}
// Skip over duplicated EBNs in the step array
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When would the EBNs in the step array be duplicated?

const auto via_node_coords = BaseAPI::facade.GetCoordinateOfNode(
maneuver_relation.instruction_node);
// Find the step that has the instruction_node at the intersection point
auto step_to_update = std::find_if(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thought: could we also store the offset of the instruction_node in the override from the first part of the sequence, and just count forward that many steps in the route sequence? If the current route steps sequence actually matches the override, it should be 1:1 right? The coordinate comparison should be an assert or a second check then.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 This is a good idea and would definitely speed things up. We're also being wasteful here by checking every coordinate - only intersection coordinates should get checked.

// Copy all the overrides into the results array.
// m_maneuver_overrides is sorted by node_sequence.front(),
// so we can stop searching after we get to a node > edge_based_node_id
for (const auto & override : m_maneuver_overrides)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be any faster to do a std::equal_range search for the edge_based_node_id and just write all of those results?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch - yeah, it would be faster, std::equal_range has sub-linear performance if the thing being searched is random-access (as opposed to just forward iterable).

The way we're comparing a member variable (override.start_node) doesn't fit with the std::equal_range pattern though, I'll see if I can re-jigger it to work.

// id of via node of the turn
// from edge-based-node id
NodeID from_edge_based_node;
// the internal OSRM id of the OSM node id that is the via node of the turn
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this comment is so sad and great at the same time

// check if all parts of the restriction reference an actual node
bool Valid() const
{
return turn_sequence.size() >= 2 || std::none_of(turn_sequence.begin(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would expect that all of these || are &&'s. Isn't an override only valid if it has at least 2 turns, none of the nodes are SPECIAL_NODEID, and the direction and override types are valid?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@danpat I'm still unclear on whether or not this check is the right one. Should the logic here be inverted?

class ScriptingEnvironment;

/**
* Parses the relations that represents turn restrictions.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these comments need to be updated a bit for the maneuver relations

};

// wrapper function to handle distinction between conditional and unconditional turn
// restrictions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this comment unrelated?

@danpat danpat force-pushed the guidance/silver-bullet branch 2 times, most recently from 0c15d5d to 7944351 Compare January 17, 2018 00:22
@danpat danpat changed the base branch from master to refactor/ebgf-guidance January 23, 2018 18:25
@oxidase oxidase force-pushed the refactor/ebgf-guidance branch 2 times, most recently from 5a3dcd7 to 8320f25 Compare January 24, 2018 12:14
@oxidase oxidase force-pushed the refactor/ebgf-guidance branch 3 times, most recently from f2757e5 to 4577f29 Compare January 29, 2018 14:17
@oxidase oxidase force-pushed the refactor/ebgf-guidance branch 5 times, most recently from 50807b4 to 3d9d1aa Compare February 1, 2018 15:02
Copy link
Contributor

@oxidase oxidase left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! Just small cleanup remarks before merging.

guidance::TurnType::Invalid,
guidance::DirectionModifier::MaxDirectionModifier};

std::clog << " ****** EXTERNAL WAY SEQUENCE " << std::endl;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could it be removed?

@@ -140,6 +168,156 @@ class RouteAPI : public BaseAPI
reversed_source,
reversed_target);

// Find overrides that match, and apply them
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would it make sense to move the code block into a guidance handler function guidance::handleManeuverOverride?

@@ -78,6 +79,7 @@ struct RouteStep
std::size_t geometry_end;
std::vector<IntermediateIntersection> intersections;
bool is_left_hand_driving;
bool is_overridden;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is_overridden is only set but never used, can it be removed?

@@ -1074,6 +1086,22 @@ void Storage::PopulateData(const DataLayout &layout, char *memory_ptr)
" in " + config.GetPath(".osrm.edges").string());
}
}

// load turn duration penalties
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// load maneuver overrides?

@oxidase oxidase force-pushed the refactor/ebgf-guidance branch 2 times, most recently from 9bf892f to 2dc70a3 Compare February 2, 2018 16:03
@chaupow chaupow added this to the 5.16.0 milestone Feb 5, 2018
@danpat danpat changed the base branch from refactor/ebgf-guidance to master February 9, 2018 08:15
@danpat danpat force-pushed the guidance/silver-bullet branch 2 times, most recently from 67d5bb6 to 54fe4be Compare February 9, 2018 17:53
@danpat danpat merged commit 5531cac into master Feb 9, 2018
datendelphin added a commit to fossgis-routing-server/osrm-backend that referenced this pull request Jun 10, 2018
  - Changes from 5.15.2:
    - Guidance
      - ADDED Project-OSRM#4676: Support for maneuver override relation, allowing data-driven overrides for turn-by-turn instructions [Project-OSRM#4676](Project-OSRM#4676)
      - CHANGED Project-OSRM#4830: Announce reference change if names are empty
      - CHANGED Project-OSRM#4835: MAXIMAL_ALLOWED_SEPARATION_WIDTH increased to 12 meters
      - CHANGED Project-OSRM#4842: Lower priority links from a motorway now are used as motorway links [Project-OSRM#4842](Project-OSRM#4842)
      - CHANGED Project-OSRM#4895: Use ramp bifurcations as fork intersections [Project-OSRM#4895](Project-OSRM#4895)
      - CHANGED Project-OSRM#4893: Handle motorway forks with links as normal motorway intersections[Project-OSRM#4893](Project-OSRM#4893)
      - FIXED Project-OSRM#4905: Check required tags of `maneuver` relations [Project-OSRM#4905](Project-OSRM#4905)
    - Profile:
      - FIXED: `highway=service` will now be used for restricted access, `access=private` is still disabled for snapping.
      - ADDED Project-OSRM#4775: Exposes more information to the turn function, now being able to set turn weights with highway and access information of the turn as well as other roads at the intersection [Project-OSRM#4775](Project-OSRM#4775)
      - FIXED Project-OSRM#4763: Add support for non-numerical units in car profile for maxheight [Project-OSRM#4763](Project-OSRM#4763)
      - ADDED Project-OSRM#4872: Handling of `barrier=height_restrictor` nodes [Project-OSRM#4872](Project-OSRM#4872)
@DennisOSRM DennisOSRM deleted the guidance/silver-bullet branch November 6, 2022 14:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants