gravitystorm / openstreetmap-carto

A general-purpose OpenStreetMap mapnik style, in CartoCSS
Other
1.55k stars 822 forks source link

Rendering specific access tags #4952

Closed dch0ph closed 1 month ago

dch0ph commented 7 months ago

Fixes #214

Changes proposed in this pull request:

The code proposed has been extensively discussed in #214, but in summary:

SQL functions introduced that interpret mode-specific access tags in addition to the overall access tag.

Tags considered are determined by a "primary mode" inferred from the highway types: Vehicle road (primary mode: motorcar): motorcar > motor_vehicle > vehicle cycleway: bicycle bridleway: horse footway, steps: foot [Access tagging on track is unchanged, i.e. only determined by access]

In this initial PR, the interpretation of path is unchanged, i.e. path is considered to be a cycleway or bridleway if bicycle=designated or horse=designated respectively.

The access tags are reduced to a single int_access tag tagging the values no, restricted and yes (which is equivalent to NULL). restricted used to indicate an intermediate "some restrictions apply" for vehicles. The access marking used is the the current access=destination, but the name change reflects the fact that other values are included, e.g. delivery.

The int_access is generated, as normal practice for this style, on-the-fly. An option to use a generated column to pre-calculate these values is commented out. In practice, the overhead of combining the access tags is likely to be small given the vast amount of in-line SQL in the roads query. Note that some cruft in the railway side of the roads query has been removed.

Other global access tags, such as access=forestry, are also now interpreted (equivalent to no). access=agriculture;forestry is also accepted, although we don't typically interpret multiple-value tags.

The code does not require a database re-load, but does require additional functions to be installed in the Postgres database. These have been placed into a file functions.sql so that there is a place where functions for the style can be gathered. This does require an additional step in installing the style, and so installation instructions and the CI test have been adjusted. The Docker set-up has not been touched and will need fixing by somebody who understands/uses it.

Test rendering with links to the example places:

Destination marking Residential highway tagged with motor_vehicle=destination.

Before image

After image

No marking Before access=yes, motor_vehicle=no, psv=yes image

After image

Honouring foot North-south footway tagged with highway=footway, foot=private

Before image

After image

Honouring bicycle highway=cycleway, bicycle=designated, access=no Before image

After image

The last example needs discussion since it is a case where access=no has been added because the bridge is closed: image

The logic of access tagging is that the general access=no is overridden by the specific bicycle=designated, and a router should allow bicycles across. So this usage is arguably tagging for the renderer: retaining perhaps a formal right of way (bicycle=designated) but indicating that the way is closed by exploiting Carto's simple approach to access tagging.

It is inevitable that a wider and more correct usage of the access tags will throw up such cases!

pnorman commented 3 months ago

You have not presented any alternative approach for @dch0ph to pursue in solving #214 compared to the approach they took.

I suggested resolving it by moving the SQL logic to import time.

In other words: Your suggestion seems to be to forgo addressing #214. I don't consider that acceptable.

I never said that.

pnorman commented 3 months ago
  • Whether to return, say, unrecognised when the access tags could not be sensibly resolved (rather than overloading the meaning of unknown).

We should avoid the overload as it causes confusion.

  1. The handling of the outcome of carto_path_type. I am happy with the current simplified code.

I'm okay with it too.

The major issue remaining is where the processing should be done, and the maintainers will need to come to a consensus on that.

imagico commented 3 months ago

I suggested resolving it by moving the SQL logic to import time.

I have said multiple times already - this is a suggestion that requires looking at a much larger context. We should discuss it separately from this PR. If you want to shelve addressing #214 until we have had that discussion and reached consensus that is fine - but then please open an issue for that and present arguments why you think this would be beneficial for this project.

dch0ph commented 3 months ago

We should avoid the overload as it causes confusion.

Addressed.

dch0ph commented 3 months ago
  • but i would then insist on adding a warning comment explaining this dependency and i would also suggest to keep the more general variant commented out so style developers who want to adjust the logic can easily move to that.

I have added this. I prefer the simpler code, where "decisions" around, say, highway=bridleway only involve the value of horse and not any other access subtags.

pnorman commented 3 months ago

I have said multiple times already - this is a suggestion that requires looking at a much larger context. We should discuss it separately from this PR. If you want to shelve addressing #214 until we have had that discussion and reached consensus that is fine - but then please open an issue for that and present arguments why you think this would be beneficial for this project.

I cannot agree that a discussion of putting logic in functions is out of scope on a PR that is the first to introduce logic in functions.

imagico commented 3 months ago

I have added this. I prefer the simpler code, where "decisions" around, say, highway=bridleway only involve the value of horse and not any other access subtags.

This is not really relevant here at the moment since we are not discussing a change in the logic of how to interpret highway=path. But i would still like to understand this. Are you saying you would like to adjust our tag interpretation logic based on what can be implemented in the framework chosen in the most compact form?

Because i am usually taking the opposite approach. I think about what is map design wise the desirable logic of displaying things and then i think about the most elegant way to implement that is the framework we have. Adjusting map design to the technical constraints is of course necessary at times - but this is typically only of concern with geometric aspects and spatial relationships, not with tag interpretation.

@pnorman:

I cannot agree that a discussion of putting logic in functions is out of scope on a PR that is the first to introduce logic in functions.

As before you seem to disagree with something i have not said. Anyway - it is fair enough that if i ask you to make your case of doing style specific tag interpretation in preprocessing in a separate issue i should likewise discuss the idea of introducing SQL functions in a separate issue - which i have done in #5004.

dch0ph commented 3 months ago

Are you saying you would like to adjust our tag interpretation logic based on what can be implemented in the framework chosen in the most compact form?

No. I'm just arguing to keep the code in functions as clear as possible. If somebody does want to change the logic, they first need to understand what the code is doing. The natural reaction to looking at carto_int_access(COALESCE(NULLIF(bicycle, 'unknown'), "access"), FALSE) after the carto_path_type code is "why is this so complex when you know bicycle is not unknown?". This was pnorman's reaction. People are reluctant to change code when they don't understand its logic.

In the end, the "more general formulation" (which I initially used from a simple cut and paste) is not adding anything useful. It only has an effect if somebody has created a perverse carto_path_type that promotes path to cycleway despite bicycle either not being set or when bicycle=unknown.

imagico commented 3 months ago

Thanks. I think i understand the consideration behind that approach better now. It is also my experience that people have very different approaches to understanding logic and its implementation in code. It is best not to infer from one's own approach to understanding on how others will see this.

Anyway, with the warning comment added i think this is ok.

It only has an effect if somebody has created a perverse carto_path_type that promotes path to cycleway despite bicycle either not being set or when bicycle=unknown.

It is not a perverse way of casting highway=path into our three classes, it is a perfectly valid variant of doing it. I have not thought about it very much yet but at the moment i would probably lean towards showing a highway=path with foot=no and horse=no but no bicycle=* as cycleway.

imagico commented 1 month ago

Merged now, thanks @dch0ph for the patience in working on this.