Skip to content

Conversation

bdferris-v2
Copy link
Contributor

Hey all, a bit late to the party, but I'm Brian Ferris at Google. I've got a long history in the GTFS space, but I've been recently asked to help out on the GBFS side of things. With that in mind, I figured my first PR should be small one that is unlikely to cause much discussion :) ...

The Geofencing refactor from #404.

What problem does your proposal solve? Please begin with the relevant issue number. If there is no existing issue, please also describe alternative solutions you have considered.

As discussed in #404 and captured in discussions at other forums (e.g. MobilityData developer workshop last summer), there have been a number of pain points around the existing geofencing_zones.json schema mechanism. Specifically, the combination of interior/exterior polygon semantics, overlapping polygons, and additive rules led to confusion amongst both producers and consumers of data about what restrictions actually applied in a given area.

What is the proposal?

This proposal attempts to capture the sentiment of various stakeholders, including those from the developers workshop, with the following high-level changes:

  • Polygons should define the interior (never the exterior) for a given restriction.
  • If geofencing is not present, there are no restrictions. If geofencing is present, rides are restricted by default any only enabled explicitly via defined geofence zone.
  • If ride-through is allowed outside the main service zone, the provider should provide a polygon corresponding with the maximum possible reach of the vehicle.
  • In the case of overlapping polygons, rules are generally not additive, but instead strict rules precedence is defined. (Note that there is still complexity on this point with optional rules fields. Feedback appreciated).

Is this a breaking change?

  • Yes
  • No
  • Unsure

Which files are affected by this change?

geofencing_zones.json

I know the GBFS 3.0 release process is well underway, but given that amount of discussion geofencing has received in the past year from ecosystem stakeholders, it seems worth trying to get this in the 3.0 release considering it is a breaking change.

@mplsmitch
Copy link
Collaborator

A few questions and some comments:

If ride-through is allowed outside the main service zone, the provider should provide a polygon corresponding with the maximum possible reach of the vehicle.

I think I understand the problem you’re trying to solve with this but I’m still a little skeptical of the maximum possible reach measure. If the vehicle is electrified, the “maximum possible reach” could be a factor of the vehicle’s range contained in max_range_meters but how would this be done for a vehicle that's not range limited like a pedal powered bike, or a shared car that could travel hundreds of miles from where the trip began?

If an operator wanted to prevent users from ending a trip outside of the city where they are permitted to operate they might put a ride_end_allowed=false rule on the outer “maximum possible reach” polygon. If that polygon intersected with another service where the rule should not be applied would that cause a problem for you? It seems like it creates the same problem as applying rules to the outside of polygons.

If there’s an area of limitation within a service area like ride_through_allowed=false, should this be done by creating a hole in the service area polygon where rides are permitted (I think that’s in the current example JSON) or should it be done with a separate overlapping polygon earlier in the JSON, before the service area polygon?

Some other stuff:

  • The definition of geometry is written in terms of limitations but your new scheme depends on allowances so maybe the geometry definition should be changed to reflect that?

  • The first sentence in the rules definition is repeated

  • The definitions for ride_start_allowed and ride_end_allowed both refer exclusively to Undocked (“free floating”) vehicles. Since these are now REQUIRED if the rules array is defined it seems like they need to apply to all vehicles, both dockless and docked (station based).

2) Remove duplicate line for `rules`.
3) Remove mentioned of free-floating-bikes in ride-start-end.
@bdferris-v2
Copy link
Contributor Author

Paraphrasing:

How should an operator model a maximum-possible-reach zone when the effective range of a vehicle (electric bike, car) could be quite large?

I'll admit this will probably be specific to each operator and could be influenced by a number of factors: vehicle range, operating licenses, restrictions on insurance, other factors. I wouldn't want to be too prescriptive on how operators model this, as it's ultimately their call. That said, I'd love to see some specific comments from operators if they have feedback on this.

What happens when service area polygons from different systems overlap?

So there are a couple of dimensions to this.

  1. Perhaps it's worth adding this explicitly to the text of the spec, but for two separate systems defined in separate feeds, the geofences of the first system should never be applied to the second system, whether they have overlap or not. Put another way, geofences are scoped to a single feed.

  2. Things are more complicated for aggregated feeds, where multiple effective systems are combined into a single feed. Here, we acknowledge the possibility that two separate systems from nearby cities or regions could potentially have overlapping geofences. However, in practice, we believe this overlap is rare. Second, in practice, many of the aggregated feeds we have seen use separate vehicle types to distinguish the vehicles of one system from another. Based on our resolution rules proposed in this PR, polygons with separate vehicle types would not cause interactions with each other.

That said, if this becomes an issue down the road (e.g. aggregator doesn’t want to specify separate vehicle types), I can imagine a number of approaches for adding system-level scoping of geofence polygons that would not break backwards-compatibility for existing feed producers.

Should restricted areas within a service area be modeled as “holes” in the service area polygon or as individual polygons that overlap (and come before) the service area polygon?

Because we are using GeoJSON as our polygon definition spec, I think we are on the hook for supporting "hole" functionality (unless we explicitly forbid it?). That said, as a best practice, I think we’d encourage providers to model restricted areas as separate polygons for clarity. That should could be called out in the spec as a SHOULD if you think it's appropriate.

Other stuff

Fixed as noted. Though I would point out that the ride_start_allowed and ride_end_allowed are just a refactor of the existing ride_allowed field for clarity, which was already REQUIRED. However, agreed that it makes sense to remove the reference to a specific vehicle type.

@ezmckinn
Copy link
Contributor

ezmckinn commented Feb 8, 2023

Thanks for this detailed proposal, @bdferris-v2! A few thoughts:

To me, the idea of maximum_possible_reach introduces more confusion than clarity. @mplsmitch interpreted this as the vehicle's maximum possible range — but did you mean it as the boundary at which a vehicle will be physically stopped? Either way, it would have different implications across modes (i.e. a car will have longer range than a scooter, and also a car driver may just be beeped at when they exit the zone, whereas a scooter rider would slow to a stop). I think it also runs contrary to the spirit of the law; most cities intend their operational zones to be the maximum outer reach, and in my view, formalizing a buffer zone invites operators to exceed that.

Clarifying that geofences should always define the inner polygon, rather than the exterior, seems fine.

I think it's fine to assume that if there are no geofences, there are no restrictions. However, I have concerns about this provision: "If geofencing is present, rides are restricted by default any only enabled explicitly via defined geofence zone."

Mostly, this latter clause would be difficult to implement. If a MaaS platform were to adopt this assumption before all the providers had updated their geofences to include an explicit "ride allowed" base layer, then large areas of many markets would suddenly appear un-rideable to riders. It would likely worsen the overlapping geofences problem, as it would only work if the "ride allowed" operations zone were the lowest layer, with all the other more restricted layers on top of it. Lastly, it would lead to cluttered user interfaces; would Google Maps overlay a colored polygon to show riders they can travel in a certain zone? If not, then what's the value of making that explicit through a geofence, rather than just leaving it as an open area? Riders would have to start a trip from operators' native app, anyway, where the operational zone would be displayed.

To my mind the simplest thing is to keep the assumption of "if there's no geofence here, you can ride" — regardless of how many geofences the system has as a whole.

@bdferris-v2
Copy link
Contributor Author

Thanks for the comments and questions @ezmckinn. Let me respond with more comments and more questions:

To me, the idea of maximum_possible_reach introduces more confusion than clarity.

I think it's worth pointing out that the spec as written makes no mention of maximum_possible_reach as an explicit concept. Using the old spec, I believe operators could define polygons for both an operating zone and a larger maximum-possible-reach zone, and they can continue to do so with the new spec if they so choose. The main distinction is that hopefully they are less likely to implement it incorrectly with the new semantics :)

The question of whether providers should be specifying maximum-possible-reach zones at all seems like more of a policy / best-practices question. I'll concede it's an important question for the community to address, but I also wonder if our thoughts on that subject actual change the details of this proposal. I'm not saying that in attempt to derail the discussion, just genuinely curious if you have specific thoughts. But maybe you sort of hinted at your stance with your next question.

However, I have concerns about this provision: "If geofencing is present, rides are restricted by default..."

Let's get into it :)

If a MaaS platform were to adopt this assumption before all the providers had updated their geofences to include an explicit "ride allowed" base layer, then large areas of many markets would suddenly appear un-rideable to riders.

Conceivably, a provider would only get the new semantics if they were specifying a new GBFS v3 feed (assuming this proposal makes it), which will likely require other refactoring for geofencing and other breaking changes. I'm hoping it wouldn't take them by surprise. Critically, we aren't proposing to apply these changes to existing v2 feeds. And yes, as a data consumer, you'll have to figure out how to potentially combine v2 and v3 geofence feeds in the same system. I acknowledge that technical burden, though I hope it doesn't stop us from trying to improve the spec.

It would likely worsen the overlapping geofences problem, as it would only work if the "ride allowed" operations zone were the lowest layer, with all the other more restricted layers on top of it.

There is no way around it. Providers /will/ need to take care in how they order their polygons in order to get the behavior they desire. However, we think the polygon ordering semantics are clearer and less error-prone than the status quo of the existing geofence spec.

Lastly, it would lead to cluttered user interfaces; would Google Maps overlay a colored polygon to show riders they can travel in a certain zone?

I can't comment too much on what Google might or might not do from a user experience (prepare to be underwhelmed either way :), but I do have some general thoughts.

First, I hope you'd agree that whether we specify allow-by-default or restrict-by-default, providers could specify a large polygon (as large a city, state, country, continent, globe) specifying the alternate behavior (restrict in allow-by-default, allow in restrict-by-default), so an app needs to be prepared to handle either scenario in terms of map rendering (or not rendering), regardless of whether they decide to color areas where you can or cannot ride (or both). In that sense, I don't think the spec choice here changes the complexity of the display problem for data consumers.

Second, if you agree with me that the rendering challenges are the same (maybe not?), then for me it comes down to what is the more reasonable default? Namely, are there more operators who want an allow-by-default policy (such that they have to specify an explicit restrict polygon as a base if they want to override) or who want restrict-by-default (such that they have to specify a base polygon for their operational area). My hunch is that it's the latter (restrict-by-default).


Field Name | REQUIRED | Type | Defines
---|---|---|---
`geofencing_zones` | Yes | GeoJSON FeatureCollection | Each geofenced zone and its associated rules and attributes is described as an object within the array of features, as follows.
\- `type` | Yes | String | “FeatureCollection” (as per IETF [RFC 7946](https://tools.ietf.org/html/rfc7946#section-3.3)).
\- `features` | Yes | Array | Array of objects as defined below.
 \- `type` | Yes | String | “Feature” (as per IETF [RFC 7946](https://tools.ietf.org/html/rfc7946#section-3.3)).
 \- `geometry` | Yes | GeoJSON MultiPolygon | A polygon that describes where rides might not be able to start, end, go through, or have other limitations. A clockwise arrangement of points defines the area enclosed by the polygon, while a counterclockwise order defines the area outside the polygon ([right-hand rule](https://tools.ietf.org/html/rfc7946#section-3.1.6)). All geofencing zones contained in this list are public (meaning they can be displayed on a map for public use).
Copy link
Contributor

@leonardehrenfried leonardehrenfried Feb 9, 2023

Choose a reason for hiding this comment

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

I'm very much in favour of dropping the clockwise/counterclockwise semantics. They are confusing and I've not actually seen them in the wild.

@leonardehrenfried
Copy link
Contributor

leonardehrenfried commented Feb 9, 2023

I have spent the last few weeks implementing the current geofencing spec in OpenTripPlanner so I feel qualified to weigh in.

Some comments:

  • I like the fact that you're proposing to remove the hole semantics. The geometry order is a better, easier to understand solution.
  • I like the fact that the presence of geofencing zones makes areas outside the zones unusable. This is something that I am currently inferring from the available data. In fact it addresses the important question of how to model a general operating area. Right now you'd probably have to use the difficult to understand clockwise/counterclockwise semantics or create a "ring of fire" . What the feeds that I looked at did instead though was to have a large area with ride_allowed=true and ride_through_allowed=true. I interpreted this as "don't allow leaving this area" which is contrary to the spec which says "By default, no restrictions apply everywhere".

In summary, I think what you're proposing is what my implementation assumes the spec should say by looking at the available data.

@ezmckinn
Copy link
Contributor

ezmckinn commented Feb 9, 2023

bdferris-v2 Thanks for the follow-up! It's helpful to understand your thinking in a bit more detail. You raise a good point about operators defining what version they are providing (e.g. v3), and also that there will be display issues whether we use "allowed" or "restricted" as the default setting. I'd be curious to know what other operators on this thread think. I'm certainly willing to be convinced either way.

@mplsmitch
Copy link
Collaborator

I was an operator of both docked and dockless bikes from 2010 to 2019. During that time we never had any limitations on where a bike could travel. Users were free to take bikes anywhere they chose for up to 24hrs so long as they paid the fees. Sometimes this meant putting them on the back of their cars and taking them far outside the city limits to a place they wanted to ride. To end the rental and stop being charged they had to return the bike to the service area.

This isn’t something that was limited to my bikeshare system, there are many examples, like this guy.

I think this is generally true if you were to rent a bike from a bike shop, just as it's true if you rent a car. Limitations on where these vehicles can travel are set via local traffic law.

The limitations that we were subject to as an operator had to do with where we were permitted to offer vehicles for rental, not where users could take those vehicles. If a bike was left by a user outside our service area, we would have to go and retrieve it since we weren't permitted to offer rentals in adjoining suburbs. In the current spec, anything outside the service area polygon would be:
ride_allowed : FALSE, ride_through_allowed : TRUE.

I've also seen the same rules applied to free floating car sharing. When Car2Go was operating in the US, you could drive the car as far as you wanted outside the service area and park the car for as long as you wanted but you couldn't end your rental (and stop being charged) until you returned to the service area.

This is all a long way of saying that many operators may not place restrictions on how far vehicles can travel outside the service area, but there is a need to place limitations on where vehicles can be rented and where rentals can end.

I would like to find a way to accomplish this that doesn't require operators to place limitations on their services in order to comply with the specification. The specification should model operators' business practices, not the other way around.

@bdferris-v2
Copy link
Contributor Author

@mplsmitch trying to get to the heart of the matter, it sounds like you are in-favor of removing the "restrict by default if geofences are defined" clause? Namely:

When geofencing_zones.json is defined, rides may not start, end, or travel through any area of the system unless explicitly enabled by a geofence zone and its associated rules.

Instead, we could replace it with two options:

  1. More restrictive. Change the semantics of "travel through":

When geofencing_zones.json is defined, rides may not start or end in any area of the system unless explicitly enabled by a geofence zone and its associated rules. Ridges may travel through any area of the system unless explicitly disabled by a geofence zone and its associated rules.

  1. Less restrictive. Enable everything by default:

When geofencing_zones.json is defined, there are no default restrictions on any area of the system not covered by a geofence zone. As such, rides can start, end, or travel through all areas of the system by default unless explicitly restricted by a geofence zone and its associated rules.

(We can wordsmith the details here)

As discussed above, a provider still has the power to globally restrict rides outside of their operating zone in either case. They just have to be explicit about it.

Thoughts?

@leonardehrenfried
Copy link
Contributor

leonardehrenfried commented Feb 10, 2023

@bdferris-v2 with your latest suggestions how would you model a general operating area that you cannot leave?

A ring around it with a ride_allowed=false?

@bdferris-v2
Copy link
Contributor Author

@leonardehrenfried yeah, I believe that's the idea. Though "ring" isn't maybe the right mental model, even though that's how it might be rendered:

┌─Poly─A──────────────────┐
│                         │
│                         │
│    ┌──Poly─B──────┐     │
│    │              │     │
│    │              │     │
│    │              │     │
│    │              │     │
│    │              │     │
│    └──────────────┘     │
│                         │
│                         │
└─────────────────────────┘

In practice, we'd have a larger Polygon A that defines the overall restricted area (it could be as large as the world, conceivably). We'd then layer a smaller Polygon B over top (by specifying it first) that defines the active operating area.

Does that make sense?

@mplsmitch
Copy link
Collaborator

mplsmitch commented Feb 10, 2023

In practice, we'd have a larger Polygon A that defines the overall restricted area (it could be as large as the world, conceivably).

If this outer area polygon could be "as large as the world", then maybe there's no need for a polygon. What I mean is if you could declare rules that had a global scope, and then override those rules using the polygons, that would solve all the issues. So the default TRUE/FALSE state for each rule used in the file is set first and then changed using the polygons.

Something like:


"global_rules" : [
 {
          "vehicle_type_id": ["bike"],
          "ride_start_allowed": false,
         "ride_end_allowed": false,

        }
],
  {
    "geometry": { "#": "... Polygon A ..." },
    "properties": {
      "rules": [
        {
          "vehicle_type_id": ["bike"],
          "ride_start_allowed": true,
         "ride_end_allowed": true,

        }
      ]
    }
  },`

@bdferris-v2
Copy link
Contributor Author

Would global rules be required? Would they be required to cover all vehicle types? If the answer is "no" to either of those questions, what should the default behavior be?

@leonardehrenfried
Copy link
Contributor

Does that make sense?

It does make sense to me. I have to think about whether that's easier or harder to understand than the clockwise/counterclockwise behaviour.

@mplsmitch
Copy link
Collaborator

Would global rules be required?

No - I don't think they need to be required, see below on default behavior

Would they be required to cover all vehicle types?

No - I would use the same language that's in the current rules array: "If vehicle type IDs are not specified, then restrictions apply to all vehicle types."

If the answer is "no" to either of those questions, what should the default behavior be?

The default behavior in any area should always be no restriction. Similar to the question above on vehicle IDs, any area including global that doesn't have a rule specified contains no restrictions.

@bdferris-v2
Copy link
Contributor Author

The default behavior in any area should always be no restriction.

@mplsmitch I hear and acknowledge your argument that there should be no restrictions on travel by default. I'm generally ok with making unrestricted travel the default, but I'll admit I'm slightly more worried about defaulting to no restrictions on trip start/end, as my intuition is that there are few operators that truly allow their trips to start/end anywhere.

What are your thoughts on adopting your global_rules amendment but upgrading it to a required field? I'm generally in favor of anything that makes the travel policy explicit, instead of relying on a default that might not be intuitive to a particular provider.

@mplsmitch
Copy link
Collaborator

@bdferris-v2 When I said no restrictions on travel by default I was thinking what's the right way to handle a file where these fields are either not included or null. In other words if global_rules was not defined or empty you wouldn't apply a restriction by default. I'm okay with making the global_rules required, but maybe it should be conditioned on the fields where it makes sense. For example if ride_start, ride_end or ride_through are applied to any polygons, then you'd be required to also set them globally.
If none of these are defined and the only thing in the file is a polygon with station_parking or maximum_speed_kph then maybe you don't need to set them globally? If there's no speed limit outside the polygon, what number do you set maximum_speed_kph at?

@sven4all
Copy link
Contributor

I like this proposal now the global rules are added. We would like to use this proposal to start communicating service areas between operators and municipalities, to give municipalities the opportunity to check if operators are complying with the permitted service areas.

What is needed to start a vote and make this proposel part of GBFS 3.0 RC?

Copy link
Collaborator

@mplsmitch mplsmitch left a comment

Choose a reason for hiding this comment

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

just a few things that need cleaning up - the diff shows something wrong around line 1605 but I can't see what it is, maybe correcting the JOSN will fix it

@bdferris-v2
Copy link
Contributor Author

Ok, I've made the updates suggested by @mplsmitch. As there seems to be positive engagement on where we've ended up at with this proposal, I'm going to call a vote.

@bdferris-v2
Copy link
Contributor Author

I hereby call a vote on this proposal. Voting will be open for 10 full calendar days until 11:59PM UTC on Thursday, March 9th, 2023.

Please vote for or against the proposal, and include the organization for which you are voting in your comment.

Please note if you can commit to implementing the proposal.

@benwedge
Copy link

Joyride (feed provider) votes in favour.

We do not currently use the geofencing file, but may do so in the future.

@josee-sabourin josee-sabourin added Vote open v3.0-RC Candidate change for GBFS 3.0 (Major release) gbfs.md labels Feb 27, 2023
@testower
Copy link
Contributor

Entur (aggregator) votes in favour.

We will implement support for this proposal.

@sven4all
Copy link
Contributor

CROW (aggregator for municipalities) votes in favour.

If this vote passes we will try to implement this next month within our dashboard https://dashboarddeelmobiliteit.nl/.

@leonardehrenfried
Copy link
Contributor

OpenTripPlanner votes in favour although it's not clear yet if and when it will be implemented.

@ezmckinn
Copy link
Contributor

ezmckinn commented Mar 3, 2023

Superpedestrian votes in favor. No timeline for implementation yet, but would implement in the future.

@josee-sabourin
Copy link
Contributor

This vote has now closed, and it passes!

Votes in favor:
Joyride (producer)
Entur (consumer)
CROW (consumer)
OpenTripPlanner (consumer)
Superpedestrian (producer)

There were no votes against.

Thank everyone for coming together on this! This is a massive accomplishment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
gbfs.md v3.0-RC Candidate change for GBFS 3.0 (Major release) Vote Passed
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants