Этот сценарий оптимизирует порядок остановок, назначенных транспортному средству, с помощью простых параметров стоимости. Это самый простой режим работы оптимизации маршрута, который гарантирует посещение всех остановок в течение указанного периода времени.
Следующий пример иллюстрирует базовый сценарий с одним транспортным средством и тремя отгрузками, все из одного места, называемого складом .
Посмотреть пример запроса
{ "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 } ] } }
Поля запроса на оптимизацию маршрута
Как упоминалось в обзоре , наиболее важными свойствами запроса оптимизации маршрута являются vehicles
и shipments
.
Помимо транспортного средства и грузов, запрос включает в себя следующие поля:
Полилинии
populatePolylines
и populateTransitionPolylines
определяют, должна ли оптимизация маршрута возвращать полилинии.
Служба кодирует полилинии с помощью кодека полилиний Maps JS, который представляет данные двоичной ломаной линии с использованием печатных символов ASCII. Вы можете использовать утилиту Interactive Polyline Encoder Utility для визуализации путей, рассчитанных с помощью оптимизации маршрута. В примере в этом руководстве populatePolylines
и populateTransitionPolylines
установлено значение true, но в других руководствах для них установлено значение false, чтобы уменьшить размер ответа.
См. Формат алгоритма кодирования ломаной линии для описания формата кодирования.
Глобальные ограничения по времени
model.globalStartTime
и model.globalEndTime
задан произвольный 24-часовой период. Это упрощает интерпретацию временных меток вывода.
Посетите локации
В примере запроса используются только model.shipments[].pickups[].arrivalLocation
и model.shipments[].deliveries[].arrivalLocation
. Существует также свойство departureLocation
для ситуаций, когда транспортное средство отправляется из другой точки, чем та, в которой оно прибывает, например, парковочный комплекс со входом с одной стороны здания и выходом с другой. В этом и последующих руководствах точки прибытия и отправления предполагаются одинаковыми.
waypoint
прибытия и отправления также существуют как альтернатива latLng
. Поля Waypoint
точек поддерживают использование идентификаторов мест Google в качестве альтернативы LatLng
, а также могут указывать направления транспортных средств. Более подробную информацию смотрите в справочной документации ( REST , gRPC ).
Ограничения в примере
Этот сценарий ограничивает оптимизатор несколькими способами:
- Все действия должны быть завершены между глобальным временем начала и окончания . В этом сценарии время начала и окончания является очень слабым ограничением, учитывая близость поставок и широкий глобальный временной интервал.
- Все поставки должны быть завершены . Это поведение по умолчанию, когда штрафные расходы не указаны в
shipments
. -
costPerKilometer
иcostPerHour
устанавливаются на транспортном средстве.
Затраты рассматриваются в параметрах модели затрат .
Свойства ответа оптимизации маршрута
Посмотреть ответ на пример запроса
{ "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 } } }
Ответ «Оптимизация маршрута» включает поле routes
верхнего уровня, в котором представлены предлагаемые маршруты, по одному маршруту на транспортное средство. Поскольку пример запроса в этом руководстве указывает только одно транспортное средство, routes
включают одно сообщение ShipmentRoute
.
Свойства ShipmentRoute
Двумя наиболее важными свойствами типа сообщений ShipmentRoute
являются visits
и transitions
.
Каждое Visit
представляет собой завершение получения или доставки одного из сообщений VisitRequest
сообщения-запроса. Посещение фактически представляет собой задание, которое транспортное средство должно выполнить в определенном месте и в определенное время.
Каждый Transition
представляет собой транспортное средство, перемещающееся из одного места в другое. Переходы могут происходить между парой начальной точки транспортного средства, местом посещения и конечной точкой транспортного средства.
Чтобы восстановить полный маршрут транспортного средства, visits
и transitions
ShipmentRoute
должны быть объединены. Объединение полей в последовательность действий транспортного средства выглядит следующим образом:
request.vehicles[0].startLocation -> transitions[0] -> visits[0] ->
transitions[1] -> visits[1] -> transitions[2] -> ... -> visits[3] ->
transitions[4] -> request.vehicles[0].endLocation
У ShipmentRoute
всегда на один transitions
больше, чем visits
, поскольку транспортное средство должно проехать от начального местоположения до первого посещения в начале маршрута и от последнего посещения до конечного местоположения в конце маршрута. Если у транспортного средства нет начального или конечного местоположения, transitions
все равно будет на один больше, чем visits
, поскольку местоположение первого или последнего посещения используется в качестве начального или конечного местоположения транспортного средства соответственно.
В этом примере первые три посещения пикапа имеют переходы между ними с нулевым расстоянием и продолжительностью, поскольку все три пикапа имеют одно и то же местоположение в запросе.
Дополнительные сведения см. в справочной документации ShipmentRoute
( REST , gRPC ).
Простая оптимизация порядка путевых точек
Как показывает этот пример, оптимизация маршрута моделирует посещения как свойства отправлений и не имеет понятия промежуточных точек или остановок как независимого объекта. Однако можно представить остановки или промежуточные точки как отправления с ровно одним VisitRequest
в качестве самовывоза или доставки. Транспортному средству по-прежнему должно быть назначено costPerHour
или costPerKilometer
, чтобы оптимизатор мог найти оптимальный маршрут (в отличие от поиска любого возможного маршрута).
Этот сценарий оптимизирует порядок остановок, назначенных транспортному средству, с помощью простых параметров стоимости. Это самый простой режим работы оптимизации маршрута, который гарантирует посещение всех остановок в течение указанного периода времени.
Следующий пример иллюстрирует базовый сценарий с одним транспортным средством и тремя отгрузками, все из одного места, называемого складом .
Посмотреть пример запроса
{ "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 } ] } }
Поля запроса на оптимизацию маршрута
Как упоминалось в обзоре , наиболее важными свойствами запроса оптимизации маршрута являются vehicles
и shipments
.
Помимо транспортного средства и грузов, запрос включает в себя следующие поля:
Полилинии
populatePolylines
и populateTransitionPolylines
определяют, должна ли оптимизация маршрута возвращать полилинии.
Служба кодирует полилинии с помощью кодека полилиний Maps JS, который представляет данные двоичной ломаной линии с использованием печатных символов ASCII. Вы можете использовать утилиту интерактивного кодировщика полилиний для визуализации путей, рассчитанных с помощью оптимизации маршрута. В примере в этом руководстве populatePolylines
и populateTransitionPolylines
установлено значение true, но в других руководствах для них установлено значение false, чтобы уменьшить размер ответа.
См. Формат алгоритма кодированной ломаной линии для описания формата кодирования.
Глобальные ограничения по времени
model.globalStartTime
и model.globalEndTime
задан произвольный 24-часовой период. Это упрощает интерпретацию временных меток вывода.
Посетите места
В примере запроса используются только model.shipments[].pickups[].arrivalLocation
и model.shipments[].deliveries[].arrivalLocation
. Существует также свойство departureLocation
для ситуаций, когда транспортное средство отправляется из другой точки, чем та, в которой оно прибывает, например, парковочный комплекс со входом с одной стороны здания и выходом с другой. В этом и последующих руководствах точки прибытия и отправления считаются одинаковыми.
waypoint
прибытия и отправления также существуют как альтернатива latLng
. Поля Waypoint
точек поддерживают использование идентификаторов мест Google в качестве альтернативы LatLng
, а также могут указывать направления транспортных средств. Более подробную информацию смотрите в справочной документации ( REST , gRPC ).
Ограничения в примере
Этот сценарий ограничивает оптимизатор несколькими способами:
- Все действия должны быть завершены между глобальным временем начала и окончания . В этом сценарии время начала и окончания является очень слабым ограничением, учитывая близость поставок и широкий глобальный временной интервал.
- Все поставки должны быть завершены . Это поведение по умолчанию, когда штрафные расходы не указаны в
shipments
. -
costPerKilometer
иcostPerHour
устанавливаются на транспортном средстве.
Затраты рассматриваются в параметрах модели затрат .
Свойства ответа оптимизации маршрута
Посмотреть ответ на пример запроса
{ "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 } } }
Ответ «Оптимизация маршрута» включает поле routes
верхнего уровня, в котором представлены предлагаемые маршруты, по одному маршруту на транспортное средство. Поскольку пример запроса в этом руководстве указывает только одно транспортное средство, routes
включают одно сообщение ShipmentRoute
.
Свойства ShipmentRoute
Двумя наиболее важными свойствами типа сообщений ShipmentRoute
являются visits
и transitions
.
Каждое Visit
представляет собой завершение получения или доставки одного из сообщений VisitRequest
сообщения-запроса. Посещение фактически представляет собой задание, которое транспортное средство должно выполнить в определенном месте и в определенное время.
Каждый Transition
представляет собой транспортное средство, перемещающееся из одного места в другое. Переходы могут происходить между парой начальной точки транспортного средства, места посещения и конечной точки транспортного средства.
Чтобы восстановить полный маршрут транспортного средства, visits
и transitions
ShipmentRoute
должны быть объединены. Объединение полей в последовательность действий транспортного средства выглядит следующим образом:
request.vehicles[0].startLocation -> transitions[0] -> visits[0] ->
transitions[1] -> visits[1] -> transitions[2] -> ... -> visits[3] ->
transitions[4] -> request.vehicles[0].endLocation
У ShipmentRoute
всегда на один transitions
больше, чем visits
, так как транспортное средство должно проехать от начального местоположения до первого посещения в начале маршрута и от последнего посещения до конечного местоположения в конце маршрута. Если у транспортного средства нет начального или конечного местоположения, transitions
все равно будет на один больше, чем visits
, поскольку местоположение первого или последнего посещения используется в качестве начального или конечного местоположения транспортного средства соответственно.
В этом примере первые три посещения пикапа имеют переходы между ними с нулевым расстоянием и продолжительностью, поскольку все три пикапа имеют одно и то же местоположение в запросе.
Дополнительные сведения см. в справочной документации ShipmentRoute
( REST , gRPC ).
Простая оптимизация порядка путевых точек
Как показывает этот пример, оптимизация маршрута моделирует посещения как свойства отправлений и не имеет понятия промежуточных точек или остановок как независимого объекта. Однако можно представить остановки или промежуточные точки как отправления с ровно одним VisitRequest
в качестве самовывоза или доставки. Транспортному средству по-прежнему должно быть назначено costPerHour
или costPerKilometer
, чтобы оптимизатор мог найти оптимальный маршрут (в отличие от поиска любого возможного маршрута).