W tym scenariuszu kolejność przystanków przypisanych do pojazdu jest optymalizowana za pomocą prostych parametrów kosztu. Jest to najprostszy tryb działania optymalizacji trasy. Zapewnia, że wszystkie przystanki są odwiedzane w określonym przedziale czasu.
Ten przykład przedstawia podstawowy scenariusz z jednym pojazdem i 3 przesyłkami, które pochodzą z jednego miejsca zwanego depot.
Przykładowe żądanie
{ "populatePolylines": true, "populateTransitionPolylines": true, "model": { "globalStartTime": "2023-01-13T16:00:00-08:00", "globalEndTime": "2023-01-14T16:00:00-08:00", "shipments": [ { "deliveries": [ { "arrivalLocation": { "latitude": 37.789456, "longitude": -122.390192 }, "duration": "250s" } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ] }, { "deliveries": [ { "arrivalLocation": { "latitude": 37.789116, "longitude": -122.395080 }, "duration": "250s" } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ] }, { "deliveries": [ { "arrivalLocation": { "latitude": 37.795242, "longitude": -122.399347 }, "duration": "250s" } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ] } ], "vehicles": [ { "endLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "startLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "costPerKilometer": 10.0, "costPerHour": 40.0 } ] } }
Pola żądania optymalizacji tras
Jak wspomniano w sekcji Omówienie, najważniejsze właściwości żądania usługi Route Optimization to vehicles
i shipments
.
Oprócz pojazdu i przesyłek prośba zawiera te pola:
Linie łamane
Parametry populatePolylines
i populateTransitionPolylines
określają, czy metoda RouteOptimization powinna zwracać ścieżki złożone.
Usługa koduje linie łamane za pomocą kodeka linii łamanych Maps JS, który reprezentuje binarne dane linii łamanej za pomocą drukowalnych znaków ASCII. Aby wizualizować ścieżki obliczone przez narzędzie Route Optimization, możesz użyć interaktywnej aplikacji do kodowania łańcuchów znaków. W tym przykładzie wartości populatePolylines
i populateTransitionPolylines
są ustawione na „PRAWDA”, ale w innych przewodnikach mają one wartość „FAŁSZ”, aby zmniejszyć rozmiar odpowiedzi.
Opis formatu kodowania znajdziesz w artykule Encoded Polyline Algorithm Format (format algorytmu zakodowanej polilinii).
Ograniczenia czasowe na całym świecie
Aplikacje model.globalStartTime
i model.globalEndTime
są ustawione na dowolny 24-godzinny okres. Dzięki temu łatwiej jest interpretować sygnatury czasowe na wyjściu.
Odwiedź lokalizacje
W tym przykładzie żądaniu towarzyszą tylko parametry model.shipments[].pickups[].arrivalLocation
i model.shipments[].deliveries[].arrivalLocation
. Dostępna jest też właściwość departureLocation
, która służy do określania sytuacji, gdy pojazd odjeżdża z miejsca, do którego przyjechał, w innym miejscu niż to, z którego przyjechał, np. gdy kompleks parkingowy ma wejście po jednej stronie budynku, a wyjście po drugiej. W tym i kolejnych przewodnikach punkty przyjazdu i odjazdu są takie same.
Właściwości przyjazdu i wyjazdu waypoint
są również dostępne jako alternatywa dla latLng
.
Pola Waypoint
obsługują identyfikatory miejsc Google jako alternatywę dla LatLng
. Można też określić kierunek jazdy pojazdu. Aby dowiedzieć się więcej, zapoznaj się z odpowiednią dokumentacją (REST, gRPC).
Ograniczenia w przykładzie
W tym scenariuszu optymalizator jest ograniczony na kilka sposobów:
- Cała aktywność musi zostać ukończona w okresie globalnego rozpoczęcia i zakończenia. W tym scenariuszu czasy rozpoczęcia i zakończenia są bardzo luźno określone ze względu na niewielką odległość między dostawami i szerokie okno czasowe na całym świecie.
- Wszystkie przesyłki muszą zostać zrealizowane. Jest to domyślne zachowanie, gdy koszty kary nie są określone w
shipments
. costPerKilometer
icostPerHour
są ustawione w pojazdach.
Koszty są omawiane w sekcji Parametry modelu kosztowego.
Właściwości odpowiedzi usługi optymalizacji tras
Zobacz odpowiedź na przykładowe zgłoszenie
{ "routes": [ { "vehicleStartTime": "2023-01-14T00:00:00Z", "vehicleEndTime": "2023-01-14T00:36:41Z", "visits": [ { "shipmentIndex": 2, "isPickup": true, "startTime": "2023-01-14T00:00:00Z", "detour": "0s" }, { "shipmentIndex": 1, "isPickup": true, "startTime": "2023-01-14T00:02:30Z", "detour": "150s" }, { "isPickup": true, "startTime": "2023-01-14T00:05:00Z", "detour": "300s" }, { "startTime": "2023-01-14T00:11:25Z", "detour": "0s" }, { "shipmentIndex": 1, "startTime": "2023-01-14T00:19:29Z", "detour": "503s" }, { "shipmentIndex": 2, "startTime": "2023-01-14T00:29:02Z", "detour": "1324s" } ], "transitions": [ { "travelDuration": "0s", "waitDuration": "0s", "totalDuration": "0s", "startTime": "2023-01-14T00:00:00Z", "routePolyline": {} }, { "travelDuration": "0s", "waitDuration": "0s", "totalDuration": "0s", "startTime": "2023-01-14T00:02:30Z", "routePolyline": {} }, { "travelDuration": "0s", "waitDuration": "0s", "totalDuration": "0s", "startTime": "2023-01-14T00:05:00Z", "routePolyline": {} }, { "travelDuration": "235s", "travelDistanceMeters": 795, "waitDuration": "0s", "totalDuration": "235s", "startTime": "2023-01-14T00:07:30Z", "routePolyline": { "points": "kvteFtfjVAA?C?C@C?A?C@AFMj@s@JKb@k@Zc@LSjA}ARWDGdAxAdAvAXa@@k@AsA\\c@FKp@_A\\c@Ze@fA{ALSFGd@o@rAgBB{BZc@" } }, { "travelDuration": "234s", "travelDistanceMeters": 793, "waitDuration": "0s", "totalDuration": "234s", "startTime": "2023-01-14T00:15:35Z", "routePolyline": { "points": "cwseFti_jVRWj@w@x@eAHLNRHJbApAHLX\\V^?@hA~AT\\PVFFDHDFJNp@~@NRLNNTFFUZIJY^Y^g@p@[`@KP{@fAEFSXe@l@c@h@WZY\\?BELk@v@MNa@l@" } }, { "travelDuration": "323s", "travelDistanceMeters": 1204, "waitDuration": "0s", "totalDuration": "323s", "startTime": "2023-01-14T00:23:39Z", "routePolyline": { "points": "cuseFhjVSTY`@Yb@GHEDIJEF]f@IJi@r@oAbBeCfDKLaApAKNQVIPKPCDQJIBIBM@iAJeALqBVC@C?A?QBYDI@C?_@Dc@FO@a@FDp@HfAHvABVDl@Dj@PpCQDiALsALAQASKwAOgBEe@COCYEa@Es@Eg@" } }, { "travelDuration": "209s", "travelDistanceMeters": 665, "waitDuration": "0s", "totalDuration": "209s", "startTime": "2023-01-14T00:33:12Z", "routePolyline": { "points": "{zteFxbajV?CAYEc@AMC_@AOAK?E?CCWAOAKCe@CY?WScDEm@d@EFA\\ENCB?XEVC^E`@EhBUVCNEB?@?\\Er@IMUe@k@k@w@AAMQa@i@SWQWMQi@u@AC?A" } } ], "routePolyline": { "points": "kvteFtfjVAA?C?C@C?A?C@AFMj@s@JKb@k@Zc@LSjA}ARWDGdAxAdAvAXa@@k@AsA\\c@FKp@_A\\c@Ze@fA{ALSFGd@o@rAgBB{BZc@RWj@w@x@eAHLNRHJbApAHLX\\V^?@hA~AT\\PVFFDHDFJNp@~@NRLNNTFFUZIJY^Y^g@p@[@KP{@fAEFSXe@l@c@h@WZY\\?BELk@v@MNa@l@STY@Yb@GHEDIJEF]f@IJi@r@oAbBeCfDKLaApAKNQVIPKPCDQJIBIBM@iAJeALqBVC@C?A?QBYDI@C?_@Dc@FO@a@FDp@HfAHvABVDl@Dj@PpCQDiALsALAQASKwAOgBEe@COCYEa@Es@Eg@?CAYEc@AMC_@AOAK?E?CCWAOAKCe@CY?WScDEm@d@EFA\\ENCB?XEVC^E`@EhBUVCNEB?@?\\Er@IMUe@k@k@w@AAMQa@i@SWQWMQi@u@AC?A" }, "metrics": { "performedShipmentCount": 3, "travelDuration": "1001s", "waitDuration": "0s", "delayDuration": "0s", "breakDuration": "0s", "visitDuration": "1200s", "totalDuration": "2201s", "travelDistanceMeters": 3457 }, "travelSteps": [ { "duration": "0s", "routePolyline": {} }, { "duration": "0s", "routePolyline": {} }, { "duration": "0s", "routePolyline": {} }, { "duration": "227s", "distanceMeters": 794, "routePolyline": { "points": "kvteFtfjVAA?C?C@C?A?C@AFMj@s@JKb@k@Zc@LSjA}ARWDGdAxAdAvAXa@@k@AsA\\c@FKp@_A\\c@Ze@fA{ALSFGd@o@rAgBB{BZc@" } }, { "duration": "233s", "distanceMeters": 791, "routePolyline": { "points": "cwseFti_jVRWj@w@x@eAHLNRHJbApAHLX\\V^?@hA~AT\\PVFFDHDFJNp@~@NRLNNTFFUZIJY^Y^g@p@[`@KP{@fAEFSXe@l@c@h@WZY\\?BELk@v@MNa@l@" } }, { "duration": "322s", "distanceMeters": 1205, "routePolyline": { "points": "cuseFhjVSTY`@Yb@GHEDIJEF]f@IJi@r@oAbBeCfDKLaApAKNQVIPKPCDQJIBIBM@iAJeALqBVC@C?A?QBYDI@C?_@Dc@FO@a@FDp@HfAHvABVDl@Dj@PpCQDiALsALAQASKwAOgBEe@COCYEa@Es@Eg@" } }, { "duration": "208s", "distanceMeters": 666, "routePolyline": { "points": "{zteFxbajV?CAYEc@AMC_@AOAK?E?CCWAOAKCe@CY?WScDEm@d@EFA\\ENCB?XEVC^E`@EhBUVCNEB?@?\\Er@IMUe@k@k@w@AAMQa@i@SWQWMQi@u@AC?A" } } ], "vehicleDetour": "2201s", "routeCosts": { "model.vehicles.cost_per_hour": 24.455555555555556, "model.vehicles.cost_per_kilometer": 34.57 }, "routeTotalCost": 59.025555555555556 } ], "totalCost": 59.025555555555556, "metrics": { "aggregatedRouteMetrics": { "performedShipmentCount": 3, "travelDuration": "1001s", "waitDuration": "0s", "delayDuration": "0s", "breakDuration": "0s", "visitDuration": "1200s", "totalDuration": "2201s", "travelDistanceMeters": 3457 }, "usedVehicleCount": 1, "earliestVehicleStartTime": "2023-01-14T00:00:00Z", "latestVehicleEndTime": "2023-01-14T00:36:41Z", "totalCost": 59.025555555555556, "costs": { "model.vehicles.cost_per_kilometer": 34.57, "model.vehicles.cost_per_hour": 24.455555555555556 } } }
Odpowiedź optymalizacji trasy zawiera pole najwyższego poziomu routes
, które reprezentuje proponowane trasy, po jednej na pojazd. Ponieważ przykładowa prośba w tym przewodniku dotyczy tylko jednego pojazdu, routes
zawiera jedną wiadomość ShipmentRoute
.
ShipmentRoute
miejsca zakwaterowania
Dwie najważniejsze właściwości w przypadku wiadomości typu ShipmentRoute
to visits
i transitions
.
Każdy element Visit
oznacza zakończenie odbioru lub dostawy z jednego z elementów VisitRequest
wiadomości z prośbą. Wizyta to przydzielone zadanie, które ma być wykonane przez pojazd w określonym miejscu i w określonym czasie.
Każdy element Transition
reprezentuje pojazd przemieszczający się z jednej lokalizacji do następnej. Przejścia mogą występować między punktem początkowym pojazdu, miejscem wizyty i punktem końcowym.
Aby odtworzyć pełną trasę przejazdu pojazdu, należy połączyć visits
i transitions
.ShipmentRoute
Połączenie pól w ramach sekwencji aktywności pojazdu wygląda tak:
request.vehicles[0].startLocation -> transitions[0] -> visits[0] ->
transitions[1] -> visits[1] -> transitions[2] -> ... -> visits[3] ->
transitions[4] -> request.vehicles[0].endLocation
W przypadku ShipmentRoute
zawsze występuje o jeden transitions
więcej niż w przypadku visits
, ponieważ pojazd musi przejechać z miejsca początkowego do pierwszego przystanku na początku trasy i z ostatniego przystanku do miejsca docelowego na końcu trasy. Jeśli pojazd nie ma lokalizacji początkowej ani końcowej, będzie o jedną transitions
więcej niż visits
, ponieważ lokalizacja pierwszej lub ostatniej wizyty jest używana odpowiednio jako lokalizacja początkowa lub końcowa pojazdu.
W tym przykładzie pierwsze 3 przejazdy mają przejścia między sobą o zerowej odległości i czasie, ponieważ wszystkie 3 przejazdy mają tę samą lokalizację w żądaniu.
Aby dowiedzieć się więcej, zapoznaj się z dokumentacją referencyjną ShipmentRoute
(REST, gRPC).
Prosta optymalizacja kolejności punktów pośrednich
Jak widać w tym przykładzie, model optymalizacji tras traktuje wizyty jako właściwości przesyłek i nie uwzględnia punktów pośrednich ani przystanków jako niezależnych elementów. Możliwe jest jednak przedstawienie przystanków lub punktów pośrednich jako przesyłek z dokładnie 1 VisitRequest
jako odbiorem lub dostawą. Aby optymalizator mógł znaleźć optymalną trasę (a nie dowolną możliwą trasę), pojazd musi mieć przypisaną wartość costPerHour
lub costPerKilometer
.