Git Product home page Git Product logo

ferrostar's People

Contributors

archdoog avatar catme0w avatar haysmike avatar ianthetechie avatar max-leopold avatar nyurik avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

ferrostar's Issues

Ability to pause navigation explicitly

The ask:

  • Expose a state on FerrostarCore in iOS / Android: navigating, stopped, and paused.
  • Introduce pauseNavigation method which stops updates from the location provider but preservers all other state

Off-route detection - initial pass

This does not have to be final; only a proof-of-concept implementation. The basic requirement would be to flag that the user is off-route (ex: by a static amount) in the core and signaling back to the native layer.

Simulate route progress in absence of GPS signal

When the user doesn’t have an accurate GPS signal, the core should be able to (optionally) assume progress along the route. This is useful for cases such as driving through a tunnel, particularly for navigation in vehicles like cars and trucks.

First pass at snapped/following camera calculation

We want the core to calculate most parameters so that all rendering frontends can implement the standard "following" camera consistently.

This information should be returned as part of TripState.

Components needed:

  • Snapped user location
  • Zoom level Distance (can be simplistic at first, but may get more dynamic over time based on things like distance to the next maneuver and speed)
  • Pitch (Configurable parameter set at init)
  • Smoothed heading (this will determine the orientation of the user's location arrow)
  • Smoothed Course over ground (the user's direction of actual travel, independent of compass readings, which can be quite bad in some situations)
  • Current deviation from the route line; useful for frontends to decide if they should show the real location or snapped one.

Initial pass at core Route schema for PoC

The Route schema (and its children) need some fleshing out to support proof of concept features. We should keep this as barebones as possible for the PoC and defer as many non-essential decisions as possible before onboarding more stakeholders using diverse routing backends.

Set up CI release automation

Lots of things TBD, but we'll need at least the following:

  • Cargo publish to crates.io (Ian)
  • Swift release artifact build process; some unknowns around this as we'll need to push a release binary framework and make sure the checksum matches Package.swift. I have a hacked up checksum update feature in the iOS build script but need to figure out how to work this into CI properly.
  • Gradle publish to GH packages

Figure out a long-term solution for the Swift type re-export problem

In Swift it is not possible to simply mark a type for re-export. This is a fairly deep seated design decision, and there are several consequences. Downstream code depending on the core Swift package cannot construct or have an explicitly typed reference to any types from dependencies, including our own FFI(!). The types are "there" and you can store one in a non-explicitly-typed variable, pass this back to another function, and even inspect any of the properties, methods, etc. with full code completion in Xcode. But you cannot construct one yourself, nor can you store it in a typed field.

This is annoying for things like NavigationStateUpdate, which we currently basically re-export with our own type that (as an enum that is constructible only from the original enum) will generally cause compilation errors in the case of a divergence from the underlying type.

This is extremely problematic with types like Route in the context of enabling local route generation from user code, since we currently lack a good solution for constructing the Route in Swift code.

Publish an MSRV policy

  • Use tools to detect the current MSRV and specify it in code
  • Add CI checks to ensure it's not violated

Decide on a more formal policy somewhat more organically as the project matures.

Initial pass at instruction banners

Initial pass at showing a banner for the next instruction. Non-PoC requirements like icons will be added later (note: iOS might actually have usable icons built in with SFSymbols).

This will require surfacing a banner object in the navigation state updates and creating the following basic UI elements:

  • iOS
    • Text to be displayed
    • Distance to the maneuver
  • Android
    • Text to be displayed
    • Distance to the maneuver

[UI] Iconography for navigation banners

We need to decide on iconography for navigation banners at some point. These symbols will show along banners when the user is supposed to turn left, continue straight, do a barrel roll, and... you get the idea ;)

SFSymbols on iOS actually get us pretty close to something usable. It's not exactly what I'd envision for the end state, but it's pretty good. Material icons on the other hand seem rather lacking.

So, we'll need to find some better iconography (I'm tentatively thinking we'd use the same set for both iOS and Android, but that's a loosely held opinion of convenience) that's available under a permissive license.

Allow for light/dark styles for night and day which are selected automatically

This would not replace the ability to set a specific preference manually, but would be nice for most navigation applications.

  • Defaults based on sunrise/sunset. This can be done using some astronomical calculations with Julian dates. I actually did something like this approximately forever ago: https://github.com/ianthetechie/NSDate-Julian. It looks like there are a few Rust crates doing something similar, so we can get it on all platforms: https://crates.io/crates/sunrise.
  • In case the platform / app have ambient light data available, use this to switch to the dark style in the daytime (like Apple Maps when driving through a tunnel).

Extract credential placeholders from source code

  • iOS
  • Android

@Archdoog mentioned that maplibre-navigation-android has a pretty good solution on this for Android (see screenshot).

image

For SPM we can look at having a PLIST file that's gitignored, which would let us have previews using non-trivial commercial or self-hosted maps (ex: Stadia, Mapbox, etc.). In both cases, I think we can store not only the API key but also things like tile URLs to use for previews.

Common/suggested camera calculations (meta-issue)

Every frontend will be in charge of camera handling, and in many cases, the user may be allowed to temporarily take over. However, for the case of the "default" camera following the user around during navigation, we want to outsource this logic in a fairly generic manner to the core, which returns the key bits to be translated into camera control of the renderer by the frontend.

This issue will track individual cases until we finish the next milestone.

[Android] Localized distance formatting

Android doesn't appear to have a built-in distance formatter analogous to MKDistanceFormatter on iOS.

Known options

  • DecimalFormat - not deprecated, but Google basically says you shouldn't use this
  • NumberFormatter - Google says to use this for localized number formatting.

Unfortunately, NumberFormatter requires API level 30, which would seem to exclude a large number of users. It also only solves half the problem. We also need to determine which units we should be using, and this is not trivial (ex: UK prefers miles for distances), and the class doesn't appear to help with those.

Requirements off the top of my head:

  • Able to specify units somewhat granularly; we need to be able to have an imperial/metric split for the UK, for example, as they usually prefer miles for long distances but metric for everything else.
  • "Smart" rounding (ex: when below 100m, round to the nearest 10m; for large distances, probably round to the nearest mile or kilometer; switch from miles to fractional miles maybe, and then to feet, etc.).

Suggestions welcome on high-quality / de-facto standard Android libraries that can accomplish this.

Route simulation first pass

Goal: be able to simulate progress along a route for testing purposes, both "live" in the UI and "speed running" for unit tests.

Requirements

For reusability, the main logic should live in the Rust core. The interface will consist of a family of constructors and public methods that facilitate transitioning to the next step. The interface should be pure where possible to allow for composability, easy unit testing, and custom behavior.

Inputs

  • route A route (fully specified including all the maneuvers and metadata; can be captured from a Valhalla instance)
  • speed_multplier or speed (optional) A multiplier to apply to the route replay. TBD. We could probably use a fixed speed to start, but ideally it might be nice to mimic real-world estimated speeds or something. @Archdoog has probably some prev experience to contribute here.
  • locations or polyline The path that the user should actually visit; defaults to the route, but we want to be able to simulate things like off-route detection.

Functions

The primary non-constructor function will be a tick() which returns a new state given a location. It seems useful to have both a parameter-less version as well as one which takes a location as a parameter. In this way, developer end users may follow the route up to a point and then decide to follow a diverging path in order to test off-route handling without having to specify a full alternate set of locations upfront / decode a polyline and edit by hand, and that sort of thing.

Audit codebase for expect() and unwrap()

There are a number of cases where I have added these lazily to speed up the early development, but this needs to be rectified. Also consider adding linter checks of some sort if possible to ensure the only ones that we accept are clearly marked.

First pass at a developer guide

Currently we have some documentation spread across the README, examples, and the ARCHITECTURE document. As things mature over the next few months, we should consolidate this into an mdBook and publish it on GitHub pages to make onboarding new devs easier.

[iOS] Initial pass at navigation UI

  • Render a map
  • Draw a route polyline (doesn't need to show progress for the PoC but that'd be a nice bonus)
  • Show banners for the upcoming maneuver #13
  • Track the user's location and course over ground/heading

[iOS] Extract debug symbols into separate files (ex: dSYM)

Right now it looks like the default for rustc is to bake debug symbols into the framework. We can extract this into a dSYM file and strip the binaries.

It will require a bit more research to figure out how/if these should be distributed though, as it would ideally be possible for users of the framework to have these symbols uploaded with their apps to Apple. This post has some potentially useful info: https://pspdfkit.com/blog/2020/supporting-xcframeworks/.

Recalculation framework for when the user is off course

After some discussion, we have elected to go the "framework" route for recalculation. While users of Ferrostar will always be able to access state updates, including whether the user has deviated from the route, recalculation is common enough and annoying enough that we see value in offering a "full-service framework" approach to recalculation for the common case.

What this means:

  1. The FerrostarCore at the imperative shell level (iOS / Android) will watch for route deviations.
  2. When a deviation is detected, it will do some sanity checks (did we recalculate recently? Do we already have a request in flight? etc...) and, if applicable, invoke getRoutes and then invoke a delegate method informing the application of the available alternative routes.

Set up CI test and lint actions

This will programmatically enforce standards and make code reviews a lot easier.

Rust:

Apple:

  • Basic build and test (released binary)
  • Basic build and test (locally built binary!)
  • Ensure that the committed Swift bindings do not differ from autogenerated ones
  • Formatting check (swiftformatt)
  • swiftlint

Android:

  • Basic build and test (don't forget to run normal tests and android tests!)
  • Formatting checks (ktfmt)
  • TBD lints (ktlint?)

[iOS] MapKit SwiftUI components

What the title says. It should be pretty straightforward to provide some basic components that make it easy to use with MapKit for SwiftUI.

[core] no_std support

At some point we'll want to explore support for no_std platforms. Our initial focus is on major mobile operating systems, which have support for the full standard library, but certain embedded platforms we may target in the future may not.

This issue tracks known steps we'll need to take to support no_std:

  • non-UniFFI interface: UniFFI requires the standard library, particularly making use of things like std::sync::Arc in constructors, and types like std::time::SystemTime for mapping timestamps.
  • We use std::collections::HashMap a few places; could probably replace with alloc::collections::BTreeMap; we can also use Vec from alloc
  • NavigationController currently uses a Mutex for internal state mutation. This is arguably an antipattern and breaks the clean "functional core / imperative shell" pattern. We should probably rearchitect this to return a new controller state (which must be saved by the caller) before v1.0.

[Android] Decide on how to get location updates

Android is an unmitigated disaster when it comes to location services. We can hack things up with the core Android Location APIs, but will need a better long-term solution.

Here is the shortest summary I can muster to describe the state of Android location services:

  • Android (AOSP) has the LocationManger class. It mostly works, but it's pretty low level and doesn't fuse updates. You have to manually subscribe to updates from GPS, network, etc., decide what to do with the updates, and handle sub/unsub yourself to manage power consumption.
  • Google made their own fused location provider, which is ostensibly more battery-friendly, but may also be wildly inaccurate. I'll give Google the benefit of the doubt here though, and assume that the devs writing this should simply be filtering based on quality, and the provider is probably doing its job as designed, so this is probably the best option. Unfortunately, instead of improving the Android core, Google shoved this in Play Services, which is unavailable, sandboxed, or shimmed with implementations of unknown quality on many Android devices.
  • It is technically possible to ask your local Android "distro" what providers it has available, but many implementations either lie or implement the fused provider poorly. See this issue on the Organic Maps repo for a sampling of what could go wrong. I assume this is not exhaustive.

I am not currently aware of any open-source projects within the Android developer community which attempts to mitigate the above issues via a common "better fused location client" that has wide adoption. I hope that I'm just missing something, but I've confirmed most of the above with others in the Android community.

If this is indeed the case, we may simply have to push this down a layer and suggest that developers building apps with Ferrostar will have to consider this for their use cases individually. The Organic Maps issue doesn't inspire much confidence as they seem to have implemented workarounds specific to F-Droid.

Sharing test data?

We need to figure out an easy way to share test data across the core, Apple, and Android. This data comes in several forms:

  1. Waypoint data from GPS traces, route polylines, etc.
  2. Predefined routes
  • Captured JSON responses
  • Methods for creating Routes and iOS/Android UI state from a predefined route

These will be useful for creating demonstration applications, SwiftUI/Compose previews, and unit testing.

Currently some of this info exists, but it is spread out and (in some cases) duplicated.

  • Rust unit tests in navigation_controller.rs and osrm/mod.rs
  • Apple
    • FerrostarCoreTests/Fixtures.swift (used in ValhallaCoreTestsl)
    • FerrostarCore/ObservableState.swift (waypoints as Swift code for a UI demo fixture)
  • Android
    • core unit tests in ValhallaCoreTest.kt
    • Probably soon to be in the demo app, at least temporarily

I don't think we necessarily need to dedupe all of this, but it probably would be useful to have an easy way to load up routes from Valhalla JSON and simulate location by replaying GPX files on both iOS and Android, and we'll need some helper code for that, and maybe a shared directory (+ symlinks? I think both Xcode and Gradle might not like looking too far afield for files.)

Track remaining waypoints in a multi-leg trip

The core should expose remaining waypoints in some way eventually. This will enable users to recalculate more easily in the case of multi-leg trips. The MVP might ship without this, depending on whether @Archdoog finds out this is a hard requirement during integration.

[Android] Initial pass at navigation UI

  • Render a map
  • Draw a route polyline (doesn't need to show progress for the PoC but that'd be a nice bonus)
  • Show banners for the upcoming maneuver #13
  • Track the user's location and course over ground/heading

Framework / support structure for online -> offline routing fallback

In some scenarios, it would be nice to have a fallback to (or maybe even selectively prefer?) offline routing, such as when the user is in a poor network zone.

Off the top of my head, I'd say maybe we can have a fallback order or something and allow multiple route adapters in sequence. The offline routing would of course be the responsibility of the library end user, as routing itself is out of scope in Ferrostar, but it should support this use case.

[iOS] Standard view of upcoming maneuvers

While not all apps will necessarily need this, I expect that most will want a predesigned view that the user can activate to get a list of the upcoming maneuvers along the route.

[iOS] Ability to select location provider and waypoints in demo app

Context from initial discussion:

Yeah, my thought was use the settings page to easily configure this as well as waypoints. Thinking:

  1. Tap the gear,
  2. Switch for LocationProviding (Simulated, Live)
  3. Any permission requirements.
  4. Editable list of waypoints (we can absolutely also enable the tap map to add them).

This stuff can all easily be done with some SwiftUI and the @AppStorage decorator.

I agree though, that should be its own ticket after this is merged.

Originally posted by @Archdoog in #34 (comment)

Support "route refresh"

Optionally, we should support configurable refresh behavior, whereby the SDK will periodically check that the current route is still the optimal one. This is useful in areas subject to traffic jams when combined with a routing solution that is aware of live traffic.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.