自定义方向

在求解操作过程生成最初的方向后,可以通过自定义方向对逐步方向文本进行更改。 可以更新或移除路径的现有方向,也可以添加新的方向点。 此操作可以更改输出方向,而无需更新基础网络数据集。

自定义方向的示例应用包括:

  • 在进入或离开收费公路或从地面街道转到地铁线路时添加方向事件。
  • 更改方向行进策略文本以强调急转角度。
  • 每行驶 120 分钟后提醒驾驶员。
  • 针对特定应用简化或详述方向指示。

要实现自定义方向,可创建一个从 arcpy.nax.DirectionsCustomizer 类继承而来的 Python 类,并将 Python 类与特定网络数据集关联起来。

当实现方向自定义器时,可以使用多个对象来收集有关网络和方向的信息,例如 DirectionPointDirectionsNameReferenceLandmark 等。

自定义方向类

要创建方向自定义器,请定义一个从 arcpy.nax.DirectionsCustomizer 类继承的类并实现 customize 方法。 您也可以使用类实现 __init__attach 方法。

自定义方向方法

以下小节描述了可用于在求解时自定义方向的方法。

初始化程序

可以选择是否实现初始化程序 (__init__) 方法。 这是 Python 对象的标准初始化程序,可以根据需要进行使用。

附加

可以选择实现 attach 方法。 该方法可用于检查和验证网络数据集,以确保其符合使用传入此方法的网络查询对象自定义方向代码的要求。 如果网络数据集有效,则 attach 方法将返回 True;否则,将返回 False。 返回 False 时,方向定制器不会与网络数据集相关联,并且不会调用其他类方法。

对于临时方向定制器,当分配的脚本中的网络数据集对象具有 directionsCustomizer 属性时,将调用 attach 方法。

对于持久化自定义方向,当打开网络数据集时,核心网络数据集代码将在内部调用 attach 方法。

注:

可以多次打开网络数据集,具体取决于应用程序用于访问网络数据集的线程数量。

自定义

必须选择实现 customize 方法。 在初始方向已经创建完成并且可以更改的情况下,将调用此方法。

传入此方法的 arcpy.nax.DirectionsQuery 对象可用于遍历交汇点和边,以获取其关联的方向点。

可以对现有方向点进行更新,例如更改显示文本。 可以创建新的方向点并将其添加到某个元素的方向点列表。 或者,可以将现有方向点移除。

注:

  • 创建方向点时,至少应设置 displayTextdirectionPointType 属性。
  • azimutharrivalTimeexitNumber 属性在内部设置,无法在方向定制器中设置。

元素具有各种属性,这些属性在自定义路径方向时可能很有帮助。 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 a traversed junction's accumulated time is over the alert interval, add an alert as a directions point.
        Enhance the existing directions text to show the time elapsed since the beginning of the trip.
        """
        alert_interval = 120  # This assumes that the travel mode's time attribute unit is minutes.
        # Loop through the traversed junctions and get the 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 the 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 the 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 脚本工具、自定义地理处理服务或 Web 工具)调用方向定制器。 临时方向定制器也可用于开发和调试持久化方向定制器。

配置临时方向定制器

要设置一个临时方向定制器,请创建一个方向定制器对象,然后使用网络数据集对象的 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 ProArcGIS Server

值得注意的是,对于持久化方向定制器,网络数据集方案仅包含对方向定制器的引用,不包含类代码。 此引用使得网络数据集在被访问时隐式查找并加载其引用的方向定制器。 包含类代码的 Python 模块必须位于活动 ArcGIS Pro Python 环境的站点包文件夹中,以便网络数据集可以找到它。

了解有关 Python 环境的详细信息

注:

如果自定义脚本需要使用默认 ArcGIS Pro Python 环境不包含的第三方 Python 包,则建议您在安装附加包之前克隆默认 Python 环境。 按照“软件包管理器”主题中的工作流创建默认 ArcGIS Pro Python 环境的克隆,添加包,然后激活环境。 自定义赋值器 Python 文件必须存储在活动 Python 环境的站点包目录中,在本例中,即默认 ArcGIS Pro Python 环境的克隆。

这一点同样适用于 ArcGIS Server。 如需为 ArcGIS Server 站点部署持久化自定义,并且需要使用 ArcGIS Server 默认 Python 环境不包含的第三方附加包,则请按照“为 ArcGIS Server 部署自定义 Python 包”主题中的步骤克隆默认 Python 环境,添加包,然后激活克隆环境。 向 ArcGIS Server 部署持久化自定义时,自定义必须复制到 ArcGIS Server 上的活动 Python 环境的站点包目录。

Python 脚本外部执行求解操作(例如在 ArcGIS ProArcGIS Server 中)时,如果需要调用方向定制器,则请使用持久化方向定制器。 例如,要在 ArcGIS Pro 中创建网络分析图层,请求解图层并使用自定义生成方向。 另一个使用持久化方向定制器的示例是当您想要使用基于网络数据集发布的标准路径服务,还想自定义方向输出的情况。

如果 Network Analyst 图层使用的网络数据集包含已发布为服务的持久化方向定制器,则自定义方向包必须被手动复制到 ArcGIS Server Python 环境的站点包目录。 此外,当在服务上使用方向定制器时,ArcGIS Server 用户应该可以访问它所使用的任何外部资源(如文件),因为这取决于服务器的配置方式。

配置持久化方向定制器

对网络数据集对象使用 updateNetworkDatasetSchema 方法传入定义方向定制器类路径的字典,以便永久更新网络数据集方案。 该路径使用点标记来定义文件夹名称(在站点包目录中)、类所在文件的文件名以及类名。

下例显示了如何更新包含持久化自定义方向类的网络数据集。 此示例中的类名为 DirectionsIndexer,其代码位于名为 direction_customization.pyPython 模块中,模块所在的文件夹名为 na_customizers,上述内容位于 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.direction_customization.DirectionsIndexer"}

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

当在网络分析中使用该网络数据集时,将创建方向定制器类对象,并且网络数据集将在生成初始方向后调用方向定制器对象以自定义方向。 在创建方向定制器的对象时,网络将从活动 ArcGIS Pro 环境的站点包文件夹中找到并加载包和模块中的指定类。 如果未找到包、模块或类,则不会使用方向定制器。 求解和方向生成在完成时将提示警告消息,指出使用方向定制器时出现问题。

当网络数据集包含持久化方向定制器时,该定制器将在常规窗格的汇总部分和网络数据集属性对话框的方向页面上列出。 如果加载引用的类时出现问题,则会显示错误或警告消息。

对象生命周期

在最初构建网络数据集时,如果其具有持久化方向定制器,则其会实例化在其整个生命周期中引用的方向定制器对象。 生命周期可能因所使用的框架(例如 ArcGIS ProArcGIS ServerPython)而有所不同。

由于方向定制器对象的特定实例可以在多次求解操作中使用,因此管理该对象的状态非常重要,特别是在根据需要遍历当前方向之前,在 Customize 方法开始时重置变量。 例如,如果方向定制器有一个在迭代方向时更新的实例变量,则应在 Customize 方法开始时将其重置,否则,它可能从上次求解操作中的某个值开始。

ArcGIS Server 环境中,每个服务器对象组件 (SOC) 进程(在启动时和循环时)将构造新的网络数据集对象,并且还将创建方向定制器对象的新实例。 方向定制器对象的这个实例将在 SOC 过程的整个生命周期中使用;只有 Customize 方法会在每个请求发生时运行。

局限性

以下限制适用于自定义方向:

  • 自定义方向仅可用于 ArcGIS ProArcGIS Server
  • 只能在文件或企业级地理数据库上调用自定义方向。
  • 出于性能考虑,方向定制器不支持使用关键字作为参数。

创建和使用临时方向定制器

以下部分将介绍如何创建和使用临时方向定制器。 每个代码示例均表示完整工作流中的一个特定组件。 该工作流的组成部分如下:

  1. 求解路径分析
  2. 定义方向定制器类
  3. 将方向定制器与网络数据集相关联

最后的代码示例显示了如何将所有组件结合到一起。

下方代码示例是使用 Network Analyst 教程创建的,该教程可从数据下载页面下载。

求解路径分析

下方代码示例演示了使用 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 an 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 an 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 模块存储在活动 Python 环境的站点包目录中,更新网络数据集以使用方向定制器,然后通过求解路径分析来测试方向定制器。 该工作流的组成部分如下:

  1. 克隆默认 Python 环境(可选)
  2. 定义方向定制器类
  3. 更新网络数据集方案
  4. 求解路径

下方代码示例是使用 Network Analyst 教程创建的,该教程可从数据下载页面下载。

克隆默认 Python 环境(可选)

此步骤是可选的。 如果自定义脚本需要使用默认 ArcGIS Pro Python 环境中不包含的第三方 Python 库,则您仅需要克隆默认 Python 环境。

了解有关克隆环境的详细信息

定义方向定制器类

下面的代码示例演示了方向定制器类的定义。 此示例会在每个方向行进策略的开头添加一个数字。

import arcpy

class DirectionsIndexer(arcpy.nax.DirectionsCustomizer):
    """Defines a directions customizer that adds an 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 环境中,找到站点包文件夹。 在该目录中创建一个名为 na_customizers 的文件夹。 将上方用于定义方向定制器类的代码保存至 na_customizers 文件夹,命名为 direction_customization.py

更新网络数据集方案

Network Analyst\Tutorial\SanFrancisco.gdb 从教程数据复制SanFrancisco_Persisted.gdb

在独立脚本中使用下方代码永久更新 SanFrancisco_Persisted.gdb 中包含持久化自定义方向类的网络数据集。

import arcpy

# Check out the ArcGIS Network Analyst extension
arcpy.CheckOutExtension("network")

# 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.direction_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 中求解路径分析问题

部署要在托管在 ArcGIS GIS Server 站点上的路径服务中使用的自定义方向

您可以发布两种类型的路径服务:标准路径服务和自定义路径服务。

标准路径服务是提供可与 ArcGIS Network Analyst extension 配合使用的即用型功能的地图和地理处理服务。 您可以使用网络数据集将标准路径服务发布到 ArcGIS GIS Server 站点,然后您将获得一组包含预定义参数和输入方案的路径服务端点。 这些服务提供完整功能和与 Esri 应用程序(例如 ArcGIS ProMap Viewer)的集成。

了解有关发布标准路径服务的详细信息

自定义路径服务是具有自定义功能的地理处理服务。 自定义路径服务可用于执行可能涉及多个网络分析求解程序或其他地理处理工具的工作流。 您还可以定义自定义参数和输入方案,以适应应用程序的要求。

了解有关发布自定义路径服务的详细信息

标准路径服务和自定义路径服务可以调用自定义方向。

通过标准路径服务调用自定义方向

要通过标准路径服务调用自定义方向,请完成以下步骤:

  1. 创建持久化方向定制器,然后将其与网络数据集关联。
  2. ArcGIS Pro 中测试方向定制器以确保其在求解路径时被调用。
  3. 在所有参与将用于托管路径服务的 ArcGIS Server 站点的计算机上,将网络数据集复制到相同的路径下。
  4. 将自定义文件夹和文件复制到所有参与 ArcGIS Server 站点的计算机上。 将文件夹和文件放置在 ArcGIS Server 活动 Python 环境的站点包文件夹中。 服务器计算机上的默认路径为:<install>\ArcGIS\Server\framework\runtime\ArcGIS\bin\Python\envs\arcgispro-py3\Lib\site-packages。 从 ArcGIS Pro Python 环境的站点包文件夹复制到 ArcGIS Server 时,请为自定义代码保留相同的文件夹结构。 例如,如果自定义代码位于 na_customizers 文件夹中的 direction_customization.py 文件中,请将 na_customizers 文件夹复制到 ArcGIS Server 上的站点包文件夹。
  5. 发布标准路径服务

使用路径服务时,会应用自定义。

通过自定义路径服务调用自定义方向

要通过自定义路径服务调用自定义方向,请完成以下步骤:

  1. 按照发布自定义路径服务主题中的步骤编写脚本工具。
  2. 将临时定制器与脚本工具中的网络数据集相关联。
  3. 按照发布自定义路径服务主题中的步骤发布服务。

使用路径服务时,会应用自定义。