import Base from "../../Base/index"; import Dialog from '../../../BaseDialog' import { setActiveViewer, closeRotateAround, closeViewFollow } from '../../../Global/global' let FlatList = {} class Flat extends Base { /** * @constructor * @description 模型压平 * @param sdk * @param {Cesium.Cesium3DTileset} tileset 三维模型 * @param {Object} options * @param {string} attr.id id * @param {Cesium.Cartesian3[]} attr.positions 压平面坐标 */ constructor(sdk, tileset, options = {}, _Dialog = {}) { super(sdk) if (!tileset || !this.sdk || !this.sdk.viewer) return; this.options = { ...options } this.options.id = options.id || this.randomString() this.options.name = options.name || '压平面' this.options.positions = options.positions || [] this.options.show = (options.show || options.show === false) ? options.show : true this.tileset = tileset; this.Dialog = _Dialog if (!this.options.height && this.options.height !== 0) { let height = this.options.positions[0].alt for (let i = 0; i < this.options.positions.length; i++) { if (height > this.options.positions[i].alt) { height = this.options.positions[i].alt } } this.options.height = height } if (FlatList[this.tileset.id]) { FlatList[this.tileset.id].push({ ...this.options }) } else { FlatList[this.tileset.id] = [{ ...this.options }] } this.center = tileset.boundingSphere.center.clone(); this.center84 = this.cartesian3Towgs84(this.center, this.sdk.viewer) this.matrix = Cesium.Transforms.eastNorthUpToFixedFrame(this.center.clone()); this.localMatrix = Cesium.Matrix4.inverse(this.matrix, new Cesium.Matrix4()); // this.entity = { // id: this.options.id // } this.addFlat() // Flat.createPolygon(this) } get show() { return this.options.show } set show(v) { this.options.show = v for (let i = 0; i < FlatList[this.tileset.id].length; i++) { if (FlatList[this.tileset.id][i].id == this.options.id) { FlatList[this.tileset.id][i].show = v } } this.addFlat() } get height() { return this.options.height } set height(v) { this.options.height = Number(v) for (let i = 0; i < FlatList[this.tileset.id].length; i++) { if (FlatList[this.tileset.id][i].id == this.options.id) { FlatList[this.tileset.id][i].height = Number(v) } } this.addFlat() } get name() { return this.options.name } set name(v) { this.options.name = v for (let i = 0; i < FlatList[this.tileset.id].length; i++) { if (FlatList[this.tileset.id][i].id == this.options.id) { FlatList[this.tileset.id][i].name = v } } } addFlat() { let localPositionsArr = [] for (let i = 0; i < FlatList[this.tileset.id].length; i++) { let item = FlatList[this.tileset.id][i]; if (item.show) { const positions = item.positions; let height = item.height let fromDegreesArray = [] for (let i = 0; i < positions.length; i++) { fromDegreesArray.push(positions[i].lng, positions[i].lat) } FlatList[this.tileset.id][i].flatHeight = height - this.center84.alt let localCoor = this.cartesiansToLocal(Cesium.Cartesian3.fromDegreesArray(fromDegreesArray)); localPositionsArr.push(localCoor); } } const funstr = this.getIsinPolygonFun(localPositionsArr); let str = ``; for (let i = 0; i < localPositionsArr.length; i++) { const coors = localPositionsArr[i]; const n = coors.length; let instr = ``; coors.forEach((coordinate, index) => { instr += `points_${n}[${index}] = vec2(${coordinate[0]}, ${coordinate[1]});\n`; }) str += ` ${instr} if(isPointInPolygon_${n}(position2D)){ vec4 tileset_local_position_transformed = vec4(tileset_local_position.x, tileset_local_position.y, ground_z + ${FlatList[this.tileset.id][i].flatHeight}, 1.0); vec4 model_local_position_transformed = czm_inverseModel * u_tileset_localToWorldMatrix * tileset_local_position_transformed; vsOutput.positionMC.xy = model_local_position_transformed.xy; vsOutput.positionMC.z = model_local_position_transformed.z+ modelMC.z*0.002; return; }`; } this.updateShader(funstr, str); } // static createPolygon(that) { // let color = '#ffffff' // let linecolor = '#000000' // let positions = that.options.positions // let fromDegreesArray = [] // for (let i = 0; i < positions.length; i++) { // fromDegreesArray.push(positions[i].lng, positions[i].lat, that.options.height) // } // that.positions = Cesium.Cartesian3.fromDegreesArrayHeights(fromDegreesArray) // that.entity = that.sdk.viewer.entities.add({ // show: that.options.show, // id: that.options.id, // polyline: { // positions: [...that.positions, that.positions[0], that.positions[1]], // width: 2, // material: Cesium.Color.fromCssColorString(linecolor), // depthFailMaterial: new Cesium.PolylineDashMaterialProperty({ // color: Cesium.Color.YELLOW // }), // clampToGround: false, // zIndex: that.sdk._entityZIndex // }, // }) // that.sdk._entityZIndex++ // } remove() { FlatList[this.tileset.id] = FlatList[this.tileset.id].filter((attr) => { return attr.id != this.options.id; }) let localPositionsArr = []; for (let i = 0; i < FlatList[this.tileset.id].length; i++) { let item = FlatList[this.tileset.id][i]; if (item.show) { const positions = item.positions; let height = item.height let fromDegreesArray = [] for (let i = 0; i < positions.length; i++) { fromDegreesArray.push(positions[i].lng, positions[i].lat) } FlatList[this.tileset.id][i].flatHeight = height - this.center84.alt let localCoor = this.cartesiansToLocal(Cesium.Cartesian3.fromDegreesArray(fromDegreesArray)); localPositionsArr.push(localCoor); } } const funstr = this.getIsinPolygonFun(localPositionsArr); let str = ``; for (let i = 0; i < localPositionsArr.length; i++) { const coors = localPositionsArr[i]; const n = coors.length; let instr = ``; coors.forEach((coordinate, index) => { instr += `points_${n}[${index}] = vec2(${coordinate[0]}, ${coordinate[1]});\n`; }) str += ` ${instr} if(isPointInPolygon_${n}(position2D)){ vec4 tileset_local_position_transformed = vec4(tileset_local_position.x, tileset_local_position.y, ground_z + ${FlatList[this.tileset.id][i].flatHeight}, 1.0); vec4 model_local_position_transformed = czm_inverseModel * u_tileset_localToWorldMatrix * tileset_local_position_transformed; vsOutput.positionMC.xy = model_local_position_transformed.xy; vsOutput.positionMC.z = model_local_position_transformed.z+ modelMC.z*0.002; return; }`; } this.updateShader(funstr, str); } // 根据数组长度,构建 判断点是否在面内 的压平函数 getIsinPolygonFun(polygons) { let pmap = polygons.map((polygon) => polygon.length); let uniqueArray = this.getUniqueArray(pmap); let str = ``; uniqueArray.forEach(length => { str += ` vec2 points_${length}[${length}]; bool isPointInPolygon_${length}(vec2 point){ int nCross = 0; // 交点数 const int n = ${length}; for(int i = 0; i < n; i++){ vec2 p1 = points_${length}[i]; vec2 p2 = points_${length}[int(mod(float(i+1),float(n)))]; if(p1[1] == p2[1]){ continue; } if(point[1] < min(p1[1], p2[1])){ continue; } if(point[1] >= max(p1[1], p2[1])){ continue; } float x = p1[0] + ((point[1] - p1[1]) * (p2[0] - p1[0])) / (p2[1] - p1[1]); if(x > point[0]){ nCross++; } } return int(mod(float(nCross), float(2))) == 1; } ` }) return str } updateShader(vtx1, vtx2) { let flatCustomShader = new Cesium.CustomShader({ uniforms: { u_tileset_localToWorldMatrix: { type: Cesium.UniformType.MAT4, value: this.matrix, }, u_tileset_worldToLocalMatrix: { type: Cesium.UniformType.MAT4, value: this.localMatrix, }, u_flatHeight: { type: Cesium.UniformType.FLOAT, value: this.flatHeight, }, }, vertexShaderText: ` // 所有isPointInPolygon函数 ${vtx1} void vertexMain(VertexInput vsInput, inout czm_modelVertexOutput vsOutput){ vec3 modelMC = vsInput.attributes.positionMC; vec4 model_local_position = vec4(modelMC.x, modelMC.y, modelMC.z, 1.0); vec4 tileset_local_position = u_tileset_worldToLocalMatrix * czm_model * model_local_position; vec2 position2D = vec2(tileset_local_position.x,tileset_local_position.y); float ground_z = 0.0; // 多个多边形区域 ${vtx2} }`, }); this.tileset.customShader = flatCustomShader; this.sdk.viewer.scene.requestRender(); } // 数组去重,不能处理嵌套的数组 getUniqueArray = (arr) => { return arr.filter(function (item, index, arr) { //当前元素,在原始数组中的第一个索引==当前索引值,否则返回当前元素 return arr.indexOf(item, 0) === index; }); } // 世界坐标转数组局部坐标 cartesiansToLocal(positions) { let arr = []; for (let i = 0; i < positions.length; i++) { let position = positions[i]; let localp = Cesium.Matrix4.multiplyByPoint( this.localMatrix, position.clone(), new Cesium.Cartesian3() ) arr.push([localp.x, localp.y]); } return arr; } /** * 飞到 */ async flyTo() { setActiveViewer(0) closeRotateAround(this.sdk) closeViewFollow(this.sdk) if (this.options.customView && this.options.customView.relativePosition && this.options.customView.orientation) { let orientation = { heading: Cesium.Math.toRadians(this.options.customView.orientation.heading || 0.0), pitch: Cesium.Math.toRadians(this.options.customView.orientation.pitch || -60.0), roll: Cesium.Math.toRadians(this.options.customView.orientation.roll || 0.0) } let lng = this.options.customView.relativePosition.lng let lat = this.options.customView.relativePosition.lat let alt = this.options.customView.relativePosition.alt let destination = Cesium.Cartesian3.fromDegrees(lng, lat, alt) let position = { lng: 0, lat: 0 } if (this.options.position) { position = { ...this.options.position } } else if (this.options.positions) { position = { ...this.options.positions[0] } } else if (this.options.line && this.options.line.positions) { position = { ...this.options.line.positions[0] } } else if (this.options.center) { position = { ...this.options.center } } else if (this.options.start) { position = { ...this.options.start } } else { if (this.options.hasOwnProperty('lng')) { position.lng = this.options.lng } if (this.options.hasOwnProperty('lat')) { position.lat = this.options.lat } if (this.options.hasOwnProperty('alt')) { position.alt = this.options.alt } } // 如果没有高度值,则获取紧贴高度计算 if (!position.hasOwnProperty('alt')) { position.alt = await this.getClampToHeight(position) } lng = this.options.customView.relativePosition.lng + position.lng lat = this.options.customView.relativePosition.lat + position.lat alt = this.options.customView.relativePosition.alt + position.alt destination = Cesium.Cartesian3.fromDegrees(lng, lat, alt) this.sdk.viewer.camera.flyTo({ destination: destination, orientation: orientation }) } else { let positionArray = [] for (let i = 0; i < this.options.positions.length; i++) { let a = Cesium.Cartesian3.fromDegrees(this.options.positions[i].lng, this.options.positions[i].lat, this.center84.alt) positionArray.push(a.x, a.y, a.z) } let BoundingSphere = Cesium.BoundingSphere.fromVertices(positionArray) this.sdk.viewer.camera.flyToBoundingSphere(BoundingSphere, { offset: { heading: Cesium.Math.toRadians(0.0), pitch: Cesium.Math.toRadians(-90.0), roll: Cesium.Math.toRadians(0.0) } }) } } async edit(state) { if (state) { this.originalOptions = this.deepCopyObj(this.options) // this._DialogObject = await new Dialog(this.sdk.viewer._container, { // title: '压平面属性', left: '180px', top: '100px', // removeCallBack: () => { // this.Dialog.removeCallBack && this.Dialog.removeCallBack() // }, // closeCallBack: () => { // this.reset() // this.Dialog.closeCallBack && this.Dialog.closeCallBack() // } // }) // await this._DialogObject.init() // 内容部分 // let contentElm = document.createElement('div'); // contentElm.innerHTML = ` // //