Esse cenário otimiza a ordem das paradas atribuídas a um veículo com parâmetros de custo simples. Esse é o modo mais simples de operação da otimização de rotas e garante que todas as paradas sejam visitadas dentro do período especificado.
O exemplo a seguir ilustra um cenário básico com um veículo e três entregas, todas originadas de um único local chamado depósito.
Confira um exemplo de solicitação
{ "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 solicitação da otimização de rotas
Como mencionado na Visão geral, as propriedades mais importantes da solicitação de otimização de rotas são vehicles
e shipments
.
Além de um veículo e das remessas, a solicitação inclui os seguintes campos:
Polilinhas
populatePolylines
e populateTransitionPolylines
especificam se a otimização de rotas precisa retornar polilinhas.
O serviço codifica polilinhas usando o codec de polilinhas JS do Maps, que representa dados binários de polilinhas usando caracteres ASCII imprimíveis. Use o Utilitário interativo de codificação de polilinhas para visualizar os caminhos calculados pela Otimização de rotas. O exemplo neste guia define populatePolylines
e populateTransitionPolylines
como "true", mas outros guias definem como "false" para reduzir o tamanho da resposta.
Consulte Formato do algoritmo de polilinhas codificadas para ver uma descrição do formato de codificação.
Restrições de tempo globais
model.globalStartTime
e model.globalEndTime
são definidos como um período arbitrário de 24 horas. Isso facilita a interpretação dos carimbos de data/hora de saída.
Visitar locais
A solicitação de exemplo usa apenas model.shipments[].pickups[].arrivalLocation
e
model.shipments[].deliveries[].arrivalLocation
. Há também uma propriedade departureLocation
para situações em que o veículo sai de um ponto diferente de onde chega, como um estacionamento com uma entrada em um lado do prédio e uma saída em outro. Neste e nos próximos guias, vamos considerar que os pontos de chegada e partida são os mesmos.
Arrival e departure waypoint
também existem como alternativa a latLng
.
Os campos Waypoint
aceitam o uso de IDs de lugar do Google como alternativa a LatLng
e também podem especificar os títulos dos veículos. Consulte a documentação de referência (REST, gRPC) para mais detalhes.
Restrições no exemplo
Esse cenário restringe o otimizador de várias maneiras:
- Toda a atividade precisa ser concluída entre os horários de início e término globais. Nesse cenário, os horários de início e término são uma restrição muito flexível devido à proximidade das remessas e à ampla janela de tempo global.
- Todas as remessas precisam ser concluídas. Esse é o comportamento padrão quando
os custos de penalidade não são especificados em
shipments
. costPerKilometer
ecostPerHour
estão definidos no veículo.
Os custos são abordados em Parâmetros do modelo de custo.
Propriedades de resposta da otimização de rotas
Conferir uma resposta ao exemplo de solicitação
{ "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 } } }
A resposta da otimização de rotas inclui um campo routes
de nível superior que representa as rotas propostas, com uma rota por veículo. Como a solicitação de exemplo neste guia especifica apenas um veículo, routes
inclui uma mensagem ShipmentRoute
.
Propriedades de ShipmentRoute
As duas propriedades mais importantes para o tipo de mensagem ShipmentRoute
são visits
e transitions
.
Cada Visit
representa a conclusão de uma coleta ou entrega de um dos VisitRequest
s da mensagem de solicitação. Uma visita é um trabalho atribuído a um veículo para ser concluído em algum lugar e horário.
Cada Transition
representa o veículo viajando de um local para o próximo. As transições podem ocorrer entre um par de pontos de partida, um local de visita e o ponto final do veículo.
Para reconstruir o trajeto completo do veículo, é necessário combinar o visits
e o transitions
do ShipmentRoute
. A combinação de campos em uma progressão de atividade do veículo é semelhante a esta:
request.vehicles[0].startLocation -> transitions[0] -> visits[0] ->
transitions[1] -> visits[1] -> transitions[2] -> ... -> visits[3] ->
transitions[4] -> request.vehicles[0].endLocation
Um ShipmentRoute
sempre tem um transitions
a mais do que visits
, já que o veículo precisa viajar do local de início até a primeira visita no começo do trajeto e da última visita até o local de término no final do trajeto. Se o veículo não tiver um local de início ou de fim, ainda haverá um transitions
a mais do que visits
, porque o local da primeira ou da última visita será usado como o local de início ou de fim do veículo, respectivamente.
Neste exemplo, as três primeiras visitas de coleta têm transições entre elas com distância e duração zero porque todas as três coletas compartilham o mesmo local na solicitação.
Consulte a documentação de referência do ShipmentRoute
(REST, gRPC) para mais detalhes.
Otimização simples da ordem dos pontos de parada
Como demonstra este exemplo, a Otimização de rotas modela as visitas como propriedades de
entregas e não tem uma noção de pontos de passagem ou paradas como uma entidade
independente. No entanto, é possível representar paradas ou pontos de passagem como remessas
com exatamente um VisitRequest
como coleta ou entrega. O veículo ainda precisa receber um costPerHour
ou costPerKilometer
para que o otimizador encontre um trajeto ideal, e não apenas um trajeto possível.