2025-09-01 16:17:11 +08:00
/ * *
* @ 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 ( ) {
2025-09-08 17:27:42 +08:00
return this . loadTileset ( this . options )
2025-09-01 16:17:11 +08:00
}
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
}
/ * * @ d e s c 打 开 平 移 模 型 功 能
*
* @ 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