前言
本篇博客完全参考cesium-地面裁剪(多个剪切面)_cesium clippingplane-CSDN博客,感谢孙霸天大佬提供的实现方法。在此博客的基础上,本篇博客做了以下工作:
- 修复点位集合逆时针和顺时针导致不同的结果的问题
- 新增了挖出的实现方案
- 创建裁切面部分添加了大量注释
挖出
挖除
注: 仅支持凸多边形的裁剪。
代码
其实就是一个方法,接收两个参数:坐标点集合和裁剪类型。
坐标点集合数据示例:
const pointList = [
{
"x": 831378.7404354169,
"y": -4856690.379372356,
"z": 4036359.538261747
},
{
"x": 3334347.320785613,
"y": -4763032.687230717,
"z": 2613474.0729391705
},
{
"x": 133401.66014090632,
"y": -6152120.724266897,
"z": 1671946.9335355863
}
]
核心代码
import { viewer } from '@/utils/createCesium.js' // 引入地图对象
import * as Cesium from 'cesium'
/**
* Calculates the area clipping of a set of points.
*
* @param {Array} points - The points to calculate the area clipping for.
* @param {boolean} [type=false] - The type of area clipping: false:保留多边形外,挖除 ; true:保留多边形内,挖出
* @return {void} This function does not return a value.
*/
export function areaClipping(points, type = false) {
// 获取点坐标,计算
const pointsCoor = points.map(({ x, y, z }) => new Cesium.Cartesian3(x, y, z))
let sum = 0
for (let i = 0; i < pointsCoor.length; i++) {
const pointA = pointsCoor[i]
const pointB = pointsCoor[(i + 1) % pointsCoor.length]
const crossProduct = Cesium.Cartesian3.cross(pointA, pointB, new Cesium.Cartesian3()) // 计算pointA和pointB两个向量的叉乘
sum += crossProduct.z
}
if (sum > 0 && type) { // 逆时针
points.reverse()
} else if (sum < 0 && !type) { // 顺时针
points.reverse()
}
const clippingPlanes = [] // 存储ClippingPlane集合
for (let i = 0; i < points.length; ++i) {
const nextIndex = (i + 1) % points.length
// 计算两个坐标点的分量和,取中点。
const midpoint = Cesium.Cartesian3.add(points[i], points[nextIndex], new Cesium.Cartesian3())
Cesium.Cartesian3.multiplyByScalar(midpoint, 0.5, midpoint)
// up 是指从地球中心(原点)到 midpoint 的向量,即一个指向地球正上方的单位向量。
const up = Cesium.Cartesian3.normalize(midpoint, new Cesium.Cartesian3())
// 计算points[nextIndex]和midpoint的差值,得到一个表示从 points[nextIndex] 指向 midpoint 的向量
const right = Cesium.Cartesian3.subtract(points[nextIndex], midpoint, new Cesium.Cartesian3())
Cesium.Cartesian3.normalize(right, right) // 计算单位向量
// 通过叉乘及归一化得到单位法向量
const normal = Cesium.Cartesian3.cross(right, up, new Cesium.Cartesian3())
Cesium.Cartesian3.normalize(normal, normal) // 计算单位向量
const originCenteredPlane = new Cesium.Plane(normal, 0.0)
const distance = Cesium.Plane.getPointDistance(originCenteredPlane, midpoint) // 计算平面到中点的距离
// 最后,我们得到一个平面,这个平面垂直于地球表面
clippingPlanes.push(new Cesium.ClippingPlane(normal, distance))
}
// 为地球添加裁剪面
viewer.scene.globe.clippingPlanes = new Cesium.ClippingPlaneCollection({
planes: clippingPlanes,
enabled: true,
modelMatrix: Cesium.Matrix4.IDENTITY,
unionClippingRegions: type, // 内 || 外
edgeColor: Cesium.Color.YELLOW,
edgeWidth: 1.0
})
viewer.scene.globe.backFaceCulling = false
viewer.scene.globe.showSkirts = false
// viewer.scene.globe.clippingPlanes = null // 销毁
}
使用方法
import { areaClipping } from '@/utils/clippingToCanyon.js'
// 挖出
areaClipping(pointList, true)
// 挖除
areaClipping(pointList, false)