Este cenário otimiza a ordem das paradas atribuídas a um veículo com parâmetros de custo simples. Esse é o modo mais simples da operação de otimização de trajetos 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 remessas, todas com origem em um único local, chamado depot.
Ver 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
Conforme mencionado na seção 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 remessas, a solicitação inclui os seguintes campos:
Polilinhas
populatePolylines
e populateTransitionPolylines
especificam se a otimização de rotas deve retornar polilinhas.
O serviço codifica as polilinhas usando o codec de polilinhas Maps JS, que representa dados de polilinhas binárias usando caracteres ASCII para impressão. Você pode usar o Utilitário interativo de codificação de polilinhas para visualizar os caminhos calculados pela otimização de rota. O exemplo neste guia define populatePolylines
e populateTransitionPolylines
como verdadeiros, mas outros guias os definem como falsos para reduzir o tamanho da resposta.
Consulte Formato de 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
O exemplo de solicitação 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 ele chega, como um complexo de estacionamento com uma entrada em um lado do edifício e uma saída em outro. Neste guia e nos próximos, presume-se que os pontos de chegada e partida sejam os mesmos.
As opções de chegada e partida (waypoint
) também são uma alternativa ao latLng
.
Os campos Waypoint
são compatíveis com o uso de IDs de lugares do Google como alternativa ao LatLng
e também podem especificar a direção de veículos. Consulte a documentação de referência
(REST, gRPC) para mais detalhes.
Restrições no exemplo
Este cenário restringe o otimizador de várias maneiras:
- Todas as atividades precisam ser concluídas entre os horários globais de início e término. Nesse cenário, os horários de início e término são uma restrição muito flexível, dada a proximidade das remessas e a ampla janela de tempo global.
- Todos os envios precisam ser concluídos. Esse é o comportamento padrão quando
os custos de multa 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
Veja 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 trajetos inclui um campo routes
de nível superior que representa os trajetos propostos, com um trajeto por veículo. Como o exemplo de solicitação neste guia especifica apenas um veículo, routes
inclui uma mensagem ShipmentRoute
.
ShipmentRoute
propriedades
As duas propriedades mais importantes para o tipo de mensagem ShipmentRoute
são
visits
e transitions
.
Cada Visit
representa a conclusão de uma retirada ou entrega de um dos
VisitRequest
s da mensagem de solicitação. Uma visita é um trabalho a ser realizado
por um veículo em determinado lugar e hora.
Cada Transition
representa o veículo que viaja de um local para o
outro. Podem ocorrer transições entre o ponto de partida, o local de visita e o endpoint do veículo.
Para reconstruir o trajeto completo do veículo, os visits
e transitions
do ShipmentRoute
precisam ser combinados. A combinação de campos em uma progressão de atividade do veículo tem a seguinte aparência:
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 início
do trajeto, e da última visita até o local final, no final do
trajeto. Se o veículo não tiver um local de partida ou de chegada, ainda haverá um transitions
a mais do que visits
, porque o local da primeira ou da última visita é usado como o local de início ou término do veículo, respectivamente.
Neste exemplo, as três primeiras visitas de retirada têm transições entre elas com distância e duração zero, porque as três embarques compartilham o mesmo local na solicitação.
Consulte a documentação de referência ShipmentRoute
(REST, gRPC) para mais detalhes.
Otimização simples da ordem dos waypoints
Como demonstrado neste exemplo, a otimização de trajetos modela as visitas como propriedades de remessas e não tem uma noção de waypoints ou paradas como uma entidade independente. No entanto, é possível representar paradas ou waypoints como remessas
com exatamente um VisitRequest
como retirada ou entrega. O veículo ainda precisa
receber um costPerHour
ou um costPerKilometer
para que o otimizador encontre uma
rota ideal (em vez de encontrar uma rota viável).