Skip to content
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

skip no in+out stops, add mode+direction parameters to stoptimes api #656

Merged
merged 1 commit into from
Nov 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions include/motis/endpoints/routing.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
11 changes: 11 additions & 0 deletions include/motis/timetable/modes_to_clasz_mask.h
Original file line number Diff line number Diff line change
@@ -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<api::ModeEnum> const&);

}
32 changes: 32 additions & 0 deletions openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
39 changes: 1 addition & 38 deletions src/endpoints/routing.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -199,44 +200,6 @@ std::vector<n::routing::offset> routing::get_offsets(
return offsets;
}

n::routing::clasz_mask_t to_clasz_mask(std::vector<api::ModeEnum> const& mode) {
auto mask = n::routing::clasz_mask_t{0U};
auto const allow = [&](n::clasz const c) {
mask |= (1U << static_cast<std::underlying_type_t<n::clasz>>(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<n::routing::query, std::optional<n::unixtime_t>> get_start_time(
api::plan_params const& query) {
if (query.pageCursor_.has_value()) {
Expand Down
38 changes: 26 additions & 12 deletions src/endpoints/stop_times.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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;
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -198,7 +202,8 @@ std::vector<n::rt::run> 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<std::unique_ptr<ev_iterator>>{};

if (rtt != nullptr) {
Expand All @@ -214,7 +219,7 @@ std::vector<n::rt::run> get_events(
n::stop{s}.out_allowed()))) {
iterators.emplace_back(std::make_unique<rt_ev_iterator>(
*rtt, rt_t, static_cast<n::stop_idx_t>(stop_idx), time, ev_type,
dir));
dir, allowed_clasz));
}
}
}
Expand All @@ -224,6 +229,9 @@ std::vector<n::rt::run> get_events(
auto seen = n::hash_set<std::pair<n::route_idx_t, n::stop_idx_t>>{};
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 &&
Expand Down Expand Up @@ -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<std::chrono::seconds>(
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<std::chrono::seconds>(
query.time_.value_or(openapi::now())->time_since_epoch())
.count())));

auto locations = std::vector{l};
auto const add = [&](n::location_idx_t const l) {
Expand Down Expand Up @@ -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<std::size_t>(query.n_));
static_cast<std::size_t>(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};
Expand Down
3 changes: 3 additions & 0 deletions src/journey_to_response.cc
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,9 @@ api::Itinerary journey_to_response(osr::ways const* w,
leg.intermediateStops_ = std::vector<api::Place>{};
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);
Expand Down
45 changes: 45 additions & 0 deletions src/timetable/modes_to_clasz_mask.cc
Original file line number Diff line number Diff line change
@@ -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<api::ModeEnum> const& mode) {
auto mask = n::routing::clasz_mask_t{0U};
auto const allow = [&](n::clasz const c) {
mask |= (1U << static_cast<std::underlying_type_t<n::clasz>>(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