2009-12-31
一个GIS项目开发(采用MapGuide)的简单总结
文章分类:Web前端
(草稿)
今年做了一个GIS项目,基于web的。过程中有不少经验和心得,也有一些挫折和疑惑,做完一直没有认真总结。
这个项目业务很简单,地图就是核心功能。某局管理着某系统2000多家各级机构,希望这些机构都在地图上标出来,方便查询,快速导航,结合机构信息、管理者信息、经营信息展示出来。具体功能不必多说,我对这个项目总体上还算满意。
项目选择的GIS引擎是开源的MapGuide。以前没做过GIS,选择MapGuide只是在简单考察之后的判断。事实上选择它并不坏,开源引擎有名的MapServer、GeoServer,许多java程序员都是用GeoServer,也许它们也不错,只是没用过。
MapGuide提供三种服务端接口,.Net的、PHP的、Java的。咱是Java程序员(&c&ruby:)),就使用Java了。
顺便讲一下Java的技术。项目采用了Struts2、OpenJPA,Struts2和JPA的组合我是第二次用了,不过上次是Hibernate的JPA。Struts2应用了REST的风格,省了很多配置。开发、调试环境是Eclipse,Maven,调试起来很方便。Maven的Tomcat插件默认是不打开JK监听端口的,我把它的MOJO加一行代码,重新编译就可以了。为了配置一些图层定义的xml我使用了Freemarker,因为Freemarker自己就能包含另一些文件,可以把变化的和不变化的部分分离开而不用写程序。整个Java的技术组合,开发效率很不错,我也比较满意。数据库用的是mysql,保存一些POI数据。因为地理数据不保存在数据库中,mysql就够了。
MapGuide引擎是通过Apache调用的,cgi把Apache和MapGuide引擎关联起来。Java web服务器使用Tomcat,因为Apache通过JK连接到Web容器,Tomcat比较自然。整个体系结构是Client(http)->Apache,Apache(cgi)->MapGuide,Apache(JK)->Java/Tomcat,Java(MapGuide服务端API)->MapGuide。
上面最后一个联系是因为,操作Map,Features主要是在服务端完成的。客户端主要是直接从MapGuide查询数据,但不修改Map,Featrues。项目中客户端、服务端处理方式都是MapGuide特有的。
MapGuide宣称也支持WMS、WFS标准,不过我没这样用。用WMS、WFS方式的话,我倒是想组合MapServer和openlayers试试,也许可以解决一些问题。
一个GIS应用从下往上可以分成这样的层次,Data->Layer->Map->Layout,Data就是数据层,对应原始的地图数据,包含多个图层;Layer关联某个图层的数据,定义了该层数据如何显示,它是Data图层数据逻辑上的概念,并且包含了图层样式;Map组合了多个Layer,定义了每个Layer的顺序,出现的比例尺等。Layout定义整个应用界面的布局,需要哪些panel,哪些按钮,怎么布局等。
上面说的Data、Layer、Map、Layout是要在工具里配置的。MapGuide的配置工具有MapGuide Studio、MapGuide Maestro,前者是Autodesk公司官方的,后者是免费的。还有安装就带的基于web的webstudio,不过比较难用。总体上MapGuide Maestro跟MapGuide Studio有差距,不过发展得比较快。我习惯使用MapGuide Maestro,MapGuide Maestro比MapGuide Studio好的就在于它能直接编辑xml。不过MapGuide Maestro好像加不了资源,我有一批png的symbol不知道怎么加上去,这个问题困扰了好几天。后来才安装了MapGuide Studio,终于得到了解决。
图层样式的配置网上很多地图可以参考。划分好比例尺,每一层在哪个比例尺上出现,不同比例尺上道路要多宽。关键一点是要突出业务上的POI,其他的颜色不要太花。
MapGuide提供的客户端解决方案是一整套的,它对Layout有很完美的支持。从普通的ajaxpanel到fusion这个重量级的框架。如果你的地图是静态的(不需要修改、增加Feature,不需要加临时层,通过配置工具很快就能部署一个GIS应用)。
我们的客户端基于普通的方式改造而来,fusion感觉太花哨,把它风格改造得庄重一些是个麻烦。没有使用Layout,这样是为了更好的控制,它对真正定制的应用总是拖累,放不开手脚改造。
地图的操作包括普通的地图操作(放大、缩小、移动,测距、获取图片等),画一个区域(矩形、圆,以在这个区域内查询),(根据查询结果)定位、标记,地图上点击POI弹出详细信息,等等。
画区域的方式是,在画形状的回调函数中,把形状信息通过ajax发到服务器(java),在服务端程序中,读取图层配置,给地图生成一个临时层,刷新地图。如果要在区域内查询,则也要调用服务端API来完成。
web上获取feature的原理是,鼠标悬停时获取鼠标的坐标,计算以鼠标为中心上下几像素的矩形,矩形坐标转换为地图坐标,发送到服务器(到MapGuide Server,不到Tomcat),服务器查询这个区域内的feature(只要一条,最上面的),返回。根据这个原理,我在取回feature的回调函数中加入自己的东西,如果取回了我需要的feture,就在鼠标所在位置加一个div,鼠标变成手形,加上单击事件。于是单击就可以弹出详细信息框(框里包含iframe)。
最初的地图上没有OverView(鹰眼),于是加了一个,花了两天时间,都可以联动。开始时出现奇怪的问题,后来发现时两个地图都用一个MapGuide的session,两者几乎同时请求Map,时间间隔太短,服务器发给后来的一样的图片。于是改成各自一个session。
由于不是通过WMS方式访问服务器的,所以都需要先建立session才能连接。可是MapGuide的session在我们应用没有多大意义,我们只需要Java web的session就够了。为了保证MapGuide的session能保持,客户端每隔一段时间就touch服务端一次。
我们用的MapGuide版本是2.0.2,开发一段时间后发现效率比较成问题,并发支持不好,甚至一个用户访问一段时间后就会无响应。后来把MapGuide服务器配置文件serverconfig.ini一些参数调整了一下,主要是一些MaxConnections和*Size参数适当的调大。基本没问题了。现在2.1版已经正式发布了,效率是它的一个重点,相信应该可以提升不少。
有两个问题也折腾了几天的时间。一个问题好解决,两个问题缠绕在一起就麻烦了。最初地图上的汉字总是乱码,变成欧洲字符的那种,后来猜想是可能是数据的.DBF文件(feature文件)内部乱码了(事实是地图数据厂商从arcGIS导出成shp造成的),用access打开再保存,重新导入。再看变成框框了。再上网查资料,装了Arial Unicode MS字体(LayerDefinition也要改成这个字体),于是可以了。不明白为什么非要这种字体,换过别的字体不行。
地图上Label的文字,如果是线型的Label的话,文字会顺着线条的方向,角度会有一些倾斜,看起来不好看,不知道能调整不。
还有一个重要问题没有提到,就是tile(瓦片)。地图的生成有两种方式,一种是每次请求时(可能是一次请求一个图层)给渲染一整张图片发回客户端,这样每次请求都得渲染一次,因为请求的中心坐标和范围都不一样。另一种是预先渲染一张张小图片,叫tile,组织到文件系统中,客户端在显示地图是自己计算需要哪些tile,分别请求服务器,如果服务器没现成的,渲染它保存,发回来,否则发回现成的。这种方式利用缓存,减轻服务器负担,会越使用越快。另外不需要一个图层一个tile,可以多个图层都渲染到一个tile中。
我们地图的图层分成3个组(不包括临时层),路、桥、面状层是一个组,地图数据固有的POI层是一个组,我们的业务POI是一个组。开始时3个组都配置成tile,但是出现了路名重复的问题,基本在每个tile重复一次,很难看。想想它应该是这样的,每个tile都是单独渲染的,不能协调路名应该出现在哪个tile中,每个tile都当自己是中心。查查资料,好像几个引擎都没有解决这个问题。为了解决这个问题,我从道路、街道的各层中分出路名层,这些路名层就不要tile了。最后路名重复的问题解决了,但拖动地图的时候,其他都是平移的,只有路名位置也会重新计算,相对位置会变化了,效果不太好。
后来发现业务POI客户也会随时调整的,于是业务组也不用tile了。给有权限的用户开放重新定位功能,可以由他们来调整。
关于坐标的收集,原来让各个系统自己报。后来发现,他们获取坐标的方式多种多样,很多都不大准确。有些是用仪器甚至带gps功能的手机测到的,但这些仪器往往本来就会有一定的偏差。后来大部分要求重新报一次,通过Google Earth找坐标,因为我们发现Google Earth的坐标是准确的,和我们地图也是吻合的。我们在坐标数据上花费了很多时间。
总的来说,GIS对我们是一个新的领域,这个项目毕竟做完了,还算令人满意。通过这个项目,我们学了不少东西,积累了不少经验。把这些写出来,虽然比较粗糙,没什么条理,但总算完了一件心事。
一个GIS项目开发(采用MapGuide)的简单总结
文章分类:Web前端
(草稿)
今年做了一个GIS项目,基于web的。过程中有不少经验和心得,也有一些挫折和疑惑,做完一直没有认真总结。
这个项目业务很简单,地图就是核心功能。某局管理着某系统2000多家各级机构,希望这些机构都在地图上标出来,方便查询,快速导航,结合机构信息、管理者信息、经营信息展示出来。具体功能不必多说,我对这个项目总体上还算满意。
项目选择的GIS引擎是开源的MapGuide。以前没做过GIS,选择MapGuide只是在简单考察之后的判断。事实上选择它并不坏,开源引擎有名的MapServer、GeoServer,许多java程序员都是用GeoServer,也许它们也不错,只是没用过。
MapGuide提供三种服务端接口,.Net的、PHP的、Java的。咱是Java程序员(&c&ruby:)),就使用Java了。
顺便讲一下Java的技术。项目采用了Struts2、OpenJPA,Struts2和JPA的组合我是第二次用了,不过上次是Hibernate的JPA。Struts2应用了REST的风格,省了很多配置。开发、调试环境是Eclipse,Maven,调试起来很方便。Maven的Tomcat插件默认是不打开JK监听端口的,我把它的MOJO加一行代码,重新编译就可以了。为了配置一些图层定义的xml我使用了Freemarker,因为Freemarker自己就能包含另一些文件,可以把变化的和不变化的部分分离开而不用写程序。整个Java的技术组合,开发效率很不错,我也比较满意。数据库用的是mysql,保存一些POI数据。因为地理数据不保存在数据库中,mysql就够了。
MapGuide引擎是通过Apache调用的,cgi把Apache和MapGuide引擎关联起来。Java web服务器使用Tomcat,因为Apache通过JK连接到Web容器,Tomcat比较自然。整个体系结构是Client(http)->Apache,Apache(cgi)->MapGuide,Apache(JK)->Java/Tomcat,Java(MapGuide服务端API)->MapGuide。
上面最后一个联系是因为,操作Map,Features主要是在服务端完成的。客户端主要是直接从MapGuide查询数据,但不修改Map,Featrues。项目中客户端、服务端处理方式都是MapGuide特有的。
MapGuide宣称也支持WMS、WFS标准,不过我没这样用。用WMS、WFS方式的话,我倒是想组合MapServer和openlayers试试,也许可以解决一些问题。
一个GIS应用从下往上可以分成这样的层次,Data->Layer->Map->Layout,Data就是数据层,对应原始的地图数据,包含多个图层;Layer关联某个图层的数据,定义了该层数据如何显示,它是Data图层数据逻辑上的概念,并且包含了图层样式;Map组合了多个Layer,定义了每个Layer的顺序,出现的比例尺等。Layout定义整个应用界面的布局,需要哪些panel,哪些按钮,怎么布局等。
上面说的Data、Layer、Map、Layout是要在工具里配置的。MapGuide的配置工具有MapGuide Studio、MapGuide Maestro,前者是Autodesk公司官方的,后者是免费的。还有安装就带的基于web的webstudio,不过比较难用。总体上MapGuide Maestro跟MapGuide Studio有差距,不过发展得比较快。我习惯使用MapGuide Maestro,MapGuide Maestro比MapGuide Studio好的就在于它能直接编辑xml。不过MapGuide Maestro好像加不了资源,我有一批png的symbol不知道怎么加上去,这个问题困扰了好几天。后来才安装了MapGuide Studio,终于得到了解决。
图层样式的配置网上很多地图可以参考。划分好比例尺,每一层在哪个比例尺上出现,不同比例尺上道路要多宽。关键一点是要突出业务上的POI,其他的颜色不要太花。
MapGuide提供的客户端解决方案是一整套的,它对Layout有很完美的支持。从普通的ajaxpanel到fusion这个重量级的框架。如果你的地图是静态的(不需要修改、增加Feature,不需要加临时层,通过配置工具很快就能部署一个GIS应用)。
我们的客户端基于普通的方式改造而来,fusion感觉太花哨,把它风格改造得庄重一些是个麻烦。没有使用Layout,这样是为了更好的控制,它对真正定制的应用总是拖累,放不开手脚改造。
地图的操作包括普通的地图操作(放大、缩小、移动,测距、获取图片等),画一个区域(矩形、圆,以在这个区域内查询),(根据查询结果)定位、标记,地图上点击POI弹出详细信息,等等。
画区域的方式是,在画形状的回调函数中,把形状信息通过ajax发到服务器(java),在服务端程序中,读取图层配置,给地图生成一个临时层,刷新地图。如果要在区域内查询,则也要调用服务端API来完成。
web上获取feature的原理是,鼠标悬停时获取鼠标的坐标,计算以鼠标为中心上下几像素的矩形,矩形坐标转换为地图坐标,发送到服务器(到MapGuide Server,不到Tomcat),服务器查询这个区域内的feature(只要一条,最上面的),返回。根据这个原理,我在取回feature的回调函数中加入自己的东西,如果取回了我需要的feture,就在鼠标所在位置加一个div,鼠标变成手形,加上单击事件。于是单击就可以弹出详细信息框(框里包含iframe)。
最初的地图上没有OverView(鹰眼),于是加了一个,花了两天时间,都可以联动。开始时出现奇怪的问题,后来发现时两个地图都用一个MapGuide的session,两者几乎同时请求Map,时间间隔太短,服务器发给后来的一样的图片。于是改成各自一个session。
由于不是通过WMS方式访问服务器的,所以都需要先建立session才能连接。可是MapGuide的session在我们应用没有多大意义,我们只需要Java web的session就够了。为了保证MapGuide的session能保持,客户端每隔一段时间就touch服务端一次。
我们用的MapGuide版本是2.0.2,开发一段时间后发现效率比较成问题,并发支持不好,甚至一个用户访问一段时间后就会无响应。后来把MapGuide服务器配置文件serverconfig.ini一些参数调整了一下,主要是一些MaxConnections和*Size参数适当的调大。基本没问题了。现在2.1版已经正式发布了,效率是它的一个重点,相信应该可以提升不少。
有两个问题也折腾了几天的时间。一个问题好解决,两个问题缠绕在一起就麻烦了。最初地图上的汉字总是乱码,变成欧洲字符的那种,后来猜想是可能是数据的.DBF文件(feature文件)内部乱码了(事实是地图数据厂商从arcGIS导出成shp造成的),用access打开再保存,重新导入。再看变成框框了。再上网查资料,装了Arial Unicode MS字体(LayerDefinition也要改成这个字体),于是可以了。不明白为什么非要这种字体,换过别的字体不行。
地图上Label的文字,如果是线型的Label的话,文字会顺着线条的方向,角度会有一些倾斜,看起来不好看,不知道能调整不。
还有一个重要问题没有提到,就是tile(瓦片)。地图的生成有两种方式,一种是每次请求时(可能是一次请求一个图层)给渲染一整张图片发回客户端,这样每次请求都得渲染一次,因为请求的中心坐标和范围都不一样。另一种是预先渲染一张张小图片,叫tile,组织到文件系统中,客户端在显示地图是自己计算需要哪些tile,分别请求服务器,如果服务器没现成的,渲染它保存,发回来,否则发回现成的。这种方式利用缓存,减轻服务器负担,会越使用越快。另外不需要一个图层一个tile,可以多个图层都渲染到一个tile中。
我们地图的图层分成3个组(不包括临时层),路、桥、面状层是一个组,地图数据固有的POI层是一个组,我们的业务POI是一个组。开始时3个组都配置成tile,但是出现了路名重复的问题,基本在每个tile重复一次,很难看。想想它应该是这样的,每个tile都是单独渲染的,不能协调路名应该出现在哪个tile中,每个tile都当自己是中心。查查资料,好像几个引擎都没有解决这个问题。为了解决这个问题,我从道路、街道的各层中分出路名层,这些路名层就不要tile了。最后路名重复的问题解决了,但拖动地图的时候,其他都是平移的,只有路名位置也会重新计算,相对位置会变化了,效果不太好。
后来发现业务POI客户也会随时调整的,于是业务组也不用tile了。给有权限的用户开放重新定位功能,可以由他们来调整。
关于坐标的收集,原来让各个系统自己报。后来发现,他们获取坐标的方式多种多样,很多都不大准确。有些是用仪器甚至带gps功能的手机测到的,但这些仪器往往本来就会有一定的偏差。后来大部分要求重新报一次,通过Google Earth找坐标,因为我们发现Google Earth的坐标是准确的,和我们地图也是吻合的。我们在坐标数据上花费了很多时间。
总的来说,GIS对我们是一个新的领域,这个项目毕竟做完了,还算令人满意。通过这个项目,我们学了不少东西,积累了不少经验。把这些写出来,虽然比较粗糙,没什么条理,但总算完了一件心事。