OGC之路(1) 之 WMS标准学习总结

一切都源于一年多以前,记得是512之后的不久,老板从国外找来一家专门提供地图业务的公司。他们本来使用ArcGIS作为服务平台,但是后来考虑到每年昂贵的服务费用,决定把业务拿到中国来,结果就找到我们。其实我们连GIS应用的开发经验都没有,不知道老板怎么说的(不愧是老板,要是我只能老老实实说没做过愿意学)把这个活拿到了手。我得简单介绍下我们要做的事情。我们需要维护一套C#的代码(甲方在沿海先找了家公司开发的,然而还是由于维护费用问题又把代码交给我们)。这套代码实话说,基本思想是正确的,可惜没有坚持到底,结果到处都是复制修改的内容。OO的基本原则它几乎都破坏了完了,可以说是反面教材的典范。但是它的关于GIS的开发是正确的,而且居然还是根据OGC的简单对象访问协议进行的设计。我的几乎所有GIS启蒙就是对这套代码的理解。也就是在这里第一次见到了OGC。经过一年焦头烂额的维护之后,我逐渐深入到GIS的一些底层领域,同时项目组来了新人,我的时间也就富裕了。于是我开始潜心学习OGC的各种标准,首先是通读,了解OGC的体系结构。然后确定了WMS,WFS,WCS,SLD,Filter,GML为重点学习目标。之所以写着个系列文章,主要是为了交流,同时也为自己的学习留下记录。这里给出OGC的连接

  1. 为了更好的学习,我们需要安装GeoServer,当然网上也有许多WMS服务可供访问。建议把返回的XML文本放到浏览器或者支持收缩的XML编辑器中便于浏览。

    先从一个例子开始,启动GeoServer,打开浏览器,在地址栏敲入如下连接:http://localhost:8080/geoserver/wms?bbox=-130,24,-66,50&styles=population&Format=image/png&request=GetMap&layers=topp:states&width=550&height=250&srs=EPSG:4326,你会看到浏览器显示的美国行政区划图(由此美国人的文化势力可见一斑,不管愿意不愿意,你时不时都会看到他们的国旗,地图,总统还有总统夫人)。关于上面连接的具体含义,我们会在下面介绍。

    再敲入第二个连接:http://localhost:8080/geoserver/wms?service=WMS&request=GetCapabilities,浏览器会返回提示打开或保存一个文件,我的机器返回的是一个叫“wms”的文件,没有扩展名。没关系我们把它保存为“wms.xml”就可以了。然后用浏览器打开,会看到是个相当大的文件,具体内容也会在下面解释。

    这里需要对WMS的调用连接做一个概要介绍,首先我们必须告诉服务器我们想使用WMS服务,因为服务器同时可能还提供了许多其他OGC服务,于是我们设置参数service=WMS。然后我们需要告诉服务器我们想要调用GetCapabilities方法,于是我们设置参数request=GetCapabilities。每个方法可能还有方法的参数,这个就在介绍方法时再说了。到这里我们已经完整的使用了一个WMS服务器的最重要功能,很简单吧。WMS之所以强大,正是由于它的简单。“简单即美”是一切设计的宗旨。

  2. GetCapabilities,如果你想使用一个WMS服务器,那你应该最先调用这个方法。

    调用:http://localhost:8080/geoserver/ows?service=WMS&request=GetCapabilities,这个方法返回服务器的能力。一般会是一个很大的XML文档,关于这个文档标准有很详细的描述,这里只做一个提纲式的介绍。

    把这个文档去头去尾以后留下两个节点Service和Capability。 Service包含了有关服务器的一般特性数据,对于只是想直接使用WMS服务器的人来说,这个节点还不太用得上,唯一值得注意的就是KeywordList节点,它里面是关键字,也就是服务器的保留字。 Capability才是我们学习的重点。如果你想正确的使用WMS服务器,这个节点里面的内容就必须搞清楚了。你可以从这个节点获得如下信息。

    1)服务器支持哪些方法,WMS服务器必须支持GetCapabilities和GetMap,此外还有许多扩展的方法,例如:DescribeLayer以及支持SLD服务器的特殊方法,由于GeoServer不是SLD服务器,这里也就没办法了解了。

    2)服务器支持哪些返回格式,WMS返回的地图都是渲染好的图片,因此这里的格式基本上都是图片格式(还是有例外不过不在这里介绍了),如:image/png。

    3)服务器发布了哪些图层,这个是WMS的重点,不然你连最简单的GetMap调用都构造不出来。

    下面我们就来学习如何获得这些数据。首先展开Capability节点,可以看到Request和Layer两个节点,此外还会有Exception和UserDefinedSymbolization,不过目前对我们用处不大。Request节点包含服务器支持的方法,我这里返回是这样几个节点:GetCapabilities,GetMap,GetFeatureInfo,DescribeLayer和GetLegendGraphic(注意老版本的WMS返在这里返回的节点名称会不一样,可能会去掉“Get”,我们这里介绍的是1.1.1版本的)。我们只介绍GetCapabilities和GetMap。

    先来说说GetCapabilities节点。你也许会说“GetCapabilities”,不就是我们正在讨论的方法吗,是的就是这个方法,你必须调用了这个方法才能知道关于它的特性,很有矛盾吧 :)。在这个节点里面你可以看到Format和DCPType节点,前者指出函数返回内容的格式,其实就是我们正在讨论的XML,后者暂时不讨论。

    GetMap节点的内容同样也是Format和DCPType节点,这里的Format列出了服务器支持返回的地图格式。

    WMS返回的图层是嵌套的形式,根节点就是我们将要说到的Layer节点。它里面除了自身的特性外还会包含其他Layer。先来说说Layer自身的特性。先得说明一下,由于Layer存在父子关系,所以他们的特性也就存在继承关系,子节点支持父节点的特性,而父节点比一定支持子节点的特性。与现实世界一样,“老子的就是儿子的,儿子的未必是老子的”。

    Layer最重要的特性就是Name,在请求方法GetMap的Layers参数中引用的就是这个值,关于GetMap方法的细节后面介绍。然后次重要的特性节点分别是SRS,LatLonBoundingBox,BoundingBox和Style,这些都是出现在GetMap方法中的参数。

    需要说明的是,根结点的Layer没有Name,因为这个Layer只是一个包装,它里面的“瓤”才是我们感兴趣的。而服务器支持的SRS(地理坐标系统)也会在这里来个总汇。这将是一个很长的清单。LatLonBoundingBox是经纬度表示的图层范围,依次是minx,miny,maxx,maxy。例如:<LatLonBoundingBox minx="-180.0" miny="-90.0" maxx="180.0" maxy="90.0" />。 BoundingBox是图层默认坐标系表示的范围与LatLonBoundingBox格式一样只是多了一个SRS属性,例如:<BoundingBox SRS="EPSG:26713" minx="588926.6865343997" miny="4913890.332215005" maxx="609271.2114429093" maxy="4927102.448786693" />。Style节点很重要,他表示图层支持的渲染样式,就是画风。一个图层可以支持多个Style。Style的子节点最重要的就是Name,我们会在GetMap方法的参数Styles中用到。到此为止,Layer节点就介绍完了。

  3. GetMap,如果你想使用一个WMS服务器,那你肯定会不断调用这个方法。调用:http://localhost:8080/geoserver/wms?request=GetMap&bbox=-130,24,-66,50&srs=EPSG:4326&layers=topp:states&styles=population&Format=image/png&width=550&height=250

    我们有必要详细说明一下调用参数。前面已经介绍过service和request了,这里集中在GetMap自己的参数上。如果你要调用GetMap方法,无疑要设置request=GetMap。随后我们需要告诉服务器我们希望看到哪个范围内的地图,于是我们设置bbox=-130,24,-66,50,这个bbox使用了EPSG:4326坐标系,于是我们设置srs=EPSG:4326。

    我们说过,服务器发布了许多图层,我们需要指明我们想看的图层,于是我们设置layers=topp:states,注意layers可以设置多个图层,用“,”隔开,图层的渲染顺序就是参数设置的顺序。我们可以使用默认的样式来渲染图层,于是设置styles=,也可以指定渲染样式,于是设置styles=population。对应layers的设置顺序,styles也可以设置多个样式,用“,”隔开。我们希望返回的图片是png格式的,于是设置Format=image/png。最后,我们需要告诉服务器,返回的图片的大小,width=550&height=250,以像素为单位。

    到此为止我们介绍完了WMS的调用,其实还有很多内容,想要深入学习的朋友可以去OGC的网站下载完整的文本,PDF格式的。找一些已经实现的开源WMS客户端通过代码学习。当然,最有效的学习途径就是自己实现一个WMS客户端。下面我们就来实现一个C#版本的WMS浏览器。

  4. WmsBrowser需求

    1、用户输入WMS服务器的URI,点击一个按钮调用GetCapabilities方法。然后用返回的数据初始化控制界面。 用户在控制界面上可以查看服务器的各种Capability数据,并且可以选择要显示的图层,调整图层顺序 ,为图层设置参数,然后返回一个地图图片显示在预览区。

    2、用户可以把返回的图片保存成文件。

    已经有许多支持WMS的客户端了,有许多代码可供学习和使用。但是,为了不干扰视线,为了避免介绍多余的内容,为了体现“自主创新精神”,最重要的是为了体验编程的乐趣(这也是我当初进入这个行业的原因),我决定只使用NotNet标准库提供的类完全从头开始编写代码。

  5. WmsBrowser设计

    根据需求,这是一个WinForm的执行程序。需求其实很不明确,完全没有说明最重要的部分,控制界面,是什么样子的,用户如何使用它。所以有必要补充一下了。

    控制界面有两个功能:

    1)查看GetCapabilities返回的数据;

    2)设置GetMap需要的调用参数。

    我们可以据此来设计这个界面。GetCapabilities返回的数据我们前面已经介绍过了,想象一下我们这款软件的潜在用户可能想要看到哪些数据,他们会如何使用这些数据。首先肯定是服务器发布的图层,这是访问WMS的唯一原因。至于服务器支持哪些调用应该不是他们关心的,而是我们开发者关心的。所以我们需要在界面上显示出Layer的内容,由于Layer是嵌套的,自然而然我们需要一个树控件。

    除了Layer的Name,Title,Abstract。这些属性外,用户应该还需要知道Layer支持的SRS,Style,Format和BoundingBox。这样他们才能构造出合理的调用参数。我们显然不应该让用户查看完数据后手动构造调用参数,我们需要让用户很方便的用鼠标完成工作。我们已经知道需要一个树控件来显示Layer信息。然后我们需要提供构造调用参数的界面。首先我们设想用户可能会如何完成这个工作。

    上面的介绍中我们一直是手动敲入字符串来完成调用URI的构建的,繁琐而且容易出错,但是这种方法很灵活,所以应该保留。于是我们需要一个TexBox来输入URI。然后我们需要一个按钮来发出GetMap请求。我们必须考虑到,有相当一部分人并不善于键盘操作(其中包括我),所以我们应该给他们提供鼠标操作模式。于是第二个界面出现了,用户在这里使用鼠标选择想要显示的Layer,调整Layer显示的顺序,选择每个Layer的Style,选择Format,选择SRS,输入BoundingBox,输入返回图片的尺寸。然后同样点击上面提到的按钮,发出GetMap请求。更进一步,我们可以用上面的界面来获得一个基本的调用参数,然后到TextBox里面去微调,这样用户会获得更好的灵活性。

    好了,到这里我们基本上搞清楚控制界面的样子了。现在需要讨论一点设计风格方面的问题。我们可以把所有代码写进一个叫MainForm的类里面,它是一个WinForm类。这样没有错,完全可以工作,实际上我见过的大部分代码都是这么干得。这样做的结果是,我很快就会放弃这个项目,转而去浏览cnblog或ifeng上面的帖子。我们需要一个更好的设计。我们在这里并不是要讨论架构,模式和开发方法,所以我们只需要达成一个共识就可以了:我们需要把界面元素,操作响应以及数据模型分开编码,为他们单独建立类体系。

    据此我们的设计也就差不多了,开始编码咯。

  6. WmsBrowser编码ing。。。

  7. 程序完成。

    代码下载

    启动程序后会看见主界面如下:下图是返回的地图

    image 

    这个程序还很稚嫩,有许多问题没有考虑,例如:输入验证,数据验证,异常处理等。以后我们会逐步完善它,目前作为一个参考和学习WMS的起点已经足够了。

  8. 后续

    在使用这个程序时,作为用户,我觉得还有很多不方便的地方。

    首先,我如果敲错了地址,我很容易敲错,程序会弹出一个丑陋的异常对话框,显示一大堆堆栈信息,完全看不出是什么错误。

    其次,设置参数BBox很不方便,如果能从已有的地图上用鼠标选择就好了。

    还有,返回时只是显示一个图片想看细节又要重复设置,Apply,GetMap的操作,太繁琐了。

    以上就是我作为用户对这款软件的看法,看来我们急需改进。我们会在以后的讨论中逐步完善这个程序。

posted on 2009-09-27 18:05  索夫特威尔  阅读(7362)  评论(1编辑  收藏  举报

导航