Skip to content
4 changes: 3 additions & 1 deletion include/motis/endpoints/routing.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,9 @@ struct routing {
std::chrono::seconds max,
double max_matching_distance,
gbfs::gbfs_routing_data&,
stats_map_t& stats) const;
stats_map_t& stats,
unsigned const min_near_stations = 0U,
unsigned const max_bbox_increases = 5U) const;
Comment thread
aff3npirat marked this conversation as resolved.
Outdated

nigiri::hash_map<nigiri::location_idx_t,
std::vector<nigiri::routing::td_offset>>
Expand Down
12 changes: 12 additions & 0 deletions openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -763,6 +763,18 @@ paths:
default: 900
minimum: 0

- name: minNearStations
Comment thread
aff3npirat marked this conversation as resolved.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

inconsistent - sometimes stops, sometimes stations
-> always stops

in: query
required: false
description: |

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

description doesn't help me to understand what's actually happening

Optional. Default is `1`.
Minimum number of stations to route from / to. Increase
`maxPostTransitTime` / `maxPreTransitTime` if less stops are found. Pass `0` to disable.
schema:
type: integer
default: 1
minimum: 0

- name: maxDirectTime
in: query
required: false
Expand Down
90 changes: 69 additions & 21 deletions src/endpoints/routing.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#include <algorithm>
#include <cmath>
#include <iterator>
#include <utility>

#include "boost/thread/tss.hpp"

Expand All @@ -23,6 +25,7 @@
#include "osr/types.h"

#include "nigiri/common/interval.h"
#include "nigiri/for_each_meta.h"
#include "nigiri/location_match_mode.h"
#include "nigiri/routing/limits.h"
#include "nigiri/routing/pareto_set.h"
Expand All @@ -33,6 +36,7 @@
#include "nigiri/routing/tb/query_engine.h"
#include "nigiri/routing/tb/tb_data.h"
#include "nigiri/routing/tb/tb_search.h"
#include "nigiri/types.h"

#include "motis/config.h"
#include "motis/constants.h"
Expand Down Expand Up @@ -222,7 +226,9 @@ std::vector<n::routing::offset> get_offsets(
std::chrono::seconds const max,
double const max_matching_distance,
gbfs::gbfs_routing_data& gbfs_rd,
stats_map_t& stats) {
stats_map_t& stats,
unsigned const min_near_stations,
unsigned const max_bbox_increases) {
if (!r.is_osr_loaded()) {
return {};
}
Expand Down Expand Up @@ -255,9 +261,30 @@ std::vector<n::routing::offset> get_offsets(
profile = osr::search_profile::kCarSharing;
}

auto const max_dist = get_max_distance(profile, osr_params, max);
auto const near_stops =
get_stops_with_traffic(*r.tt_, rtt, *r.loc_tree_, pos, max_dist);
constexpr unsigned const FACTOR = 2U;

auto near_stops = std::vector<n::location_idx_t>{};
auto expanded_dist = get_max_distance(profile, osr_params, max);
auto expanded_time = max;
auto prev_distance = 0U;
for (unsigned i = 0U; i < max_bbox_increases; ++i) {
auto const stops =
get_stops_with_traffic(*r.tt_, rtt, *r.loc_tree_, pos, expanded_dist);
std::copy_if(stops.begin(), stops.end(), std::back_inserter(near_stops),
[&](auto const& l) {
return geo::distance(pos.pos_,
r.tt_->locations_.coordinates_[l]) >
prev_distance;
});
Comment thread
aff3npirat marked this conversation as resolved.
Outdated

if (near_stops.size() >= min_near_stations * FACTOR) {
break;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

no new line loop start

Suggested change

prev_distance = expanded_dist;
expanded_dist *= 2;
expanded_time *= 2;
}
auto const near_stop_locations = utl::to_vec(
near_stops,
[&](n::location_idx_t const l) { return stop_to_osr_location(r, l); });
Expand All @@ -270,21 +297,25 @@ std::vector<n::routing::offset> get_offsets(
auto const near_stop_matches = get_reverse_platform_way_matches(
*r.l_, r.way_matches_, p, near_stops, near_stop_locations, dir,
max_matching_distance);

return osr::route(params, *r.w_, *r.l_, p, pos, near_stop_locations,
pos_match, near_stop_matches,
static_cast<osr::cost_t>(max.count()), dir, nullptr,
sharing, elevations);
static_cast<osr::cost_t>(expanded_time.count()), dir,
nullptr, sharing, elevations);
};

auto mode_offsets = std::vector<n::routing::offset>{};

if (osr::is_rental_profile(profile)) {
if (!gbfs_rd.has_data()) {
return;
}

auto const max_dist_to_departure =
dir == osr::direction::kForward
? get_max_distance(osr::search_profile::kFoot, osr_params, max)
: max_dist;
? get_max_distance(osr::search_profile::kFoot, osr_params,
expanded_time)
: expanded_dist;
auto providers = hash_set<gbfs_provider_idx_t>{};
gbfs_rd.data_->provider_rtree_.in_radius(
pos.pos_, max_dist_to_departure,
Expand Down Expand Up @@ -320,10 +351,10 @@ std::vector<n::routing::offset> get_offsets(
ignore_walk = true;
for (auto const [p, l] : utl::zip(paths, near_stops)) {
if (p.has_value()) {
offsets.emplace_back(l,
n::duration_t{static_cast<unsigned>(
std::ceil(p->cost_ / 60.0))},
gbfs_rd.get_transport_mode(prod_ref));
mode_offsets.emplace_back(l,
n::duration_t{static_cast<unsigned>(
std::ceil(p->cost_ / 60.0))},
gbfs_rd.get_transport_mode(prod_ref));
}
}
}
Expand All @@ -332,19 +363,31 @@ std::vector<n::routing::offset> get_offsets(
fmt::streamed(m), provider->id_),
UTL_GET_TIMING_MS(provider_timer));
}

} else {
auto const paths = route(profile, nullptr);
for (auto const [p, l] : utl::zip(paths, near_stops)) {
if (p.has_value()) {
offsets.emplace_back(
mode_offsets.emplace_back(
l,
n::duration_t{static_cast<unsigned>(std::ceil(p->cost_ / 60.0))},
static_cast<n::transport_mode_id_t>(profile));
}
}
}

utl::sort(mode_offsets, [](auto const& a, auto const& b) {
return a.duration_ < b.duration_;
});
auto N = min_near_stations;
for (auto const& a : mode_offsets) {
if (a.duration_.count() * 60 < max.count() + 60 || N > 0) {
--N;
offsets.push_back(a);
} else {
break;
}
}
Comment thread
aff3npirat marked this conversation as resolved.
Outdated

stats.emplace(fmt::format("prepare_{}_{}", to_str(dir), fmt::streamed(m)),
UTL_GET_TIMING_MS(timer));
};
Expand Down Expand Up @@ -415,12 +458,15 @@ std::vector<n::routing::offset> routing::get_offsets(
std::chrono::seconds const max,
double const max_matching_distance,
gbfs::gbfs_routing_data& gbfs_rd,
stats_map_t& stats) const {
stats_map_t& stats,
unsigned const min_near_stations,
unsigned const max_bbox_increases) const {
auto const do_get_offsets = [&](osr::location const pos) {
return ::motis::ep::get_offsets(*this, rtt, pos, dir, elevations_, modes,
ro, osr_params, pedestrian_profile,
elevation_costs, max, max_matching_distance,
gbfs_rd, stats);
return ::motis::ep::get_offsets(
*this, rtt, pos, dir, elevations_, modes, ro, osr_params,
pedestrian_profile, elevation_costs, max, max_matching_distance,
gbfs_rd, stats, min_near_stations,
(min_near_stations == 0U) ? 0U : max_bbox_increases);
};
return std::visit(
utl::overloaded{
Expand Down Expand Up @@ -878,7 +924,8 @@ api::plan_response routing::operator()(boost::urls::url_view const& url) const {
osr_params, query.pedestrianProfile_,
query.elevationCosts_,
query.arriveBy_ ? post_transit_time : pre_transit_time,
query.maxMatchingDistance_, gbfs_rd, prepare_stats),
query.maxMatchingDistance_, gbfs_rd, prepare_stats,
static_cast<unsigned>(query.minNearStations_)),
.destination_ =
use_radius_dest
? radius_offsets(*loc_tree_, std::get<osr::location>(dest).pos_,
Expand All @@ -895,7 +942,8 @@ api::plan_response routing::operator()(boost::urls::url_view const& url) const {
osr_params, query.pedestrianProfile_,
query.elevationCosts_,
query.arriveBy_ ? pre_transit_time : post_transit_time,
query.maxMatchingDistance_, gbfs_rd, prepare_stats),
query.maxMatchingDistance_, gbfs_rd, prepare_stats,
static_cast<unsigned>(query.minNearStations_)),
.td_start_ = get_td_offsets(
rtt, e, start,
query.arriveBy_ ? osr::direction::kBackward
Expand Down
Loading