2007年,因为需求的缘故,写了一个ArcGIS的插件http://blog.csdn.net/jx1228/archive/2010/04/15/5488755.aspx,我自己定义了一种符号绘制方式,用户可以用我的插件绘制出更好的线型。在插件底层的实现过程中,我用了微软的GDI+组件,反锯齿的效果不错,效率也很高。这些年不断有人希望我能随ESRI的产品升级插件,当初开发的时候是基于ArcGIS9.2的,现在ArcGIS10了过段时间10.1版本也要出来了。当初写完插件,联系美国ESRI,让他们也能改进一下,但是他们也只是说会改进,现在看来他们对Server上有了改进,但是桌面还是没有改进。
最近花了些时间整理了一下问题,然后来改进原先写的组件。希望我改进这款组件的用户,大部分都是直接用ArcGIS软件面向制图的,地图的绘制效果对于他们来说,非常重要,仅次于效率问题;还有一些用户是Server用户,他们大都采用非池化机制的动态地图。上述我说过ESRI在Server上有改进,也只是在地图切片的过程中把生成图片的锯齿给平滑掉了。
目前的版本改进最大的地方是支持椭圆弧线,圆弧线,以及贝塞尔曲线的反锯齿功能。
通过对比,反锯齿功的效果明显会好于不用反锯齿的效果。很多人会问这是怎么做到的?很容易做到,只要弄清楚GDI+的线型绘制和ArcObjects线型绘制之间的差异就可以做到。这里我会比较两种线型模型结构以及实现上的差异。
大部分人对GDI+或GDI并不陌生,这是微软提供给我们的基于Windows的绘图组件,微软在早些年的操作系统中都是GDI组件,使用过程一般就是设置画笔,绘制对象,释放对象。后来微软提供了可以直接采用面向对象开发的GDI+组件,后续的操作系统都慢慢改用了GDI+组件。ESRI的ArcObjects组件开发出来时间也非常的早,可能底层的绘制也采用了类似GDI的方式,所以一直保留到现在的ArcGIS中。ArcObjects组件的架构下,绘制方式和绘制内容是分离,这就给我们留下了扩展的机会,我们可以选择采用GDI+的绘制方式而不是ESRI默认设置的绘制方式,那么绘制效果就会根据GDI+的效果而定。在这里我们更需要观注的是绘制的内容,假如有个ESRI的ArcObjects方式定义的圆结构,你需要先转换成GDI+下定义的圆结构,然后让GDI+去绘制他认可的圆结构。由此引出关于两者线型的比较。
在ArcObjects下的线型模型中,线类型被分为两种类型,高级类型,次高级类型,以及低级类型。高级类型就是Polyline,次高级类型就是Path, 低级类型有,Circular(圆弧线),Line(简单线),Elliptic(椭圆线),Bezier(贝塞尔线)。一般的GIS处理过程中涉及的对象都是高级类型(如在面类型中就是Polygon),ArcGIS的大部分空间处理也是直接基于高级对象的,这也遵循了软件设计的一个原则,把对象的创建和对象的使用分开。那高级类型的创建就是有次高级类型和低级类型来完成的。ArcObects中线型可以参考下面的图:
GDI+ 的线类型和ArcGIS类似,但是有差异。GDI+特点是线类型有个GraphicsPath, 这相当于一个容器,可以把需要的线类型都直接放进去,甚至还能把其他的GraphicsPath也直接放进去,具体可以在网上了解,此处只是简单介绍。
比较了两种线型弄清差异,就可以开始开发之旅。在线符号的绘制过程中,ArcGIS会把所有线对象传到我们的绘制组件。这个线对象就像我刚才描述的情况一样,肯定是一个高级线对象(因为在Feature中存的就是高级对象)Polyline,我有了Polyline就可以构造GDI+需要的对象?如何构造,关键看开发者的视角,你可以很简单的人为所有线都是由点构成的,我只要取出Polyline的所有构成的点,然后通过坐标转换,得到GDI+下的点,在把这些点组合成GDI+下的线型,直接绘制出来,这个想法很朴素,对简单线适用,容易理解。对于数学描述的线型可能无从下手,但是思路也类似,把数学描述的曲线参数转换到GDI+下同样适用。关键点就是把ArcObjects下的Polyline拆分成低级对象,通过坐标系转换低级对象的坐标,取得低级对象的数学描述信息(或者就是点),转换到GDI+对象,由GDI+在设备上绘制。
在开发过程中始终存在一个问题,那就是精度问题。坐标系的转换过程中,如果使用GDI+的方法,误差比较大,微软采用的是float类型进行运算,ArcGIS采用的是double类型参与运算。网上很多人在吹嘘基于GDI+的高精度制图,我想如果是用GDI+的坐标转换方式处理数据,所谓高精度就存在疑问呀。