/* 引入Cesium */ // import * as Cesium from 'Cesium'; /** * 方量分析 * 过获取绘制的范围,获取面的坐标,对该面的坐标进行插值,将面等分为一个个的小三角面,求该三角面内定点的平均高度作为该三角面对应的高度。然后 体积 = 三角形面积 x 高度,然后对体积进行累加,即获取了体积。 * 填方体积为:当当前点的地形高度低于基准面高度时,用三角面的面积乘以基准面高度减去当前点的地形高度,然后体积求和。 * 挖方体积为:当当前点的地形高度高于基准面高度时,用三角面的面积乘以当前点的地形高度减去基准面高度,然后体积求和。 */ class CutFill { /** * 默认初始化 * @param {Object} viewer 三维场景 */ constructor(viewer) { if (!viewer) throw new Cesium.DeveloperError('no viewer object!'); this._viewer = viewer; this.delEntitys = []; this.maxHeigh = -1000000; //用来记录整块区域的最小高程 } /** * @ignore * @param {Object} options */ _VolumeAnalysis(options) { let _self = this; let cutArea = 0, cutVolume = 0, fillArea = 0, fillVolume = 0; const indices = options.geom.indices; //获取顶点索引数据 const positions = options.geom.attributes.position.values; for (let index = 0; index < indices.length; index += 3) { const pos0 = _self._returnPosition(positions, indices[index]); const pos1 = _self._returnPosition(positions, indices[index + 1]); const pos2 = _self._returnPosition(positions, indices[index + 2]); let _entities = _self._viewer.entities.add({ name: "三角面", polygon: { hierarchy: [pos0.heightPos, pos1.heightPos, pos2.heightPos], perPositionHeight: true, material: Cesium.Color.fromRandom(), extrudedHeight: options.height, outline: true, outlineColor: Cesium.Color.BLACK, }, }); _self.delEntitys.push(_entities); //水平状态下三角形面积 const area = _self._computeArea4Triangle( pos0.noHeightPos, pos1.noHeightPos, pos2.noHeightPos ); //计算三个点的均高 //计算三角体的平均高度 const height = (pos0.height + pos1.height + pos2.height) / 3; //判断是 填方还是挖方 //如果三角体低于基准面,则需要填方 if (height < options.height) { // 需要填方的部分 fillArea += area; const volume = area * (options.height - height); fillVolume += volume; } else { // 需要挖方的部分 cutArea += area; const volume = area * (height - options.height); cutVolume += volume; } } let allArea = cutArea + fillArea; allArea = allArea.toFixed(2); cutArea = cutArea.toFixed(2); cutVolume = cutVolume.toFixed(2); fillArea = fillArea.toFixed(2); fillVolume = fillVolume.toFixed(2); let result = { allArea, cutArea, cutVolume, fillArea, fillVolume, }; return result; } /** * 海伦公式求取三角形面积 * @ignore * @param {*} pos1 * @param {*} pos2 * @param {*} pos3 * @returns 三角形面积㎡ */ _computeArea4Triangle(pos1, pos2, pos3) { let a = Cesium.Cartesian3.distance(pos1, pos2); let b = Cesium.Cartesian3.distance(pos2, pos3); let c = Cesium.Cartesian3.distance(pos3, pos1); let S = (a + b + c) / 2; return Math.sqrt(S * (S - a) * (S - b) * (S - c)); } /** * @ignore * @param {Object} positions * @param {Object} index */ _returnPosition(positions, index) { let cartesian = new Cesium.Cartesian3( positions[index * 3], positions[index * 3 + 1], positions[index * 3 + 2] ); let cartographic = Cesium.Cartographic.fromCartesian(cartesian); let height = this._viewer.scene.sampleHeightSupported ? this._viewer.scene.sampleHeight(cartographic) : this._viewer.scene.globe.getHeight(cartographic); if (height > this.maxHeigh) { this.maxHeigh = height; } return { heightPos: Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, height), noHeightPos: Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, 0), height: height, }; } } /** * 通用对外公开函数 */ Object.assign(CutFill.prototype, /** @lends CutFill.prototype */ { /** * 方量分析 * @param {Object} points * @param {Object} options */ createPolygonGeo(points, options) { //异步函数 return new Promise((resolve, reject) => { let _self = this; options = options || {}; options.precision = Cesium.defaultValue(options.precision, 256); options.height = Cesium.defaultValue(options.height, 10); //移除 _self.remove(); /* 转换坐标 */ let positions = []; for (let i = 0; i < points.length; i++) { if (points[i] instanceof Cesium.Cartesian3) { positions.push(points[i]); } else { positions.push(Cesium.Cartesian3.fromDegrees(points[i][0], points[i][1], points[i][1] || 0)); } } //计算网格粒度-精度 let granularity = Math.PI / Math.pow(2, 11); granularity = granularity / options.precision; let polygonGeometry = new Cesium.PolygonGeometry.fromPositions({ positions: positions, vertexFormat: Cesium.PerInstanceColorAppearance.FLAT_VERTEX_FORMAT, granularity: granularity, }); options.geom = new Cesium.PolygonGeometry.createGeometry(polygonGeometry); let result = _self._VolumeAnalysis(options); //设置球体背景色 //设置地图basecolor为透明色 _self._viewer.scene.globe.baseColor = new Cesium.Color(1, 1, 1, 0.9); _self._viewer.scene.screenSpaceCameraController.enableCollisionDetection = false; //相机与地形的碰撞检测,允许相机进入地下 _self._viewer.scene.globe.translucency.enabled = true; //地球将被渲染为半透明的球体。 resolve(result); }); }, /** * 移除 */ remove() { /* 删除符合条件的所有实体 */ for (var i = 0; i < this.delEntitys.length; i++) { this._viewer.entities.remove(this.delEntitys[i]); } this._viewer.scene.screenSpaceCameraController.enableCollisionDetection = true; //相机与地形的碰撞检测,允许相机进入地下 this._viewer.scene.globe.translucency.enabled = false; //地球将被渲染为半透明的球体。 }, }); export default CutFill;