Базовая оптимизация стоп-заявок для самовывоза и доставки

Этот сценарий оптимизирует порядок остановок, назначенных транспортному средству, с помощью простых параметров стоимости. Это самый простой режим работы оптимизации маршрута, который гарантирует посещение всех остановок в течение указанного периода времени.

Следующий пример иллюстрирует базовый сценарий с одним транспортным средством и тремя отгрузками, все из одного места, называемого складом .

Посмотреть пример запроса

      {
        "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 ).

Ограничения в примере

Этот сценарий ограничивает оптимизатор несколькими способами:

  1. Все действия должны быть завершены между глобальным временем начала и окончания . В этом сценарии время начала и окончания является очень слабым ограничением, учитывая близость поставок и широкий глобальный временной интервал.
  2. Все поставки должны быть завершены . Это поведение по умолчанию, когда штрафные расходы не указаны в shipments .
  3. 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 ).

Ограничения в примере

Этот сценарий ограничивает оптимизатор несколькими способами:

  1. Все действия должны быть завершены между глобальным временем начала и окончания . В этом сценарии время начала и окончания является очень слабым ограничением, учитывая близость поставок и широкий глобальный временной интервал.
  2. Все поставки должны быть завершены . Это поведение по умолчанию, когда штрафные расходы не указаны в shipments .
  3. 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 , чтобы оптимизатор мог найти оптимальный маршрут (в отличие от поиска любого возможного маршрута).