在 ArcGIS Pro 中进行地图制图时我们常常会遇到需要标注圆弧线如道路弯道、河流拐弯处半径的需求。无论是交通规划、工程设计还是地理分析精确的半径信息都是关键参数。然而ArcGIS Pro 本身并未提供直接标注圆弧线半径的工具手动计算和标注不仅效率低下而且容易出错。本文将分享一个基于 ArcGIS Pro 加载项Add-in开发的“圆弧线半径标注”工具它能够自动识别线要素中的圆弧段并计算、标注其半径极大地提升了制图与分析的效率。无论你是 GIS 开发新手还是希望扩展 ArcGIS Pro 功能的资深用户都能通过本文掌握从环境搭建、代码编写到打包部署的完整流程。1. 背景与核心概念在深入开发之前我们首先需要理解几个核心概念ArcGIS Pro 加载项、圆弧线几何以及半径计算原理。1.1 什么是 ArcGIS Pro 加载项ArcGIS Pro 加载项是一种扩展 ArcGIS Pro 功能的方式。它允许开发者使用 .NET如 C#或 Python 创建自定义工具、按钮、窗格等并将其无缝集成到 ArcGIS Pro 的 Ribbon 界面中。加载项相比传统的独立桌面应用程序Add-Ins for ArcMap或 ArcPy 脚本工具具有更好的集成度和用户体验。用户安装后新功能就像原生功能一样出现在软件中。1.2 圆弧线在 GIS 中的表示在 GIS 中线要素Polyline通常由一系列连续的折线段Line Segment组成。所谓的“圆弧线”或“曲线段”在 ArcGIS 的几何模型中通常指的是贝塞尔曲线段Bezier Segment或椭圆弧线段Elliptic Arc Segment它们是构成 Polyline 的基本线段类型之一用于平滑地连接两个顶点。我们的目标就是从一条复杂的线要素中自动识别出这些曲线段。1.3 半径标注的原理对于一段标准的圆弧圆形的一部分其半径是一个恒定值。给定圆弧上的三个点理论上可以确定一个唯一的圆从而计算出半径。在 ArcGIS Pro 的 ArcPy 或 ArcGIS.Core SDK 中我们可以通过访问线要素的几何部件Parts和线段Segments来获取构成圆弧的坐标点然后应用几何公式进行计算。本工具的核心工作流程如下用户选择一个线图层。工具遍历图层中的每一个线要素。对每个线要素遍历其所有几何部件和线段。识别出类型为“椭圆弧线段”Elliptic Arc的线段。从该线段中提取关键参数如中心点、长半轴、短半轴、旋转角等或采样点计算其半径。在圆弧的合适位置如中心点或中点创建一个标注点要素并将计算出的半径值作为属性存储或图形标注。2. 环境准备与版本说明开发 ArcGIS Pro 加载项需要搭建特定的开发环境。以下是必需的软件和工具。2.1 核心软件与版本ArcGIS Pro: 本文以ArcGIS Pro 3.0版本为例进行开发。请确保你安装的 ArcGIS Pro 版本是 2.6 或更高版本建议使用最新稳定版以获取最好的 SDK 支持。你可以在 Esri 官网或通过许可管理器获取安装包。.NET 桌面开发工作负载: ArcGIS Pro 是基于 .NET 构建的因此需要使用 Visual Studio 进行开发。Visual Studio: 推荐使用Visual Studio 2022。社区版是免费的完全满足开发需求。安装时务必在“工作负载”中选择“.NET 桌面开发”。ArcGIS Pro SDK for .NET: 这是开发加载项的基石。你需要从 Esri 的 GitHub 发布页面或通过 Visual Studio 的扩展管理器下载并安装与你的 ArcGIS Pro 版本匹配的 SDK。例如ArcGIS Pro 3.0 对应的是ArcGIS Pro SDK for .NET 3.0。2.2 安装与验证步骤安装 Visual Studio 2022运行安装程序勾选“.NET 桌面开发”工作负载完成安装。安装 ArcGIS Pro SDK方法一推荐打开 Visual Studio点击“扩展” - “管理扩展”。在“联机”中搜索 “ArcGIS Pro SDK”找到对应版本并安装。安装后需要重启 VS。方法二从 GitHub 发布页面下载.vsix安装包双击运行。验证安装重启 Visual Studio 后新建项目。你应该能在模板列表中看到“ArcGIS Pro”分类其下有如“ArcGIS Pro 模块”、“ArcGIS Pro 按钮”等模板这证明 SDK 安装成功。2.3 项目结构预览使用 SDK 模板创建的项目会自动生成一个结构清晰、包含必要引用和配置的解决方案。一个典型的加载项项目主要包含Config.daml文件这是加载项的“清单”文件以 XML 格式定义了按钮、工具、窗格等在 Ribbon 上的位置、图标、文本等UI信息。Module.cs类加载项的入口点负责初始化和清理。具体的工具类如RadiusAnnotationTool.cs实现工具核心逻辑的地方。3. 核心原理与 ArcGIS Pro SDK 拆解要开发半径标注工具我们需要深入理解 ArcGIS Pro SDK 中几个关键的命名空间和类。3.1 几何对象模型 (ArcGIS.Core.Geometry)这是处理空间数据的核心。MapView: 代表当前地图视图我们可以通过它获取活动地图和图层。FeatureLayer: 表示一个可编辑的要素图层我们可以从中查询和编辑要素。Polyline: 线几何对象由ReadOnlyPartCollection部件集合组成。ReadOnlySegmentCollection: 线段集合是部件的一部分。线段类型包括LineSegment,EllipticArcSegment,BezierSegment,CubicBezierSegment等。EllipticArcSegment: 椭圆弧线段类。它包含了计算圆弧半径所需的关键属性如CenterPoint,SemiMajorAxis,SemiMinorAxis,RotationAngle等。对于圆弧圆的一部分其长半轴和短半轴是相等的这个值就是半径。3.2 异步编程模式ArcGIS Pro SDK 广泛采用了基于任务的异步模式TAP。几乎所有涉及用户界面或地理处理的操作都必须是异步的以防止界面卡死。这意味着我们的工具方法需要标记为async并使用await关键字来调用异步 API。protected async override void OnClick() { // 工具点击事件 await QueuedTask.Run(() { // 在这里执行核心的、耗时的地理处理逻辑 ProcessFeatures(); }); // 异步操作完成后的后续处理 }QueuedTask.Run方法确保其中的代码在 ArcGIS Pro 的内部地理处理线程上运行这是访问和修改几何对象的必要条件。3.3 属性与标注的生成计算出的半径需要被持久化。有两种主要方式创建新要素类在现有或新建的要素类中为每个圆弧中心点创建一个点要素并将半径值写入该点的一个属性字段中。这种方式数据管理清晰便于后续查询和分析。图形标注在MapView上直接添加一个图形元素GraphicElement以文本形式显示半径。这种方式是临时的不会保存到地理数据库中适合快速查看。本文将重点介绍第一种更实用的方式——创建新的点要素类来存储结果。4. 完整实战开发圆弧线半径标注加载项接下来我们将一步步创建一个完整的加载项。4.1 创建新项目打开 Visual Studio 2022。点击“创建新项目”。在搜索框中输入“ArcGIS Pro”选择“ArcGIS Pro 模块”模板这是一个包含基础按钮和工具的项目模板适合初学者。点击“下一步”。为项目命名例如ArcRadiusAnnotator。选择合适的位置和解决方案名称。点击“创建”。在弹出的“配置新模块”窗口中可以修改模块名称和描述暂时保持默认即可。点击“确定”。项目创建完成后解决方案资源管理器会显示生成的文件结构。4.2 设计 DAML 配置打开Config.daml文件。这个文件定义了UI。我们找到tool相关的部分修改或添加我们自己的工具定义。!-- 在 modules 标签内找到或添加一个 tool 定义 -- tool idArcRadiusAnnotator_RadiusAnnotationTool caption圆弧半径标注 categoryArcRadiusAnnotator_Tools classNameRadiusAnnotationTool keytipRAT loadOnClicktrue smallImageImages\GenericButtonRed16.png largeImageImages\GenericButtonRed32.png conditionesri_mapping_mapPane tooltip heading圆弧半径标注 选择线图层自动计算并标注圆弧段的半径。disabledText //tooltip /tool同时我们需要确保这个工具被放置在一个菜单或工具栏中。在DAML文件中找到menus或toolbars部分添加我们的工具引用。updateModule refesri_core_ribbon insertToolbar refesri_core_editingToolbar positionlast tool refArcRadiusAnnotator_RadiusAnnotationTool / /insertToolbar /updateModule这段代码意思是将我们的工具插入到 ArcGIS Pro 核心的编辑工具栏的末尾。4.3 实现核心工具逻辑现在在项目中创建一个新的类文件命名为RadiusAnnotationTool.cs。这个类需要继承ArcGIS.Desktop.Mapping.MapTool。using ArcGIS.Core.CIM; using ArcGIS.Core.Data; using ArcGIS.Core.Geometry; using ArcGIS.Desktop.Core.Geoprocessing; using ArcGIS.Desktop.Framework.Threading.Tasks; using ArcGIS.Desktop.Mapping; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace ArcRadiusAnnotator { internal class RadiusAnnotationTool : MapTool { public RadiusAnnotationTool() { // 设置工具属性这是一个草图工具但我们将用它来触发处理逻辑 IsSketchTool true; SketchType SketchGeometryType.Rectangle; SketchOutputMode SketchOutputMode.Screen; } protected override Taskbool OnSketchCompleteAsync(Geometry geometry) { // 当用户在地图上完成绘制例如点击或框选后此方法被调用 // 我们在这里启动核心处理流程 return QueuedTask.Run(() { try { // 1. 获取当前活动地图 var map MapView.Active.Map; // 2. 获取用户当前选择的线图层这里简化处理实际中可能需要更复杂的图层选择逻辑 // 例如可以遍历地图中的所有图层找到第一个线图层或者通过UI让用户选择 var lineLayers map.GetLayersAsFlattenedList().OfTypeFeatureLayer().Where(lyr lyr.ShapeType esriGeometryType.esriGeometryPolyline).ToList(); if (!lineLayers.Any()) { ArcGIS.Desktop.Framework.Dialogs.MessageBox.Show(当前地图中没有找到线图层。, 提示); return false; } // 为了示例我们取第一个线图层 FeatureLayer targetLayer lineLayers.First(); // 3. 创建一个新的点要素类来存储结果 // 首先获取目标图层的路径地理数据库和数据集 var table targetLayer.GetTable(); var dataset table.GetDatastore() as Geodatabase; var featureDataset dataset.GetDatasets().OfTypeFeatureDataset().FirstOrDefault(); // 假设在线图层所在的数据集 // 定义新要素类的名称和空间参考 string newFcName targetLayer.Name _RadiusPoints; var sr targetLayer.GetSpatialReference(); // 使用Geoprocessing工具创建点要素类 var createParams new Liststring { System.IO.Path.Combine(featureDataset.GetPath(), newFcName), // 输出路径 POINT, // 几何类型 , // 模板空 DISABLED, // 是否启用M值 DISABLED, // 是否启用Z值 sr.WKT // 空间参考 }; // 执行创建要素类工具 var createResult Geoprocessing.ExecuteToolAsync(CreateFeatureclass_management, createParams).Result; // 4. 打开新创建的点要素类进行编辑 using (var newFc dataset.OpenDatasetFeatureClass(System.IO.Path.GetFileName(newFcName))) using (var rowBuffer newFc.CreateRowBuffer()) { // 5. 定义新要素类的字段除了系统默认的ObjectID, Shape外我们添加一个Radius字段 // 注意CreateFeatureclass工具已创建Shape字段。我们需要添加Radius字段。 // 这里简化实际应在创建要素类时通过字段定义参数添加字段。 // 更佳实践使用Geoprocessing的“AddField”工具或在CreateFeatureclass时指定template。 // 为了流程完整我们假设Radius字段已存在。 // 6. 遍历目标线图层的每一个要素 using (var rowCursor targetLayer.Search()) { while (rowCursor.MoveNext()) { using (var feature rowCursor.Current as Feature) { var polyline feature.GetShape() as Polyline; if (polyline null) continue; // 遍历多段线的每个部件 foreach (var part in polyline.Parts) { // 遍历部件中的每个线段 foreach (var segment in part) { // 检查是否为椭圆弧线段 if (segment is EllipticArcSegment arcSegment) { // 7. 计算圆弧半径 // 对于椭圆弧SemiMajorAxis 是长半轴SemiMinorAxis 是短半轴。 // 对于圆弧圆的一部分两者应相等即为半径。 double radius arcSegment.SemiMajorAxis; // 单位与数据空间参考一致 // 也可以使用中心点和圆弧上的点来计算距离作为验证 // double radius GeometryEngine.Instance.Distance(arcSegment.CenterPoint, arcSegment.StartPoint); // 8. 获取圆弧的中心点作为标注点位置 MapPoint annotationPoint arcSegment.CenterPoint; // 9. 创建新的点要素 rowBuffer.SetValue(rowBuffer.FindField(Shape), annotationPoint); // 设置几何 // 假设有一个名为“Radius”的字段 int radiusFieldIndex rowBuffer.FindField(Radius); if (radiusFieldIndex ! -1) { rowBuffer.SetValue(radiusFieldIndex, radius); } using (var newRow newFc.CreateRow(rowBuffer)) { // 行已创建并保存 } } } } } } } } // 10. 将新创建的图层添加到当前地图 Layer newLayer LayerFactory.Instance.CreateLayer(new Uri(System.IO.Path.Combine(featureDataset.GetPath(), newFcName)), map); ArcGIS.Desktop.Framework.Dialogs.MessageBox.Show($半径标注完成已创建图层{newFcName}, 成功); return true; } catch (Exception ex) { ArcGIS.Desktop.Framework.Dialogs.MessageBox.Show($处理过程中发生错误{ex.Message}, 错误); return false; } }); } } }代码关键点解释OnSketchCompleteAsync: 这是工具的主入口。用户在地图上点击后触发。QueuedTask.Run: 确保所有对 ArcGIS Pro 对象模型尤其是几何对象的访问都在正确的线程上。EllipticArcSegment: 关键类用于判断和获取圆弧参数。CreateFeatureclass_management: 通过地理处理工具创建新的要素类这是管理数据最可靠的方式。遍历逻辑通过Polyline.Parts和Part的枚举器可以访问到每一个Segment。错误处理使用try-catch捕获异常并通过消息框反馈给用户。4.4 编译、调试与部署编译在 Visual Studio 中按F6或点击“生成解决方案”。确保没有编译错误。调试按F5启动调试。Visual Studio 会自动启动一个新的 ArcGIS Pro 实例并安装你的加载项。在 ArcGIS Pro 中测试在新的 ArcGIS Pro 窗口中打开或创建一个包含线要素最好是包含圆弧段如道路中心线的地图。在“编辑”选项卡的工具栏中你应该能找到我们添加的“圆弧半径标注”按钮图标为红色。点击该按钮然后在地图视图上点击一下我们的工具是草图工具需要一次交互来触发。观察结果。如果一切顺利会弹出一个成功消息并且地图中会添加一个新的点图层点位于圆弧中心属性表中包含半径值。打包部署开发测试完成后可以在 Visual Studio 中右键点击项目选择“发布”Publish。这将生成一个.esriAddinX文件。其他用户只需双击这个文件即可在他们的 ArcGIS Pro 中安装此加载项。5. 常见问题与排查思路在开发和运行过程中你可能会遇到以下问题问题现象常见原因解决思路编译错误找不到 ArcGIS.Desktop... 命名空间1. ArcGIS Pro SDK 未正确安装。2. 项目引用丢失或版本不匹配。1. 在 VS 扩展管理中确认 SDK 已安装并重启。2. 检查项目引用确保引用的ArcGIS.Desktop.*程序集路径正确通常指向%APPDATA%\Esri\ArcGISPro\AssemblyCache。可以尝试删除引用后重新添加。工具按钮在 ArcGIS Pro 中不显示1.Config.daml文件配置错误如condition不满足。2. 工具类名与 DAML 中className不匹配。3. 加载项未成功激活。1. 检查 DAML 文件的 XML 语法确保condition是有效的如esri_mapping_mapPane表示地图窗格激活时。2. 确保className属性值包括命名空间与后台 C# 类的全名完全一致。3. 在 ArcGIS Pro “项目”-“选项”-“附加模块”中查看你的加载项是否被列出并已勾选启用。运行时错误InvalidOperationException(非 GUI 线程)在QueuedTask.Run外部访问了地图或几何对象。所有涉及MapView.Active.Map、FeatureLayer.GetFeature、几何运算的代码都必须包裹在QueuedTask.Run(() { ... })或await QueuedTask.Run(...)内部。无法识别椭圆弧线段1. 线要素本身由直线段构成没有圆弧。2. 数据来源不同曲线可能以密集折线Densified Polyline或贝塞尔曲线形式存储。1. 使用 ArcGIS Pro 的“编辑”工具创建一条真正的圆弧线进行测试。2. 对于密集折线需要编写算法如三点定圆法来从一系列顶点中拟合出圆弧段并计算半径。这超出了本文基础工具的范围。创建的要素类没有Radius字段在代码中我们假设目标字段已存在但创建要素类时并未实际添加该字段。在调用CreateFeatureclass_management后应紧接着调用AddField_management地理处理工具来添加Radius双精度型字段。或者在创建时通过template参数指定一个包含所需字段的模板要素类。半径计算值异常过大或为01. 空间参考单位问题如数据是经纬度计算出的“半径”是度。2. 椭圆弧不是正圆SemiMajorAxis不等于SemiMinorAxis。1. 在计算和显示时考虑将半径转换为更直观的单位如米。可以使用GeometryEngine.Instance.Distance计算实际地面距离。2. 对于椭圆弧严格来说没有单一的“半径”。本工具主要针对圆弧。可以输出长半轴和短半轴或计算平均半径。6. 最佳实践与工程建议将一个小工具打造成健壮、易用的产品还需要考虑更多工程化细节。6.1 增强用户体验图层选择对话框不应默认选择第一个线图层。更好的做法是弹出一个自定义窗格DockPane让用户从图层列表中选择一个或多个目标图层。进度反馈处理大量要素时操作会耗时。应该在UI上显示进度条Progressor让用户知道处理状态。参数配置允许用户配置输出要素类的名称、位置以及半径的单位是保持原单位还是转换为米、英尺等。6.2 代码优化与健壮性异常处理细化当前的try-catch块太笼统。应该对文件访问、数据库操作、几何计算等不同环节进行更精细的异常捕获和提示。资源释放确保所有RowCursor、RowBuffer、Geodatabase等实现了IDisposable接口的对象都在using语句中或正确调用Dispose()。算法健壮性三点定圆法在点共线时会出现问题。实现拟合算法时要增加数值稳定性检查和容错处理。6.3 数据与生产环境考量编辑会话如果工具需要修改现有图层而非创建新图层所有的编辑操作必须在编辑会话EditOperation内进行以支持撤销/重做。版本化数据库在企业级地理数据库中操作时要考虑到版本化、冲突检测等问题。性能遍历极大数量的要素和线段可能很慢。考虑提供“仅处理选中要素”的选项或使用空间查询先过滤出可能包含圆弧的区域。6.4 扩展功能思路一个基础的半径标注工具可以扩展为更强大的“道路弯道分析工具包”标注样式化不仅存储属性还能根据半径大小如急弯、缓弯自动生成不同颜色和样式的标注图形。批量报表生成计算完后自动生成一个包含所有弯道位置、半径、所在道路名称的 CSV 或 PDF 报告。安全分析结合设计标准对弯道半径进行合规性检查标记出半径小于安全标准的“危险弯道”。动态标注实现一个地图工具让用户点击任意一个弯道实时显示其半径和相关信息。本文从实际需求出发详细讲解了在 ArcGIS Pro 中开发一个自定义加载项来解决圆弧线半径标注问题的完整流程。从环境搭建、SDK 核心概念理解到 DAML 配置、工具类实现再到常见问题排查和工程化建议涵盖了从零到一的关键步骤。希望这篇教程能帮助你顺利开启 ArcGIS Pro 二次开发之旅将想法转化为能够切实提升工作效率的工具。