前言
本篇博客完全参考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 = 0for (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 = falseviewer.scene.globe.showSkirts = false// viewer.scene.globe.clippingPlanes = null // 销毁
}
使用方法
import { areaClipping } from '@/utils/clippingToCanyon.js'// 挖出
areaClipping(pointList, true)// 挖除
areaClipping(pointList, false)