feature : radius to find stations around coordinates#1360
Conversation
|
What is the reason to not just load OSM or let the user choose a stop nearby via geocoding? With this implementation, you can get results that require you to walk a long detour to cross a river, motorway or train tracks which is less user friendly than just letting the user select a stop. |
|
This addresses a specific need for SNCF itinerary planning. One of the legacy planning modes is not door-to-door, but station-to-station. It is still used in particular for train ticket sales. In this context, the risk of detours is largely acceptable, since this mode is not intended for door-to-door usage. The goal is simply to identify nearby stations within a given radius and compute rail-only journeys between them, rather than provide accurate pedestrian routing If needed by the user, pre-routing and post-routing are currently handled separately through other mechanisms |
|
I also tried including the France OSM data following your suggestion in the matrix discussion, with the idea of filtering out pre-routing and post-routing segments on our side if we don’t need them. However, I noticed that the /plan endpoint became significantly slower when using the following parameters: This seems to introduce a noticeable performance overhead compared to the station-to-station approach |
|
We should definitely have a test case for this functionality then. Otherwise, a future change might introduce bugs without us noticing. I think you can just extend an existing test case like the routing test. |
| auto prepare_stats = std::map<std::string, std::uint64_t>{}; | ||
|
|
||
| auto const get_radius_offsets = [&](place_t const& p) { | ||
| if (!query.radius_.has_value() || loc_tree_ == nullptr) { |
There was a problem hiding this comment.
loc_rtree_ should be set exactly when tt_ != nullptr
so we can just verify this here tt_ != nullptr && tags_ != nullptr <- add loc_rtree_ != nullptr
There was a problem hiding this comment.
and in this case, dest_has_radius and start_has_radius become both query.radius_.has_value() (can be inlined)
There was a problem hiding this comment.
done, i've inlined as asked. i also removed the has radius check from the get_radius_offsets lambda as it is checked when assigning start_ and end_ (lines 873 and 884)
There was a problem hiding this comment.
it broke the routing when only one of the origin or destination is a coordinate. i've added a commit to fix this + a test
Co-authored-by: Felix Gündling <felix.guendling@gmail.com>
| "&timetableView=false"); | ||
| ASSERT_FALSE(res.itineraries_.empty()); | ||
| EXPECT_TRUE(std::any_of( | ||
| res.itineraries_.front().legs_.begin(), |
There was a problem hiding this comment.
please use utl::any_of (and other helpers) that don't require begin+end if you want to apply it to the whole range
| auto prepare_stats = std::map<std::string, std::uint64_t>{}; | ||
|
|
||
| auto const use_radius_start = query.radius_.has_value() && | ||
| std::get_if<osr::location>(&start) != nullptr; |
There was a problem hiding this comment.
please use std::holds_alternative
|
The way it's programmed now, you will only get the fastest option from all stops regardless of how far away they are. So if A is 1m away and B is 10km away but the option from B is 1min faster, you will never see the option from A (even though the journey via A is probably more interesting). Alternatives from different stops dominate each other directly. Another option would be to apply an offset based on beeline distance multiplied with an average speed. |
Co-authored-by: Felix Gündling <felix.guendling@gmail.com>
|
There might be one other option to address this use case: Meta stations, i.e. amend the feed with a special This would require curation of stop groups outside of MOTIS, enabling more fine-granular control over which stops are considered, which might make it faster (e.g. otherwise with the radius in Paris hundreds or thousands of bus stops will be considered). I'm not sure what exactly is the main factor that makes the CAR pre/postTransit solution you proposed slower in your case – it probably also depends on the local circumstances in the queried area. There will always be the one-to-all CAR routing that takes some time where we might have room for improvement, then the matching to the stops (which should be negligible if you had |
|
@orhazal maybe you can explain a bit more how your current solution works? If it has the same shortcomings I described and you just want to replicate it "bug-by-bug", then this PR might be one option. However, if you for example have a faster car routing outside of MOTIS such as OSRM, it might be an option to supply the offsets computed by OSRM to MOTIS. This would eliminate the disadvantage of the approach in this PR. |
|
@traines-source @felixguendling This PR provides this legacy functionality we need for SNCF Connect. However, in the long term, I personally hope we can move toward a single, unified itinerary engine. |
|
In case the radius overlaps, you won't find any connections with the current approach. If we switch to offsets |
|
In our use case, we have a business rule that only activates the radius from 100 km. This is due to the “segmented” computation of journeys coming from multiple sources. For short distances, the rules are completely different from those used for train/long-distance travel. As you mentioned earlier, this is within a legacy context with case-by-case or bug-by-bug replication. @felixguendling For this PR, do we need to add protection against radius overlap? |
I think we can leave it like it is now. Garbage in = garbage out. |
For a Motis instance containing only GTFS data (without any OSM/street routing data), calling the /plan API with coordinates does not work as Motis cannot compute routes between coordinates and stations
To enable station-to-station itinerary planning in this setup, a radius-based approach is needed. When a radius is provided, all stops within that radius are retrieved from the location RTree and used as zero-duration offsets. This allows computing pure train journeys using coordinates without requiring OSM data
Radius based offsets are only applied when the radius parameter is explicitly set in the /plan query
Note : i have little to no experience with C++, but i'm very enthusiastic about this project and happy to learn and contribute
Follow-up : https://matrix.to/#/!kDMWQgLgnsbvxbEJdH:matrix.org/$vShE6andX9uV8oqTtdDxuBdHdxWbCPOp6n3MxmV3VtQ?via=matrix.org&via=kde.org&via=matrix.tu-berlin.de