diff --git a/.pkg b/.pkg index 8ba37c3c1e..93b6cf09d4 100644 --- a/.pkg +++ b/.pkg @@ -1,7 +1,7 @@ [nigiri] url=git@github.com:motis-project/nigiri.git branch=master - commit=d09a28b696b0a765d29497c1d1ee827ac0063428 + commit=c12f6827aa5649ec55e8a8caa1688ae3ff14d605 [cista] url=git@github.com:felixguendling/cista.git branch=master @@ -9,7 +9,7 @@ [osr] url=git@github.com:motis-project/osr.git branch=master - commit=34307eb0da3508b12de2b3568c916e9a72e98b6c + commit=9f2d528d3389a1ea5759b5288adb53bd38b37a90 [utl] url=git@github.com:motis-project/utl.git branch=master diff --git a/.pkg.lock b/.pkg.lock index 7bf5896e13..c484a495e7 100644 --- a/.pkg.lock +++ b/.pkg.lock @@ -1,4 +1,4 @@ -9237175939260143388 +4569470289789309275 cista 7bda4b158a87a4db73b5462b6c1821e891295d03 zlib-ng 68ab3e2d80253ec5dc3c83691d9ff70477b32cd3 boost c590212cf9f10badecd5411a8ce11bc1016c74c4 @@ -31,7 +31,7 @@ pugixml 60175e80e2f5e97e027ac78f7e14c5acc009ce50 sol2 40c7cbc7c5cfed1e8c7f1bbe6fcbe23d7a67fc75 unordered_dense 2c7230ae7f9c30849a5b089fb4a5d11896b45dcf wyhash 1e012b57fc2227a9e583a57e2eacb3da99816d99 -nigiri d09a28b696b0a765d29497c1d1ee827ac0063428 +nigiri c12f6827aa5649ec55e8a8caa1688ae3ff14d605 conf f9bf4bd83bf55a2170725707e526cbacc45dcc66 expat 636c9861e8e7c119f3626d1e6c260603ab624516 libosmium 6e6d6b3081cc8bdf25dda89730e25c36eb995516 @@ -45,7 +45,7 @@ pbf-sdf-fonts 66f0c760272c7bdd0efeaac5aab5520b9194225e variant 5aa73631dc969087c77433a5cdef246303051f69 tiles fb8187e7b1ff30f0fffa6e508575b6b1d6c33791 rtree.c 6ed73a7dc4f1184f2b5b2acd8ac1c2b28a273057 -osr 34307eb0da3508b12de2b3568c916e9a72e98b6c +osr 9f2d528d3389a1ea5759b5288adb53bd38b37a90 prometheus-cpp e420cd7cf3995a994220b40a36c987ac8e67c0bf reflect-cpp b1bc07262026260a1a1ae56e9c6503c9c34117a3 FTXUI dd6a5d371fd7a3e2937bb579955003c54b727233 diff --git a/include/motis/compute_footpaths.h b/include/motis/compute_footpaths.h index 1e907b13c4..3582f0e37d 100644 --- a/include/motis/compute_footpaths.h +++ b/include/motis/compute_footpaths.h @@ -14,15 +14,18 @@ using elevator_footpath_map_t = hash_map< osr::node_idx_t, hash_set>>; -struct routed_transfers_settings { +struct transfer_routing_options { osr::search_profile profile_; - nigiri::profile_idx_t profile_idx_; double max_matching_distance_; - bool extend_missing_{false}; + bool extend_missing_; std::chrono::seconds max_duration_; - std::function is_candidate_{}; }; +nigiri::profile_idx_t get_profile_idx(osr::search_profile); + +using transfer_routing_profiles_t = + std::array, nigiri::kNProfiles>; + elevator_footpath_map_t compute_footpaths( osr::ways const&, osr::lookup const&, @@ -30,6 +33,6 @@ elevator_footpath_map_t compute_footpaths( nigiri::timetable&, osr::elevation_storage const*, bool update_coordinates, - std::vector const& settings); + transfer_routing_profiles_t const& settings); } // namespace motis \ No newline at end of file diff --git a/include/motis/config.h b/include/motis/config.h index c9860847f8..50f521b79c 100644 --- a/include/motis/config.h +++ b/include/motis/config.h @@ -14,6 +14,8 @@ #include "utl/verify.h" +#include "motis/compute_footpaths.h" + namespace motis { using headers_t = std::map; @@ -59,6 +61,14 @@ struct config { std::optional tiles_{}; struct timetable { + struct transfer_profile { + bool operator==(transfer_profile const&) const = default; + std::string profile_; + double max_matching_distance_meters_; + unsigned max_duration_seconds_; + bool extend_missing_; + }; + struct dataset { struct rt { bool operator==(rt const&) const = default; @@ -87,6 +97,8 @@ struct config { bool operator==(timetable const&) const = default; + transfer_routing_profiles_t get_profiles() const; + std::string first_day_{"TODAY"}; std::uint16_t num_days_{365U}; bool railviz_{true}; @@ -105,6 +117,7 @@ struct config { double preprocess_max_matching_distance_{0.0}; std::optional default_timezone_{}; std::map datasets_{}; + std::optional> transfer_profiles_{}; std::optional assistance_times_{}; }; std::optional timetable_{}; diff --git a/include/motis/endpoints/routing.h b/include/motis/endpoints/routing.h index f3ac79f728..6c4fccee60 100644 --- a/include/motis/endpoints/routing.h +++ b/include/motis/endpoints/routing.h @@ -63,6 +63,7 @@ struct routing { bool ignore_rental_return_constraints, api::PedestrianProfileEnum, api::ElevationCostsEnum, + bool fastest_bike, std::chrono::seconds max, double max_matching_distance, gbfs::gbfs_routing_data&) const; @@ -94,6 +95,7 @@ struct routing { bool arrive_by, api::PedestrianProfileEnum, api::ElevationCostsEnum, + bool fastest_bike, std::chrono::seconds max, double max_matching_distance, double fastest_direct_factor, diff --git a/include/motis/journey_to_response.h b/include/motis/journey_to_response.h index beb7f633ea..8ced115d14 100644 --- a/include/motis/journey_to_response.h +++ b/include/motis/journey_to_response.h @@ -50,9 +50,8 @@ api::Itinerary journey_to_response(osr::ways const*, place_t const& dest, street_routing_cache_t&, osr::bitvec* blocked_mem, - bool car_transfers, - api::PedestrianProfileEnum, - api::ElevationCostsEnum, + nigiri::profile_idx_t, + transfer_routing_profiles_t const&, bool join_interlined_legs, bool detailed_transfers, bool with_fares, diff --git a/include/motis/mode_to_profile.h b/include/motis/mode_to_profile.h index 45fa54401e..651e51d454 100644 --- a/include/motis/mode_to_profile.h +++ b/include/motis/mode_to_profile.h @@ -10,6 +10,7 @@ namespace motis { api::ModeEnum to_mode(osr::mode); osr::search_profile to_profile(api::ModeEnum, api::PedestrianProfileEnum, - api::ElevationCostsEnum); + api::ElevationCostsEnum, + bool fastest_bike); } // namespace motis \ No newline at end of file diff --git a/openapi.yaml b/openapi.yaml index 4874021f2e..8a852be425 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -217,6 +217,14 @@ paths: $ref: '#/components/schemas/ElevationCosts' default: NONE + - name: fastestBike + in: query + required: false + description: Experimental. Optional. Default is `false`. Will probably be replaced by more fine-grained control (e.g. speed). + schema: + type: boolean + default: false + - name: useRoutedTransfers in: query required: false diff --git a/src/compute_footpaths.cc b/src/compute_footpaths.cc index 9b6fe37565..b9c4df6881 100644 --- a/src/compute_footpaths.cc +++ b/src/compute_footpaths.cc @@ -25,6 +25,19 @@ namespace n = nigiri; namespace motis { +n::profile_idx_t get_profile_idx(osr::search_profile const p) { + switch (p) { + case osr::search_profile::kFoot: return n::kFootProfile; + case osr::search_profile::kWheelchair: return n::kWheelchairProfile; + case osr::search_profile::kCar: return n::kCarProfile; + case osr::search_profile::kBike: + case osr::search_profile::kBikeFast: + case osr::search_profile::kBikeElevationHigh: [[fallthrough]]; + case osr::search_profile::kBikeElevationLow: return n::kBikeProfile; + default: throw utl::fail("{} not supported for transfers", to_str(p)); + } +} + elevator_footpath_map_t compute_footpaths( osr::ways const& w, osr::lookup const& lookup, @@ -32,7 +45,7 @@ elevator_footpath_map_t compute_footpaths( nigiri::timetable& tt, osr::elevation_storage const* elevations, bool const update_coordinates, - std::vector const& settings) { + transfer_routing_profiles_t const& settings) { fmt::println(std::clog, "creating matches"); auto const matches = get_matches(tt, pl, w); @@ -80,7 +93,14 @@ elevator_footpath_map_t compute_footpaths( auto candidates = vector_map{}; auto transfers = n::vector_map>( tt.n_locations()); - for (auto const& mode : settings) { + for (auto const [i, profile] : utl::enumerate(settings)) { + if (!profile.has_value()) { + continue; + } + + auto const prf_idx = static_cast(i); + auto const& mode = *profile; + candidates.clear(); candidates.resize(tt.n_locations()); for (auto& fps : transfers) { @@ -88,7 +108,20 @@ elevator_footpath_map_t compute_footpaths( } auto const is_candidate = [&](n::location_idx_t const l) { - return !mode.is_candidate_ || mode.is_candidate_(l); + switch (mode.profile_) { + case osr::search_profile::kBike: + case osr::search_profile::kBikeFast: + case osr::search_profile::kBikeElevationHigh: [[fallthrough]]; + case osr::search_profile::kBikeElevationLow: + return utl::any_of(tt.location_routes_[l], + [&](auto r) { return tt.has_bike_transport(r); }); + + case osr::search_profile::kCar: + return utl::any_of(tt.location_routes_[l], + [&](auto r) { return tt.has_car_transport(r); }); + + default: return true; + } }; { @@ -113,10 +146,10 @@ elevator_footpath_map_t compute_footpaths( } utl::parallel_for_run_threadlocal( - tt.n_locations(), [&](state& s, auto const i) { + tt.n_locations(), [&](state& s, auto const idx) { cista::for_each_field(s, [](auto& f) { f.clear(); }); - auto const l = n::location_idx_t{i}; + auto const l = n::location_idx_t{idx}; if (!is_candidate(l)) { pt->update_monotonic(n_done + i); return; @@ -202,22 +235,22 @@ elevator_footpath_map_t compute_footpaths( auto transfers_in = n::vector_map>{}; transfers_in.resize(tt.n_locations()); - for (auto const [i, out] : utl::enumerate(transfers)) { - auto const l = n::location_idx_t{i}; + for (auto const [j, out] : utl::enumerate(transfers)) { + auto const l = n::location_idx_t{j}; for (auto const fp : out) { assert(fp.target() < tt.n_locations()); transfers_in[fp.target()].push_back(n::footpath{l, fp.duration()}); } } for (auto const& x : transfers) { - tt.locations_.footpaths_out_[mode.profile_idx_].emplace_back(x); + tt.locations_.footpaths_out_[prf_idx].emplace_back(x); } for (auto const& x : transfers_in) { - tt.locations_.footpaths_in_[mode.profile_idx_].emplace_back(x); + tt.locations_.footpaths_in_[prf_idx].emplace_back(x); } - n::loader::build_lb_graph(tt, mode.profile_idx_); - n::loader::build_lb_graph(tt, mode.profile_idx_); + n::loader::build_lb_graph(tt, prf_idx); + n::loader::build_lb_graph(tt, prf_idx); n_done += tt.n_locations(); } diff --git a/src/config.cc b/src/config.cc index 0f5a564b3e..e2e9b0f5f0 100644 --- a/src/config.cc +++ b/src/config.cc @@ -17,6 +17,8 @@ #include "rfl.hpp" #include "rfl/yaml.hpp" +#include "motis/compute_footpaths.h" + namespace fs = std::filesystem; namespace motis { @@ -123,6 +125,7 @@ void config::verify() const { nigiri::routing::kMaxSearchIntervalSize.count()); if (timetable_) { + timetable_->get_profiles(); for (auto const& [id, d] : timetable_->datasets_) { utl::verify(!id.contains("_"), "dataset identifier may not contain '_'"); if (d.rt_.has_value()) { @@ -174,6 +177,27 @@ void config::verify_input_files_exist() const { } } +transfer_routing_profiles_t config::timetable::get_profiles() const { + if (!transfer_profiles_.has_value()) { + return {}; + } + + auto map = transfer_routing_profiles_t{}; + for (auto const& p : *transfer_profiles_) { + auto const profile = osr::to_profile(p.profile_); + auto const prf_idx = get_profile_idx(profile); + utl_verify(!map[prf_idx].has_value(), + "adding transfer profile {}: index {} already taken by {}", + p.profile_, prf_idx, osr::to_str(map[prf_idx]->profile_)); + map[prf_idx] = transfer_routing_options{ + .profile_ = profile, + .max_matching_distance_ = p.max_matching_distance_meters_, + .extend_missing_ = p.extend_missing_, + .max_duration_ = p.max_duration_seconds_ * std::chrono::seconds{1}}; + } + return map; +} + bool config::requires_rt_timetable_updates() const { return timetable_.has_value() && ((has_elevators() && get_elevators()->url_.has_value()) || diff --git a/src/endpoints/one_to_all.cc b/src/endpoints/one_to_all.cc index 52e3f8b88b..4698e5ecaa 100644 --- a/src/endpoints/one_to_all.cc +++ b/src/endpoints/one_to_all.cc @@ -79,7 +79,7 @@ api::Reachable one_to_all::operator()(boost::urls::url_view const& url) const { .start_ = r.get_offsets( nullptr, one, one_dir, one_modes, std::nullopt, std::nullopt, std::nullopt, false, query.pedestrianProfile_, query.elevationCosts_, - one_max_time, query.maxMatchingDistance_, gbfs_rd), + true, one_max_time, query.maxMatchingDistance_, gbfs_rd), .td_start_ = r.get_td_offsets(nullptr, nullptr, one, one_dir, one_modes, query.pedestrianProfile_, query.elevationCosts_, diff --git a/src/endpoints/one_to_many.cc b/src/endpoints/one_to_many.cc index 8358305b3f..757c0f50c3 100644 --- a/src/endpoints/one_to_many.cc +++ b/src/endpoints/one_to_many.cc @@ -35,7 +35,7 @@ api::oneToMany_response one_to_many::operator()( auto const paths = osr::route( w_, l_, to_profile(query.mode_, api::PedestrianProfileEnum::FOOT, - query.elevationCosts_), + query.elevationCosts_, true), *one, many, query.max_, query.arriveBy_ ? osr::direction::kBackward : osr::direction::kForward, query.maxMatchingDistance_, nullptr, nullptr, elevations_); diff --git a/src/endpoints/routing.cc b/src/endpoints/routing.cc index 4ede43a0ad..8fbdd31aa8 100644 --- a/src/endpoints/routing.cc +++ b/src/endpoints/routing.cc @@ -111,7 +111,8 @@ n::routing::td_offsets_t get_td_offsets( continue; } - auto const profile = to_profile(m, pedestrian_profile, elevation_costs); + auto const profile = + to_profile(m, pedestrian_profile, elevation_costs, false); if (e == nullptr || profile != osr::search_profile::kWheelchair) { continue; // handled by get_offsets @@ -175,6 +176,7 @@ std::vector get_offsets( bool const ignore_rental_return_constraints, api::PedestrianProfileEnum const pedestrian_profile, api::ElevationCostsEnum const elevation_costs, + bool const fastest_bike, std::chrono::seconds const max, double const max_matching_distance, gbfs::gbfs_routing_data& gbfs_rd) { @@ -185,7 +187,8 @@ std::vector get_offsets( auto ignore_walk = false; auto const handle_mode = [&](api::ModeEnum const m) { - auto const profile = to_profile(m, pedestrian_profile, elevation_costs); + auto const profile = + to_profile(m, pedestrian_profile, elevation_costs, fastest_bike); if (r.rt_->e_ && profile == osr::search_profile::kWheelchair) { return; // handled by get_td_offsets @@ -299,6 +302,7 @@ std::vector routing::get_offsets( bool const ignore_rental_return_constraints, api::PedestrianProfileEnum const pedestrian_profile, api::ElevationCostsEnum const elevation_costs, + bool const fastest_bike, std::chrono::seconds const max, double const max_matching_distance, gbfs::gbfs_routing_data& gbfs_rd) const { @@ -309,8 +313,8 @@ std::vector routing::get_offsets( *this, rtt, pos, dir, elevations_, modes, form_factors, propulsion_types, rental_providers, ignore_rental_return_constraints, - pedestrian_profile, elevation_costs, max, - max_matching_distance, gbfs_rd); + pedestrian_profile, elevation_costs, fastest_bike, + max, max_matching_distance, gbfs_rd); }}, p); } @@ -350,6 +354,7 @@ std::pair, n::duration_t> routing::route_direct( bool const arrive_by, api::PedestrianProfileEnum const pedestrian_profile, api::ElevationCostsEnum const elevation_costs, + bool const fastest_bike, std::chrono::seconds max, double const max_matching_distance, double const fastest_direct_factor, @@ -396,7 +401,8 @@ std::pair, n::duration_t> routing::route_direct( m == api::ModeEnum::CAR_DROPOFF || (!omit_walk && m == api::ModeEnum::WALK)) { route_with_profile(default_output{ - *w_, to_profile(m, pedestrian_profile, elevation_costs)}); + *w_, + to_profile(m, pedestrian_profile, elevation_costs, fastest_bike)}); } else if (m == api::ModeEnum::RENTAL && gbfs_rd.has_data()) { // could be bike sharing or car sharing - car sharing has the higher max // distance, so we use this here to be safe @@ -429,7 +435,7 @@ std::pair, n::duration_t> routing::route_direct( if (routed == 0U && utl::find(modes, api::ModeEnum::WALK) != end(modes)) { route_with_profile(default_output{ *w_, to_profile(api::ModeEnum::WALK, pedestrian_profile, - elevation_costs)}); + elevation_costs, fastest_bike)}); } } } @@ -599,7 +605,7 @@ api::plan_response routing::operator()(boost::urls::url_view const& url) const { query.directRentalProviders_, query.ignoreDirectRentalReturnConstraints_, *t, query.arriveBy_, query.pedestrianProfile_, - query.elevationCosts_, + query.elevationCosts_, query.fastestBike_, std::chrono::seconds{query.maxDirectTime_}, query.maxMatchingDistance_, query.fastestDirectFactor_, api_version) @@ -656,24 +662,24 @@ api::plan_response routing::operator()(boost::urls::url_view const& url) const { .start_match_mode_ = get_match_mode(start), .dest_match_mode_ = get_match_mode(dest), .use_start_footpaths_ = !is_intermodal(start), - .start_ = - get_offsets(rtt, start, - query.arriveBy_ ? osr::direction::kBackward - : osr::direction::kForward, - start_modes, start_form_factors, start_propulsion_types, - start_rental_providers, start_ignore_return_constraints, - query.pedestrianProfile_, query.elevationCosts_, - std::chrono::seconds{query.maxPreTransitTime_}, - query.maxMatchingDistance_, gbfs_rd), - .destination_ = - get_offsets(rtt, dest, - query.arriveBy_ ? osr::direction::kForward - : osr::direction::kBackward, - dest_modes, dest_form_factors, dest_propulsion_types, - dest_rental_providers, dest_ignore_return_constraints, - query.pedestrianProfile_, query.elevationCosts_, - std::chrono::seconds{query.maxPostTransitTime_}, - query.maxMatchingDistance_, gbfs_rd), + .start_ = get_offsets( + rtt, start, + query.arriveBy_ ? osr::direction::kBackward + : osr::direction::kForward, + start_modes, start_form_factors, start_propulsion_types, + start_rental_providers, start_ignore_return_constraints, + query.pedestrianProfile_, query.elevationCosts_, query.fastestBike_, + std::chrono::seconds{query.maxPreTransitTime_}, + query.maxMatchingDistance_, gbfs_rd), + .destination_ = get_offsets( + rtt, dest, + query.arriveBy_ ? osr::direction::kForward + : osr::direction::kBackward, + dest_modes, dest_form_factors, dest_propulsion_types, + dest_rental_providers, dest_ignore_return_constraints, + query.pedestrianProfile_, query.elevationCosts_, query.fastestBike_, + std::chrono::seconds{query.maxPostTransitTime_}, + query.maxMatchingDistance_, gbfs_rd), .td_start_ = get_td_offsets(rtt, e, start, query.arriveBy_ ? osr::direction::kBackward @@ -771,9 +777,8 @@ api::plan_response routing::operator()(boost::urls::url_view const& url) const { return journey_to_response( w_, l_, pl_, *tt_, *tags_, fa_, e, rtt, matches_, elevations_, shapes_, gbfs_rd, lp_, tz_, j, start, dest, cache, - blocked.get(), - query.requireCarTransport_ && query.useRoutedTransfers_, - query.pedestrianProfile_, query.elevationCosts_, + blocked.get(), q.prf_idx_, + config_.timetable_.value().get_profiles(), query.joinInterlinedLegs_, query.detailedTransfers_, query.withFares_, query.withScheduledSkippedStops_, config_.timetable_.value().max_matching_distance_, diff --git a/src/endpoints/trip.cc b/src/endpoints/trip.cc index e34c48e17f..eab81aba4e 100644 --- a/src/endpoints/trip.cc +++ b/src/endpoints/trip.cc @@ -58,11 +58,10 @@ api::Itinerary trip::operator()(boost::urls::url_view const& url) const { .transfers_ = 0U}, tt_location{from_l.get_location_idx(), from_l.get_scheduled_location_idx()}, - tt_location{to_l.get_location_idx()}, cache, &blocked, false, - api::PedestrianProfileEnum::FOOT, api::ElevationCostsEnum::NONE, - query.joinInterlinedLegs_, true, false, query.withScheduledSkippedStops_, - config_.timetable_.value().max_matching_distance_, kMaxMatchingDistance, - api_version, false, false, query.language_); + tt_location{to_l.get_location_idx()}, cache, &blocked, 0U, + transfer_routing_profiles_t{}, query.joinInterlinedLegs_, false, false, + query.withScheduledSkippedStops_, 0.0, 0.0, api_version, false, false, + query.language_); } } // namespace motis::ep diff --git a/src/import.cc b/src/import.cc index a7e3e28eec..dcb0b330cf 100644 --- a/src/import.cc +++ b/src/import.cc @@ -426,28 +426,24 @@ data import(config const& c, fs::path const& data_path, bool const write) { [&]() { return c.osr_footpath_ && c.timetable_; }, [&]() { return d.tt_ && d.tags_ && d.w_ && d.l_ && d.pl_; }, [&]() { - auto const profiles = std::vector{ - {.profile_ = osr::search_profile::kFoot, - .profile_idx_ = n::kFootProfile, - .max_matching_distance_ = c.timetable_->max_matching_distance_, - .extend_missing_ = c.timetable_->extend_missing_footpaths_, - .max_duration_ = c.timetable_->max_footpath_length_ * 1min}, - {.profile_ = osr::search_profile::kWheelchair, - .profile_idx_ = n::kWheelchairProfile, - .max_matching_distance_ = 8.0, - .max_duration_ = c.timetable_->max_footpath_length_ * 1min}, - {.profile_ = osr::search_profile::kCar, - .profile_idx_ = n::kCarProfile, - .max_matching_distance_ = 250.0, - .max_duration_ = 8h, - .is_candidate_ = [&](n::location_idx_t const l) { - return utl::any_of(d.tt_->location_routes_[l], [&](auto r) { - return d.tt_->has_car_transport(r); - }); - }}}; - auto const elevator_footpath_map = compute_footpaths( - *d.w_, *d.l_, *d.pl_, *d.tt_, d.elevations_.get(), - c.timetable_->use_osm_stop_coordinates_, profiles); + auto const profiles = c.timetable_->transfer_profiles_.value_or( + std::vector{ + {.profile_ = "foot", + .max_matching_distance_meters_ = + c.timetable_->max_matching_distance_, + .max_duration_seconds_ = + c.timetable_->max_footpath_length_ * 60U, + .extend_missing_ = c.timetable_->extend_missing_footpaths_}, + {.profile_ = "wheelchair", + .max_matching_distance_meters_ = 8.0, + .max_duration_seconds_ = + c.timetable_->max_footpath_length_ * 60U, + .extend_missing_ = false}, + }); + auto const elevator_footpath_map = + compute_footpaths(*d.w_, *d.l_, *d.pl_, *d.tt_, d.elevations_.get(), + c.timetable_->use_osm_stop_coordinates_, + c.timetable_->get_profiles()); if (write) { cista::write(data_path / "elevator_footpath_map.bin", diff --git a/src/journey_to_response.cc b/src/journey_to_response.cc index 4866c78bdb..4e3a0566e2 100644 --- a/src/journey_to_response.cc +++ b/src/journey_to_response.cc @@ -46,9 +46,10 @@ api::ModeEnum to_mode(osr::search_profile const m) { case osr::search_profile::kFoot: [[fallthrough]]; case osr::search_profile::kWheelchair: return api::ModeEnum::WALK; case osr::search_profile::kCar: return api::ModeEnum::CAR; - case osr::search_profile::kBikeElevationLow: - case osr::search_profile::kBikeElevationHigh: [[fallthrough]]; - case osr::search_profile::kBike: return api::ModeEnum::BIKE; + case osr::search_profile::kBike: + case osr::search_profile::kBikeFast: + case osr::search_profile::kBikeElevationLow: [[fallthrough]]; + case osr::search_profile::kBikeElevationHigh: return api::ModeEnum::BIKE; case osr::search_profile::kBikeSharing: [[fallthrough]]; case osr::search_profile::kCarSharing: return api::ModeEnum::RENTAL; } @@ -209,9 +210,8 @@ api::Itinerary journey_to_response( place_t const& dest, street_routing_cache_t& cache, osr::bitvec* blocked_mem, - bool const car_transfers, - api::PedestrianProfileEnum const pedestrian_profile, - api::ElevationCostsEnum const elevation_costs, + n::profile_idx_t const prf_idx, + transfer_routing_profiles_t const& transfer_profiles, bool const join_interlined_legs, bool const detailed_transfers, bool const with_fares, @@ -223,6 +223,8 @@ api::Itinerary journey_to_response( bool const ignore_dest_rental_return_constraints, std::optional const& language) { utl::verify(!j.legs_.empty(), "journey without legs"); + utl::verify(prf_idx == 0U || transfer_profiles[prf_idx].has_value(), + "transfer profile not found"); auto const fares = with_fares ? std::optional{n::get_fares(tt, rtt, j)} : std::nullopt; @@ -493,24 +495,24 @@ api::Itinerary journey_to_response( } }, [&](n::footpath) { - append(w && l && detailed_transfers - ? street_routing( - *w, *l, e, elevations, from, to, - default_output{ - *w, car_transfers - ? osr::search_profile::kCar - : to_profile(api::ModeEnum::WALK, - pedestrian_profile, - elevation_costs)}, - j_leg.dep_time_, j_leg.arr_time_, - car_transfers ? 250.0 - : timetable_max_matching_distance, - cache, *blocked_mem, api_version, - std::chrono::duration_cast( - j_leg.arr_time_ - j_leg.dep_time_) + - std::chrono::minutes{10}) - : dummy_itinerary(from, to, api::ModeEnum::WALK, - j_leg.dep_time_, j_leg.arr_time_)); + append( + w && l && detailed_transfers + ? street_routing( + *w, *l, e, elevations, from, to, + default_output{ + *w, prf_idx == 0U + ? osr::search_profile::kFoot + : transfer_profiles[prf_idx]->profile_}, + j_leg.dep_time_, j_leg.arr_time_, + prf_idx == 0U ? timetable_max_matching_distance + : transfer_profiles[prf_idx] + ->max_matching_distance_, + cache, *blocked_mem, api_version, + std::chrono::duration_cast( + j_leg.arr_time_ - j_leg.dep_time_) + + std::chrono::minutes{10}) + : dummy_itinerary(from, to, api::ModeEnum::WALK, + j_leg.dep_time_, j_leg.arr_time_)); }, [&](n::routing::offset const x) { auto out = std::unique_ptr{}; diff --git a/src/max_distance.cc b/src/max_distance.cc index cf609b4086..6f125cdf55 100644 --- a/src/max_distance.cc +++ b/src/max_distance.cc @@ -10,10 +10,11 @@ double get_max_distance(osr::search_profile const profile, switch (profile) { case osr::search_profile::kWheelchair: return seconds * 0.8; case osr::search_profile::kFoot: return seconds * 1.1; + case osr::search_profile::kBike: + case osr::search_profile::kBikeFast: case osr::search_profile::kBikeSharing: - case osr::search_profile::kBikeElevationLow: - case osr::search_profile::kBikeElevationHigh: [[fallthrough]]; - case osr::search_profile::kBike: return seconds * 4.0; + case osr::search_profile::kBikeElevationLow: [[fallthrough]]; + case osr::search_profile::kBikeElevationHigh: return seconds * 4.1; case osr::search_profile::kCar: case osr::search_profile::kCarDropOff: case osr::search_profile::kCarDropOffWheelchair: diff --git a/src/mode_to_profile.cc b/src/mode_to_profile.cc index 478b63edf6..7169bc3a87 100644 --- a/src/mode_to_profile.cc +++ b/src/mode_to_profile.cc @@ -17,7 +17,8 @@ api::ModeEnum to_mode(osr::mode const m) { osr::search_profile to_profile( api::ModeEnum const m, api::PedestrianProfileEnum const pedestrian_profile, - api::ElevationCostsEnum const elevation_costs) { + api::ElevationCostsEnum const elevation_costs, + bool const fastest_bike) { auto const wheelchair = pedestrian_profile == api::PedestrianProfileEnum::WHEELCHAIR; switch (m) { @@ -25,6 +26,9 @@ osr::search_profile to_profile( return wheelchair ? osr::search_profile::kWheelchair : osr::search_profile::kFoot; case api::ModeEnum::BIKE: + if (fastest_bike) { + return osr::search_profile::kBikeFast; + } switch (elevation_costs) { case api::ElevationCostsEnum::NONE: return osr::search_profile::kBike; case api::ElevationCostsEnum::LOW: diff --git a/src/odm/meta_router.cc b/src/odm/meta_router.cc index c9ab7142b5..eb3b48f922 100644 --- a/src/odm/meta_router.cc +++ b/src/odm/meta_router.cc @@ -173,8 +173,8 @@ n::duration_t init_direct(std::vector& direct_rides, auto [_, odm_direct_duration] = r.route_direct( e, gbfs, from_p, to_p, {api::ModeEnum::CAR}, std::nullopt, std::nullopt, std::nullopt, false, intvl.from_, false, query.pedestrianProfile_, - query.elevationCosts_, kODMMaxDuration, query.maxMatchingDistance_, - kODMDirectFactor, api_version); + query.elevationCosts_, query.fastestBike_, kODMMaxDuration, + query.maxMatchingDistance_, kODMDirectFactor, api_version); auto const step = std::chrono::duration_cast(kODMDirectPeriod); @@ -237,20 +237,14 @@ void init_pt(std::vector& rides, return; } - auto offsets = r.get_offsets(rtt, l, dir, {api::ModeEnum::ODM}, std::nullopt, - std::nullopt, std::nullopt, false, - query.pedestrianProfile_, query.elevationCosts_, - max, query.maxMatchingDistance_, gbfs_rd); + auto offsets = r.get_offsets( + rtt, l, dir, {api::ModeEnum::ODM}, std::nullopt, std::nullopt, + std::nullopt, false, query.pedestrianProfile_, query.elevationCosts_, + query.fastestBike_, max, query.maxMatchingDistance_, gbfs_rd); std::erase_if(offsets, [&](n::routing::offset const& o) { - auto const out_of_bounds = - (r.odm_bounds_ != nullptr && - !r.odm_bounds_->contains(r.tt_->locations_.coordinates_[o.target_])); - /*if (out_of_bounds) { - n::log(n::log_lvl::debug, "motis.odm", "Bounds filtered: {}", - n::location{*r.tt_, o.target_}); - }*/ - return out_of_bounds; + return r.odm_bounds_ != nullptr && + !r.odm_bounds_->contains(r.tt_->locations_.coordinates_[o.target_]); }); for (auto& o : offsets) { @@ -598,7 +592,7 @@ api::plan_response meta_router::run() { start_modes_, start_form_factors_, start_propulsion_types_, start_rental_providers_, start_ignore_rental_return_constraints_, query_.pedestrianProfile_, query_.elevationCosts_, - std::chrono::seconds{query_.maxPreTransitTime_}, + query_.fastestBike_, std::chrono::seconds{query_.maxPreTransitTime_}, query_.maxMatchingDistance_, gbfs_rd_), .dest_walk_ = r_.get_offsets( rtt_, dest_, @@ -607,7 +601,7 @@ api::plan_response meta_router::run() { dest_modes_, dest_form_factors_, dest_propulsion_types_, dest_rental_providers_, dest_ignore_rental_return_constraints_, query_.pedestrianProfile_, query_.elevationCosts_, - std::chrono::seconds{query_.maxPostTransitTime_}, + query_.fastestBike_, std::chrono::seconds{query_.maxPostTransitTime_}, query_.maxMatchingDistance_, gbfs_rd_), .td_start_walk_ = r_.get_td_offsets( rtt_, e_, start_, @@ -747,8 +741,7 @@ api::plan_response meta_router::run() { r_.w_, r_.l_, r_.pl_, *tt_, *r_.tags_, r_.fa_, e_, rtt_, r_.matches_, r_.elevations_, r_.shapes_, gbfs_rd_, r_.lp_, r_.tz_, j, start_, dest_, cache, ep::blocked.get(), - query_.requireCarTransport_ && query_.useRoutedTransfers_, - query_.pedestrianProfile_, query_.elevationCosts_, + qf.base_query_.prf_idx_, r_.config_.timetable_->get_profiles(), query_.joinInterlinedLegs_, query_.detailedTransfers_, query_.withFares_, query_.withScheduledSkippedStops_, r_.config_.timetable_.value().max_matching_distance_, diff --git a/src/street_routing.cc b/src/street_routing.cc index cd7bc3dc0b..156868b130 100644 --- a/src/street_routing.cc +++ b/src/street_routing.cc @@ -49,6 +49,7 @@ api::ModeEnum default_output::get_mode() const { case osr::search_profile::kFoot: [[fallthrough]]; case osr::search_profile::kWheelchair: return api::ModeEnum::WALK; case osr::search_profile::kBike: [[fallthrough]]; + case osr::search_profile::kBikeFast: case osr::search_profile::kBikeElevationLow: [[fallthrough]]; case osr::search_profile::kBikeElevationHigh: return api::ModeEnum::BIKE; case osr::search_profile::kCar: return api::ModeEnum::CAR; diff --git a/test/matching_test.cc b/test/matching_test.cc index d2d3ebc0da..bad98c2424 100644 --- a/test/matching_test.cc +++ b/test/matching_test.cc @@ -15,6 +15,7 @@ #include "motis/config.h" #include "motis/import.h" #include "motis/match_platforms.h" +#include "osr/routing/with_profile.h" using namespace std::string_view_literals; using namespace osr; @@ -117,23 +118,9 @@ TEST(motis, get_way_candidates) { auto const get_path = [&](search_profile const p, way_candidate const& a, node_candidate const& anc, location const& l) { - switch (p) { - case search_profile::kFoot: - return d.l_->get_node_candidate_path>(a, anc, true, l); - case search_profile::kWheelchair: - return d.l_->get_node_candidate_path>(a, anc, true, l); - case search_profile::kCar: - return d.l_->get_node_candidate_path(a, anc, true, l); - case search_profile::kBike: - return d.l_->get_node_candidate_path>(a, anc, - true, l); - case search_profile::kCarSharing: - return d.l_->get_node_candidate_path>( - a, anc, true, l); - case search_profile::kBikeSharing: - return d.l_->get_node_candidate_path(a, anc, true, l); - default: return std::vector{}; - } + return osr::with_profile(p, [&](Profile&&) { + return d.l_->get_node_candidate_path(a, anc, true, l); + }); }; for (auto profile :