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 dos envios 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. costPerKilometerecostPerHourestã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 VisitRequests 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 a rota completa 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 é usado como 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 referência como remessas
com exatamente um VisitRequest como uma coleta ou entrega. O veículo ainda precisa receber um costPerHour ou costPerKilometer para que o otimizador encontre um trajeto ideal, e não qualquer trajeto possível.