您好,欢迎来电子发烧友网! ,新用户?[免费注册]

您的位置:电子发烧友网>电子百科>通信技术>卫星通信>

GIS地图开发

2018年01月15日 18:33 电子发烧友网 作者: 用户评论(0

一、 地图是怎么做出来的

首先说一下地图是怎么出来的,可能你感觉是废话,但实际上很多人并不知道如何下手。我觉得这里需要先给你个思路准备:地图就是使用绘图语句画出来的!

从底层绘制地图,能使用的就是绘图函数,在.NET里,就是用Graphics类的方法,在窗口中绘制点、线、面、标准、栅格等,组合起来,就是一张地图(瓦片图方式除外)。

关于.NET的绘图,本文不进行讲解,如果你还还不熟悉,建议你先看看这方面资料

二、 坐标转换-地图绘制的关键

.NET提供了大量绘图方法,基本上都是以Graphics类的函数形式提供,包括各类几何形状、图像、文字的绘制,灵活运用这些方法,就可以画出精美的图出来。假设你已熟悉.NET的绘图,这样就只有有一个问题要解决:图我会画了,但拿到地图元素一般为地理坐标(经纬度),应该画在地图上什么位置?这就需要涉及到坐标转换问题。

先不考虑怎么实现,首先需要这么一个函数:

/// 《summary》

/// 经纬度转换为屏幕坐标

/// 《/summary》

/// 《param name=“xy”》经纬度《/param》

/// 《returns》屏幕坐标《/returns》

public Point WorldToScreen(PointF xy)

再一个,有时,还需要根据屏幕上点位置反算出它的经纬度,如在需要显示鼠标指针处的经纬度,所以还需要这么一个函数:

/// 《summary》

/// 屏幕坐标转换为经纬度

/// 《/summary》

/// 《param name=“xy”》屏幕坐标《/param》

/// 《returns》经纬度《/returns》

public PointF ScreenToWorld(Point xy)

有了这两个函数,就可以将以经纬度表示的地理坐标转换为屏幕坐标,然后再屏幕绘图了。

为了完成坐标转换,需要使用几个地图参数的变量:地图缩放倍数、地图中心点经纬度、地图大小,关于地图参数,可参考这篇文章:

http://hi.baidu.com/geochenyj/blog/item/6b5c5c1294057557f819b835.html

另外,还需要对地图进行缩放、平移,这些操作实质上也是对地图参数的操作,如放大就是对地图缩放倍数操作,平移就是对地图中心点进行操作,我们将这些操作也写Coordinator类的方法。投影变换也作为坐标转换的一部分,Coordinator类还增加了投影方面方法,这个后面再讲。

将上面两个坐标转换函数和三个地图参数封装为一个类Coordinator。,的类如下所示:

 GIS地图开发

三、 绘图

有了坐标转换类Coordinator,就可以用经纬度数据来绘图了,如拿到某省的行政边界经纬度坐标数据,就可以将经纬度数据转换为屏幕坐标,然后用Graphics的方法来画出来了,Graphics对象又从哪里来呢?可以从一个Image对象创建,也可以从一个控件的Paint事件中取得,总之,有了坐标,发挥你的想象力,自己画吧。

在气象数据分析中,除了要绘制点、线、面、文字、栅格外,还需要绘制一些特殊符号,如风、天气现象、云等。这些符号,可以用图片、天气字库、符号库来实现,图片方式实现简单,色彩丰富,但缩放效果不好;字库方式,需要安装字库,程序部署比较麻烦;符号库方式代码编写较麻烦。FreeMicaps的天气现象符号采用符号库方式,祥见: http://blog.csdn.net/HZGJF/archive/2009/05/27/4220508.aspx

风符号和云量符号采用计算坐标绘制方式。

为了使用方便,FreeMicaps把符号绘制功能封装到三个符号类中,以静态方法提供。

 GIS地图开发

.NET的绘图是对GDI+的封装,包括了对点、线、面等各种图形元素的封装,图形图像的绘制、坐标旋转,各种反走样和平滑等功能,功能十分强大(当然,效率不太高),利用它可以绘出漂亮的图形。

根据OGC标准,GIS系统首先需要对地图元素进行抽象和封装,但FreeMicaps中,经再三考虑,放弃了这种方式,一个是因为工作量比较大,另一个是因为我不敢保证能很好地进行封装,可能给插件开发带来麻烦,不如把绘图权完全交给图层,大家自由发挥。

四、 图层

为了使绘图过程便于管理,可将绘图过程分为组,如可以将一张地图的绘制分为:绘制世界地图、绘制中国地图、绘制河流、填地名几个过程,每次绘图好像就是在一张玻璃上绘制,叠加起来就形成了一张地图图,这里把每次绘图过程形象地称为一个图层。地图分层后,图层可以增删,每个图层可以单独进行隐藏、设置属性等,更重要的是可以将利用面向对象技术把每个图层当做一个对象进行管理。详细介绍见:http://blog.csdn.net/HZGJF/archive/2008/10/03/3014558.aspx

对图层进行抽象,它应该有一个图层绘制方法(Render),一个图层标题(LayerName),一个用于表示数据源的字符串(DataSource),一个用于表示绘图样式的设置的LayerStyle,加上一些辅助方法属性,最终形成如下抽象图层类(CustomLayer),各种图层均从它继承:

 GIS地图开发

FreeMicaps中,每种数据对应一种图层类,为了使图层类编写方便,使用了设计模式中的模板方法,定义绘制流程,主程序在调用图层的Render()方法时,会自动判断是否已经读入数据,根据需要读数据绘图。

对于一种类型数据,需要从CustomLayer继承新建一个图层类。各种类型数据图层的工作方式完全一样,仅在数据读取和绘制方面不同,所以,写新图层类时,仅需实现DoLoad()和DoRender()两个抽象方法,完成读取数据和绘制图层代码即可。FreeMicaps里使用了字符串作为数据源标识,通用GIS系统对数据源进行了抽象,我也尝试这么做,但代码过于复杂,增加图层开发难度,最终增大插件开发难度,所以放弃了。

前面说了,一张地图有多个图层,所以还需要将图层放入一个列表,绘制地图时遍历图层,调用每个图层的Render()方法,画出一张完整的地图。对于图层列表,大家马上会想到使用List类,但图层绘制是需要有顺序的,如在卫星云图上面叠加地名,需要先画卫星云图,再填地名,否则云图会把地名盖住,所以在图层的样式(LayerStyle)中放了一个ZOrder属性,通过它来控制图层顺序。但由于List本身的排序方法是一种“非稳固排序”,也就是说当两个图层的ZOrder相等时,它们的顺序是不确定的,为了避免这个问题,FreeMicaps从CollectionBase继承了一个类LayerList,实现对图层的管理,并实现了IXmlSerializable接口,完成图层序列化功能。另外,还增加了添加图层、删除图层事件。LayerList类如下:

FreeMicaps中,每种数据对应一种图层类,为了使图层类编写方便,使用了设计模式中的模板方法,定义绘制流程,主程序在调用图层的Render()方法时,会自动判断是否已经读入数据,根据需要读数据绘图。

对于一种类型数据,需要从CustomLayer继承新建一个图层类。各种类型数据图层的工作方式完全一样,仅在数据读取和绘制方面不同,所以,写新图层类时,仅需实现DoLoad()和DoRender()两个抽象方法,完成读取数据和绘制图层代码即可。FreeMicaps里使用了字符串作为数据源标识,通用GIS系统对数据源进行了抽象,我也尝试这么做,但代码过于复杂,增加图层开发难度,最终增大插件开发难度,所以放弃了。

前面说了,一张地图有多个图层,所以还需要将图层放入一个列表,绘制地图时遍历图层,调用每个图层的Render()方法,画出一张完整的地图。对于图层列表,大家马上会想到使用List类,但图层绘制是需要有顺序的,如在卫星云图上面叠加地名,需要先画卫星云图,再填地名,否则云图会把地名盖住,所以在图层的样式(LayerStyle)中放了一个ZOrder属性,通过它来控制图层顺序。但由于List本身的排序方法是一种“非稳固排序”,也就是说当两个图层的ZOrder相等时,它们的顺序是不确定的,为了避免这个问题,FreeMicaps从CollectionBase继承了一个类LayerList,实现对图层的管理,并实现了IXmlSerializable接口,完成图层序列化功能。另外,还增加了添加图层、删除图层事件。 

非常好我支持^.^

(0) 0%

不好我反对

(0) 0%

( 发表人:彭菁 )

      发表评论

      用户评论
      评价:好评中评差评

      发表评论,获取积分! 请遵守相关规定!