Пользовательские маршруты

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

Примерами применения пользовательских маршрутов могут быть:

  • Добавьте событие в маршрут при въезде или выезде с платной дороги или при переходе с наземной улицы на линию метро.
  • Измените текст маневра в маршруте, чтобы подчеркнуть острые углы поворота.
  • Предупреждайте водителя после каждых 120 минут вождения.
  • Упростите или расширите инструкции по маршруту для конкретного приложения.

Пользовательские маршруты реализуются путем создания класса Пользовательские направления реализуются путем создания класса Python, который наследуется от класса arcpy.nax.DirectionsCustomizer, и связывания класса Python с определенным набором сетевых данных.

При реализации алгоритма пользовательских маршрутов существует несколько объектов, которые можно использовать для сбора информации о сети и направлениях, например DirectionPoint, DirectionsName, ReferenceLandmark и другие.

Пользовательский класс маршрутов

Пользовательский алгоритм расчета маршрутов создается путем определения класса arcpy.nax.DirectionsCustomizer, который наследуется от класса и реализует метод customize. Класс может дополнительно реализовать методы __init__ и attach.

Пользовательский методы маршрутов

В подразделах ниже описаны методы, которые можно использовать для настройки маршрутов во время решения.

Initializer

Дополнительно вы можете реализовать метод (__init__). Это стандартный инициализатор объекта Python, который можно использовать по мере необходимости.

Attach

Встраивание метода attach является необязательным. Этот метод можно использовать для оценки и проверки набора сетевых данных, чтобы убедиться, что он соответствует требованиям кода пользовательских маршрутов, с помощью объекта сетевого запроса, передаваемого в этот метод. Если набор сетевых данных корректен, метод attach должен вернуть значение True; в противном случае он должен вернуть False, и в этом случае алгоритм построения маршрутов не будет связан с набором сетевых данных и никакие другие методы класса вызываться не будут.

Для временных настройщиков маршрутов метод attach вызывается, когда в скрипте назначается свойство directionsCustomizer для объекта набора сетевых данных.

Для существующих пользовательских маршрутов метод attach вызывается внутри кода основного набора сетевых данных при открытии набора сетевых данных.

Примечание:

Набор сетевых данных можно открывать несколько раз в зависимости от количества потоков, которые приложение использует для доступа к набору сетевых данных.

Настройка

Требуется встраивание метода customize. Этот метод будет вызываться после создания исходных маршрутов и там, где их можно изменить.

Объект arcpy.nax.DirectionsQuery, передаваемый в этот метод, можно использовать для перебора соединений и ребер, чтобы получить связанные с ними точки маршрутов.

Существующие точки маршрута можно обновить, например, изменив отображаемый текст. При необходимости можно создать новые точки маршрута и добавить их в список точек маршрута элемента. Либо существующие точки маршрута можно удалить.

Примечание:

  • При создании точки маршрута должны быть установлены как минимум свойства displayText и directionPointType.
  • Свойства azimuth, arrivalTime и exitNumber устанавливаются внутренне и не могут быть установлены в настройщике маршрутов.

У этих элементов есть различные свойства, которые могут оказаться полезными при настройке направлений маршрута. Объект self.networkQuery можно использовать для получения информации из набора сетевых данных.

Маршрут состоит из остановок, ребер и соединений. Эти классы объектов используются для создания направлений маршрута. Сами направления состоят из точек направления и классов объектов-линий направления. Направления создаются путем анализа остановок, ребер и соединений, чтобы найти места, где происходит что-то, о чем следует проинформировать пользователя. Затем в этих местах создаются точки направления и связываются с соответствующим элементом. Обычно точки направления связаны с соединениями. В настоящее время точки направления связаны с ребрами только в том случае, если встречается ориентир. Затем линии направления создаются путем сложения ребер между точками направления.

Примечание:

С одним и тем же объектом может быть связано несколько точек направления.

Примеры

Пример 1. Приведенный ниже код представляет собой простой пример класса пользовательских маршрутов, который добавляет число в начало каждого маневра по направлениям.

import arcpy

class DirectionsIndexer(arcpy.nax.DirectionsCustomizer):
    """Defines a directions customizer that adds and index number to directions."""

    def customize(self, directions_query: arcpy.nax.DirectionsQuery):
        """Add an index number to each directions maneuver."""
        index = 1
        for junction in directions_query.junctions:
            for point in junction.directionPoints:
                point.displayText = f"{index} -> {point.displayText}"
                index += 1

Пример 2. В приведенном ниже коде показан класс пользовательских маршрутов с реализованными дополнительными методами.

import arcpy

class DirectionsIndexer(arcpy.nax.DirectionsCustomizer):
    """Defines a directions customizer that adds and index number to directions."""

    def __init__(self):
        """Example initializer."""
        super().__init__()
        # Do additional custom initialization

    def attach(self, network_query: arcpy.nax.NetworkQuery) -> bool:
        # Do additional validation checks before returning Boolean
        return True

    def customize(self, directions_query: arcpy.nax.DirectionsQuery):
        """Add an index number to each directions maneuver."""
        index = 1
        for junction in directions_query.junctions:
            for point in junction.directionPoints:
                point.displayText = f"{index} -> {point.displayText}"
                index += 1

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

import arcpy

class LongDriveAlert(arcpy.nax.DirectionsCustomizer):
    """Defines a directions customizer that reports an alert after a long drive."""

    def customize(self, directions_query: arcpy.nax.DirectionsQuery) -> None:
        """Customize directions.

        If traversed junction's accumulated time is over alert interval, add an alert as a directions point.
        Enhance existing directions text to show time elapsed since beginning of the trip.
        """
        alert_interval = 120  # This assumes the travel mode's time attribute unit is minutes.
        # Loop through traversed junctions and get accumulated time at each junction.
        # If the accumulated time is over the alert interval, add a directions point with an alert message.
        i = 1
        for junction in directions_query.junctions:
            elapsed_time = junction.accumulatedTime
            if elapsed_time > alert_interval * i:
                # Create a new directions point at junction.
                point = arcpy.nax.DirectionPoint(junction)
                point.displayText = f"You have driven for over 2 hours. Consider taking a break."
                point.directionPointType = arcpy.nax.DirectionPointType.Event
                # Update junction direction points to add the new break reminder
                junction.directionPoints.append(point)
                i += 1
            else:
                for point in junction.directionPoints:
                    # For existing directions, report the elapsed time at each direction point.
                    point.displayText = f"{point.displayText} (Time elapsed: {elapsed_time:.2f} minutes)"

Пример 4. В приведенном ниже коде показан класс пользовательских маршрутов, который проверяет тип точки направления для определения поворотов налево и добавляет дополнительный текст предупреждения к инструкциям по направлениям.

import arcpy

class LeftTurnsHighlighter(arcpy.nax.DirectionsCustomizer):
    """Add warning text for left turn maneuvers."""

    def __init__(self) -> None:
        """Initialize customizer.

        Set left_turn_maneuver_types in initialization so it is set only once
        when the network dataset object is constructed and when the
        customizer instance is initialized.
        """
        super().__init__()
        self.left_turn_manuever_types = [
            arcpy.nax.DirectionPointType.ManeuverForkLeft,
            arcpy.nax.DirectionPointType.ManeuverRampLeft,
            arcpy.nax.DirectionPointType.ManeuverUTurnLeft,
            arcpy.nax.DirectionPointType.ManeuverBearLeft,
            arcpy.nax.DirectionPointType.ManeuverTurnLeft,
            arcpy.nax.DirectionPointType.ManeuverSharpLeft,
            arcpy.nax.DirectionPointType.ManeuverTurnLeftLeft,
            arcpy.nax.DirectionPointType.ManeuverTurnLeftRight,
            arcpy.nax.DirectionPointType.ManeuverTurnRightLeft
        ]

    def customize(self, directions_query: arcpy.nax.DirectionsQuery) -> None:
        """Alter directions text to highlight left turns with warning text."""
        for junction in directions_query.junctions:
            for point in junction.directionPoints:
                if point.directionPointType in self.left_turn_manuever_types:
                    point.displayText = f"{point.displayText} (LEFT TURN WARNING!)"

Связывание настройщика маршрутов с набором сетевых данных

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

Подсказка:

Создайте свой класс пользовательских маршрутов и протестируйте его в качестве временного настройщика маршрутов. Затем запустите скрипт в режиме отладки в таком редакторе, как Visual Studio Code. Как только скрипт заработает должным образом, при необходимости вы можете сделать его настройщиком постоянных маршрутов. Проверьте настройщик сохраненных маршрутов, чтобы убедиться, что все работает правильно.

Временный настройщик маршрутов

Временные настройщики маршрутов связаны только с объектом набора сетевых данных, созданным в скрипте; они не сохраняются постоянно в наборе сетевых данных. Временные настройщики маршрутов настраиваются с использованием свойства directionsCustomizer объекта набора сетевых данных в сценарии, выполняющем решение.

Временный настройщик маршрутов можно использовать для приложений, в которых настройщик направлений должен вызываться из скрипта Python, например, из автономного скрипта Python, инструмента-скрипта Python, пользовательского сервиса геообработки или веб-инструмента. Они также могут быть полезны для разработки и отладки настройщиков постоянных маршрутов.

Конфигурация временного настройщика маршрутов

Чтобы отладить временный настройщик маршрутов, создайте объект настройщика маршрутов, а затем используйте свойство directionsCustomizer объекта набора сетевых данных, чтобы связать с ним объект настройщика маршрутов.

В приведенном ниже примере показано, как создать экземпляр объекта настраиваемых маршрутов и связать его с объектом набора сетевых данных. Чтобы вызвать пользовательские маршруты во время решения, создайте экземпляр объекта решения маршрута, используя объект набора сетевых данных.

# Instantiate a directions customizer object that adds an index number
# to each directions maneuver's display text
add_numbers_customizer = DirectionsIndexer()

# Create a network dataset object
network_dataset = arcpy.nax.NetworkDataset(
    r"C:\Data\Tutorial\SanFrancisco.gdb\Transportation\Streets_ND")

# Attach the custom directions object to the network dataset
network_dataset.directionsCustomizer = add_numbers_customizer

# Instantiate a route analysis
route = arcpy.nax.Route(network_dataset)

Постоянный настройщик маршрутов

Постоянные настройщики маршрутов хранят ссылку на класс настройщика маршрутов как часть схемы набора сетевых данных, которая хранится в базе геоданных. Эти настройщики маршрутов будут вызываться всякий раз, когда выполняется решение с использованием этого набора сетевых данных. Такой вариант называется постоянным, поскольку ссылка является частью самого набора сетевых данных. Они настраиваются с использованием метода updateNetworkDatasetSchema объекта набора сетевых данных.

При открытии сети с сохраненным настройщиком маршрутов класс настройщика маршрутов загружается и кэшируется. Этот кэш сохраняется в течение всего срока работы приложения. Это означает, что любые изменения, внесенные в сохраняемый класс, не будут прочитаны до тех пор, пока приложение, открывшее набор сетевых данных, не будет закрыто и перезапущено. Это применимо и к ArcGIS Pro и к ArcGIS Server.

Важно отметить, что для постоянных настройщиков маршрутов схема набора сетевых данных содержит только ссылку на настройщик направлений, а не код класса. Эта ссылка позволяет набору сетевых данных при доступе к нему неявно найти и загрузить соответствующий настройщик маршрутов. Модуль Python, содержащий код класса, должен находиться в папке site-packages активной среды ArcGIS Pro Python, чтобы набор сетевых данных мог его найти.

Более подробно о средах Python

Примечание:

Рекомендуется клонировать среду по умолчанию ArcGIS Pro Python, прежде чем вносить какие-либо изменения. При добавлении файла пользовательских маршрутов Python в каталог пакетов сайта рекомендуется сначала клонировать среду и активировать клонированную среду.

Постоянный настройщик маршрутов будет использоваться, когда вам нужно вызвать настройщик маршрутов при выполнении решения вне скрипта Python, например, в ArcGIS Pro или ArcGIS Server. Например, чтобы создать слой сетевого анализа в ArcGIS Pro, решите слой и сгенерируйте маршруты, используя ваши настройки, или если вы хотите использовать стандартные сервисы построения маршрутов, опубликованные на основе набора сетевых данных, но хотите настроить выходные данные маршрутов.

Если уровень сетевого анализа, использующий набор сетевых данных с постоянным настройщиком маршрутов, публикуется как сервис, то пакет настраиваемых маршрутов необходимо вручную скопировать в каталог пакетов сайта среды ArcGIS Server Python. Кроме того, когда в сервисе используется настройщик маршрутов, любой внешний ресурс, который он использует (например, файлы), должен быть доступен пользователю ArcGIS Server, поскольку это зависит от того, как настроен сервер.

Конфигурация постоянного настройщика маршрутов

Используйте метод updateNetworkDatasetSchema для объекта набора сетевых данных, чтобы постоянно обновлять схему набора сетевых данных, передавая словарь, определяющий путь к классу настройщика маршрутов. Этот путь использует точечную нотацию для определения имени папки (в каталоге site-packages), имени файла, в котором находится класс, и самого имени класса.

В приведенном ниже примере показано, как обновить набор сетевых данных с помощью сохраненного класса пользовательских маршрутов. Класс в этом примере называется DirectionsIndexer, а его код находится в модуле Python с именем customization.py в папке с именем na_customizers, которая находится в папке site-packages для ArcGIS Pro активной среды Python.

import arcpy

# Create a network dataset object
network_dataset = arcpy.nax.NetworkDataset(
    r"C:\Data\Tutorial\SanFrancisco_Persisted.gdb\Transportation\Streets_ND")

# Create a dictionary referencing the custom directions class to use
my_custom_directions = {"class": "na_customizers.customization.DirectionsIndexer"}

# Update the network dataset to use the custom directions class
network_dataset.updateNetworkDatasetSchema(
    custom_directions=my_custom_directions
)

Когда этот набор сетевых данных используется в сетевом анализе, будет создан объект класса настройщика маршрутов, и набор сетевых данных вызовет объект настройщика маршрутов после создания начальных маршрутов при их настройке. При создании объекта настройщика маршрутов сеть найдет и загрузит указанный класс внутри пакета и модуль из папки пакетов сайта активной среды ArcGIS Pro. Если пакет, модуль или класс не найден, настройщик маршрутов не будет использоваться. Создание решения и маршрута завершится появлением предупреждающего сообщения о том, что возникла проблема с использованием настройщика маршрутов.

Если набор сетевых данных имеет постоянный настройщик маршрутов, он будет указан в разделе Общие > и на странице Путевые листы диалогового окна Свойства набора сетевых данных. Если при загрузке указанного класса возникла проблема, появится сообщение об ошибке или предупреждение.

Жизненный цикл объекта

Когда набор сетевых данных изначально создается и имеет постоянный настройщик маршрутов, он создает экземпляр объекта настройщика маршрутов, на который ссылаются на протяжении всего его существования, причем время жизни может варьироваться в зависимости от используемой платформы (например, ArcGIS Pro, ArcGIS Server или Python).

Поскольку конкретный экземпляр объекта настройки направлений может использоваться для нескольких решений, важно управлять состоянием этого объекта, в частности, сбрасывать переменные в начале метода Customize перед повторением текущих направлений по мере необходимости. Например, если настройщик маршрутов имеет переменную экземпляра, которая обновляется при переборе маршрутов, ее следует сбросить в начале метода Customize; в противном случае оно может начаться со значения из предыдущего решения.

В контексте ArcGIS Server каждый процесс SOC (во время запуска и во время перезапуска) создаст новый объект набора сетевых данных, а также создаст новый экземпляр объекта настройки направлений. Этот экземпляр объекта настройки направлений будет использоваться на протяжении всего жизненного цикла процесса SOC; только метод Customize будет запускаться для каждого запроса.

Ограничения

Следующие ограничения применяются только к пользовательским маршрутам:

  • Пользовательские маршруты доступны только в ArcGIS Pro и ArcGIS Server.
  • Пользовательские маршруты могут быть вызваны только для файловой или корпоративной базы геоданных.
  • Из соображений производительности настройщики маршрутов не поддерживают использование ключевых слов в качестве аргументов.

Руководство по быстрому началу работы по созданию и использованию временного настройщика маршрутов

Ниже приведены разделы из руководства по быстрому началу работы по созданию и использованию временного настройщика маршрутов Каждый пример кода иллюстрирует определенный компонент полного рабочего процесса. Используются следующие компоненты:

  1. Расчет анализа маршрутов
  2. Определение класса настройщика маршрутов
  3. Создайте экземпляр класса и свяжите его с набором сетевых данных, который используется для расчета маршрута.

Последний пример кода показывает, как соединить все компоненты вместе.

Примеры кода созданы на основе руководства по сетевому анализу, которое можно загрузить со страницы загрузки данных.

Расчет анализа маршрутов

В приведенном ниже примере кода показан рабочий процесс для анализа маршрута с использованием объекта механизма расчета arcpy.nax и печати пошаговых путевых листов.

Примечание:

Путь к базе геоданных в приведенном ниже коде необходимо обновить, чтобы отразить расположение данных в вашей системе.

import arcpy

# Create a network dataset object
network_dataset = arcpy.nax.NetworkDataset(
    r"C:\Data\Tutorial\SanFrancisco.gdb\Transportation\Streets_ND")

# Instantiate a route analysis
route = arcpy.nax.Route(network_dataset)
route.returnDirections = True

# Insert stops for the route
with route.insertCursor(
    arcpy.nax.RouteInputDataType.Stops,
    ["NAME", "SHAPE@XY"]
) as cursor:
    cursor.insertRow(["Stop1", (-122.501, 37.757)])
    cursor.insertRow(["Stop2", (-122.445, 37.767)])

# Solve the route
result = route.solve()

# Print the directions
if result.solveSucceeded:
    for row in result.searchCursor(
        arcpy.nax.RouteOutputDataType.DirectionPoints, ["DisplayText"]
    ):
        print(row[0])

Определение класса настройщика маршрутов

В приведенном ниже примере кода показано определение класса настройщика маршрутов. В этом примере добавляется число в начале каждого маневра в маршрутах. Например, без настройки первым шагом будет Start at Stop1, с настройкой первым шагом будет 1 -> Start at Stop1.

import arcpy

class DirectionsIndexer(arcpy.nax.DirectionsCustomizer):
    """Defines a directions customizer that adds and index number to directions."""

    def customize(self, directions_query: arcpy.nax.DirectionsQuery):
        """Add an index number to each directions maneuver."""
        index = 1
        for junction in directions_query.junctions:
            for point in junction.directionPoints:
                point.displayText = f"{index} -> {point.displayText}"
                index += 1

Связывание настройщика маршрутов с набором сетевых данных

В приведенном ниже примере кода показано создание экземпляра класса настройщика маршрутов и его связывание с объектом набора сетевых данных. Это следует сделать до вызова метода расчета маршрута (route.solve()).

# Instantiate a directions customizer object that adds an index number
# to each directions maneuver's display text
add_numbers_customizer = DirectionsIndexer()

# Attach the custom directions object to the network dataset
network_dataset.directionsCustomizer = add_numbers_customizer

Сборка всех компонентов

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

import arcpy

class DirectionsIndexer(arcpy.nax.DirectionsCustomizer):
    """Defines a directions customizer that adds and index number to directions."""

    def customize(self, directions_query: arcpy.nax.DirectionsQuery):
        """Add an index number to each directions maneuver."""
        index = 1
        for junction in directions_query.junctions:
            for point in junction.directionPoints:
                point.displayText = f"{index} -> {point.displayText}"
                index += 1

# Create a network dataset object
network_dataset = arcpy.nax.NetworkDataset(
    r"C:\Data\Tutorial\SanFrancisco.gdb\Transportation\Streets_ND")

# Instantiate a directions customizer object that adds an index number
# to each directions maneuver's display text
add_numbers_customizer = DirectionsIndexer()

# Attach the custom directions object to the network dataset
network_dataset.directionsCustomizer = add_numbers_customizer

# Instantiate a route analysis
route = arcpy.nax.Route(network_dataset)
route.returnDirections = True

# Insert stops for the route
with route.insertCursor(
    arcpy.nax.RouteInputDataType.Stops,
    ["NAME", "SHAPE@XY"]
) as cursor:
    cursor.insertRow(["Stop1", (-122.501, 37.757)])
    cursor.insertRow(["Stop2", (-122.445, 37.767)])

# Solve the route
result = route.solve()

# Print the directions
if result.solveSucceeded:
    for row in result.searchCursor(
        arcpy.nax.RouteOutputDataType.DirectionPoints, ["DisplayText"]
    ):
        print(row[0])

Руководство по быстрому началу работы по созданию и использованию постоянного настройщика маршрутов

Ниже приведены разделы из руководства по быстрому началу работы по созданию и использованию постоянного настройщика маршрутов Далее вы создадите модуль Python, содержащий класс настройщика маршрутов, сохраните модуль Python в каталоге site-packages активной среды Python, обновите набор сетевых данных для использования настройщика маршрутов и протестируете его, выполнив анализ маршрута.

  1. Клонируйте среду Python по умолчанию
  2. Определение класса настройщика маршрутов
  3. Обновление схемы набора сетевых данных
  4. Сохранение маршрута

Примеры кода созданы на основе руководства по сетевому анализу, которое можно загрузить со страницы загрузки данных.

Клонируйте среду Python по умолчанию

Код настройщика маршрутов должен быть сохранен в среде ArcGIS Pro Python. Если вы используете среду ArcGIS Pro Python по умолчанию, рекомендуется сначала клонировать и активировать новую среду.

Более подробно о клонировании среды

Определение класса настройщика маршрутов

В приведенном ниже примере кода показано определение класса настройщика маршрутов. В этом примере добавляется число в начале каждого маневра в маршрутах.

import arcpy

class DirectionsIndexer(arcpy.nax.DirectionsCustomizer):
    """Defines a directions customizer that adds and index number to directions."""

    def customize(self, directions_query: arcpy.nax.DirectionsQuery):
        """Add an index number to each directions maneuver."""
        index = 1
        for junction in directions_query.junctions:
            for point in junction.directionPoints:
                point.displayText = f"{index} -> {point.displayText}"
                index += 1

В активной среде ArcGIS Pro Python найдите папку site-packages. Внутри нее создайте папку с именем na_customizers. Сохраните приведенный выше код, определяющий класс настройки маршрутов, в папку na_customizers как direction_customization.py.

Обновление схемы набора сетевых данных

Копирование Network Analyst\Tutorial\SanFrancisco.gdb из данных для обучения SanFrancisco_Persisted.gdb.

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

import arcpy

# Create a network dataset object
network_dataset = arcpy.nax.NetworkDataset(
    r"C:\Data\Tutorial\SanFrancisco_Persisted.gdb\Transportation\Streets_ND")

# Create a dictionary referencing the custom directions class to use
my_custom_directions = {
    {"class": "na_customizers.customization.DirectionsIndexer"}
}

# Update the network dataset to use the custom directions class
network_dataset.updateNetworkDatasetSchema(
    custom_directions=my_custom_directions
)

Решение маршрута

В ArcGIS Pro используйте набор сетевых данных из SanFrancisco_Persisted.gdb для решения маршрута. Решите второй маршрут, используя SanFrancisco.gdb и те же остановки, и сравните путевые листы выходного маршрута. Путевые листы в маршруте SanFrancisco_Persisted.gdb должны иметь номер перед каждым из направлений из-за настройщика маршрутов. Например, при использовании SanFrancisco.gdb, первым шагом будет Start at Stop1, а при использовании SanFrancisco_Persisted.gdb первым шагом будет 1 -> Start at Stop1.

Подробнее о расчетах в анализе маршрутов в ArcGIS Pro