Ten scenariusz optymalizuje kolejność przystanków przypisanych do pojazdu za pomocą prostych parametrów kosztów. Jest to najprostszy tryb działania optymalizacji trasy, który zapewnia odwiedzenie wszystkich przystanków w określonym przedziale czasu.
Poniższy przykład ilustruje podstawowy scenariusz z 1 pojazdem i 3 przesyłkami, które pochodzą z jednego miejsca zwanego depot.
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 tras
Jak wspomnieliśmy w omówieniu, 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
Parametry populatePolylines
i populateTransitionPolylines
określają, czy funkcja Route
Optimization ma zwracać linie łamane.
Usługa koduje linie łamane za pomocą kodeka linii łamanych w Mapach Google w JavaScript, który reprezentuje binarne dane linii łamanych za pomocą znaków ASCII możliwych do wydrukowania. Za pomocą interaktywnego narzędzia do kodowania polilinii możesz wizualizować ścieżki obliczone przez optymalizację trasy. W przykładzie w tym przewodniku wartości populatePolylines
i populateTransitionPolylines
są ustawione na „true”, ale w innych przewodnikach są ustawione na „false”, aby zmniejszyć rozmiar odpowiedzi.
Opis formatu kodowania znajdziesz w sekcji Format algorytmu zakodowanej linii łamanej.
Globalne ograniczenia czasowe
Aplikacje model.globalStartTime
i model.globalEndTime
są ustawione na dowolny 24-godzinny okres. Ułatwia to interpretację sygnatur czasowych danych wyjściowych.
Odwiedzanie lokalizacji
Przykładowe żądanie używa tylko parametrów model.shipments[].pickups[].arrivalLocation
i model.shipments[].deliveries[].arrivalLocation
. Jest też właściwość
departureLocation
, która przydaje się w sytuacjach, gdy pojazd wyjeżdża z innego miejsca niż to, do którego przyjeżdża, np. w przypadku parkingu z wejściem po jednej stronie budynku i wyjściem po drugiej. W tym i kolejnych przewodnikach zakłada się, że punkt przyjazdu i odjazdu są takie same.
Właściwości przyjazd i wyjazd waypoint
są też dostępne jako alternatywa dla właściwości latLng
.
Pola Waypoint
obsługują używanie identyfikatorów miejsc w Google jako alternatywy dla LatLng
, a także mogą określać kierunek jazdy pojazdu. Więcej informacji znajdziesz w dokumentacji referencyjnej (REST, gRPC).
Ograniczenia w przykładzie
Ten scenariusz ogranicza optymalizator na kilka sposobów:
- Wszystkie działania muszą zostać wykonane między globalną godziną rozpoczęcia a globalną godziną zakończenia. W tym przypadku czas rozpoczęcia i zakończenia jest bardzo luźnym ograniczeniem ze względu na bliskość przesyłek i szerokie okno czasowe na całym świecie.
- Wszystkie dostawy muszą zostać zrealizowane. Jest to domyślne działanie, gdy koszty kary nie są określone w
shipments
. costPerKilometer
icostPerHour
są ustawione w pojeździe.
Koszty są omówione w sekcji Parametry modelu kosztów.
Właściwości odpowiedzi optymalizacji tras
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ź Optymalizacji trasy zawiera pole najwyższego poziomu routes
, które reprezentuje proponowane trasy, po jednej na pojazd. Ponieważ przykładowe żądanie w tym przewodniku określa tylko 1 pojazd, routes
zawiera 1 wiadomość ShipmentRoute
.
ShipmentRoute
miejsca zakwaterowania
Dwie najważniejsze właściwości typu wiadomości ShipmentRoute
to visits
i transitions
.
Każdy element Visit
oznacza ukończenie odbioru lub dostawy z jednego z VisitRequest
w wiadomości z prośbą. Wizyta to przypisana praca, którą pojazd ma wykonać w określonym miejscu i czasie.
Każdy symbol Transition
oznacza pojazd przemieszczający się z jednej lokalizacji do drugiej. Przejścia mogą występować między parą punktów: punktem początkowym pojazdu, lokalizacją wizyty i punktem końcowym pojazdu.
Aby odtworzyć pełną trasę pojazdu, należy połączyć ShipmentRoute
z visits
i transitions
. Połączenie pól w ciąg 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
Liczba ShipmentRoute
jest zawsze o 1 większa od liczby visits
, ponieważ na początku trasy pojazd musi dojechać z lokalizacji początkowej do pierwszego punktu, a na końcu trasy z ostatniego punktu do lokalizacji końcowej.transitions
Jeśli pojazd nie ma lokalizacji początkowej ani końcowej, będzie o 1 więcej transitions
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 wizyty w miejscu odbioru mają przejścia między nimi o zerowej odległości i czasie trwania, ponieważ wszystkie 3 miejsca odbioru mają w żądaniu tę samą lokalizację.
Więcej informacji znajdziesz w ShipmentRoute
dokumentacji referencyjnej (REST, gRPC).
Prosta optymalizacja kolejności punktów
Jak pokazuje ten przykład, model optymalizacji trasy traktuje wizyty jako właściwości przesyłek i nie ma pojęcia o punktach pośrednich ani przystankach jako niezależnych jednostkach. Można jednak przedstawić przystanki lub punkty pośrednie jako przesyłki
z dokładnie jednym VisitRequest
jako odbiór lub dostawę. Pojazd musi mieć przypisany stan costPerHour
lub costPerKilometer
, aby optymalizator mógł znaleźć optymalną trasę (a nie tylko dowolną możliwą trasę).