diff --git a/locales/ar-SA.json b/locales/ar-SA.json index d697a31a57..6bf8b56a49 100644 --- a/locales/ar-SA.json +++ b/locales/ar-SA.json @@ -2319,6 +2319,20 @@ ] } }, + "bike_share_verbal": { + "phrases": { + "0": "Rent a bike from bike share station.", + "1": "Return the bike to the bike share station." + }, + "example_phrases": { + "0": [ + "Rent a bike from bike share station." + ], + "1": [ + "Return a bike at the bike share station." + ] + } + }, "enter_building": { "phrases": { "0": "Enter the building.", diff --git a/locales/bg-BG.json b/locales/bg-BG.json index e443fb9256..09b98e2f17 100644 --- a/locales/bg-BG.json +++ b/locales/bg-BG.json @@ -2319,6 +2319,20 @@ ] } }, + "bike_share_verbal": { + "phrases": { + "0": "Rent a bike from bike share station.", + "1": "Return the bike to the bike share station." + }, + "example_phrases": { + "0": [ + "Rent a bike from bike share station." + ], + "1": [ + "Return a bike at the bike share station." + ] + } + }, "enter_building": { "phrases": { "0": "Enter the building.", diff --git a/locales/ca-ES.json b/locales/ca-ES.json index e006a6dea1..446136e84e 100644 --- a/locales/ca-ES.json +++ b/locales/ca-ES.json @@ -2319,6 +2319,20 @@ ] } }, + "bike_share_verbal": { + "phrases": { + "0": "Rent a bike from bike share station.", + "1": "Return the bike to the bike share station." + }, + "example_phrases": { + "0": [ + "Rent a bike from bike share station." + ], + "1": [ + "Return a bike at the bike share station." + ] + } + }, "enter_building": { "phrases": { "0": "Entra a l'edifici.", diff --git a/locales/cs-CZ.json b/locales/cs-CZ.json index cc264c2416..ee8e480cbc 100644 --- a/locales/cs-CZ.json +++ b/locales/cs-CZ.json @@ -2319,6 +2319,20 @@ ] } }, + "bike_share_verbal": { + "phrases": { + "0": "Rent a bike from bike share station.", + "1": "Return the bike to the bike share station." + }, + "example_phrases": { + "0": [ + "Rent a bike from bike share station." + ], + "1": [ + "Return a bike at the bike share station." + ] + } + }, "enter_building": { "phrases": { "0": "Enter the building.", diff --git a/locales/da-DK.json b/locales/da-DK.json index 89d4343617..8fa92328af 100644 --- a/locales/da-DK.json +++ b/locales/da-DK.json @@ -2319,6 +2319,20 @@ ] } }, + "bike_share_verbal": { + "phrases": { + "0": "Rent a bike from bike share station.", + "1": "Return the bike to the bike share station." + }, + "example_phrases": { + "0": [ + "Rent a bike from bike share station." + ], + "1": [ + "Return a bike at the bike share station." + ] + } + }, "enter_building": { "phrases": { "0": "Enter the building.", diff --git a/locales/de-DE.json b/locales/de-DE.json index e163d4c454..c441eeb94b 100644 --- a/locales/de-DE.json +++ b/locales/de-DE.json @@ -2319,6 +2319,20 @@ ] } }, + "bike_share_verbal": { + "phrases": { + "0": "Rent a bike from bike share station.", + "1": "Return the bike to the bike share station." + }, + "example_phrases": { + "0": [ + "Rent a bike from bike share station." + ], + "1": [ + "Return a bike at the bike share station." + ] + } + }, "enter_building": { "phrases": { "0": "In das Gebäude eintreten.", diff --git a/locales/el-GR.json b/locales/el-GR.json index bd171acb8a..9a76f2fc3c 100644 --- a/locales/el-GR.json +++ b/locales/el-GR.json @@ -2319,6 +2319,20 @@ ] } }, + "bike_share_verbal": { + "phrases": { + "0": "Rent a bike from bike share station.", + "1": "Return the bike to the bike share station." + }, + "example_phrases": { + "0": [ + "Rent a bike from bike share station." + ], + "1": [ + "Return a bike at the bike share station." + ] + } + }, "enter_building": { "phrases": { "0": "Enter the building.", diff --git a/locales/en-AU.json b/locales/en-AU.json index 220a0af697..cc8e2ca357 100644 --- a/locales/en-AU.json +++ b/locales/en-AU.json @@ -2319,6 +2319,20 @@ ] } }, + "bike_share_verbal": { + "phrases": { + "0": "Rent a bike from bike share station.", + "1": "Return the bike to the bike share station." + }, + "example_phrases": { + "0": [ + "Rent a bike from bike share station." + ], + "1": [ + "Return a bike at the bike share station." + ] + } + }, "enter_building": { "phrases": { "0": "Enter the building.", diff --git a/locales/en-GB.json b/locales/en-GB.json index 5510f0ea33..fc9af93c69 100644 --- a/locales/en-GB.json +++ b/locales/en-GB.json @@ -2317,6 +2317,20 @@ ] } }, + "bike_share_verbal": { + "phrases": { + "0": "Rent a bike from bike share station.", + "1": "Return the bike to the bike share station." + }, + "example_phrases": { + "0": [ + "Rent a bike from bike share station." + ], + "1": [ + "Return a bike at the bike share station." + ] + } + }, "enter_building": { "phrases": { "0": "Enter the building.", diff --git a/locales/en-US-x-pirate.json b/locales/en-US-x-pirate.json index 48915e215f..9500c9a259 100644 --- a/locales/en-US-x-pirate.json +++ b/locales/en-US-x-pirate.json @@ -2319,6 +2319,20 @@ ] } }, + "bike_share_verbal": { + "phrases": { + "0": "Rent a bike from bike share station.", + "1": "Return the bike to the bike share station." + }, + "example_phrases": { + "0": [ + "Rent a bike from bike share station." + ], + "1": [ + "Return a bike at the bike share station." + ] + } + }, "enter_building": { "phrases": { "0": "Enter the building.", diff --git a/locales/en-US.json b/locales/en-US.json index 12dc9cdba3..dad1a2adb2 100644 --- a/locales/en-US.json +++ b/locales/en-US.json @@ -2319,6 +2319,20 @@ ] } }, + "bike_share_verbal": { + "phrases": { + "0": "Rent a bike from bike share station.", + "1": "Return the bike to the bike share station." + }, + "example_phrases": { + "0": [ + "Rent a bike from bike share station." + ], + "1": [ + "Return a bike at the bike share station." + ] + } + }, "enter_building": { "phrases": { "0": "Enter the building.", diff --git a/locales/es-ES.json b/locales/es-ES.json index 6c88d8ee47..0be3347695 100644 --- a/locales/es-ES.json +++ b/locales/es-ES.json @@ -2319,6 +2319,20 @@ ] } }, + "bike_share_verbal": { + "phrases": { + "0": "Alquile una bicicleta en la estación de bicicletas compartidas.", + "1": "Devuelva la bicicleta a la estación de bicicletas compartidas." + }, + "example_phrases": { + "0": [ + "Alquile una bicicleta en la estación de bicicletas compartidas." + ], + "1": [ + "Devuelva la bicicleta a la estación de bicicletas compartidas." + ] + } + }, "enter_building": { "phrases": { "0": "Entre al edificio.", diff --git a/locales/et-EE.json b/locales/et-EE.json index b689cf69b1..e6e82131b2 100644 --- a/locales/et-EE.json +++ b/locales/et-EE.json @@ -2319,6 +2319,20 @@ ] } }, + "bike_share_verbal": { + "phrases": { + "0": "Rent a bike from bike share station.", + "1": "Return the bike to the bike share station." + }, + "example_phrases": { + "0": [ + "Rent a bike from bike share station." + ], + "1": [ + "Return a bike at the bike share station." + ] + } + }, "enter_building": { "phrases": { "0": "Sisene hoonesse.", diff --git a/locales/fi-FI.json b/locales/fi-FI.json index 7b877c5641..f9bba160c4 100644 --- a/locales/fi-FI.json +++ b/locales/fi-FI.json @@ -2319,6 +2319,20 @@ ] } }, + "bike_share_verbal": { + "phrases": { + "0": "Rent a bike from bike share station.", + "1": "Return the bike to the bike share station." + }, + "example_phrases": { + "0": [ + "Rent a bike from bike share station." + ], + "1": [ + "Return a bike at the bike share station." + ] + } + }, "enter_building": { "phrases": { "0": "Enter the building.", diff --git a/locales/fr-FR.json b/locales/fr-FR.json index 79a526567c..b56795d4ca 100644 --- a/locales/fr-FR.json +++ b/locales/fr-FR.json @@ -2319,6 +2319,20 @@ ] } }, + "bike_share_verbal": { + "phrases": { + "0": "Louez un vélo à la station de vélos en libre-service.", + "1": "Remettez le vélo à la station de vélos en libre-service." + }, + "example_phrases": { + "0": [ + "Louez un vélo à la station de vélos en libre-service." + ], + "1": [ + "Remettez le vélo à la station de vélos en libre-service." + ] + } + }, "enter_building": { "phrases": { "0": "Entrez dans le bâtiment.", diff --git a/locales/hi-IN.json b/locales/hi-IN.json index 10d3db641f..73ce44ff4e 100644 --- a/locales/hi-IN.json +++ b/locales/hi-IN.json @@ -2319,6 +2319,20 @@ ] } }, + "bike_share_verbal": { + "phrases": { + "0": "Rent a bike from bike share station.", + "1": "Return the bike to the bike share station." + }, + "example_phrases": { + "0": [ + "Rent a bike from bike share station." + ], + "1": [ + "Return a bike at the bike share station." + ] + } + }, "enter_building": { "phrases": { "0": "Enter the building.", diff --git a/locales/hu-HU.json b/locales/hu-HU.json index 1c38246b07..68e7b6272f 100644 --- a/locales/hu-HU.json +++ b/locales/hu-HU.json @@ -2319,6 +2319,20 @@ ] } }, + "bike_share_verbal": { + "phrases": { + "0": "Rent a bike from bike share station.", + "1": "Return the bike to the bike share station." + }, + "example_phrases": { + "0": [ + "Rent a bike from bike share station." + ], + "1": [ + "Return a bike at the bike share station." + ] + } + }, "enter_building": { "phrases": { "0": "Lépjen be az épületbe.", diff --git a/locales/it-IT.json b/locales/it-IT.json index f1afc7a922..fd29a0cc9e 100644 --- a/locales/it-IT.json +++ b/locales/it-IT.json @@ -2319,6 +2319,20 @@ ] } }, + "bike_share_verbal": { + "phrases": { + "0": "Noleggia una bici dalla stazione del bike sharing.", + "1": "Riconsegna la bici alla stazione di bike sharing." + }, + "example_phrases": { + "0": [ + "Rent a bike from bike share station." + ], + "1": [ + "Riconsegna la bici alla stazione di bike sharing." + ] + } + }, "enter_building": { "phrases": { "0": "Enter the building.", diff --git a/locales/ja-JP.json b/locales/ja-JP.json index 25e70028f0..61fb48ebe1 100644 --- a/locales/ja-JP.json +++ b/locales/ja-JP.json @@ -2319,6 +2319,20 @@ ] } }, + "bike_share_verbal": { + "phrases": { + "0": "Rent a bike from bike share station.", + "1": "Return the bike to the bike share station." + }, + "example_phrases": { + "0": [ + "Rent a bike from bike share station." + ], + "1": [ + "Return a bike at the bike share station." + ] + } + }, "enter_building": { "phrases": { "0": "Enter the building.", diff --git a/locales/ko-KR.json b/locales/ko-KR.json index 5aab9385ce..2810b9f336 100644 --- a/locales/ko-KR.json +++ b/locales/ko-KR.json @@ -2319,6 +2319,20 @@ ] } }, + "bike_share_verbal": { + "phrases": { + "0": "Rent a bike from bike share station.", + "1": "Return the bike to the bike share station." + }, + "example_phrases": { + "0": [ + "Rent a bike from bike share station." + ], + "1": [ + "Return a bike at the bike share station." + ] + } + }, "enter_building": { "phrases": { "0": "건물로 진입", diff --git a/locales/mn-MN.json b/locales/mn-MN.json index a98ce0e222..e87877b34f 100644 --- a/locales/mn-MN.json +++ b/locales/mn-MN.json @@ -2319,6 +2319,20 @@ ] } }, + "bike_share_verbal": { + "phrases": { + "0": "Rent a bike from bike share station.", + "1": "Return the bike to the bike share station." + }, + "example_phrases": { + "0": [ + "Rent a bike from bike share station." + ], + "1": [ + "Return a bike at the bike share station." + ] + } + }, "enter_building": { "phrases": { "0": "Барилга руу ор.", diff --git a/locales/nb-NO.json b/locales/nb-NO.json index 33f448a415..fcc67c1fa3 100644 --- a/locales/nb-NO.json +++ b/locales/nb-NO.json @@ -2319,6 +2319,20 @@ ] } }, + "bike_share_verbal": { + "phrases": { + "0": "Rent a bike from bike share station.", + "1": "Return the bike to the bike share station." + }, + "example_phrases": { + "0": [ + "Rent a bike from bike share station." + ], + "1": [ + "Return a bike at the bike share station." + ] + } + }, "enter_building": { "phrases": { "0": "Enter the building.", diff --git a/locales/nl-NL.json b/locales/nl-NL.json index e3521cdb03..349802c8da 100644 --- a/locales/nl-NL.json +++ b/locales/nl-NL.json @@ -2319,6 +2319,20 @@ ] } }, + "bike_share_verbal": { + "phrases": { + "0": "Rent a bike from bike share station.", + "1": "Return the bike to the bike share station." + }, + "example_phrases": { + "0": [ + "Rent a bike from bike share station." + ], + "1": [ + "Return a bike at the bike share station." + ] + } + }, "enter_building": { "phrases": { "0": "Ga het gebouw in.", diff --git a/locales/pl-PL.json b/locales/pl-PL.json index c7b2f3cf84..c1e3879c8f 100644 --- a/locales/pl-PL.json +++ b/locales/pl-PL.json @@ -2319,6 +2319,20 @@ ] } }, + "bike_share_verbal": { + "phrases": { + "0": "Rent a bike from bike share station.", + "1": "Return the bike to the bike share station." + }, + "example_phrases": { + "0": [ + "Rent a bike from bike share station." + ], + "1": [ + "Return a bike at the bike share station." + ] + } + }, "enter_building": { "phrases": { "0": "Wejdź do budynku.", diff --git a/locales/pt-BR.json b/locales/pt-BR.json index e01ad71619..de43a1fbcb 100644 --- a/locales/pt-BR.json +++ b/locales/pt-BR.json @@ -2317,6 +2317,20 @@ ] } }, + "bike_share_verbal": { + "phrases": { + "0": "Rent a bike from bike share station.", + "1": "Return the bike to the bike share station." + }, + "example_phrases": { + "0": [ + "Rent a bike from bike share station." + ], + "1": [ + "Return a bike at the bike share station." + ] + } + }, "enter_building": { "phrases": { "0": "Enter the building.", diff --git a/locales/pt-PT.json b/locales/pt-PT.json index ad59e2266c..f7d22d9f62 100644 --- a/locales/pt-PT.json +++ b/locales/pt-PT.json @@ -2319,6 +2319,20 @@ ] } }, + "bike_share_verbal": { + "phrases": { + "0": "Rent a bike from bike share station.", + "1": "Return the bike to the bike share station." + }, + "example_phrases": { + "0": [ + "Rent a bike from bike share station." + ], + "1": [ + "Return a bike at the bike share station." + ] + } + }, "enter_building": { "phrases": { "0": "Enter the building.", diff --git a/locales/ro-RO.json b/locales/ro-RO.json index 00058c0c9d..091974522e 100644 --- a/locales/ro-RO.json +++ b/locales/ro-RO.json @@ -2319,6 +2319,20 @@ ] } }, + "bike_share_verbal": { + "phrases": { + "0": "Rent a bike from bike share station.", + "1": "Return the bike to the bike share station." + }, + "example_phrases": { + "0": [ + "Rent a bike from bike share station." + ], + "1": [ + "Return a bike at the bike share station." + ] + } + }, "enter_building": { "phrases": { "0": "Enter the building.", diff --git a/locales/ru-RU.json b/locales/ru-RU.json index eb25bf85b3..98632b21f7 100644 --- a/locales/ru-RU.json +++ b/locales/ru-RU.json @@ -2319,6 +2319,20 @@ ] } }, + "bike_share_verbal": { + "phrases": { + "0": "Rent a bike from bike share station.", + "1": "Return the bike to the bike share station." + }, + "example_phrases": { + "0": [ + "Rent a bike from bike share station." + ], + "1": [ + "Return a bike at the bike share station." + ] + } + }, "enter_building": { "phrases": { "0": "Войдите в здание.", diff --git a/locales/sk-SK.json b/locales/sk-SK.json index 1d941021eb..656fbe3912 100644 --- a/locales/sk-SK.json +++ b/locales/sk-SK.json @@ -2319,6 +2319,20 @@ ] } }, + "bike_share_verbal": { + "phrases": { + "0": "Rent a bike from bike share station.", + "1": "Return the bike to the bike share station." + }, + "example_phrases": { + "0": [ + "Rent a bike from bike share station." + ], + "1": [ + "Return a bike at the bike share station." + ] + } + }, "enter_building": { "phrases": { "0": "Vojdite do budovy.", diff --git a/locales/sl-SI.json b/locales/sl-SI.json index f6d317ccb7..a9fb7256ab 100644 --- a/locales/sl-SI.json +++ b/locales/sl-SI.json @@ -2319,6 +2319,20 @@ ] } }, + "bike_share_verbal": { + "phrases": { + "0": "Rent a bike from bike share station.", + "1": "Return the bike to the bike share station." + }, + "example_phrases": { + "0": [ + "Rent a bike from bike share station." + ], + "1": [ + "Return a bike at the bike share station." + ] + } + }, "enter_building": { "phrases": { "0": "Enter the building.", diff --git a/locales/sv-SE.json b/locales/sv-SE.json index 8085e592c4..42d5871f69 100644 --- a/locales/sv-SE.json +++ b/locales/sv-SE.json @@ -2319,6 +2319,20 @@ ] } }, + "bike_share_verbal": { + "phrases": { + "0": "Rent a bike from bike share station.", + "1": "Return the bike to the bike share station." + }, + "example_phrases": { + "0": [ + "Rent a bike from bike share station." + ], + "1": [ + "Return a bike at the bike share station." + ] + } + }, "enter_building": { "phrases": { "0": "Enter the building.", diff --git a/locales/tr-TR.json b/locales/tr-TR.json index ce0cce1eaf..ac91204e2f 100644 --- a/locales/tr-TR.json +++ b/locales/tr-TR.json @@ -2319,6 +2319,20 @@ ] } }, + "bike_share_verbal": { + "phrases": { + "0": "Rent a bike from bike share station.", + "1": "Return the bike to the bike share station." + }, + "example_phrases": { + "0": [ + "Rent a bike from bike share station." + ], + "1": [ + "Return a bike at the bike share station." + ] + } + }, "enter_building": { "phrases": { "0": "Enter the building.", diff --git a/locales/uk-UA.json b/locales/uk-UA.json index 9040cb041c..2a1d0bb1ed 100644 --- a/locales/uk-UA.json +++ b/locales/uk-UA.json @@ -2319,6 +2319,20 @@ ] } }, + "bike_share_verbal": { + "phrases": { + "0": "Rent a bike from bike share station.", + "1": "Return the bike to the bike share station." + }, + "example_phrases": { + "0": [ + "Rent a bike from bike share station." + ], + "1": [ + "Return a bike at the bike share station." + ] + } + }, "enter_building": { "phrases": { "0": "Увійдіть в будівлю.", diff --git a/locales/vi-VN.json b/locales/vi-VN.json index 6cd3d3c4b1..0a34d06e18 100644 --- a/locales/vi-VN.json +++ b/locales/vi-VN.json @@ -2319,6 +2319,20 @@ ] } }, + "bike_share_verbal": { + "phrases": { + "0": "Louez un vélo à la station de vélos en libre-service.", + "1": "Remettez le vélo à la station de vélos en libre-service." + }, + "example_phrases": { + "0": [ + "Louez un vélo à la station de vélos en libre-service." + ], + "1": [ + "Remettez le vélo à la station de vélos en libre-service." + ] + } + }, "enter_building": { "phrases": { "0": "Đi vào toà nhà.", diff --git a/proto/directions.proto b/proto/directions.proto index bafb07e467..afce6b4692 100644 --- a/proto/directions.proto +++ b/proto/directions.proto @@ -84,6 +84,8 @@ message DirectionsLeg { kBuildingEnter = 42; kBuildingExit = 43; kLevelChange = 44; + kTypeRentBikeAtBikeShare = 45; + kTypeReturnBikeAtBikeShare = 46; } enum BssManeuverType{ diff --git a/src/odin/maneuversbuilder.cc b/src/odin/maneuversbuilder.cc index 48afb8fa2a..7e676b9233 100644 --- a/src/odin/maneuversbuilder.cc +++ b/src/odin/maneuversbuilder.cc @@ -204,6 +204,22 @@ std::list ManeuversBuilder::Build() { return maneuvers; } +float ManeuversBuilder::bike_share_cost(valhalla::Costing_Type costing_type, int node_index) const { + auto bike_share_cost_it = options_.costings().find(costing_type); + if (bike_share_cost_it != options_.costings().end()) { + return bike_share_cost_it->second.options().bike_share_cost(); + } + auto node = trip_path_->GetEnhancedNode(node_index); + if (node->HasBssInfo()) { + auto bss_info = node->GetBssInfo(); + if (costing_type == valhalla::Costing_Type::Costing_Type_bicycle) { + return bss_info.rent_cost(); + } + return bss_info.return_cost(); + } + return 0.0f; +} + std::list ManeuversBuilder::Produce() { std::list maneuvers; @@ -312,7 +328,20 @@ std::list ManeuversBuilder::Produce() { } else { // Finalize current maneuver FinalizeManeuver(maneuvers.front(), i); - + if (CanRentBikeAtBikeShare(i)) { + // RentBikeAtBikeShare current maneuver + auto rent_cost = bike_share_cost(valhalla::Costing_Type::Costing_Type_bicycle, i); + maneuvers.front().set_time(maneuvers.front().time() - rent_cost); + maneuvers.emplace_front(); + AddBssManeuver(maneuvers.front(), DirectionsLeg_Maneuver_Type_kTypeRentBikeAtBikeShare, i); + } + if (CanReturnBikeAtBikeShare(i)) { + // ReturnBikeAtBikeShare current maneuver + auto return_cost = bike_share_cost(valhalla::Costing_Type::Costing_Type_pedestrian, i); + maneuvers.front().set_time(maneuvers.front().time() - return_cost); + maneuvers.emplace_front(); + AddBssManeuver(maneuvers.front(), DirectionsLeg_Maneuver_Type_kTypeReturnBikeAtBikeShare, i); + } // Initialize new maneuver maneuvers.emplace_front(); InitializeManeuver(maneuvers.front(), i); @@ -464,6 +493,18 @@ void ManeuversBuilder::Combine(std::list& maneuvers) { curr_man = next_man; ++next_man; } + // Do not combine + // if current or next maneuver is Bss rent or return + else if ((curr_man->type() == DirectionsLeg_Maneuver_Type_kTypeReturnBikeAtBikeShare) || + (curr_man->type() == DirectionsLeg_Maneuver_Type_kTypeRentBikeAtBikeShare) || + (next_man->type() == DirectionsLeg_Maneuver_Type_kTypeReturnBikeAtBikeShare) || + (next_man->type() == DirectionsLeg_Maneuver_Type_kTypeRentBikeAtBikeShare)) { + LOG_TRACE("+++ Do Not Combine: if Rent or Return BikeShare +++"); + // Update with no combine + prev_man = curr_man; + curr_man = next_man; + ++next_man; + } // Combine current left unspecified internal maneuver with next left maneuver else if (PossibleUnspecifiedInternalManeuver(prev_man, curr_man, next_man) && prev_man->HasSimilarNames(&(*next_man), true) && @@ -1135,6 +1176,14 @@ void ManeuversBuilder::CreateDestinationManeuver(Maneuver& maneuver) { trip_path_->GetStateCode(node_index))); } +void ManeuversBuilder::AddBssManeuver(Maneuver& maneuver, + const DirectionsLeg_Maneuver_Type& type, + int node_index) { + InitializeManeuver(maneuver, node_index); + maneuver.set_type(type); + FinalizeManeuver(maneuver, node_index); +} + void ManeuversBuilder::CreateStartManeuver(Maneuver& maneuver) { int node_index = 0; // Determine if the origin has a side of street @@ -1570,24 +1619,8 @@ void ManeuversBuilder::FinalizeManeuver(Maneuver& maneuver, int node_index) { maneuver.set_begin_street_names(std::move(curr_edge_names)); } } - if (node->type() == TripLeg_Node_Type::TripLeg_Node_Type_kBikeShare && prev_edge && - (prev_edge->travel_mode() == TravelMode::kBicycle) && - maneuver.travel_mode() == TravelMode::kPedestrian) { - maneuver.set_bss_maneuver_type(DirectionsLeg_Maneuver_BssManeuverType_kReturnBikeAtBikeShare); - if (node->HasBssInfo()) { - auto bss_info = node->GetBssInfo(); - maneuver.set_bss_info(bss_info); - } - } - if (node->type() == TripLeg_Node_Type::TripLeg_Node_Type_kBikeShare && prev_edge && - (prev_edge->travel_mode() == TravelMode::kPedestrian) && - maneuver.travel_mode() == TravelMode::kBicycle) { - maneuver.set_bss_maneuver_type(DirectionsLeg_Maneuver_BssManeuverType_kRentBikeAtBikeShare); - if (node->HasBssInfo()) { - auto bss_info = node->GetBssInfo(); - maneuver.set_bss_info(bss_info); - } - } + + UpdateBssManeuver(maneuver, node_index); // Set the verbal text formatter maneuver.set_verbal_formatter( @@ -1644,6 +1677,33 @@ void ManeuversBuilder::FinalizeManeuver(Maneuver& maneuver, int node_index) { SetManeuverType(maneuver); } +void ManeuversBuilder::UpdateBssManeuver(Maneuver& maneuver, int node_index) { + auto node = trip_path_->GetEnhancedNode(node_index); + if (node->HasBssInfo()) { + auto bss_info = node->GetBssInfo(); + maneuver.set_bss_info(bss_info); + } + + if (maneuver.type() != DirectionsLeg_Maneuver_Type_kTypeRentBikeAtBikeShare && + maneuver.type() != DirectionsLeg_Maneuver_Type_kTypeReturnBikeAtBikeShare) { + return; + } + + auto duration = 0.0f; + if (maneuver.type() == DirectionsLeg_Maneuver_Type_kTypeRentBikeAtBikeShare) { + maneuver.set_bss_maneuver_type(DirectionsLeg_Maneuver_BssManeuverType_kRentBikeAtBikeShare); + duration = bike_share_cost(valhalla::Costing_Type::Costing_Type_bicycle, node_index); + } + + if (maneuver.type() == DirectionsLeg_Maneuver_Type_kTypeReturnBikeAtBikeShare) { + maneuver.set_bss_maneuver_type(DirectionsLeg_Maneuver_BssManeuverType_kReturnBikeAtBikeShare); + duration = bike_share_cost(valhalla::Costing_Type::Costing_Type_pedestrian, node_index); + } + maneuver.set_time(duration); + maneuver.set_length(0); + maneuver.set_travel_mode(TravelMode::kBicycle); +} + void ManeuversBuilder::SetManeuverType(Maneuver& maneuver, bool none_type_allowed) { // If the type is already set then just return if (maneuver.type() != DirectionsLeg_Maneuver_Type_kNone) { @@ -2146,6 +2206,21 @@ ManeuversBuilder::DetermineCardinalDirection(uint32_t heading) { throw valhalla_exception_t{220}; } +bool ManeuversBuilder::CanRentBikeAtBikeShare(int node_index) { + auto prev_edge = trip_path_->GetPrevEdge(node_index); + auto node = trip_path_->GetEnhancedNode(node_index); + + return (node && node->type() == TripLeg_Node_Type::TripLeg_Node_Type_kBikeShare && prev_edge && + (prev_edge->travel_mode() == TravelMode::kPedestrian)); +} + +bool ManeuversBuilder::CanReturnBikeAtBikeShare(int node_index) { + auto prev_edge = trip_path_->GetPrevEdge(node_index); + auto node = trip_path_->GetEnhancedNode(node_index); + return (node->type() == TripLeg_Node_Type::TripLeg_Node_Type_kBikeShare && prev_edge && + (prev_edge->travel_mode() == TravelMode::kBicycle)); +} + bool ManeuversBuilder::CanManeuverIncludePrevEdge(Maneuver& maneuver, int node_index) { auto prev_edge = trip_path_->GetPrevEdge(node_index); auto curr_edge = trip_path_->GetCurrEdge(node_index); diff --git a/src/odin/narrative_dictionary.cc b/src/odin/narrative_dictionary.cc index 08deafbcec..0366942f7b 100644 --- a/src/odin/narrative_dictionary.cc +++ b/src/odin/narrative_dictionary.cc @@ -340,6 +340,10 @@ void NarrativeDictionary::Load(const boost::property_tree::ptree& narrative_pt) LOG_TRACE("Populate level_change_subset"); // Populate level_change_subset Load(level_change_subset, narrative_pt.get_child(kLevelChangeKey)); + + LOG_TRACE("Populate lbike_share_verbal_subset"); + // Populate bike_share_verbal_subset + Load(bike_share_verbal, narrative_pt.get_child(kBikeShareVerbalKey)); } void NarrativeDictionary::Load(PhraseSet& phrase_handle, diff --git a/src/odin/narrativebuilder.cc b/src/odin/narrativebuilder.cc index ce4e19afc7..22b9d7ed64 100644 --- a/src/odin/narrativebuilder.cc +++ b/src/odin/narrativebuilder.cc @@ -513,6 +513,12 @@ void NarrativeBuilder::Build(std::list& maneuvers) { case DirectionsLeg_Maneuver_Type_kLevelChange: maneuver.set_instruction(FormGenericLevelChangeInstruction(maneuver)); break; + case DirectionsLeg_Maneuver_Type_kTypeRentBikeAtBikeShare: + maneuver.set_instruction(FormBikeShareInstruction(maneuver)); + break; + case DirectionsLeg_Maneuver_Type_kTypeReturnBikeAtBikeShare: + maneuver.set_instruction(FormBikeShareInstruction(maneuver)); + break; case DirectionsLeg_Maneuver_Type_kContinue: default: { if (maneuver.has_node_type()) { @@ -539,8 +545,6 @@ void NarrativeBuilder::Build(std::list& maneuvers) { break; } } - maneuver.set_instruction(FormBssManeuverType(maneuver.bss_maneuver_type()) + - maneuver.instruction()); // Update previous maneuver prev_maneuver = &maneuver; @@ -4329,6 +4333,13 @@ std::string NarrativeBuilder::FormEnterBuildingInstruction(Maneuver& maneuver) { return instruction; } +std::string NarrativeBuilder::FormBikeShareInstruction(Maneuver& maneuver) { + if (maneuver.type() == DirectionsLeg_Maneuver_Type_kTypeRentBikeAtBikeShare) { + return dictionary_.bike_share_verbal.phrases.at(std::to_string(kBikeShareRentIndex)); + } + return dictionary_.bike_share_verbal.phrases.at(std::to_string(kBikeShareReturnIndex)); +} + std::string NarrativeBuilder::FormExitBuildingInstruction(Maneuver& maneuver) { // "0": "Exit the building.", // "1": "Exit the building, and continue on ." @@ -4926,17 +4937,5 @@ std::string NarrativeBuilder_ruRU::GetPluralCategory(size_t count) { return kPluralCategoryOtherKey; } -std::string NarrativeBuilder::FormBssManeuverType(DirectionsLeg_Maneuver_BssManeuverType type) { - switch (type) { - case DirectionsLeg_Maneuver_BssManeuverType_kRentBikeAtBikeShare: { - return "Then rent a bike at BSS. "; - } - case DirectionsLeg_Maneuver_BssManeuverType_kReturnBikeAtBikeShare: { - return "Then return the bike to BSS. "; - } - default: - return ""; - } -} } // namespace odin } // namespace valhalla diff --git a/src/sif/bicyclecost.cc b/src/sif/bicyclecost.cc index aa59212bbd..8f2b47d1a9 100644 --- a/src/sif/bicyclecost.cc +++ b/src/sif/bicyclecost.cc @@ -393,7 +393,7 @@ class BicycleCost : public DynamicCost { } virtual Cost BSSCost() const override { - return {kDefaultBssCost, kDefaultBssPenalty}; + return bike_share_cost_; }; // Hidden in source file so we don't need it to be protected diff --git a/src/sif/pedestriancost.cc b/src/sif/pedestriancost.cc index fb5db212ac..9bd9dda688 100644 --- a/src/sif/pedestriancost.cc +++ b/src/sif/pedestriancost.cc @@ -490,7 +490,7 @@ class PedestrianCost : public DynamicCost { } virtual Cost BSSCost() const override { - return {kDefaultBssCost, kDefaultBssPenalty}; + return bike_share_cost_; }; public: diff --git a/test/astar_bikeshare.cc b/test/astar_bikeshare.cc index 141b43424f..c35356aba5 100644 --- a/test/astar_bikeshare.cc +++ b/test/astar_bikeshare.cc @@ -58,6 +58,7 @@ void test_request(const std::string& request, const std::vector& expected_route, // We mark only the maneuvers that are RentBike and ReturnBike const std::map& expected_bss_maneuver, + const std::map& expected_maneuver_types = {}, const std::map& expected_bss_ref = {}, const std::optional& expected_shape = {}) { @@ -82,7 +83,6 @@ void test_request(const std::string& request, std::vector travel_modes; std::vector route; - for (const auto& d : directions) { if (expected_shape) { EXPECT_TRUE(test::encoded_shape_equality(d.shape(), *expected_shape)) @@ -105,6 +105,11 @@ void test_request(const std::string& request, EXPECT_EQ(m.bss_info().ref(), search->second) << "bss_info.osm_node_id at " + std::to_string(idx) + " is incorrect"; } + if (!expected_maneuver_types.empty()) { + auto it_maneuver_type = expected_maneuver_types.find(idx); + EXPECT_EQ(m.type(), it_maneuver_type->second) + << "maneuver type at " + std::to_string(idx) + " is incorrect"; + } travel_modes.push_back(m.travel_mode()); std::string name; for (const auto& n : m.street_name()) { @@ -140,24 +145,44 @@ void test_request(const std::string& request, TEST(AstarBss, test_With_Mode_Changes) { std::string request = R"({"locations":[{"lat":48.864655,"lon":2.361374},{"lat":48.859608,"lon":2.36117}],"costing":"bikeshare", - "costing_options":{"pedestrian":{"bss_rent_cost":0,"bss_rent_penalty":0}, - "bicycle" :{"bss_return_cost":0,"bss_return_penalty":0}}})"; + "costing_options":{"pedestrian":{"bss_rent_cost":0,"bss_rent_penalty":0}, + "bicycle" :{"bss_return_cost":0,"bss_return_penalty":0}}})"; + std::vector expected_travel_modes{TravelMode::kPedestrian, TravelMode::kBicycle, TravelMode::kPedestrian}; std::vector expected_route{"Rue Gabriel Vicaire", "Rue Perrée", - "Rue Perrée", "Rue Caffarelli", - "Rue de Bretagne", "Rue de Turenne", - "Rue du Parc Royal", "Place de Thorigny", + "Rue Perrée", "Rue Perrée", + "Rue Caffarelli", "Rue de Bretagne", + "Rue de Turenne", "Rue du Parc Royal", + "Place de Thorigny", "Rue de la Perle", "Rue de la Perle", "Rue de la Perle"}; const std::map& expected_bss_maneuver{{2, DirectionsLeg_Maneuver_BssManeuverType_kRentBikeAtBikeShare}, - {9, DirectionsLeg_Maneuver_BssManeuverType_kReturnBikeAtBikeShare}}; - const std::map& expected_bss_ref{{2, "3006"}, {9, "3008"}}; + {10, DirectionsLeg_Maneuver_BssManeuverType_kReturnBikeAtBikeShare}}; + + const std::map + expected_maneuver_types{{0, DirectionsLeg_Maneuver_Type_kStart}, + {1, DirectionsLeg_Maneuver_Type_kLeft}, + {2, DirectionsLeg_Maneuver_Type_kTypeRentBikeAtBikeShare}, + {3, DirectionsLeg_Maneuver_Type_kRight}, + {4, DirectionsLeg_Maneuver_Type_kRight}, + {5, DirectionsLeg_Maneuver_Type_kLeft}, + {6, DirectionsLeg_Maneuver_Type_kRight}, + {7, DirectionsLeg_Maneuver_Type_kRight}, + {8, DirectionsLeg_Maneuver_Type_kSlightRight}, + {9, DirectionsLeg_Maneuver_Type_kSlightLeft}, + {10, DirectionsLeg_Maneuver_Type_kTypeReturnBikeAtBikeShare}, + {11, DirectionsLeg_Maneuver_Type_kUturnRight}, + {12, DirectionsLeg_Maneuver_Type_kDestinationRight}}; + const std::map& expected_bss_ref{{2, "3006"}, + {2, "3006"}, + {10, "3008"}, + {11, "3008"}}; test_request(request, expected_travel_modes, expected_route, expected_bss_maneuver, - expected_bss_ref); + expected_maneuver_types, expected_bss_ref); } /* @@ -168,9 +193,9 @@ TEST(AstarBss, test_BSS_mode_Without_Mode_Changes) { std::string request = R"({"locations":[{"lat":48.865020,"lon":2.369113},{"lat":48.859782,"lon":2.36101}], - "costing":"bikeshare", - "costing_options":{"pedestrian":{"bss_rent_cost":0,"bss_rent_penalty":1800}, - "bicycle" :{"bss_return_cost":0,"bss_return_penalty":1800}}})"; + "costing":"bikeshare", + "costing_options":{"pedestrian":{"bss_rent_cost":0,"bss_rent_penalty":1800}, + "bicycle" :{"bss_return_cost":0,"bss_return_penalty":1800}}})"; std::vector expected_travel_modes{TravelMode::kPedestrian}; @@ -193,9 +218,9 @@ TEST(AstarBss, test_BSS_mode_Without_Mode_Changes) { TEST(AstarBss, test_BSS_mode_Without_Mode_Changes_2) { std::string request = R"({"locations":[{"lat":48.865020,"lon":2.369113},{"lat":48.859782,"lon":2.36101}], - "costing":"bikeshare", - "costing_options":{"pedestrian":{"bss_rent_cost":1800,"bss_rent_penalty":0}, - "bicycle" :{"bss_return_cost":1800,"bss_return_penalty":0}}})"; + "costing":"bikeshare", + "costing_options":{"pedestrian":{"bss_rent_cost":1800,"bss_rent_penalty":0}, + "bicycle" :{"bss_return_cost":1800,"bss_return_penalty":0}}})"; std::vector expected_travel_modes{TravelMode::kPedestrian}; @@ -215,11 +240,12 @@ TEST(AstarBss, test_BSS_mode_Without_Mode_Changes_2) { TEST(AstarBss, test_With_Mode_Changes_2) { std::string request = R"({"locations":[{"lat":48.8601411,"lon":2.3716413},{"lat":48.8594916,"lon":2.3602581}],"costing":"bikeshare", - "costing_options":{"pedestrian":{"bss_rent_cost":0,"bss_rent_penalty":0}, - "bicycle" :{"bss_return_cost":0,"bss_return_penalty":0}}})"; + "costing_options":{"pedestrian":{"bss_rent_cost":0,"bss_rent_penalty":0}, + "bicycle" :{"bss_return_cost":0,"bss_return_penalty":0}}})"; std::vector expected_travel_modes{TravelMode::kPedestrian, TravelMode::kBicycle, TravelMode::kPedestrian}; std::vector expected_route{"Rue Pelée", + "Rue Pelée", "Rue Pelée", "Rue Alphonse Baudin", "Rue Saint-Sébastien", @@ -230,14 +256,35 @@ TEST(AstarBss, test_With_Mode_Changes_2) { "Place de Thorigny", "Rue de la Perle", "Rue de la Perle", + "Rue de la Perle", "Rue Vieille du Temple"}; const std::map& expected_bss_maneuver{{1, DirectionsLeg_Maneuver_BssManeuverType_kRentBikeAtBikeShare}, - {10, DirectionsLeg_Maneuver_BssManeuverType_kReturnBikeAtBikeShare}}; - const std::map& expected_bss_ref{{1, "11103"}, {10, "3008"}}; + {11, DirectionsLeg_Maneuver_BssManeuverType_kReturnBikeAtBikeShare}}; + + const std::map& + expected_maneuver_types{{0, DirectionsLeg_Maneuver_Type_kStart}, + {1, DirectionsLeg_Maneuver_Type_kTypeRentBikeAtBikeShare}, + {2, DirectionsLeg_Maneuver_Type_kSlightLeft}, + {3, DirectionsLeg_Maneuver_Type_kRight}, + {4, DirectionsLeg_Maneuver_Type_kLeft}, + {5, DirectionsLeg_Maneuver_Type_kRight}, + {6, DirectionsLeg_Maneuver_Type_kLeft}, + {7, DirectionsLeg_Maneuver_Type_kLeft}, + {8, DirectionsLeg_Maneuver_Type_kRight}, + {9, DirectionsLeg_Maneuver_Type_kSlightRight}, + {10, DirectionsLeg_Maneuver_Type_kSlightLeft}, + {11, DirectionsLeg_Maneuver_Type_kTypeReturnBikeAtBikeShare}, + {12, DirectionsLeg_Maneuver_Type_kLeft}, + {13, DirectionsLeg_Maneuver_Type_kLeft}, + {14, DirectionsLeg_Maneuver_Type_kDestinationLeft}}; + const std::map& expected_bss_ref{{1, "11103"}, + {2, "11103"}, + {11, "3008"}, + {12, "3008"}}; test_request(request, expected_travel_modes, expected_route, expected_bss_maneuver, - expected_bss_ref); + expected_maneuver_types, expected_bss_ref); } // When pedestrian is chosen as travel_mode, the departure edge must NOT be a bss connections edge @@ -315,6 +362,7 @@ TEST(AstarBss, test_BSSConnections_on_Pedestrian_and_Bicycle) { std::vector expected_travel_modes{TravelMode::kPedestrian, TravelMode::kBicycle, TravelMode::kPedestrian}; std::vector expected_route{"Rue Perrée", + "Rue Perrée", "Rue Perrée", "Rue Perrée", "Rue Eugène Spuller", @@ -324,19 +372,41 @@ TEST(AstarBss, test_BSSConnections_on_Pedestrian_and_Bicycle) { "Place de la République", "Boulevard de Magenta", "Rue du Château d'Eau", + "Rue du Château d'Eau", "Rue du Château d'Eau"}; const std::map& expected_bss_maneuver{{2, DirectionsLeg_Maneuver_BssManeuverType_kRentBikeAtBikeShare}, - {11, DirectionsLeg_Maneuver_BssManeuverType_kReturnBikeAtBikeShare}}; - - const std::map& expected_bss_ref{{2, "3006"}, {11, "10011"}}; + {12, DirectionsLeg_Maneuver_BssManeuverType_kReturnBikeAtBikeShare}}; + + const std::map& expected_bss_ref{{2, "3006"}, + {3, "3006"}, + {12, "10011"}, + {13, "10011"}}; + + const std::map& + expected_maneuver_types{{0, DirectionsLeg_Maneuver_Type_kStart}, + {1, DirectionsLeg_Maneuver_Type_kSlightRight}, + {2, DirectionsLeg_Maneuver_Type_kTypeRentBikeAtBikeShare}, + {3, DirectionsLeg_Maneuver_Type_kUturnRight}, + {3, DirectionsLeg_Maneuver_Type_kRight}, + {4, DirectionsLeg_Maneuver_Type_kLeft}, + {5, DirectionsLeg_Maneuver_Type_kLeft}, + {6, DirectionsLeg_Maneuver_Type_kRight}, + {7, DirectionsLeg_Maneuver_Type_kLeft}, + {8, DirectionsLeg_Maneuver_Type_kRight}, + {9, DirectionsLeg_Maneuver_Type_kContinue}, + {10, DirectionsLeg_Maneuver_Type_kLeft}, + {11, DirectionsLeg_Maneuver_Type_kSlightRight}, + {12, DirectionsLeg_Maneuver_Type_kTypeReturnBikeAtBikeShare}, + {13, DirectionsLeg_Maneuver_Type_kContinue}, + {14, DirectionsLeg_Maneuver_Type_kDestination}}; std::string expected_shape = "e~le|A_ldoCyD~IoAtCkArC]z@kBpEeAsAdArAjBqE\\{@jAsCad@ai@yAgBo@iCuF_Ua@_B[uAyQgz@i@cCwAt@mg@bXyt@b`@yCvAyBqH{EgLiCvEoD|G{\\`r@wFqHoPqTy@gAyAkBe@o@i@q@{D_CeB{@wCfC{XfVt@jCjA~Dn@xB?lBcA|BV\\f@r@wBlE"; test_request(request, expected_travel_modes, expected_route, expected_bss_maneuver, - expected_bss_ref, expected_shape); + expected_maneuver_types, expected_bss_ref, expected_shape); } class AstarBSSTest : public thor::AStarBSSAlgorithm { diff --git a/valhalla/odin/maneuversbuilder.h b/valhalla/odin/maneuversbuilder.h index 9a97cc6e75..5eeb538d33 100644 --- a/valhalla/odin/maneuversbuilder.h +++ b/valhalla/odin/maneuversbuilder.h @@ -79,6 +79,7 @@ class ManeuversBuilder { void CreateDestinationManeuver(Maneuver& maneuver); void CreateStartManeuver(Maneuver& maneuver); + void AddBssManeuver(Maneuver& maneuver, const DirectionsLeg_Maneuver_Type& type, int node_index); void InitializeManeuver(Maneuver& maneuver, int node_index); @@ -87,6 +88,8 @@ class ManeuversBuilder { void FinalizeManeuver(Maneuver& maneuver, int node_index); void SetManeuverType(Maneuver& maneuver, bool none_type_allowed = true); + void UpdateBssManeuver(Maneuver& maneuver, int node_index); + float bike_share_cost(valhalla::Costing_Type costing_type, int node_index) const; void SetSimpleDirectionalManeuverType(Maneuver& maneuver, EnhancedTripLeg_Edge* prev_edge, @@ -94,6 +97,8 @@ class ManeuversBuilder { DirectionsLeg_Maneuver_CardinalDirection DetermineCardinalDirection(uint32_t heading); + bool CanRentBikeAtBikeShare(int node_index); + bool CanReturnBikeAtBikeShare(int node_index); bool CanManeuverIncludePrevEdge(Maneuver& maneuver, int node_index); bool IncludeUnnamedPrevEdge(int node_index, diff --git a/valhalla/odin/narrative_dictionary.h b/valhalla/odin/narrative_dictionary.h index cb279803c6..c6b2aa291d 100644 --- a/valhalla/odin/narrative_dictionary.h +++ b/valhalla/odin/narrative_dictionary.h @@ -84,6 +84,7 @@ constexpr auto kEnterBuildingKey = "instructions.enter_building"; constexpr auto kExitBuildingKey = "instructions.exit_building"; constexpr auto kPosixLocaleKey = "posix_locale"; constexpr auto kLevelChangeKey = "instructions.level_change"; +constexpr auto kBikeShareVerbalKey = "instructions.bike_share_verbal"; // Variable keys constexpr auto kPhrasesKey = "phrases"; @@ -115,6 +116,10 @@ constexpr auto kStepsIndex = 4; constexpr auto kBridgeIndex = 5; constexpr auto kTunnelIndex = 6; +// Bike Share Verbal indexes +constexpr auto kBikeShareRentIndex = 0; +constexpr auto kBikeShareReturnIndex = 1; + // object label indexes constexpr auto kGateIndex = 0; constexpr auto kBollardIndex = 1; @@ -406,6 +411,9 @@ class NarrativeDictionary { // Level Change PhraseSet level_change_subset; + // Bike Share Verbal + PhraseSet bike_share_verbal; + // Enter Building EnterBuildingSubset enter_building_subset; diff --git a/valhalla/odin/narrativebuilder.h b/valhalla/odin/narrativebuilder.h index 2939998d37..8f19fc7cbc 100644 --- a/valhalla/odin/narrativebuilder.h +++ b/valhalla/odin/narrativebuilder.h @@ -419,6 +419,8 @@ class NarrativeBuilder { std::string FormExitBuildingInstruction(Maneuver& maneuver); + std::string FormBikeShareInstruction(Maneuver& maneuver); + std::string FormGenericLevelChangeInstruction(Maneuver& maneuver); /////////////////////////////////////////////////////////////////////////////