En este caso, se optimiza el orden de las paradas asignadas a un vehículo con parámetros de costos simples. Este es el modo más simple de operación de la optimización de rutas y garantiza que se visiten todas las paradas dentro del período especificado.
En el siguiente ejemplo, se ilustra una situación básica con un vehículo y tres envíos, todos originados en una sola ubicación llamada depósito.
Ver una solicitud de ejemplo
{ "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 } ] } }
Campos de la solicitud de optimización de rutas
Como se mencionó en la Descripción general, las propiedades de solicitud de Route Optimization más importantes son vehicles
y shipments
.
Además de un vehículo y envíos, la solicitud incluye los siguientes campos:
Polilíneas
populatePolylines
y populateTransitionPolylines
especifican si RouteOptimization debe devolver polilíneas.
El servicio codifica polilíneas con el códec de polilíneas de Maps JS, que representa datos de polilíneas binarias con caracteres ASCII imprimibles. Puedes usar la utilidad de codificación de polilíneas interactivas para visualizar las rutas que calcula la Optimización de rutas. En el ejemplo de esta guía, se establecen populatePolylines
y populateTransitionPolylines
como verdaderos, pero otras guías los establecen como falsos para reducir el tamaño de la respuesta.
Consulta Formato del algoritmo de polilínea codificada para obtener una descripción del formato de codificación.
Restricciones de tiempo globales
model.globalStartTime
y model.globalEndTime
se establecen en un período arbitrario de 24 horas. Esto facilita la interpretación de las marcas de tiempo de salida.
Visitar ubicaciones
La solicitud de ejemplo solo usa model.shipments[].pickups[].arrivalLocation
y model.shipments[].deliveries[].arrivalLocation
. También hay una propiedad departureLocation
para situaciones en las que el vehículo sale de un punto diferente al que llega, como un estacionamiento con una entrada en un lado del edificio y una salida en otro. En esta y las siguientes guías, se supone que los puntos de llegada y partida son los mismos.
La llegada y la salida waypoint
también existen como alternativa a latLng
.
Los campos Waypoint
admiten el uso de IDs de lugar de Google como alternativa a LatLng
y también pueden especificar los encabezados de los vehículos. Consulta la documentación de referencia (REST, gRPC) para obtener más detalles.
Restricciones en el ejemplo
Esta situación restringe el optimizador de varias maneras:
- Todas las actividades deben completarse entre las horas de inicio y finalización globales. En este caso, las horas de inicio y finalización son una restricción muy flexible, dada la proximidad de los envíos y el amplio período global.
- Todos los envíos deben completarse. Este es el comportamiento predeterminado cuando no se especifican costos de penalización en
shipments
. costPerKilometer
ycostPerHour
están configurados en el vehículo.
Los costos se abordan en Cost Model Parameters.
Propiedades de la respuesta de Route Optimization
Ver una respuesta a la solicitud de ejemplo
{ "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 } } }
La respuesta de Route Optimization incluye un campo routes
de nivel superior que representa las rutas propuestas, con una ruta por vehículo. Dado que la solicitud de ejemplo de esta guía especifica solo un vehículo, routes
incluye un mensaje ShipmentRoute
.
ShipmentRoute
propiedades
Las dos propiedades más importantes para el tipo de mensaje ShipmentRoute
son visits
y transitions
.
Cada Visit
representa la finalización de un retiro o una entrega de uno de los VisitRequest
s del mensaje de solicitud. Una visita es un trabajo que se asigna de manera efectiva para que un vehículo lo complete en algún lugar y momento.
Cada Transition
representa el vehículo que viaja de una ubicación a la siguiente. Las transiciones pueden ocurrir entre un par de puntos: el punto de partida del vehículo, una ubicación de visita y el punto final del vehículo.
Para reconstruir la ruta completa del vehículo, se deben combinar los campos visits
y transitions
del objeto ShipmentRoute
. La combinación de campos en una progresión de actividad del vehículo se ve de la siguiente manera:
request.vehicles[0].startLocation -> transitions[0] -> visits[0] ->
transitions[1] -> visits[1] -> transitions[2] -> ... -> visits[3] ->
transitions[4] -> request.vehicles[0].endLocation
Un ShipmentRoute
siempre tiene un transitions
más que un visits
, ya que el vehículo debe viajar desde su ubicación de inicio hasta su primera visita al comienzo de la ruta y desde su última visita hasta su ubicación final al final de la ruta. Si el vehículo no tiene una ubicación de inicio o finalización, seguirá habiendo una transitions
más que visits
, ya que la ubicación de la primera o la última visita se usa como la ubicación de inicio o finalización del vehículo, respectivamente.
En este ejemplo, las primeras tres visitas de retiro tienen transiciones entre ellas con distancia y duración cero porque los tres retiros comparten la misma ubicación en la solicitud.
Consulta la documentación de referencia de ShipmentRoute
(REST, gRPC) para obtener más detalles.
Optimización simple del orden de las paradas
Como se demuestra en este ejemplo, el modelo de optimización de rutas considera las visitas como propiedades de los envíos y no tiene una noción de los puntos de ruta o las paradas como una entidad independiente. Sin embargo, es posible representar paradas o puntos de ruta como envíos con exactamente un VisitRequest
como retiro o entrega. El vehículo debe tener asignado un costPerHour
o un costPerKilometer
para que el optimizador encuentre una ruta óptima (en lugar de encontrar cualquier ruta factible).