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

Interpolation bug fix #2275

Merged
merged 15 commits into from
Mar 23, 2020
Merged

Interpolation bug fix #2275

merged 15 commits into from
Mar 23, 2020

Conversation

yuzheyan
Copy link
Contributor

@yuzheyan yuzheyan commented Mar 17, 2020

Issue

This PR is targeting on the fix of interpolation bug. The previous logic has a flaw that, the interpolated locations are allowed to go beyond the boundaries of the actual matched point. See following example of interpolated point's (B) distance_along of the edge is smaller than matched point (A). Such behavior will lead to discontinuity for the serializer, the serializer thinks there is a discontinuity which is incorrect.

1584473755841

after the fix, the clip the distance_along of B to A's distance along.

Tasklist

  • Add tests
  • Add #fixes with the issue number that this PR addresses
  • Generally use squash merge to rebase and clean comments before merging
  • Update the changelog

Requirements / Relations

Link any requirements here. Other pull requests this PR is based on?

Copy link
Member

@kevinkreiser kevinkreiser left a comment

Choose a reason for hiding this comment

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

I would like to propose a simpler alternative that uses the interpolation to move the window rather than an unordered map and extra looping.

diff --git a/src/meili/map_matcher.cc b/src/meili/map_matcher.cc
index 3924651a2..21ef43470 100644
--- a/src/meili/map_matcher.cc
+++ b/src/meili/map_matcher.cc
@@ -35,6 +35,7 @@ struct Interpolation {
   float route_distance;
   float route_time;
   float edge_distance;
+  std::vector<EdgeSegment>::const_iterator segment;
 
   float sortcost(const EmissionCostModel& emission_model,
                  const TransitionCostModel& transition_model,
@@ -61,6 +62,7 @@ inline MatchResult CreateMatchResult(const Measurement& measurement, const Inter
 Interpolation InterpolateMeasurement(const MapMatcher& mapmatcher,
                                      const Measurement& measurement,
                                      std::vector<EdgeSegment>::const_iterator begin,
+                                     float begin_source_offset,
                                      std::vector<EdgeSegment>::const_iterator end,
                                      float match_measurement_distance,
                                      float match_measurement_time) {
@@ -75,6 +77,8 @@ Interpolation InterpolateMeasurement(const MapMatcher& mapmatcher,
   Interpolation best_interp;
 
   for (auto segment = begin; segment != end; segment++) {
+    // TODO: skip if this edgeid is the same as the previous one we dont need to check it twice
+
     const auto directededge = mapmatcher.graphreader().directededge(segment->edgeid, tile);
     if (!directededge) {
       continue;
@@ -96,6 +100,16 @@ Interpolation InterpolateMeasurement(const MapMatcher& mapmatcher,
       offset = 1.f - offset;
     }
 
+    // clip distance along to the match boundaries
+    if (segment == begin && offset < begin_source_offset) {
+      offset = begin_source_offset;
+      // TODO: update the snap to this offset along the edge (projected_point, sq_distance)
+    }
+    if (segment == end - 1 && offset > segment->target) {
+      offset = segment->target;
+      // TODO: update the snap to this offset along the edge (projected_point, sq_distance)
+    }
+
     // Distance from the projected point to the segment begin, or
     // segment begin if we walk reversely
     const auto distance_to_segment_ends =
@@ -109,8 +123,8 @@ Interpolation InterpolateMeasurement(const MapMatcher& mapmatcher,
     auto edge_percent = segment->target - segment->source;
     auto route_time = mapmatcher.costing()->EdgeCost(directededge, tile).secs * edge_percent;
 
-    Interpolation interp{projected_point, segment->edgeid, sq_distance,
-                         route_distance,  route_time,      offset};
+    Interpolation interp{projected_point, segment->edgeid, sq_distance, route_distance,
+                         route_time,      offset,          segment};
 
     const auto cost =
         interp.sortcost(mapmatcher.emission_cost_model(), mapmatcher.transition_cost_model(),
@@ -153,13 +167,22 @@ std::vector<MatchResult> InterpolateMeasurements(const MapMatcher& mapmatcher,
                                               mapmatcher.state_container().state(next_stateid));
 
   // for each point that needs interpolated
+  std::vector<EdgeSegment>::const_iterator left_most_segment = route.begin();
+  float left_most_offset = route.begin()->source;
   for (const auto& measurement : measurements) {
     const auto& match_measurement = mapmatcher.state_container().measurement(stateid.time());
     const auto match_measurement_distance = GreatCircleDistance(measurement, match_measurement);
     const auto match_measurement_time = ClockDistance(measurement, match_measurement);
+
     // interpolate this point along the route
-    const auto& interp = InterpolateMeasurement(mapmatcher, measurement, route.begin(), route.end(),
-                                                match_measurement_distance, match_measurement_time);
+    const auto interp =
+        InterpolateMeasurement(mapmatcher, measurement, left_most_segment, left_most_offset,
+                               route.end(), match_measurement_distance, match_measurement_time);
+
+    // shift the point at which we are allowed to start interpolating from to the right
+    // so that its on the interpolation point this way the next interpolation happens after
+    left_most_segment = interp.segment;
+    left_most_offset = interp.edge_distance;
 
     // if it was able to do the interpolation
     if (interp.edgeid.Is_Valid()) {

…into interpolation_bug_fix

* 'interpolation_bug_fix' of github.com:valhalla/valhalla:
  Update intersection classes in osrm response to not label all ramps as motorway (#2279)
  More stop impact changes (#2282)
@@ -152,28 +169,39 @@ std::vector<MatchResult> InterpolateMeasurements(const MapMatcher& mapmatcher,
std::vector<EdgeSegment> route = MergeRoute(mapmatcher.state_container().state(stateid),
mapmatcher.state_container().state(next_stateid));

if (route.empty()) {
Copy link
Member

Choose a reason for hiding this comment

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

what is this doing, what tests do we have to show that this is doing what its supposed to

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes, after the changes. Some existing unit test in the test matcher got broken if we do not have this protection.

@@ -664,12 +697,15 @@ std::vector<MatchResults> MapMatcher::OfflineMatch(const std::vector<Measurement
const auto& this_stateid = original_state_ids[time];
const auto& next_stateid =
time + 1 < original_state_ids.size() ? original_state_ids[time + 1] : StateId();

midgard::PointLL first_projection = results[time].lnglat;
midgard::PointLL last_projection = results[time + 1].lnglat;
const auto& interpolated_results =
Copy link
Member

Choose a reason for hiding this comment

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

this shouldnt be a reference and if you do the move iterator you need to remove const as well

kevinkreiser
kevinkreiser previously approved these changes Mar 23, 2020
Copy link
Member

@kevinkreiser kevinkreiser left a comment

Choose a reason for hiding this comment

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

excellent debugging once again!

@kevinkreiser kevinkreiser merged commit 7c74c7b into master Mar 23, 2020
@yuzheyan yuzheyan deleted the interpolation_bug_fix branch March 23, 2020 21:41
yuzheyan added a commit that referenced this pull request Mar 25, 2020
* master:
  additional data processing options  (#2285)
  Fix Uturn cases on not_thru edge connected to origin. (#2272)
  Interpolation bug fix (#2275)
yuzheyan added a commit that referenced this pull request Mar 25, 2020
* master:
  additional data processing options  (#2285)
  Fix Uturn cases on not_thru edge connected to origin. (#2272)
  Interpolation bug fix (#2275)
  Update intersection classes in osrm response to not label all ramps as motorway (#2279)
  More stop impact changes (#2282)
  Fixed verbal multi-cue logic (#2270)
  Re-write test/astar.cc to use gurka graph creation helpers rather than hard-coding edge creation/IDs
  Add gurka test framework to ease creation of test cases with ascii-maps
  Add helper functions so that we can perform actions without serializing if desired - this is to support testing of intermediate results.
  Make protobuf cleanup after tile building optional (on by default) so that tests can repeatedly call mjolnir::build_tile_set
  Downgrade some log messages to warnings - they are non-fatal behaviours, no error is actually emitted by the code.
  Reduce concurrency of lint debug build so that it doesn't hit OOM problems on CI
  Exact Reachability (ie v3) (#2243)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants