之前做系统需要很多图上量算的功能,由于cesium没有提供相关接口,我自己实现了,准备和大家分享(也参考了很多别人的代码,十分感谢)。因为我做的是capacitor移动端,发现点击只有Cesium.ScreenSpaceEventType.LEFT_DOWN可以用,我就放了一个按钮用来停止。一共有6个图上测量功能,这篇文章先分享坐标测量和高度测量的代码。希望大家点点关注,可以多多交流!
坐标测量
// 坐标测量类
import * as Cesium from "cesium";
export default class MeasureCoordinates {
constructor(viewer) {
this.viewer = viewer;
this.initEvents();
this.positions = [];
this.vertexEntities = [];
this.labelEntities = [];
this.isMeasure = false;
}
// 初始化鼠标事件
initEvents() {
if (!this.handler_coor) {
this.handler_coor = new Cesium.ScreenSpaceEventHandler(
this.viewer.scene.canvas
);
}
this.MeasureEndEvent = new Cesium.Event(); // 结束事件
}
// 激活测量工具
activate() {
this.deactivate(); // 确保没有重复的事件监听
this.registerEvents();
this.positions = [];
this.vertexEntities = [];
this.labelEntities = [];
this.isMeasure = true;
}
registerEvents() {
// 注册鼠标点击事件
this.handler_coor.setInputAction((event) => {
const position = this.viewer.scene.pickPosition(event.position);
if (Cesium.defined(position)) {
this.positions.push(position);
this.createVertex(position);
this.createLabel(position, this.getCoordinatesText(position));
}
}, Cesium.ScreenSpaceEventType.LEFT_DOWN);
// 注册鼠标右键事件
// this.handler_coor.setInputAction(() => {
// if (this.positions.length > 0) {
// this.displayCoordinates();
// }
// this.deactivate();
// }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
}
// 停止测量工具
deactivate() {
if (!this.isMeasure) return;
this.unRegisterEvents();
this.handler_coor = null;
this.isMeasure = false;
}
// 清空所有实体和标签
clear() {
this.vertexEntities.forEach((entity) =>
this.viewer.entities.remove(entity)
);
this.labelEntities.forEach((entity) => this.viewer.entities.remove(entity));
this.positions = [];
this.vertexEntities = [];
this.labelEntities = [];
}
// 创建点实体
createVertex(position) {
const vertexEntity = this.viewer.entities.add({
position: position,
point: {
pixelSize: 8,
color: Cesium.Color.RED,
},
});
this.vertexEntities.push(vertexEntity);
}
// 创建标签
createLabel(position, text) {
const labelEntity = this.viewer.entities.add({
position: position,
label: {
text: text,
font: "25px sans-serif",
fillColor: Cesium.Color.WHITE,
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
outlineColor: Cesium.Color.BLACK,
outlineWidth: 2,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
pixelOffset: new Cesium.Cartesian2(0, -20),
disableDepthTestDistance: Number.POSITIVE_INFINITY,
},
});
this.labelEntities.push(labelEntity);
}
// 获取坐标信息文本
getCoordinatesText(position) {
const cartographic = Cesium.Cartographic.fromCartesian(position);
const lon = Cesium.Math.toDegrees(cartographic.longitude).toFixed(6);
const lat = Cesium.Math.toDegrees(cartographic.latitude).toFixed(6);
const height = cartographic.height.toFixed(2);
return `经度: ${lon}, 纬度: ${lat}, 高度: ${height}m`;
}
// 显示所有坐标信息
displayCoordinates() {
const coordinates = this.positions.map((position, index) => {
const cartographic = Cesium.Cartographic.fromCartesian(position);
const lon = Cesium.Math.toDegrees(cartographic.longitude).toFixed(6);
const lat = Cesium.Math.toDegrees(cartographic.latitude).toFixed(6);
const height = cartographic.height.toFixed(2);
return `点${index + 1}: 经度: ${lon}, 纬度: ${lat}, 高度: ${height}m`;
});
console.log("测量的坐标信息:");
coordinates.forEach((coord) => console.log(coord));
alert(coordinates.join("\n"));
}
//测量结束
measureEnd() {
this.deactivate();
this.MeasureEndEvent.raiseEvent(this.measureDistance); //触发结束事件 传入结果
}
endMeasure() {
if (this.isMeasure) {
this.displayCoordinates();
this.measureEnd();
}
}
//解除鼠标事件
unRegisterEvents() {
this.handler_coor.removeInputAction(
Cesium.ScreenSpaceEventType.RIGHT_CLICK
);
this.handler_coor.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOWN);
this.handler_coor.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
}
}
高度差测量
//高度测量类
import * as Cesium from "cesium";
export default class MeasureHeight {
constructor(viewer) {
this.viewer = viewer;
this.initEvents();
this.positions = [];
this.vertexEntities = [];
this.labelEntity = undefined;
this.measureHeight = 0; //测量结果
this.circleRadius = 1; // 默认圆半径固定为1米
}
//初始化事件
initEvents() {
if (!this.handler_hei) {
this.handler_hei = new Cesium.ScreenSpaceEventHandler(
this.viewer.scene.canvas
);
}
this.MeasureStartEvent = new Cesium.Event(); //开始事件
this.MeasureEndEvent = new Cesium.Event(); //结束事件
}
//激活
activate() {
this.deactivate();
this.registerEvents(); //注册鼠标事件
//设置鼠标状态
this.viewer.enableCursorStyle = false;
this.viewer._element.style.cursor = "default";
this.isMeasure = true;
this.circleRadius = 0.1;
this.measureHeight = 0;
this.positions = [];
}
//禁用
deactivate() {
if (!this.isMeasure) return;
this.unRegisterEvents();
this.handler_hei = null;
this.viewer._element.style.cursor = "pointer";
this.viewer.enableCursorStyle = true;
this.isMeasure = false;
}
//清空绘制
clear() {
//清除线对象
this.viewer.entities.remove(this.lineEntity);
this.lineEntity = undefined;
//清除文本
this.viewer.entities.remove(this.labelEntity);
this.labelEntity = undefined;
//移除圆
this.removeCircleEntity();
//清除节点
this.vertexEntities.forEach((item) => {
this.viewer.entities.remove(item);
});
this.vertexEntities = [];
}
//创建线对象
createLineEntity() {
this.lineEntity = this.viewer.entities.add({
polyline: {
positions: new Cesium.CallbackProperty((e) => {
return this.positions;
}, false),
width: 2,
material: Cesium.Color.YELLOW,
depthFailMaterial: new Cesium.PolylineDashMaterialProperty({
color: Cesium.Color.RED,
}),
},
});
}
//创建结果文本标签
createLabel() {
this.labelEntity = this.viewer.entities.add({
position: new Cesium.CallbackProperty((e) => {
return this.positions[this.positions.length - 1]; //返回最后一个点
}, false),
label: {
text: "",
scale: 0.5,
font: "normal 40px MicroSoft YaHei",
distanceDisplayCondition: new Cesium.DistanceDisplayCondition(
0,
50000000000
),
scaleByDistance: new Cesium.NearFarScalar(500, 1.5, 1500, 1.5),
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
pixelOffset: new Cesium.Cartesian2(0, -30),
outlineWidth: 9,
outlineColor: Cesium.Color.WHITE,
disableDepthTestDistance: Number.POSITIVE_INFINITY,
},
});
}
//创建线节点
createVertex(index) {
let vertexEntity = this.viewer.entities.add({
position: new Cesium.CallbackProperty((e) => {
return this.positions[index];
}, false),
type: "MeasureHeightVertex",
point: {
color: Cesium.Color.FUCHSIA,
pixelSize: 6,
// disableDepthTestDistance: 2000,
},
});
this.vertexEntities.push(vertexEntity);
}
positionHeight(cartesian) {
if (!cartesian) {
return 0; // 默认高度
}
const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
return cartographic.height; // 返回高度值
}
//创建圆 这样方便看出水平面的高低
createCircleEntitiy() {
this.circleEntity = this.viewer.entities.add({
position: new Cesium.CallbackProperty((e) => {
return this.positions[this.positions.length - 1]; //返回最后一个点
}, false),
ellipse: {
height: new Cesium.CallbackProperty((e) => {
return this.positionHeight(this.positions[this.positions.length - 1]);
}, false),
semiMinorAxis: 5, // 固定半径为5米
semiMajorAxis: 5, // 固定半径为5米
material: Cesium.Color.BLUE.withAlpha(0.6), // 设置颜色为蓝色并调整透明度
},
});
}
//删除圆
removeCircleEntity() {
this.viewer.entities.remove(this.circleEntity);
this.circleEntity = undefined;
}
//注册鼠标事件
registerEvents() {
this.leftClickEvent();
this.rightClickEvent();
this.mouseMoveEvent();
}
//左键点击事件
leftClickEvent() {
//单击鼠标左键画点点击事件
this.handler_hei.setInputAction((e) => {
this.viewer._element.style.cursor = "default";
let position = this.viewer.scene.pickPosition(e.position);
if (!position) {
const ellipsoid = this.viewer.scene.globe.ellipsoid;
position = this.viewer.scene.camera.pickEllipsoid(
e.position,
ellipsoid
);
}
if (!position) return;
if (this.positions.length == 0) {
//首次点击
this.positions.push(position);
this.createVertex(0);
this.createLineEntity();
this.createCircleEntitiy();
this.createLabel();
} else {
//第二次点击结束测量
//添加更多点
this.positions.push(position);
this.createVertex(this.positions.length - 1);
}
}, Cesium.ScreenSpaceEventType.LEFT_DOWN);
}
//鼠标移动事件
mouseMoveEvent() {
this.handler_hei.setInputAction((e) => {
if (!this.isMeasure) return;
this.viewer._element.style.cursor = "default";
let position = this.viewer.scene.pickPosition(e.endPosition);
if (!position) {
position = this.viewer.scene.camera.pickEllipsoid(
e.startPosition,
this.viewer.scene.globe.ellipsoid
);
}
if (!position) return;
this.handleMoveEvent(position);
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
}
cartesian3Point3(position) {
const c = Cesium.Cartographic.fromCartesian(position);
const lon = Cesium.Math.toDegrees(c.longitude);
const lat = Cesium.Math.toDegrees(c.latitude);
return [lon, lat, c.height];
}
//处理鼠标移动
handleMoveEvent(position) {
if (this.positions.length < 1) return;
let firstPoint = this.cartesian3Point3(this.positions[0]); //第一个点
let movePoint = this.cartesian3Point3(position); //鼠标移动点
const h = movePoint[2] - firstPoint[2];
firstPoint[2] = movePoint[2];
const twoPosition = Cesium.Cartesian3.fromDegrees(
firstPoint[0],
firstPoint[1],
movePoint[2]
);
if (this.positions.length < 2) {
this.positions.push(twoPosition);
this.createVertex(1);
} else {
this.positions[1] = twoPosition;
this.measureHeight = h.toFixed(3);
this.labelEntity.label.text = "高度:" + this.measureHeight + " 米";
}
//计算圆的半径
this.circleRadius = this.getDistanceH(this.positions[0], position);
}
cartesian3ToPoint3D(cartesian) {
if (!cartesian) {
return null;
}
const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
const longitude = Cesium.Math.toDegrees(cartographic.longitude); // 经度
const latitude = Cesium.Math.toDegrees(cartographic.latitude); // 纬度
const height = cartographic.height; // 高度
return {
lon: longitude,
lat: latitude,
alt: height,
};
}
// 获取半径
getDistanceH(p1, p2) {
if (!p1 || !p2) return 2;
let distance = Cesium.Cartesian3.distance(p1, p2);
let p2Car = this.cartesian3ToPoint3D(p2);
let radius = Math.sqrt(
Math.abs(Math.pow(distance, 2) - Math.pow(p2Car.alt, 2))
);
return radius;
}
//右键事件
rightClickEvent() {
this.handler_hei.setInputAction((e) => {
if (this.isMeasure) {
this.deactivate();
this.clear();
}
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
}
//测量结束
measureEnd() {
this.deactivate();
this.MeasureEndEvent.raiseEvent(this.measureHeight); //触发结束事件 传入结果
}
endMeasure() {
this.measureEnd();
}
//解除鼠标事件
unRegisterEvents() {
this.handler_hei.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK);
this.handler_hei.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOWN);
this.handler_hei.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
}
}