diff --git a/include/motis/endpoints/routing.h b/include/motis/endpoints/routing.h index b1ee09557..7ab58b51a 100644 --- a/include/motis/endpoints/routing.h +++ b/include/motis/endpoints/routing.h @@ -3,6 +3,8 @@ #include "osr/location.h" #include "osr/types.h" +#include "nigiri/routing/clasz_mask.h" + #include "motis-api/motis-api.h" #include "motis/elevators/elevators.h" #include "motis/fwd.h" diff --git a/include/motis/timetable/modes_to_clasz_mask.h b/include/motis/timetable/modes_to_clasz_mask.h new file mode 100644 index 000000000..8c6a86e9c --- /dev/null +++ b/include/motis/timetable/modes_to_clasz_mask.h @@ -0,0 +1,11 @@ +#pragma once + +#include "motis-api/motis-api.h" + +#include "nigiri/routing/clasz_mask.h" + +namespace motis { + +nigiri::routing::clasz_mask_t to_clasz_mask(std::vector const&); + +} \ No newline at end of file diff --git a/openapi.yaml b/openapi.yaml index fc32c2b5f..c3aa25e2c 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -188,6 +188,38 @@ paths: - `arriveBy=true`: the parameters `date` and `time` refer to the arrival time - `arriveBy=false`: the parameters `date` and `time` refer to the departure time + - name: direction + in: query + required: false + schema: + type: string + enum: + - EARLIER + - LATER + description: | + This parameter will be ignored in case `pageCursor` is set. + + Optional. Default is + - `LATER` for `arriveBy=false` + - `EARLIER` for `arriveBy=true` + + The response will contain the next `n` arrivals / departures + in case `EARLIER` is selected and the previous `n` + arrivals / departures if `LATER` is selected. + + - name: mode + in: query + schema: + type: array + items: + $ref: '#/components/schemas/Mode' + default: + - TRANSIT + description: | + Optional. Default is all transit modes. + + Only return arrivals/departures of the given modes. + - name: n in: query schema: diff --git a/src/endpoints/routing.cc b/src/endpoints/routing.cc index 0c51d14ec..83d48b2e2 100644 --- a/src/endpoints/routing.cc +++ b/src/endpoints/routing.cc @@ -26,6 +26,7 @@ #include "motis/parse_location.h" #include "motis/street_routing.h" #include "motis/tag_lookup.h" +#include "motis/timetable/modes_to_clasz_mask.h" #include "motis/timetable/time_conv.h" #include "motis/update_rtt_td_footpaths.h" @@ -199,44 +200,6 @@ std::vector routing::get_offsets( return offsets; } -n::routing::clasz_mask_t to_clasz_mask(std::vector const& mode) { - auto mask = n::routing::clasz_mask_t{0U}; - auto const allow = [&](n::clasz const c) { - mask |= (1U << static_cast>(c)); - }; - for (auto const& m : mode) { - switch (m) { - case api::ModeEnum::TRANSIT: - mask = n::routing::all_clasz_allowed(); - return mask; - case api::ModeEnum::TRAM: allow(n::clasz::kTram); break; - case api::ModeEnum::SUBWAY: allow(n::clasz::kSubway); break; - case api::ModeEnum::FERRY: allow(n::clasz::kShip); break; - case api::ModeEnum::AIRPLANE: allow(n::clasz::kAir); break; - case api::ModeEnum::BUS: allow(n::clasz::kBus); break; - case api::ModeEnum::COACH: allow(n::clasz::kCoach); break; - case api::ModeEnum::RAIL: - allow(n::clasz::kHighSpeed); - allow(n::clasz::kLongDistance); - allow(n::clasz::kNight); - allow(n::clasz::kRegional); - allow(n::clasz::kRegionalFast); - allow(n::clasz::kMetro); - allow(n::clasz::kSubway); - break; - case api::ModeEnum::HIGHSPEED_RAIL: allow(n::clasz::kHighSpeed); break; - case api::ModeEnum::LONG_DISTANCE: allow(n::clasz::kLongDistance); break; - case api::ModeEnum::NIGHT_RAIL: allow(n::clasz::kNight); break; - case api::ModeEnum::REGIONAL_FAST_RAIL: - allow(n::clasz::kRegionalFast); - break; - case api::ModeEnum::REGIONAL_RAIL: allow(n::clasz::kRegional); break; - default: continue; - } - } - return mask; -} - std::pair> get_start_time( api::plan_params const& query) { if (query.pageCursor_.has_value()) { diff --git a/src/endpoints/stop_times.cc b/src/endpoints/stop_times.cc index a97578eed..64df9270d 100644 --- a/src/endpoints/stop_times.cc +++ b/src/endpoints/stop_times.cc @@ -6,6 +6,7 @@ #include "utl/enumerate.h" #include "utl/erase_duplicates.h" +#include "nigiri/routing/clasz_mask.h" #include "nigiri/rt/frun.h" #include "nigiri/rt/rt_timetable.h" #include "nigiri/rt/run.h" @@ -17,6 +18,7 @@ #include "motis/parse_location.h" #include "motis/tag_lookup.h" #include "motis/timetable/clasz_to_mode.h" +#include "motis/timetable/modes_to_clasz_mask.h" #include "motis/timetable/time_conv.h" namespace n = nigiri; @@ -150,14 +152,16 @@ struct rt_ev_iterator : public ev_iterator { n::stop_idx_t const stop_idx, n::unixtime_t const start, n::event_type const ev_type, - n::direction const dir) + n::direction const dir, + n::routing::clasz_mask_t const allowed_clasz) : rtt_{rtt}, stop_idx_{stop_idx}, rt_t_{rt_t}, ev_type_{ev_type}, - finished_(dir == n::direction::kForward ? time() < start - : time() > start) { - + finished_{ + !n::routing::is_allowed( + allowed_clasz, rtt.rt_transport_section_clasz_[rt_t].at(0)) || + (dir == n::direction::kForward ? time() < start : time() > start)} { assert((ev_type == n::event_type::kDep && stop_idx_ < rtt_.rt_transport_location_seq_[rt_t].size() - 1U) || (ev_type == n::event_type::kArr && stop_idx_ > 0U)); @@ -198,7 +202,8 @@ std::vector get_events( n::unixtime_t const time, n::event_type const ev_type, n::direction const dir, - std::size_t const count) { + std::size_t const count, + n::routing::clasz_mask_t const allowed_clasz) { auto iterators = std::vector>{}; if (rtt != nullptr) { @@ -214,7 +219,7 @@ std::vector get_events( n::stop{s}.out_allowed()))) { iterators.emplace_back(std::make_unique( *rtt, rt_t, static_cast(stop_idx), time, ev_type, - dir)); + dir, allowed_clasz)); } } } @@ -224,6 +229,9 @@ std::vector get_events( auto seen = n::hash_set>{}; for (auto const x : locations) { for (auto const r : tt.location_routes_[x]) { + if (!n::routing::is_allowed(allowed_clasz, tt.route_clasz_[r])) { + continue; + } auto const location_seq = tt.route_location_seq_[r]; for (auto const [stop_idx, s] : utl::enumerate(location_seq)) { if (n::stop{s}.location_idx() == x && @@ -273,11 +281,17 @@ api::stoptimes_response stop_times::operator()( auto const x = tags_.get_location(tt_, query.stopId_); auto const p = tt_.locations_.parents_[x]; auto const l = p == n::location_idx_t::invalid() ? x : p; - auto const [dir, time] = parse_cursor(query.pageCursor_.value_or( - fmt::format("{}|{}", query.arriveBy_ ? "EARLIER" : "LATER", - std::chrono::duration_cast( - query.time_.value_or(openapi::now())->time_since_epoch()) - .count()))); + auto const allowed_clasz = to_clasz_mask(query.mode_); + auto const [dir, time] = parse_cursor(query.pageCursor_.value_or(fmt::format( + "{}|{}", + query.direction_ + .transform([](auto&& x) { + return x == api::directionEnum::EARLIER ? "EARLIER" : "LATER"; + }) + .value_or(query.arriveBy_ ? "EARLIER" : "LATER"), + std::chrono::duration_cast( + query.time_.value_or(openapi::now())->time_since_epoch()) + .count()))); auto locations = std::vector{l}; auto const add = [&](n::location_idx_t const l) { @@ -305,7 +319,7 @@ api::stoptimes_response stop_times::operator()( auto const ev_type = query.arriveBy_ ? n::event_type::kArr : n::event_type::kDep; auto events = get_events(locations, tt_, rtt, time, ev_type, dir, - static_cast(query.n_)); + static_cast(query.n_), allowed_clasz); utl::sort(events, [&](n::rt::run const& a, n::rt::run const& b) { auto const fr_a = n::rt::frun{tt_, rtt, a}; auto const fr_b = n::rt::frun{tt_, rtt, b}; diff --git a/src/journey_to_response.cc b/src/journey_to_response.cc index c57916609..28da5ae2a 100644 --- a/src/journey_to_response.cc +++ b/src/journey_to_response.cc @@ -146,6 +146,9 @@ api::Itinerary journey_to_response(osr::ways const* w, leg.intermediateStops_ = std::vector{}; for (auto i = first; i < last; ++i) { auto const stop = fr[i]; + if (stop.is_canceled()) { + continue; + } auto& p = leg.intermediateStops_->emplace_back( to_place(tt_location{stop})); p.departure_ = stop.time(n::event_type::kDep); diff --git a/src/timetable/modes_to_clasz_mask.cc b/src/timetable/modes_to_clasz_mask.cc new file mode 100644 index 000000000..82304756a --- /dev/null +++ b/src/timetable/modes_to_clasz_mask.cc @@ -0,0 +1,45 @@ +#include "motis/timetable/modes_to_clasz_mask.h" + +namespace n = nigiri; + +namespace motis { + +n::routing::clasz_mask_t to_clasz_mask(std::vector const& mode) { + auto mask = n::routing::clasz_mask_t{0U}; + auto const allow = [&](n::clasz const c) { + mask |= (1U << static_cast>(c)); + }; + for (auto const& m : mode) { + switch (m) { + case api::ModeEnum::TRANSIT: + mask = n::routing::all_clasz_allowed(); + return mask; + case api::ModeEnum::TRAM: allow(n::clasz::kTram); break; + case api::ModeEnum::SUBWAY: allow(n::clasz::kSubway); break; + case api::ModeEnum::FERRY: allow(n::clasz::kShip); break; + case api::ModeEnum::AIRPLANE: allow(n::clasz::kAir); break; + case api::ModeEnum::BUS: allow(n::clasz::kBus); break; + case api::ModeEnum::COACH: allow(n::clasz::kCoach); break; + case api::ModeEnum::RAIL: + allow(n::clasz::kHighSpeed); + allow(n::clasz::kLongDistance); + allow(n::clasz::kNight); + allow(n::clasz::kRegional); + allow(n::clasz::kRegionalFast); + allow(n::clasz::kMetro); + allow(n::clasz::kSubway); + break; + case api::ModeEnum::HIGHSPEED_RAIL: allow(n::clasz::kHighSpeed); break; + case api::ModeEnum::LONG_DISTANCE: allow(n::clasz::kLongDistance); break; + case api::ModeEnum::NIGHT_RAIL: allow(n::clasz::kNight); break; + case api::ModeEnum::REGIONAL_FAST_RAIL: + allow(n::clasz::kRegionalFast); + break; + case api::ModeEnum::REGIONAL_RAIL: allow(n::clasz::kRegional); break; + default: continue; + } + } + return mask; +} + +} // namespace motis \ No newline at end of file