Skip to content

Commit

Permalink
Add the possibility to advance when nearing the end of a step
Browse files Browse the repository at this point in the history
  • Loading branch information
ianthetechie committed Oct 23, 2023
1 parent d29d0f6 commit 2375d1a
Show file tree
Hide file tree
Showing 11 changed files with 92 additions and 32 deletions.
4 changes: 2 additions & 2 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-syntax.git",
"state" : {
"revision" : "74203046135342e4a4a627476dd6caf8b28fe11b",
"version" : "509.0.0"
"revision" : "ffa3cd6fc2aa62adbedd31d3efaf7c0d86a9f029",
"version" : "509.0.1"
}
}
],
Expand Down
4 changes: 2 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ if useLocalFramework {
path: "./common/target/ios/ferrostar-rs.xcframework"
)
} else {
let releaseTag = "0.0.6"
let releaseChecksum = "f122f35cc657ad3758a105ec62516a0a8c2f358e24f32f0e115bbc592961f2ce"
let releaseTag = "0.0.7"
let releaseChecksum = "637d6837bd671791c4a4ef7e315755d39f04bcbcc053cef4498793a58e68f76d"
binaryTarget = .binaryTarget(
name: "FerrostarCoreRS",
url: "https://github.com/stadiamaps/ferrostar/releases/download/\(releaseTag)/ferrostar-rs.xcframework.zip",
Expand Down
10 changes: 5 additions & 5 deletions apple/Sources/FerrostarCore/ModelWrappers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,18 +51,18 @@ public enum StepAdvanceMode {
///
/// Distance and horizontal accuracy are measured in meters.
case distanceToEndOfStep(distance: UInt16, minimumHorizontalAccuracy: UInt16)
/// Automatically advances when the user's distance to the *next* step's linestring is less
/// than or equal to the distance to the current step's linestring.
case relativeLineStringDistance(minimumHorizontalAccuracy: UInt16)
/// At this (optional) distance, navigation should advance to the next step regardless
/// of which LineString appears closer.
case relativeLineStringDistance(minimumHorizontalAccuracy: UInt16, automaticAdvanceDistance: UInt16?)

var ffiValue: UniFFI.StepAdvanceMode {
switch self {
case .manual:
return .manual
case .distanceToEndOfStep(distance: let distance, minimumHorizontalAccuracy: let minimumHorizontalAccuracy):
return .distanceToEndOfStep(distance: distance, minimumHorizontalAccuracy: minimumHorizontalAccuracy)
case .relativeLineStringDistance(minimumHorizontalAccuracy: let minimumHorizontalAccuracy):
return .relativeLineStringDistance(minimumHorizontalAccuracy: minimumHorizontalAccuracy)
case .relativeLineStringDistance(minimumHorizontalAccuracy: let minimumHorizontalAccuracy, automaticAdvanceDistance: let automaticAdvanceDistance):
return .relativeLineStringDistance(minimumHorizontalAccuracy: minimumHorizontalAccuracy, automaticAdvanceDistance: automaticAdvanceDistance)
}
}
}
8 changes: 5 additions & 3 deletions apple/Sources/UniFFI/ferrostar.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1536,7 +1536,7 @@ extension RoutingResponseParseError: Error {}
public enum StepAdvanceMode {
case manual
case distanceToEndOfStep(distance: UInt16, minimumHorizontalAccuracy: UInt16)
case relativeLineStringDistance(minimumHorizontalAccuracy: UInt16)
case relativeLineStringDistance(minimumHorizontalAccuracy: UInt16, automaticAdvanceDistance: UInt16?)
}

public struct FfiConverterTypeStepAdvanceMode: FfiConverterRustBuffer {
Expand All @@ -1553,7 +1553,8 @@ public struct FfiConverterTypeStepAdvanceMode: FfiConverterRustBuffer {
)

case 3: return try .relativeLineStringDistance(
minimumHorizontalAccuracy: FfiConverterUInt16.read(from: &buf)
minimumHorizontalAccuracy: FfiConverterUInt16.read(from: &buf),
automaticAdvanceDistance: FfiConverterOptionUInt16.read(from: &buf)
)

default: throw UniffiInternalError.unexpectedEnumCase
Expand All @@ -1570,9 +1571,10 @@ public struct FfiConverterTypeStepAdvanceMode: FfiConverterRustBuffer {
FfiConverterUInt16.write(distance, into: &buf)
FfiConverterUInt16.write(minimumHorizontalAccuracy, into: &buf)

case let .relativeLineStringDistance(minimumHorizontalAccuracy):
case let .relativeLineStringDistance(minimumHorizontalAccuracy, automaticAdvanceDistance):
writeInt(&buf, Int32(3))
FfiConverterUInt16.write(minimumHorizontalAccuracy, into: &buf)
FfiConverterOptionUInt16.write(automaticAdvanceDistance, into: &buf)
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion common/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion common/ferrostar-core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ferrostar-core"
version = "0.0.6"
version = "0.0.7"
authors = ["Ian Wagner <[email protected]>", "Luke Seelenbinder <[email protected]>"]
license = "BSD-3-Clause"
repository = "https://github.com/stadiamaps/ferrostar"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Seeds for failure cases proptest has generated in the past. It is
# automatically read and these particular cases re-run before any
# novel cases are generated.
#
# It is recommended to check this file in to source control so that
# everyone who runs the test benefits from these saved cases.
cc b960506a2a3ada78b4d042a2ec23695871c1676d7a8e6d4c16053e56197acff9 # shrinks to x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0, x3 = 0.0, y3 = 0.0, error = 0.0009697441544620993, has_next_step = false, distance = 153, minimum_horizontal_accuracy = 0, automatic_advance_distance = Some(0)
2 changes: 1 addition & 1 deletion common/ferrostar-core/src/ferrostar.udl
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ interface NavigationStateUpdate {
interface StepAdvanceMode {
Manual();
DistanceToEndOfStep(u16 distance, u16 minimum_horizontal_accuracy);
RelativeLineStringDistance(u16 minimum_horizontal_accuracy);
RelativeLineStringDistance(u16 minimum_horizontal_accuracy, u16? automatic_advance_distance);
};

dictionary NavigationControllerConfig {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use crate::models::{GeographicCoordinates, RouteStep, UserLocation};
use geo::{Closest, ClosestPoint, EuclideanDistance, HaversineDistance, HaversineLength, LineLocatePoint, LineString, Point};
use geo::{
Closest, ClosestPoint, EuclideanDistance, HaversineDistance, HaversineLength, LineLocatePoint,
LineString, Point,
};

use super::models::{StepAdvanceMode, StepAdvanceStatus};
use crate::navigation_controller::models::StepAdvanceStatus::{Advanced, EndOfRoute};
Expand Down Expand Up @@ -33,6 +36,21 @@ fn snap_point_to_line(point: &Point, line: &LineString) -> Option<Point> {
}
}

fn is_close_enough_to_end_of_step(
current_position: &Point,
current_step_linestring: &LineString,
threshold: f64,
) -> bool {
if let Some(end_coord) = current_step_linestring.coords().last() {
let end_point = Point::from(*end_coord);
let distance_to_end = end_point.haversine_distance(&current_position);

distance_to_end <= threshold
} else {
false
}
}

/// Determines whether the navigation controller should complete the current route step
/// and move to the next.
///
Expand All @@ -53,21 +71,32 @@ pub fn should_advance_to_next_step(
} => {
if user_location.horizontal_accuracy > minimum_horizontal_accuracy.into() {
false
} else if let Some(end_coord) = current_step_linestring.coords().last() {
let end_point = Point::from(*end_coord);
let distance_to_end = end_point.haversine_distance(&current_position);

distance_to_end <= distance as f64
} else {
false
is_close_enough_to_end_of_step(
&current_position,
current_step_linestring,
distance as f64,
)
}
}
StepAdvanceMode::RelativeLineStringDistance {
minimum_horizontal_accuracy,
automatic_advance_distance,
} => {
if user_location.horizontal_accuracy > minimum_horizontal_accuracy.into() {
false
} else {
if let Some(distance) = automatic_advance_distance {
// Short-circuit: if we are close to the end of the step, we may advance
if is_close_enough_to_end_of_step(
&current_position,
current_step_linestring,
distance as f64,
) {
return true;
}
}

if let Some(next_step) = next_route_step {
// FIXME: This isn't very efficient to keep doing at the moment
let next_step_linestring = next_step.get_linestring();
Expand Down Expand Up @@ -189,7 +218,8 @@ proptest! {
x2 in -180f64..180f64, y2 in -90f64..90f64,
x3 in -180f64..180f64, y3 in -90f64..90f64,
has_next_step: bool,
distance: u16, minimum_horizontal_accuracy: u16, excess_inaccuracy in 0f64..65535f64
distance: u16, minimum_horizontal_accuracy: u16, excess_inaccuracy in 0f64..65535f64,
automatic_advance_distance: Option<u16>,
) {
let current_route_step = gen_dummy_route_step(x1, y1, x2, y2);
let next_route_step = if has_next_step {
Expand Down Expand Up @@ -220,15 +250,17 @@ proptest! {

// Same when looking at the relative distances between the two step geometries
assert!(should_advance_to_next_step(&current_route_step.get_linestring(), next_route_step.as_ref(), &exact_user_location, StepAdvanceMode::RelativeLineStringDistance {
minimum_horizontal_accuracy
minimum_horizontal_accuracy,
automatic_advance_distance
}));

// Should always fail (unless excess_inaccuracy is zero), as the horizontal accuracy is worse than (>) than the desired error threshold
assert_eq!(should_advance_to_next_step(&current_route_step.get_linestring(), next_route_step.as_ref(), &inaccurate_user_location, StepAdvanceMode::DistanceToEndOfStep {
distance, minimum_horizontal_accuracy
}), excess_inaccuracy == 0.0, "Expected that the navigation would not advance to the next step except when excess_inaccuracy is 0");
assert_eq!(should_advance_to_next_step(&current_route_step.get_linestring(), next_route_step.as_ref(), &inaccurate_user_location, StepAdvanceMode::RelativeLineStringDistance {
minimum_horizontal_accuracy
minimum_horizontal_accuracy,
automatic_advance_distance
}), excess_inaccuracy == 0.0, "Expected that the navigation would not advance to the next step except when excess_inaccuracy is 0");
}

Expand All @@ -238,7 +270,8 @@ proptest! {
x2 in -180f64..180f64, y2 in -90f64..90f64,
x3 in -180f64..180f64, y3 in -90f64..90f64,
error in -0.003f64..0.003f64, has_next_step: bool,
distance: u16, minimum_horizontal_accuracy in 0u16..250u16
distance: u16, minimum_horizontal_accuracy in 0u16..250u16,
automatic_advance_distance: Option<u16>,
) {
let current_route_step = gen_dummy_route_step(x1, y1, x2, y2);
let next_route_step = if has_next_step {
Expand All @@ -259,15 +292,25 @@ proptest! {
timestamp: SystemTime::now(),
};
let user_location_point = Point::from(user_location);
// let distance_from_end_of_current_step = user_location.into().
let distance_from_end_of_current_step = user_location_point.haversine_distance(&end_of_step.into());

// Never advance to the next step when StepAdvanceMode is Manual
assert!(!should_advance_to_next_step(&current_route_step.get_linestring(), next_route_step.as_ref(), &user_location, StepAdvanceMode::Manual));

// Assumes that haversine_distance is correct
assert_eq!(should_advance_to_next_step(&current_route_step.get_linestring(), next_route_step.as_ref(), &user_location, StepAdvanceMode::DistanceToEndOfStep {
distance, minimum_horizontal_accuracy
}), user_location_point.haversine_distance(&end_of_step.into()) <= distance.into(), "Expected that the step should advance in this case as we are closer to the end of the step than the threshold.");
}), distance_from_end_of_current_step <= distance.into(), "Expected that the step should advance in this case as we are closer to the end of the step than the threshold.");

// Similar test for automatic advance on the relative line string distance mode
if automatic_advance_distance.map_or(false, |advance_distance| {
distance_from_end_of_current_step <= advance_distance.into()
}) {
assert!(should_advance_to_next_step(&current_route_step.get_linestring(), next_route_step.as_ref(), &user_location, StepAdvanceMode::RelativeLineStringDistance {
minimum_horizontal_accuracy,
automatic_advance_distance,
}), "Expected that the step should advance any time that the haversine distance to the end of the step is within the automatic advance threshold.");
}

// TODO: We can use snap_to_line and, assuming that snap_to_line works and haversine_distance works, we have a valid end to end test
}
Expand Down
13 changes: 9 additions & 4 deletions common/ferrostar-core/src/navigation_controller/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
mod algorithms;
pub mod models;
mod utils;

use crate::models::{Route, UserLocation};
use crate::navigation_controller::utils::{advance_step, distance_to_end_of_step, should_advance_to_next_step};
use crate::navigation_controller::algorithms::{
advance_step, distance_to_end_of_step, should_advance_to_next_step,
};
use algorithms::snap_user_location_to_line;
use geo::Coord;
use models::*;
use std::sync::Mutex;
use utils::snap_user_location_to_line;

/// Manages the navigation lifecycle of a single trip, requesting the initial route and updating
/// internal state based on inputs like user location updates.
Expand Down Expand Up @@ -197,7 +199,10 @@ impl NavigationController {
// let fraction_along_line = route_linestring.line_locate_point(&point!(x: snapped_user_location.coordinates.lng, y: snapped_user_location.coordinates.lat));

if let Some(step) = current_step {
let distance_to_next_maneuver = distance_to_end_of_step(&snapped_user_location.into(), current_step_linestring);
let distance_to_next_maneuver = distance_to_end_of_step(
&snapped_user_location.into(),
current_step_linestring,
);

NavigationStateUpdate::Navigating {
snapped_user_location,
Expand Down
3 changes: 3 additions & 0 deletions common/ferrostar-core/src/navigation_controller/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ pub enum StepAdvanceMode {
/// The minimum required horizontal accuracy of the user location.
/// Values larger than this cannot trigger a step advance.
minimum_horizontal_accuracy: u16,
/// At this (optional) distance, navigation should advance to the next step regardless
/// of which LineString appears closer.
automatic_advance_distance: Option<u16>,
},
}

Expand Down

0 comments on commit 2375d1a

Please sign in to comment.