Ten scenariusz optymalizuje kolejność przystanków przypisanych do pojazdu z prostymi parametrami dotyczącymi kosztów. Jest to najprostszy tryb działania optymalizacji trasy, który gwarantuje, że wszystkie przystanki zostaną odwiedzone w określonym czasie.
Poniższy przykład ilustruje podstawowy scenariusz z jednym pojazdem i 3 przesyłkami, z których wszystkie pochodzą z jednej lokalizacji zwanej depozytem.
Zobacz 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 trasy
Jak wspomnieliśmy w sekcji Omówienie, najważniejsze właściwości żądania optymalizacji trasy to vehicles
i shipments
.
Oprócz pojazdu i przesyłek żądanie zawiera te pola:
Linie łamane
populatePolylines
i populateTransitionPolylines
określają, czy optymalizacja trasy ma zwracać linie łamane.
Usługa koduje linie łamane za pomocą kodeka linii łamanych Maps JS, który reprezentuje dane binarnej linii łamanej przy użyciu możliwych do wydrukowania znaków ASCII. Aby zwizualizować ścieżki obliczone przez optymalizację trasy, możesz użyć interaktywnego kodera Polyline Encoder. Przykład w tym przewodniku ustawia wartość populatePolylines
i populateTransitionPolylines
na wartość true, ale inne przewodniki mają ustawioną wartość Fałsz, co zmniejsza rozmiar odpowiedzi.
Opis formatu kodowania znajdziesz w sekcji Format algorytmu łamanego zakodowanego.
Globalne ograniczenia czasowe
model.globalStartTime
i model.globalEndTime
mają ustawiony dowolny okres 24-godzinny. Ułatwia to interpretację sygnatur czasowych wyjściowych.
Odwiedź lokalizacje
W przykładowym żądaniu są używane tylko właściwości model.shipments[].pickups[].arrivalLocation
i model.shipments[].deliveries[].arrivalLocation
. Istnieje również właściwość departureLocation
obowiązująca w sytuacjach, gdy pojazd wyjeżdża z innego miejsca niż przyjechał, np. w parkingu z wejściem po jednej stronie budynku, a wyjściem z drugiej. W tym i kolejnych przewodnikach punkty przyjazdu i wyjazdu są takie same.
Przyjazd i wylot waypoint
jest również alternatywą dla latLng
.
Pola Waypoint
obsługują identyfikatory Miejsc Google jako alternatywę dla pola LatLng
i mogą też określać nagłówki pojazdów. Więcej informacji znajdziesz w dokumentacji referencyjnej (REST, gRPC).
Ograniczenia w przykładzie
Ten scenariusz ogranicza optymalizatora na kilka sposobów:
- Cała aktywność musi być wykonana między globalnym czasem rozpoczęcia a zakończeniem. W tym scenariuszu czas rozpoczęcia i zakończenia jest bardzo rygorystycznym ograniczeniem ze względu na bliskość bliskości dostawy i szerokiego globalnego przedziału czasu.
- Wszystkie przesyłki muszą zostać zrealizowane. Jest to działanie domyślne, gdy koszty karne nie są określone w
shipments
. costPerKilometer
icostPerHour
są ustawione w pojeździe.
Koszty są określone w parametrach modelu kosztu.
Właściwości odpowiedzi na potrzeby optymalizacji trasy
Wyświetlanie odpowiedzi na przykładowe żądanie
{ "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ź dotycząca optymalizacji trasy zawiera pole routes
najwyższego poziomu reprezentujące proponowane trasy z jedną trasą dla każdego pojazdu. Przykładowe żądanie w tym przewodniku dotyczy tylko 1 pojazdu, dlatego routes
zawiera 1 komunikat ShipmentRoute
.
ShipmentRoute
miejsca zakwaterowania
Dwie najważniejsze właściwości typu wiadomości ShipmentRoute
to visits
i transitions
.
Każdy znak Visit
oznacza zakończenie odbioru lub dostawy z jednego z VisitRequest
wiadomości z prośbą. Wizyta to w praktyce przydzielane miejsce i czas
do wykonania przez pojazd.
Każdy symbol Transition
oznacza pojazd podróżujący z jednej lokalizacji do następnej. Przejścia mogą wystąpić między parą punktu początkowego pojazdu, lokalizacji wizyty i punktu końcowego pojazdu.
Aby odtworzyć pełną trasę pojazdu, należy połączyć punkty visits
i transitions
na linii ShipmentRoute
. Połączenie pól w postępach
aktywności pojazdów 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
ShipmentRoute
ma zawsze o 1 element transitions
więcej niż visits
, ponieważ pojazd musi dojechać z miejsca początkowego do pierwszego na początku trasy, a od ostatniego do ostatniego miejsca na końcu trasy. Jeśli pojazd nie ma określonej lokalizacji początkowej lub końcowej, nadal będzie o 1 transitions
więcej niż visits
, ponieważ jako lokalizacja początkowa lub końcowa pojazdu używana jest odpowiednio lokalizacja dotycząca pierwszej lub ostatniej wizyty.
W tym przykładzie w przypadku pierwszych 3 wizyt z odbiorem występują między nimi przejścia z zerową odległością i czasem trwania, ponieważ wszystkie 3 punkty odbioru znajdują się w tej samej lokalizacji w żądaniu.
Więcej informacji znajdziesz w dokumentacji referencyjnej ShipmentRoute
(REST, gRPC).
Prosta optymalizacja kolejności punktów pośrednich
Ten przykład pokazuje, że modele optymalizacji trasy wizyty są właściwościami statków i nie mają pojęcia punktów na trasie ani przystanków jako niezależnej jednostki. Przystanki lub punkty na trasie mogą jednak być przedstawiane jako przesyłki z jednym atrybutem VisitRequest
jako odbiór lub dostawa. Pojazd nadal musi mieć przypisaną costPerHour
lub costPerKilometer
, aby optymalizator mógł wybrać optymalną trasę (zamiast znaleźć jakąkolwiek możliwą trasę).