基于AutoCAD.NET开发的悬挂点检查与自动处理
2018-07-21陈树林李国平
盛 杰 陈树林 李国平
(江西省地矿测绘院 江西南昌 330030)
1 引言
在测绘领域中,AutoCAD是一款常用的绘图软件,它常用于地图的编图、成图等图形处理操作。虽然它在成图制图方面能很好的满足需要,但AutoCAD不是一款专业的测绘软件,不具备测绘有关的功能。比如AutoCAD自身并不具备拓扑检查功能,然而对于地图编图、成图来说,拓扑检查是成图、入库的基础,是一个必不可少的要求。所幸的是AutoCAD支持二次开发,我们可以通过基于AutoCAD二次开发的方式扩展AutoCAD的功能,编写用户自定义工具。
研究现状。由于CAD软件广泛应用于测绘领域的成图,已有相关学者及技术人员针对CAD平台下悬挂检查与处理的问题做过研究并给出了很好的解决方法。在当时的技术背景下确实是很好的解决方案。但随着CAD二次开发技术的不断进步,特别是AutoCAD.NET API的发布,采用最新的AutoCAD.NET技术不论在程序执行效率还是在开发效率上都有了显著提升,能更好的解决此问题。
在《在AutoCAD中悬挂点的检查方法》及《基于CAD平台开发的悬挂点检查与自动处理》的论文中,分别采用AutoLISP和ObjectARX的方式解决问题。但采用AutoLISP程序执行效率略低,在处理大量数据是速度较慢,而采用ObjectARX技术虽然有着较高的执行效率,但开发难度较大,较为复杂,开发周期长,开发人员需要掌握 VC++[2]。在《基于 CAD平台开发的悬挂点检查与自动处理》一文中,虽然给出了很好的解决方案,但算法、逻辑对于普通测绘人员来说过于复杂,难以掌握,并且还是采用C++的开发方式,这就更令测绘人员望而却步,难以在测绘领域为广大测绘人员掌握、应用;而AutoCAD.NET采用程序集的方式直接调用,在拥有与C++相匹配的强大功能与效率的同时,还具有.NET简单易学易用的特点,使开发更为简单开发周期更短[1]。
当然也有人士提出采用AutoCAD.NET的方式处理悬挂点的问题,在《AutoCAD中一种自动处理悬挂的方法及其实现》一文中,采用的就是NET方式解决此问题。但作者在文中提出存在因线型(如虚线)导致悬挂点判断错误的问题[5]。本文采用线型预处理及恢复线型的方式很好的解决了此问题。并采用与之不大相同的方式对悬挂点进行自动处理,使其有更高的执行效率以及更广的实用范围。
2 技术手段
开发语言:C#;开发平台:Visual Stdio;调用CAD.NET API,实现程序功能。另外还调用AutoCAD ActiveX Automation(COM)组件的一些方法,来实现自定义菜单的添加。
3 程序设计
3.1 悬挂点检查
悬挂点就是线段的端点附近无其它线与之相连的点。因此,悬挂点的检查方法可以通过查找每一条线段的两端点在一定缓冲区范围内有无其它线来实现。具体步骤如下:
(1)新建项目
新建一个类库项目,然后添加AutoCAD安装目录下的acdbmgd.dll和acmgd.dll程序集的引用,以及CAD组件的引用。
(2)查找、遍历所有的多段线
通过设置一个过滤条件(SelectionFilter),查找所有的可见多段线(Polyline)。
(3)判断线段的端点是否悬挂的方法
假设某线段的端点为P(x,y),定义一个极小的缓冲范围:tol=0.0000001,在由(x-tol,y-tol)、(x+tol,y+tol)确定的矩形内,如果没有任何其它多段线与该矩形相交,则认为该点悬挂。如图1所示:
图1 判断端点是否悬挂
实现代码:
通过SelectCrossingWindow函数,获得与上图矩形区域相交的所有多段线。
PromptSelectionResult acSSPrompt=acDocEd.SelectCrossingWindow(new Point3d(point.X-tol,point.Y-tol,0),new Point3d(point.X+tol,point.Y+tol,0),acSelFtr);
遍历该选择集,如果该选择集存在图形的OBjectID不等于该多段线的OBjectID,则该端点不悬挂。否则,该端点悬挂。
(4)进行悬挂分析之前的图形预处理
在使用SelectCrossWindow函数时,需要注意一下几个问题:
1)SelectCrossWindow函数是在当前视图的范围内,获取两点定义的区域。
也就是说,当某线段端点不在当前视图范围内,其分析结果必然是个空集。从而导致分析结果的错误;另外,当图形缩放的很小,图形元素非常的密集,某线段端点的缓冲范围内会分析出大量的多段线。当图形缩放到合理范围时,在该缓冲区范围内是不存在这么多多段线的。因此,这也会导致悬挂判断的错误。
为解决上述问题,可以在对某端点进行悬挂判断之前,先将视图缩放到该端点附近范围。这样就会得到正确的结果。
2)特殊的线型与线宽也会导致SelectCrossing-Window函数得到错误的结果,如图2所示,由于要比较的多段线为虚线,导致多段线端点的缓冲区范围内,不存在与之相交的其它多段线,而得到错误的结果;
图2 线型导致悬挂判断错误
同样,如图3所示,由于线宽太粗,CAD会判定其与缓冲区不相交,也会得到错误的结果。
图3 线宽导致悬挂判断错误
为解决此问题,可以在悬挂分析前,将所有非实线线型以及所有宽度大于0的多段线,都转化成线型为实线,宽度为0的多段线。并将所有被修改过多段线的 ObjecctID、线型 (LineTypeId)、以及线宽(ConstantWidth)存储在数组变量中。以便在分析完成后,对线型、线宽的恢复。
(5)悬挂分析、分析结果展示、恢复线型线宽
采用步骤(3)的方法,对每条多段线的两端点进行悬挂分析,然后将存在悬挂的端点插入一个悬挂标记;并将所有的悬挂点放在一个列表框内,当选中某项时,视图就会自动缩放到该悬挂点,以便于对每个悬挂点的查找。最后,恢复步骤(4)改变的线型和线宽。分析结果如下图4所示。
图4 悬挂检查效果图
3.2 悬挂点的自动处理
(1)定义一个比判断端点悬挂更大的缓冲区范围,然后在该缓冲区范围内,查找有无其它多段线与该缓冲区范围相交,如图5所示。如果存在,则对该悬挂点进行自动处理。
图5 悬挂点的自动处理
(2)找出该多段线上离悬挂点最近的点:N,如图5所示。点N可通过调用该多段线的GetClosetPointTo函数来获得。代码如下:其中point为悬挂点。
Point3d nearPoint= polyline.GetClosestPointTo(point,false);
(3)求出最近点 N在多段线上的曲线参数parameter:
double parameter=polyline.GetParameterAtPoint(nearPoint);
然后根据曲线参数,求得邻近两节点A、B的节点序号。假设该多段线的起点是S,终点是E,则A点的节点序号aIndex为parameter的整数部分。
int aIndex=(int)Math.Floor(parameter);
B点的节点序号bIndex为parameter的整数部分加1。
int bIndex=(int)Math.Floor(parameter)+1;
最后通过该多段线的GetPoint3dAt函数,就可获得A、B两个节点。
(4)判断 A、B 两点是否在步骤(1)设定的缓冲区范围内。如果在,如上图5所示,B点在该缓冲区范围内,则移动悬挂点P到B点,消除该悬挂点。可通过调用多段线的SetPointAt函数来修改P点的坐标。
(5)如果 A、B 两点不在步骤(1)设定的缓冲区范围内,则在步骤(3)中的bIndex序号处,将最近点N作为新节点,插入到该多段线中 (调用多段线的AddVertexAt函数来实现节点插入);然后将悬挂点P移动到N点,进而消除该悬挂点。
与悬挂点检查类似,悬挂点的自动处理之前,也需要将视图缩放到各悬挂点附近范围;并调整非规则的线型与线宽,在此就不再赘述。
继续图4的悬挂点处理,点击“自动处理所有悬挂”按钮。处理后,结果如下图6所示。与之前悬挂点个数742相比,剩下314个悬挂点需要手工处理,程序共自动处理了428个悬挂点达到了预期目标。
图6 自动处理悬挂点效果图
3.3 悬挂缓冲区的设置
针对不同比例尺的地图,各自的悬挂点检查以及悬挂点自动处理的缓冲区范围(分别如图1、图5所示)也应该有所不同。如小比例尺的地图要设置较大的缓冲区,大比例尺的地图要设置较小的缓冲区,这样才能满足各自的需要。因此,为满足不同比例尺下悬挂处理的要求,本程序将缓冲区范围设置成可供用户修改设置的变量,从而满足不同比例尺地图的要求,如下图7所示:
图7 设置缓冲区范围
4 结束语
该程序经我院“湖南不动产登记DLG数据采集与入库项目”使用,平均每幅图悬挂点检查用时4秒,能查出所有悬挂点,约700个;悬挂点自动处理用时5秒,能自动处理掉约400个悬挂点。
(1)从程序正确性来看,程序能正确找出图幅内的所有悬挂点,无遗漏;并且能自动正确处理掉大部分的悬挂点,达到了预期效果。
(2)从程序执行速度来看,采用.NET的CAD开发,与前几代的AutoCAD开发技术相比,具有更高的执行效率。程序的查图、处理速度快,速度上令人满意,程序设计的算法切实可行。
(3)作为CAD下的一个拓扑检查与处理工具,该程序可用于其他项目地图的悬挂点检查与自动处理,具有较强的实用性。
结论:该程序解决了项目成果存在的悬挂点多,查找困难,处理费时费力的问题;大大提升了项目拓扑检查与处理工作效率,节约了项目查图、入库人力成本;提高了项目成果质量。