This commit is contained in:
zh
2025-09-01 16:17:11 +08:00
parent d802602200
commit 6fa99df21c
1035 changed files with 377083 additions and 1 deletions

View File

@ -0,0 +1,93 @@
function html() {
return `
<span class="custom-divider"></span>
<div class="div-item">
<div class="row">
<div class="col">
<span class="label">名称</span>
<input class="input" @model="name">
</div>
<div class="col">
</div>
</div>
</div>
<span class="custom-divider"></span>
<div class="div-item">
<div class="row">
<div class="col">
<span class="label">经度</span>
<input class="input" type="number" title="" min="-180" max="180" @model="lng">
</div>
<div class="col">
<span class="label">x轴</span>
<input type="number" title="" min="-180" max="180" @model="roll">
</div>
</div>
<div class="row">
<div class="col">
<span class="label">纬度</span>
<input class="input" type="number" title="" min="-90" max="90" @model="lat">
</div>
<div class="col">
<span class="label">y轴</span>
<input type="number" title="" min="-180" max="180" @model="heading">
</div>
</div>
<div class="row">
<div class="col">
<span class="label">高度</span>
<div class="input-number input-number-unit-1">
<input class="input" type="number" title="" min="-9999999" max="999999999" @model="height">
<span class="unit">m</span>
<span class="arrow"></span>
</div>
</div>
<div class="col">
<span class="label">z轴</span>
<input type="number" title="" min="-180" max="180" @model="pitch">
</div>
</div>
<div class="row">
<div class="col">
<span class="label">大小</span>
<input type="range" max="10" min="0.1" step="0.1" @model="scale">
<div class="input-number" style="width: 100px;margin-left: 10px;">
<input type="number" title="" min="0" max="10" step="0.1" @model="scale">
<span class="arrow"></span>
</div>
</div>
</div>
</div>
<div class="divide">
<div class="line"></div>
<p>BIM属性导出选项</p>
<div class="line"></div>
</div>
<div class="row">
<div style="display: flex;">
<div class="checkbox-box" @click="exportState">
<input type="checkbox" value="3">
<span>修建中</span>
</div>
<div class="checkbox-box" @click="exportState">
<input type="checkbox" value="2">
<span>未完成</span>
</div>
<div class="checkbox-box" @click="exportState">
<input type="checkbox" value="1">
<span>已完成</span>
</div>
</div>
<div class="col">
<button @click="exportProperty">导 出</button>
</div>
</div>
<span class="custom-divider"></span>
`
}
export { html }

View File

@ -0,0 +1,82 @@
function html2() {
return `
<div class="row">
<div class="col">
<span class="label">构件名称</span>
<input class="input" name="name" disabled="disabled">
</div>
</div>
<div class="row">
<div class="col">
<span class="label">选择状态</span>
<select class="input input-select" name="state-select">
<option value="0" style="color: #000;">重置</option>
<option value="1" style="color: #f00;">已完成</option>
<option value="2" style="color: #0f0;">未完成</option>
<option value="3" style="color: #00f;">修建中</option>
</select>
</div>
</div>
<div class="divide">
<div class="line"></div>
<p>自定义属性</p>
<div class="line"></div>
</div>
<div class="property">
</div>
`
}
function css2() {
return `
.YJ-custom-base-dialog>.content {
width: 440px;
}
.YJ-custom-base-dialog>.content .row .label {
flex: 0 0 110px;
}
.col:first-child {
margin-right: 10px;
}
.col:last-child {
margin-left: 10px;
}
.YJ-custom-base-dialog>.content .divide {
position: relative;
display: flex;
align-items: center;
margin: 20px 0;
}
.YJ-custom-base-dialog>.content .divide .line{
height: 1px;
background: #ddd;
flex: 1;
}
.YJ-custom-base-dialog>.content .divide p{
margin: 0 10px;
}
.YJ-custom-base-dialog>.content .property .property-item .btn{
font-size: 24px;
line-height: 20px;
padding: 2px 0;
}
.YJ-custom-base-dialog>.content .property .property-item .input_lable {
flex: 0 0 115px;
border: none;
margin-right: 15px;
text-align: right;
}
.YJ-custom-base-dialog>.content .property .property-item:first-child .delete{
display: none
}
.YJ-custom-base-dialog>.content .property .property-item .add{
display: none;
}
.YJ-custom-base-dialog>.content .property .property-item:last-child .add{
display: inline-block;
}
`
}
export { html2, css2 }

View File

@ -0,0 +1,877 @@
/**
* @name: index
* @author: Administrator
* @date: 2023-11-20 16:05
* @descriptionindex
* @update: 2023-11-20 16:05
*/
import BaseTileset from "../index";
import { html } from "./_element";
import { html2, css2 } from "./_element2";
import Dialog from '../../../../Element/Dialog';
import EventBinding from '../../../../Element/Dialog/eventBinding';
import BaseDialog from '../../../../../BaseDialog'
import { syncData } from '../../../../../Global/MultiViewportMode'
import { syncSplitData } from '../../../../../Global/SplitScreen'
import { setActiveViewer, closeRotateAround, closeViewFollow} from '../../../../../Global/global'
class BIM extends BaseTileset {
#updateModelTimeout
/**
* @constructor
* @description 加载BIM模型
* @param sdk {object} sdk
* @param options {object} 模型参数
* @param options.id {string} 对象id
* @param options.show=true {boolean} 模型显隐
* @param options.name {string} 名称
* @param options.url {string} 资源地址
* @param options.position {object} 模型位置
* @param options.position.lng {number} 经度
* @param options.position.lat {number} 纬度
* @param options.position.alt {number} 高度
* */
constructor(sdk, options = {}, _Dialog = {}) {
super(sdk, options)
this.picking = false
this.features = options.features || []
this.exportStateArray = []
this.Dialog = _Dialog
this._elms = {};
this._EventBinding = new EventBinding()
this.Dialog.exportState = (e) => {
this.exportState(e)
}
this.Dialog.exportProperty = (e) => {
this.exportProperty(this.exportStateArray)
}
this.features = new Map()
}
get type() {
return "bim"
}
get name() {
return this.newData.name
}
set name(v) {
this.newData.name = v
this._elms.name && this._elms.name.forEach((item) => {
item.value = v
})
}
get lng() {
return this.newData.lng
}
set lng(v) {
this.newData.lng = v
this.updateModel(this.newData.lng, this.newData.lat, this.newData.height, this.newData.roll, this.newData.heading, this.newData.pitch, this.newData.scale)
this._elms.lng && this._elms.lng.forEach((item) => {
item.value = v
})
}
get lat() {
return this.newData.lat
}
set lat(v) {
this.newData.lat = v
this.updateModel(this.newData.lng, this.newData.lat, this.newData.height, this.newData.roll, this.newData.heading, this.newData.pitch, this.newData.scale)
this._elms.lat && this._elms.lat.forEach((item) => {
item.value = v
})
}
get height() {
return this.newData.height
}
set height(v) {
this.newData.height = v
this.updateModel(this.newData.lng, this.newData.lat, this.newData.height, this.newData.roll, this.newData.heading, this.newData.pitch, this.newData.scale)
this._elms.height && this._elms.height.forEach((item) => {
item.value = v
})
}
get roll() {
return this.newData.roll
}
set roll(v) {
this.newData.roll = v
this.updateModel(this.newData.lng, this.newData.lat, this.newData.height, this.newData.roll, this.newData.heading, this.newData.pitch, this.newData.scale)
this._elms.roll && this._elms.roll.forEach((item) => {
item.value = v
})
}
get heading() {
return this.newData.heading
}
set heading(v) {
this.newData.heading = v
this.updateModel(this.newData.lng, this.newData.lat, this.newData.height, this.newData.roll, this.newData.heading, this.newData.pitch, this.newData.scale)
this._elms.heading && this._elms.heading.forEach((item) => {
item.value = v
})
}
get pitch() {
return this.newData.pitch
}
set pitch(v) {
this.newData.pitch = v
this.updateModel(this.newData.lng, this.newData.lat, this.newData.height, this.newData.roll, this.newData.heading, this.newData.pitch, this.newData.scale)
this._elms.pitch && this._elms.pitch.forEach((item) => {
item.value = v
})
}
get scale() {
return this.newData.scale
}
set scale(v) {
this.newData.scale = v
this.updateModel(this.newData.lng, this.newData.lat, this.newData.height, this.newData.roll, this.newData.heading, this.newData.pitch, this.newData.scale)
this._elms.scale && this._elms.scale.forEach((item) => {
item.value = v
})
}
// get transparency() {
// return this.newData.transparency
// }
// set transparency(v) {
// this.newData.transparency = v
// this.entity.style = new Cesium.Cesium3DTileStyle({
// color: "color('rgba(255,255,255," + this.newData.transparency + ")')",
// show: true,
// });
// this.entity.transparency = Number(this.newData.transparency)
// this._elms.transparency && this._elms.transparency.forEach((item) => {
// item.value = v
// })
// }
async loadSceneTree(url) {
// Cesium.ExperimentalFeatures.enableModelExperimental = true;
let array = url.split('/')
array[array.length - 1] = 'scenetree.json'
await Cesium.Resource.fetchJson({
url: array.join('/')
}).then(res => {
this.scenetree = res
const initData = (array) => {
array.forEach(item => {
if (this.features.has(item.id)) {
this.features.get(item.id).sphere = item.sphere
}
else {
this.features.set(item.id, { sphere: item.sphere })
}
if (item.children) {
initData(item.children)
}
})
}
initData(res.scenes[0].children)
// res.scenes[0].children.forEach(item => {
// if (this.features.has(item.id)) {
// this.features.get(item.id).sphere = item.sphere
// }
// else {
// this.features.set(item.id, {sphere: item.sphere})
// }
// })
})
}
// 编辑框
async edit(state) {
let _this = this
this.originalOptions = this.deepCopyObj(this.options)
if (this._DialogObject && this._DialogObject.close) {
this._DialogObject.close()
this._DialogObject = null
}
if (state) {
this._DialogObject = await new Dialog(this.sdk, this.newData, {
title: 'BIM模型属性', left: '180px', top: '100px',
resetCallBack: () => {
this.reset()
this.Dialog.resetCallBack && this.Dialog.resetCallBack()
},
confirmCallBack: (info) => {
this.name = this.name.trim()
if (!this.name) {
this.name = '未命名对象'
}
this.oldData.name = this.newData.name
this.oldData.height = this.newData.height
this.oldData.lng = this.newData.lng
this.oldData.lat = this.newData.lat
// this.oldData.transparency = this.newData.transparency
this.oldData.scale = this.newData.scale
this.oldData.roll = this.newData.roll
this.oldData.heading = this.newData.heading
this.oldData.pitch = this.newData.pitch
this._DialogObject.close()
let features = new Map()
this.features.forEach((item, key) => {
let data = { ...item }
delete data.features
features.set(key, data)
})
this.Dialog.confirmCallBack && this.Dialog.confirmCallBack({ ...this.oldData, features: features, type: this.type })
syncSplitData(this.sdk, this.oldData.id)
},
removeCallBack: () => {
this.Dialog.removeCallBack && this.Dialog.removeCallBack()
},
closeCallBack: () => {
this.reset()
// this.newData.transparency = this.oldData.transparency
// this.newData.name = this.oldData.name
// this.newData.height = this.oldData.height
// this.newData.lng = this.oldData.lng
// this.newData.lat = this.oldData.lat
// this.newData.scale = this.oldData.scale
// this.entity.style = new Cesium.Cesium3DTileStyle({
// color: "color('rgba(255,255,255," + this.newData.transparency + ")')",
// show: true,
// });
this.editObj.destroy()
this.Dialog.closeCallBack && this.Dialog.closeCallBack()
},
showCallBack: (show) => {
this.newData.show = show
this.entity && (this.entity.show = show)
this.Dialog.showCallBack && this.Dialog.showCallBack()
},
rotateCallBack: () => {
if (this.rotationEditing) {
this.rotationEditing = false
}
else {
this.rotationEditing = true
}
},
translationalCallBack: () => {
if (this.positionEditing) {
this.positionEditing = false
}
else {
this.positionEditing = true
}
}
})
this._DialogObject._element.body.className = this._DialogObject._element.body.className + ' tileset-bim'
// 内容部分
let contentElm = document.createElement('div');
contentElm.innerHTML = html()
this._DialogObject.contentAppChild(contentElm)
let all_elm = contentElm.getElementsByTagName("*")
this._EventBinding.on(this, all_elm)
this._elms = this._EventBinding.element
} else {
if (this._DialogObject && this._DialogObject.close) {
this._DialogObject.close()
this._DialogObject = null
}
}
}
async featureEdit(state, feature) {
let _this = this
this._element_style = null
if (this._DialogObject && this._DialogObject.close) {
this._DialogObject.close()
this._DialogObject = null
}
if (state) {
// console.log(this.entity)
// console.log(this.entity.root.children[0].content)
// console.log(feature.getProperty('id'), feature.getProperty('name'), feature.getProperty('state'))
let name = feature.getProperty('name')
// console.log(feature.getProperty('descriptions'))
let data = {
id: feature.getProperty('id'),
name: name,
state: feature.getProperty('state') || 0,
descriptions: feature.getProperty('descriptions') || [
{
id: this.randomString(),
key: "点击此处可编辑",
value: ""
}
]
}
switch (feature.getProperty('state')) {
case '0': data.stateCH = ''
break
case '1': data.stateCH = '已完成'
break
case '2': data.stateCH = '未完成'
break
case '3': data.stateCH = '修建中'
break
}
// let feature = this.entity.root.children[0].content.getFeature(0)
// console.log(id,feature, this.entity)
// return
this._element_style = document.createElement('style');
this._element_style.type = 'text/css';
this._element_style.setAttribute('data-name', 'YJ_style_dialog');
this._element_style.innerHTML = css2();
this._DialogObject = await new BaseDialog(this.sdk.viewer._container, {
title: this.oldData.name + '-----设置状态', left: 'calc(50% - 200px)', top: 'calc(50% - 200px)',
closeCallBack: () => {
this.Dialog.closeCallBack && this.Dialog.closeCallBack()
}
})
await this._DialogObject.init()
document.getElementsByTagName('head')[0].appendChild(this._element_style);
// 内容部分
let content = document.createElement('div');
content.innerHTML = html2()
// 名称
let e_name = content.querySelector("input[name='name']")
e_name.value = name
//状态
let e_state = content.querySelector("select[name='state-select']")
e_state.value = data.state
e_state.addEventListener('change', (e) => {
data.state = e.target.value
switch (data.state) {
case '0': data.stateCH = ''
break
case '1': data.stateCH = '已完成'
break
case '2': data.stateCH = '未完成'
break
case '3': data.stateCH = '修建中'
break
}
});
//自定义属性
let e_property = content.getElementsByClassName('property')[0]
for (let i = 0; i < data.descriptions.length; i++) {
createPropertyItem(data.descriptions[i], i)
}
function createPropertyItem(item) {
let html = `<div class="row property-item">
<div class="col">
<input class="input_lable" name="key" value="${item.key}">
<input class="input" name="value" value="${item.value}">
<button class="btn add"></button>
<button class="btn delete"></button>
</div>
</div>`
// document.createRange().createContextualFragment(html)
let newElement = document.createElement("div");
newElement.innerHTML = html
let itemElm = newElement.getElementsByClassName('property-item')[0]
let e_key = itemElm.querySelector("input[name='key']")
let e_value = itemElm.querySelector("input[name='value']")
let e_add = itemElm.getElementsByClassName('add')[0]
let e_delete = itemElm.getElementsByClassName('delete')[0]
e_key.addEventListener('input', (e) => {
item.key = e.target.value
})
e_value.addEventListener('input', (e) => {
item.value = e.target.value
})
e_add.addEventListener('click', () => {
let newItem = {
id: _this.randomString(),
key: "点击此处可编辑",
value: ""
}
data.descriptions.push(newItem)
createPropertyItem(newItem)
})
e_delete.addEventListener('click', (e) => {
for (let i = 0; i < data.descriptions.length; i++) {
if (data.descriptions[i].id === item.id) {
data.descriptions.splice(i, 1)
break
}
}
e_property.removeChild(itemElm)
// let item = {
// key: "点击此处可编辑",
// value: ""
// }
// createPropertyItem(item)
})
e_property.appendChild(itemElm)
}
let target = this._DialogObject._element.foot.getElementsByClassName('translational')[0]
this._DialogObject.contentAppChild(content)
// foot部分
let confirmBtn = document.createElement('button');
confirmBtn.className = 'confirm';
confirmBtn.innerHTML = '确认'
this._DialogObject.footAppChild(confirmBtn, target)
confirmBtn.addEventListener('click', () => {
let flag = false
for (let i = 0; i < this.features.length; i++) {
if (this.features[i].id == data.id) {
this.features[i] = data
flag = true
break
}
}
if (!flag) {
this.features.push(data)
}
feature.setProperty('state', data.state)
feature.setProperty('descriptions', data.descriptions)
let color = '#fff'
switch (data.state) {
case '0':
color = '#fff'
break;
case '1':
color = '#f00'
break;
case '2':
color = '#0f0'
break;
case '3':
color = '#00f'
break;
default:
}
feature.color = Cesium.Color.fromCssColorString(color)
this._DialogObject.close()
this.Dialog.confirmCallBack && this.Dialog.confirmCallBack({ ...this.newData, features: this.features })
});
} else {
if (this._element_style) {
document.getElementsByTagName('head')[0].removeChild(this._element_style)
this._element_style = null
}
if (this._DialogObject && this._DialogObject.close) {
this._DialogObject.close()
this._DialogObject = null
}
}
}
reset() {
if (!this.entity) {
return
}
// this.transparency = this.oldData.transparency
this.name = this.oldData.name
this.height = this.oldData.height
this.lng = this.oldData.lng
this.lat = this.oldData.lat
this.roll = this.oldData.roll
this.heading = this.oldData.heading
this.pitch = this.oldData.pitch
this.scale = this.oldData.scale
}
//更新模型位置
updateModel(_tx, _ty, _tz, _rx = 0, _ry = 0, _rz = 0, s = 1) {
if (!this.tileset.root.transform) {
if (window.ELEMENT) {
window.ELEMENT.Message.closeAll();
window.ELEMENT.Message({
message: '该模型不支持移动和旋转!',
type: 'warning',
duration: 1500
});
}
console.warn('该模型不支持移动和旋转!')
return
}
if ((!_tx && _tx!==0) || (!_ty && _ty!==0) || (!_tz && _tz!==0)) {
return
}
let mx = Cesium.Matrix3.fromRotationX(
Cesium.Math.toRadians(_rx)
)
let my = Cesium.Matrix3.fromRotationY(
Cesium.Math.toRadians(_ry)
)
let mz = Cesium.Matrix3.fromRotationZ(
Cesium.Math.toRadians(_rz)
)
// 平移
let m = Cesium.Transforms.eastNorthUpToFixedFrame(new Cesium.Cartesian3.fromDegrees(_tx, _ty, _tz))
// 旋转
let rotationX = Cesium.Matrix4.fromRotationTranslation(mx)
let rotationY = Cesium.Matrix4.fromRotationTranslation(my)
let rotationZ = Cesium.Matrix4.fromRotationTranslation(mz)
let originalMatrix = new Cesium.Matrix4()
Cesium.Matrix4.multiply(m, rotationX, originalMatrix)
Cesium.Matrix4.multiply(originalMatrix, rotationY, originalMatrix)
Cesium.Matrix4.multiply(originalMatrix, rotationZ, originalMatrix)
const scale = Cesium.Matrix4.fromUniformScale(s);
Cesium.Matrix4.multiply(originalMatrix, scale, this.entity._root.transform)
if (!this.editObj.activeAxis) {
this.editObj.position = { lng: _tx, lat: _ty, alt: _tz }
}
if (!this.editObj.activeCircle) {
this.editObj.rotate = { x: _rx, y: _ry, z: _rz }
}
this.editObj && this.editObj.update()
clearTimeout(this.#updateModelTimeout)
this.#updateModelTimeout = setTimeout(() => {
clearTimeout(this.#updateModelTimeout)
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
}
}
}
}, 300);
}
// exportProperty(states) {
// console.log(this.features)
// let fieldKeys = ['name', '', '', '', '', '', '', '', '', '', '', '', 'stateCH', 'descriptions']
// let fieldLabels = ['构件名称', '体积', '墩全高H', '墩身高h', '底部高程', '承台宽', '承台长', '承台高', '族', '桩径', '桩长', '结构材质', '完成情况', '自定义属性']
// let dataStr = fieldLabels.toString() + '\r\n';
// for (let i = 0; i < this.features.length; i++) {
// for (let j = 0; j < states.length; j++) {
// if (this.features[i].state == states[j]) {
// fieldKeys.forEach(key => {
// if (Array.isArray(this.features[i][key])) {
// let str = ''
// for (let k in this.features[i][key]) {
// str += `${this.features[i][key][k].key + '' + this.features[i][key][k].value}\n`
// }
// dataStr += `"${str}"\t`
// }
// else {
// // 加引号是为了使换行符在单元格内正常显示
// dataStr += `"${this.features[i][key] ? this.features[i][key] : ''}"\t,`;
// }
// });
// dataStr += '\r\n';
// break
// }
// }
// }
// // encodeURIComponent 解决中文乱码
// const url = "data:text/xls;charset=utf-8,\ufeff" + encodeURIComponent(dataStr);
// console.log(url)
// // const link = document.createElement("a");
// // link.href = url;
// // link.download = this.oldData.name + "--构件属性.xls";
// // link.style.display = 'none';
// // document.body.appendChild(link);
// // link.click();
// // document.body.removeChild(link); //释放标签
// }
getScenetree() {
return this.scenetree
}
// 设置feature颜色
featureColor(id, color) {
if (this.features.has(id)) {
let features = this.features.get(id).features
for (let key in features) {
if (features[key].content._model) {
features[key].color = Cesium.Color.fromCssColorString(color)
}
features[key].customColor = Cesium.Color.fromCssColorString(color)
}
this.features.get(id).customColor = Cesium.Color.fromCssColorString(color)
}
}
getFeatureColor(id) {
if (this.features.has(id)) {
if (this.features.get(id).customColor) {
return this.features.get(id).customColor
}
let features = this.features.get(id).features
for (let key in features) {
if (features[key].content._model) {
return features[key].customColor || features[key].color
}
}
}
}
// 设置feature显隐
featureShow(id, show) {
if (this.features.has(id)) {
let features = this.features.get(id).features
for (let key in features) {
if (features[key].content._model) {
features[key].show = show
}
features[key].customShow = show
}
this.features.get(id).customShow = show
}
}
//飞到feature位置
async featureFlyto(id) {
if (this.features.has(id)) {
let sphere = this.features.get(id).sphere
let center = new Cesium.Cartesian3(
sphere[0],
sphere[1],
sphere[2]
)
let srcMatInv = this.entity._root.originalTransform
srcMatInv = Cesium.Matrix4.inverse(srcMatInv, new Cesium.Matrix4())
let curMat = this.entity._root.transform
let mat = Cesium.Matrix4.multiply(curMat, srcMatInv, new Cesium.Matrix4())
let center2 = Cesium.Matrix4.multiplyByPoint(
mat,
center,
new Cesium.Cartesian3()
)
let wgs84 = this.cartesian3Towgs84(center2, this.sdk.viewer)
let cartesian3 = Cesium.Cartesian3.fromDegrees(
wgs84.lng,
wgs84.lat,
wgs84.alt + sphere[3]
)
setActiveViewer(0)
closeRotateAround(this.sdk)
closeViewFollow(this.sdk)
this.sdk.viewer.camera.flyTo({
destination: cartesian3
})
// this.entity.style = await new Cesium.Cesium3DTileStyle({
// color: "color('rgba(255,255,255,0.2)')"
// });
this.features.forEach((item, key) => {
if (key === id) {
let color = this.getFeatureColor(id)
if (this.features.has(id) && color) {
let features = this.features.get(id).features
for (let k in features) {
if (features[k].content._model) {
features[k].color = color
}
features[k].customAlpha = 1
}
this.features.get(id).customAlpha = 1
}
// this.featureColor(id, `rgba(${Cesium.Color.floatToByte(color.red)},${Cesium.Color.floatToByte(color.green)},${Cesium.Color.floatToByte(color.blue)},${color.alpha})`)
}
else {
let color = this.getFeatureColor(key)
if (this.features.has(key) && color) {
let features = this.features.get(key).features
for (let k in features) {
if (features[k].content._model) {
features[k].color = Cesium.Color.fromCssColorString(`rgba(${Cesium.Color.floatToByte(color.red)},${Cesium.Color.floatToByte(color.green)},${Cesium.Color.floatToByte(color.blue)},${color.alpha * 0.2})`)
}
features[k].customAlpha = color.alpha * 0.2
}
this.features.get(key).customAlpha = color.alpha * 0.2
}
// this.featureColor(key, `rgba(${Cesium.Color.floatToByte(color.red)},${Cesium.Color.floatToByte(color.green)},${Cesium.Color.floatToByte(color.blue)},${color.alpha * 0.2})`)
}
})
// this.entity.readyPromise.then(()=>{
// this.featureColor(id, '#ffffff')
// })
}
else {
this.features.forEach((item, key) => {
let features = this.features.get(key).features
let color = this.getFeatureColor(key)
if (color) {
for (let k in features) {
if (features[k].content._model) {
features[k].color = color
}
features[k].customAlpha = 1
}
this.features.get(key).customAlpha = color.alpha * 0.2
}
})
}
}
// 导出属性
exportProperty(states) {
if (this.exportStateArray.length === 0) {
window.ELEMENT && window.ELEMENT.Message({
message: '未选择属性导出选项!',
type: 'warning',
duration: 1500
});
return
}
let fieldKeys = ['name', '', '', '', '', '', '', '', '', '', '', '', 'stateCH', 'descriptions']
let fieldLabels = ['构件名称', '体积', '墩全高H', '墩身高h', '底部高程', '承台宽', '承台长', '承台高', '族', '桩径', '桩长', '结构材质', '完成情况', '自定义属性']
var url = 'data:application/vnd.ms-excel;base64,',
tmplWorkbookXML = '<?xml version="1.0"?><?mso-application progid="Excel.Sheet"?><Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">'
+ '<DocumentProperties xmlns="urn:schemas-microsoft-com:office:office"><Author>Axel Richter</Author><Created>{created}</Created></DocumentProperties>'
+ '<Styles>'
+ '<Style ss:ID="Currency"><NumberFormat ss:Format="Currency"></NumberFormat></Style>'
+ '<Style ss:ID="Date"><NumberFormat ss:Format="Medium Date"></NumberFormat></Style>'
+ '</Styles>'
+ '{worksheets}</Workbook>'
, tmplWorksheetXML = '<Worksheet ss:Name="{nameWS}"><Table><ss:Column ss:Width="120"/><ss:Column ss:Width="120"/><ss:Column ss:Width="120"/><ss:Column ss:Width="120"/><ss:Column ss:Width="120"/><ss:Column ss:Width="120"/><ss:Column ss:Width="120"/><ss:Column ss:Width="120"/><ss:Column ss:Width="120"/><ss:Column ss:Width="120"/><ss:Column ss:Width="120"/><ss:Column ss:Width="120"/><ss:Column ss:Width="120"/><ss:Column ss:Width="240"/>{rows}</Table></Worksheet>'
, tmplCellXML = '<Cell><Data ss:Type="{nameType}">{data}</Data></Cell>'
, base64 = function (s) {
return window.btoa(unescape(encodeURIComponent(s)))
}
, format = function (s, c) {
return s.replace(/{(\w+)}/g, function (m, p) {
return c[p];
})
}
var ctx = "";
var workbookXML = "";
var worksheetsXML = "";
var rowsXML = "";
var pil = 0;
for (var i = 0; i < this.features.length; i++) {
for (let j = 0; j < states.length; j++) {
if (this.features[i].state == states[j]) {
if (i == 0) {
rowsXML += '<Row>' +
'<Cell><Data ss:Type="String">构件名称</Data></Cell>' +
'<Cell><Data ss:Type="String">体积</Data></Cell>' +
'<Cell><Data ss:Type="String">墩全高H</Data></Cell>' +
'<Cell><Data ss:Type="String">墩身高h</Data></Cell>' +
'<Cell><Data ss:Type="String">底部高程</Data></Cell>' +
'<Cell><Data ss:Type="String">承台宽</Data></Cell>' +
'<Cell><Data ss:Type="String">承台长</Data></Cell>' +
'<Cell><Data ss:Type="String">承台高</Data></Cell>' +
'<Cell><Data ss:Type="String">族</Data></Cell>' +
'<Cell><Data ss:Type="String">桩径</Data></Cell>' +
'<Cell><Data ss:Type="String">桩长</Data></Cell>' +
'<Cell><Data ss:Type="String">结构材质</Data></Cell>' +
'<Cell><Data ss:Type="String">完成情况</Data></Cell>' +
'<Cell><Data ss:Type="String">自定义属性</Data></Cell>' +
'</Row>';
}
rowsXML += '<Row>';
for (var key in fieldKeys) {
if (Array.isArray(this.features[i][fieldKeys[key]])) {
let str = ''
for (let k in this.features[i][fieldKeys[key]]) {
str += `${this.features[i][fieldKeys[key]][k].key + '' + this.features[i][fieldKeys[key]][k].value}&#10;`
}
ctx = {
nameType: 'String',
data: str
};
}
else {
ctx = {
nameType: 'String',
data: this.features[i][fieldKeys[key]] || "0"
};
}
rowsXML += format(tmplCellXML, ctx);
}
rowsXML += '</Row>';
if (i > 0 && (i / 60000) % 1 === 0) {
pil++;
ctx = { rows: rowsXML, nameWS: 'Sheet' + i };
worksheetsXML += format(tmplWorksheetXML, ctx);
rowsXML = "";
rowsXML += '<Row>' +
'<Cell><Data ss:Type="String">构件名称</Data></Cell>' +
'<Cell><Data ss:Type="String">体积</Data></Cell>' +
'<Cell><Data ss:Type="String">墩全高H</Data></Cell>' +
'<Cell><Data ss:Type="String">墩身高h</Data></Cell>' +
'<Cell><Data ss:Type="String">底部高程</Data></Cell>' +
'<Cell><Data ss:Type="String">承台宽</Data></Cell>' +
'<Cell><Data ss:Type="String">承台长</Data></Cell>' +
'<Cell><Data ss:Type="String">承台高</Data></Cell>' +
'<Cell><Data ss:Type="String">族</Data></Cell>' +
'<Cell><Data ss:Type="String">桩径</Data></Cell>' +
'<Cell><Data ss:Type="String">桩长</Data></Cell>' +
'<Cell><Data ss:Type="String">结构材质</Data></Cell>' +
'<Cell><Data ss:Type="String">完成情况</Data></Cell>' +
'<Cell><Data ss:Type="String">自定义属性</Data></Cell>' +
'</Row>';
}
}
}
}
ctx = { rows: rowsXML, nameWS: 'Sheet' };
worksheetsXML += format(tmplWorksheetXML, ctx);
rowsXML = "";
ctx = { created: (new Date()).getTime(), worksheets: worksheetsXML };
workbookXML = format(tmplWorkbookXML, ctx);
var link = document.createElement("A");
link.href = url + base64(workbookXML);
link.download = this.oldData.name + "--构件属性.xls"
link.target = '_blank';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
exportState(e) {
let checkbox = e.target.getElementsByTagName('input')[0]
checkbox.checked = !checkbox.checked
if (checkbox.checked) {
this.exportStateArray.push(checkbox.value)
this.exportStateArray = Array.from(new Set(this.exportStateArray))
}
else {
for (let i = 0; i < this.exportStateArray.length; i++) {
if (this.exportStateArray[i] == checkbox.value) {
this.exportStateArray.splice(i, 1)
break
}
}
}
}
}
export default BIM

View File

@ -0,0 +1,54 @@
function html() {
return `
<span class="custom-divider"></span>
<div class="div-item">
<div class="row">
<div class="col">
<span class="label">名称</span>
<input class="input" @model="name">
</div>
</div>
</div>
<span class="custom-divider"></span>
<div class="div-item">
<div class="row">
<div class="col">
<span class="label">高度</span>
<div class="input-number input-number-unit-3">
<input class="input" type="number" title="" @model="height">
<span class="unit">m</span>
<span class="arrow"></span>
</div>
</div>
<div class="col">
<span class="label">精度</span>
<div class="input-number input-number-unit-3">
<input class="input" type="number" title="" min="0.1" max="10" step="0.1" @model="accuracy">
<span class="unit">倍</span>
<span class="arrow"></span>
</div>
</div>
</div>
<div class="row">
<div class="col">
<span class="label">透视</span>
<input type="range" min="0" max="1" step="0.01" @model="transparency">
</div>
</div>
</div>
`
}
function css() {
return `
.YJ-custom-base-dialog>.content {
width: 420px;
}
.YJ-custom-base-dialog>.content .row .label {
flex: 0 0 45px;
}
`
}
export { html, css }

View File

@ -0,0 +1,87 @@
class eventBinding {
constructor() {
this.element = {}
}
static event = {}
getEvent(name) {
return eventBinding.event[name]
}
getEventAll() {
return eventBinding.event
}
setEvent(name, event) {
eventBinding.event[name] = event
}
on(that, elements) {
for (let i = 0; i < elements.length; i++) {
let Event = []
let isEvent = false
let removeName = []
if (!elements[i] || !elements[i].attributes) {
continue;
}
for (let m of elements[i].attributes) {
switch (m.name) {
case '@model': {
isEvent = true
if (elements[i].type == 'checkbox') {
Event.push((e) => { that[m.value] = e.target.checked })
elements[i].checked = that[m.value]
}
else {
Event.push((e) => {
let value = e.target.value
if(e.target.type == 'number') {
value = Number(value)
}
that[m.value] = value
})
if(elements[i].nodeName=='IMG') {
elements[i].src = that[m.value]
}
else {
elements[i].value = that[m.value]
}
}
this.element[m.value] = elements[i]
removeName.push(m.name)
break;
}
case '@click': {
elements[i].addEventListener('click', (e) => {
if (typeof (that.Dialog[m.value]) === 'function') {
that.Dialog[m.value](e)
}
});
removeName.push(m.name)
// elements[i].attributes.removeNamedItem(m.name)
break;
}
}
// elements[i].attributes[m] = undefined
}
for(let n=0;n<removeName.length;n++) {
elements[i].attributes.removeNamedItem(removeName[n])
}
if (isEvent) {
let ventType = 'input'
if (elements[i].tagName != 'INPUT' || elements[i].type == 'checkbox') {
ventType = 'change'
}
elements[i].addEventListener(ventType, (e) => {
for (let t = 0; t < Event.length; t++) {
Event[t](e)
}
});
}
}
}
}
const EventBinding = new eventBinding();
export default EventBinding;

View File

@ -0,0 +1,373 @@
/**
* @name: index
* @author: Administrator
* @date: 2023-11-20 16:05
* @descriptionindex
* @update: 2023-11-20 16:05
*/
import BaseTileset from "../index";
import cy_slider from "../../../../Element/cy_html_slider";
import { html, css } from "./_element";
import EventBinding from '../../../../Element/Dialog/eventBinding';
import { syncSplitData } from '../../../../../Global/SplitScreen'
import Dialog from '../../../../Element/Dialog';
class Tileset extends BaseTileset {
#updateModelTimeout;
/**
* @constructor
* @description 加载Tileset模型
* @param sdk {object} sdk
* @param options {object} 模型参数
* @param options.id {string} 对象id
* @param options.show=true {boolean} 模型显隐
* @param options.name {string} 名称
* @param options.url {string} 资源地址
* @param options.accuracy=1 {number} 精度(倍)
* @param options.position {object} 模型位置
* @param options.position.lng {number} 经度
* @param options.position.lat {number} 纬度
* @param options.position.alt {number} 高度
* */
constructor(earth, options = {}, _Dialog = {}) {
super(earth, options)
this.picking = false
this.Dialog = _Dialog
this._elms = {};
this._EventBinding = new EventBinding()
}
get type() {
return "tileset"
}
on() {
return this.add()
}
get name() {
return this.newData.name
}
set name(v) {
this.newData.name = v
this._elms.name && this._elms.name.forEach((item) => {
item.value = v
})
}
get height() {
return this.newData.height
}
set height(v) {
this.newData.height = v
this.options.position.alt = v
this._elms.height && this._elms.height.forEach((item) => {
item.value = v
})
this.updateModel(this.newData.lng, this.newData.lat, this.newData.height, this.newData.roll, this.newData.heading, this.newData.pitch)
}
get accuracy() {
return this.newData.accuracy
}
set accuracy(v) {
this.newData.accuracy = Number(v.toFixed(1))
if(this.newData.accuracy<0.1) {
this.newData.accuracy = 0.1
}
if(this.entity) {
this.entity.maximumScreenSpaceError = 32/this.newData.accuracy
}
this._elms.accuracy && this._elms.accuracy.forEach((item) => {
item.value = this.newData.accuracy
})
}
get lng() {
return this.newData.lng
}
set lng(v) {
this.newData.lng = v
this.options.position.lng = v
this.updateModel(this.newData.lng, this.newData.lat, this.newData.height, this.newData.roll, this.newData.heading, this.newData.pitch)
}
get lat() {
return this.newData.lat
}
set lat(v) {
this.newData.lat = v
this.options.position.lat = v
this.updateModel(this.newData.lng, this.newData.lat, this.newData.height, this.newData.roll, this.newData.heading, this.newData.pitch)
}
get roll() {
return this.newData.roll
}
set roll(v) {
this.newData.roll = v
this.updateModel(this.newData.lng, this.newData.lat, this.newData.height, this.newData.roll, this.newData.heading, this.newData.pitch, this.newData.scale)
}
get heading() {
return this.newData.heading
}
set heading(v) {
this.newData.heading = v
this.updateModel(this.newData.lng, this.newData.lat, this.newData.height, this.newData.roll, this.newData.heading, this.newData.pitch, this.newData.scale)
}
get pitch() {
return this.newData.pitch
}
set pitch(v) {
this.newData.pitch = v
this.updateModel(this.newData.lng, this.newData.lat, this.newData.height, this.newData.roll, this.newData.heading, this.newData.pitch, this.newData.scale)
}
get transparency() {
return this.newData.transparency
}
set transparency(v) {
if (!this.newData) {
return
}
this.newData.transparency = Number(v)
this._elms.transparency && this._elms.transparency.forEach((item) => {
item.value = v
})
let transparency = this.newData.transparency
// if (transparency == 1) {
// transparency = 0.99
// }
this.entity.style = new Cesium.Cesium3DTileStyle({
color: {
"conditions": [
//有size属性表示为点云需要与点颜色融合
["Boolean(${SIZE})", "${COLOR} * color('rgba(255,255,255)', " + transparency + ")"],
["true", "color('rgba(255,255,255," + transparency + ")')"]
]
},
show: true,
});
}
/**
* @description 编辑框
* @param state=false {boolean} 状态: true打开, false关闭
*/
async edit(state = false) {
let _this = this
this._element_style = null
// let elms = this.sdk.viewer._container.getElementsByClassName('YJ-custom-base-dialog')
// for (let i = elms.length - 1; i >= 0; i--) {
// this.sdk.viewer._container.removeChild(elms[i])
// }
if (this._DialogObject && this._DialogObject.close) {
this._DialogObject.close()
this._DialogObject = null
}
if (state) {
this._element_style = document.createElement('style');
this._element_style.type = 'text/css';
this._element_style.setAttribute('data-name', 'YJ_style_dialog');
this._element_style.innerHTML = css();
this._DialogObject = await new Dialog(this.sdk, this.newData, {
title: '倾斜模型属性', left: '180px', top: '100px',
confirmCallBack: (options) => {
this.oldData.name = this.newData.name
this.oldData.height = this.newData.height
this.oldData.lng = this.newData.lng
this.oldData.lat = this.newData.lat
this.oldData.transparency = this.newData.transparency
this.oldData.scale = this.newData.scale
this.oldData.roll = this.newData.roll
this.oldData.heading = this.newData.heading
this.oldData.pitch = this.newData.pitch
this.oldData.type = this.type
this.oldData.accuracy = this.newData.accuracy
this._DialogObject.close()
this.Dialog.confirmCallBack && this.Dialog.confirmCallBack({ ...this.oldData, type: this.type })
syncSplitData(this.sdk, this.oldData.id)
},
resetCallBack: () => {
this.reset()
this.Dialog.resetCallBack && this.Dialog.resetCallBack()
},
removeCallBack: () => {
this.Dialog.removeCallBack && this.Dialog.removeCallBack()
},
closeCallBack: () => {
this.reset()
if (this.positionEditing) {
this.positionEditing = false
}
if (this.rotationEditing) {
this.rotationEditing = false
}
this.Dialog.closeCallBack && this.Dialog.closeCallBack()
},
showCallBack: (show) => {
this.newData.show = show
this.entity && (this.entity.show = show)
this.Dialog.showCallBack && this.Dialog.showCallBack()
},
rotateCallBack: () => {
if (this.rotationEditing) {
this.rotationEditing = false
}
else {
this.rotationEditing = true
}
},
translationalCallBack: () => {
if (this.positionEditing) {
this.positionEditing = false
}
else {
this.positionEditing = true
}
}
}, true)
document.getElementsByTagName('head')[0].appendChild(this._element_style);
let contentElm = document.createElement('div');
contentElm.innerHTML = html()
this._DialogObject.contentAppChild(contentElm)
let all_elm = contentElm.getElementsByTagName("*")
this._EventBinding.on(this, all_elm)
this._elms = this._EventBinding.element
} else {
// if (this._element_style) {
// document.getElementsByTagName('head')[0].removeChild(this._element_style)
// this._element_style = null
// }
// if (this._DialogObject && this._DialogObject.remove) {
// this._DialogObject.remove()
// this._DialogObject = null
// }
}
}
//更新模型位置
updateModel(_tx, _ty, _tz, _rx = 0, _ry = 0, _rz = 0, s = 1) {
if (!this.tileset.root.transform) {
if (window.ELEMENT) {
window.ELEMENT.Message.closeAll();
window.ELEMENT.Message({
message: '该模型不支持移动和旋转!',
type: 'warning',
duration: 1500
});
}
console.warn('该模型不支持移动和旋转!')
return
}
if ((!_tx && _tx!==0) || (!_ty && _ty!==0) || (!_tz && _tz!==0)) {
return
}
let mx = Cesium.Matrix3.fromRotationX(
Cesium.Math.toRadians(_rx)
)
let my = Cesium.Matrix3.fromRotationY(
Cesium.Math.toRadians(_ry)
)
let mz = Cesium.Matrix3.fromRotationZ(
Cesium.Math.toRadians(_rz)
)
// 平移
let m = Cesium.Transforms.eastNorthUpToFixedFrame(new Cesium.Cartesian3.fromDegrees(_tx, _ty, _tz))
// 旋转
let rotationX = Cesium.Matrix4.fromRotationTranslation(mx)
let rotationY = Cesium.Matrix4.fromRotationTranslation(my)
let rotationZ = Cesium.Matrix4.fromRotationTranslation(mz)
let originalMatrix = new Cesium.Matrix4()
Cesium.Matrix4.multiply(m, rotationX, originalMatrix)
Cesium.Matrix4.multiply(originalMatrix, rotationY, originalMatrix)
Cesium.Matrix4.multiply(originalMatrix, rotationZ, originalMatrix)
const scale = Cesium.Matrix4.fromUniformScale(s);
Cesium.Matrix4.multiply(originalMatrix, scale, this.entity._root.transform)
// console.log(_tx, _ty, _tz)
if (!this.editObj.activeAxis) {
this.editObj.position = { lng: _tx, lat: _ty, alt: _tz }
}
if (!this.editObj.activeCircle) {
this.editObj.rotate = { x: _rx, y: _ry, z: _rz }
}
this.editObj && this.editObj.update()
clearTimeout(this.#updateModelTimeout)
this.#updateModelTimeout = setTimeout(() => {
clearTimeout(this.#updateModelTimeout)
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
}
}
}
}, 300);
}
// flyTo() {
// this.entity.readyPromise.then(() => {
// console.log(this.entity)
// let boundingSphere
// if(!this.lng || !this.lat) {
// boundingSphere = new Cesium.BoundingSphere(this.entity.boundingSphere)
// }
// else {
// boundingSphere = new Cesium.BoundingSphere(Cesium.Cartesian3.fromDegrees(this.lng, this.lat, this.height), this.entity.boundingSphere.radius)
// }
// this.sdk.viewer.camera.flyToBoundingSphere(boundingSphere)
// })
// }
reset() {
this.editObj.destroy()
if (!this.entity) {
return
}
this.transparency = this.oldData.transparency
this.name = this.oldData.name
this.height = this.oldData.height
this.lng = this.oldData.lng
this.lat = this.oldData.lat
this.roll = this.oldData.roll
this.heading = this.oldData.heading
this.pitch = this.oldData.pitch
this.scale = this.oldData.scale
this.accuracy = this.oldData.accuracy
this.entity.style = new Cesium.Cesium3DTileStyle({
color: {
"conditions": [
["Boolean(${SIZE})", "${COLOR} * color('rgba(255,255,255)', " + this.transparency + ")"],
["true", "color('rgba(255,255,255," + this.transparency + ")')"]
]
},
show: true,
});
}
}
export default Tileset

View File

@ -0,0 +1,650 @@
/**
* @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