Skip to content

Commit a426b61

Browse files
rt: resolve by route (#286)
* rt: resolve by route * wip
1 parent 53b5f39 commit a426b61

File tree

3 files changed

+133
-55
lines changed

3 files changed

+133
-55
lines changed

include/nigiri/rt/gtfsrt_resolve_run.h

Lines changed: 102 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,60 @@ namespace nigiri::rt {
1717
std::pair<date::days, duration_t> split(duration_t);
1818

1919
template <typename Fn>
20-
void resolve_static(date::sys_days const today,
21-
timetable const& tt,
22-
source_idx_t const src,
23-
transit_realtime::TripDescriptor const& td,
24-
Fn&& fn) {
25-
using loader::gtfs::hhmm_to_min;
26-
using loader::gtfs::parse_date;
20+
void resolve_trip(date::sys_days const today,
21+
timetable const& tt,
22+
trip_idx_t const trip,
23+
std::optional<date::sys_days> const& start_date,
24+
std::optional<duration_t> const& start_time,
25+
Fn&& fn) {
26+
for (auto const [t, stop_range] : tt.trip_transport_ranges_[trip]) {
27+
auto const [first_dep_offset, tz_offset] =
28+
tt.transport_first_dep_offset_[t].to_offset();
29+
auto const utc_dep =
30+
tt.event_mam(t, stop_range.from_, event_type::kDep).as_duration();
31+
auto const gtfs_static_dep = utc_dep + first_dep_offset + tz_offset;
32+
auto const [gtfs_static_dep_day, gtfs_static_dep_time] =
33+
split(gtfs_static_dep);
34+
auto const [start_time_day, start_time_time] =
35+
start_time.has_value() ? split(*start_time)
36+
: std::pair{date::days{0U}, duration_t{0U}};
37+
38+
if (start_time.has_value() && gtfs_static_dep_time != start_time_time) {
39+
continue;
40+
}
41+
42+
auto const start_time_day_offset =
43+
start_time.has_value() ? gtfs_static_dep_day - start_time_day
44+
: date::days{0U};
2745

28-
auto const& trip_id = td.trip_id();
46+
auto const day_idx =
47+
((start_date.has_value() ? *start_date : today) + first_dep_offset -
48+
start_time_day_offset - tt.internal_interval_days().from_)
49+
.count();
50+
51+
if (day_idx > kMaxDays || day_idx < 0) {
52+
continue;
53+
}
54+
55+
auto const& traffic_days = tt.bitfields_[tt.transport_traffic_days_[t]];
56+
if (traffic_days.test(static_cast<std::size_t>(day_idx))) {
57+
auto const r = run{.t_ = transport{t, day_idx_t{day_idx}},
58+
.stop_range_ = stop_range};
59+
if (fn(r, trip) == utl::continue_t::kBreak) {
60+
return;
61+
}
62+
}
63+
}
64+
}
65+
66+
template <typename Fn>
67+
void resolve_static_trip_id(date::sys_days const today,
68+
timetable const& tt,
69+
source_idx_t const src,
70+
std::string const& trip_id,
71+
std::optional<date::sys_days> const& start_date,
72+
std::optional<duration_t> const& start_time,
73+
Fn&& fn) {
2974
auto const lb = std::lower_bound(
3075
begin(tt.trip_id_to_idx_), end(tt.trip_id_to_idx_), trip_id,
3176
[&](pair<trip_id_idx_t, trip_idx_t> const& a, auto&& b) {
@@ -34,58 +79,65 @@ void resolve_static(date::sys_days const today,
3479
std::tuple{src, static_cast<std::string_view>(b)};
3580
});
3681

37-
auto const start_date = td.has_start_date()
38-
? std::make_optional(parse_date(
39-
utl::parse<unsigned>(td.start_date())))
40-
: std::nullopt;
41-
auto const start_time = td.has_start_time()
42-
? std::make_optional(hhmm_to_min(td.start_time()))
43-
: std::nullopt;
44-
4582
auto const id_matches = [&](trip_id_idx_t const t_id_idx) {
4683
return tt.trip_id_src_[t_id_idx] == src &&
4784
tt.trip_id_strings_[t_id_idx].view() == trip_id;
4885
};
4986

5087
for (auto i = lb; i != end(tt.trip_id_to_idx_) && id_matches(i->first); ++i) {
51-
for (auto const [t, stop_range] : tt.trip_transport_ranges_[i->second]) {
52-
auto const [first_dep_offset, tz_offset] =
53-
tt.transport_first_dep_offset_[t].to_offset();
54-
auto const utc_dep =
55-
tt.event_mam(t, stop_range.from_, event_type::kDep).as_duration();
56-
auto const gtfs_static_dep = utc_dep + first_dep_offset + tz_offset;
57-
auto const [gtfs_static_dep_day, gtfs_static_dep_time] =
58-
split(gtfs_static_dep);
59-
auto const [start_time_day, start_time_time] =
60-
start_time.has_value() ? split(*start_time)
61-
: std::pair{date::days{0U}, duration_t{0U}};
62-
63-
if (start_time.has_value() && gtfs_static_dep_time != start_time_time) {
64-
continue;
65-
}
88+
resolve_trip(today, tt, i->second, start_date, start_time, fn);
89+
}
90+
}
6691

67-
auto const start_time_day_offset =
68-
start_time.has_value() ? gtfs_static_dep_day - start_time_day
69-
: date::days{0U};
92+
template <typename Fn>
93+
void resolve_static_route(date::sys_days const today,
94+
timetable const& tt,
95+
source_idx_t const src,
96+
std::string const& route_id,
97+
direction_id_t const direction,
98+
date::sys_days const start_date,
99+
duration_t const start_time,
100+
Fn&& fn) {
101+
auto const route = tt.route_ids_[src].ids_.find(route_id);
102+
if (!route.has_value()) {
103+
return;
104+
}
70105

71-
auto const day_idx =
72-
((start_date.has_value() ? *start_date : today) + first_dep_offset -
73-
start_time_day_offset - tt.internal_interval_days().from_)
74-
.count();
106+
for (auto const trip : tt.route_ids_[src].route_id_trips_[*route]) {
107+
if (tt.trip_direction_id_.test(trip) == (direction != 0U)) {
108+
resolve_trip(today, tt, trip, start_date, start_time, fn);
109+
}
110+
}
111+
}
75112

76-
if (day_idx > kMaxDays || day_idx < 0) {
77-
continue;
78-
}
113+
template <typename Fn>
114+
void resolve_static(date::sys_days const today,
115+
timetable const& tt,
116+
source_idx_t const src,
117+
transit_realtime::TripDescriptor const& td,
118+
Fn&& fn) {
119+
using loader::gtfs::hhmm_to_min;
120+
using loader::gtfs::parse_date;
79121

80-
auto const& traffic_days = tt.bitfields_[tt.transport_traffic_days_[t]];
81-
if (traffic_days.test(static_cast<std::size_t>(day_idx))) {
82-
auto const r = run{.t_ = transport{t, day_idx_t{day_idx}},
83-
.stop_range_ = stop_range};
84-
if (fn(r, i->second) == utl::continue_t::kBreak) {
85-
return;
86-
}
87-
}
88-
}
122+
auto const start_date = td.has_start_date()
123+
? std::make_optional(parse_date(
124+
utl::parse<unsigned>(td.start_date())))
125+
: std::nullopt;
126+
auto const start_time = td.has_start_time()
127+
? std::make_optional(hhmm_to_min(td.start_time()))
128+
: std::nullopt;
129+
130+
if (td.has_trip_id()) {
131+
resolve_static_trip_id(today, tt, src, td.trip_id(), start_date, start_time,
132+
std::forward<Fn>(fn));
133+
} else {
134+
utl_verify(td.has_route_id() && td.has_direction_id() &&
135+
start_time.has_value() && start_date.has_value(),
136+
"bad trip descriptor {}", td.DebugString());
137+
resolve_static_route(
138+
today, tt, src, td.route_id(),
139+
td.direction_id() == 0U ? direction_id_t{0U} : direction_id_t{1U},
140+
start_date.value(), start_time.value(), std::forward<Fn>(fn));
89141
}
90142
}
91143

src/rt/gtfsrt_update.cc

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -676,8 +676,8 @@ statistics gtfsrt_update_msg(timetable const& tt,
676676

677677
if (!entity.has_trip_update()) {
678678
log(log_lvl::error, "rt.gtfs.unsupported",
679-
R"(unsupported: no "trip_update" field (tag={}, id={}), skipping message)",
680-
tag, entity.id());
679+
R"(unsupported: no "trip_update" field (tag={}, id={}, vehicle={}), skipping message)",
680+
tag, entity.id(), entity.has_vehicle());
681681
++stats.no_trip_update_;
682682
continue;
683683
}
@@ -690,10 +690,21 @@ statistics gtfsrt_update_msg(timetable const& tt,
690690
continue;
691691
}
692692

693-
if (!entity.trip_update().trip().has_trip_id()) {
693+
if (!entity.trip_update().trip().has_trip_id() &&
694+
!(entity.trip_update().trip().has_schedule_relationship() &&
695+
(entity.trip_update().trip().schedule_relationship() ==
696+
transit_realtime::
697+
TripDescriptor_ScheduleRelationship_SCHEDULED ||
698+
entity.trip_update().trip().schedule_relationship() ==
699+
transit_realtime::
700+
TripDescriptor_ScheduleRelationship_CANCELED) &&
701+
entity.trip_update().trip().has_start_date() &&
702+
entity.trip_update().trip().has_start_time() &&
703+
entity.trip_update().trip().has_route_id() &&
704+
entity.trip_update().trip().has_direction_id())) {
694705
log(log_lvl::error, "rt.gtfs.unsupported",
695-
R"(unsupported: no "trip_id" field in "trip_update.trip" (tag={}, id={}), skipping message)",
696-
tag, entity.id());
706+
R"(unsupported: no "trip_id" field in "trip_update.trip" (tag={}, td={}), skipping message)",
707+
tag, entity.trip_update().trip().DebugString());
697708
++stats.unsupported_no_trip_id_;
698709
continue;
699710
}

test/rt/gtfsrt_resolve_trip_test.cc

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,21 @@ TEST(rt, gtfsrt_resolve_static_trip) {
115115
tt, &rtt, source_idx_t{0}, td);
116116
ASSERT_TRUE(r.valid());
117117
}
118+
119+
{ // test with route_id + start_date + start_time + direction_id
120+
auto td = transit_realtime::TripDescriptor();
121+
*td.mutable_start_time() = "00:30:00";
122+
*td.mutable_start_date() = "20190504";
123+
*td.mutable_route_id() = "R_RE2";
124+
td.set_schedule_relationship(
125+
transit_realtime::TripDescriptor_ScheduleRelationship_SCHEDULED);
126+
td.set_direction_id(0);
127+
// *td.mutable_trip_id() = "T_RE2";
128+
129+
auto const [r, t] = rt::gtfsrt_resolve_run(date::sys_days{2019_y / May / 4},
130+
tt, &rtt, source_idx_t{0}, td);
131+
ASSERT_TRUE(r.valid());
132+
}
118133
}
119134

120135
mem_dir miami_test_files() {

0 commit comments

Comments
 (0)