前言
在Cesium中,可使用Entity绘制一些图形,包括点、线、圆形、长方形、不规则图形等,从而满足我们在实际开发中的需要,比如绘制电子围栏。
一、绘制点
原理:监听鼠标点击事件,在点击后的坐标出添加点位Entity
initEventHandlers() {
this.handler = new Cesium.ScreenSpaceEventHandler(
this.viewer?.scene.canvas,
);
// 左键点击添加点
this.handler.setInputAction((event: any) => {
if (!this.isDrawing) return;
// 使用pick函数获取点击位置的实际位置
const cartesian = this.viewer?.scene.pickPosition(event.position);
if (Cesium.defined(cartesian)) {
// 将笛卡尔坐标转换为经纬度坐标
const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
const longitude = Cesium.Math.toDegrees(cartographic.longitude);
const latitude = Cesium.Math.toDegrees(cartographic.latitude);
const height = cartographic.height;
const position = Cesium.Cartesian3.fromDegrees(
longitude,
latitude,
height,
);
this.addPosition(position);
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
// 右键点击结束绘制
this.handler.setInputAction(() => {
if (this.isDrawing) {
this.finishDrawing();
}
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
}
addPosition(position: any) {
const entity = new Cesium.Entity({
position,
point: {
color: Cesium.Color.RED,
pixelSize: 5,
},
});
this.viewer?.entities.add(entity);
this.drawnPoints.push(entity);
}
二、绘制线
原理:监听鼠标的点击事件,将鼠标点击位置的坐标进行保存,通过保存的所有点位绘制出路线Entity
/**
* 初始化鼠标事件处理器
*/
initEventHandlers() {
this.handler = new Cesium.ScreenSpaceEventHandler(
this.viewer?.scene.canvas,
);
// 左键点击添加点
this.handler.setInputAction((event: any) => {
if (!this.isDrawing) return;
// 使用pick函数获取点击位置的实际位置
const cartesian = this.viewer?.scene.pickPosition(event.position);
if (Cesium.defined(cartesian)) {
// 将笛卡尔坐标转换为经纬度坐标
const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
const longitude = Cesium.Math.toDegrees(cartographic.longitude);
const latitude = Cesium.Math.toDegrees(cartographic.latitude);
const height = cartographic.height;
const position = Cesium.Cartesian3.fromDegrees(
longitude,
latitude,
height,
);
this.lastPoint = position;
if (this.currentLine) {
// 增加点位
this.currentLine.addPoint(position);
}
}
}, Cesium.ScreenSpaceEventType.LEFT_DOWN);
// 右键点击结束绘制
this.handler.setInputAction(() => {
if (this.isDrawing) {
this.finishDrawing();
}
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
/**
* 开始绘制(对外暴露的API)
*/
startDrawing() {
// 重置当前绘制状态,保留历史绘制结果
this.currentLine = new LineObject();
const lineInstance = this.createLineInstance();
// 将路线添加到地图上
this.viewer?.entities.add(lineInstance as Cesium.Entity);
}
// 创建路线
createLineInstance() {
this.key = `line-${dayjs().valueOf()}`;
this.lineInstance = new Cesium.Entity({
id: this.key,
name: '画线',
polyline: {
// 使用CallbackProperty允许我们在用户点击时动态更新线段的位置
positions: new Cesium.CallbackProperty(() => {
return this.polylinePoints;
}, false),
width: 2,
material: Cesium.Color.RED,
},
});
}
三、绘制圆
原理:监听鼠标左键的点击事件,将点击的坐标确定为圆的圆心坐标;监测鼠标的移动事件,将鼠标移动的距离确定圆的半径。根据圆心坐标和半径绘制圆
/**
* 初始化鼠标事件处理器
*/
initEventHandlers() {
this.handler = new Cesium.ScreenSpaceEventHandler(
this.viewer?.scene.canvas,
);
// 左键点击添加点
this.handler.setInputAction((event: any) => {
if (!this.isDrawing) return;
// 使用pick函数获取点击位置的实际位置
const cartesian = this.viewer?.scene.pickPosition(event.position);
if (Cesium.defined(cartesian)) {
// 将笛卡尔坐标转换为经纬度坐标
const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
const longitude = Cesium.Math.toDegrees(cartographic.longitude);
const latitude = Cesium.Math.toDegrees(cartographic.latitude);
const height = cartographic.height;
const position = Cesium.Cartesian3.fromDegrees(
longitude,
latitude,
height,
);
if (this.currentCircle) {
// 设置当前圆的圆心
this.currentCircle.resetCenterPoint(position);
}
}
}, Cesium.ScreenSpaceEventType.LEFT_DOWN);
// 右键点击结束绘制
this.handler.setInputAction(() => {
if (this.isDrawing) {
this.finishDrawing();
}
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
// 鼠标移动更新预览线/面
this.handler.setInputAction((event: any) => {
if (!this.isDrawing) return;
// 使用pick函数获取点击位置的实际位置
const cartesian = this.viewer?.scene.pickPosition(event.endPosition);
if (Cesium.defined(cartesian)) {
// 将笛卡尔坐标转换为经纬度坐标
const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
const longitude = Cesium.Math.toDegrees(cartographic.longitude);
const latitude = Cesium.Math.toDegrees(cartographic.latitude);
const height = cartographic.height;
const position = Cesium.Cartesian3.fromDegrees(
longitude,
latitude,
height,
);
if (this.currentCircle?.centerPoint) {
const distance = Cesium.Cartesian3.distance(
this.currentCircle?.centerPoint,
position,
);
this.currentCircle.resetRadius(distance);
}
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
}
/**
* 开始绘制(对外暴露的API)
*/
startDrawing() {
// 重置当前绘制状态,保留历史绘制结果
this.isDrawing = true;
this.currentCircle = new CircleObject();
this.currentCircle.createCircleInstance();
this.viewer?.entities.add(
this.currentCircle.circleInstance as Cesium.Entity,
);
}
// CircleObject类内,创建圆Entity
createCircleInstance() {
this.key = `circle-${dayjs().valueOf()}`;
this.circleInstance = new Cesium.Entity({
id: this.key,
name: '画圆',
ellipse: {
semiMinorAxis: new Cesium.CallbackProperty(() => {
return this.currentRadius;
}, false),
semiMajorAxis: new Cesium.CallbackProperty(() => {
return this.currentRadius;
}, false),
material: Cesium.Color.BLUE.withAlpha(0.2),
outline: true,
outlineColor: Cesium.Color.RED,
outlineWidth: 2,
fill: true, // 为true时只显示轮廓线
},
});
}
四、绘制矩形
原理:监听鼠标左侧点击事件,确定矩形的一个点坐标;监听鼠标移动事件,监听移动结束后的鼠标的点的坐标,来确定矩形的另一个点坐标;通过两个点坐标作为矩形的一对对焦来绘制矩形。
/**
* 初始化鼠标事件处理器
*/
initEventHandlers() {
this.handler = new Cesium.ScreenSpaceEventHandler(
this.viewer?.scene.canvas,
);
// 左键点击添加点
this.handler.setInputAction((event: any) => {
if (!this.isDrawing) return;
// 使用pick函数获取点击位置的实际位置
const cartesian = this.viewer?.scene.pickPosition(event.position);
if (Cesium.defined(cartesian)) {
// 将笛卡尔坐标转换为经纬度坐标
const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
const longitude = Cesium.Math.toDegrees(cartographic.longitude);
const latitude = Cesium.Math.toDegrees(cartographic.latitude);
if (this.currentRect) {
// 设置矩形左上角点
this.currentRect.resetTopLeftPoint(longitude, latitude);
}
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
// 右键点击结束绘制
this.handler.setInputAction(() => {
if (this.isDrawing) {
this.finishDrawing();
}
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
// 鼠标移动更新预览线/面
this.handler.setInputAction((event: any) => {
if (!this.isDrawing) return;
// 使用pick函数获取点击位置的实际位置
const cartesian = this.viewer?.scene.pickPosition(event.endPosition);
if (Cesium.defined(cartesian)) {
// 将笛卡尔坐标转换为经纬度坐标
const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
const longitude = Cesium.Math.toDegrees(cartographic.longitude);
const latitude = Cesium.Math.toDegrees(cartographic.latitude);
if (this.currentRect && this.currentRect.startLat) {
this.currentRect.resetBottomRightPoint(longitude, latitude);
}
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
}
/**
* 开始绘制(对外暴露的API)
*/
startDrawing() {
// 重置当前绘制状态,保留历史绘制结果
this.isDrawing = true;
this.currentRect = new RectObject();
this.currentRect.createRectInstance();
this.viewer?.entities.add(this.currentRect.rectInstance as Cesium.Entity);
}
// RectObject中创建矩形对象
createRectInstance() {
this.key = `circle-${dayjs().valueOf()}`;
this.rectInstance = new Cesium.Entity({
id: this.key,
name: '画矩形',
rectangle: {
coordinates: new Cesium.CallbackProperty(() => {
if (
!this.startLng ||
!this.startLat ||
!this.endLng ||
!this.endLat
) {
return;
}
// 西
const west = Math.min(this.startLng, this.endLng);
// 东
const east = Math.max(this.startLng, this.endLng);
// 南
const south = Math.min(this.startLat, this.endLat);
// 北
const north = Math.max(this.startLat, this.endLat);
return Cesium.Rectangle.fromDegrees(west, south, east, north);
}, false),
material: Cesium.Color.BLUE.withAlpha(0.2),
outline: true,
outlineColor: Cesium.Color.RED,
outlineWidth: 2,
fill: true, // 为true时只显示轮廓线
},
});
}
五、绘制不规则图形
原理:监听鼠标的左侧点击事件,将点击的坐标进行保存;通过点击的坐标的数据,绘制一个不规则图形。
/**
* 初始化鼠标事件处理器
*/
initEventHandlers() {
this.handler = new Cesium.ScreenSpaceEventHandler(
this.viewer?.scene.canvas,
);
// 左键点击添加点
this.handler.setInputAction((event: any) => {
if (!this.isDrawing) return;
// 使用pick函数获取点击位置的实际位置
const cartesian = this.viewer?.scene.pickPosition(event.position);
if (Cesium.defined(cartesian)) {
// 将笛卡尔坐标转换为经纬度坐标
const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
const longitude = Cesium.Math.toDegrees(cartographic.longitude);
const latitude = Cesium.Math.toDegrees(cartographic.latitude);
const height = cartographic.height;
const position = Cesium.Cartesian3.fromDegrees(
longitude,
latitude,
height,
);
if (this.currentPolygon) {
this.currentPolygon.resetPointHeight(height);
this.currentPolygon.addPoint(position);
if (this.currentPolygon.polygonPoints.length === 1) {
this.currentPolygon.addPoint(position.clone());
}
}
}
}, Cesium.ScreenSpaceEventType.LEFT_DOWN);
// 右键点击结束绘制
this.handler.setInputAction(() => {
if (this.isDrawing) {
this.finishDrawing();
if (
this.currentPolygon &&
this.currentPolygon.polygonPoints.length > 0
) {
const position = this.currentPolygon.polygonPoints[0];
this.currentPolygon.addPoint(position);
}
}
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
}
/**
* 开始绘制(对外暴露的API)
*/
startDrawing() {
// 重置当前绘制状态,保留历史绘制结果
this.isDrawing = true;
this.currentPolygon = new PolygonObject();
this.currentPolygon.createPoygonInstance();
this.viewer?.entities.add(
this.currentPolygon.polygonInstance as Cesium.Entity,
);
}
// 创建不规则图形对象
createPoygonInstance() {
this.key = `polygon-${dayjs().valueOf()}`;
this.polygonInstance = new Cesium.Entity({
id: this.key,
name: '画多边形',
polygon: {
hierarchy: new Cesium.CallbackProperty(() => {
return new Cesium.PolygonHierarchy(this.polygonPoints);
}, false),
material: Cesium.Color.BLUE.withAlpha(0.2),
perPositionHeight: false, // true:不贴地/false:贴地
outline: true,
outlineColor: Cesium.Color.CYAN,
outlineWidth: 2,
height: undefined,
extrudedHeight: undefined,
},
});
}