//地形开挖 class TerrainExcavation { constructor(viewer) { if (!viewer) throw new Error("no viewer object!"); this.viewer = viewer; } //计算并更新wellData prepareWell(activePoints) { let pointLength = activePoints.length; let heightDiff = this.excavateMinHeight - this.height; let no_height_top = [], bottom_pos = [], lerp_pos = []; for (let l = 0; l < pointLength; l++) { let u = l == pointLength - 1 ? 0 : l + 1; let point0 = [ Cesium.Cartographic.fromCartesian(activePoints[l]).longitude, Cesium.Cartographic.fromCartesian(activePoints[l]).latitude, ]; let point1 = [ Cesium.Cartographic.fromCartesian(activePoints[u]).longitude, Cesium.Cartographic.fromCartesian(activePoints[u]).latitude, ]; if (0 == l) { lerp_pos.push(new Cesium.Cartographic(point0[0], point0[1])); bottom_pos.push( Cesium.Cartesian3.fromRadians(point0[0], point0[1], heightDiff) ); no_height_top.push( Cesium.Cartesian3.fromRadians(point0[0], point0[1], 0) ); } for (let p = 1; p <= this.splitNum; p++) { let m = Cesium.Math.lerp(point0[0], point1[0], p / this.splitNum); let g = Cesium.Math.lerp(point0[1], point1[1], p / this.splitNum); (l == pointLength - 1 && p == this.splitNum) || (lerp_pos.push(new Cesium.Cartographic(m, g)), bottom_pos.push(Cesium.Cartesian3.fromRadians(m, g, heightDiff)), no_height_top.push(Cesium.Cartesian3.fromRadians(m, g, 0))); } } this.wellData = { lerp_pos: lerp_pos, bottom_pos: bottom_pos, no_height_top: no_height_top, }; } //开始创建底面和侧面 createWell(wallData) { let $this = this; if (this.viewer.terrainProvider._layers) { this.createBottomSurface(wallData.bottom_pos); let positions = Cesium.sampleTerrainMostDetailed( this.viewer.terrainProvider, wallData.lerp_pos ); positions.then(function(pos) { let positionList = []; for (let index = 0; index < pos.length; index++) { const element = pos[index]; let curPos = Cesium.Cartesian3.fromRadians( element.longitude, element.latitude, element.height ); positionList.push(curPos); } $this.createWellWall(wallData.bottom_pos, positionList); }); // Cesium.when(positions, function(pos) { // let positionList = []; // for (let index = 0; index < pos.length; index++) { // const element = pos[index]; // let curPos = Cesium.Cartesian3.fromRadians( // element.longitude, // element.latitude, // element.height // ); // positionList.push(curPos); // } // $this.createWellWall(wallData.bottom_pos, positionList); // }); } else { this.createBottomSurface(wallData.bottom_pos); this.createWellWall(wallData.bottom_pos, wallData.no_height_top); } } //坐标转换,转出经纬度格式 ellipsoidToDegree(pos) { let cartesian3 = new Cesium.Cartesian3(pos.x, pos.y, pos.z); let cartographic = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian3); return { longitude: Cesium.Math.toDegrees(cartographic.longitude), latitude: Cesium.Math.toDegrees(cartographic.latitude), altitude: cartographic.height, }; } //创建地形开挖的底面对象 createBottomSurface(points) { if (points.length) { let minHeight = this.getMinHeight(points); let positions = []; for (let i = 0; i < points.length; i++) { let curPoint = this.ellipsoidToDegree(points[i]); positions.push(curPoint.longitude, curPoint.latitude, minHeight); } let polygon = new Cesium.PolygonGeometry({ polygonHierarchy: new Cesium.PolygonHierarchy( Cesium.Cartesian3.fromDegreesArrayHeights(positions) ), perPositionHeight: true, }); let material = new Cesium.Material({ fabric: { type: "Image", uniforms: { image: this.bottomImg, }, }, }); let appearance = new Cesium.MaterialAppearance({ translucent: false, flat: true, material: material, }); this.bottomSurface = new Cesium.Primitive({ geometryInstances: new Cesium.GeometryInstance({ geometry: Cesium.PolygonGeometry.createGeometry(polygon), }), appearance: appearance, asynchronous: false, }); this.viewer.scene.primitives.add(this.bottomSurface); } } // 创建地形开挖的侧面墙对象 createWellWall(bottomPos, positionList) { let minHeight = this.getMinHeight(bottomPos); let maxHeights = [], minHeights = []; for (let i = 0; i < positionList.length; i++) { maxHeights.push(this.ellipsoidToDegree(positionList[i]).altitude); minHeights.push(minHeight); } let wall = new Cesium.WallGeometry({ positions: positionList, maximumHeights: maxHeights, minimumHeights: minHeights, }); let geometry = Cesium.WallGeometry.createGeometry(wall); let material = new Cesium.Material({ fabric: { type: "Image", uniforms: { image: this.wallImg, }, }, }); let appearance = new Cesium.MaterialAppearance({ translucent: false, flat: true, material: material, }); this.wellWall = new Cesium.Primitive({ geometryInstances: new Cesium.GeometryInstance({ geometry: geometry, attributes: { color: Cesium.ColorGeometryInstanceAttribute.fromColor( Cesium.Color.GREY ), }, id: "PitWall", }), appearance: appearance, asynchronous: false, }); this.viewer.scene.primitives.add(this.wellWall); } //获取地形开挖最低点高程值 getMinHeight(points) { let minHeight = 5000000; let minPoint = null; for (let i = 0; i < points.length; i++) { let height = points[i]["z"]; if (height < minHeight) { minHeight = height; minPoint = this.ellipsoidToDegree(points[i]); } } return minPoint.altitude; } switchExcavate(show) { if (show) { this.viewer.scene.globe.material = null; this.wellWall.show = true; this.bottomSurface.show = true; } else { this.viewer.scene.globe.material = null; this.wellWall.show = false; this.bottomSurface.show = false; } } updateExcavateDepth(height) { this.viewer.scene.primitives.remove(this.bottomSurface); this.viewer.scene.primitives.remove(this.wellWall); console.log(this.wellData, this.excavateMinHeight); let lerp_pos = this.wellData.lerp_pos; let posList = []; for (let n = 0; n < lerp_pos.length; n++) { posList.push( Cesium.Cartesian3.fromRadians( lerp_pos[n].longitude, lerp_pos[n].latitude, this.excavateMinHeight - height ) ); } this.wellData.bottom_pos = posList; this.createWell(this.wellData); } } Object.defineProperties(TerrainExcavation.prototype, { show: { get: function() { return this._show; }, set: function(e) { this._show = e; this.switchExcavate(e); }, }, height: { get: function() { return this._height; }, set: function(e) { this._height = e; this.updateExcavateDepth(e); }, }, }); /** * 通用对外公开函数 */ Object.assign(TerrainExcavation.prototype, /** @lends TerrainExcavation.prototype */ { /** * @param {Object} activePoints * @param {Object} options 具有以下属性: * @param {String} [options.id=guid] 服务ID(不支持全数字),加入到整体图层中 以便可以删除对应的图层 * @param {String} options.url 服务地址 * @param {Number} [options.maximumScreenSpaceError=16] 用于驱动细节细化级别的最大屏幕空间误差 * @return {String} 服务Id */ add(activePoints, options) { options = options || {}; this._height = options.excavateDepth || 10; this.bottomImg = options.bottomImg || "jt3dSDK/imgs/polygon/ground.png"; this.wallImg = options.wallImg || "jt3dSDK/imgs/polygon/ground.png"; this.splitNum = Cesium.defaultValue(options.splitNum, 50); activePoints = activePoints.map(point => { return Cesium.Cartesian3.fromDegrees(point[0], point[1], point[2] || 0); }); let viewer = this.viewer; this.clear(); let clippingPlanesList = []; let car3Difference = Cesium.Cartesian3.subtract( activePoints[0], activePoints[1], new Cesium.Cartesian3() ); //计算两个笛卡尔函数的分量差异 let boolDiff = car3Difference.x > 0; this.excavateMinHeight = 999999999; for (let index = 0; index < activePoints.length; ++index) { let s = (index + 1) % activePoints.length; let curMidPoint = Cesium.Cartesian3.midpoint( activePoints[index], activePoints[s], new Cesium.Cartesian3() ); let cartographic = Cesium.Cartographic.fromCartesian(activePoints[index]); let curHeight = viewer.scene.globe.getHeight(cartographic) || cartographic.height; console.log(curHeight); if (curHeight < this.excavateMinHeight) { this.excavateMinHeight = curHeight; } let curMidPointNormal = Cesium.Cartesian3.normalize( curMidPoint, new Cesium.Cartesian3() ); let curMidPointDifference = boolDiff ? Cesium.Cartesian3.subtract( activePoints[index], curMidPoint, new Cesium.Cartesian3() ) : Cesium.Cartesian3.subtract( activePoints[s], curMidPoint, new Cesium.Cartesian3() ); curMidPointDifference = Cesium.Cartesian3.normalize( curMidPointDifference, curMidPointDifference ); let curMidPointCross = Cesium.Cartesian3.cross( curMidPointDifference, curMidPointNormal, new Cesium.Cartesian3() ); curMidPointCross = Cesium.Cartesian3.normalize( curMidPointCross, curMidPointCross ); let plane = new Cesium.Plane(curMidPointCross, 0); let distance = Cesium.Plane.getPointDistance(plane, curMidPoint); clippingPlanesList.push( new Cesium.ClippingPlane(curMidPointCross, distance) ); } this.viewer.scene.globe.clippingPlanes = new Cesium.ClippingPlaneCollection({ planes: clippingPlanesList, edgeWidth: 1, edgeColor: Cesium.Color.WHITE, enabled: true, }); this.prepareWell(activePoints); this.createWell(this.wellData); }, /** * 清除开挖 */ clear() { if (this.viewer.scene.globe.clippingPlanes) { this.viewer.scene.globe.clippingPlanes.removeAll(); this.viewer.scene.primitives.remove(this.bottomSurface); this.viewer.scene.primitives.remove(this.wellWall); this.viewer.scene.render(); } } }); export default TerrainExcavation;