背景
最近碰到一个有意思的GIS功能需求:有一份小区的面图层,在地图上点一下,找出距离最近的小区面。
为什么说是有意思呢?如果大家仔细回想下,就会发现,很多时候,我们通过点击地图上的一个目标跟地图进行交互,目的是要看一下我们所点的这个目标的信息。譬如我们在地图上点一个餐馆的图标,想看看它是做什么菜系的,评论好不好,等等。这个点击动作其实是很明确的,就是奔着看餐馆的信息去。
而相对而言,上面的这个需求所带出来的就是另一类诉求了。找出距离最近的小区,或者说找出最近的目标,这其实是懒人的一种需要。譬如说,我肚子饿了,帮我找出里我最近的餐馆,甭管是西餐还是中餐,粤菜、湘菜、川菜还是海南粉,都可以,只要能填饱肚子(温饱问题没解决,让国家领导人操心了~)。
那这个需求能不能实现?答案是肯定的,怎么实现?
实现思路
好了,坑已经挖好了,现在开始填坑。在填坑之前,需要补充的是,咨询这个问题的朋友用的是ArcGIS API for JavaScript来开发的业务系统。所以他最初的问题是:JS API有没有提供接口直接实现这个功能?
去过了一遍JS API,没发现有这个接口可以直接实现?那有没有其他的方式可以很方便的就实现?当时第一个念头想到的解决方案是:建模+发布GP服+JS API调用。那除了这种还有没有其他的方法?答案是肯定的,譬如SOE,又或者直接通过ST_Geometry。但是对于懒人来说,本着【能少写些代码就少写些代码】的精神,还是选择了初衷。
那这里我主要是重点把建模这个过程解释一下,至于发布成GP服务和利用JS API调用,大家百度一下就可以了,很多文章介绍。好,先把模型图放上来:
这个模型当然是用ArcGIS 桌面的模型构建器实现的。模型构建器是一个用来创建、编辑和管理模型的应用程序,而模型是将一系列地理处理工具串联在一起的工作流,它将其中一个工具的输出作为另一个工具的输入。也可以将模型构建器看成是用于构建工作流的可视化编程语言。
- 首先创建一个变量【inputpoint】,接收点击地图后返回的点要素,这个变量类型是要素集;
-
将inputpoint通过工具【Make Feature Layer】转换成图层,为什么要转换成图层?因为工具【Near】的输入要求是图层,输出的结果名为point的图层;
-
然后再用【Near】工具进行邻近要素分析。这个工具的说明如下:
我们把point图层当做输入要素,把小区面region图层作为邻近要素。
注意:到这一步执行完了以后,你可能认为,已经实现了最近小区面的功能。但是,其实咱们是错了,刚开始我也是这么认为,但是一看这个工具的帮助,No way。返回的结果是我们所输入的点要素,同时还附加了其他的字段,包括:最近的要素对象 ID、输入要素与邻近要素之间的距离。所以我们还得往下走。但至少我们已经知道了最近的这个要素的OBJECTID,这就好办了。本来到这一步其实也可以完成了,因为拿到这个OBJECTID值之后,在前端就可以通过API来查询这个小区面。但是呢,本着"一条龙服务"的念头,还是希望能一次性解决的好。
图-临近分析的上半场
-
知道了对象的ID,那接下来就需要去找对象了。首先,我们需要一个工具把对象ID拿出来,然后再用找对象工具来找对象:
图-把对象ID拿出来
把对象ID拿出来我用工具【Get Field Value】,顾名思义就是获取字段的值。
图- Get Field Value
这个工具必须要点赞的一点是,它只获取第一行的值,这正是我们需要的。
图-找对象工具【Select】
找对象工具我们用【Select】,根据对象的OBJECTID去选择:
图-Select工具界面
那怎么把对象ID和Select给串联起来呢?答案在变量Expression,如下图:
看到这个表达式就很清晰了吧?OBJECTID=%NearRegionOID%
注意,表达式里如果要引用其他的变量需要在变量的前后加入符号%,这是硬性要求,没得谈!
-
剩下的就是把输入和输出作为模型参数:
做这一步的目的是发布成GP服务时,我们需要接收前端传过来的点坐标,并返回分析后的最近小区面要素。
到这里,建模的部分就已经完成了,我们可以先在ArcMap中测试下:
图-在地图上打一个点
图-找到对象的结果
当然,如果你想要发布成GP服务的话,那就打开【结果】窗口,如下图:
图-打开地理处理分析结果窗口
展开当前会话,找到刚刚分析完成的结果,右键点击之后选择【共享为】à【地理处理服务】,如下图:
图-将地理处理的分析结果发布成GP服务(地理处理服务)
点击之后就会出现一个很熟悉的界面,发布服务:
剩下的就跟发布普通的Map Server服务差不多了,就不再展开了。最后上一张发布好的GP服务界面:
具体的开发可以参考以下链接:
GP服务REST API接口说明:
http://resources.arcgis.com/en/help/arcgis-rest-api/#/GP_Service/02r3000000rq000000/
JavaScript API关于Geoprocessor接口说明:
https://developers.arcgis.com/javascript/3/jsapi/geoprocessor-amd.html
API调用GP服务Demo:
https://developers.arcgis.com/javascript/3/jssamples/util_relation.html、
这个Demo演示的是在地图上点击一个位置,然后调用GP服务分析出 3分钟车程内的披萨餐厅。