Skip to content

Add option to avoid specific geometries #662

@1ec5

Description

@1ec5

The Directions API recently overloaded the exclude query parameter with an option to specify a list of point geometries in WKT format. We should add support for this syntax to serve certain use cases that require arbitrary avoidance. This would also help us achieve platform parity with the Java SDK, which implemented the feature in mapbox/mapbox-java#1362. However, it should not be implemented until the new exclude syntax leaves beta and becomes a formal part of the API contract.

Design

The overloading of exclude is particularly problematic for this library, which has always exposed exclude as an option set. But now it can hold arbitrary geometry data, which needs to be typed as a Geometry. Unfortunately, an OptionSet struct can’t store associated values, so there’s no way for us to support this syntax without breaking backwards compatibility. Besides, a geometry is semantically different than a road class.

case roadClassesToAvoid = "exclude"
/**
The route classes that the calculated routes will avoid.
Currently, you can only specify a single road class to avoid.
*/
open var roadClassesToAvoid: RoadClasses = []
/**
Option set that contains attributes of a road segment.
*/
public struct RoadClasses: OptionSet, CustomStringConvertible {

Perhaps this conflation in the API can be revisited in light of the semantic awkwardness that becomes apparent in Swift. Regardless, we can implement a parallel property, shapeToAvoid, declared as type Geometry?, with the expectation of being set to a MultiPoint until more geometry types are implemented on the server side. RouteOptions’ Codable implementation can switch between roadClassesToAvoid and shapeToAvoid depending on the value. This feature depends on Turf adding support for converting between WKT and GeoJSON: mapbox/turf-swift#185.

Workaround

Until we’re able to formally add support for this syntax, a developer can hook into the beta parameter themselves:

/**
  Route options for avoiding known [pedestrian scrambles](https://en.wikipedia.org/wiki/Pedestrian_scramble).
 */
class UnscrambledRouteOptions: RouteOptions {
    /// The locations of some known pedestrian scrambles to avoid.
    let scrambles = MultiPoint([
        .init(latitude: 39.3184214, longitude: -84.3689036),
        .init(latitude: 39.3109335, longitude: -84.3798639),
        .init(latitude: 37.3383465, longitude: -121.8807453),
        .init(latitude: 37.3330494, longitude: -121.8796307),
    ])
    
    override var urlQueryItems: [URLQueryItem] {
        var items = super.urlQueryItems
        let wktToAvoid = scrambles.coordinates
            .map { "point(\($0.longitude) \($0.latitude)" }
            .joined(separator: ",")
        items.append(.init(name: "exclude", value: wktToAvoid))
        return items
    }
}

/cc @ShrayKhullarMX @Guardiola31337

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions