前言
现在市面上GIS产品已经很丰富了,为什么还要自己动手做一个呢?你看到这个标题,并点开它,说明你感兴趣。作为技术人员,只要有兴趣,这就足够了,“不要问为什么”。如果非要给个理由的话,那就是市面上的GIS产品都做得太复杂、太难用,学会使用它所花的时间,不会比自己动手做一个所花的时间少,当然前提是你写代码够快。
至于最终写出来的东西能做什么用?这好比是屠龙术,会不会屠龙术是技能问题;找得到找不到龙来屠,那是人品问题。这里只能帮忙解决点技能问题,人品问题那只能靠你自己!如果实在找不到龙,找只猪来替代也行,会屠龙的人多了,杀猪市场的竞争压力可能就不会那么大。
本文主要根据GIS平台的大体实现步骤来描述,偏向于纸上谈兵,当然了,会有少量代码辅助解说。个人认为vb.net语言是很简便的开发语言,最容易理解,因此演示代码使用vb.net语言(VS2008 express、.net2.0)。若实际开发的话,建议使用开发原生程序的工具,如VC(本人是用VC来开发)、Delphi等,因为性能是软件产品里的生命线。人生苦短,让用户坐在电脑前,等待软件蜗牛般的处理,那无异于谋杀,程序员很可能是这个时代最疯狂的杀手。
这里所介绍的内容只在window和winmobile系统上检验过,理论上说,也适合其它平台,信不信由你。
除了开发工具,在图形库上,2D选用gdi+,3D则采用directx,选它们是因为都是WIN操作系统里现成的。你可以根据自己爱好选择不同的图形库,如OpenGL等,没什么限制。
1、图形概念
开发GIS的核心是什么,当然是图形了。GIS软件从本质上说和其它常用图形软件如AutoCAD没什么不同,只不过GIS除了图形外,有很多地理属性信息,行业专业性强一点而已。所以虽然主题是“做个GIS平台”,其实能做个GIS平台,改去做CAD平台也没什么困难。图形有很多种分法,开发中主要用的是“位图”和“矢量图”这两种概念。简单举例说,photoshop软件处理的就是位图,AutoCAD处理的就是矢量图。
1.1、位图
在GIS里,位图处理比较简单,大多数动作就是载入图片,作为底图,在对应位置显示出来就行。通常直接调用图形库对应功能就可以了。
A、 新建一个VB窗口应用工程HateMap项目,系统会自动建一个窗口Form1,此项目可直接运行。
B、 修改Form1名称为FormMain,做为显示主窗口。给各个对象起个容易识别的名称是个好习惯,可避免很多不必要麻烦。编码规范很重要,有时能决定产品的生死存亡。
C、 增加个按钮,命名ButtonPng,双击此按钮,输入代码
''' <summary>在0,0位置开始绘制影象图片</summary> Private Sub ButtonPng_Click(ByVal sender As System.Object,ByVal e As System.EventArgs) Handles ButtonPng.Click Dim imgPng As Image = Image.FromFile("c:\trstrtqss.png") '载入影象图片,假设图片已在C盘 Dim grDraw As Graphics = Graphics.FromHwnd(Me.Handle) '把当前窗口当做画布 grDraw.Clear(Color.White) '底色改为白色 grDraw.DrawImage(imgPng,0) '0,0位置开始画上图片 '资源释放,说明:.net平台上很多对象类为了省事,都是对WIN原生dll直接封装,这部分对象资源没法自动回收,需要使用者手动释放。 '一个简单原则,只要类有提供Dispose函数,那对应的对象实例用完后,调用下Dispose。 '更稳妥的方式,是在Try Finally里保证释放。本文只是提供演示代码,一切从简。 imgPng.Dispose() grDraw.Dispose() End Sub
D、 运行效果:
从代码里可看到,窗口左上角为起始坐标(0,0),X轴向右正方向,Y轴向下正方向,与笛卡儿坐标不同。如下图所示:
上面代码虽然能把影象显示出来,可是问题多多,比如切换下窗口,在回到此窗口,就发现什么都没了。那是因为窗口被别的窗口覆盖后,此窗口被覆盖的地方就变成了脏区域,重新显示此窗口时,这些区域需要重新绘制(具体内容请参考window相关编程资料,推荐《Programming Windows》)。所以,要在Paint事件里重新绘制。此外,显示区域一般为独立的区域,而上面例子中按钮直接覆盖在图片上。一般做法是新增加个Panel控件(示例里命名为PanelView)来替代Form做为显示区域。
Public Class FormMain '图形不直接绘制在控件上,而是绘制在内存图片上。 '这样做的好处首先不需要重复画,只要绘制一次就够了; '其次,实现双缓存机制,频繁显示时屏幕不会闪。 Dim imgMain As Bitmap Dim grImg As Graphics '指向imgMain Dim grPanel As Graphics '指向控件PanelView ''' <summary>在0,ByVal e As System.EventArgs) Handles ButtonPng.Click '已初始化并显示,直接退出 If imgMain IsNot Nothing Then Return End If Dim imgPng As Image = Image.FromFile("c:\trstrtqss.png") '载入影象图片,假设图片已在C盘 '创建与PanelView同样大小内存图片 imgMain = New Bitmap(PanelView.Width,PanelView.Height) grImg = Graphics.FromImage(imgMain) grImg.Clear(Color.White) '底色改为白色 grImg.DrawImage(imgPng,0位置开始画上图片 grPanel = Graphics.FromHwnd(PanelView.Handle) '把PanelView控件区域当做画布 grPanel.DrawImage(imgMain,0) '资源释放 imgPng.Dispose() End Sub ''' <summary>刷新</summary> Private Sub FormMain_Paint(ByVal sender As System.Object,ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint If imgMain IsNot Nothing Then grPanel.DrawImage(imgMain,0) End If End Sub ''' <summary>退出是释放资源</summary> Private Sub FormMain_FormClosed(ByVal sender As System.Object,ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles MyBase.FormClosed If imgMain IsNot Nothing Then grPanel.Dispose() grImg.Dispose() imgMain.Dispose() End If End Sub End Class
运行结果如下:
当然这是最简陋的界面,但对于示例来说基本框架有了,界面越简单越好,正常程序要包括菜单、工具栏、状态栏等标准界面。
其实上面程序还是问题多多,比如改变窗口大小,把窗口最大化,就会发现绘制区域没按想象那样延伸。这就涉及到Resize事件处理,你可以自己改改看。
地理信息里卫星图片、航拍图片就是位图,这些数据处理麻烦的地方在于投影坐标转换、比例调整等,更多的是地理专业上的处理。从严格意义上说这与软件关系不大,只要照着地图商提供的参数转换、切割、拼接就行。不过,这种数据量都很大,如何有效管理是个问题。