diff --git a/.pkg b/.pkg index 1ba232325..abe108946 100644 --- a/.pkg +++ b/.pkg @@ -17,7 +17,7 @@ [adr] url=git@github.com:triptix-tech/adr.git branch=master - commit=bd3bb6bb8f1b5c0e066acd975767df27d5de22f8 + commit=28365ed6b64b804296a09cb19cf8527247687f04 [googletest] url=git@github.com:motis-project/googletest.git branch=master diff --git a/.pkg.lock b/.pkg.lock index 2e42d6894..a28854c7c 100644 --- a/.pkg.lock +++ b/.pkg.lock @@ -1,4 +1,4 @@ -5061172279391244024 +18178785441693657313 cista 847b27100b7e730370b810ce62206a66b0bf2d79 zlib-ng 68ab3e2d80253ec5dc3c83691d9ff70477b32cd3 boost 930f38eb0365ceb7853273e03da4d9e7787abfb9 @@ -46,5 +46,5 @@ reflect-cpp c54fe66de4650b60c23aadd4a06d9db4ffeda22f FTXUI dd6a5d371fd7a3e2937bb579955003c54b727233 tg 20c0f298b8ce58de29a790290f44dca7c4ecc364 utf8proc 779b780da3b99d123133eb99707b65c7e4324cc8 -adr bd3bb6bb8f1b5c0e066acd975767df27d5de22f8 +adr 28365ed6b64b804296a09cb19cf8527247687f04 openapi-cpp 6b5fd40a2b552fc5656aeff56f203a34c1d9e9af diff --git a/include/motis/adr_extend_tt.h b/include/motis/adr_extend_tt.h index 0011e3326..e8cafa4e2 100644 --- a/include/motis/adr_extend_tt.h +++ b/include/motis/adr_extend_tt.h @@ -5,7 +5,7 @@ namespace motis { void adr_extend_tt(nigiri::timetable const&, - adr::area_database const&, + adr::area_database const*, adr::typeahead&); } // namespace motis \ No newline at end of file diff --git a/include/motis/parse_location.h b/include/motis/parse_location.h index 6c254bac4..d927a6fec 100644 --- a/include/motis/parse_location.h +++ b/include/motis/parse_location.h @@ -14,9 +14,6 @@ namespace motis { std::optional parse_location(std::string_view, char separator = ','); -nigiri::unixtime_t get_date_time(std::optional const& date = {}, - std::optional const& time = {}); - date::sys_days parse_iso_date(std::string_view); nigiri::routing::query cursor_to_query(std::string_view); diff --git a/include/motis/street_routing.h b/include/motis/street_routing.h index 9926d7697..b59e5ec27 100644 --- a/include/motis/street_routing.h +++ b/include/motis/street_routing.h @@ -19,6 +19,12 @@ using street_routing_cache_key_t = std:: using street_routing_cache_t = hash_map>; +api::Itinerary dummy_itinerary(api::Place const& from, + api::Place const& to, + api::ModeEnum, + nigiri::unixtime_t const start_time, + nigiri::unixtime_t const end_time); + api::Itinerary route(osr::ways const&, osr::lookup const&, gbfs::gbfs_data const*, diff --git a/src/adr_extend_tt.cc b/src/adr_extend_tt.cc index 24cd3e64a..920202ddb 100644 --- a/src/adr_extend_tt.cc +++ b/src/adr_extend_tt.cc @@ -20,7 +20,7 @@ constexpr auto const kClaszMax = static_cast>(n::kNumClasses); void adr_extend_tt(nigiri::timetable const& tt, - a::area_database const& area_db, + a::area_database const* area_db, a::typeahead& t) { if (tt.n_locations() == 0) { return; @@ -127,6 +127,10 @@ void adr_extend_tt(nigiri::timetable const& tt, // Add to typeahead. auto areas = std::basic_string{}; + auto no_areas_idx = adr::area_set_idx_t{t.area_sets_.size()}; + if (area_db == nullptr) { + t.area_sets_.emplace_back(areas); + } for (auto const [prio, l] : utl::zip(importance, place_location)) { auto const str_idx = a::string_idx_t{t.strings_.size()}; auto const place_idx = a::place_idx_t{t.place_names_.size()}; @@ -147,14 +151,18 @@ void adr_extend_tt(nigiri::timetable const& tt, t.string_to_type_.emplace_back( std::initializer_list{a::location_type_t::kPlace}); - area_db.lookup( - t, a::coordinates::from_latlng(tt.locations_.coordinates_[l]), areas); - t.place_areas_.emplace_back( - utl::get_or_create(area_set_lookup, areas, [&]() { - auto const set_idx = a::area_set_idx_t{t.area_sets_.size()}; - t.area_sets_.emplace_back(areas); - return set_idx; - })); + if (area_db == nullptr) { + t.place_areas_.emplace_back(no_areas_idx); + } else { + area_db->lookup( + t, a::coordinates::from_latlng(tt.locations_.coordinates_[l]), areas); + t.place_areas_.emplace_back( + utl::get_or_create(area_set_lookup, areas, [&]() { + auto const set_idx = a::area_set_idx_t{t.area_sets_.size()}; + t.area_sets_.emplace_back(areas); + return set_idx; + })); + } } t.build_ngram_index(); diff --git a/src/config.cc b/src/config.cc index ccb6650e5..443de5b37 100644 --- a/src/config.cc +++ b/src/config.cc @@ -96,11 +96,6 @@ config config::read(std::string const& s) { } void config::verify() const { - utl::verify(!geocoding_ || osm_, - "feature GEOCODING requires OpenStreetMap data"); - utl::verify(!reverse_geocoding_ || (geocoding_ && osm_), - "feature REVERSE_GEOCODING requires OpenStreetMap data and " - "feature GEOCODING"); utl::verify(!tiles_ || osm_, "feature TILES requires OpenStreetMap data"); utl::verify(!street_routing_ || osm_, "feature STREET_ROUTING requires OpenStreetMap data"); diff --git a/src/endpoints/routing.cc b/src/endpoints/routing.cc index f964fd4b2..5edc0f516 100644 --- a/src/endpoints/routing.cc +++ b/src/endpoints/routing.cc @@ -381,7 +381,7 @@ api::plan_response routing::operator()(boost::urls::url_view const& url) const { UTL_START_TIMING(direct); auto const [direct, fastest_direct] = - t.has_value() && !direct_modes.empty() + t.has_value() && !direct_modes.empty() && w_ && l_ ? route_direct(e, gbfs.get(), from_p, to_p, direct_modes, *t, query.wheelchair_, std::chrono::seconds{query.maxDirectTime_}) diff --git a/src/import.cc b/src/import.cc index e10e37637..6599a87f5 100644 --- a/src/import.cc +++ b/src/import.cc @@ -40,6 +40,7 @@ #include "osr/ways.h" #include "adr/adr.h" +#include "adr/area_database.h" #include "adr/reverse.h" #include "adr/typeahead.h" @@ -185,6 +186,10 @@ data import(config const& c, fs::path const& data_path, bool const write) { [&]() { return c.geocoding_ || c.reverse_geocoding_; }, []() { return true; }, [&]() { + if (!c.osm_) { + return; + } + adr::extract(*c.osm_, data_path / "adr", data_path / "adr"); // We can't use d.load_geocoder() here because @@ -198,6 +203,10 @@ data import(config const& c, fs::path const& data_path, bool const write) { } }, [&]() { + if (!c.osm_) { + return; + } + // Same here, need to load base-line version for adr_extend! d.t_ = adr::read(data_path / "adr" / "t.bin"); d.tc_ = std::make_unique(d.t_->strings_.size(), 100U); @@ -298,48 +307,58 @@ data import(config const& c, fs::path const& data_path, bool const write) { }, {tt_hash, n_version()}}; - auto adr_extend = - task{"adr_extend", - [&]() { return c.geocoding_ && c.timetable_.has_value(); }, - [&]() { return d.tt_ && d.t_; }, - [&]() { - auto const area_db = adr::area_database{ - data_path / "adr", cista::mmap::protection::READ}; - adr_extend_tt(*d.tt_, area_db, *d.t_); - if (write) { - cista::write(data_path / "adr" / "t_ext.bin", *d.t_); - } - d.r_.reset(); - { - auto r = adr::reverse{data_path / "adr", - cista::mmap::protection::WRITE}; - r.build_rtree(*d.t_); - r.write(); - } - d.t_.reset(); - if (c.geocoding_) { - d.load_geocoder(); - } - if (c.reverse_geocoding_) { - d.load_reverse_geocoder(); - } - }, - [&]() { - d.t_.reset(); - d.r_.reset(); - if (c.geocoding_) { - d.load_geocoder(); - } - if (c.reverse_geocoding_) { - d.load_reverse_geocoder(); - } - }, - {tt_hash, - osm_hash, - adr_version(), - n_version(), - {"geocoding", c.geocoding_}, - {"reverse_geocoding", c.reverse_geocoding_}}}; + auto adr_extend = task{ + "adr_extend", + [&]() { return c.timetable_.has_value(); }, + [&]() { return d.tt_.get() != nullptr; }, + [&]() { + auto const area_db = d.t_ ? (std::optional{ + std::in_place, data_path / "adr", + cista::mmap::protection::READ}) + : std::nullopt; + if (!d.t_) { + d.t_ = cista::wrapped{ + cista::raw::make_unique()}; + } + adr_extend_tt(*d.tt_, area_db.has_value() ? &*area_db : nullptr, *d.t_); + if (write) { + cista::write(data_path / "adr" / "t_ext.bin", *d.t_); + } + d.r_.reset(); + { + auto r = + adr::reverse{data_path / "adr", cista::mmap::protection::WRITE}; + r.build_rtree(*d.t_); + r.write(); + } + d.t_.reset(); + if (c.geocoding_) { + d.load_geocoder(); + } + if (c.reverse_geocoding_) { + d.load_reverse_geocoder(); + } + }, + [&]() { + if (d.t_) { + d.t_.reset(); + } + if (d.r_) { + d.r_.reset(); + } + if (c.geocoding_) { + d.load_geocoder(); + } + if (c.reverse_geocoding_) { + d.load_reverse_geocoder(); + } + }, + {tt_hash, + osm_hash, + adr_version(), + n_version(), + {"geocoding", c.geocoding_}, + {"reverse_geocoding", c.reverse_geocoding_}}}; auto osr_footpath = task{ "osr_footpath", diff --git a/src/journey_to_response.cc b/src/journey_to_response.cc index 36080dcdd..867b34968 100644 --- a/src/journey_to_response.cc +++ b/src/journey_to_response.cc @@ -159,10 +159,13 @@ api::Itinerary journey_to_response(osr::ways const* w, } }, [&](n::footpath) { - append(route(*w, *l, gbfs, e, from, to, api::ModeEnum::WALK, - wheelchair, j_leg.dep_time_, j_leg.arr_time_, - gbfs_provider_idx_t::invalid(), cache, blocked_mem, - std::chrono::seconds{900})); + append(w && l + ? route(*w, *l, gbfs, e, from, to, api::ModeEnum::WALK, + wheelchair, j_leg.dep_time_, j_leg.arr_time_, + gbfs_provider_idx_t::invalid(), cache, + blocked_mem, std::chrono::seconds{900}) + : dummy_itinerary(from, to, api::ModeEnum::WALK, + j_leg.dep_time_, j_leg.arr_time_)); }, [&](n::routing::offset const x) { append(route( diff --git a/src/parse_location.cc b/src/parse_location.cc index 120c5461d..eee4f988f 100644 --- a/src/parse_location.cc +++ b/src/parse_location.cc @@ -42,32 +42,6 @@ std::optional parse_location(std::string_view s, return osr::location{pos, osr::level_t{level}}; } -n::unixtime_t get_date_time(std::optional const& date, - std::optional const& time) { - if (!date.has_value()) { - utl::verify(!time.has_value(), "time without date no supported"); - return std::chrono::time_point_cast( - std::chrono::system_clock::now()); - } else { - utl::verify(time.has_value(), "date without time not supported"); - auto const date_time = *date + " " + *time; - - // 06-28-2024 7:06pm - // 06-28-2024 19:06 - std::stringstream ss; - ss << date_time; - - auto t = n::unixtime_t{}; - if (date_time.contains("AM") || date_time.contains("PM")) { - ss >> date::parse("%m-%d-%Y %I:%M %p", t); - } else { - ss >> date::parse("%m-%d-%Y %H:%M", t); - } - - return t; - } -} - date::sys_days parse_iso_date(std::string_view s) { auto d = date::sys_days{}; (std::stringstream{} << s) >> date::parse("%F", d); diff --git a/src/street_routing.cc b/src/street_routing.cc index 8dedf3ff4..ed320911e 100644 --- a/src/street_routing.cc +++ b/src/street_routing.cc @@ -176,6 +176,31 @@ struct sharing { }; }; +api::Itinerary dummy_itinerary(api::Place const& from, + api::Place const& to, + api::ModeEnum const mode, + n::unixtime_t const start_time, + n::unixtime_t const end_time) { + auto itinerary = api::Itinerary{ + .duration_ = std::chrono::duration_cast(end_time - + start_time) + .count(), + .startTime_ = start_time, + .endTime_ = end_time}; + auto& leg = itinerary.legs_.emplace_back(api::Leg{ + .mode_ = mode, + .from_ = from, + .to_ = to, + .duration_ = std::chrono::duration_cast(end_time - + start_time) + .count(), + .startTime_ = start_time, + .endTime_ = end_time}); + leg.from_.departure_ = leg.startTime_; + leg.to_.arrival_ = leg.endTime_; + return itinerary; +} + api::Itinerary route(osr::ways const& w, osr::lookup const& l, gbfs::gbfs_data const* gbfs, @@ -239,27 +264,9 @@ api::Itinerary route(osr::ways const& w, if (!end_time.has_value()) { return {}; } - std::cout << "ROUTING\n FROM: " << from << " \n TO: " << to << "\n -> CREATING DUMMY LEG\n"; - auto itinerary = api::Itinerary{ - .duration_ = std::chrono::duration_cast( - *end_time - start_time) - .count(), - .startTime_ = start_time, - .endTime_ = *end_time}; - auto& leg = itinerary.legs_.emplace_back( - api::Leg{.mode_ = mode, - .from_ = from, - .to_ = to, - .duration_ = std::chrono::duration_cast( - *end_time - start_time) - .count(), - .startTime_ = start_time, - .endTime_ = *end_time}); - leg.from_.departure_ = leg.startTime_; - leg.to_.arrival_ = leg.endTime_; - return itinerary; + return dummy_itinerary(from, to, mode, start_time, *end_time); } auto itinerary = api::Itinerary{ diff --git a/test/read_test.cc b/test/read_test.cc index 7333a7d73..f1d75fe7a 100644 --- a/test/read_test.cc +++ b/test/read_test.cc @@ -20,11 +20,6 @@ TEST(motis, parse_location_no_level) { EXPECT_EQ((osr::location{{-23.1, 45.2}, osr::level_t{0.F}}), *parsed); } -TEST(motis, parse_date_time) { - auto const t = get_date_time("06-28-2024", "7:06 PM"); - EXPECT_EQ(sys_days{2024_y / June / 28} + 19h + 6min, t); -} - TEST(motis, parse_cursor_earlier) { auto const q = cursor_to_query("EARLIER|1720036560"); diff --git a/ui/src/lib/AddressTypeahead.svelte b/ui/src/lib/AddressTypeahead.svelte index 53489ebd7..1911bf0d5 100644 --- a/ui/src/lib/AddressTypeahead.svelte +++ b/ui/src/lib/AddressTypeahead.svelte @@ -65,11 +65,14 @@ return; } - items = ( - await geocode({ - query: { text: inputValue, language } - }) - ).data.map((match: Match): Location => { + const { data: matches, error } = await geocode({ + query: { text: inputValue, language } + }); + if (error) { + console.error('TYPEAHEAD ERROR: ', error); + return; + } + items = matches!.map((match: Match): Location => { return { label: getLabel(match), value: { match, precision: GEOCODER_PRECISION } diff --git a/ui/src/routes/+page.svelte b/ui/src/routes/+page.svelte index 8f0a35e90..b56f08734 100644 --- a/ui/src/routes/+page.svelte +++ b/ui/src/routes/+page.svelte @@ -164,11 +164,14 @@ let stopArriveBy = $state(); let selectedStop = $state<{ name: string; stopId: string; time: Date }>(); - const onClickTrip = (tripId: string) => { - trip({ query: { tripId } }).then((r) => { - selectedItinerary = r.data; - selectedStop = undefined; - }); + const onClickTrip = async (tripId: string) => { + const { data: itinerary, error } = await trip({ query: { tripId } }); + if (error) { + alert(error); + return; + } + selectedItinerary = itinerary; + selectedStop = undefined; }; type CloseFn = () => void; diff --git a/ui/src/routes/RailViz.svelte b/ui/src/routes/RailViz.svelte index 22e1236ea..ea7dc8b63 100644 --- a/ui/src/routes/RailViz.svelte +++ b/ui/src/routes/RailViz.svelte @@ -186,7 +186,6 @@ }); }; - let railvizError = $state(); const railvizRequest = () => { const b = maplibregl.LngLatBounds.convert(bounds!); const min = lngLatToStr(b.getNorthWest()); @@ -204,19 +203,22 @@ }); }; + let railvizError = $state(); let animation: number | null = null; const updateRailvizLayer = async () => { try { - const { data, error } = await railvizRequest(); + const { data, error, response } = await railvizRequest(); if (animation) { cancelAnimationFrame(animation); } if (error) { - railvizError = error; + railvizError = `map trips error status ${response.status}`; return; } + railvizError = undefined; + const tripSegmentsWithKeyFrames = data!.map((tripSegment: TripSegment) => { return { ...tripSegment, ...getKeyFrames(tripSegment) }; });