/** * @name: index * @author: Administrator * @date: 2023-11-20 17:54 * @description:index * @update: 2023-11-20 17:54 */ import { getHost } from "../../../../on"; import BaseSource from "../index"; import { regLeftClickCallback, regRightClickCallback, regMoveCallback } from "../../../../Global/ClickCallback"; import Controller from "../../../../Controller/index"; import { syncData } from '../../../../Global/MultiViewportMode' import { setSplitDirection, syncSplitData, setActiveId } from '../../../../Global/SplitScreen' class BaseTileset extends BaseSource { #updateModelTimeout; /** * @constructor * @param sdk * @description 模型 * @param options {object} * @param options.id{string} id * @param options.name{string} 名称 * @param options.url{string} 模型地址 * @param options.lng{number} 经度 * @param options.lat{number} 纬度 * @param options.height=0{number} 高度 * @param options.scale=1{number} 模型比例 * @param options.roll=0{number} 模型x旋转 * @param options.heading=0{number} 模型z轴旋转角度 * @param options.pitch=0{number} 模型y轴旋转角度 * */ constructor(sdk, options) { super(sdk, options); this.setDefaultValue() this.watchs = [] this.positionCallBack = null this.rotationCallback = null this.onClickCallback = null this._DialogObject = null this._element_style = null this.options.accuracy = options.accuracy ? Number(options.accuracy.toFixed(1)) : 1 this.options.position = this.options.position || {} this.oldData = { id: this.options.id, transparency: (this.options.transparency || this.options.transparency === 0) ? this.options.transparency : 1, name: this.options.name, accuracy: this.options.accuracy, url: this.options.url, height: this.options.position.alt || 0, lng: this.options.position.lng, lat: this.options.position.lat, scale: (this.options.scale || this.options.scale === 0) ? this.options.scale : 1, roll: this.options.roll || 0, heading: this.options.heading || 0, pitch: this.options.pitch || 0 } this.newData = { id: this.options.id, transparency: (this.options.transparency || this.options.transparency === 0) ? this.options.transparency : 1, name: this.options.name, accuracy: this.options.accuracy, url: this.options.url, height: this.options.position.alt || 0, lng: this.options.position.lng, lat: this.options.position.lat, scale: (this.options.scale || this.options.scale === 0) ? this.options.scale : 1, roll: this.options.roll || 0, heading: this.options.heading || 0, pitch: this.options.pitch || 0 } this.tileset = undefined this.editObj = new Controller(this.sdk) this.editObj.controllerCallBack = this.rotationEditingCallBack } loadSceneTree() { } async loadTileset(options) { let object = { ...options } let url = "" if (object.url.startsWith("http")) url = object.url else { //说明是本地的json,在磁盘中存在的 if (object.url.includes(":")) { url = object.url } else { if (this.options.host) { let o = new URL(object.url, this.options.host) url = o.href } else url = object.url } } let response = await fetch(url, { method: 'get', headers: { 'Content-Type': 'application/json', } }) if (response.status === 200) { this.tileset = await response.json() } let params = { show: this.options.show, skipLevelOfDetail: true, baseScreenSpaceError: 1024, maximumScreenSpaceError: 32, // 数值加大,能让最终成像变模糊 skipScreenSpaceErrorFactor: 16, skipLevels: 1, immediatelyLoadDesiredLevelOfDetail: false, loadSiblings: true, // 如果为true则不会在已加载完概况房屋后,自动从中心开始超清化房屋 cullWithChildrenBounds: true, cullRequestsWhileMoving: true, cullRequestsWhileMovingMultiplier: 10, // 值越小能够更快的剔除 preloadWhenHidden: false, preferLeaves: true, maximumCacheOverflowBytes: 128, // 内存分配变小有利于倾斜摄影数据回收,提升性能体验 progressiveResolutionHeightFraction: 0.5, // 数值偏于0能够让初始加载变得模糊 dynamicScreenSpaceErrorDensity: 0.1, // 数值加大,能让周边加载变快 dynamicScreenSpaceErrorFactor: 1, dynamicScreenSpaceError: true // 有了这个后,会在真正的全屏加载完之后才清晰化房屋 } let tileset if (Number(Cesium.VERSION.split('.')[1]) >= 107) { tileset = await Cesium.Cesium3DTileset.fromUrl(url, params); this.entity = tileset this.entity.imageBasedLighting.luminanceAtZenith = 0.1 } else { params.url = url tileset = new Cesium.Cesium3DTileset(params); this.entity = await tileset.readyPromise this.entity.imageBasedLighting.luminanceAtZenith = 0.1 } // syncData(this.sdk, this.options.id) await this.loadSceneTree(url) const initData = (tile) => { if (tile._contents) { for (let i = 0; i < tile._contents.length; i++) { initData(tile._contents[i]) } } else { for (let i = 0; i < tile.featuresLength; i++) { let feature = tile.getFeature(i) let file = feature.content.url let id = feature.getProperty('id') if (this.features.has(id)) { if (this.features.get(id).features) { if (this.features.get(id).features[file]) { // feature = this.features.get(id).features[feature.featureId] if (this.features.get(id).features[file].customColor) { feature.color = this.features.get(id).features[file].customColor feature.customColor = this.features.get(id).features[file].customColor } if (this.features.get(id).features[file].customAlpha) { let color = feature.color feature.color = Cesium.Color.fromCssColorString(`rgba(${Cesium.Color.floatToByte(color.red)},${Cesium.Color.floatToByte(color.green)},${Cesium.Color.floatToByte(color.blue)},${this.features.get(id).features[file].customAlpha})`) feature.customAlpha = this.features.get(id).features[file].customAlpha } if (this.features.get(id).features[file].customShow) { feature.show = this.features.get(id).features[file].customShow feature.customShow = this.features.get(id).features[file].customShow } } this.features.get(id).features[file] = feature } else { let object = {} if (this.features.get(id).customColor) { feature.color = this.features.get(id).customColor feature.customColor = this.features.get(id).customColor } if (this.features.get(id).customAlpha) { let color = feature.color feature.color = Cesium.Color.fromCssColorString(`rgba(${Cesium.Color.floatToByte(color.red)},${Cesium.Color.floatToByte(color.green)},${Cesium.Color.floatToByte(color.blue)},${this.features.get(id).customAlpha})`) feature.customAlpha = this.features.get(id).customAlpha } if (this.features.get(id).customShow) { feature.show = this.features.get(id).customShow feature.customShow = this.features.get(id).customShow } object[file] = feature this.features.get(id).features = object } } else { let object = {} object[file] = feature this.features.set(id, { features: object }) } if (!feature.customColor) { feature.customColor = Cesium.Color.fromCssColorString('#ffffff') } } } // for (let i = 0; i < tile._content.featuresLength; i++) { // let feature = tile._content.getFeature(i) // feature.show = false // } // if (tile._content._contents) { // for (let i = 0; i < tile._content._contents.length; i++) { // for (let m = 0; m < tile._content._contents[i].featuresLength; m++) { // let feature = tile._content._contents[i].getFeature(m) // feature.show = false // } // } // } } if (!this.sdk || !this.sdk.viewer || !this.sdk.viewer.scene) { return } tileset.tileLoad.addEventListener(tile => { // this.test() initData(tile._content) clearTimeout(this.#updateModelTimeout) this.#updateModelTimeout = setTimeout(() => { clearTimeout(this.#updateModelTimeout) let center = this.cartesian3Towgs84(tileset.boundingSphere.center, this.sdk.viewer) let circle = turf.circle([center.lng, center.lat], tileset.boundingSphere.radius / 1000, { steps: 360, units: 'kilometers' }); for (let [key, entity] of this.sdk.entityMap) { if (entity.type === 'BillboardObject' && entity.heightMode == 3) { let pt = turf.point([entity.lng, entity.lat]); if (turf.booleanPointInPolygon(pt, circle)) { entity.updateHeight() } } else { if (entity.label) { entity.label.show = entity.label.show } } } }, 500); // if (tile._content._contents) { // for (let i = 0; i < tile._content._contents.length; i++) { // for (let m = 0; m < tile._content._contents[i].featuresLength; m++) { // let feature = tile._content._contents[i].getFeature(m) // console.log(feature) // feature.show = false // } // } // } // for (let i = 0; i < tile._content.featuresLength; i++) { // let feature = tile._content.getFeature(i) // let file = feature.content.url // let id = feature.getProperty('id') // if (this.features.has(id)) { // if (this.features.get(id).features) { // if (this.features.get(id).features[file]) { // // feature = this.features.get(id).features[feature.featureId] // if (this.features.get(id).features[file].customColor) { // feature.color = this.features.get(id).features[file].customColor // feature.customColor = this.features.get(id).features[file].customColor // } // if (this.features.get(id).features[file].customAlpha) { // let color = feature.color // feature.color = Cesium.Color.fromCssColorString(`rgba(${Cesium.Color.floatToByte(color.red)},${Cesium.Color.floatToByte(color.green)},${Cesium.Color.floatToByte(color.blue)},${this.features.get(id).features[file].customAlpha})`) // feature.customAlpha = this.features.get(id).features[file].customAlpha // } // if (this.features.get(id).features[file].customShow) { // feature.show = this.features.get(id).features[file].customShow // feature.customShow = this.features.get(id).features[file].customShow // } // } // this.features.get(id).features[file] = feature // } // else { // let object = {} // object[file] = feature // this.features.get(id).features = object // } // } // else { // let object = {} // object[file] = feature // this.features.set(id, { features: object }) // } // if (!feature.customColor) { // feature.customColor = Cesium.Color.fromCssColorString('#ffffff') // } // } }) // // console.log(tileset) // if (this.type === 'bim') { // const setTilesetStyle = (f) => { // if (tileset.style) { // // tileset.style = new Cesium.Cesium3DTileStyle({ // // color: { // // conditions: [ // // ['${name} ==="对象074" ', 'color("red")'], //符合条件项 // // ['true', 'rgba(255,255,255,1)'] //其他项 // // ] // // } // // }) // // tileset.tileLoad.removeEventListener(setTilesetStyle) // } // console.log(f) // } // tileset.tileLoad.addEventListener(setTilesetStyle) // } this.entity._root.originalTransform = { ...this.entity._root.transform } this.entity.id = this.options.id || this.randomString() this.entity.type = this.type // this.editObj = new EditB3DM(this.sdk, this.entity) this.sdk.viewer.scene.primitives.add(tileset); if (this.options.position && JSON.stringify(this.options.position) != "{}" && (this.options.position.lng || this.options.position.lng === 0) && (this.options.position.lat || this.options.position.lat === 0)) { this.options.position.alt == this.options.position.alt || 0 let cartographic = Cesium.Cartographic.fromCartesian(this.entity.boundingSphere.center); if (this.tileset.root.transform) { cartographic = Cesium.Cartographic.fromCartesian({ x: this.tileset.root.transform[12], y: this.tileset.root.transform[13], z: this.tileset.root.transform[14] }) } this.entity.original = { lng: Cesium.Math.toDegrees(cartographic.longitude), // 经度 lat: Cesium.Math.toDegrees(cartographic.latitude), // 纬度 height: cartographic.height } let m = Cesium.Transforms.eastNorthUpToFixedFrame(new Cesium.Cartesian3.fromDegrees(this.options.position.lng, this.options.position.lat, this.options.position.alt)) const scale = Cesium.Matrix4.fromUniformScale(this.oldData.scale); if (this.tileset.root.transform) { Cesium.Matrix4.multiply(m, scale, this.entity._root.transform) } this.lng = this.oldData.lng this.lat = this.oldData.lat this.height = this.oldData.height } else { this.options.position = {} let cartographic = Cesium.Cartographic.fromCartesian(this.entity.boundingSphere.center); if (this.tileset.root.transform) { cartographic = Cesium.Cartographic.fromCartesian({ x: this.tileset.root.transform[12], y: this.tileset.root.transform[13], z: this.tileset.root.transform[14] }) } this.entity.original = { lng: Cesium.Math.toDegrees(cartographic.longitude), lat: this.oldData.lat = Cesium.Math.toDegrees(cartographic.latitude), height: cartographic.height, } this.lng = this.oldData.lng = Cesium.Math.toDegrees(cartographic.longitude); // 经度 this.lat = this.oldData.lat = Cesium.Math.toDegrees(cartographic.latitude); // 纬度 this.height = this.oldData.height = cartographic.height; // 高度 } this.scale = this.oldData.scale this.roll = this.oldData.roll this.heading = this.oldData.heading this.pitch = this.oldData.pitch this.transparency = this.oldData.transparency syncSplitData(this.sdk, this.options.id) regMoveCallback(this.entity.id, this.mouseMoveCB, this) // this.entity = this.sdk.viewer.scene.primitives.add(tileset); // if (this.options.position && JSON.stringify(this.options.position) != "{}") { // let m = Cesium.Transforms.eastNorthUpToFixedFrame(new Cesium.Cartesian3.fromDegrees(this.options.position.lng, this.options.position.lat, this.options.position.alt)) // const scale = Cesium.Matrix4.fromUniformScale(this.oldData.scale); // Cesium.Matrix4.multiply(m, scale, this.entity._root.transform) // } // else { // this.options.position = {} // } // this.lng = this.oldData.lng // this.lat = this.oldData.lat // this.height = this.oldData.height // this.scale = this.oldData.scale // this.roll = this.oldData.roll // this.heading = this.oldData.heading // this.pitch = this.oldData.pitch // this.transparency = this.oldData.transparency // regMoveCallback(this.entity.id, this.mouseMoveCB, this) // this.editObj = new EditB3DM(this.sdk, this.entity) // this.editObj.transformCallBack = this.rotationEditingCallBack // tileset.readyPromise.then(() => { // this.entity = this.sdk.viewer.scene.primitives.add(tileset); // }) // let x = this.sdk.viewer.scene.primitives.add(new Cesium.Cesium3DTileset({ // url: url // })); // setTimeout(() => { // console.log(x) // this.sdk.viewer.flyTo(this.entity) // }, 3000); } // test() { // let heightstyle = new Cesium.Cesium3DTileStyle({ // color: { // conditions: [ // ["Number(${height})>=300", "rgba(45,0,75,0.5)"], // ["Number(${height})>=200", "rgb(102,71,151)"], // ["Number(${height})>=100", "rgb(170,162,204)"], // ["Number(${height})>=50", "rgb(224,226,238)"], // ["Number(${height})>=25", "rgb(252,230, 200)"], // ["Number(${height})>=10", "rgb(248,176,87)"], // ["Number(${height})>=5", "rgb(198, 106,11)"], // ["isNaN(Number(${height}))", "rgb(255, 255, 255)"], // ["true", "rgb(127,59,8)"] // ] // } // }); // this.entity.style = heightstyle; // } remove() { super.remove() this.editObj.destroy() this.sdk.viewer.scene.primitives.remove(this.entity); this.entity = null if (this._DialogObject) { this._DialogObject.close() this._DialogObject = null } } flyTo() { super.flyTo() } on() { return this.loadTileset(this.options) } setDefaultValue() { super.setDefaultValue() this.options.host = this.options.host || getHost() this.options.url = this.options.url || "" } get position() { let cartographic = Cesium.Cartographic.fromCartesian(this.entity.boundingSphere.center); if (this.tileset.root.transform) { cartographic = Cesium.Cartographic.fromCartesian({ x: this.tileset.root.transform[12], y: this.tileset.root.transform[13], z: this.tileset.root.transform[14] }) } let lng = Cesium.Math.toDegrees(cartographic.longitude + 0.00000000663814); let lat = Cesium.Math.toDegrees(cartographic.latitude + 0.00000025137835); if (this.newData.lng && this.newData.lat && this.newData.height) { return { lng: this.newData.lng, lat: this.newData.lat, height: this.newData.height } } else { return { lng: lng, lat: lat, height: cartographic.height - 2.19104611043234 } } } set position(p) { } /** * @desc 打开模型旋转功能 * @param status {boolean} * @methodOf Source * */ set rotationEditing(status) { if (!this.tileset.root.transform) { if (window.ELEMENT) { window.ELEMENT.Message.closeAll(); window.ELEMENT.Message({ message: '该模型不支持移动和旋转!', type: 'warning', duration: 1500 }); } console.warn('该模型不支持移动和旋转!') return } if (status) { this.editObj.position = { lng: this.newData.lng, lat: this.newData.lat, alt: this.newData.height } this.editObj.update() this.editObj.editRtation() } else { this.editObj.destroy() } } /** * @desc 获取模型旋转状态 * @method rotationEditing * @return boolean * @methodOf Source * */ get rotationEditing() { if (this.editObj.getActiveState() === 'rtation') { return true } return false } /**@desc 打开平移模型功能 * * @memberOf Source *@param status {boolean} * * */ set positionEditing(status) { if (!this.sdk || !this.sdk.viewer || !this.entity) { return } if (!this.tileset.root.transform) { if (window.ELEMENT) { window.ELEMENT.Message.closeAll(); window.ELEMENT.Message({ message: '该模型不支持移动和旋转!', type: 'warning', duration: 1500 }); } console.warn('该模型不支持移动和旋转!') return } if (status) { this.editObj.position = { lng: this.newData.lng, lat: this.newData.lat, alt: this.newData.height } this.editObj.update() this.editObj.editTranslational() } else { this.editObj.destroy() } } get positionEditing() { if (this.editObj.getActiveState() === 'translational') { return true } return false } //平移时,坐标信息变化的回调 set positionEditingCallBack(callback) { return } get positionEditingCallBack() { } //旋转时,坐标信息变化的回调 set rotationEditingCallBack(callback) { this._rotationEditingCallBack = callback } get rotationEditingCallBack() { return (params, state) => { this.lng = params.position.lng this.lat = params.position.lat this.height = params.position.alt this.roll = params.rotate.x this.heading = params.rotate.y this.pitch = params.rotate.z // this._rotationEditingCallBack && this._rotationEditingCallBack(this.editObj._params) } } flicker() { } // 编辑框 async edit(state) { } get show() { return this.options.show } set show(v) { if (typeof v === "boolean") { this.options.show = v this.entity && (this.entity.show = v) if (this._DialogObject && this._DialogObject.showBtn) { this._DialogObject.showBtn.checked = v } if (this.options.label && this.options.label.show && this.label) { this.label.show = v } setTimeout(() => { let center = this.cartesian3Towgs84(this.entity.boundingSphere.center, this.sdk.viewer) let circle = turf.circle([center.lng, center.lat], this.entity.boundingSphere.radius / 1000, { steps: 360, units: 'kilometers' }); for (let [key, entity] of this.sdk.entityMap) { if (entity.type === 'BillboardObject' && entity.heightMode == 3) { let pt = turf.point([entity.lng, entity.lat]); if (turf.booleanPointInPolygon(pt, circle)) { entity.updateHeight() } } else { if (entity.label) { entity.label.show = entity.label.show } } } syncData(this.sdk, this.options.id) syncSplitData(this.sdk, this.options.id) }, 300); } else { console.error("参数必须为boolean") } } } export default BaseTileset