Ten scenariusz optymalizuje kolejność przystanków przypisaną do pojazdu za pomocą prostych parametrów kosztów. To najprostszy tryb optymalizacji trasy, który zapewnia, że wszystkie przystanki zostaną odwiedzone we wskazanym okresie.
Poniższy przykład przedstawia podstawowy scenariusz z 1 pojazdem i 3 przesyłkami, które pochodzą z jednej lokalizacji nazywanej 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 trasy
Jak wspomnieliśmy w sekcji Omówienie, najważniejsze właściwości prośby o optymalizację trasy to vehicles
i shipments
.
Oprócz pojazdu i przesyłek żądanie zawiera te pola:
Linie łamane
populatePolylines
i populateTransitionPolylines
określają, czy optymalizacja tras ma zwracać linie łamane.
Usługa koduje Polylines za pomocą kodeka łamanego Map Google JS, który reprezentuje dane binarnych linii łamanych za pomocą możliwych do wydrukowania znaków ASCII. Aby zwizualizować ścieżki wygenerowane przez optymalizację tras, możesz użyć narzędzia interaktywnego kodera Polyline. W przykładzie w tym przewodniku ustawiamy wartości populatePolylines
i populateTransitionPolylines
na „true”, a inne ustawiają wartość „false” (fałsz), aby zmniejszyć rozmiar odpowiedzi.
Opis formatu kodowania znajdziesz w sekcji Format algorytmu kodowania łamanego kodu.
Globalne ograniczenia czasowe
Parametry model.globalStartTime
i model.globalEndTime
są ustawione na dowolny 24-godzinny okres. Dzięki temu wyjściowe sygnatury czasowe są łatwiejsze do interpretacji.
Odwiedź lokalizacje
Przykładowe żądanie używa tylko właściwości model.shipments[].pickups[].arrivalLocation
i model.shipments[].deliveries[].arrivalLocation
. Właściwość departureLocation
występuje też w sytuacjach, gdy pojazd wyjeżdża z innego punktu niż tam, gdzie się pojawia. Przykładem może być kompleks parkingowy z wejściem po jednej stronie budynku i wyjazdem po drugiej. W tym i kolejnych przewodnikach zakłada się, że miejsca przyjazdu i odjazdu są takie same.
waypoint
– przyloty i wyloty to także alternatywa dla linii latLng
.
Pola Waypoint
obsługują używanie identyfikatorów Miejsc Google jako alternatywy dla pola LatLng
. Mogą też służyć do określania kierunku pojazdów. Więcej informacji znajdziesz w dokumentacji (REST, gRPC).
Ograniczenia w przykładzie
W tym scenariuszu działanie optymalizatora jest ograniczone na kilka sposobów:
- Wszystkie działania muszą zostać ukończone między globalną godziną rozpoczęcia a zakończenia. W tym scenariuszu czasy rozpoczęcia i zakończenia są bardzo restrykcyjne ze względu na bliskość przesyłek i szeroki globalny przedział czasowy.
- Wszystkie przesyłki muszą zostać zrealizowane. Jest to działanie domyślne, gdy w dniu
shipments
koszty karne nie są określone. - W pojeździe ustawiono
costPerKilometer
icostPerHour
.
Informacje na temat kosztów można znaleźć w sekcji Parametry modelu kosztu.
Właściwości odpowiedzi optymalizacji trasy
Zobacz odpowiedź 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, które reprezentuje proponowane trasy z 1 trasą na pojazd. Przykładowe żądanie w tym przewodniku wskazuje tylko 1 pojazd, więc 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 element Visit
oznacza zakończenie odbioru lub dostawy w jednym z elementów VisitRequest
wiadomości. Wizyta to tak zwane zadanie, które
pojazd może wykonać w określonym miejscu i o czasie.
Każdy Transition
oznacza pojazd podróżujący z jednego miejsca do następnego. Przejścia mogą wystąpić między parą punktu początkowego pojazdu, lokalizacji wizyty i punktu końcowego pojazdu.
Aby można było odtworzyć pełną trasę pojazdu, visits
i transitions
pojazdu ShipmentRoute
muszą być połączone. Połączenie pól w postęp działań związanych z pojazdem 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
Samochód ShipmentRoute
ma zawsze o jeden więcej transitions
niż visits
, ponieważ pojazd musi pokonać trasę od miejsca początkowego do pierwszego przejazdu na początku trasy oraz od ostatniego wizyty do miejsca zakończenia na końcu trasy. Jeśli pojazd nie ma określonej lokalizacji początkowej lub końcowej, nadal będzie mieć o 1 więcej wyświetleń transitions
niż visits
, ponieważ lokalizacja początkowa lub końcowa będzie używana odpowiednio jako lokalizacja początkowa lub końcowa.
W tym przykładzie pierwsze 3 wizyty z odbiorem przechodzą między nimi przy zerowej odległości i czasie trwania, ponieważ wszystkie 3 odbiory mają tę samą lokalizację w żądaniu.
Więcej informacji znajdziesz w dokumentacji referencyjnej ShipmentRoute
(REST, gRPC).
Prosta optymalizacja kolejności punktów pośrednich
Jak pokazujemy w tym przykładzie, optymalizacja tras modeluje wizyty jako właściwości przesyłki i nie uwzględnia punktów pośrednich ani przystanków jako niezależnych elementów. Można jednak przedstawić przystanki lub punkty pośrednie jako przesyłki z dokładnie jednym elementem VisitRequest
jako odbiorem lub dostawą. Pojazd musi mieć przypisany costPerHour
lub costPerKilometer
, aby optymalizator mógł znaleźć optymalną trasę (a nie możliwą trasę).