功能:测量两个经纬度之间的距离
核心类:Cesium.EllipsoidGeodesic
function transformWGS84ToCartographic(position) {
return position
? Cesium.Cartographic.fromDegrees(
position.lng || position.lon,
position.lat,
position.alt
)
: Cesium.Cartographic.ZERO;
}
function getPositionDistance(positions) {
/*
* positions:存储坐标点的数组
* distance:累加值,用来存储计算出的所有点之间的总距离
* transformWGS84ToCartographic:将 WGS84 坐标(经纬度高度)转换为 笛卡尔坐标系 下的 Cartographic 坐标
* Cesium.EllipsoidGeodesic:计算地球椭球表面两点之间的最短距离
* setEndPoints:将两个点设置为起点和终点,计算这两个点之间的地表距离
* geodesic.surfaceDistance:获取这两个点之间的表面距离,单位是米
* */
let distance = 0;
for (let i = 0; i < positions.length - 1; i++) {
let point1cartographic = transformWGS84ToCartographic(positions[i]);
let point2cartographic = transformWGS84ToCartographic(
positions[i + 1]
);
let geodesic = new Cesium.EllipsoidGeodesic();
geodesic.setEndPoints(point1cartographic, point2cartographic);
let s = geodesic.surfaceDistance;
//通过勾股定理解决高度差问题,获得三维空间中两点之间的实际直线距离
s = Math.sqrt(
Math.pow(s, 2) +
Math.pow(point2cartographic.height - point1cartographic.height, 2)
);
distance = distance + s;
}
//保留小数点后三位
return distance.toFixed(3);
}
实现测量功能:
通过鼠标左键来存储需要测量距离的坐标点,每两个坐标点之间连一条线,第二个坐标标明线的长度,鼠标右键取消测量功能
/*拾取位置点
* 从鼠标点击位置 (px) 对应的笛卡尔坐标 (Cartesian3),
* 并根据点击的位置判断该位置是在3D模型、地形或者地球表面上。
* 具体来说 先通过 drillPick 方法检测点击是否在3D模型或地形上,
* 再根据不同的情况进行坐标转换
* */
function getCatesian3FromPX(px) {
if (viewer && px) {
let picks = viewer.scene.drillPick(px);
let cartesian = null;
let isOn3dtiles = false,
isOnTerrain = false;
//处理3D模型或3D Tiles
for (let i in picks) {
let pick = picks[i];
if (
(pick && pick.primitive instanceof Cesium.Cesium3DTileFeature) ||
(pick && pick.primitive instanceof Cesium.Cesium3DTileset) ||
(pick && pick.primitive instanceof Cesium.Model)
) {
isOn3dtiles = true;
}
}
if (isOn3dtiles) {
viewer.scene.pick(px); // pick
cartesian = viewer.scene.pickPosition(px);
if (cartesian) {
let cartographic = Cesium.Cartographic.fromCartesian(cartesian);
if (cartographic.height < 0) cartographic.height = 0;
let lon = Cesium.Math.toDegrees(cartographic.longitude),
lat = Cesium.Math.toDegrees(cartographic.latitude),
height = cartographic.height;
cartesian = transformWGS84ToCartesian({
lng: lon,
lat: lat,
alt: height,
});
}
}
//处理地形
let boolTerrain = viewer.terrainProvider instanceof Cesium.EllipsoidTerrainProvider;
if (!isOn3dtiles && !boolTerrain) {
let ray = viewer.scene.camera.getPickRay(px);
if (!ray) return null;
cartesian = viewer.scene.globe.pick(ray, viewer.scene);
isOnTerrain = true;
}
//处理地球表面
if (!isOn3dtiles && !isOnTerrain && boolTerrain) {
cartesian = viewer.scene.camera.pickEllipsoid(px, viewer.scene.globe.ellipsoid);
}
//转换坐标
if (cartesian) {
let position = transformCartesianToWGS84(cartesian);
if (position.alt < 0) {
cartesian = transformWGS84ToCartesian(position, 0.1);
}
return cartesian;
}
return false;
}
}
let positions = [];
let lineEntity = new Cesium.Entity();
let handlers = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
//监听鼠标的左键单击事件,存储点击的坐标点
handlers.setInputAction(function (event){
let cartesian = getCatesian3FromPX(event.position);
if (cartesian && cartesian.x) {
if (positions.length == 0) {
positions.push(cartesian.clone());
}
// 添加量测信息点
addPoint(cartesian,cartesian.x,positions);
positions.push(cartesian);
}
},Cesium.ScreenSpaceEventType.LEFT_CLICK)
//鼠标移动事件:存入新的坐标
handlers.setInputAction(function (event){
let cartesian = getCatesian3FromPX(event.endPosition);
if (positions.length >= 2) {
if (cartesian && cartesian.x) {
positions.pop();
positions.push(cartesian);
}
}
},Cesium.ScreenSpaceEventType.MOUSE_MOVE)
handlers.setInputAction(function (event){
//结束鼠标监听事件
handlers.destroy();
handlers = null;
let cartesian = getCatesian3FromPX(event.position);
//添加点
addPoint(cartesian,cartesian.x,positions);
},Cesium.ScreenSpaceEventType.RIGHT_CLICK)
//添加线
lineEntity.polyline = {
width: 5,
material: Cesium.Color.BLUE.withAlpha(0.8),
clampToGround: false,
};
lineEntity.polyline.positions = new Cesium.CallbackProperty(function () {
return positions;
}, false);
viewer.entities.add(lineEntity)
/***
* 坐标数组转换 笛卡尔转86
*
* @param {Array} cartesianArr 三维位置坐标数组
*
* @return {Array} {lng,lat,alt} 地理坐标数组
*/
function transformCartesianArrayToWGS84Array(cartesianArr,viewer) {
if (viewer) {
return cartesianArr
? cartesianArr.map(function (item) {
return transformCartesianToWGS84(item,viewer);
})
: [];
}
}
/**
* 获取84坐标的距离
* @param {*} positions
*/
function getPositionDistance(positions) {
let distance = 0;
for (let i = 0; i < positions.length - 1; i++) {
let point1cartographic = transformWGS84ToCartographic(positions[i]);
let point2cartographic = transformWGS84ToCartographic(
positions[i + 1]
);
let geodesic = new Cesium.EllipsoidGeodesic();
geodesic.setEndPoints(point1cartographic, point2cartographic);
let s = geodesic.surfaceDistance;
s = Math.sqrt(
Math.pow(s, 2) +
Math.pow(point2cartographic.height - point1cartographic.height, 2)
);
distance = distance + s;
}
return distance.toFixed(3);
}
function addPoint(pos,id,positions){
//添加点的实体
let list = {
id:id,
name:'点',
show:true,
position:pos,
point:{
color:Cesium.Color.GREEN,
pixelSize:20,
outlineColor: Cesium.Color.SKYBLUE, //边框颜色
outlineWidth: 2, //边框宽度
},
label:{
text:
(
getPositionDistance(
transformCartesianArrayToWGS84Array(positions,data.viewer)
) / 1000
).toFixed(4) + "公里",
show: true,
showBackground: true,
font: "14px monospace",
horizontalOrigin: Cesium.HorizontalOrigin.LEFT,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
pixelOffset: new Cesium.Cartesian2(-10, -10)
}
}
let entity = data.viewer.entities.add(list)
pageResource.measuringDistanceList.floatModels.push(entity);
pageResource.measuringDistanceList.floatModelIds.push(list.id);
}