Skip to content

Commit 325771e

Browse files
wip
1 parent 6e5e92b commit 325771e

File tree

2 files changed

+140
-47
lines changed

2 files changed

+140
-47
lines changed

src/loader/netex/load_timetable.cc

Lines changed: 139 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,12 @@
2020
#include "pugixml.hpp"
2121

2222
#include "nigiri/loader/gtfs/route_key.h"
23+
#include "nigiri/loader/gtfs/shape.h"
24+
#include "nigiri/loader/gtfs/shape_prepare.h"
2325
#include "nigiri/loader/gtfs/trip.h"
2426
#include "nigiri/loader/loader_interface.h"
2527
#include "nigiri/logging.h"
28+
#include "nigiri/shapes_storage.h"
2629
#include "nigiri/timetable.h"
2730

2831
#include "utl/progress_tracker.h"
@@ -85,6 +88,12 @@ std::string_view id(pugi::xml_node n) {
8588
return str == nullptr ? std::string_view{} : std::string_view{str};
8689
}
8790

91+
geo::latlng get_pos(pugi::xml_node const x) {
92+
auto const loc = x.child("Location");
93+
return geo::latlng{utl::parse<double>(val(loc, "Latitude")),
94+
utl::parse<double>(val(loc, "Longitude"))};
95+
}
96+
8897
std::uint16_t get_route_type(std::string_view transport_mode,
8998
std::string_view rail_sub_mode) {
9099
switch (cista::hash(transport_mode)) {
@@ -236,6 +245,8 @@ using destination_display_map_t =
236245
destination_display_map_t get_destination_displays(
237246
pugi::xml_document const& doc) {
238247
auto destination_displays = destination_display_map_t{};
248+
destination_displays.emplace(std::string_view{},
249+
uniq(destination_display{.direction_ = ""}));
239250
for (auto const display : doc.select_nodes(
240251
"//ServiceFrame/destinationDisplays/DestinationDisplay")) {
241252
auto const n = display.node();
@@ -270,15 +281,6 @@ stop_map_t get_stops(pugi::xml_document const& doc) {
270281
"Value");
271282
};
272283

273-
auto const get_pos = [](pugi::xml_node const x) {
274-
return geo::latlng{
275-
utl::parse<double>(
276-
x.select_node("Centroid/Location/Latitude").node().child_value()),
277-
utl::parse<double>(x.select_node("Centroid/Location/Longitude")
278-
.node()
279-
.child_value())};
280-
};
281-
282284
auto const stop_id = id(n);
283285
auto const global_stop_id = get_global_id(n);
284286
auto const parent =
@@ -287,7 +289,7 @@ stop_map_t get_stops(pugi::xml_document const& doc) {
287289
uniq(stop{.id_ = !global_stop_id.empty() ? global_stop_id
288290
: stop_id,
289291
.name_ = val(n, "Name"),
290-
.pos_ = get_pos(n)}))
292+
.pos_ = get_pos(n.child("Centroid"))}))
291293
.first->second.get();
292294

293295
for (auto const q : n.select_nodes("quays/Quay")) {
@@ -299,7 +301,7 @@ stop_map_t get_stops(pugi::xml_document const& doc) {
299301
uniq(stop{.parent_ = parent,
300302
.id_ = !global_quay_id.empty() ? global_quay_id : quay_id,
301303
.name_ = val(qn, "Name"),
302-
.pos_ = get_pos(qn)}));
304+
.pos_ = get_pos(qn.child("Centroid"))}));
303305
}
304306
}
305307
return stops;
@@ -384,17 +386,8 @@ day_type_assignment_map_t get_day_type_assignments(
384386
"//ServiceCalendarFrame/ServiceCalendar/dayTypeAssignments/"
385387
"DayTypeAssignment")) {
386388
auto const n = x.node();
387-
auto const op_period = ref(n, "OperatingPeriodRef");
388-
auto const day_type = ref(n, "DayTypeRef");
389-
390-
auto const it = operating_periods.find(op_period);
391-
if (it == end(operating_periods)) {
392-
log(log_lvl::error, "netex.DayTypeAssignment",
393-
"OperatingPeriodRef=\"{}\" not found", op_period);
394-
continue;
395-
}
396-
397-
days.emplace(day_type, it->second.get());
389+
days.emplace(ref(n, "DayTypeRef"),
390+
operating_periods.at(ref(n, "OperatingPeriodRef")).get());
398391
}
399392
return days;
400393
}
@@ -422,9 +415,33 @@ journey_pattern_map_t get_journey_patterns(
422415
pugi::xml_document const& doc,
423416
stop_assignment_map_t const& stop_assignments,
424417
destination_display_map_t const& destination_displays,
425-
line_map_t const& lines) {
426-
418+
line_map_t const& lines,
419+
stop_map_t& stops) {
427420
auto journey_patterns = journey_pattern_map_t{};
421+
422+
auto const get_stop =
423+
[&](std::string_view stop_point_ref) -> netex::stop const* {
424+
auto const it = stop_assignments.find(stop_point_ref);
425+
if (it != end(stop_assignments)) {
426+
return it->second;
427+
}
428+
429+
// Invalid - fall back to information from ScheduledStopPoint
430+
return utl::get_or_create(
431+
stops, stop_point_ref,
432+
[&]() {
433+
auto const stop_point = doc.select_node(
434+
fmt::format("//ServiceFrame/scheduledStopPoints/"
435+
"ScheduledStopPoint[id='{}']",
436+
stop_point_ref)
437+
.c_str());
438+
return uniq(stop{.id_ = stop_point_ref,
439+
.name_ = val(stop_point.node(), "Name"),
440+
.pos_ = get_pos(stop_point.node())});
441+
})
442+
.get();
443+
};
444+
428445
for (auto const j : doc.select_nodes(
429446
"//ServiceFrame/journeyPatterns/ServiceJourneyPattern")) {
430447
auto const n = j.node();
@@ -435,7 +452,7 @@ journey_pattern_map_t get_journey_patterns(
435452
auto const out = val(sp, "ForAlighting");
436453
stop_points.push_back(journey_pattern::stop_point{
437454
.id_ = id(sp),
438-
.stop_ = stop_assignments.at(ref(sp, "ScheduledStopPointRef")),
455+
.stop_ = get_stop(ref(sp, "ScheduledStopPointRef")),
439456
.destination_display_ =
440457
destination_displays.at(ref(sp, "DestinationDisplayRef")).get(),
441458
.in_allowed_ = in.empty() || in == "true"sv,
@@ -594,27 +611,27 @@ cista::hash_t hash(dir const& d) {
594611
}
595612

596613
auto h = std::uint64_t{0U};
597-
auto const hash_file = [&](fs::path const& p) {
598-
if (!d.exists(p)) {
599-
h = wyhash64(h, _wyp[0]);
600-
} else {
601-
auto const f = d.get_file(p);
602-
auto const data = f.data();
603-
h = wyhash(data.data(), data.size(), h, _wyp);
604-
}
605-
};
606-
607-
for (auto const& f : d.list_files("/")) {
608-
if (is_xml_file(f)) {
609-
hash_file(f);
610-
}
611-
}
614+
// auto const hash_file = [&](fs::path const& p) {
615+
// if (!d.exists(p)) {
616+
// h = wyhash64(h, _wyp[0]);
617+
// } else {
618+
// auto const f = d.get_file(p);
619+
// auto const data = f.data();
620+
// h = wyhash(data.data(), data.size(), h, _wyp);
621+
// }
622+
// };
623+
//
624+
// for (auto const& f : d.list_files("/")) {
625+
// if (is_xml_file(f)) {
626+
// hash_file(f);
627+
// }
628+
// }
612629

613630
return h;
614631
}
615632

616633
bool applicable(dir const& d) {
617-
return utl::any_of(d.list_files("/"), is_xml_file);
634+
return utl::any_of(d.list_files("."), is_xml_file);
618635
}
619636

620637
void load_timetable(loader_config const& config,
@@ -623,16 +640,18 @@ void load_timetable(loader_config const& config,
623640
timetable& tt,
624641
hash_map<bitfield, bitfield_idx_t>& bitfield_indices,
625642
assistance_times* /*assistance*/,
626-
shapes_storage* /*shapes_data*/) {
643+
shapes_storage* shapes_data) {
627644
auto const global_timer = nigiri::scoped_timer{"netex parser"};
628645

646+
auto const locations_start = location_idx_t{tt.n_locations()};
647+
629648
tt.n_sources_ = std::max(tt.n_sources_, to_idx(src + 1U));
630649
tt.fares_.emplace_back();
631650
tt.src_end_date_.push_back(date::sys_days::max());
632651
tt.route_ids_.emplace_back();
633652

634653
auto const xml_files =
635-
utl::all(d.list_files("")) //
654+
utl::all(d.list_files(".")) //
636655
| utl::remove_if([&](fs::path const& f) { return !is_xml_file(f); }) //
637656
| utl::vec();
638657

@@ -693,7 +712,7 @@ void load_timetable(loader_config const& config,
693712
[&](fs::path const& path) {
694713
auto im = intermediate{};
695714

696-
{
715+
try {
697716
auto f = d.get_file(path);
698717
auto doc = pugi::xml_document{};
699718
auto const result =
@@ -715,16 +734,19 @@ void load_timetable(loader_config const& config,
715734
im.stops_ = get_stops(doc);
716735
im.lines_ = get_lines(doc, im.authorities_);
717736
im.destination_displays_ = get_destination_displays(doc);
718-
im.journey_patterns_ =
719-
get_journey_patterns(doc, get_stop_assignments(doc, im.stops_),
720-
im.destination_displays_, im.lines_);
737+
im.journey_patterns_ = get_journey_patterns(
738+
doc, get_stop_assignments(doc, im.stops_),
739+
im.destination_displays_, im.lines_, im.stops_);
721740
im.operating_periods_ =
722741
get_operating_periods(doc, tt.internal_interval_days());
723742
im.service_journeys_ = get_service_journeys(
724743
doc, get_day_type_assignments(doc, im.operating_periods_),
725744
im.journey_patterns_);
726745
im.f_ = std::move(f);
727746
im.doc_ = std::move(doc);
747+
} catch (std::exception const& e) {
748+
std::cout << "ERROR: " << e.what() << " IN " << path << "\n";
749+
return;
728750
}
729751

730752
{
@@ -742,6 +764,13 @@ void load_timetable(loader_config const& config,
742764
}
743765

744766
auto const add_stop = [&](stop* stop) {
767+
auto const existing =
768+
tt.locations_.find(location_id{stop->id_, src});
769+
if (existing.has_value()) {
770+
stop->location_ = existing->l_;
771+
return;
772+
}
773+
745774
auto s = loader::location{stop->id_,
746775
stop->name_,
747776
"",
@@ -835,6 +864,11 @@ void load_timetable(loader_config const& config,
835864
source_file_idx, static_cast<unsigned>(sj.dbg_offset_),
836865
static_cast<unsigned>(sj.dbg_offset_)});
837866
tt.trip_stop_seq_numbers_.add_back_sized(0U);
867+
if (shapes_data != nullptr) {
868+
shapes_data->add_trip_shape_offsets(
869+
trip_idx, cista::pair{shape_idx_t::invalid(),
870+
shape_offset_idx_t::invalid()});
871+
}
838872

839873
auto const c = gtfs::to_clasz(sj.route_type_);
840874
auto const stops = stop_seq(sj);
@@ -956,6 +990,64 @@ void load_timetable(loader_config const& config,
956990
assert(tt.location_routes_.size() == l + 1U);
957991
}
958992
}
993+
994+
// Generate default footpaths.
995+
auto const locations_end = location_idx_t{tt.n_locations()};
996+
auto const new_locations = interval{locations_start, locations_end};
997+
auto const get_location = [&](std::size_t const i) {
998+
return new_locations.from_ + static_cast<unsigned>(i);
999+
};
1000+
auto const get_new_location = [&](location_idx_t const l) {
1001+
return to_idx(l - new_locations.from_);
1002+
};
1003+
1004+
auto const stop_rtree = geo::make_point_rtree(
1005+
new_locations,
1006+
[&](location_idx_t const l) { return tt.locations_.coordinates_[l]; });
1007+
1008+
auto metas = std::vector<std::vector<footpath>>{};
1009+
metas.resize(new_locations.size());
1010+
1011+
utl::parallel_for_run(
1012+
new_locations.size(),
1013+
[&](std::size_t const new_l) {
1014+
auto const l = get_location(new_l);
1015+
auto const pos = tt.locations_.coordinates_[l];
1016+
if (std::abs(pos.lat_) < 2.0 && std::abs(pos.lng_) < 2.0) {
1017+
return;
1018+
}
1019+
auto const dist_lng_degrees = geo::approx_distance_lng_degrees(pos);
1020+
for (auto const& eq :
1021+
stop_rtree.in_radius(pos, config.link_stop_distance_)) {
1022+
auto const neighbor = get_location(eq);
1023+
auto const neighbor_pos = tt.locations_.coordinates_[neighbor];
1024+
auto const dist = std::sqrt(geo::approx_squared_distance(
1025+
pos, neighbor_pos, dist_lng_degrees));
1026+
auto const duration = duration_t{std::max(
1027+
2, static_cast<int>(std::ceil((dist / kWalkSpeed) / 60.0)))};
1028+
metas[get_new_location(l)].emplace_back(neighbor, duration);
1029+
}
1030+
},
1031+
pt->update_fn());
1032+
1033+
for (auto const [i, fps] : utl::enumerate(metas)) {
1034+
auto const from = get_location(i);
1035+
for (auto const fp : fps) {
1036+
tt.locations_.equivalences_[from].emplace_back(fp.target());
1037+
tt.locations_.preprocessing_footpaths_out_[from].emplace_back(fp);
1038+
tt.locations_.preprocessing_footpaths_in_[fp.target()].emplace_back(
1039+
footpath{from, fp.duration()});
1040+
}
1041+
}
1042+
1043+
if (shapes_data != nullptr) {
1044+
auto const trips = vector_map<gtfs::gtfs_trip_idx_t, gtfs::trip>{};
1045+
auto const shape_states = gtfs::shape_loader_state{};
1046+
gtfs::calculate_shape_offsets_and_bboxes(tt, *shapes_data, shape_states,
1047+
trips);
1048+
}
1049+
1050+
tt.location_areas_.resize(tt.n_locations());
9591051
}
9601052

9611053
} // namespace nigiri::loader::netex

src/loader/register.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,7 @@ location_idx_t register_location(timetable& tt, location const& l) {
418418
loc.transfer_time_.emplace_back(l.transfer_time_);
419419
loc.parents_.emplace_back(l.parent_);
420420
} else {
421+
assert(false && "duplicate station");
421422
log(log_lvl::error, "timetable.register_location", "duplicate station {}",
422423
l.id_);
423424
}

0 commit comments

Comments
 (0)