En esta situación, se optimiza el orden de las paradas asignadas a un vehículo con parámetros de costo simples. Este es el modo más sencillo 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 embarques, todos provenientes de una sola ubicación llamada depósito.
Consulta 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 solicitud de optimización de rutas
Como se menciona en la Descripción general, las propiedades más importantes de la solicitud de optimización de rutas 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 la optimización de rutas debe mostrar polilíneas.
El servicio codifica las polilíneas con el códec de polilíneas de Maps JS, que representa los datos de polilíneas binarias con caracteres ASCII imprimibles. Puedes usar la utilidad codificadora de polilínea interactiva para visualizar las rutas que calcula la optimización de rutas. En el ejemplo de esta guía, se establece 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
En la solicitud de ejemplo, solo se usan 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 complejo de estacionamiento con una entrada en un lado del edificio y una salida en otro. En esta guía y las posteriores, se supone que los puntos de llegada y salida son los mismos.
Los waypoint
de llegada y salida también existen como alternativa a latLng
.
Los campos Waypoint
admiten el uso de IDs de Google Places como alternativa a LatLng
y también pueden especificar los rumbos del vehículo. Consulta la documentación de referencia (REST, gRPC) para obtener más detalles.
Restricciones en el ejemplo
Esta situación limita al optimizador de varias maneras:
- Toda la actividad debe completarse entre las horas de inicio y finalización globales. En esta situación, las horas de inicio y finalización son una restricción muy laxa, dada la proximidad de los envíos y el amplio período global.
- Todos los envíos deben estar completos. Este es el comportamiento predeterminado cuando no se especifican los costos de penalización en
shipments
. costPerKilometer
ycostPerHour
se configuran en el vehículo.
Los costos se abordan en Parámetros del modelo de costos.
Propiedades de respuesta de la optimización de rutas
Cómo 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 la optimización de rutas incluye un campo routes
de nivel superior que representa las rutas propuestas, con una ruta por vehículo. Como la solicitud de ejemplo de esta guía solo especifica 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
del mensaje de solicitud. Una visita es una tarea asignada de manera efectiva para que un vehículo la complete en un lugar y momento determinado.
Cada Transition
representa el vehículo que viaja de una ubicación a la siguiente. Las transiciones pueden ocurrir entre un par de puntos de partida del vehículo, una ubicación de visita y el destino del vehículo.
Para reconstruir la ruta completa del vehículo, se deben combinar visits
y transitions
de ShipmentRoute
. La combinación de campos en una progresión de la 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 visits
, ya que el vehículo debe viajar desde su ubicación de partida hasta su primera visita al comienzo de la ruta y desde su última visita hasta su ubicación de destino al final de la ruta. Si el vehículo no tiene una ubicación de inicio o finalización, habrá 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 partida tienen transiciones entre ellas con cero distancia y duración porque los tres puntos de partida 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 los puntos de referencia
Como se muestra en este ejemplo, la optimización de rutas modela las visitas como propiedades de los envíos y no tiene una noción de puntos de referencia o paradas como una entidad independiente. Sin embargo, es posible representar paradas o puntos de referencia como envíos con exactamente un VisitRequest
como punto de partida o destino. Se debe asignar un costPerHour
o costPerKilometer
al vehículo para que el optimizador encuentre una ruta óptima (en lugar de encontrar cualquier ruta factible).