关于测量
测量是一个GIS系统最基本的,也是必备的模块,网上也有很多相关开发者分享过关于Cesium测量的技术文章,风格各异,但是大同小异,只要弄清楚了原理以及方法,其实每个人都可以写出自己的测量小工具。
测距
测距其实计算两点之间的距离,这个计算方法可以使用最原始的直角三角形求斜边的方法,但是我们也可以直接使用Cesium中Cartesian3接口的distance方法。
Cesium.Cartesian3.distance(firstPoint, secondPoint);
计算方法已经有了,我们要做的就是添砖加瓦,做成一个可供用户交互的测距,并且实时显示距离长度的效果。
// 注册鼠标左击事件
viewer.screenSpaceEventHandler.setInputAction(function (clickEvent) {
var cartesian = viewer.scene.pickPosition(clickEvent.position);
// 如果是第一次点击
if (positions.length == 0) {
addPoint(cartesian); // 存储第一个点,并在点击处绘制一个点entity
// 同时注册鼠标移动事件
} else {
addPoint(cartesian); // 存储第二个点,并在点击处绘制一个点entity,测量结束,注销所有的鼠标注册事件
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
// 注册鼠标移动事件
viewer.screenSpaceEventHandler.setInputAction(function (moveEvent) {
var movePosition = viewer.scene.pickPosition(moveEvent.endPosition); // 鼠标移动的点
if (positions.length == 1) {
// 存储第二个点
positions.push(movePosition);
// 绘制线
addLine(positions);
} else {
positions.pop(); // 移除上次鼠标经过的点
positions.push(movePosition); // 存储这次鼠标经过的点
// 计算中点
var centerPoint = Cesium.Cartesian3.midpoint(positions[0], positions[1], new Cesium.Cartesian3());
// 计算距离
var lengthText = "距离:" + getLengthText(positions[0], positions[1]);
// 绘制距离长度标签
labelEntity = addLabel(centerPoint, lengthText);
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
测面
测面积,也就是计算至少三个点构成的任意多边形的面积,可以使用拆分三角曲面的方法计算每一个小三角形的面积,然后累加得到任意多边形的面积。由于多边形点的个数是至少3个,所以我们还要比测距多一个结束注册事件,可以双击结束,也可以右击结束。
// 注册鼠标左击事件
viewer.screenSpaceEventHandler.setInputAction(function (clickEvent) {
var cartesian = viewer.scene.pickPosition(clickEvent.position);
if (positions.length == 0) {
positions.push(cartesian.clone()); //鼠标左击 添加第1个点
addPoint(cartesian);
// 注册鼠标移动事件
} else if (positions.length == 2) {
positions.pop();
positions.push(cartesian.clone()); // 鼠标左击 添加第2个点
addPoint(cartesian);
addPolyGon(positions); // 绘制面
// 注册鼠标右击结束事件
} else if (positions.length >= 3) {
positions.pop();
positions.push(cartesian.clone()); // 鼠标左击 添加第3个点
addPoint(cartesian);
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
// 注册鼠标移动事件
viewer.screenSpaceEventHandler.setInputAction(function (moveEvent) {
var movePosition = viewer.scene.pickPosition(moveEvent.endPosition);
if (positions.length == 1) {
positions.push(movePosition);
addLine(positions);
} else {
positions.pop();
positions.push(movePosition);
}
if (positions.length >= 3) {
var text = "面积:" + getArea(positions);
// 获取面积的重心
var centerPoint = getCenterOfGravityPoint(positions);
// 绘制label
addLabel(centerPoint, text);
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
// 注册鼠标右击结束事件
viewer.screenSpaceEventHandler.setInputAction(function (clickEvent) {
var clickPosition = viewer.scene.pickPosition(clickEvent.position);
positions.pop();
positions.push(clickPosition);
positions.push(positions[0]); // 闭合
addPoint(clickPosition);
// 解除注册的事件
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
测高
测高即是在测距的基础上,计算两个点之间的空间高度,这个是对测距的一个功能扩展。
// 注册鼠标左击事件
viewer.screenSpaceEventHandler.setInputAction(function (clickEvent) {
var cartesian = viewer.scene.pickPosition(clickEvent.position); // 坐标
// 存储第一个点
if (positions.length == 0) {
positions.push(cartesian.clone());
addPoint(cartesian);
// 注册鼠标移动事件
} else {
// 存储第二个点
positions.pop();
positions.pop();
positions.pop();
var cartographic = Cesium.Cartographic.fromCartesian(cartesian);
var height = Cesium.Cartographic.fromCartesian(positions[0]).height;
// 得到辅助点
var verticalPoint = Cesium.Cartesian3.fromDegrees(Cesium.Math.toDegrees(cartographic.longitude), Cesium.Math.toDegrees(cartographic.latitude), height);
positions.push(verticalPoint);
positions.push(cartesian);
positions.push(positions[0]);
addPoint(cartesian);
// 移除所有注册的事件
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
// 注册鼠标移动事件
viewer.screenSpaceEventHandler.setInputAction(function (moveEvent) {
var movePosition = viewer.scene.pickPosition(moveEvent.endPosition); // 鼠标移动的点
if (positions.length >= 2) {
positions.pop();
positions.pop();
positions.pop();
var cartographic = Cesium.Cartographic.fromCartesian(movePosition);
var height = Cesium.Cartographic.fromCartesian(positions[0]).height;
// 辅助点
var verticalPoint = Cesium.Cartesian3.fromDegrees(Cesium.Math.toDegrees(cartographic.longitude), Cesium.Math.toDegrees(cartographic.latitude), height);
positions.push(verticalPoint);
positions.push(movePosition);
positions.push(positions[0]);
// 计算中点
var centerPoint_1 = Cesium.Cartesian3.midpoint(positions[0], positions[1], new Cesium.Cartesian3());
// 计算距离
var lengthText_1 = "水平距离:" + getLengthText(positions[0], positions[1]);
addLabel(centerPoint_1, lengthText_1);
// 计算中点
var centerPoint_2 = Cesium.Cartesian3.midpoint(positions[1], positions[2], new Cesium.Cartesian3());
// 计算距离
var lengthText_2 = "垂直距离:" + getLengthText(positions[1], positions[2]);
addLabel(centerPoint_2, lengthText_2);
// 计算中点
var centerPoint_3 = Cesium.Cartesian3.midpoint(positions[2], positions[3], new Cesium.Cartesian3());
// 计算距离
var lengthText_3 = "直线距离:" + getLengthText(positions[2], positions[3]);
addLabel(centerPoint_3, lengthText_3);
} else {
var verticalPoint = new Cesium.Cartesian3(movePosition.x, movePosition.y, positions[0].z);
positions.push(verticalPoint);
positions.push(movePosition);
positions.push(positions[0]);
// 绘制线
addLine(positions);
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
注意
当然,上面给出的代码只是思路性的代码,其中还有一些要注意的,比如Entity和Label的显示控制啊,Polyline、Polygon、以及Point的动态刷新实时绘制,还有所有entity的在viewer容器中的控制等等,需要进一步完善。
补充:本来这篇文章只是想给一个测量思路,由于太多订阅者联系我,让我提供一下源码,所以,在这里还是把代码放出来,当然,如果遇到版本不兼容或者有功能性错误的,可以联系我。
link==>