123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 |
- /* 引入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;
|