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;width: 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                         width: 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-長度測量和面積測量自行實現,無需計算貼地距離。細節處還可優化。

 最后實現的效果如下:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM