Skip to content

Potential false positive class 11 (stop order) in analyzer relations_public_transport on (bus) routes using way twice #2489

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
esteinmann opened this issue Apr 5, 2025 · 6 comments

Comments

@esteinmann
Copy link

esteinmann commented Apr 5, 2025

Sorry if this is a known issue but couldn't find an existing GitHub issue.

I have noticed that Osmose reports "The stops may not be in the right order" on some local bus route relation that I changed (I only splitted some road that is part of the bus route so now I am the last modifier of the relation).

After some research I found the analyzer and tried to understand what is doing to determine the expected stop order. The analyzer is: https://github.com/osm-fr/osmose-backend/blob/dev/analysers/analyser_osmosis_relation_public_transport.py

The temp table that is constructed to facilitate comparison of stop order in relation and on route line geometry is:

CREATE TEMP TABLE platform_that_can_project AS (
SELECT
    route_linestring.id AS route_id,
    stop_platform.member_type || stop_platform.mid AS stop_id,
    stop_platform.geom AS stop,
    ROW_NUMBER () OVER (PARTITION BY route_linestring.id ORDER BY stop_platform.morder) AS stop_order,
    ROW_NUMBER () OVER (PARTITION BY route_linestring.id ORDER BY ST_LineLocatePoint(route_linestring.geom, stop_platform.geom)) AS projected_stop_order,
    CASE
        WHEN LEAD(stop_platform.morder, 1) OVER (PARTITION BY route_linestring.id ORDER BY stop_platform.morder) IS NULL THEN 1
        ELSE 0
    END AS is_last_platform
FROM
    stop_platform
    JOIN route_linestring ON
        route_linestring.id = stop_platform.id
    WHERE
        stop_platform.mrole IN ('platform', 'platform_exit_only', 'platform_entry_only') AND
        stop_platform.member_type='N' AND
        GeometryType(route_linestring.geom) = 'LINESTRING' AND
        ST_LineLocatePoint(route_linestring.geom, ST_ClosestPoint(route_linestring.geom, stop_platform.geom)) NOT IN (0, 1)
)

Running the Osmose backend on Monaco (as per the docker sample) luckily also encounters this issue so I can inspect the data by running the query myself.

Two example of route where this error class is reported:
https://www.openstreetmap.org/relation/2214023
https://www.openstreetmap.org/relation/2211942

What those routes have in common is that that the bus loops after the start so the line will overlap itself (same way is in the relation twice). This results in the first stops having an unexpected value for ST_LineLocatePoint. Using another temp table I can show the values of this function for each stop on route 2214023:

   stop_id   |            stop_name            | morder |  line_locate_point  
-------------+---------------------------------+--------+---------------------
  4939122068 | Saint-Roman                     |      1 | 0.15939694503354393  <--
  4937669543 | Varavilla                       |      3 | 0.07389976050609681  <--
  4939122054 | Saint-Roman MC                  |      5 |  0.1259758608277057  <--
  2189614157 | Carmes                          |      7 | 0.20985591669283463
  4939150469 | La Rousse                       |      9 |  0.2715753931560574
  4938970036 | Place des Moulins               |     11 |  0.3270172325689365
  4938970029 | Saint-Charles                   |     13 | 0.39297672946797796
  2189614158 | Crémaillère                     |     15 |  0.4669802630793612
  4938969807 | Roqueville                      |     17 |  0.5252238014995443
  4937669521 | Pont Sainte-Dévote              |     19 |  0.5874168580629439
 11449925731 | Louis Aureglia                  |     21 |  0.6464254027913752
 11449925732 | Castelleretto                   |     23 |  0.7197663434638272
  8047787742 | Honoré II                       |     25 |  0.7608717266032766
  4937556537 | Place d'Armes (Port)            |     27 |  0.8473856964040217
  4938436901 | Princesse Stéphanie             |     29 |  0.8921235692386069
  4937556420 | Fontvieille - Centre Commercial |     31 |  0.9997876778365224

Saint-Roman is expected to the first on the line geometry as it is close to the starting coordinate of the first way in the relation but I suspect that ST_LineLocatePoint finds it further on the line as the route passes this point again? Without local knowledge I can't tell if the stop order in the relation is correct but it seems alright as it aligns with the order of the ways in the relation.

The same thing happens with route 2211942

   stop_id   |         stop_name          | morder |  line_locate_point   
-------------+----------------------------+--------+----------------------
  2189620623 | Rotondes                   |      1 |  0.08283935055673683 <--
  9153994027 | Villa Paloma               |      3 | 0.016798942503149363 <--
 11449741817 | Moneghetti                 |      5 |  0.15172635367896206
  4938342182 | Belgique                   |      7 |  0.21271170299679512
  4937669527 | Pont Sainte-Dévote         |      9 |   0.2976911507027532
  4938969804 | Roqueville                 |     11 |   0.3668643694433014
  4938969814 | Monte-Carlo                |     13 |  0.44635405607514006
   280490389 | Square Beaumarchais        |     15 |  0.48842575406869865
 11449581672 | Ostende                    |     17 |   0.5612875966987445
  4939122085 | Place Sainte-Dévote (Gare) |     19 |   0.6310200148283822
  2185515267 | Princesse Florestine       |     21 |   0.6693014684566264
  4937556532 | Place d'Armes              |     23 |   0.7802402641224183
  4937556413 | Monaco Ville (le Rocher)   |     25 |   0.9999737708989132

To conclude my question:
Are these false positives or am I misinterpreting the data and is the stop order indeed incorrect?

@frodrigo
Copy link
Contributor

frodrigo commented Apr 5, 2025

I think you are right. Do you have idea to fix that ?

cc @nlehuby

@esteinmann
Copy link
Author

This is probably complicated to fix but a rough idea I have is to split the route line into multiple parts:

The red line represents the first linestring, the green part is skipped and blue represents the second linestring. Together they are still the complete route line.
Image

I think the procedure of checking against these set of linestrings could still work more or less the same as now however the order correctness needs to be determined per separate route part. For the example of relation 2214023:

Red part:
All stops except Varavilla and "Saint-Roman MC" return 0 for ST_LineLocatePoint(route_linestring.geom, ST_ClosestPoint(route_linestring.geom, stop_platform.geom)) so are ignored for comparison and it only matters if Varavilla and SRMC are in the right relative order.

Blue part:
SR, Varavilla and SRMC would return 0 for ST_LineLocatePoint(route_linestring.geom, ST_ClosestPoint(route_linestring.geom, stop_platform.geom)) the rest can be checked for relative order correctness on this route part.

Not sure how to implement that with PostGIS queries though (how to get multiple route_linestring per route relation) and there are probably more complex situations with turn loops that might not work with this setup.

@nlehuby
Copy link
Contributor

nlehuby commented Apr 6, 2025

I have already proposed a fix to this : #1274

@esteinmann
Copy link
Author

Thanks! So if I understand correctly a performance issue is holding back that PR?

If that works it seems like an elegant fix with minimal code change :) How does it work exactly? I've read the documentation on ST_OffsetCurve but wouldn't the returned line be the same for the ways that are used twice and the stops still have the same relative position on that line?

@nlehuby
Copy link
Contributor

nlehuby commented Apr 6, 2025

Well done for understanding how the analysis works and for identifying this issue, this sql is particularly tricky!

The offset depends on the direction (the line is oriented), so the offset is different on the first and return parts.
For example, here is the offset line for the example shown above (relation/2214023)

Image

@esteinmann
Copy link
Author

Ah thanks, that's a great solution if the performance issue can be tackled. I see the PR is quite old, maybe the situation has improved in recent versions of PostGIS?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants