参考
Cesium地形开挖-附带源码 - 掘金 (juejin.cn)
说明
代码直接用的上述链接中的,我只做了一些小改动:
原代码支持拖拽边界点后更新开挖范围,但是在拖拽时会带着球一起动,会造成拖拽不起作用,所以我在
LEFT_DOWN
和LEFT_UP
这两个鼠标事件中分别对地图拖拽旋转功能设置了开关在
stop()
方法中添加了清除所有 entity 和鼠标事件的方法,写得比较简略,一次性全清了,各位可以根据自己的需求去调整清理原作者墙体和底部的材质简单用了颜色,我从网上选了张泥土材质的图片替换掉了原本的贴图(贴图我放在文章下面),看上去舒服点儿,getAssetsFile 这个方法只是用来获取图片 Url 的方法,各位可以根据自己的项目情况采用合适的引入方式
clippingPlaneCollection()
方法中另外添加了一行代码this.viewer.scene.globe.depthTestAgainstTerrain = true;
这是开启深度检测的,否则最终开挖出来的效果看上去在球上飘
目前功能还有些不足,后期待有时间逐步完善:
连续开挖多个会有问题
不能开挖凹多边形
完整代码
class TerrainCutting {
constructor(viewer) {
this.viewer = viewer; //场景
//注册区域挖掘
this.clippingPlanesArray = []; //裁剪区域数组
this.clippingPoint = []; //点位
this.temporayrPolygonEntity = null; //多边形对象
this.clippingWallEntities = null;//挖掘墙体
this.clippingBootomWallEntities = null; //挖掘墙体底部区域
this.cesiumEvent = null; //鼠标事件
this.activeClickPick = null; //当前点击的覆盖物
this.infoWindowElement = null;//信息窗体Dom
this.preRenderEvent = null;//窗口更新事件
this.clippingDeepValue = 200;//定义挖掘深度
this.cesiumEventState = ""; //鼠标按压状态
}
//开始挖掘
create() {
//开始之前清除数据
this.cesiumEvent = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
this.cesiumEvent.setInputAction((event) => {
//更新鼠标状态
this.cesiumEventState = "leftClick";
//当前点击覆盖物
this.activeClickPick = this.viewer.scene.pick(event.position);
//点击空白区域重新绘制
if (!this.activeClickPick || !this.activeClickPick.id) {
//恢复地形开挖状态
if (this.clippingWallEntities) {
this.destroy();
}
//绘制地形开挖边界
this.saveClippingPlaneCollectionData(event);
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
//鼠标按下事件
this.cesiumEvent.setInputAction((event) => {
//更新鼠标状态
this.cesiumEventState = "leftDown";
//当前点击覆盖物
this.activeClickPick = this.viewer.scene.pick(event.position);
if (this.clippingWallEntities) {
if (this.activeClickPick && this.activeClickPick.id) {
//选中点击位置
this.selectClickPoint();
}
}
}, Cesium.ScreenSpaceEventType.LEFT_DOWN);
//鼠标抬起事件
this.cesiumEvent.setInputAction((event) => {
//更新鼠标状态
this.cesiumEventState = "leftUp";
this.viewer.scene.screenSpaceCameraController.enableRotate = true;
}, Cesium.ScreenSpaceEventType.LEFT_UP);
//鼠标移动事件
this.cesiumEvent.setInputAction((event) => {
if (this.activeClickPick && this.activeClickPick.id) {
//判断鼠标是否为按压状态
if (this.cesiumEventState == "leftDown") {
this.viewer.scene.screenSpaceCameraController.enableRotate = false;
this.changeLayerPointPostion(event);
}
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
this.cesiumEvent.setInputAction((event) => {
//更新鼠标状态
this.cesiumEventState = "rightClick";
this.clippingPlaneCollection();
this.cesiumEvent.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
// this.cesiumEvent.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
this.cesiumEvent.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK);
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
}
//停止挖掘
//解绑事件,销毁挖掘图层,用于在其他操作之前,关闭挖掘功能
stop() {
this.viewer.scene.screenSpaceCameraController.enableRotate = true;
this.cesiumEvent.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK)
this.cesiumEvent.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE)
this.cesiumEvent.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK)
this.cesiumEvent.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_UP)
this.cesiumEvent.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOWN)
this.viewer.entities.removeAll();
this.clippingWallEntities = null;
this.clippingBootomWallEntities = null;
this.clippingPlanesArray = null;
this.clippingPoint = null;
this.viewer.scene.globe.clippingPlanes = new Cesium.ClippingPlaneCollection({
planes: [],
edgeWidth: 0
});
}
//销毁挖掘图层,不解绑事件,用于重新绘制
destroy() {
}
//保存鼠标点击获取到的挖掘区域,并且根据坐标绘制出开挖区域
//保存区域挖掘数据
saveClippingPlaneCollectionData(event) {
var cartesian = this.viewer.camera.pickEllipsoid(event.position, this.viewer.scene.globe.ellipsoid);
this.clippingPlanesArray.push(cartesian);
//绘制点
var clippingPoint = this.viewer.entities.add({
name: "定位点",
position: cartesian,
point: {
color: Cesium.Color.SKYBLUE,
pixelSize: 10,
outlineColor: Cesium.Color.YELLOW,
outlineWidth: 3,
disableDepthTestDistance: Number.POSITIVE_INFINITY,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
}
});
this.clippingPoint.push(clippingPoint);
//绘制开挖区域
if (!this.temporayrPolygonEntity) {
this.temporayrPolygonEntity = this.viewer.entities.add({
polygon: {
hierarchy: new Cesium.CallbackProperty(() => {
return new Cesium.PolygonHierarchy(this.clippingPlanesArray);
}, false),
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
material: Cesium.Color.RED.withAlpha(0.5)
}
});
}
}
//实现挖掘功能,用于挖掘区域的创建和更新
//开始挖掘
clippingPlaneCollection() {
//开始挖掘之前移除已经挖掘过的区域
if (this.clippingWallEntities) {
this.viewer.entities.remove(this.clippingWallEntities);
this.clippingWallEntities = null;
}
if (this.clippingBootomWallEntities) {
this.viewer.entities.remove(this.clippingBootomWallEntities);
this.clippingBootomWallEntities = null;
}
this.viewer.scene.globe.clippingPlanes = new Cesium.ClippingPlaneCollection({
planes: [],
edgeWidth: 0
});
var points = this.clippingPlanesArray;
var pointsLength = points.length;
var clippingPlanes = [];
for (var i = 0; i < pointsLength; ++i) {
var nextIndex = (i + 1) % pointsLength;
var midpoint = Cesium.Cartesian3.add(points[i], points[nextIndex], new Cesium.Cartesian3());
midpoint = Cesium.Cartesian3.multiplyByScalar(midpoint, 0.5, midpoint);
var up = Cesium.Cartesian3.normalize(midpoint, new Cesium.Cartesian3());
var right = Cesium.Cartesian3.subtract(points[nextIndex], midpoint, new Cesium.Cartesian3());
right = Cesium.Cartesian3.normalize(right, right);
var normal = Cesium.Cartesian3.cross(right, up, new Cesium.Cartesian3());
normal = Cesium.Cartesian3.normalize(normal, normal);
var originCenteredPlane = new Cesium.Plane(normal, 0.0);
var distance = Cesium.Plane.getPointDistance(originCenteredPlane, midpoint);
clippingPlanes.push(new Cesium.ClippingPlane(normal, distance));
}
this.viewer.scene.globe.clippingPlanes = new Cesium.ClippingPlaneCollection({
planes: clippingPlanes,
edgeWidth: 1
});
this.viewer.scene.globe.depthTestAgainstTerrain = true;
// 侧边墙体
this.clippingWallEntities = this.viewer.entities.add({
corridor: {
positions: [
...this.clippingPlanesArray,
this.clippingPlanesArray[0],
this.clippingPlanesArray[1]
],
height: this.clippingDeepValue * -1,
extrudedHeight: 0,
width: 1,
cornerType: Cesium.CornerType.ROUNDED,
material: new Cesium.ImageMaterialProperty({
image: getAssetsFile('img/ExcavationAnalysis/wallMaterial.png'),
repeat: new Cesium.Cartesian2(1000, 1000),
}),
outline: false
},
});
//底部墙体
this.clippingBootomWallEntities = this.viewer.entities.add({
polygon: {
hierarchy: this.clippingPlanesArray,
height: this.clippingDeepValue * -1,
extrudedHeight: this.clippingDeepValue * -1 + 1,
material: new Cesium.ImageMaterialProperty({
image: getAssetsFile('img/ExcavationAnalysis/wallMaterial.png'),
repeat: new Cesium.Cartesian2(1, 1),
}),
},
});
}
//修改定位点选中状态
selectClickPoint() {
if (this.activeClickPick.id.name == "定位点") {
for (var i = 0; i < this.clippingPoint.length; i++) {
this.clippingPoint[i].point.color = Cesium.Color.SKYBLUE;
}
this.activeClickPick.id.point.color = Cesium.Color.RED;
}
}
//修改选中点的位置,更新矩形边框位置
changeLayerPointPostion(event) {
var cartesian = this.viewer.camera.pickEllipsoid(event.endPosition, this.viewer.scene.globe.ellipsoid);
this.activeClickPick.id.position = cartesian;
//根据ID得到修改的index
var activeIndex = -1;
for (var i = 0; i < this.clippingPoint.length; i++) {
if (this.activeClickPick.id._id == this.clippingPoint[i]._id) {
activeIndex = i;
}
}
this.clippingPlanesArray[activeIndex] = cartesian;
//修改挖掘区域
if (this.clippingWallEntities) {
this.clippingPlaneCollection();
}
}
}
评论区