diff --git a/include/nigiri/routing/one_to_all.h b/include/nigiri/routing/one_to_all.h index 6c0b55755..3357720cc 100644 --- a/include/nigiri/routing/one_to_all.h +++ b/include/nigiri/routing/one_to_all.h @@ -31,4 +31,13 @@ fastest_offset get_fastest_one_to_all_offsets(timetable const& tt, unixtime_t start_time, std::uint8_t transfers); +void for_each_one_to_all_round_time( + timetable const&, + raptor_state const&, + direction, + location_idx_t, + unixtime_t start_time, + std::uint8_t transfers, + std::function const&); + } // namespace nigiri::routing diff --git a/src/routing/one_to_all.cc b/src/routing/one_to_all.cc index 9a253c3fd..dda00c2ad 100644 --- a/src/routing/one_to_all.cc +++ b/src/routing/one_to_all.cc @@ -128,6 +128,30 @@ fastest_offset get_fastest_one_to_all_offsets(timetable const& tt, return {}; }; +void for_each_one_to_all_round_time( + timetable const& tt, + raptor_state const& state, + direction const search_dir, + location_idx_t const l, + unixtime_t const start_time, + std::uint8_t const transfers, + std::function const& cb) { + auto const invalid_delta = search_dir == direction::kForward + ? kInvalidDelta + : kInvalidDelta; + auto const& round_times = state.get_round_times(); + auto const base = + tt.internal_interval_days().from_ + + static_cast(to_idx(make_base(tt, start_time))) * date::days{1}; + for (auto const k : std::views::iota(std::uint8_t{0U}, transfers + 2U)) { + if (round_times[k][to_idx(l)][kVias] != invalid_delta) { + auto end_time = delta_to_unix(base, round_times[k][to_idx(l)][kVias]); + cb(k, search_dir == direction::kForward ? end_time - start_time + : start_time - end_time); + } + } +} + template raptor_state one_to_all(timetable const&, rt_timetable const*, query const&); diff --git a/test/rt/frun_shape_test.cc b/test/rt/frun_shape_test.cc index 69b5edabc..fca9589aa 100644 --- a/test/rt/frun_shape_test.cc +++ b/test/rt/frun_shape_test.cc @@ -245,6 +245,12 @@ TEST( leg_shape.push_back(point); }; + using round_times_t = std::vector>; + auto round_times = round_times_t{}; + auto const add_round_time = [&](std::uint8_t const k, duration_t const d) { + round_times.emplace_back(k, d); + }; + auto const to_location_idx = [&](std::string_view x) { auto const src = source_idx_t{0}; return tt.locations_.location_id_to_idx_.at({x, src}); @@ -894,6 +900,24 @@ TEST( delta_t{185 + kDefaultFootpathDuration.count()}); ASSERT_EQ(stats_s_direct.k_, 1U); } + // Test round times + { + round_times.clear(); + routing::for_each_one_to_all_round_time( + tt, state, kSearchDir, to_location_idx("S"), start_time, + q.max_transfers_, add_round_time); + EXPECT_EQ( + (round_times_t{{1, duration_t{185} + kDefaultFootpathDuration}, + {2, duration_t{140} + kDefaultFootpathDuration}}), + round_times); + round_times.clear(); + routing::for_each_one_to_all_round_time( + tt, state, kSearchDir, to_location_idx("W"), start_time, + q.max_transfers_, add_round_time); + EXPECT_EQ( + (round_times_t{{2, duration_t{200} + kDefaultFootpathDuration}}), + round_times); + } } } // One-to-All backwards search for time point @@ -971,6 +995,13 @@ TEST( q.max_transfers_); EXPECT_EQ(stats_f.duration_, delta_t{-110 - kDefaultFootpathDuration.count()}); + // Test round times + round_times.clear(); + routing::for_each_one_to_all_round_time(tt, state, kSearchDir, + to_location_idx("F"), start_time, + q.max_transfers_, add_round_time); + EXPECT_EQ((round_times_t{{1, duration_t{110} + kDefaultFootpathDuration}}), + round_times); } // Loading statistics {