ArcGIS Maritime Server 开发教程(五)Maritime Service 系列问题应对

ArcGIS Maritime Server 开发教程(五)Maritime Service 系列问题应对

本章导读:Maritime Service 前端没有专门的开发接口,其开发都是依赖传统的 ArcGIS JavaScript API ,这跟它的架构有着密切的关系,其 SOE 扩展本身就是针对服务器端的功能进行扩展,依赖于主体服务进行发布和管理,因此接口方面有着绝大部分的对应。但由于数据源方面是非传统 GIS 数据,所以也限制了它在传统开发中的顺利过渡。本章主要围绕开发过程中的几个主要问题进行论述,旨在让开发人员了解更多一点,少走一些弯路。By 李远祥

有些参数是必须的

上一章节提到的 identify 功能,虽然操作和接口都是跟传统方式类似,但 identifyParams.layerOption 实际上是不生效的,它不能处理查询的图层是否可见图层或全部图层查询,因为 S-57 数据本身就没有层的概念。所以,如果希望点击查询时操作对象为可见图层,那就肯定是白搭了,设置了等于没设置。必须设置 identifyParams.mapExtent,否则点选查询不作响应。

这两个参数属性比较坑,一不小心掉进去就出不来了。当初笔者还一直在调试代码,代码一直没有任何的问题,但一直却出不来效果。最后还是监测了很久才试出问题的所在。通过思考其原理,大概还是明白其具体原因,毕竟 S-57 数据跟 GIS 数据的差别,还是使得 Maritime Service 完全适配存在问题。但这些问题似乎没有在产品文档中体验出来( Maritime Server 能找到的帮助少之又少)。

具体情况可以参考上一章节《ArcGIS Maritime Server 开发教程(四)Maritime Service 开发实践》中的 【 Maritime Service identify 操作】的内容。

有些参数是无效的

在 Maritime Service 调用的过程中,有些参数无效的,有时候也会让人哭笑不得。由于 Maritime Service 没有 Query 的操作,所以在空间查询方面就只能依靠 identify 功能了。从传统的 IdentifyParameters 接口来看,它是有 geometry 属性的,是支持输入一个图形作为查询的几何图形的,如下图所示:

为此,笔者还暗自欢喜,这样子也不赖,可以通过 identify 的方式来实现 Query 的一些空间操作。但测试的实际结果,还是有点强差人意。

但实际结果是,IdentifyParameters 的 geometry 参数只支持点和规则矩形两种,并不是所有的 geometry 。 如果希望通过其他如 Polygon 、Polyline 或者一些图形 Buffer 之后做操作,那就会出现失败操作。
为了测试其支持的 geometry 类型,笔者特意写了一个比较通用的程序进行测试,其思路是编写一个 Draw 方式去做一个绘图的工具,在绘制图形之后使用该图形作为 IdentifyParameters 的 geometry 参数传入,并且支持 identify 操作。其代码如下:

<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no" />
  <title>空间查询海图要素</title>
  <link rel="stylesheet" href="http://localhost/arcgis_js_api/3.19/esri/css/esri.css">
  <style>
    html,
    body,
    #mapDiv {
      width: 100%;
      height: 100%;
      margin: 0;
      padding: 0;
    }
  </style>
  <script src="http://localhost/arcgis_js_api/3.19/init.js"></script>
  <script>
    var map, tb;
    var drawGrapic;
    require(["esri/map",
      "esri/layers/ArcGISDynamicMapServiceLayer",
      "esri/geometry/Extent",
      "esri/symbols/SimpleMarkerSymbol",
      "esri/symbols/SimpleLineSymbol",
      "esri/symbols/SimpleFillSymbol",
      "esri/tasks/IdentifyTask",
      "esri/tasks/IdentifyParameters",
      "esri/tasks/IdentifyResult",
      "dojo/Deferred",
      "esri/Color", "esri/graphic",
      "esri/toolbars/draw",
      "esri/symbols/PictureFillSymbol", "esri/symbols/CartographicLineSymbol",
      "dojo/on", "dojo/dom",
      "dojo/domReady!"],
      function (Map, DynamicLayer, Extent,
        SimpleMarkerSymbol, SimpleLineSymbol, SimpleFillSymbol,
        IdentifyTask, IdentifyParameters, IdentifyResult, Deferred,
        Color, Graphic, Draw,
        PictureFillSymbol, CartographicLineSymbol,
        on, dom) {
        //初始化显示范围
        var initexten = new Extent({ "xmin": 113.42, "ymin": 22.15, "xmax": 113.58, "ymax": 22.26, "spatialReference": { "wkid": 4326 } });
        map = new Map("mapDiv", { extent: initexten });
        //加载基础服务WGS 84
        var basemap = new DynamicLayer("http://localhost:6080/arcgis/rest/services/SampleWorldCities/MapServer");
        map.addLayer(basemap);
        //ENC WGS 84
        var enc84 = new DynamicLayer("http://localhost:6080/arcgis/rest/services/SampleWorldCities/MapServer/exts/MaritimeChartService/MapServer");
        map.addLayer(enc84);
        //map.on("load", initToolbar);

        //注册点击查询事件
        map.on("load", initToolbar);
        //简单点符号
        var markerSymbol = new SimpleMarkerSymbol();
        markerSymbol.setColor(new Color("#00FFFF"));
        markerSymbol.setStyle(SimpleMarkerSymbol.STYLE_CIRCLE);
        markerSymbol.setSize(12);
        //制图线符号
        var lineSymbol = new CartographicLineSymbol(
          CartographicLineSymbol.STYLE_SOLID,
          new Color([255, 0, 0]), 10,
          CartographicLineSymbol.CAP_ROUND,
          CartographicLineSymbol.JOIN_MITER, 5
        );

        //图片填充
        var fillSymbol = new PictureFillSymbol(
          "/mangrove.png",
          new SimpleLineSymbol(
            SimpleLineSymbol.STYLE_SOLID,
            new Color('#000'),
            1
          ),
          42,
          42
        );

        //点击地图,通过屏幕上的点进行查询
        function mapIdentifyByGeometry(geom) {
          var identifyParams, identifyTask;
          identifyTask = new IdentifyTask("http://localhost:6080/arcgis/rest/services/SampleWorldCities/MapServer/exts/MaritimeChartService/MapServer");
          identifyParams = new IdentifyParameters();
          identifyParams.tolerance = 30;
          identifyParams.returnGeometry = true;
          identifyParams.geometry = geom;
          identifyParams.mapExtent = map.extent;
          identifyParams.layerOption = IdentifyParameters.LAYER_OPTION_VISIBLE;
          identifyParams.width = map.width;
          identifyParams.height = map.height;
          identifyTask.execute(identifyParams, getResult);
        }

        function getResult(results) {
          //先清空地图上的要素,便于展示结果数据
          //map.graphics.clear();
          //遍历所有的查找结果
          dojo.forEach(results, function (result) {
            //对每个查找结果进行渲染
            setGrapic(result.feature);
          }
          );
        }
        //渲染查找结果
        function setGrapic(gra) {
          //定义点线面符号
          var pointSym = new SimpleMarkerSymbol();
          var lineSym = new SimpleLineSymbol();
          var polySym = new SimpleFillSymbol();
          var color = new Color([255, 0, 0, 0.5]);
          var outColor = new Color([0, 255, 0, 0.5]);
          //点符号设置
          pointSym.setColor(color);
          pointSym.setSize(12);
          pointSym.outline.setColor(outColor);
          //线符号设置
          lineSym.setColor(color);
          lineSym.setWidth(3);
          //面符号设置
          polySym.setColor(color);
          polySym.outline.setColor(outColor);
          //对返回的物标要素进行渲染
          //获取物标所有的属性,其中objectType(固定标识) 为物标的唯一标识
          var featureAttributes = gra.attributes;
          for (var attr in featureAttributes) {
            if (attr == "objectType") {
              var oType = featureAttributes[attr];
              if (oType == "TSSBND") {
                //对点线面图形设置符号
                if (gra.geometry.type == "point") {
                  gra.symbol = pointSym;
                } else if (gra.geometry.type == "polyline") {
                  gra.symbol = lineSym;
                } else if (gra.geometry.type == "polygon") {
                  gra.symbol = polySym;
                }
                map.graphics.add(gra);
                //跳转到地图位置
                jumptoMap(gra);
              }
            }
          }
        }
        //跳转到要素所在的位置
        function jumptoMap(gra) {
          if (gra.geometry.type == "point") {
            map.centerAndZoom(gra.geometry);
          } else {
            map.setLevel(6);
            map.setExtent(gra.geometry.getExtent());
          }
        }

        //跳转到要素所在的位置
        function jumptoMap(gra) {
          if (gra.geometry.type == "point") {
            map.centerAndZoom(gra.geometry);
          } else {
            map.setLevel(6);
            map.setExtent(gra.geometry.getExtent());
          }
        }

        function initToolbar() {
          tb = new Draw(map);
          tb.on("draw-end", addGraphic);
          on(dom.byId("info"), "click", function (evt) {
            if (evt.target.id === "info") {
              return;
            }
            var tool = evt.target.id.toLowerCase();
            map.disableMapNavigation();
            tb.activate(tool);
          });
        }

        function addGraphic(evt) {
          tb.deactivate();
          map.enableMapNavigation();
          var symbol;
          if (evt.geometry.type === "point" || evt.geometry.type === "multipoint") {
            symbol = markerSymbol;
          } else if (evt.geometry.type === "line" || evt.geometry.type === "polyline") {
            symbol = lineSymbol;
          }
          else {
            symbol = fillSymbol;
          }
          var drawGrapic2 = new Graphic(evt.geometry, symbol);
          map.graphics.add(drawGrapic2);
          mapIdentifyByGeometry(evt.geometry);
        }
      });
  </script>
</head>

<body>
  <div id="info">
    <button id="Point">Point</button>
    <button id="Multipoint">Multipoint</button>
    <button id="Line">Line</button>
    <button id="Polyline">Polyline</button>
    <button id="FreehandPolyline">Freehand Polyline</button>
    <button id="Triangle">Triangle</button>
    <button id="Extent">Rectangle</button>
    <button id="Circle">Circle</button>
    <button id="Ellipse">Ellipse</button>
    <button id="Polygon">Polygon</button>
    <button id="FreehandPolygon">Freehand Polygon</button>
  </div>
  <div id="mapDiv"></div>
</body>
</html>

先看成功部分,Point 的操作,点击地图后顺利的查询并返回结果,如下图
Point 操作成功

然后是 Rectangle ,同样也是成功操作,并返回结果,如下图
Rectangle 操作成功

再来测试最常见的 Polygon 操作,并打开监测工具查看。

同样的代码在传入不同图形的时候,出现了报错现象。这种现象在其他罗列的各种图形中同样存在。

所以,笔者非常肯定的是 Maritime Service 的 identify 操作是不支持点和矩形之外的其他图形操作的。读者也无需费大气力再去测试。

有些功能是特定场景才能使用的

例如 mcstpk 工具 ,它只能制作基于 web 墨卡托,并且基于谷歌地图的切片方案的切片包 。无论如何修改 ServerConfiguration.xml 的 wkid 都是无效的,反而还会导致切片生成出问题。 mcstpk 工具界面中没有任何可以设置坐标系和切片方案的按钮和菜单,顶多只有设置生成哪几个级别的切片,如下图所示

生成的 tpk 能在 ArcMap、ArcGIS earth 、ArcGIS Runtime、ArcGIS Online 中使用,但并不支持直接上传到 ArcGIS Portal 中发布切片服务( ArcGIS Online 上没问题)

使用 mcstpk 工具生成的 tpk 包跟传统的 tpk 有点区别,笔者解压后对二者进行过对比。后续有时间的话,笔者会和小伙伴们制作一个小程序来解决标准 tpk 生成的问题,是的 ArcGIS Portal 能够顺利读取并发布切片地图。

使用模式问题

由于 S-57 的数据结构限制了 Maritime Service 向传统 MapService 发展,使得使用传统的 ArcGIS JavaScript API 开发存在各种的问题。不管是操作失效还是功能限制,都让传统 ArcGIS 开发人员感觉到麻烦。

这个问题基本上不可能在短期内得到解决,笔者设置认为 ArcGIS 软件短期内应该不会针对 S-57 的 Maritime Service 进行跟多有效的改进。因为这是一个即将废弃的标准,只是目前 S-100 系列还没能有效的推行。从 ArcGIS Bathymetry 扩展非常有效的支持 S-102 数据可以看出,Esri 更加注重将海图产品压在未来的 S-100 系列标准中。

因为一些问题在短期内无法解决,所以只能探讨应用模式的问题。ArcGIS Maritime Server 的出现,解决了 ArcGIS 海图应用的一个非常重要的问题,就是配图。利用传统的配图方式去配置 S-52 样式,其工作量几乎让人无法忍受。而 Maritime Server 出现之后,该工作就完全不需要做了,直接有服务器端根据 S-57 数据自动生成。

地图的空间操作方面,由于使用的是非 GIS 数据,几乎是不能适配的了。就算解决掉 identify 存在的问题,或者加入 Query 的操作,都不能适应 GIS 的使用。因为很多的图层叠加计算无法操作,很多 GP 工具都无法使用。

从 Maritime Server 的角度来看,其主要作用还是解决 S-57 数据的发布以及 S-52 海图样式的出图显示两大问题,并不能解决从海图到传统地图的所有功能操作。

既然是这样,那么使用模式就很好确定了。利用 Maritime Service 作为前端的显示,解决 S-52 的显示问题;针对 S-57 数据提取或生成 GIS 数据,另外发布一个 GIS 服务(不作叠加显示),用作各种的空间分析和叠加分析,这样就可以顺利解决从海图向 GIS 过渡的各种问题。当然,这里也就引入了一些工作量,就是海图数据到 GIS 数据的提取和转换。

解决一个问题的同时,还是会引入另一个问题的。最需要考虑的地方则是成本问题,也就是传说中的值不值的问题。^_^

如果是强海图应用,这种方案是最省力的了,也是不二之选。如果只是调用海图作为底图,那就无所谓其他的空间操作了,直接将自身的专题数据制作成 GIS 格式,发布地图服务进行叠加即可。

总结

就目前来说,针对 S-57 的 Maritime Service 还是存在各种小问题,但在改变应用模式的基础上,似乎能够很好的解决其自身的不足,能够顺利的从海图到 GIS 的过渡。笔者认为,现阶段是海图向 GIS 过渡的阶段,不管是技术上还是使用模式上,均属于探索性的工作。海图的信息化进步应该在不远的 S-100 体系推广之后。

更多的GIS主流和非主流技术,可以持续关注CSDN的GIS制图乐园,以及微信公众号【GIS制图乐园】。BY 李远祥

阅读更多

扫码向博主提问

李远祥

博客专家

非学,无以致疑;非问,无以广识
去开通我的Chat快问
版权声明:欢迎分享地理价值,但请注明出处,http://blog.csdn.net/liyuanxiang1984 https://blog.csdn.net/liyuanxiang1984/article/details/79955605
个人分类: 海图
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭