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

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

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

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

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

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

封装代码如下:

 /*
* params:
* viewer:required,三维视图
* target:required,测量工具放置的div的id
* */ var MeasureTool = (function() {
function _(option) {
this.viewer = option.viewer;
this.dom = document.getElementById(option.target);
this.options = option; var me = this;
var btnDistance = document.createElement('button');
btnDistance.innerHTML = '测量距离';
btnDistance.onclick = function() {
if(me.bMeasuring)
return; me.bMeasuring = true;
me._measureLineSpace();
};
this.dom.appendChild(btnDistance); var btnArea = document.createElement('button');
btnArea.innerHTML = '测量面积';
btnArea.onclick = function() {
if(me.bMeasuring)
return; me.bMeasuring = true;
me._measureAreaSpace();
};
this.dom.appendChild(btnArea); var btnClear = document.createElement('button');
btnClear.innerHTML = '清除结果';
btnClear.onclick = function() {
//删除事先记录的id
for(var jj = 0; jj < me.measureIds.length; jj++) {
me.viewer.entities.removeById(me.measureIds[jj]);
}
me.measureIds.length = 0;
};
this.dom.appendChild(btnClear); this.bMeasuring = false;
this.measureIds = [];
} _.prototype._finishMeasure = function() {
this.bMeasuring = false;
} //内部测量距离函数
_.prototype._measureLineSpace = function() {}
//内部测量面积函数
_.prototype._measureAreaSpace = function() {} return _;
})();

调用方法:

 <div style="position:absolute;width: 350px;height: 30px; top: 25px; left: 10px;">
<div id="measure"> </div>
</div> //创建测量工具
new MeasureTool({
viewer: viewer,
target: 'measure'
})

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

     //内部测量距离函数
_.prototype._measureLineSpace = function() {
var me = this;
var viewer = this.viewer;
// 取消双击事件-追踪该位置
viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK); var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene._imageryLayerCollection);
var positions = [];
var poly = null;
var distance = 0;
var cartesian = null;
var floatingPoint;
var labelPt; handler.setInputAction(function(movement) {
let ray = viewer.camera.getPickRay(movement.endPosition);
cartesian = viewer.scene.globe.pick(ray, viewer.scene);
if(!Cesium.defined(cartesian)) //跳出地球时异常
return;
if(positions.length >= 2) {
if(!Cesium.defined(poly)) {
poly = new PolyLinePrimitive(positions);
} else {
positions.pop();
positions.push(cartesian);
}
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE); handler.setInputAction(function(movement) {
let ray = viewer.camera.getPickRay(movement.position);
cartesian = viewer.scene.globe.pick(ray, viewer.scene);
if(!Cesium.defined(cartesian)) //跳出地球时异常
return; if(positions.length == 0) {
positions.push(cartesian.clone());
}
positions.push(cartesian);
//记录鼠标单击时的节点位置,异步计算贴地距离
labelPt = positions[positions.length - 1];
if(positions.length > 2) {
getSpaceDistance(positions);
} else if(positions.length == 2) {
//在三维场景中添加Label
floatingPoint = viewer.entities.add({
name: '空间距离',
position: labelPt,
point: {
pixelSize: 5,
color: Cesium.Color.RED,
outlineColor: Cesium.Color.WHITE,
outlineWidth: 2,
}
});
me.measureIds.push(floatingPoint.id);
} }, Cesium.ScreenSpaceEventType.LEFT_CLICK); handler.setInputAction(function(movement) {
handler.destroy(); //关闭事件句柄
handler = undefined;
positions.pop(); //最后一个点无效
if(positions.length == 1)
viewer.entities.remove(floatingPoint);
//记录测量工具状态
me._finishMeasure(); }, Cesium.ScreenSpaceEventType.RIGHT_CLICK); var PolyLinePrimitive = (function() {
function _(positions) {
this.options = {
name: '直线',
polyline: {
show: true,
positions: [],
material: Cesium.Color.CHARTREUSE,
width: 5,
clampToGround: true
}
};
this.positions = positions;
this._init();
} _.prototype._init = function() {
var _self = this;
var _update = function() {
return _self.positions;
};
//实时更新polyline.positions
this.options.polyline.positions = new Cesium.CallbackProperty(_update, false);
var addedEntity = viewer.entities.add(this.options);
me.measureIds.push(addedEntity.id);
}; return _;
})(); //空间两点距离计算函数
function getSpaceDistance(positions) {
//只计算最后一截,与前面累加
//因move和鼠标左击事件,最后两个点坐标重复
var i = positions.length - 3;
var point1cartographic = Cesium.Cartographic.fromCartesian(positions[i]);
var point2cartographic = Cesium.Cartographic.fromCartesian(positions[i + 1]);
getTerrainDistance(point1cartographic, point2cartographic);
} function getTerrainDistance(point1cartographic, point2cartographic) {
var geodesic = new Cesium.EllipsoidGeodesic();
geodesic.setEndPoints(point1cartographic, point2cartographic);
var s = geodesic.surfaceDistance;
var cartoPts = [point1cartographic];
for(var jj = 1000; jj < s; jj += 1000) {  //分段采样计算距离
var cartoPt = geodesic.interpolateUsingSurfaceDistance(jj);
// console.log(cartoPt);
cartoPts.push(cartoPt);
}
cartoPts.push(point2cartographic);
//返回两点之间的距离
var promise = Cesium.sampleTerrain(viewer.terrainProvider, 8, cartoPts);
Cesium.when(promise, function(updatedPositions) {
// positions height have been updated.
// updatedPositions is just a reference to positions.
for(var jj = 0; jj < updatedPositions.length - 1; jj++) {
var geoD = new Cesium.EllipsoidGeodesic();
geoD.setEndPoints(updatedPositions[jj], updatedPositions[jj + 1]);
var innerS = geoD.surfaceDistance;
innerS = Math.sqrt(Math.pow(innerS, 2) + Math.pow(updatedPositions[jj + 1].height - updatedPositions[jj].height, 2));
distance += innerS;
} //在三维场景中添加Label
var textDisance = distance.toFixed(2) + "米";
if(distance > 10000)
textDisance = (distance / 1000.0).toFixed(2) + "千米";
floatingPoint = viewer.entities.add({
name: '贴地距离',
position: labelPt,
point: {
pixelSize: 5,
color: Cesium.Color.RED,
outlineColor: Cesium.Color.WHITE,
outlineWidth: 2,
},
label: {
text: textDisance,
font: '18px sans-serif',
fillColor: Cesium.Color.GOLD,
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
outlineWidth: 2,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
pixelOffset: new Cesium.Cartesian2(20, -20),
}
});
me.measureIds.push(floatingPoint.id);
});
} }

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

最后实现的效果如下:

cesium入门示例-测量工具的更多相关文章

  1. cesium入门示例-矢量化单体分类

    实现楼层的分层选择和属性信息展示,该功能基于大雁塔倾斜数据实现单体化分类显示. 数据准备: 1.大雁塔倾斜数据,已转换为3dTiles,参考cesium入门示例-3dTiles加载的第2节osgb数据 ...

  2. cesium入门示例-HelloWorld

    示例准备: 在Cesium ion官网(https://cesium.com/)上注册用户,获取AccessToken,在js代码入口设置Cesium.Ion.defaultAccessToken,即 ...

  3. cesium入门示例-探测效果

    动画实现方式通过多个canvas实现,参考的https://www.yueyanshaosun.cn/ysCesium/views/5_geometricObj2_entityCanvas.html ...

  4. cesium入门示例-3dTiles加载

    数据转换工具采用cesiumlab1.5.17版本,转换后的3dTiles加载显示比较简单,通过Cesium.Cesium3DTileset接口指定url即可,3dTiles文件可与js前端代码放置一 ...

  5. cesium入门示例-geoserver服务访问

    1.wms服务访问 //wms服务 viewer.imageryLayers.addImageryProvider(new Cesium.WebMapServiceImageryProvider({ ...

  6. Cesium入门2 - Cesium环境搭建及第一个示例程序

    Cesium入门2 - Cesium环境搭建及第一个示例程序 Cesium中文网:http://cesiumcn.org/ | 国内快速访问:http://cesium.coinidea.com/ 验 ...

  7. Cesium入门13 - Extras - 附加内容

    Cesium入门13 - Extras - 附加内容 Cesium中文网:http://cesiumcn.org/ | 国内快速访问:http://cesium.coinidea.com/ 剩下的代码 ...

  8. Cesium入门9 - Loading and Styling Entities - 加载和样式化实体

    Cesium入门9 - Loading and Styling Entities - 加载和样式化实体 Cesium中文网:http://cesiumcn.org/ | 国内快速访问:http://c ...

  9. Cesium入门8 - Configuring the Scene - 配置视窗

    Cesium入门8 - Configuring the Scene - 配置视窗 Cesium中文网:http://cesiumcn.org/ | 国内快速访问:http://cesium.coini ...

随机推荐

  1. 201604-1 折点计数 Java

    思路: 这个题要小心考虑不全.左右两边都比这个数小 或者 左右两边都比这个数大 import java.util.Scanner; public class Main { public static ...

  2. PAT Basic 1043 输出PATest (20分)[Hash散列]

    题目 给定⼀个⻓度不超过10000的.仅由英⽂字⺟构成的字符串.请将字符重新调整顺序,按"PATestPATest-."这样的顺序输出,并忽略其它字符.当然,六种字符的个数不⼀定是 ...

  3. UML-领域模型-准则

    1.是否使用工具维护模型? 在白板上画完草图后,整理到UML工具里去 2.模型中是否要包含“票据”? 不包含,因为,票据用于退货,而本次迭代不涉及退货所以不需要体现. 总结:概念一定在本次迭代需求内的 ...

  4. Angular(三)

    Angular开发者指南(三)数据绑定   数据绑定AngularJS应用程序中的数据绑定是模型和视图组件之间的数据的自动同步. AngularJS实现数据绑定的方式可以将模型视为应用程序中的单一来源 ...

  5. 计量经济与时间序列_关于Box-Jenkins的ARMA模型的经济学意义(重要思路)

    1 很多人已经了解到AR(1)这种最简单的时间序列模型,ARMA模型包括AR模型和MA模型两个部分,这里要详细介绍Box-Jenkins模型的观念(有些资料中把ARMA模型叫做Box-Jenkins模 ...

  6. 嵌入式开发为什么选择C语言作为开发语言?

    了解嵌入式开发的朋友们都非常的清楚其核心的开发语言为C语言,C语言在嵌入式开发的过程中占有十分重要的地位,可以说两者之间“你中有我,我中有你”.但是有很多人会想,有那么多的开发语言为什么会单单的选择C ...

  7. 第一个----关于GPIO的总结

    首先,自己本来报的是单片机的  ,但是因为队友的脑残,给我报成了嵌入式,哎,惨啊,就得从头看这个云里雾里的东西,但是没办法,都报名了  不能呢个交白卷,不然自己就是逃兵了,还有20天就比赛了  我得加 ...

  8. SQL Server Driver for PHP之sqlsrv相关函数

    SQL Server Driver for PHP 包含以下函数: 函数 说明 sqlsrv_begin_transaction 开始事务. sqlsrv_cancel 取消语句:并放弃相应语句的所有 ...

  9. office 无法打开xlsx文件的问题

    1. 设置content-type和header response.setContentType("application/vnd.openxmlformats-officedocument ...

  10. 安卓ButtomBar实现方法

    这里ButtomBar有3个items,分别有icon和文字,在当前fragment时,所属的icon和文字会显示不同颜色. 1. 首先要准好ICON素材,命名规范要清楚. 2. 实现这个Buttom ...