王光昇 ,周奎
(天津市测绘院,天津 300381)
AutoCAD 软件是国内地形图数据采集加工的主流软件,它为开发人员提供了丰富的开发接口,便于我们定制开发满足专业应用需求的应用程序。为了满足国家新版地形图图式、数据字典的要求,天津市测绘院开发了基于AutoCAD Map3D 的地形图采集编辑软件,该软件实现了局部拓扑构面功能,即通过已有的边界自动生成多边形。最初,我们通过Map3D 的Clean、Topology 等功能来实现,但经过应用测试,发现这种方法存在弊端,首先,Clean 操作会生产中间数据,对于最终结果而言,这些数据是没有用的;其次,Map3D 的Clean、Topology 功能没有完全释放选择集,在同一绘图环境下多次应用会产生“超出选择集数量的最大范围”的问题,而采集软件中的拓扑构面功能应该是能够与用户交互的反复调用的工具,所以这种构建多边形的方法是不可取的。本文阐述了在AutoCAD 中引入符合OpenGIS 标准的GIS 分析、操作类库NetTopology-Suite,通过GIS 解决方案对AutoCAD 中的线状对象进行空间分析,生成拓扑多边形。这种方法的优点是:采用完全的几何运算,不产生中间数据,速度快;不依赖于Map3D 软件,降低了对CAD 软件平台的要求。
NetTopologySuite(以下简称NTS)是著名的JTS Topology Suite 的C#/.NET 版本,NTS 项目的目的是提供一个基于.NET,快速、稳定的GIS 解决方案,以应用于所有.NET 平台,包括各类嵌入式设备。
JTS Topology Suite 是一个OpenGIS 标准的GIS 分析、操作类库,它实现了OGC(Open Geospatial Consortium)定义在SFS(Simple Features Specification)中的简单对象模型,提供了完整的二元比较集合,支持的空间关系包括:equals、disjoint、touches、crosses、within、contains、overlaps;JTS 支持基本的空间分析方法,包括:Intersection、Union、Difference、Symmetric Difference、Convex hull、Buffer。同时,JTS API 支持用户自定义精度模型。
程序实现的基本流程如图1所示。
图1 程序基本流程
用户输入的数据主要包括3 项:线状边界、精度模型比例尺、多边形内一点。
NTS 允许用户指定一个明确的精度模型,即输入坐标值精确的位数。实现方法如下:
PrecisionModel _precisionModel;
GeometryFactory _geometryFactory;
_precisionModel.Scale=in_scale;
_geometryFactory = new GeometryFactory(_precisionModel,0);
在后续的步骤中,用_geometryFactory 的CreateLineString 方法建立的LineString 对象都受到精度模型_precisionModel 的约束,如:
ILineString lstr=_geometryFactory.CreateLineString(
cl.ToCoordinateArray());
分如下几步:
第一,用AutoCAD 的几何类型存储每条边界线的每一段。如果是直线段(Line),用LineSegment2d 类型存储,如果是弧段,用CircularArc2d 存储,如果是多段线(Polyline),由于它是由多个直线段(或弧段)组成的,所以可以将其存储为LineSegment2d 与CircularArc2d 的集合。使用几何类型存储后,后续的坐标信息读取、几何运算就不用再读取CAD 对象了,可以有效地提高运算速度。
第二,建立LineString 集合。将直线段直接创建LineString 对象并存入集合中;对于弧段,首先计算与其他所有线段的交点,然后对交点排序,再分割弧段为子弧段,最后,对子弧段进行加密、创建LineString 对象存入集合。
分割弧段时,首先要对弧上所有分割点按照相对起始点的参数(或距离)进行排序,如图2所示:
图2 分割圆弧
排序方法为:
其中,MyCompare 是自定义的比较器:
然后取得相邻两个分割点之间子弧段,方法如下:
分割子弧段后,还需要按4.2 所述的方法加密子弧段。
通过上面的分析处理,我们已经准备好了用于拓扑分析的原材料,即LineString 集合,在生成多边形之前,需要进行图形规范化,其中最主要的是打断交叉对象,如图3所示:
图3 打断交叉对象
实现方法如下:
NTS 提供了Polygonizer 类,可以对规范化之后的LineString 集合进行处理,获取多边形,方法为:
Polygonizer polygonizer=new Polygonizer();
polygonizer.Add(nodedLineStrings);
IList <IGeometry >polys=polygonizer.GetPolygons()as IList <IGeometry >;
遍历所有多边形,包含用户输入的区域内一点的多边形即为目标多边形。
上述目标多边形点表中如果包含子弧段加密点,那么我们必须对加密弧段信息进行解析,复原弧段信息,才能得到最终的结果,详见4.2。
程序整个过程,仅仅在用户输入边界数据之后,我们读取了一次AutoCAD 线状边界数据,并保存到几何类型中,之后所有的运算都是通过几何运算来实现的,最大限度地减少了对AutoCAD 对象的直接操作。这样既提高了运算速度,又增强了程序的稳定性。
基于此设计思想,在输出结果多边形时,我们并不直接创建具体的AutoCAD 闭合多段线,而是通过ResultBuffer 类型返回多边形点表及凸度信息,然后由调用函数完成具体对象的创建。
通过NTS 在AutoCAD 实现拓扑多边形的构建,需要解决两个关键的问题:
刚开始研究本课题的时候,没有用到精度模型,很快就遇到了一些奇怪的问题:在CAD 中明明是能够形成闭合的边界,但在NTS 中却得不到多边形。如图4所示,a、b、c 是由不同的边界围成的闭合区域,用NTS构面时,可能只能得到a、b 两个多边形。
图4 NTS 构面
经过研究发现,NTS 在处理坐标精度时,默认情况下使用精密精确度模型,即用双精度表示,自从Java使用IEEE-754 浮点标准以来,它就提供了53 位的精确度。过高的精度设置使得NTS 在比较两个双精度浮点数是否相等时过于严格,导致我们无法得到期望的结果。图4中区域c 中边l1的终点和边l2的起点由于精度要求过高,使得NTS 认为它们并不重合,所以无法构建多边形。
为了解决这一问题,我们先后测试了两种方法:
第一种,在AutoCAD 中,先将所选的线状边界对象放大一定的比例(相当于精度模型中的比例尺),分析处理以后,再恢复对象比例。这种方法虽然解决了精度问题,但是需要修改CAD 对象,并不是最理想的方案。
第二种,NTS 中精度模型的设计很好地解决了这一难题。精度模型包括三种类型:固定精度、浮点精度、精密精确度。这里使用固定精度模型,替代了前一种方法,程序编写起来更简单、结构更清晰、代码更易于维护。
如图5所示,只有分割圆弧后再进行圆弧加密,最终生成的多边形才能解析出弧段信息。圆弧的分割点1、2 是多边形的特征点,是解析子弧段信息的重要依据,是不能遗失的。而在(a)中只是粗略地对整个圆弧进行加密,遗失了特征点,所以不能再解析子弧段了;(b)中先对整个圆弧进行分割,然后对每个子弧段进行加密,生成的多边形中不仅包含了特征点,而且包含了完整的子弧段加密信息,所以能够解析出子弧段的信息。
图5 圆弧分割、加密与解析
圆弧的分割方法3.3 中已经提到,子弧段加密的方法如下:
Point2d[]pts=sub_arc.GetSamplePoints(20);
即对所有圆弧的采样点取固定的数值,这里取值20。采样点仅仅是为处理圆弧而使用的临时点,所以选取数量可以自己设定,但要前后统一,考虑到效率问题,也不宜选取太多的点。
解析子弧段的方法:
遍历所有子弧段,每个子弧段取采样点20 个,将采样点集合与多边形上的点进行比较,如果都落在多边形上,则该子弧段的圆弧信息就应该映射到多边形上,作如下处理:保留多边形上与采样点集合中首尾点重合的点,移除与中间的点重合的点,然后计算凸度值,即可恢复子弧段信息。如图5中(b)、(c)所示。
计算3 点圆弧凸度的方法为:
// s_pt 是起点,e_pt 是终点,i_pt 是弧上一点
private static double GetBulgeBy3Pt(Point2d s_pt,Point2d e_pt,Point2d i_pt)
{
//i_pt 到e_pt 的角度
double angle1 =i_pt.GetVectorTo(e_pt).Angle;
//s_pt 到i_pt 的角度
double angle2 =s_pt.GetVectorTo(i_pt).Angle;
double bulge=Math.Tan((angle1 - angle2)/ 2.0);
return bulge;
}
如图6所示,拓扑得到的多边形为一个带有内环的多边形,经过圆弧处理,所有的弧段信息都正确地解析出来了。在NTS 中,读取Polygon 对象的坐标时,用ExteriorRing 属性获得外环坐标,用InteriorRings 获得所有内环信息,如:
图6 环状拓扑多边形
Coordinate[]pts1 =poly.ExteriorRing.Coordinates;
foreach (LineString ls in poly.InteriorRings){
Coordinate[]pts2 =ls.Coordinates;
}
目前,很多开源的GIS 软件都将NTS 作为其空间几何对象运算、处理的插件。本文讨论了如何在AutoCAD 中引入NTS GIS 分析、操作类库,实现拓扑多边形的构建。其中,对精度模型的建立和圆弧信息的处理两个关键问题进行了深入的论述,并提出了解决方案。
总之,NTS 的很多功能都可以移植到CAD 平台,为CAD 的数据处理提供更丰富的空间分析手段,具有很强的实用价值。
[1]JTS Topology Suite Developer’s Guide[R].2003,9 ~12.
[2]JTS Topology Suite Technical Specification[R].2003.
[3]Nagel.C.C#高级编程[M].北京:清华大学出版社,2008.
[4]Charles McAuley.AutoCAD 2000 ObjectARX 编 程 指 南[M].北京:机械工业出版社,2000.
[5]李冠亿.深居浅出AutoCAD 二次开发[M].北京:中国建筑工业出版社,2012.
[6]王文波,邹清源,张斯珩等.AutoCAD 2010 二次开发实例教程(ObjectARX)[M].北京:机械工业出版社,2013.