zoukankan      html  css  js  c++  java
  • cesium入门示例-测量工具

    作为cesium入门示例级别的最后一篇,参考cesium-长度测量和面积测量实现测量工具封装,修改了其中的距离测量函数,计算贴地距离,并对事件内部处理做了调整。包括贴地距离测量、面积测量、结果清除。

    实现思路(以距离测量为例):

    1、点击按钮开始测量,侦听鼠标LEFT_CLICK事件,记录坐标,绘制节点和折线;

    2、侦听鼠标移动事件,鼠标点击后即复制一个浮动点,在MOUSE_MOVE事件中不断更新最后一个浮动点,动态更新折线绘制;

    3、侦听鼠标右击事件,RIGHT_CLICK触发时销毁测量相关事件句柄(ScreenSpaceEventHandler),删除多余的浮动点;

    4、折线的动态绘制通过CallbackProperty属性绑定positions属性实现。

    封装代码如下:

     1 /*
     2  * params:
     3  *     viewer:required,三维视图
     4  *     target:required,测量工具放置的div的id
     5  * */
     6 
     7 var MeasureTool = (function() {
     8     function _(option) {
     9         this.viewer = option.viewer;
    10         this.dom = document.getElementById(option.target);
    11         this.options = option;
    12 
    13         var me = this;
    14         var btnDistance = document.createElement('button');
    15         btnDistance.innerHTML = '测量距离';
    16         btnDistance.onclick = function() {
    17             if(me.bMeasuring)
    18                 return;
    19 
    20             me.bMeasuring = true;
    21             me._measureLineSpace();
    22         };
    23         this.dom.appendChild(btnDistance);
    24 
    25         var btnArea = document.createElement('button');
    26         btnArea.innerHTML = '测量面积';
    27         btnArea.onclick = function() {
    28             if(me.bMeasuring)
    29                 return;
    30 
    31             me.bMeasuring = true;
    32             me._measureAreaSpace();
    33         };
    34         this.dom.appendChild(btnArea);
    35 
    36         var btnClear = document.createElement('button');
    37         btnClear.innerHTML = '清除结果';
    38         btnClear.onclick = function() {
    39             //删除事先记录的id
    40             for(var jj = 0; jj < me.measureIds.length; jj++) {
    41                 me.viewer.entities.removeById(me.measureIds[jj]);
    42             }
    43             me.measureIds.length = 0;
    44         };
    45         this.dom.appendChild(btnClear);
    46 
    47         this.bMeasuring = false;
    48         this.measureIds = [];
    49     }
    50 
    51     _.prototype._finishMeasure = function() {
    52         this.bMeasuring = false;
    53     }
    54 
    55     //内部测量距离函数
    56     _.prototype._measureLineSpace = function() {}
    57     //内部测量面积函数
    58     _.prototype._measureAreaSpace = function() {}
    59 
    60     return _;
    61 })();

    调用方法:

    1 <div style="position:absolute; 350px;height: 30px; top: 25px; left: 10px;">
    2     <div id="measure"> </div>
    3 </div>
    4 
    5 //创建测量工具
    6 new MeasureTool({
    7     viewer: viewer,
    8     target: 'measure'
    9 })

    计算贴地距离时,对折线按距离或按比例切分成小线段,通过SampleTerrain函数统一获取各点的高度,分段计算空间距离叠加即为贴地距离,因该过程稍费时异步计算后再显示计算结果,测量折线贴地距离的代码如下:

      1     //内部测量距离函数
      2     _.prototype._measureLineSpace = function() {
      3         var me = this;
      4         var viewer = this.viewer;
      5         // 取消双击事件-追踪该位置
      6         viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
      7 
      8         var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene._imageryLayerCollection);
      9         var positions = [];
     10         var poly = null;
     11         var distance = 0;
     12         var cartesian = null;
     13         var floatingPoint;
     14         var labelPt;
     15 
     16         handler.setInputAction(function(movement) {
     17             let ray = viewer.camera.getPickRay(movement.endPosition);
     18             cartesian = viewer.scene.globe.pick(ray, viewer.scene);
     19             if(!Cesium.defined(cartesian)) //跳出地球时异常
     20                 return;
     21             if(positions.length >= 2) {
     22                 if(!Cesium.defined(poly)) {
     23                     poly = new PolyLinePrimitive(positions);
     24                 } else {
     25                     positions.pop();
     26                     positions.push(cartesian);
     27                 }
     28             }
     29         }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
     30 
     31         handler.setInputAction(function(movement) {
     32             let ray = viewer.camera.getPickRay(movement.position);
     33             cartesian = viewer.scene.globe.pick(ray, viewer.scene);
     34             if(!Cesium.defined(cartesian)) //跳出地球时异常
     35                 return;
     36 
     37             if(positions.length == 0) {
     38                 positions.push(cartesian.clone());
     39             }
     40             positions.push(cartesian);
     41             //记录鼠标单击时的节点位置,异步计算贴地距离
     42             labelPt = positions[positions.length - 1];
     43             if(positions.length > 2) {
     44                 getSpaceDistance(positions);
     45             } else if(positions.length == 2) {
     46                 //在三维场景中添加Label
     47                 floatingPoint = viewer.entities.add({
     48                     name: '空间距离',
     49                     position: labelPt,
     50                     point: {
     51                         pixelSize: 5,
     52                         color: Cesium.Color.RED,
     53                         outlineColor: Cesium.Color.WHITE,
     54                         outlineWidth: 2,
     55                     }
     56                 });
     57                 me.measureIds.push(floatingPoint.id);
     58             }
     59 
     60         }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
     61 
     62         handler.setInputAction(function(movement) {
     63             handler.destroy(); //关闭事件句柄
     64             handler = undefined;
     65             positions.pop(); //最后一个点无效
     66             if(positions.length == 1)
     67                 viewer.entities.remove(floatingPoint);
     68             //记录测量工具状态
     69             me._finishMeasure();
     70 
     71         }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
     72 
     73         var PolyLinePrimitive = (function() {
     74             function _(positions) {
     75                 this.options = {
     76                     name: '直线',
     77                     polyline: {
     78                         show: true,
     79                         positions: [],
     80                         material: Cesium.Color.CHARTREUSE,
     81                          5,
     82                         clampToGround: true
     83                     }
     84                 };
     85                 this.positions = positions;
     86                 this._init();
     87             }
     88 
     89             _.prototype._init = function() {
     90                 var _self = this;
     91                 var _update = function() {
     92                     return _self.positions;
     93                 };
     94                 //实时更新polyline.positions
     95                 this.options.polyline.positions = new Cesium.CallbackProperty(_update, false);
     96                 var addedEntity = viewer.entities.add(this.options);
     97                 me.measureIds.push(addedEntity.id);
     98             };
     99 
    100             return _;
    101         })();
    102 
    103         //空间两点距离计算函数
    104         function getSpaceDistance(positions) {
    105             //只计算最后一截,与前面累加
    106             //因move和鼠标左击事件,最后两个点坐标重复
    107             var i = positions.length - 3;
    108             var point1cartographic = Cesium.Cartographic.fromCartesian(positions[i]);
    109             var point2cartographic = Cesium.Cartographic.fromCartesian(positions[i + 1]);
    110             getTerrainDistance(point1cartographic, point2cartographic);
    111         }
    112 
    113         function getTerrainDistance(point1cartographic, point2cartographic) {
    114             var geodesic = new Cesium.EllipsoidGeodesic();
    115             geodesic.setEndPoints(point1cartographic, point2cartographic);
    116             var s = geodesic.surfaceDistance;
    117             var cartoPts = [point1cartographic];
    118             for(var jj = 1000; jj < s; jj += 1000) {  //分段采样计算距离
    119                 var cartoPt = geodesic.interpolateUsingSurfaceDistance(jj);
    120                 //                console.log(cartoPt);
    121                 cartoPts.push(cartoPt);
    122             }
    123             cartoPts.push(point2cartographic);
    124             //返回两点之间的距离
    125             var promise = Cesium.sampleTerrain(viewer.terrainProvider, 8, cartoPts);
    126             Cesium.when(promise, function(updatedPositions) {
    127                 // positions height have been updated.
    128                 // updatedPositions is just a reference to positions.
    129                 for(var jj = 0; jj < updatedPositions.length - 1; jj++) {
    130                     var geoD = new Cesium.EllipsoidGeodesic();
    131                     geoD.setEndPoints(updatedPositions[jj], updatedPositions[jj + 1]);
    132                     var innerS = geoD.surfaceDistance;
    133                     innerS = Math.sqrt(Math.pow(innerS, 2) + Math.pow(updatedPositions[jj + 1].height - updatedPositions[jj].height, 2));
    134                     distance += innerS;
    135                 }
    136 
    137                 //在三维场景中添加Label
    138                 var textDisance = distance.toFixed(2) + "米";
    139                 if(distance > 10000)
    140                     textDisance = (distance / 1000.0).toFixed(2) + "千米";
    141                 floatingPoint = viewer.entities.add({
    142                     name: '贴地距离',
    143                     position: labelPt,
    144                     point: {
    145                         pixelSize: 5,
    146                         color: Cesium.Color.RED,
    147                         outlineColor: Cesium.Color.WHITE,
    148                         outlineWidth: 2,
    149                     },
    150                     label: {
    151                         text: textDisance,
    152                         font: '18px sans-serif',
    153                         fillColor: Cesium.Color.GOLD,
    154                         style: Cesium.LabelStyle.FILL_AND_OUTLINE,
    155                         outlineWidth: 2,
    156                         verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
    157                         pixelOffset: new Cesium.Cartesian2(20, -20),
    158                     }
    159                 });
    160                 me.measureIds.push(floatingPoint.id);
    161             });
    162         }
    163 
    164     }

    测量面积实现方式与折线类似,可参考cesium-长度测量和面积测量自行实现,无需计算贴地距离。细节处还可优化。

     最后实现的效果如下:

  • 相关阅读:
    SuperMap房产测绘成果管理平台
    SuperMap产权登记管理平台
    Android adb shell am 的用法(1)
    由浅入深谈Perl中的排序
    Android 内存监测和分析工具
    Android 网络通信
    adb server is out of date. killing...
    引导页使用ViewPager遇到OutofMemoryError的解决方案
    adb logcat 详解
    How to send mail by java mail in Android uiautomator testing?
  • 原文地址:https://www.cnblogs.com/HandyLi/p/11125326.html
Copyright © 2011-2022 走看看