ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

ArcGIS批量出图插件:动态文本与坐标表全自动实现

ArcGIS批量出图插件:动态文本与坐标表全自动实现 干了这么多年测绘内业我最怕听到的一句话就是“这批地块图明天要交”。权籍调查、宅基地确权、基础测绘项目凡是跟地块打交道的活都逃不开一件事一个地块一张图图名、地块编号、权属人、面积、坐标表全部要自动带出来。如果还在手动放大到每个地块、手动改标题、手动翻Excel表格填坐标一天出二十张图已经是极限。所以我把整套流程整理成了一个可复用的arcgis插件核心就两个词动态文本、动态节点坐标表。这篇文章把工具的完整设计思路、实现细节、踩坑记录都摊开讲适合正在被批量图幅折磨的测绘内业人员也适合想自己动手写GIS自动化小工具的同学参考。1. 这个工具到底解决什么问题1.1 手动出图的那些坑先说说没有这个工具之前一天是怎么过的。打开ArcMap加载地块图层放大到第一个地块调整数据框范围到刚好显示完整手动改图名、填地块编号、抄权属人、复制粘贴面积再打开Excel把界址点坐标一行行填进表格里最后导出PDF。这一套流程下来一张图少说十五分钟遇到地块形状不规则、需要旋转坐标表方向的半小时都不一定够。如果项目里有三百个地块光出图就得耗费一两周而且全程都是机械性重复劳动人还特别容易出错——图名写串行、面积抄错一位数、坐标表漏掉一个点审图的时候被质检打回来又得重新来一遍。批量出图这件事本质上就是把四个环节自动化数据框自动切换、字段信息自动填入、坐标表自动生成、图纸自动导出。只要这四个环节打通人工只需要做一件事审核。这也是我做这个插件的核心思路——不是要替代内业人员而是把重复劳动全部拿走让人去做机器做不了的质量判断。1.2 工具定位和功能清单这个工具的实际形态是一个ArcGIS Add-in插件装好之后在ArcMap工具栏上多出一排按钮不需要打开一堆脚本窗口去敲命令。界面上的操作简化成三步选地块图层、选模板、点导出。工具内部跑的是Python脚本处理逻辑全部封装在按钮事件里。功能上我把它分成两条主线动态文本图名、地块编号、权利人、面积、比例尺、页码等信息全部通过动态文本绑定到地块属性字段上页面切到哪个地块这些文字就自动变成哪个地块的值。动态节点坐标表自动读取当前地块的所有折点坐标计算表格的摆放方向沿地块主方向旋转再生成一张坐标表图片插入到图框里点号、坐标值、边长全部自动排好。这两条线配在一起才能真正实现“一个按钮出一批图”。如果只做动态文本坐标表还是要手动填效率只提升一半如果只做坐标表图名图号还是手动改出图速度同样上不来。两者必须同时自动化才叫完整的批量出图。2. 动态文本与按地块切图的实现原理2.1 数据驱动页面批量出图的地基在ArcGIS里按地块自动切图本身有一套现成的机制叫做Data Driven Pages中文界面里叫数据驱动页面。原理很简单指定一个图层作为索引图层这个图层里的每一个要素就对应PDF里的一页ArcMap会自动把数据框的范围缩放到当前要素的外包矩形上。举个例子我把一个村的地块图层设为索引图层这个村有八十个地块数据驱动页面就会生成八十页。每一页对应一个地块数据框自动居中、自动缩放不需要手动放大缩小。但是原生数据驱动页面有一个明显短板它只解决了“视图范围自动切换”的问题并没有解决“图面文字自动更新”的问题。地块编号、权利人、面积这些信息索引图层里有字段但ArcMap默认不会自动帮你填进图名图框里。这就是动态文本要补的位。2.2 动态文本标签规则与模板摆放动态文本本质上是一段XML标签放在布局的文本元素里。ArcMap在布局视图下插入动态文本时界面会列出很多类型页码、页数、页面名称、当前日期、文档路径、文档标题、自定义表达式等。每个类型背后就是一段XML标签。我实际用得最多的是这几类动态文本类型标签示例说明页码dyn typepage propertynumber/当前页序号比如1总页数dyn typepage propertycount/总页数比如80页面名称dyn typepage propertyname/显示当前页面对应索引要素的显示表达式自定义表达式dyn typepage propertyexpression fieldname图层名.字段名/直接引用索引图层某个字段的值页面名称是我用得最频繁的。只要把地块图层的显示表达式设置成“地块编号”那dyn typepage propertyname/就会显示当前地块的编号。标题栏里的图名我一般用一个组合表达式拼出来比如“XX项目宗地图”加地块编号这样在模板里只需要放一行文字就能同时体现项目名和图名。摆放位置上我的习惯是左上角放项目名和比例尺正上方放“宗地图”大标题左上或右上放地块编号、权利人、面积信息框图框右下角放坐标表左下角放制图人、日期、页码。这个布局是跟测绘制图规范对齐的动态文本替换的只是文字内容底图框、指北针、图例这些静态元素还是手动摆好。2.3 动态文本为什么能“动”很多第一次接触动态文本的人会有一个疑问这不就是个普通文本吗为什么切页的时候它会变关键在于ArcMap的布局引擎在每次刷新页面时会重新解析一遍文本元素里的XML标签。当前页面对应的是索引图层里的哪个要素XML标签里的属性就绑定到那个要素的哪个字段。也就是说页面编号从1切到2时dyn typepage propertyname/里绑定的要素变了显示的内容自然跟着变。理解了这个机制就能明白一个很重要的点动态文本绑定的字段必须是索引图层里的字段或者至少是能通过索引图层关系访问到的字段。如果地块编号存在另一个表里没有提前关联到索引图层动态文本是拿不到值的。这一点在前期数据处理时就要注意否则到出图阶段会发现所有页面的图名都一样——因为字段本身就是空的或者绑定关系没建立。另外还有一个细节数据驱动页面的索引图层可以是Shp文件也可以是要素类但建议统一放在地理数据库GDB里。Shp文件的字段名长度限制在10个字符以内中文字段名还会出现乱码风险放到GDB里这些问题就都不存在了。我一开始是用Shp做索引图层的结果字段名短、中文显示异常排查了整整一天才找到原因后来全部改成GDB要素类一劳永逸。3. 动态节点坐标表从坐标到表格的全自动流水线3.1 地块折点坐标怎么读、怎么转节点坐标表就是界址点成果表一个多边形地块每个转折点的点号、X坐标、Y坐标有的还包括边长的列表。这个表是地籍图、宗地图的标配但也是批量出图里最麻烦的一块。先说坐标从哪来。ArcPy里读取一个地块要素的几何对象遍历geometry.getPart(0)就能拿到这个多边形的所有折点每个折点取point.X和point.Y。注意一个多边形可能带内环比如一个地块中间抠掉一块水塘内环坐标要单独处理不要跟外环混在一起否则表格里点号顺序就乱了。坐标获取之后要解决坐标系问题。地块图层本身如果是地方坐标系比如CGCS2000高斯投影的某度带那读出来的坐标就是平面坐标直接填表没问题。但有些成果要求填经纬度这就得在读取时做投影转换arcpy.Project_geometry可以处理。我在做的时候遇到一个带号相关的坑有些地方用的是独立坐标系中央经线不是标准的3度带整数倍如果拿标准投影参数去转换坐标会偏出去几百米。所以我在插件参数里专门加了一个选项让用户选择“沿用数据框坐标系”还是“转国家2000经纬度”而不是写死一套转换参数。3.2 表格朝向与旋转角度的计算坐标表不是简单堆在角落就行正规图纸上坐标表的横排方向应该尽量跟地块的主轴方向一致这样图纸空间利用合理也便于查看。实际工作中很多地块是斜的如果表格永远横平竖直一边空出一大片另一边挤得要命。要计算主轴方向我采用的办法是对地块的所有折点坐标做PCA主成分分析取第一主成分的方向作为主轴方向角。原理可以这么理解PCA找到数据方差最大的方向对于狭长地块来说最长的那个方向就是主轴。平面几何上还可以用最小外接矩形来做但算法复杂一些。实际测试下来PCA的实现代码短计算速度快而且对绝大多数地块形状都够用。公式上对于n个点(xi, yi)先算中心点坐标(x0, y0)然后构造协方差矩阵求协方差矩阵的特征值和特征向量最大特征值对应的特征向量的角度就是主轴方向角θ用math.atan2算出来再转成角度制。拿到θ之后坐标表里显示的点位是做了一次平面旋转的旋转后的本地坐标(X, Y)满足X (X - X0) * cos θ (Y - Y0) * sin θ Y -(X - X0) * sin θ (Y - Y0) * cos θ这样处理后表格第一行点号1的坐标约等于(0,0)后续点就在这个本地坐标系里排开表格整体自然就沿着地块的主轴方向“躺”在图纸上。实际使用时我还会判断一下角度是否超过90度如果超过就再加180度避免表格头朝下、字倒着看。3.3 坐标表插入布局的三种方案坐标数据算好之后要放进布局里。这里有三条路可以走我分别试过方案A生成Excel文件再把Excel截图贴进布局。缺点是每张图都要调用Excel速度慢而且Excel截图的分辨率不容易控制放大容易虚。方案B用ArcObjects插入TableFrame表格框架这是ESRI官方面向复杂制图的标准做法但需要.NET或Java环境Python脚本里做这件事很别扭开发成本高。方案C用Python生成一张位图表格插入到布局这也是我最终采用的方案。先在一个空白的位图画布上用PIL库把点号、坐标值一行一行画出来整个表格渲染成PNG图片然后用arcpy.mapping.AddPictureElement把这个图片加到布局里。每切到一个新的地块就重新算一次坐标、重新生成图片、重新更新图片元素的source路径。有人说位图表格不是矢量图导出PDF会不会糊实际上只要生成图片时把分辨率拉到300dpi以上打印到A4纸上完全够用。我实测600dpi渲染出来的坐标表放到图框里占8cm宽度放大看数字边缘都很锐利。而且位图方案在处理旋转、带边框、中文字体等问题上极其方便直接就是控制像素没有字体丢失的问题。插入布局时还有个关键点要把图片元素放在坐标表占位区域的正中间且每次生成的新图片尺寸应该保持一致只是内容不同。这样才能保证切页时坐标表不会在图纸上跑来跑去。我在代码里固定了表格的宽度、行高、列宽和字体大小只让行数随坐标数量变化行数不足的地方用空行补齐这样所有页面的坐标表位置和大小看起来是统一的。4. 完整实操建模板、配参数、一键出图4.1 准备工程文件和图层用这个插件之前要先准备好三样东西一个已经配好符号化效果的地块图层、一个出图模板mxd、一个输出文件夹。地块图层的要求就一条每个地块必须有唯一标识字段比如“DKBH”或者“BSM”而且字段值不能有重复不能有空值。这个唯一标识是后面页面命名和图面关联的锚点。如果原始数据里没有就先跑一遍“要素转点空间连接”或者手动补字段不要拖到出图阶段才发现编号重复。模板mxd的准备工作是重头戏。打开ArcMap按正常流程加载地块图层调整符号化、设置好标注因为出图时图片范围虽然自动切换但图层显示效果是继承当前mxd的。然后切到布局视图设置页面尺寸A4或A3根据任务书要求添加图名、图框、指北针、比例尺、图例、坐标表占位区域和制图人信息栏。模板建好之后在“页面和打印设置”里启用数据驱动页面索引图层选地块图层名称字段选地块编号。这里名称字段很重要它会作为默认排序和页面标识。可以在数据驱动页面面板里预览翻页看看每个地块是否都能正确显示完整。4.2 插件参数配置插件界面上的参数不算多但每一项都影响最终出图效果。我设计的是这样一组配置参数名含义建议值索引图层地块面图层从当前文档中选择动态文本字段映射图名、编号、权利人字段与属性字段的对应关系按项目实际配置坐标表坐标系平面坐标/经纬度按成果要求坐标小数位坐标值保留位数2位或3位地籍图一般3位表格方向自动沿主轴/固定水平一般选自动沿主轴导出格式PDF/PNG/JPG批量出图用PDFDPI图片导出分辨率300打印要求高时选600命名规则地块编号/地块编号图号按项目要求这里最容易被忽略的是“动态文本字段映射”。虽然动态文本可以直接在模板里写死字段名但不同项目的字段名可能不一样比如有的叫“TDMJ”有的叫“TBDJ”如果插件里面写死换一个项目就得改代码。所以我把字段映射做成配置项出图前在界面上选一次工具内部再把选好的字段名组合成动态文本标签去更新模板。4.3 批量导出与文件命名参数配好之后点“开始出图”工具内部会循环做这几件事遍历索引图层里的每个地块要素按编号排序跳转到数据驱动页面的对应页触发布局刷新遍历模板里所有动态文本元素更新绑定字段信息读取当前地块的折点坐标计算主轴方向生成坐标表图片并更新布局中的图片元素调用arcpy.mapping.ExportToPDF导出当前页面到输出目录继续下一个地块。这一步里文件命名规则一定要提前想清楚。我见过不少项目因为文件名重复覆盖出完图发现少了十几张。命名规则我建议用“项目编号_地块编号_图号.pdf”比如XC2023_A-012_0123.pdf这样既能在文件夹里排序也不会重名。如果项目本身有任务编号表那就从配置表里读取宁可在这一步啰嗦一点也不要到最后归档时发现文件名乱七八糟。导出完成之后工具还会生成一个简单的日志文件记录哪些地块导出成功、哪些地块报错以及报错原因。这个日志在项目质量检查时非常有用不用自己记着哪张图失败了。5. 常见问题与排错经验5.1 动态文本不显示字段值这个问题我遇到得最多而且藏得比较深。模板里的动态文本在布局视图中显示为“!”或者“动态文本”之类的内容切页之后还是不变或者干脆全显示成同样的值。排查顺序是这样的先确认索引图层的显示表达式是否正确因为dyn typepage propertyname/显示的内容取决于索引图层的显示表达式再检查动态文本标签里的字段名是否写对字段名必须带图层名前缀比如地块图层.DKBH只在界面上选字段时看起来是一回事手写标签时很容易漏掉前缀最后检查字段值本身有没有空值空值是不报错的但会显示成空白。还有一个不太容易想到的原因Shp文件的字段名被截断。ArcMap对Shp文件字段名默认限制在10个字符内如果字段名超过长度电脑会自动截断你看到界面里的字段名不是原字段名那动态文本绑定肯定失败。解决方式就是把数据放到GDB要素类里不要用Shp做索引图层。5.2 坐标表方向不对、文字颠倒坐标表旋转方向不对基本是主轴角度计算那一步出了问题。最常见的情况是地块形状接近正方形PCA计算出来的第一主成分方向不稳定有时候指向45度有时候指向135度看起来就是表格方向一会儿朝左一会儿朝右。我的处理办法是计算完主轴角度之后先做一个方向修正角度范围控制在0到180度之内然后判断角度是否大于90度如果大于90度就减去180度并交换X、Y方向的符号。这样所有地块的坐标表都保证表头朝上或者朝左不会出现字头朝下的情况。另外补充一句坐标表里显示的点号顺序一定要跟地块数据的节点顺序保持一致。如果地块图层在矢量化的过程中节点方向有反转表格里会出现从某个点开始逆序排列的现象这时候需要用geometry.getPart(0)的节点原始顺序来判断是否需要反转有些数据源节点本身就是乱的这种情况我会在预处理阶段统一做一次“按顺时针重排节点”的处理。5.3 页面范围异常与性能瓶颈数据驱动页面默认的缩放模式是“适合页面”也就是把当前地块的外包矩形恰好缩放到数据框范围内。这个模式对长条状地块特别不友好——一个又长又窄的地块放到A4纸宽的框里结果地块在图面上占了一条线大部分区域是空的比例尺也被压得奇怪。我的做法是在模板数据框属性里调整动态范围“数据驱动页面”选“最佳范围”同时设置一定的缓冲比例比如地块外扩10%。这样既保证地块完整显示又不会出现半个图面空白的情况。如果还是遇到特别狭长的地块可以在预处理阶段把这类地块单独分出来处理人为调整比例尺。性能方面几百个地块循环导出时最怕渲染卡死。我的经验是把模板里的复杂标注改成静态缓存关掉实时预览的图层导出PDF时把Resolution设为300但不要把图片压缩选项打开否则坐标表会糊。还有一点很实用分批导出不要一次循环全部比如循环到第150个地块时调用一次arcpy.RefreshActiveView强制刷新释放内存否则连续导出超过三百个页面ArcMap经常白屏崩溃。5.4 快速排错速查表现象可能原因解决办法所有页面图名相同动态文本字段绑定错误检查字段名前缀和索引图层显示表达式坐标表空白地块要素没有折点或几何为空先跑一遍图层检查修复空几何坐标表文字倒置主轴角度未做方向修正角度90度时做方向和符号交换导出PDF缺少部分页地块编号重复导致文件覆盖命名规则里加图号或序号字段批量导出卡死内存溢出或渲染冲突分批导出定期刷新视图坐标值偏大或偏小投影带号或中央经线设置错误确认数据框坐标系检查地方独立坐标参数6. 扩展把出图工具做成“超级工具插件”6.1 出图前自动检查尖锐角等几何瑕疵批量出图跑起来之后我很快又发现一个前置问题有些地块几何图形本身不干净出出来的图没法交。最典型的就是尖锐角。一个多边形的某个内角特别小比如小于10度图面上两条边几乎叠在一起标注文字挤不下界址点坐标表里相邻两个点的距离又特别近打印出来根本看不清。这种地块就算动态文本和坐标表全自动化了出的图还是废图。所以我把一个“尖锐角检查”的功能做成了配套工具放在同一个插件面板里。原理不算复杂遍历每个地块的相邻三条边计算中间角的夹角用向量点积求余弦再反算角度小于阈值的就标记出来。阈值可以在界面上调默认10度因为老年份的住宅宗地图很多建筑转角就是90度附近小于10度的不太可能是正常建筑形状基本可以判定为数据问题。这个检查跑完之后插件会生成一个结果表包含地块编号、尖锐角位置点号、角度值、对应坐标同时在地图视图中把尖锐角所在位置用红旗符号标出来。人工根据标记去修图根、补节点确认没问题之后再来跑批量出图返工率下降非常明显。现在这个插件已经不只是出图工具更像是一个完备的内业质检小工具集。6.2 可以继续叠加的其他功能顺着这个思路我之前一直想做的还有一些扩展但不是每一条都已经实现界址点成果表的Word导出坐标表不仅出现在图面上很多地方要求单独交一份界址点成果表格式是按照不动产登记规范走的。在插件里加一个按钮选中地块后直接把坐标、边长、面积导成Word表格。面积对比检查批量出图前跑一遍图形面积和属性面积对比不相符的地块直接标红避免图面上的面积数和数据库里的面积数对不上。批量拓扑检查除了尖锐角还可以检查重叠、缝隙、自相交等拓扑问题合并进同一个预处理流程。升级到ArcGIS Pro Add-inPro的排版引擎比ArcMap强不少布局里的表格元素是原生支持的动态文本的绑定和表达式的易用性也比ArcMap好。把目前脚本迁移到Pro的Python环境里整套逻辑可以精简很多。我自己的收尾经验是这种内业工具不用追求大而全先把批量出图这一条主流程跑顺把坐标表和动态文本这两个最痛的点啃下来就能解决你80%的加班时间。剩下那些锦上添花的功能等真正遇到需求时再加毕竟咱们写工具是为了省时间不是给工具本身打工。
返回列表