zoukankan      html  css  js  c++  java
  • 【转】ArcGIS Server如何动态添加图层并进行查询

    摘要:在ArcGIS Server 9.2的应用程序中,如果使用的资源类型是com.esri.adf.web.ags.data.AGSLocalMapResource,就可以在该资源上动态添加新的图层,图层数据可以来自不同的地方,比如本地的shapefile、file geodatabase或者SDE,也可以来自WMS等web服务。本文以本地的file geodatabase为例,为AGSLocalMapResource动态添加一个新的图层。

    软件:ArcGIS Server for Java platform

    版本:9.2

    平台:Solaris 9.0, 10; Linux Red Hat AS/ES 3.0, AS/ES 4.0; Linux-SUSE Server 9

      在ArcGIS Server 9.2的应用程序中,如果使用的资源类型是com.esri.adf.web.ags.data.AGSLocalMapResource,就可以在该资源上动态添加新的图层,图层数据可以来自不同的地方,比如本地的shapefile、file geodatabase或者SDE,也可以来自WMS等web服务。本文以本地的file geodatabase为例,为AGSLocalMapResource动态添加一个新的图层。

      首先,要得到地图的IMap接口才能对地图的图层进行操作。

    清单1. 获取IMap接口

    1.  AGSLocalMapResource res = (AGSLocalMapResource)webContext                               .getResources().get("ags0");

    2.  com.esri.arcgis.carto.MapServer mapServer = res.getLocalMapServer();

    3.  try {

    4.    IMap map = mapServer.getMap(mapServer.getDefaultMapName());

    5.    map.addLayer(ILayer layer);

    6.  }catch(Exception e){

    7.  }

      动态添加图层的核心代码就是第5行,它接收的参数是实现了ILayer接口的对象。因此,接下来我们需要把file geodatabase里的feature class组装成一个ILayer对象。

    清单2. 从Feature Class到ILayer

    1.  IServerContext sctx = res.getServerContext();

    2.   IWorkspaceFactory pWorkspaceFactory = (IWorkspaceFactory) sctx                                         .createObject(FileGDBWorkspaceFactory.getClsid());

    3.    IFeatureWorkspace pFWS = (IFeatureWorkspace) pWorkspaceFactory                                    .openFromFile("E:\\data\\qixiang\\qixiang.gdb", 0);

    4.    IFeatureClass fc = pFWS.openFeatureClass("Road");

    5.   IFeatureLayer fLayer = (IFeatureLayer) sctx                                                    .createObject(FeatureLayer.getClsid());

                               

    6.   fLayer.setFeatureClassByRef(fc);

    7.  fLayer.setName("Road");

      Server中的AO对象,必须在一个IServerContext上下文中使用,因此,AO对象的创建跟一般的Java类有所不同。因为数据是保存在filegeodatabase,所以在第2行代码中我们创建了一个FileGDBWorkspaceFactory,接下来的两行利用这个工厂类打开了一个IFeatureWorkspace,然后读取了其中的一个feature class。最后,用这个feature class设置了一个IFeatureLayer(ILayer的一个子类)。

      有了IMap和IFeatureLayer对象以后,其实就已经能动态添加图层了。但是这样添加的图层有一点欠缺的地方——它的渲染方式是随机的。就像我们用ArcMap直接打开一个polygon feature class时,ArcMap会随机选择一个填充色。为了保证每次用户添加图层以后能够看到同样的效果,我们需要为动态图层设置一个渲染方式。当然,我们可以在程序中为不同类型的要素分别设置一个Renderer,但是本文将探讨另一种方式。先用ArcMap设置好渲染方式,然后保存成一个*.lyr文件,动态添加图层的时候从lyr文件中读取Renderer信息,然后添加到IFeatureLayer。毕竟,用ArcMap设置Renderer比写代码要简单多了!而且,也更易于分发。

    清单3. 从*.lyr文件中读取Renderer信息

    1.  IMapDocument doc = (IMapDocument)sctx.createObject(MapDocument.getClsid());

    2.  doc.open(lyrFilePath, null);

    3.    ILayer lyr = doc.getLayer(0, 0);//get the first map's first layer

    4.    IFeatureRenderer renderer = null;

    5.    if(lyr instanceof IGeoFeatureLayer){

    6.                  IGeoFeatureLayer geoLyr = (IGeoFeatureLayer)lyr;

    7.                  renderer = geoLyr.getRenderer();

    8.   }

      在清单3中我们创建了一个MapDocument对象来读取lyr文件(API说明:The MapDocument CoClass encapsulates map document files (*.mxd, *mxt, *.pmf) and layer files (*.lyr))。第2行代码中的lyrFilePath就是lyr文件存放的路径。由于打开的是lyr文件,只有一个图层,所以第3行代码的两个参数都为零,表示打开的是第一个地图的第一个图层。接下来从图层文件中读取Renderer信息。

      接下来,我们就可以把Renderer信息赋给图层,然后将图层添加到地图上。

    清单4. 设置渲染方式,添加图层

    1.  if(renderer != null){

    2.           IGeoFeatureLayer geoFeatureLyr = (IGeoFeatureLayer)fLayer;

    3.           geoFeatureLyr.setRendererByRef(renderer);

    4.    }

    5.    fLayer.setVisible(true);

    6.    map.addLayer(fLayer);

    7.   map.moveLayer(fLayer, 1);

      至此,我们通过map service提供的AO接口完成了动态添加图层的工作,但是如果这时候我们去刷新浏览器,并不会看到新增加的图层!这是由于Web ADF层还不知道图层信息发生变化了。这与Web ADF的初始化有关,当一个session启动的时候,WebContext会根据map service的信息完成初始化,包括一些列的functionalities以及attributes,这些初始化信息中就包含图层信息(保存在com.esri.arcgisws.MapDescription和com.esri.arcgisws.MapLayerInfo等类中)。在WebContext初始化完成以后,如果map service的信息发生改变,必须由程序员自己去刷新Web ADF中的相关对象,实现Web ADF对象与map service同步。有趣的是,并不是所有对map service的修改都要自己去通知Web ADF,比如修改图层的Renderer信息就不需要。我觉得如果com.esri.arcgisws包中的与AO同名的对象,很可能就需要手工修改,因为这些对象都是初始化的时候创建的;如果没有,说明没有必要为其单独创建Web ADF对象,需要的时候就直接访问AO接口了。

    清单5. 刷新ADF对象

    1.  mapServer.refreshServerObjects();

                               

    2.  IMapServerInfo serverInfo = mapServer.getServerInfo(mapServer.getDefaultMapName());

                               

    3.  agsServerInfo = (com.esri.arcgisws.MapServerInfo)AGSUtil.createStubFromArcObject(serverInfo,com.esri.arcgisws.MapServerInfo.class,sctx);

     

    4.    com.esri.arcgisws.MapServerInfo si = mapFun.getMapServerInfo();

    5.    si.setMapLayerInfos(agsServerInfo.getMapLayerInfos());

    6.   mapFun.setMapDescription(agsServerInfo.getDefaultMapDescription());

      在清单5中,我们先刷新了map server object,然后获取了新的IMapServerInfo对象。第3行代码中我们完成了从AO对象到ADF对象的转换,这样,ADF就有了一个反映当前map service状态的com.esri.arcgisws.MapServerInfo。4到6行代码用新的com.esri.arcgisws.MapServerInfo刷新了AGSMapFunctionality,从而完成了ADF与map service的同步。下面的截图显示了动态添加图层的效果。

     

      由于WebContext以及它管理的一系列ADF资源只在session开始时进行一次初始化,因此动态添加的图层就无法用WebQuery来进行查询和高亮显示。在清单5中已经介绍了如何刷新ADF端的对象,因此,我们可以用更新以后的com.esri.arcgisws.MapServerPort对动态添加的图层进行查询。

      接下来的例子中,让用户在地图上拖一个矩形框,然后查询所有图层中与该矩形框相交的要素,并将它们高亮显示。首先需要将用户在地图上绘制的矩形框传递到服务器端,并创建一个com.esri.arcgisws.PolygonN对象。

    清单6. 捕获屏幕操作并构造服务器端几何要素

    1. WebExtent ext = (WebExtent)event.getWebGeometry().toMapGeometry(webContext.getWebMap());

    2. EnvelopeN env = (EnvelopeN)AGSUtil.toAGSGeometry(ext);

      接下来可以根据该PolygonN新建一个com.esri.arcgisws.SpatialFilter对象。

    清单7. 创建SpatailFilter对象

    1.  SpatialFilter spatialFilter = new SpatialFilter();

    2.  spatialFilter.setSpatialRel(EsriSpatialRelEnum.esriSpatialRelIntersects);

    3.  spatialFilter.setWhereClause("");

    4.  spatialFilter.setSearchOrder(EsriSearchOrder.esriSearchOrderSpatial);

    5.  spatialFilter.setSpatialRelDescription("");

    6.  spatialFilter.setGeometryFieldName("");

    7.  spatialFilter.setFilterGeometry(env);

       com.esri.arcgisws.MapServerPort的queryFeatureData()方法只能对某一个图层进行查询,所以,如果要查询所有的图层,需要对所有图层做一次循环。

    清单8. 空间查询

    1.  AGSMapFunctionality mapFunc = (AGSMapFunctionality)res.getFunctionality("map");

    2.  int layerCount = mapFunc.getLayerDescriptions().length;

    3.   MapServerPort svrPort = res.getMapServer();

    4.  try{

    5.           for(int i=0;i<layerCount;i++){

    6.       RecordSet rs = svrPort.queryFeatureData(“”,i, spatialFilter);

    7.     }

    8.  }catch(Exception e){

    9.  }

       第8行代码对每一个图层都做了一次空间查询,将查询结果保存在com.esri.arcgisws.RecordSet中。查询结果中包含了图层要素的所有信息,包括属性信息和空间信息,可以根据需要进行提取。这个例子中需要对查询结果做高亮显示,所以接下来我们关心的焦点就是获取查询结果的空间信息。

    清单9. 高亮显示查询结果

    1.  Record[] records = rs.getRecords();

    2.  for(int j=0;j<records.length;j++){

    3.           Record item = records[j];

    4.           int n = item.getValues().length;

    5.           for(int k=0;k<n;k++){

    6.               Object obj = item.getValues()[k];

    7.               if(obj instanceof com.esri.arcgisws.Geometry){

    8.                      WebGeometry geom = AGSUtil.fromAGSGeometry((com.esri.arcgisws.Geometry)obj);

    9.                      query.addDisplayGeometry(geom);

    10.             }

    11.         }

    12. }

       com.esri.arcgisws.Record对应的是某个图层的一条记录,它的getValues()方法获取该记录属性表中的所有信息(包括shape字段)。第6行开始我们读取每一个字段的值,判断该字段是否记录了shape信息,如果是,就将shape信息转成WebGeometry对象,然后用WebQuery进行高亮显示。

      下面两幅是查询然后高亮显示的效果图。

     

    原文链接:http://www.gissky.net/Article/1316.htm

     

  • 相关阅读:
    git(1)-git关联GitHub-windows-转载
    jenkins(4)-jenkins配置邮件通知
    jenkins(3)-linux下安装jenkins(yum install方式)
    【PAT甲级】1090 Highest Price in Supply Chain (25 分)(DFS)
    【PAT甲级】1087 All Roads Lead to Rome (30 分)(MAP【int,string】,邻接表,DFS,模拟,SPFA)
    【PAT甲级】1018 Public Bike Management (30 分)(DFS,SPFA)
    Educational Codeforces Round 61 (Rated for Div. 2) G(线段树,单调栈)
    Atcoder Grand Contest 032C(欧拉回路,DFS判环)
    Educational Codeforces Round 62 (Rated for Div. 2)E(染色DP,构造,思维,组合数学)
    Atcoder Grand Contest 031C(构造,思维,异或,DFS)
  • 原文地址:https://www.cnblogs.com/dwf07223/p/3024097.html
Copyright © 2011-2022 走看看