Files
sdk4.0_new/src/Obj/Base/BaseSource/BaseTileset/index.js

651 lines
23 KiB
JavaScript
Raw Normal View History

2025-09-01 16:17:11 +08:00
/**
* @name: index
* @author: Administrator
* @date: 2023-11-20 17:54
* @descriptionindex
* @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
}
async add() {
if (this.options.url) {
return this.loadTileset({
url: this.options.url
})
} else {
let res = await this.requestResource()
let text = await res.text()
text = JSON.parse(text)
if ([0, 200].includes(text.code)) {
if (text.data.url.length)
return this.loadTileset(text.data)
else
return new Promise((res, reject) => {
reject('资源不存在')
})
} else {
return new Promise((res, reject) => {
reject(text.msg || text.message)
})
}
}
}
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.add()
}
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