代码迁移

This commit is contained in:
zh
2025-07-03 13:54:01 +08:00
parent b04de8a084
commit 2a4da33e62
985 changed files with 358292 additions and 13 deletions

204
src/BaseDialog/index.js Normal file
View File

@ -0,0 +1,204 @@
class BaseDialog {
constructor(container, options = {}) {
this.container = container
this.options = { ...options }
this.options.ismove = true
if(options.ismove === false) {
this.options.ismove = options.ismove
}
this.closeCallBack = options.closeCallBack
this._element = {}
this._element_style = undefined
}
async init() {
this.closeAll()
DialogAll.push(this)
this.isDestroy = false
// body
this._element.body = document.createElement('div');
this._element.body.className = 'YJ-custom-base-dialog';
this._element.body.style.top = this.options.top
this._element.body.style.bottom = this.options.bottom
this._element.body.style.left = this.options.left
this._element.body.style.right = this.options.right
this.container.appendChild(this._element.body)
//title
this._element.title = document.createElement('div');
this._element.title.className = 'title-box';
this._element.title.innerHTML = `<span class="title">${(this.options.title || '')}</span>` + `<span class="close-box"><span class="close"></span><i>&#10005</i></span>`
this._element.body.appendChild(this._element.title)
//content
this._element.content = await document.createElement('div');
this._element.content.className = 'content';
this._element.body.appendChild(this._element.content)
// foot
this._element.foot = await document.createElement('div');
this._element.foot.className = 'foot';
// this._element.foot.innerHTML = `
// <button class="translational">平移</button>
// <button class="resetting">重置</button>
// <button class="delete">删除</button>
// <button class="close">关闭</button>
// `
this._element.foot.innerHTML = `
<button class="close">关闭</button>
`
this._element.body.appendChild(this._element.foot)
// 关闭
let closeBtnsBox = this._element.body.getElementsByClassName('close-box')[0];
closeBtnsBox.addEventListener('click', () => {
this.close()
});
let closeBtns = this._element.body.getElementsByClassName('close');
for (let i = 0; i < closeBtns.length; i++) {
closeBtns[i].addEventListener('click', () => {
this.close()
});
}
if(this.options.ismove) {
this.moveDiv()
}
}
close() {
let styles = document.getElementsByTagName("style")
for (let i = styles.length - 1; i >= 0; i--) {
if (styles[i].dataset) {
if (styles[i].dataset.name === 'YJ_style_dialog') {
document.getElementsByTagName('head')[0].removeChild(styles[i])
}
}
}
if (this._element.body && this._element.body.parentNode) {
this.container.removeChild(this._element.body)
}
this._element.body = null
this._element.title = null
this._element.content = null
this._element.foot = null
this._element_style = null
this.isDestroy = true
if (this.closeCallBack) {
this.closeCallBack()
this.closeCallBack = null
}
}
closeAll() {
for(let i=DialogAll.length-1;i>=0;i--) {
DialogAll[i].close()
DialogAll.splice(i, 1)
}
return
let styles = document.getElementsByTagName("style")
for (let i = styles.length - 1; i >= 0; i--) {
if (styles[i].dataset) {
if (styles[i].dataset.name === 'YJ_style_dialog') {
document.getElementsByTagName('head')[0].removeChild(styles[i])
}
}
}
if (this._element_style) {
this._element_style = null
}
let elms = this.container.getElementsByClassName('YJ-custom-base-dialog')
for (let i = elms.length - 1; i >= 0; i--) {
this.container.removeChild(elms[i])
}
this._element.body = null
this._element.title = null
this._element.content = null
this._element.foot = null
}
titleAppChild(node) {
this._element.title.appendChild(node)
}
contentAppChild(node) {
this._element.content.appendChild(node)
}
footAppChild(node, target) {
if (target) {
this._element.foot.insertBefore(node, target);
}
else {
this._element.foot.prepend(node)
}
}
moveDiv() {
let x = 0
let y = 0
let l = 0
let t = 0
let oClickDiv = this._element.body
let _this = this
oClickDiv.onmousedown = (e) => {
if (e.toElement.className !== 'title-box') {
return
}
// dialog的宽度、高度
// let oMoveDivHeight = that.oMoveDiv.offsetHeight
let oMoveDivHeight = this._element.body.offsetHeight
// let oMoveDivWidth = that.oMoveDiv.offsetWidth
let oMoveDivWidth = this._element.body.offsetWidth
x = e.clientX
y = e.clientY
let leftPx = window.getComputedStyle(this._element.body).left
let topPx = window.getComputedStyle(this._element.body).top
l = leftPx.substr(0, leftPx.indexOf('px')) * 1
t = topPx.substr(0, topPx.indexOf('px')) * 1
// 视口大小
let windowHeight = document.documentElement.clientHeight
let windowWidth = document.documentElement.clientWidth
//鼠标移动
window.onmousemove = function (e) {
e.preventDefault()
//获取x和y
let nx = e.clientX
let ny = e.clientY
//计算移动后的左偏移量和顶部的偏移量
let leftPx = nx - (x - l)
let topPx = ny - (y - t)
if (leftPx < 0) {
leftPx = 0
} else if (leftPx + oMoveDivWidth > windowWidth) {
leftPx = windowWidth - oMoveDivWidth
}
if (topPx <= 0) {
topPx = 0
} else if (topPx + oMoveDivHeight > windowHeight) {
topPx = windowHeight - oMoveDivHeight
}
_this._element.body.style.left = leftPx + 'px'
_this._element.body.style.top = topPx + 'px'
_this._element.body.style.bottom = 'unset'
_this._element.body.style.right = 'unset'
}
}
//鼠标抬起事件
document.onmouseup = function (e) {
window.onmousemove = null
}
window.ondragend = function (e) {
window.onmousemove = null
}
}
}
let DialogAll = []
export default BaseDialog

35
src/BaseDialog/rule.js Normal file
View File

@ -0,0 +1,35 @@
function check(elm, rule) {
let input = elm.getElementsByTagName('input')[0]
rules[rule.validator](input, rule.trigger, (s, error) => {
if (s) {
elm.className = 'input-box'
let eElm = elm.getElementsByClassName('input-error-text')[0]
if(eElm) {
elm.removeChild(eElm)
}
}
else {
elm.className = 'input-box error'
let e = rule.message || error
let eElm = document.createElement('span');
eElm.className = 'input-error-text'
eElm.innerHTML = e
elm.appendChild(eElm)
}
})
}
const rules = {
notEmpty: (input, trigger, cd) => {
input.addEventListener(trigger, ()=>{
if (input.value) {
cd(true)
}
else {
cd(false, '不能为空!')
}
})
}
}
export { check }

905
src/Controller/index.js Normal file
View File

@ -0,0 +1,905 @@
/**
* @description 平移旋转-改
*/
import MouseEvent from '../Event'
class ControllerObject {
constructor(sdk, options = {}) {
this.sdk = sdk
this.viwer = this.sdk.viewer
this.options = options
this.options.position = options.position || {}
this.options.rotate = options.rotate || {}
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
this.options.rotate.x = this.options.rotate.x || 0
this.options.rotate.y = this.options.rotate.y || 0
this.options.rotate.z = this.options.rotate.z || 0
this.activeAxis
this.activeCircle
this.activeModelParam
this.origin
this.rayX
this.rayY
this.rayZ
this.arrow = {}
this.activeState
this.coordArrows = []
this.coordCircles = []
this.MapEvent = new MouseEvent(this.sdk)
}
get position() {
return this.options.position
}
set position(v) {
this.options.position = v
this.againArrow()
this.againCircle()
}
get rotate() {
return this.options.rotate
}
set rotate(v) {
this.options.rotate = v
}
initParam() {
this._params = {
tx: this.options.position.lng, //模型中心X轴坐标经度单位十进制度
ty: this.options.position.lat, //模型中心Y轴坐标纬度单位十进制度
tz: this.options.position.alt, //模型中心Z轴坐标高程单位
rx: this.options.rotate.x, //X轴经度方向旋转角度单位
ry: this.options.rotate.y, //Y轴纬度方向旋转角度单位
rz: this.options.rotate.z //Z轴高程方向旋转角度单位
}
return { ...this.options.position, ...this.options.rotate }
}
/**
* 开始编辑平移
*/
async editTranslational() {
this.destroy()
this.activeState = 'translational'
this.MapEvent = new MouseEvent(this.sdk)
// this.viwer.scene.camera.flyTo({
// destination: new Cesium.Cartesian3.fromDegrees(104.17401, 30.63593, 1000),
// orientation: {
// pitch: Cesium.Math.toRadians(-35.0)
// },
// duration: 1
// })
/**
* 创建一条射线
*/
let _this = this
let param = this.initParam()
let lng = param.lng
let lat = param.lat
let h = param.alt
let viewer = this.viwer
// let lon = 104.17401
// let lat = 30.64593
// let h = 0
// 原点
this.origin = Cesium.Cartesian3.fromDegrees(lng, lat, h)
// 计算xyz轴方向
const directionVectorX = Cesium.Cartesian3.normalize(Cesium.Cartesian3.subtract(this.origin, Cesium.Cartesian3.fromDegrees(lng - 0.001, lat, h), new Cesium.Cartesian3()), new Cesium.Cartesian3());
const directionVectorY = Cesium.Cartesian3.normalize(Cesium.Cartesian3.subtract(this.origin, Cesium.Cartesian3.fromDegrees(lng, lat - 0.001, h), new Cesium.Cartesian3()), new Cesium.Cartesian3());
const directionVectorZ = Cesium.Cartesian3.normalize(Cesium.Cartesian3.subtract(this.origin, Cesium.Cartesian3.fromDegrees(lng, lat, h - 1), new Cesium.Cartesian3()), new Cesium.Cartesian3());
this.rayX = new Cesium.Ray(this.origin, directionVectorX)
this.rayY = new Cesium.Ray(this.origin, directionVectorY)
this.rayZ = new Cesium.Ray(this.origin, directionVectorZ)
this.arrow.positionX = Cesium.Ray.getPoint(this.rayX, 0)
this.arrow.positionY = Cesium.Ray.getPoint(this.rayY, 0)
this.arrow.positionZ = Cesium.Ray.getPoint(this.rayZ, 0)
const matrix = Cesium.Transforms.eastNorthUpToFixedFrame(
new Cesium.Cartesian3.fromDegrees(lng, lat, h)
)
// 获取相机的位置
var cameraPosition = viewer.camera.position;
// 计算相机与目标坐标之间的距离
var distance = Cesium.Cartesian3.distance(cameraPosition, this.origin);
let newRadius = distance / 15
let scale = newRadius
Cesium.Matrix4.multiplyByScale(matrix, new Cesium.Cartesian3(scale, scale, scale), matrix)
let axisArrowX = this.createAxisArrow('model_edit_xAxis', [new Cesium.Cartesian3(0, 0.001, 0), new Cesium.Cartesian3(1, 0, 0)], matrix, Cesium.Color.RED)
let axisArrowY = this.createAxisArrow('model_edit_yAxis', [new Cesium.Cartesian3(0, 0.001, 0), new Cesium.Cartesian3(0, 1, 0)], matrix, Cesium.Color.LIME)
let axisArrowZ = this.createAxisArrow('model_edit_zAxis', [new Cesium.Cartesian3(0, 0.001, 0), new Cesium.Cartesian3(0, 0, 1)], matrix, Cesium.Color.BLUE)
let positions = []
let radius = 1
// for (let i = 0; i <= 360; i += 3) {
// const sin = Math.sin(Cesium.Math.toRadians(i))
// const cos = Math.cos(Cesium.Math.toRadians(i))
// const x = radius * cos
// const y = radius * sin
// positions.push(new Cesium.Cartesian3(x, y, 0))
// }
// console.log('positions', positions)
// let axisCircular = this.createAxisCircular('model_edit_circular', positions, matrix)
this.viwer.scene.primitives.add(axisArrowX)
this.viwer.scene.primitives.add(axisArrowY)
this.viwer.scene.primitives.add(axisArrowZ)
// this.viwer.scene.primitives.add(axisCircular)
this.againArrow()
// this.viwer.entities.add({
// id: "tool-position_plane_xy",
// rectangle: {
// coordinates: new Cesium.CallbackProperty(function () {
// return Cesium.Rectangle.fromCartesianArray([positionX, positionY])
// }, false),
// material: Cesium.Color.YELLOW.withAlpha(0),
// }
// });
// 监听相机移动
this.viwer.camera.percentageChanged = 0.001
this.viwer.camera.changed.addEventListener(this.againArrow, { _that: this });
let coordinatesDiffer = { x: 0, y: 0 }
let lastPickTime = 0;
let timeoutEvent
this.MapEvent.mouse_move((e, cartesian) => {
moveEvent(e)
})
function moveEvent(movement) {
if (!_this.activeAxis) {
const now = Date.now();
if (now - lastPickTime < 100) {
clearTimeout(timeoutEvent)
timeoutEvent = setTimeout(() => {
moveEvent(movement)
}, 100);
return
}
clearTimeout(timeoutEvent)
lastPickTime = now;
let primitives = _this.coordArrows
for (let i = 0; i < primitives.length; i++) {
if (primitives[i].getGeometryInstanceAttributes) {
switch (primitives[i]._name) {
case 'model_edit_xAxis':
primitives[i].appearance = new Cesium.PolylineMaterialAppearance({
material: Cesium.Material.fromType(Cesium.Material.PolylineArrowType, {
color: Cesium.Color.RED,
}),
translucent: true,
renderState: {
depthTest: {
enabled: false,
},
depthMask: false,
depthFunction: Cesium.DepthFunction.ALWAYS,
},
})
break;
case 'model_edit_yAxis':
primitives[i].appearance = new Cesium.PolylineMaterialAppearance({
material: Cesium.Material.fromType(Cesium.Material.PolylineArrowType, {
color: Cesium.Color.LIME,
}),
translucent: true,
renderState: {
depthTest: {
enabled: false,
},
depthMask: false,
depthFunction: Cesium.DepthFunction.ALWAYS,
},
})
break;
case 'model_edit_zAxis':
primitives[i].appearance = new Cesium.PolylineMaterialAppearance({
material: Cesium.Material.fromType(Cesium.Material.PolylineArrowType, {
color: Cesium.Color.BLUE,
}),
translucent: true,
renderState: {
depthTest: {
enabled: false,
},
depthMask: false,
depthFunction: Cesium.DepthFunction.ALWAYS,
},
})
break;
default:
}
}
}
let pickedObjectArray = _this.viwer.scene.drillPick(movement.endPosition, 10);
for (let i = pickedObjectArray.length - 1; i >= 0; i--) {
let pick = pickedObjectArray[i]
if (pick && pick.primitive && pick.id) {
switch (pick.primitive._name) {
case 'model_edit_xAxis':
case 'model_edit_yAxis':
case 'model_edit_zAxis':
pick.primitive.appearance = new Cesium.PolylineMaterialAppearance({
material: Cesium.Material.fromType(Cesium.Material.PolylineArrowType, {
color: Cesium.Color.YELLOW,
}),
translucent: true,
renderState: {
depthTest: {
enabled: false,
},
depthMask: false,
depthFunction: Cesium.DepthFunction.ALWAYS,
},
})
return
default:
}
}
}
}
else {
let y = movement.startPosition.y - movement.endPosition.y //负数往下
let endPosition = { x: movement.endPosition.x - coordinatesDiffer.x, y: movement.endPosition.y - coordinatesDiffer.y }
let ray = viewer.camera.getPickRay(endPosition);//获取一条射线
let position = viewer.scene.globe.pick(ray, viewer.scene);
let finalPosition = new Cesium.Cartesian3();
let matrix4 = Cesium.Transforms.eastNorthUpToFixedFrame(viewer.camera.position);
Cesium.Matrix4.inverse(matrix4, matrix4);
Cesium.Matrix4.multiplyByPoint(matrix4, position, finalPosition);
Cesium.Cartesian3.normalize(finalPosition, finalPosition);
let param = _this.initParam()
let pitch = 90 + Cesium.Math.toDegrees(Math.asin(finalPosition.z))
let camera_cartographic = Cesium.Cartographic.fromCartesian(viewer.camera.position);
let a = camera_cartographic.height
let b = _this.activeModelParam.alt
// let d = Cesium.Cartesian3.distance(viewer.camera.position, position);
let d = a / Math.cos(Cesium.Math.toRadians(pitch))
let geodesic = new Cesium.EllipsoidGeodesic(Cesium.Cartographic.fromCartesian(position), Cesium.Cartographic.fromCartesian(viewer.camera.position))
position = Cesium.Ray.getPoint(ray, d * (1 - (b / a)))
let cartographic = Cesium.Cartographic.fromCartesian(position);
let lng = Cesium.Math.toDegrees(cartographic.longitude); // 经度
let lat = Cesium.Math.toDegrees(cartographic.latitude); // 纬度
let m
switch (_this.activeAxis._name) {
case 'model_edit_xAxis':
_this._params.tx = lng
_this._params.ty = _this.activeModelParam.lat
_this._params.tz = b
_this.origin = Cesium.Cartesian3.fromDegrees(param.lng, param.lat, param.alt)
// 计算xyz轴方向
const directionVectorX = Cesium.Cartesian3.normalize(Cesium.Cartesian3.subtract(_this.origin, Cesium.Cartesian3.fromDegrees(param.lng - 0.001, param.lat, param.alt), new Cesium.Cartesian3()), new Cesium.Cartesian3());
const directionVectorY = Cesium.Cartesian3.normalize(Cesium.Cartesian3.subtract(_this.origin, Cesium.Cartesian3.fromDegrees(param.lng, param.lat - 0.001, param.alt), new Cesium.Cartesian3()), new Cesium.Cartesian3());
const directionVectorZ = Cesium.Cartesian3.normalize(Cesium.Cartesian3.subtract(_this.origin, Cesium.Cartesian3.fromDegrees(param.lng, param.lat, param.alt - 1), new Cesium.Cartesian3()), new Cesium.Cartesian3());
_this.rayX = new Cesium.Ray(_this.origin, directionVectorX)
_this.rayY = new Cesium.Ray(_this.origin, directionVectorY)
_this.rayZ = new Cesium.Ray(_this.origin, directionVectorZ)
break
case 'model_edit_yAxis':
_this._params.tx = _this.activeModelParam.lng
_this._params.ty = lat
_this._params.tz = b
_this.origin = Cesium.Cartesian3.fromDegrees(param.lng, param.lat, param.alt)
// 计算xyz轴方向
const directionVectorX2 = Cesium.Cartesian3.normalize(Cesium.Cartesian3.subtract(_this.origin, Cesium.Cartesian3.fromDegrees(param.lng - 0.001, param.lat, param.alt), new Cesium.Cartesian3()), new Cesium.Cartesian3());
const directionVectorY2 = Cesium.Cartesian3.normalize(Cesium.Cartesian3.subtract(_this.origin, Cesium.Cartesian3.fromDegrees(param.lng, param.lat - 0.001, param.alt), new Cesium.Cartesian3()), new Cesium.Cartesian3());
const directionVectorZ2 = Cesium.Cartesian3.normalize(Cesium.Cartesian3.subtract(_this.origin, Cesium.Cartesian3.fromDegrees(param.lng, param.lat, param.alt - 1), new Cesium.Cartesian3()), new Cesium.Cartesian3());
_this.rayX = new Cesium.Ray(_this.origin, directionVectorX2)
_this.rayY = new Cesium.Ray(_this.origin, directionVectorY2)
_this.rayZ = new Cesium.Ray(_this.origin, directionVectorZ2)
break
case 'model_edit_zAxis':
_this.activeModelParam.alt += (Cesium.Cartesian3.distance(viewer.camera.position, Cesium.Cartesian3.fromDegrees(_this.options.position.lng, _this.options.position.lat, _this.options.position.alt)) / 4300) * y * 3
_this._params.tx = _this.activeModelParam.lng
_this._params.ty = _this.activeModelParam.lat
_this._params.tz = _this.activeModelParam.alt
_this.origin = Cesium.Cartesian3.fromDegrees(param.lng, param.lat, _this.activeModelParam.alt)
// 计算xyz轴方向
const directionVectorX3 = Cesium.Cartesian3.normalize(Cesium.Cartesian3.subtract(_this.origin, Cesium.Cartesian3.fromDegrees(param.lng - 0.001, param.lat, _this.activeModelParam.alt), new Cesium.Cartesian3()), new Cesium.Cartesian3());
const directionVectorY3 = Cesium.Cartesian3.normalize(Cesium.Cartesian3.subtract(_this.origin, Cesium.Cartesian3.fromDegrees(param.lng, param.lat - 0.001, _this.activeModelParam.alt), new Cesium.Cartesian3()), new Cesium.Cartesian3());
const directionVectorZ3 = Cesium.Cartesian3.normalize(Cesium.Cartesian3.subtract(_this.origin, Cesium.Cartesian3.fromDegrees(param.lng, param.lat, _this.activeModelParam.alt - 1), new Cesium.Cartesian3()), new Cesium.Cartesian3());
_this.rayX = new Cesium.Ray(_this.origin, directionVectorX3)
_this.rayY = new Cesium.Ray(_this.origin, directionVectorY3)
_this.rayZ = new Cesium.Ray(_this.origin, directionVectorZ3)
break;
default:
}
_this.updateModel(_this._params.tx, _this._params.ty, _this._params.tz, _this._params.rx, _this._params.ry, _this._params.rz)
_this.againArrow()
}
}
this.MapEvent.mouse_left_down((event, cartesian) => {
let canvasCoordinates = viewer.scene.cartesianToCanvasCoordinates(this.origin)
coordinatesDiffer.x = event.position.x - Math.floor(canvasCoordinates.x)
coordinatesDiffer.y = event.position.y - Math.floor(canvasCoordinates.y)
let pickedObjectArray = viewer.scene.drillPick(event.position, 10);
for (let i = pickedObjectArray.length - 1; i >= 0; i--) {
let pickedObject = pickedObjectArray[i]
if (pickedObject && pickedObject.primitive && pickedObject.primitive._name) {
if (_this.activeAxis) {
_this.activeAxis = null
_this.activeModelParam = null
_this.controllerCallBack
}
else {
switch (pickedObject.primitive._name) {
case 'model_edit_xAxis':
case 'model_edit_yAxis':
case 'model_edit_zAxis':
viewer.scene.screenSpaceCameraController.enableRotate = false;
_this.activeAxis = pickedObject.primitive
_this.activeModelParam = _this.initParam()
pickedObject.primitive.appearance = new Cesium.PolylineMaterialAppearance({
material: Cesium.Material.fromType(Cesium.Material.PolylineArrowType, {
color: Cesium.Color.YELLOW,
}),
translucent: true,
renderState: {
depthTest: {
enabled: false,
},
depthMask: false,
depthFunction: Cesium.DepthFunction.ALWAYS,
},
})
return;
default:
}
}
}
}
})
this.MapEvent.mouse_left_up((event) => {
viewer.scene.screenSpaceCameraController.enableRotate = true;
for (let i = 0; i < _this.coordArrows.length; i++) {
switch (_this.coordArrows[i]._name) {
case 'model_edit_xAxis':
_this.coordArrows[i].appearance = new Cesium.PolylineMaterialAppearance({
material: Cesium.Material.fromType(Cesium.Material.PolylineArrowType, {
color: Cesium.Color.RED,
}),
translucent: true,
renderState: {
depthTest: {
enabled: false,
},
depthMask: false,
depthFunction: Cesium.DepthFunction.ALWAYS,
},
})
break;
case 'model_edit_yAxis':
_this.coordArrows[i].appearance = new Cesium.PolylineMaterialAppearance({
material: Cesium.Material.fromType(Cesium.Material.PolylineArrowType, {
color: Cesium.Color.LIME,
}),
translucent: true,
renderState: {
depthTest: {
enabled: false,
},
depthMask: false,
depthFunction: Cesium.DepthFunction.ALWAYS,
},
})
break;
case 'model_edit_zAxis':
_this.coordArrows[i].appearance = new Cesium.PolylineMaterialAppearance({
material: Cesium.Material.fromType(Cesium.Material.PolylineArrowType, {
color: Cesium.Color.BLUE,
}),
translucent: true,
renderState: {
depthTest: {
enabled: false,
},
depthMask: false,
depthFunction: Cesium.DepthFunction.ALWAYS,
},
})
break;
default:
}
}
if (_this.activeAxis) {
_this.activeAxis = null
_this.activeModelParam = null
_this.controllerCallBack
}
})
}
// 重新计算箭头位置
againArrow() {
let _that = (this._that || this)
if (!_that.origin) {
return
}
_that.initParam()
_that.origin = new Cesium.Cartesian3.fromDegrees(_that._params.tx, _that._params.ty, _that._params.tz)
let viewer = _that.viwer
// 获取相机的位置
var cameraPosition = viewer.camera.position;
// 计算相机与目标坐标之间的距离
var distance = Cesium.Cartesian3.distance(cameraPosition, _that.origin);
let scale = distance / 15
const matrix = Cesium.Transforms.eastNorthUpToFixedFrame(_that.origin)
let primitives = _that.coordArrows
for (let i = 0; i < primitives.length; i++) {
switch (primitives[i]._name) {
case 'model_edit_xAxis':
case 'model_edit_yAxis':
case 'model_edit_zAxis':
Cesium.Matrix4.multiplyByScale(matrix, new Cesium.Cartesian3(scale, scale, scale), primitives[i].modelMatrix)
break;
default:
}
}
}
//重新计算圆
againCircle() {
let _that = (this._that || this)
if (!_that.origin) {
return
}
_that.initParam()
_that.origin = new Cesium.Cartesian3.fromDegrees(_that._params.tx, _that._params.ty, _that._params.tz)
let viewer = _that.viwer
// 获取相机的位置
var cameraPosition = viewer.camera.position;
// 计算相机与目标坐标之间的距离
var distance = Cesium.Cartesian3.distance(cameraPosition, _that.origin);
let radius = distance / 15
const matrix = Cesium.Transforms.eastNorthUpToFixedFrame(_that.origin)
let primitives = _that.coordCircles
for (let i = 0; i < primitives.length; i++) {
// _that.viwer.scene.primitives.lowerToBottom(primitives[i])
switch (primitives[i]._name) {
case 'model_edit_zCircle':
case 'model_edit_yCircle':
case 'model_edit_xCircle':
let scale = radius / 20
Cesium.Matrix4.multiplyByScale(matrix, new Cesium.Cartesian3(scale, scale, scale), primitives[i].modelMatrix)
primitives[i]._radius = radius
break;
default:
}
}
}
/**
* 开始旋转编辑
*/
async editRtation() {
this.destroy()
this.activeState = 'rtation'
this.MapEvent = new MouseEvent(this.sdk)
const param = this.initParam()
this.origin = Cesium.Cartesian3.fromDegrees(param.lng, param.lat, param.alt)
this.createCircle(
param.lng,
param.lat,
param.alt,
20
)
// 监听相机移动
this.viwer.camera.percentageChanged = 0.001
this.viwer.camera.changed.addEventListener(this.againCircle, { _that: this });
}
async createCircle(lng, lat, height, radius) {
let _that = (this._that || this)
let _this = this
let viewer = this.viwer
const position = []
for (let i = 0; i <= 360; i += 3) {
const sin = Math.sin(Cesium.Math.toRadians(i))
const cos = Math.cos(Cesium.Math.toRadians(i))
const x = radius * cos
const y = radius * sin
position.push(new Cesium.Cartesian3(x, y, 0))
}
const matrix = Cesium.Transforms.eastNorthUpToFixedFrame(
new Cesium.Cartesian3.fromDegrees(lng, lat, height)
)
// 获取相机的位置
var cameraPosition = viewer.camera.position;
// 计算相机与目标坐标之间的距离
var distance = Cesium.Cartesian3.distance(cameraPosition, this.origin);
let newRadius = distance / 15
let scale = newRadius / radius
Cesium.Matrix4.multiplyByScale(matrix, new Cesium.Cartesian3(scale, scale, scale), matrix)
// Cesium.Matrix4.multiply(
// matrix,
// x,
// matrix
// )
//绕Z轴
const axisSphereZ = await this.createAxisSphere(
'model_edit_zCircle',
position,
matrix,
Cesium.Color.RED,
newRadius
)
viewer.scene.primitives.add(axisSphereZ)
//绕Y周
const axisSphereY = await this.createAxisSphere(
'model_edit_yCircle',
position,
matrix,
Cesium.Color.BLUE,
newRadius
)
viewer.scene.primitives.add(axisSphereY)
let my = Cesium.Matrix3.fromRotationY(Cesium.Math.toRadians(90))
let rotationY = Cesium.Matrix4.fromRotationTranslation(my)
Cesium.Matrix4.multiply(
axisSphereY.geometryInstances.modelMatrix,
rotationY,
axisSphereY.geometryInstances.modelMatrix
)
//绕X周
const axisSphereX = await this.createAxisSphere(
'model_edit_xCircle',
position,
matrix,
Cesium.Color.LIME,
newRadius
)
viewer.scene.primitives.add(axisSphereX)
let mx = Cesium.Matrix3.fromRotationX(Cesium.Math.toRadians(90))
let rotationX = Cesium.Matrix4.fromRotationTranslation(mx)
Cesium.Matrix4.multiply(
axisSphereX.geometryInstances.modelMatrix,
rotationX,
axisSphereX.geometryInstances.modelMatrix
)
let lastPickTime = 0;
let timeoutEvent
this.MapEvent.mouse_move((movement) => {
moveEvent(movement)
})
function moveEvent(movement) {
if (!_this.activeCircle) {
const now = Date.now();
if (now - lastPickTime < 100) {
clearTimeout(timeoutEvent)
timeoutEvent = setTimeout(() => {
moveEvent(movement)
}, 100);
return
}
clearTimeout(timeoutEvent)
lastPickTime = now;
let primitives = _that.coordCircles
for (let i = 0; i < primitives.length; i++) {
if (primitives[i].getGeometryInstanceAttributes) {
let attributes = primitives[i].getGeometryInstanceAttributes(primitives[i]._name);
switch (primitives[i]._name) {
case 'model_edit_zCircle':
attributes.color = Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.RED).value
break;
case 'model_edit_yCircle':
attributes.color = Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.BLUE).value
break;
case 'model_edit_xCircle':
attributes.color = Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.LIME).value
break;
default:
}
}
}
let pickedObjectArray = viewer.scene.drillPick(movement.endPosition, 10);
for (let i = 0; i < pickedObjectArray.length; i++) {
let pick = pickedObjectArray[i]
if (pick && pick.primitive && pick.id) {
let attributes = pick.primitive.getGeometryInstanceAttributes(pick.id);
switch (pick.primitive._name) {
case 'model_edit_zCircle':
attributes.color = Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.YELLOW).value
return;
case 'model_edit_yCircle':
attributes.color = Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.YELLOW).value
return;
case 'model_edit_xCircle':
attributes.color = Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.YELLOW).value
return;
default:
}
}
}
}
else {
let position1 = Cesium.SceneTransforms.wgs84ToWindowCoordinates(viewer.scene, _that.ciclkPosition);
let _rx = 0,
_ry = 0,
_rz = 0 //xyz方向的旋转量
if (!position1) {
return
}
const _yPix = movement.startPosition.y - movement.endPosition.y
const _xPix = movement.startPosition.x - movement.endPosition.x
switch (_this.activeCircle._name) {
case 'model_edit_xCircle':
_ry = 1 * _xPix
break;
case 'model_edit_yCircle':
_rx = 1 * _yPix
break;
case 'model_edit_zCircle':
_rz = 1 * _xPix
break;
default:
}
_this._params.rx -= _rx
if (_this._params.rx > 360) {
_this._params.rx = 1
}
if (_this._params.rx < 0) {
_this._params.rx = 360
}
let mx = Cesium.Matrix3.fromRotationX(
Cesium.Math.toRadians(_this._params.rx)
)
_this._params.ry -= _ry
if (_this._params.ry > 360) {
_this._params.ry = 1
}
if (_this._params.ry < 0) {
_this._params.ry = 360
}
_this._params.rz -= _rz
if (_this._params.rz > 360) {
_this._params.rz = 1
}
if (_this._params.rz < 0) {
_this._params.rz = 360
}
_this.updateModel(_this._params.tx, _this._params.ty, _this._params.tz, _this._params.rx, _this._params.ry, _this._params.rz)
}
}
this.MapEvent.mouse_left_down((event) => {
let cartesian = viewer.scene.pickPosition(event.position);
_that.ciclkPosition = cartesian
let pickedObjectArray = viewer.scene.drillPick(event.position, 10);
for (let i = 0; i < pickedObjectArray.length; i++) {
let pickedObject = pickedObjectArray[i]
if (pickedObject && pickedObject.primitive && pickedObject.id) {
switch (pickedObject.primitive._name) {
case 'model_edit_xCircle':
case 'model_edit_yCircle':
case 'model_edit_zCircle':
viewer.scene.screenSpaceCameraController.enableRotate = false;
let attributes = pickedObject.primitive.getGeometryInstanceAttributes(pickedObject.primitive._name);
attributes.color = Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.YELLOW).value
_this.activeCircle = pickedObject.primitive
_this.activeModelParam = _this.initParam()
return;
default:
}
}
}
_this.activeCircle = null
_this.activeModelParam = null
viewer.scene.screenSpaceCameraController.enableRotate = true
})
this.MapEvent.mouse_left_up((event) => {
viewer.scene.screenSpaceCameraController.enableRotate = true;
let primitives = _this.coordCircles
_this.activeCircle = null
_this.activeModelParam = null
for (let i = 0; i < primitives.length; i++) {
if (primitives[i].getGeometryInstanceAttributes) {
let attributes = primitives[i].getGeometryInstanceAttributes(primitives[i]._name);
switch (primitives[i]._name) {
case 'model_edit_zCircle':
attributes.color = Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.RED).value
break;
case 'model_edit_yCircle':
attributes.color = Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.BLUE).value
break;
case 'model_edit_xCircle':
attributes.color = Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.LIME).value
break;
default:
}
}
}
})
}
//更新模型位置
updateModel(_tx, _ty, _tz, _rx = 0, _ry = 0, _rz = 0) {
this._params.tx = _tx = parseFloat(parseFloat(_tx).toFixed(8))
this._params.ty = _ty = parseFloat(parseFloat(_ty).toFixed(8))
this._params.tz = _tz = parseFloat(parseFloat(_tz).toFixed(2))
this._params.rx = _rx = parseFloat(_rx)
this._params.ry = _ry = parseFloat(_ry)
this._params.rz = _rz = parseFloat(_rz)
this.options.position.lng = _tx
this.options.position.lat = _ty
this.options.position.alt = _tz
this.options.rotate = { x: _rx, y: _ry, z: _rz }
// this.model.position = new Cesium.Cartesian3.fromDegrees(_tx, _ty, _tz)
// this.model.rotate = { x: _rx, y: _ry, z: _rz }
// 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, this.model.modelMatrix)
this.controllerCallBack
}
set controllerCallBack(callback) {
this._controllerCallBack = callback
}
get controllerCallBack() {
this._controllerCallBack && this._controllerCallBack(this.options, this.activeAxis ? false : true)
}
createAxisArrow(name, position, matrix, color) {
let result = new Cesium.Primitive({
geometryInstances: new Cesium.GeometryInstance({
id: name,
geometry: new Cesium.PolylineGeometry({
positions: position,
width: 20
}),
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(color)
}
}),
releaseGeometryInstances: false,
appearance: new Cesium.PolylineMaterialAppearance({
material: Cesium.Material.fromType(Cesium.Material.PolylineArrowType, {
color: color,
}),
translucent: true,
renderState: {
depthTest: {
enabled: false,
},
depthMask: false,
depthFunction: Cesium.DepthFunction.ALWAYS,
},
}),
modelMatrix: matrix
})
result._name = name
this.coordArrows.push(result)
return result
}
createAxisCircular(name, position, matrix, color) {
let result = new Cesium.Primitive({
geometryInstances: new Cesium.GeometryInstance({
geometry: new Cesium.EllipseGeometry(
{
center: { x: 1, y: 1, z: 1 },
semiMinorAxis: 500000.0,
semiMajorAxis: 1000000.0,
rotation: Cesium.Math.PI_OVER_FOUR,
vertexFormat: Cesium.VertexFormat.POSITION_AND_ST
}
)
}),
releaseGeometryInstances: false,
appearance: new Cesium.EllipsoidSurfaceAppearance({
material: new Cesium.Material({
fabric: {
type: 'Color',
uniforms: {
color: Cesium.Color.YELLOW
}
}
})
}),
modelMatrix: matrix
})
result._name = name
this.coordArrows.push(result)
return result
}
createAxisSphere(name, position, matrix, color, radius) {
let result = new Cesium.Primitive({
geometryInstances: new Cesium.GeometryInstance({
id: name,
geometry: new Cesium.PolylineGeometry({
positions: position,
width: 5
}),
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(color)
}
}),
releaseGeometryInstances: false,
appearance: new Cesium.PolylineColorAppearance({
translucent: true,
renderState: {
depthTest: {
enabled: false,
},
depthMask: false,
depthFunction: Cesium.DepthFunction.ALWAYS,
},
}),
modelMatrix: matrix
})
result._radius = radius
result._name = name
this.coordCircles.push(result)
return result
}
removeCoordArrows() {
for (let i = 0; i < this.coordArrows.length; i++) {
this.viwer.scene.primitives.remove(this.coordArrows[i])
}
this.coordArrows = []
}
removeCoordCircle() {
for (let i = 0; i < this.coordCircles.length; i++) {
this.viwer.scene.primitives.remove(this.coordCircles[i])
}
this.coordCircles = []
}
removeAllTools() {
this.removeCoordArrows()
this.removeCoordCircle()
}
/**
* 关闭/注销
*/
destroy() {
this.removeAllTools()
this.activeAxis = undefined
this.activeState = undefined
this.MapEvent && this.MapEvent.destroy()
this.viwer.camera.changed.removeEventListener(this.againArrow)
this.viwer.camera.changed.removeEventListener(this.againCircle)
}
getActiveState() {
return this.activeState
}
update() {
this.againArrow()
this.againCircle()
}
}
export default ControllerObject

View File

@ -0,0 +1,88 @@
import { getHost, getToken } from "../../../on";
import BaseLoadObjModel from '../../../Obj/Base/LoadObjModel'
import LoadObjModel from '../LoadObjModel'
export default class BatchLoadObjModel {
constructor(sdk, options = {}) {
this.sdk = sdk
this.options = { ...options }
this.options.show = (options.show || options.show === false) ? options.show : true
this.options.host = this.options.host || getHost()
this.objModelObject = []
this._loaded = false
this._loadEvent = void 0
this.on()
}
get show() {
return this.options.show
}
set show(v) {
if (typeof v === "boolean") {
this.options.show = v
for (let i = 0; i < this.objModelObject.length; i++) {
this.objModelObject[i].load(() => {
this.objModelObject[i].show = v
})
}
} else {
console.error("参数必须为boolean")
}
}
async on() {
let url = ""
if (this.options.host.endsWith("yjearth4.0"))
url = this.options.host + '/api/v1/source/obj'
else
url = this.options.host + '/yjearth4.0/api/v1/source/obj'
if (this.options.code) {
url = url + '?code=' + this.options.code
}
const res = await fetch(url, {
method: 'get',
headers: {
'Content-Type': 'application/json',
"token": getToken(),
"Authorization": "Bearer " + getToken(),
}
});
if (res.ok) {
this.objModelObject = []
this.list = (await res.json()).data;
if (this.options.count) {
this.list = this.list.splice(0, this.options.count)
}
for (let i = 0; i < this.list.length; i++) {
let options = JSON.parse(this.list[i].detail)
options.host = this.options.host
if (this.options.show || this.options.show === false) {
options.show = this.options.show
}
let object = new LoadObjModel(this.sdk, options);
this.objModelObject.push(object)
}
this._loaded = true
if (this._loadEvent) {
this._loadEvent()
}
}
}
remove() {
for (let i = 0; i < this.objModelObject.length; i++) {
this.objModelObject[i].load(() => {
this.objModelObject[i].remove()
})
}
}
load(callback) {
if (this._loaded) {
callback();
}
else {
this._loadEvent = callback
}
}
}

View File

@ -0,0 +1,180 @@
import AModelLoader from '../../../Obj/Base/LoadObjModel/AModelLoader'
import { getHost, getToken } from "../../../on";
import BaseLoadObjModel from '../../../Obj/Base/LoadObjModel'
export default class LoadObjModel extends BaseLoadObjModel {
constructor(sdk, options, CallBack) {
super(sdk, options, CallBack)
this._loadEvent = void 0
this._loaded = false
this.options.objId = options.objId
this.options.videoId = options.videoId
this.options.videoType = options.videoType || 'flv'
}
async addResource() {
let that = this
that.options.xmlURL = that.options.objUrl.replace('.obj', '.xml')
if (that.options.xmlURL !== '') {
const xml = await fetch(that.options.xmlURL)
if (xml.ok) {
const xmlString = await xml.text()
const parser = new DOMParser()
const xmlDoc = parser.parseFromString(xmlString, 'text/xml')
// console.log('xmlDocxmlDocxmlDoc', xmlDoc)
const position = xmlDoc
.getElementsByTagName('Position')[0]
.textContent.split(',')
// const bbox = xmlDoc.getElementsByTagName('bbox')[0]
const crs = xmlDoc.getElementsByTagName('Crs')[0].textContent
const result = that.convert(
[{ x: position[0], y: position[1], z: position[2] }],
crs,
'EPSG:4326'
)
that.options.position = that.options.position || { lng: result.points[0].x, lat: result.points[0].y, alt: result.points[0].z }
that.ControllerObject.position = that.options.position
const scene = that.viwer.scene
const origin = Cesium.Cartesian3.fromDegrees(
that.options.position.lng,
that.options.position.lat,
that.options.position.alt
)
const obj_modelMatrix = Cesium.Transforms.headingPitchRollToFixedFrame(
origin,
new Cesium.HeadingPitchRoll(
Cesium.Math.toRadians(0.85),
Cesium.Math.toRadians(0),
Cesium.Math.toRadians(0)
)
)
let objLoader = new AModelLoader(that.viwer.scene.context)
let obj = await objLoader.Load(that.options.objUrl, that.options.videoId, that.options.host)
obj.modelMatrix = obj_modelMatrix
obj.show = that.options.show
obj.setFlvVideo(that.options.videoUrl)
scene.primitives.add(obj)
that.primitive = obj
that.controllerCallBack({
rotate: { x: that.options.roll, y: -that.options.pitch, z: -that.options.heading },
position: { ...that.options.position }
})
that.loaded = true
that._loaded = true
if (that._loadEvent) {
that._loadEvent()
}
}
} else {
return
}
if (that.options.objUrl === '') {
return
}
}
async requestResource() {
let that = this
if(!that._loaded) {
if(that.options.objId) {
that.options.objUrl = await that.requestObjResource()
}
if(that.options.videoId) {
that.options.videoUrl = await that.requestVideoResource()
}
await that.addResource()
}
}
requestObjResource() {
let host = ""
if (this.options.host.endsWith("yjearth4.0"))
host = this.options.host
else
host = this.options.host + '/yjearth4.0'
let url = host + '/obj/' + this.options.objId
return fetch(url, {
method: 'get',
headers: {
'Content-Type': 'application/json',
"token": getToken(),
"Authorization": "Bearer " + getToken(),
}
}).then(async (res) => {
let text = await res.text()
text = JSON.parse(text)
if ([0, 200].includes(text.code)) {
if (text.data.objPath.length)
return host + '/obj/wirte/file/' + text.data.objPath
else
console.warn('资源不存在')
return
} else {
console.warn(text.msg || text.message)
return
}
})
}
requestVideoResource() {
let host = ""
if (this.options.host.endsWith("yjearth4.0"))
host = this.options.host
else
host = this.options.host + '/yjearth4.0'
let url = host + '/videoFusion/' + this.options.videoId
return fetch(url, {
method: 'get',
headers: {
'Content-Type': 'application/json',
"token": getToken(),
"Authorization": "Bearer " + getToken(),
}
}).then(async (res) => {
let text = await res.text()
text = JSON.parse(text)
if ([0, 200].includes(text.code)) {
if (text.data.deviceCode.length) {
return fetch(host+'/videoFusion/vide/stream', {
method: 'post',
body: JSON.stringify({type: 'flv', deviceCode: text.data.deviceCode}),
headers: {
'Content-Type': 'application/json',
"token": getToken(),
"Authorization": "Bearer " + getToken(),
}
}).then(async (res2) => {
let text2 = await res2.text()
text2 = JSON.parse(text2)
if ([0, 200].includes(text2.code)) {
if (text2.data.flv && text2.data.flv.length) {
return text2.data.flv
}
else
console.warn('地址不存在')
return
} else {
console.warn(text2.msg || text2.message)
return
}
})
}
else
console.warn('设备不存在')
return
} else {
console.warn(text.msg || text.message)
return
}
})
}
load(callback) {
if (this._loaded) {
callback();
}
else {
this._loadEvent = callback
}
}
}

69
src/Draw/draw.js Normal file
View File

@ -0,0 +1,69 @@
/**
* @name: draw
* @author: Administrator
* @date: 2022-06-14 16:29
* @descriptiondraw
* @update: 2022-06-14 16:29
*/
import Tools from '../Tools'
import { get2DView } from '../Global/MultiViewportMode'
class Draw extends Tools {
/**
* @constructor
* */
constructor(sdk, options = {}, is2D = false) {
super(sdk, options)
this.viewer = sdk.viewer
this.entityHasCreated = false
this.event = null
this.tip = null
this.points_ids = []
this.color = options.color || 'rgba(185,14,14,0.58)'
this._is2D = is2D
this._sdk2D = get2DView()
}
create_point(cartesian, viewer = this.viewer) {
let id = this.randomString()
viewer.entities.add(
new Cesium.Entity({
id: id,
position: cartesian,
billboard: {
image: this.getSourceRootPath() + '/img/point.png',
// verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
color: Cesium.Color.WHITE.withAlpha(0.99)
// disableDepthTestDistance: 1000000
},
})
)
return id
}
remove_entity(id) {
this.viewer.entities.removeById(id)
if (!this._is2D && this._sdk2D && this._sdk2D.viewer && this._sdk2D.viewer.entities) {
this._sdk2D.viewer.entities.removeById(id)
}
}
start() {
// this.setPickStatus(false)
}
end() {
// this.setPickStatus(true)
YJ.Measure.SetMeasureStatus(false)
this.entityHasCreated = false
this.event && this.event.destroy()
this.event2D && this.event2D.destroy()
this.tip && this.tip.destroy()
this.points_ids.forEach((id) => {
this.remove_entity(id)
})
}
}
export default Draw

595
src/Draw/drawAssemble.js Normal file
View File

@ -0,0 +1,595 @@
import MouseTip from '../MouseTip'
import MouseEvent from '../Event'
import Draw from './draw'
const transformCartesianToWGS84 = cartesian => {
let ellipsoid = Cesium.Ellipsoid.WGS84
let cartographic = ellipsoid.cartesianToCartographic(cartesian)
const x = Cesium.Math.toDegrees(cartographic.longitude)
const y = Cesium.Math.toDegrees(cartographic.latitude)
const z = cartographic.height
return { x, y, z }
}
/**
* @extends Draw*/
class DrawAssemble extends Draw {
/**
* @constructor
* @param sdk
* @param [options] {object} 面属性
* @param [options.color=rgba(185,14,14,0.58)] {object} 线属性
* */
constructor(sdk, options = {}) {
super(sdk, options)
this.points = null
this.polygonHasCreated = false
}
static polygon(that, viewer = that.viewer) {
let id = that.randomString()
return viewer.entities.add(
new Cesium.Entity({
name: 'AssemblePolygon',
id,
polygon: {
hierarchy: new Cesium.CallbackProperty(e => {
let arr = that.computeAssemble(that.positions)
for (let i = 0; i < arr.length; i++) {
if (isNaN(arr[i].x)) {
arr = []
break
}
}
return new Cesium.PolygonHierarchy(arr)
}, false),
material: Cesium.Color.fromCssColorString(that.color),
outline: true,
outlineColor: Cesium.Color.GREEN,
zIndex: 99999999
}
})
)
}
/**
* @desc 开始动态绘制面
* @method start
* @param cb {function} 回调函数
* @memberOf DrawPolygon
* @example draw.start((err,positions)=>{
*
* })
* */
start(cb) {
let that = this
// eslint-disable-next-line no-undef
if (YJ.Measure.GetMeasureStatus()) {
cb('上一次测量未结束')
} else {
super.start()
// eslint-disable-next-line no-undef
YJ.Measure.SetMeasureStatus(true)
let into
this.tip = new MouseTip('左键确定,右键取消;', that.sdk)
this.event = new MouseEvent(that.sdk)
this.positions = []
this.points_ids = [] //存放左键点击时临时添加的point的id
let cache_positions = []
let cache_84_position = []
this.anchorpoints = []
this.event.mouse_left((movement, cartesian) => {
if (into === '2D') {
return
}
into = '3D'
if (!cartesian) return
if (this.anchorpoints.length === 3) {
this.anchorpoints[1] = cartesian;
}
else {
this.anchorpoints.push(cartesian)
}
cache_positions.push(this.cartesian3Towgs84(cartesian, this.viewer))
// console.log(this.cartesian3Towgs84(cartesian))
this.points_ids.push(this.create_point(cartesian))
if (this.points_ids.length === 3) {
let array = [cache_positions[0], cache_positions[2], cache_positions[1]]
cb(null, array)
this.end()
}
})
this.event.mouse_move((movement, cartesian) => {
if (into === '2D') {
return
}
this.tip.setPosition(
cartesian,
movement.endPosition.x,
movement.endPosition.y
)
if (!cartesian || this.points_ids.length === 0) return
if (cache_positions.length > 1) {
this.positions = [cache_positions[0], this.cartesian3Towgs84(cartesian, this.viewer), cache_positions[1]]
}
else {
this.positions = [cache_positions[0], this.cartesian3Towgs84(cartesian, this.viewer)]
}
if (this.points_ids.length === 1 && !Cesium.defined(this.assemblePolygon)) {
this.assemblePolygon = DrawAssemble.polygon(this)
}
if (this.anchorpoints.length >= 2) {
if (this.points_ids.length === 1) {
let pnts = new Array();
this.positions.forEach((item) => {
pnts.push([item.lng, item.lat]);
});
let mid = P.PlotUtils.mid(pnts[0], pnts[1])
let d = P.PlotUtils.distance(pnts[0], mid) / 0.9
let pnt = P.PlotUtils.getThirdPoint(pnts[0], mid, P.Constants.HALF_PI, d, true)
this.positions = [this.positions[0], { lng: pnt[0], lat: pnt[1] }, this.positions[1]];
}
//替换中间点
this.anchorpoints[1] = cartesian;
}
else {
this.anchorpoints.push(cartesian)
}
})
this.event.mouse_right((movement, cartesian) => {
if (into === '2D') {
return
}
cb(null)
this.end()
})
this.event.gesture_pinck_start((movement, cartesian) => {
if (into === '2D') {
return
}
let startTime = new Date()
this.event.gesture_pinck_end(() => {
let endTime = new Date()
if (endTime - startTime >= 500) {
this.end()
cb(false)
}
else {
if (this.anchorpoints.length === 2) {
this.anchorpoints.push(cartesian)
cb(null, this.positions)
this.end()
}
else {
if (!cartesian || Cesium.defined(this.assemblePolygon)) return
this.tip.setPosition(
cartesian,
(movement.position1.x + movement.position2.x) / 2,
(movement.position1.y + movement.position2.y) / 2
)
this.anchorpoints.push(cartesian)
this.assemblePolygon = DrawAssemble.polygon(this)
cache_positions.push(this.cartesian3Towgs84(cartesian))
// console.log(this.cartesian3Towgs84(cartesian))
this.points_ids.push(this.create_point(cartesian))
}
}
})
})
if (!this._is2D && this._sdk2D) {
this.event2D = new MouseEvent(this._sdk2D)
this.event2D.mouse_left((movement, cartesian) => {
if (into === '3D') {
return
}
into = '2D'
if (!cartesian) return
if (this.anchorpoints.length === 3) {
this.anchorpoints[1] = cartesian;
}
else {
this.anchorpoints.push(cartesian)
}
cache_positions.push(this.cartesian3Towgs84(cartesian, this.viewer))
// console.log(this.cartesian3Towgs84(cartesian))
this.points_ids.push(this.create_point(cartesian, this._sdk2D.viewer))
if (this.points_ids.length === 3) {
let array = [cache_positions[0], cache_positions[2], cache_positions[1]]
cb(null, array)
this.end()
}
})
this.event2D.mouse_move((movement, cartesian) => {
if (into === '3D') {
return
}
this.tip.setPosition(
cartesian,
movement.endPosition.x + this.viewer.canvas.width,
movement.endPosition.y
)
if (!cartesian || this.points_ids.length === 0) return
if (cache_positions.length > 1) {
this.positions = [cache_positions[0], this.cartesian3Towgs84(cartesian, this.viewer), cache_positions[1]]
}
else {
this.positions = [cache_positions[0], this.cartesian3Towgs84(cartesian, this.viewer)]
}
if (this.points_ids.length === 1 && !Cesium.defined(this.assemblePolygon)) {
this.assemblePolygon = DrawAssemble.polygon(this, this._sdk2D.viewer)
}
if (this.anchorpoints.length >= 2) {
if (this.points_ids.length === 1) {
let pnts = new Array();
this.positions.forEach((item) => {
pnts.push([item.lng, item.lat]);
});
let mid = P.PlotUtils.mid(pnts[0], pnts[1])
let d = P.PlotUtils.distance(pnts[0], mid) / 0.9
let pnt = P.PlotUtils.getThirdPoint(pnts[0], mid, P.Constants.HALF_PI, d, true)
this.positions = [this.positions[0], { lng: pnt[0], lat: pnt[1] }, this.positions[1]];
}
//替换中间点
this.anchorpoints[1] = cartesian;
}
else {
this.anchorpoints.push(cartesian)
}
})
this.event2D.mouse_right((movement, cartesian) => {
if (into === '3D') {
return
}
cb(null)
this.end()
})
this.event2D.gesture_pinck_start((movement, cartesian) => {
if (into === '3D') {
return
}
let startTime = new Date()
this.event2D.gesture_pinck_end(() => {
let endTime = new Date()
if (endTime - startTime >= 500) {
this.end()
cb(false)
}
else {
if (this.anchorpoints.length === 2) {
this.anchorpoints.push(cartesian)
cb(null, this.positions)
this.end()
}
else {
if (!cartesian || Cesium.defined(this.assemblePolygon)) return
this.tip.setPosition(
cartesian,
((movement.position1.x + movement.position2.x) / 2) + this.viewer.canvas.width,
(movement.position1.y + movement.position2.y) / 2
)
this.anchorpoints.push(cartesian)
this.assemblePolygon = DrawAssemble.polygon(this, this._sdk2D.viewer)
cache_positions.push(this.cartesian3Towgs84(cartesian))
// console.log(this.cartesian3Towgs84(cartesian))
this.points_ids.push(this.create_point(cartesian, this._sdk2D.viewer))
}
}
})
})
}
}
}
end() {
super.end();
this.viewer.entities.remove(this.assemblePolygon)
if (!this._is2D && this._sdk2D) {
this._sdk2D.viewer.entities.remove(this.assemblePolygon)
}
}
// computeAssemblePoints(anchorpoints) {
// let points = []
// let originP = transformCartesianToWGS84(anchorpoints[0])
// let lastP = anchorpoints[1]
// ? transformCartesianToWGS84(anchorpoints[1])
// : { x: originP.x + 0.00001, y: originP.y + 0.00001, z: originP.z }
// let vectorOL = { x: lastP.x - originP.x, y: lastP.y - originP.y }
// let dOL = Math.sqrt(vectorOL.x * vectorOL.x + vectorOL.y * vectorOL.y)
// let v_O_P1_lr = this.calculateVector(
// vectorOL,
// Math.PI / 3,
// (Math.sqrt(3) / 12) * dOL
// )
// let originP_P1 = v_O_P1_lr[1]
// let p1 = { x: originP.x + originP_P1.x, y: originP.y + originP_P1.y }
// let p2 = { x: (originP.x + lastP.x) / 2, y: (originP.y + lastP.y) / 2 }
// let v_L_P3_lr = this.calculateVector(
// vectorOL,
// (Math.PI * 2) / 3,
// (Math.sqrt(3) / 12) * dOL
// )
// let lastP_P3 = v_L_P3_lr[1]
// let p3 = { x: lastP.x + lastP_P3.x, y: lastP.y + lastP_P3.y }
// let v_O_P5_lr = this.calculateVector(vectorOL, Math.PI / 2, (1 / 2) * dOL)
// let v_O_P5 = v_O_P5_lr[0]
// let p5 = { x: v_O_P5.x + p2.x, y: v_O_P5.y + p2.y }
// let p0 = originP
// let p4 = lastP
// points.push(p0, p1, p2, p3, p4, p5)
// const closeCardinal = this.createCloseCardinal(points)
// const fb_points = this.calculatePointsFBZ3(closeCardinal, 100)
// let result = []
// let result2 = []
// for (let index = 0; index < fb_points.length; index++) {
// const ele = fb_points[index]
// let obj = {
// lng: ele.x,
// lat: ele.y,
// alt: 0
// }
// result.push(ele.x, ele.y, 0)
// result2.push(obj)
// }
// this.position = result2
// this.points = result
// }
// computeAssemblePoints2(anchorpoints) {
// let points = anchorpoints.length;
// if (points < 2) {
// return false
// } else {
// let pnts = new Array();
// anchorpoints.forEach((item) => {
// let posLonLat = this.cartesian3Towgs84(item, this.viewer);;
// pnts.push([posLonLat.lng, posLonLat.lat]);
// });
// //console.log("pnts6666",pnts);
// // pnts.push(tailPoint);
// // pnts.push(headerPoint);
// if (pnts.length === 2) {
// let mid = P.PlotUtils.mid(pnts[0], pnts[1])
// //let d = utils.MathDistance(pnts[0], mid) / 0.9
// let d = P.PlotUtils.distance(pnts[0], mid) / 0.9
// //console.log("d",d);
// let pnt = P.PlotUtils.getThirdPoint(pnts[0], mid, P.Constants.HALF_PI, d, true)
// pnts = [pnts[0], pnt, pnts[1]];
// //console.log("pnt",pnt);
// //createPoint(Cesium.Cartesian3.fromDegrees(pnt[0], pnt[1]));
// }
// let mid = P.PlotUtils.mid(pnts[0], pnts[2])
// pnts.push(mid, pnts[0], pnts[1])
// let [normals, pnt1, pnt2, pnt3, result, result2] = [[], undefined, undefined, undefined, [], []]
// for (let i = 0; i < pnts.length - 2; i++) {
// pnt1 = pnts[i]
// pnt2 = pnts[i + 1]
// pnt3 = pnts[i + 2]
// let normalPoints = P.PlotUtils.getBisectorNormals(0.4, pnt1, pnt2, pnt3)
// normals = normals.concat(normalPoints)
// }
// let count = normals.length
// normals = [normals[count - 1]].concat(normals.slice(0, count - 1))
// for (let i = 0; i < pnts.length - 2; i++) {
// pnt1 = pnts[i]
// pnt2 = pnts[i + 1]
// result = result.concat([...pnt1, 0])
// result2.push(
// {
// lng: pnt1[0],
// lat: pnt1[1],
// alt: 0
// }
// )
// for (let t = 0; t <= P.Constants.FITTING_COUNT; t++) {
// let pnt = P.PlotUtils.getCubicValue(t / P.Constants.FITTING_COUNT, pnt1, normals[i * 2], normals[i * 2 + 1], pnt2)
// result = result.concat([...pnt, 0])
// result2.push(
// {
// lng: pnt[0],
// lat: pnt[1],
// alt: 0
// }
// )
// }
// result = result.concat([...pnt2, 0])
// result2.push(
// {
// lng: pnt2[0],
// lat: pnt2[1],
// alt: 0
// }
// )
// }
// this.position = result2
// this.points = result
// }
// }
calculateVector(v, theta, d) {
if (!theta) theta = Math.PI / 2
if (!d) d = 1
let x_1
let x_2
let y_1
let y_2
let v_l
let v_r
let d_v = Math.sqrt(v.x * v.x + v.y * v.y)
if (v.y == 0) {
x_1 = x_2 = (d_v * d * Math.cos(theta)) / v.x
if (v.x > 0) {
y_1 = Math.sqrt(d * d - x_1 * x_1)
y_2 = -y_1
} else if (v.x < 0) {
y_2 = Math.sqrt(d * d - x_1 * x_1)
y_1 = -y_2
}
v_l = { x: x_1, y: y_1 }
v_r = { x: x_2, y: y_2 }
} else {
let n = -v.x / v.y
let m = (d * d_v * Math.cos(theta)) / v.y
let a = 1 + n * n
let b = 2 * n * m
let c = m * m - d * d
x_1 = (-b - Math.sqrt(b * b - 4 * a * c)) / (2 * a)
x_2 = (-b + Math.sqrt(b * b - 4 * a * c)) / (2 * a)
y_1 = n * x_1 + m
y_2 = n * x_2 + m
if (v.y >= 0) {
v_l = { x: x_1, y: y_1 }
v_r = { x: x_2, y: y_2 }
} else if (v.y < 0) {
v_l = { x: x_2, y: y_2 }
v_r = { x: x_1, y: y_1 }
}
}
return [v_l, v_r]
}
createCloseCardinal(points) {
if (points == null || points.length < 3) {
return points
}
//获取起点,作为终点,以闭合曲线。
let lastP = points[0]
points.push(lastP)
//定义传入的点数组,将在点数组中央(每两个点)插入两个控制点
let cPoints = points
//包含输入点和控制点的数组
let cardinalPoints = []
//至少三个点以上
//这些都是相关资料测出的经验数值
//定义张力系数取值在0<t<0.5
let t = 0.4
//为端点张力系数因子取值在0<b<1
// let b = 0.5;
//误差控制是一个大于等于0的数用于三点非常趋近与一条直线时减少计算量
let e = 0.005
//传入的点数量至少有三个n至少为2
let n = cPoints.length - 1
//从开始遍历到倒数第二个,其中倒数第二个用于计算起点(终点)的插值控制点
for (let k = 0; k <= n - 1; k++) {
let p0, p1, p2
//计算起点(终点)的左右控制点
if (k == n - 1) {
//三个基础输入点
p0 = cPoints[n - 1]
p1 = cPoints[0]
p2 = cPoints[1]
} else {
p0 = cPoints[k]
p1 = cPoints[k + 1]
p2 = cPoints[k + 2]
}
//定义p1的左控制点和右控制点
let p1l = { x: undefined, y: undefined }
let p1r = { x: undefined, y: undefined }
//通过p0、p1、p2计算p1点的做控制点p1l和又控制点p1r
//计算向量p0_p1和p1_p2
let p0_p1 = { x: p1.x - p0.x, y: p1.y - p0.y }
let p1_p2 = { x: p2.x - p1.x, y: p2.y - p1.y }
//并计算模
let d01 = Math.sqrt(p0_p1.x * p0_p1.x + p0_p1.y * p0_p1.y)
let d12 = Math.sqrt(p1_p2.x * p1_p2.x + p1_p2.y * p1_p2.y)
//向量单位化
let p0_p1_1 = { x: p0_p1.x / d01, y: p0_p1.y / d01 }
let p1_p2_1 = { x: p1_p2.x / d12, y: p1_p2.y / d12 }
//计算向量p0_p1和p1_p2的夹角平分线向量
let p0_p1_p2 = { x: p0_p1_1.x + p1_p2_1.x, y: p0_p1_1.y + p1_p2_1.y }
//计算向量 p0_p1_p2 的模
let d012 = Math.sqrt(p0_p1_p2.x * p0_p1_p2.x + p0_p1_p2.y * p0_p1_p2.y)
//单位化向量p0_p1_p2
let p0_p1_p2_1 = { x: p0_p1_p2.x / d012, y: p0_p1_p2.y / d012 }
//判断p0、p1、p2是否共线这里判定向量p0_p1和p1_p2的夹角的余弦和1的差值小于e就认为三点共线
let cosE_p0p1p2 = (p0_p1_1.x * p1_p2_1.x + p0_p1_1.y * p1_p2_1.y) / 1
//共线
if (Math.abs(1 - cosE_p0p1p2) < e) {
//计算p1l的坐标
p1l.x = p1.x - p1_p2_1.x * d01 * t
p1l.y = p1.y - p1_p2_1.y * d01 * t
//计算p1r的坐标
p1r.x = p1.x + p0_p1_1.x * d12 * t
p1r.y = p1.y + p0_p1_1.y * d12 * t
}
//非共线
else {
//计算p1l的坐标
p1l.x = p1.x - p0_p1_p2_1.x * d01 * t
p1l.y = p1.y - p0_p1_p2_1.y * d01 * t
//计算p1r的坐标
p1r.x = p1.x + p0_p1_p2_1.x * d12 * t
p1r.y = p1.y + p0_p1_p2_1.y * d12 * t
}
//记录起点(终点)的左右插值控制点及倒数第二个控制点
if (k == n - 1) {
cardinalPoints[0] = p1
cardinalPoints[1] = p1r
cardinalPoints[(n - 2) * 3 + 2 + 3] = p1l
cardinalPoints[(n - 2) * 3 + 2 + 4] = cPoints[n]
} else {
//记录下这三个控制点
cardinalPoints[k * 3 + 2 + 0] = p1l
cardinalPoints[k * 3 + 2 + 1] = p1
cardinalPoints[k * 3 + 2 + 2] = p1r
}
}
return cardinalPoints
}
calculatePointsFBZ3(points, part) {
if (!part) part = 20
//获取待拆分的点
let bezierPts = []
let scale = 0.05
if (part > 0) {
scale = 1 / part
}
for (let i = 0; i < points.length - 3;) {
//起始点
let pointS = points[i]
//第一个控制点
let pointC1 = points[i + 1]
//第二个控制点
let pointC2 = points[i + 2]
//结束点
let pointE = points[i + 3]
bezierPts.push(pointS)
for (let t = 0; t < 1;) {
//三次贝塞尔曲线公式
let x =
(1 - t) * (1 - t) * (1 - t) * pointS.x +
3 * t * (1 - t) * (1 - t) * pointC1.x +
3 * t * t * (1 - t) * pointC2.x +
t * t * t * pointE.x
let y =
(1 - t) * (1 - t) * (1 - t) * pointS.y +
3 * t * (1 - t) * (1 - t) * pointC1.y +
3 * t * t * (1 - t) * pointC2.y +
t * t * t * pointE.y
let point = { x: x, y: y }
bezierPts.push(point)
t += scale
}
i += 3
if (i >= points.length) {
bezierPts.push(pointS)
}
}
return bezierPts
}
}
export default DrawAssemble

263
src/Draw/drawAttackArrow.js Normal file
View File

@ -0,0 +1,263 @@
/**
* @name: drawAttackArrow
* @author: Administrator
* @date: 2022-06-15 16:38
* @descriptiondrawAttackArrow
* @update: 2022-06-15 16:38
*/
import Draw from './draw'
import MouseTip from '../MouseTip'
import MouseEvent from '../Event'
export default class DrawAttackArrow extends Draw {
constructor(sdk, options = {}) {
super(sdk, options)
}
static create_arrow_polygon(that, viewer = that.viewer) {
that.entityHasCreated = true
let id = that.randomString()
viewer.entities.add(
new Cesium.Entity({
id: id,
polygon: {
classificationType: Cesium.ClassificationType.BOTH,
hierarchy: new Cesium.CallbackProperty((e) => {
let arr = that.computeAttackArrow(that.positions)
for (let i = 0; i < arr.length; i++) {
if (isNaN(arr[i].x)) {
arr = []
break
}
}
return new Cesium.PolygonHierarchy(arr)
}, false),
material: Cesium.Color.fromCssColorString(that.color),
zIndex: 99999999
},
})
)
return id
}
start(cb) {
if (YJ.Measure.GetMeasureStatus()) {
cb('上一次测量未结束')
} else {
super.start()
let into
YJ.Measure.SetMeasureStatus(true)
this.tip = new MouseTip('左键确定右键结束CTRL+右键撤销', this.sdk)
this.event = new MouseEvent(this.sdk)
this.positions = []
this.points_ids = [] //存放左键点击时临时添加的point的id
let cache_positions = []
let isMove = false
this.event.mouse_left((movement, cartesian) => {
if(into === '2D') {
return
}
into = '3D'
if (!this.entityHasCreated) {
let polyline_id = DrawAttackArrow.create_arrow_polygon(this)
this.points_ids.push(polyline_id)
}
this.points_ids.push(this.create_point(cartesian))
cache_positions.push(this.cartesian3Towgs84(cartesian, this.viewer))
isMove = false
})
this.event.mouse_right((movement, cartesian) => {
if(into === '2D') {
return
}
let c = []
if (this.points_ids.length > 2) {
let positions = this.viewer.entities.getById(this.points_ids[0]).polygon.hierarchy.getValue().positions
positions.forEach(it => {
c.push(this.cartesian3Towgs84(it, this.viewer))
})
}
this.end()
if (isMove) {
this.positions.pop()
}
cb(null, this.positions, c)
})
this.event.mouse_move((movement, cartesian) => {
if(into === '2D') {
return
}
isMove = true
this.positions = cache_positions.concat(
this.cartesian3Towgs84(cartesian, this.viewer)
)
this.tip.setPosition(
cartesian,
movement.endPosition.x,
movement.endPosition.y
)
})
this.event.mouse_right_keyboard_ctrl((movement, cartesian) => {
if(into === '2D') {
return
}
if (this.points_ids.length > 1) {
this.remove_entity(this.points_ids.pop()) //移除point
cache_positions.pop()
}
})
this.event.gesture_pinck_start_keyboard_ctrl(() => {
if(into === '2D') {
return
}
if (this.points_ids.length > 1) {
this.remove_entity(this.points_ids.pop()) //移除point
cache_positions.pop()
}
})
this.event.gesture_pinck_start((movement, cartesian) => {
if(into === '2D') {
return
}
let startTime = new Date()
this.event.gesture_pinck_end(() => {
let endTime = new Date()
if (endTime - startTime >= 500) {
let c = []
if (this.points_ids.length > 2) {
let positions = this.viewer.entities.getById(this.points_ids[0]).polygon.hierarchy.getValue().positions
positions.forEach(it => {
c.push(this.cartesian3Towgs84(it, this.viewer))
})
}
this.end()
cb(null, this.positions, c)
}
else {
if (!this.entityHasCreated) {
let polyline_id = DrawAttackArrow.create_arrow_polygon(this)
this.points_ids.push(polyline_id)
}
this.points_ids.push(this.create_point(cartesian))
cache_positions.push(this.cartesian3Towgs84(cartesian, this.viewer))
this.positions = cache_positions.concat(
this.cartesian3Towgs84(cartesian, this.viewer)
)
this.tip.setPosition(
cartesian,
(movement.position1.x + movement.position2.x) / 2,
(movement.position1.y + movement.position2.y) / 2
)
}
})
})
if (!this._is2D && this._sdk2D) {
this.event2D = new MouseEvent(this._sdk2D)
this.event2D.mouse_left((movement, cartesian) => {
if(into === '3D') {
return
}
into = '2D'
if (!this.entityHasCreated) {
let polyline_id = DrawAttackArrow.create_arrow_polygon(this, this._sdk2D.viewer)
this.points_ids.push(polyline_id)
}
this.points_ids.push(this.create_point(cartesian, this._sdk2D.viewer))
cache_positions.push(this.cartesian3Towgs84(cartesian, this.viewer))
isMove = false
})
this.event2D.mouse_right((movement, cartesian) => {
if(into === '3D') {
return
}
let c = []
if (this.points_ids.length > 2) {
let positions = this.event2D.viewer.entities.getById(this.points_ids[0]).polygon.hierarchy.getValue().positions
positions.forEach(it => {
c.push(this.cartesian3Towgs84(it, this.viewer))
})
}
this.end()
if (isMove) {
this.positions.pop()
}
cb(null, this.positions, c)
})
this.event2D.mouse_move((movement, cartesian) => {
if(into === '3D') {
return
}
isMove = true
this.positions = cache_positions.concat(
this.cartesian3Towgs84(cartesian, this.viewer)
)
this.tip.setPosition(
cartesian,
movement.endPosition.x + this.viewer.canvas.width,
movement.endPosition.y
)
})
this.event2D.mouse_right_keyboard_ctrl((movement, cartesian) => {
if(into === '3D') {
return
}
if (this.points_ids.length > 1) {
this.remove_entity(this.points_ids.pop()) //移除point
cache_positions.pop()
}
})
this.event2D.gesture_pinck_start_keyboard_ctrl(() => {
if(into === '3D') {
return
}
if (this.points_ids.length > 1) {
this.remove_entity(this.points_ids.pop()) //移除point
cache_positions.pop()
}
})
this.event2D.gesture_pinck_start((movement, cartesian) => {
if(into === '3D') {
return
}
let startTime = new Date()
this.event2D.gesture_pinck_end(() => {
let endTime = new Date()
if (endTime - startTime >= 500) {
let c = []
if (this.points_ids.length > 2) {
let positions = this.viewer.entities.getById(this.points_ids[0]).polygon.hierarchy.getValue().positions
positions.forEach(it => {
c.push(this.cartesian3Towgs84(it, this.viewer))
})
}
this.end()
cb(null, this.positions, c)
}
else {
if (!this.entityHasCreated) {
let polyline_id = DrawAttackArrow.create_arrow_polygon(this, this._sdk2D.viewer)
this.points_ids.push(polyline_id)
}
this.points_ids.push(this.create_point(cartesian, this._sdk2D.viewer))
cache_positions.push(this.cartesian3Towgs84(cartesian, this.viewer))
this.positions = cache_positions.concat(
this.cartesian3Towgs84(cartesian, this.viewer)
)
this.tip.setPosition(
cartesian,
((movement.position1.x + movement.position2.x) / 2) + this.viewer.canvas.width,
(movement.position1.y + movement.position2.y) / 2
)
}
})
})
}
}
}
}

271
src/Draw/drawCircle.js Normal file
View File

@ -0,0 +1,271 @@
/**
* @name: drawCircle
* @author: Administrator
* @date: 2022-06-15 14:55
* @descriptiondrawCircle
* @update: 2022-06-15 14:55
*/
import Draw from './draw'
import MouseTip from '../MouseTip'
import MouseEvent from '../Event'
export default class DrawCircle extends Draw {
constructor(sdk, options = {}) {
super(sdk, options)
}
start(cb) {
if (YJ.Measure.GetMeasureStatus()) {
cb('上一次测量未结束')
} else {
super.start()
let into
YJ.Measure.SetMeasureStatus(true)
this.tip = new MouseTip('左键开始,右键取消', this.sdk)
this.event = new MouseEvent(this.sdk)
let clickNum = 0
this.circle_id = this.randomString() //圆id
let radius_points = []
let cache_points = []
let radius = 1 //默认半径
let positions = []
let center = {}
let endpoint = null
this.event.mouse_left((movement, cartesian) => {
if(into === '2D') {
return
}
into = '3D'
this.tip.set_text('再次左键,完成绘制;右键取消')
clickNum++
if (clickNum === 1) {
this.point_id = this.create_point(cartesian)
center = this.cartesian3Towgs84(cartesian, this.viewer)
positions = this.createCircle(center, 0.01)
cache_points.push(cartesian)
createCirclePolygon()
}
if (clickNum === 2) {
radius_points = cache_points.concat(cartesian)
endpoint = this.cartesian3Towgs84(cartesian, this.viewer)
radius = this.computeDistance([center, endpoint])
positions = this.createCircle(center, radius)
this.end()
cb(null, { center, radius: Number(radius) })
}
})
this.event.mouse_right((movement, cartesian) => {
if(into === '2D') {
return
}
this.end()
cb(false)
})
this.event.mouse_move((movement, cartesian) => {
if(into === '2D') {
return
}
this.tip.setPosition(
cartesian,
movement.endPosition.x,
movement.endPosition.y
)
if (clickNum) {
radius_points = cache_points.concat(cartesian)
endpoint = this.cartesian3Towgs84(cartesian, this.viewer)
radius = this.computeDistance([center, endpoint])
positions = this.createCircle(center, radius)
}
})
this.event.gesture_pinck_start((movement, cartesian) => {
if(into === '2D') {
return
}
let startTime = new Date()
this.event.gesture_pinck_end(() => {
let endTime = new Date()
if (endTime - startTime >= 500) {
this.end()
cb(false)
}
else {
this.tip.set_text('再次左键,完成绘制;右键取消')
clickNum++
if (clickNum === 1) {
this.point_id = this.create_point(cartesian)
center = this.cartesian3Towgs84(cartesian, this.viewer)
cache_points.push(cartesian)
createCirclePolygon()
this.tip.setPosition(
cartesian,
(movement.position1.x + movement.position2.x) / 2,
(movement.position1.y + movement.position2.y) / 2
)
}
if (clickNum === 2) {
radius_points = cache_points.concat(cartesian)
endpoint = this.cartesian3Towgs84(cartesian, this.viewer)
radius = this.computeDistance([center, endpoint])
positions = this.createCircle(center, radius)
this.end()
cb(null, { center, radius: Number(radius) })
}
}
})
})
if (!this._is2D && this._sdk2D) {
this.event2D = new MouseEvent(this._sdk2D)
this.event2D.mouse_left((movement, cartesian) => {
if(into === '3D') {
return
}
into = '2D'
this.tip.set_text('再次左键,完成绘制;右键取消')
clickNum++
if (clickNum === 1) {
this.point_id = this.create_point(cartesian, this._sdk2D.viewer)
center = this.cartesian3Towgs84(cartesian, this.viewer)
positions = this.createCircle(center, 0.01)
cache_points.push(cartesian)
createCirclePolygon(this._sdk2D.viewer)
}
if (clickNum === 2) {
radius_points = cache_points.concat(cartesian)
endpoint = this.cartesian3Towgs84(cartesian, this.viewer)
radius = this.computeDistance([center, endpoint])
positions = this.createCircle(center, radius)
this.end()
cb(null, { center, radius: Number(radius) })
}
})
this.event2D.mouse_right((movement, cartesian) => {
if(into === '3D') {
return
}
this.end()
cb(false)
})
this.event2D.mouse_move((movement, cartesian) => {
if(into === '3D') {
return
}
this.tip.setPosition(
cartesian,
movement.endPosition.x + this.viewer.canvas.width,
movement.endPosition.y
)
if (clickNum) {
radius_points = cache_points.concat(cartesian)
endpoint = this.cartesian3Towgs84(cartesian, this.viewer)
radius = this.computeDistance([center, endpoint])
positions = this.createCircle(center, radius)
}
})
this.event2D.gesture_pinck_start((movement, cartesian) => {
if(into === '3D') {
return
}
let startTime = new Date()
this.event2D.gesture_pinck_end(() => {
let endTime = new Date()
if (endTime - startTime >= 500) {
this.end()
cb(false)
}
else {
this.tip.set_text('再次左键,完成绘制;右键取消')
clickNum++
if (clickNum === 1) {
this.point_id = this.create_point(cartesian, this._sdk2D.viewer)
center = this.cartesian3Towgs84(cartesian, this.viewer)
cache_points.push(cartesian)
createCirclePolygon(this._sdk2D.viewer)
this.tip.setPosition(
cartesian,
((movement.position1.x + movement.position2.x) / 2) + this.viewer.canvas.width,
(movement.position1.y + movement.position2.y) / 2
)
}
if (clickNum === 2) {
radius_points = cache_points.concat(cartesian)
endpoint = this.cartesian3Towgs84(cartesian, this.viewer)
radius = this.computeDistance([center, endpoint])
positions = this.createCircle(center, radius)
this.end()
cb(null, { center, radius: Number(radius) })
}
}
})
})
}
let that = this
function createCirclePolygon(viewer = that.viewer) {
let a = viewer.entities.add(
new Cesium.Entity({
id: that.circle_id,
position: new Cesium.CallbackProperty((e) => {
if (endpoint) {
let c = that.computeMidpoint(center, endpoint)
return Cesium.Cartesian3.fromDegrees(c.lng, c.lat, endpoint.alt)
} else {
return Cesium.Cartesian3()
}
}, false),
label: {
text: new Cesium.CallbackProperty((e) => {
if (radius > 1000) {
return '半径:' + (radius / 1000).toFixed(2) + ' 公里'
}
return '半径:' + radius + ' 米'
}, false),
font: '20px Microsoft YaHei',
distanceDisplayCondition: 10000000,
scale: 1,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
fillColor: Cesium.Color.fromCssColorString('#f5ce0a'),
style: Cesium.LabelStyle.FILL_AND_OUTLINE
},
polygon: {
classificationType: Cesium.ClassificationType.BOTH,
hierarchy: new Cesium.CallbackProperty((e) => {
return new Cesium.PolygonHierarchy(
Cesium.Cartesian3.fromDegreesArray(positions)
)
}, false),
material: Cesium.Color.fromCssColorString(that.color),
zIndex: 99999999
},
polyline: {
positions: new Cesium.CallbackProperty((e) => {
return radius_points
}, false),
width: 2,
material:
Cesium.Color.fromCssColorString('#c1c505').withAlpha(0.5),
clampToGround: true,
zIndex: 99999999
}
})
)
}
}
}
end() {
this.remove_entity(this.circle_id)
this.remove_entity(this.point_id)
YJ.Measure.SetMeasureStatus(false)
this.tip && this.tip.destroy()
this.event && this.event.destroy()
this.event2D && this.event2D.destroy()
}
}

244
src/Draw/drawElliptic.js Normal file
View File

@ -0,0 +1,244 @@
import Draw from './draw'
import MouseTip from '../MouseTip'
import MouseEvent from '../Event'
export default class DrawElliptic extends Draw {
constructor(sdk, options = {}) {
super(sdk, options)
}
start(cb) {
if (YJ.Measure.GetMeasureStatus()) {
cb('上一次测量未结束')
} else {
super.start()
let into
this.entity_ids = []
YJ.Measure.SetMeasureStatus(true)
this.tip = new MouseTip('左键开始,右键取消', this.sdk)
this.event = new MouseEvent(this.sdk)
let clickNum = 0
this.elliptic_id = this.randomString() //圆id
let radius_points = []
let cache_points = []
let cache_84_position = []
let radius = 1 //默认半径
let positions = []
let center
let semiMinorAxis = 0
let semiMajorAxis = 0
let endpoint = null
let distanceAB = 0
let distanceAC = 0
let distanceBC = 0
let bearing = 0
this.event.mouse_left((movement, cartesian) => {
if(into === '2D') {
return
}
into = '3D'
this.tip.set_text('再次左键,完成绘制;右键取消')
clickNum++
this.points_ids.push(this.create_point(cartesian))
cache_points.push(cartesian)
if (clickNum === 1) {
cache_points = [cartesian, cartesian, cartesian]
let pos84 = this.cartesian3Towgs84(cartesian, this.viewer)
center = pos84
cache_84_position = [pos84, pos84, pos84]
calculateElliptic()
createEllipticPolygon()
}
if (clickNum === 2) {
cache_points[1] = cartesian
cache_points[2] = cartesian
let pos84 = this.cartesian3Towgs84(cartesian, this.viewer)
cache_84_position[1] = pos84
cache_84_position[2] = pos84
}
if (clickNum >= 3) {
this.end()
cb(null, { center, bearing, semiMajorAxis, semiMinorAxis })
}
// if (clickNum === 2) {
// radius_points = cache_points.concat(cartesian)
// endpoint = this.cartesian3Towgs84(cartesian, this.viewer)
// radius = this.computeDistance([center, endpoint])
// positions = this.createCircle(center, radius)
// this.end()
// cb(null, { center, radius: Number(radius) })
// }
})
this.event.mouse_right((movement, cartesian) => {
if(into === '2D') {
return
}
this.end()
cb(false)
})
this.event.mouse_move((movement, cartesian) => {
if(into === '2D') {
return
}
this.tip.setPosition(
cartesian,
movement.endPosition.x,
movement.endPosition.y
)
cache_points[clickNum] = cartesian
cache_84_position[clickNum] = this.cartesian3Towgs84(cartesian, this.viewer)
if (clickNum !== 0) {
calculateElliptic()
}
})
if (!this._is2D && this._sdk2D) {
this.event2D = new MouseEvent(this._sdk2D)
this.event2D.mouse_left((movement, cartesian) => {
if(into === '3D') {
return
}
into = '2D'
this.tip.set_text('再次左键,完成绘制;右键取消')
clickNum++
this.points_ids.push(this.create_point(cartesian, this._sdk2D.viewer))
cache_points.push(cartesian)
if (clickNum === 1) {
cache_points = [cartesian, cartesian, cartesian]
let pos84 = this.cartesian3Towgs84(cartesian, this.viewer)
center = pos84
cache_84_position = [pos84, pos84, pos84]
calculateElliptic()
createEllipticPolygon(this._sdk2D.viewer)
}
if (clickNum === 2) {
cache_points[1] = cartesian
cache_points[2] = cartesian
let pos84 = this.cartesian3Towgs84(cartesian, this.viewer)
cache_84_position[1] = pos84
cache_84_position[2] = pos84
}
if (clickNum >= 3) {
this.end()
cb(null, { center, bearing, semiMajorAxis, semiMinorAxis })
}
// if (clickNum === 2) {
// radius_points = cache_points.concat(cartesian)
// endpoint = this.cartesian3Towgs84(cartesian, this.viewer)
// radius = this.computeDistance([center, endpoint])
// positions = this.createCircle(center, radius)
// this.end()
// cb(null, { center, radius: Number(radius) })
// }
})
this.event2D.mouse_right((movement, cartesian) => {
if(into === '3D') {
return
}
this.end()
cb(false)
})
this.event2D.mouse_move((movement, cartesian) => {
if(into === '3D') {
return
}
this.tip.setPosition(
cartesian,
movement.endPosition.x + this.viewer.canvas.width,
movement.endPosition.y
)
cache_points[clickNum] = cartesian
cache_84_position[clickNum] = this.cartesian3Towgs84(cartesian, this.viewer)
if (clickNum !== 0) {
calculateElliptic()
}
})
}
let that = this
function calculateElliptic() {
let pointA = Cesium.Cartesian3.fromDegrees(cache_84_position[0].lng, cache_84_position[0].lat);
let pointB = Cesium.Cartesian3.fromDegrees(cache_84_position[1].lng, cache_84_position[1].lat);
let pointC = Cesium.Cartesian3.fromDegrees(cache_84_position[2].lng, cache_84_position[2].lat);
if (clickNum === 1) {
distanceAB = Cesium.Cartesian3.distance(pointA, pointB);
semiMajorAxis = distanceAB
semiMinorAxis = semiMajorAxis / 2;
let start = { x: center.lng, y: center.lat }
let end = { x: cache_84_position[1].lng, y: cache_84_position[1].lat }
let rad = Math.PI / 180,
lat1 = start.y * rad,
lat2 = end.y * rad,
lon1 = start.x * rad,
lon2 = end.x * rad;
const a = Math.sin(lon2 - lon1) * Math.cos(lat2);
const b =
Math.cos(lat1) * Math.sin(lat2) -
Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon2 - lon1);
const radians = Math.atan2(a, b)
const degrees = radians % (2 * Math.PI);
bearing = 450 - ((degrees * 180) / Math.PI < 0
? 360 + (degrees * 180) / Math.PI
: (degrees * 180) / Math.PI);
}
if (clickNum === 2) {
distanceAC = Cesium.Cartesian3.distance(pointA, pointC);
distanceBC = Cesium.Cartesian3.distance(pointB, pointC);
let point1 = turf.point([cache_84_position[0].lng, cache_84_position[0].lat]);
let point2 = turf.point([cache_84_position[1].lng, cache_84_position[1].lat]);
let point3 = turf.point([cache_84_position[2].lng, cache_84_position[2].lat]);
const bearing1 = turf.rhumbBearing(point1, point2);
const bearing2 = turf.rhumbBearing(point2, point3);
const angleDiff = Math.abs(bearing1 - bearing2);
let finalAngle = angleDiff > 180 ? 360 - angleDiff : angleDiff;
finalAngle = 180 - finalAngle
semiMinorAxis = distanceBC * Math.sin(Cesium.Math.toRadians(finalAngle));
}
}
function createEllipticPolygon(viewer = that.viewer) {
viewer.entities.add(
new Cesium.Entity({
id: that.elliptic_id,
position: Cesium.Cartesian3.fromDegrees(center.lng, center.lat),
ellipse: {
semiMinorAxis: new Cesium.CallbackProperty((e) => {
return semiMinorAxis
}, false),
semiMajorAxis: new Cesium.CallbackProperty((e) => {
return semiMajorAxis
}, false),
granularity: Cesium.Math.toRadians(0.1),
rotation: new Cesium.CallbackProperty((e) => {
return Cesium.Math.toRadians(bearing)
}, false),
material: Cesium.Color.fromCssColorString(that.color),
zIndex: 99999999
}
})
)
}
}
}
end() {
this.remove_entity(this.elliptic_id)
this.points_ids.forEach((id) => {
this.remove_entity(id)
})
YJ.Measure.SetMeasureStatus(false)
this.tip && this.tip.destroy()
this.event && this.event.destroy()
this.event2D && this.event2D.destroy()
}
}

273
src/Draw/drawPincerArrow.js Normal file
View File

@ -0,0 +1,273 @@
/**
* @name: drawPincerArrow
* @author: Administrator
* @date: 2022-06-15 17:12
* @descriptiondrawPincerArrow
* @update: 2022-06-15 17:12
*/
import Draw from './draw'
import MouseTip from '../MouseTip'
import MouseEvent from '../Event'
export default class DrawPincerArrow extends Draw {
constructor(sdk, options = {}) {
super(sdk, options)
}
static create_arrow_polygon(that, viewer = that.viewer) {
that.entityHasCreated = true
let id = that.randomString()
viewer.entities.add(
new Cesium.Entity({
id: id,
polygon: {
classificationType: Cesium.ClassificationType.BOTH,
hierarchy: new Cesium.CallbackProperty((e) => {
let arr = that.computePincerArrow(that.positions)
for (let i = 0; i < arr.length; i++) {
if (isNaN(arr[i].x)) {
arr = []
break
}
}
return new Cesium.PolygonHierarchy(arr)
}, false),
material: Cesium.Color.fromCssColorString(that.color),
zIndex: 99999999
},
})
)
return id
}
start(cb) {
if (YJ.Measure.GetMeasureStatus()) {
cb('上一次测量未结束')
} else {
super.start()
let into
YJ.Measure.SetMeasureStatus(true)
this.tip = new MouseTip('左键确定右键取消CTRL+右键撤销', this.sdk)
this.event = new MouseEvent(this.sdk)
this.positions = []
this.points_ids = [] //存放左键点击时临时添加的point的id
let cache_positions = []
this.event.mouse_left((movement, cartesian) => {
if(into === '2D') {
return
}
into = '3D'
if (!this.entityHasCreated) {
let polyline_id = DrawPincerArrow.create_arrow_polygon(this)
this.points_ids.push(polyline_id)
}
this.points_ids.push(this.create_point(cartesian))
cache_positions.push(this.cartesian3Towgs84(cartesian, this.viewer))
if (cache_positions.length === 5) {
let c = []
if (this.points_ids.length > 2) {
let positions = this.viewer.entities.getById(this.points_ids[0]).polygon.hierarchy.getValue().positions
positions.forEach(it => {
c.push(this.cartesian3Towgs84(it, this.viewer))
})
}
this.end()
cb(null, cache_positions, c)
}
})
this.event.mouse_right((movement, cartesian) => {
if(into === '2D') {
return
}
this.end()
cb('取消绘制')
})
this.event.mouse_move((movement, cartesian) => {
if(into === '2D') {
return
}
this.positions = cache_positions.concat(
this.cartesian3Towgs84(cartesian, this.viewer)
)
this.tip.setPosition(
cartesian,
movement.endPosition.x,
movement.endPosition.y
)
})
this.event.mouse_right_keyboard_ctrl((movement, cartesian) => {
if(into === '2D') {
return
}
if (this.points_ids.length > 1) {
this.remove_entity(this.points_ids.pop()) //移除point
cache_positions.pop()
}
})
this.event.gesture_pinck_start_keyboard_ctrl(() => {
if(into === '2D') {
return
}
if (this.points_ids.length > 1) {
this.remove_entity(this.points_ids.pop()) //移除point
cache_positions.pop()
this.positions = cache_positions.concat(
this.cartesian3Towgs84(cartesian, this.viewer)
)
}
})
this.event.gesture_pinck_start((movement, cartesian) => {
if(into === '2D') {
return
}
let startTime = new Date()
this.event.gesture_pinck_end(() => {
let endTime = new Date()
if (endTime - startTime >= 500) {
this.end()
cb('取消绘制')
}
else {
if (!this.entityHasCreated) {
let polyline_id = DrawPincerArrow.create_arrow_polygon(this)
this.points_ids.push(polyline_id)
}
this.points_ids.push(this.create_point(cartesian))
cache_positions.push(this.cartesian3Towgs84(cartesian, this.viewer))
this.positions = cache_positions.concat(
this.cartesian3Towgs84(cartesian, this.viewer)
)
this.tip.setPosition(
cartesian,
(movement.position1.x + movement.position2.x) / 2,
(movement.position1.y + movement.position2.y) / 2
)
if (cache_positions.length === 5) {
let c = []
if (this.points_ids.length > 2) {
let positions = this.viewer.entities.getById(this.points_ids[0]).polygon.hierarchy.getValue().positions
positions.forEach(it => {
c.push(this.cartesian3Towgs84(it, this.viewer))
})
}
this.end()
cb(null, cache_positions, c)
}
}
})
})
if (!this._is2D && this._sdk2D) {
this.event2D = new MouseEvent(this._sdk2D)
this.event2D.mouse_left((movement, cartesian) => {
if(into === '3D') {
return
}
into = '2D'
if (!this.entityHasCreated) {
let polyline_id = DrawPincerArrow.create_arrow_polygon(this, this._sdk2D.viewer)
this.points_ids.push(polyline_id)
}
this.points_ids.push(this.create_point(cartesian, this._sdk2D.viewer))
cache_positions.push(this.cartesian3Towgs84(cartesian, this.viewer))
if (cache_positions.length === 5) {
let c = []
if (this.points_ids.length > 2) {
let positions = this.event2D.viewer.entities.getById(this.points_ids[0]).polygon.hierarchy.getValue().positions
positions.forEach(it => {
c.push(this.cartesian3Towgs84(it, this.viewer))
})
}
this.end()
cb(null, cache_positions, c)
}
})
this.event2D.mouse_right((movement, cartesian) => {
if(into === '3D') {
return
}
this.end()
cb('取消绘制')
})
this.event2D.mouse_move((movement, cartesian) => {
if(into === '3D') {
return
}
this.positions = cache_positions.concat(
this.cartesian3Towgs84(cartesian, this.viewer)
)
this.tip.setPosition(
cartesian,
movement.endPosition.x + this.viewer.canvas.width,
movement.endPosition.y
)
})
this.event2D.mouse_right_keyboard_ctrl((movement, cartesian) => {
if(into === '3D') {
return
}
if (this.points_ids.length > 1) {
this.remove_entity(this.points_ids.pop()) //移除point
cache_positions.pop()
}
})
this.event2D.gesture_pinck_start_keyboard_ctrl(() => {
if(into === '3D') {
return
}
if (this.points_ids.length > 1) {
this.remove_entity(this.points_ids.pop()) //移除point
cache_positions.pop()
this.positions = cache_positions.concat(
this.cartesian3Towgs84(cartesian, this.viewer)
)
}
})
this.event2D.gesture_pinck_start((movement, cartesian) => {
if(into === '3D') {
return
}
let startTime = new Date()
this.event2D.gesture_pinck_end(() => {
let endTime = new Date()
if (endTime - startTime >= 500) {
this.end()
cb('取消绘制')
}
else {
if (!this.entityHasCreated) {
let polyline_id = DrawPincerArrow.create_arrow_polygon(this, this._sdk2D.viewer)
this.points_ids.push(polyline_id)
}
this.points_ids.push(this.create_point(cartesian, this._sdk2D.viewer))
cache_positions.push(this.cartesian3Towgs84(cartesian, this.viewer))
this.positions = cache_positions.concat(
this.cartesian3Towgs84(cartesian, this.viewer)
)
this.tip.setPosition(
cartesian,
((movement.position1.x + movement.position2.x) / 2) + this.viewer.canvas.width,
(movement.position1.y + movement.position2.y) / 2
)
if (cache_positions.length === 5) {
let c = []
if (this.points_ids.length > 2) {
let positions = this.event2D.viewer.entities.getById(this.points_ids[0]).polygon.hierarchy.getValue().positions
positions.forEach(it => {
c.push(this.cartesian3Towgs84(it, this.viewer))
})
}
this.end()
cb(null, cache_positions, c)
}
}
})
})
}
}
}
}

116
src/Draw/drawPoint.js Normal file
View File

@ -0,0 +1,116 @@
import MouseTip from '../MouseTip'
import MouseEvent from '../Event'
import Draw from "./draw";
class DrawPoint extends Draw {
/**
* @constructor
* @desc 获取坐标点
* */
constructor(sdk, options = {}, is2D = false) {
super(sdk, options, is2D)
}
/**
* @desc 开始动态获取坐标点
* @method start
* @param cb {function} 回调函数
* @memberOf DrawPoint
* @example draw.start((err,position)=>{
*
* })
* */
start(cb) {
if (YJ.Measure.GetMeasureStatus()) {
cb('上一次测量未结束')
} else {
let car = undefined
YJ.Measure.SetMeasureStatus(true)
this.tip = new MouseTip('左键确定,右键结束;', this.sdk)
this.event = new MouseEvent(this.sdk)
this.event.mouse_left((movement, cartesian) => {
this.end()
let p = this.cartesian3Towgs84(car || cartesian, this.viewer)
cb(null, p, Cesium)
})
this.event.mouse_right((movement, cartesian) => {
this.end()
cb(false)
})
this.event.mouse_move((movement, cartesian) => {
car = cartesian
this.tip.setPosition(
cartesian,
movement.endPosition.x,
movement.endPosition.y
)
})
this.event.gesture_pinck_start((movement, cartesian) => {
let startTime = new Date()
this.event.gesture_pinck_end(() => {
let endTime = new Date()
if (endTime - startTime >= 500) {
this.end()
cb(false)
}
else {
this.end()
let p = this.cartesian3Towgs84(car || cartesian, this.viewer)
cb(null, p)
}
})
})
if (!this._is2D && this._sdk2D) {
this.event2D = new MouseEvent(this._sdk2D)
this.event2D.mouse_left((movement, cartesian) => {
this.end()
let p = this.cartesian3Towgs84(car || cartesian, this.viewer)
cb(null, p, Cesium)
})
this.event2D.mouse_right((movement, cartesian) => {
this.end()
cb(false)
})
this.event2D.mouse_move((movement, cartesian) => {
car = cartesian
this.tip.setPosition(
cartesian,
movement.endPosition.x + this.viewer.canvas.width,
movement.endPosition.y
)
})
this.event2D.gesture_pinck_start((movement, cartesian) => {
let startTime = new Date()
this.event2D.gesture_pinck_end(() => {
let endTime = new Date()
if (endTime - startTime >= 500) {
this.end()
cb(false)
}
else {
this.end()
let p = this.cartesian3Towgs84(car || cartesian, this.viewer)
cb(null, p)
}
})
})
}
}
}
end() {
YJ.Measure.SetMeasureStatus(false)
this.event && this.event.destroy()
this.event2D && this.event2D.destroy()
this.tip && this.tip.destroy()
}
}
export default DrawPoint

276
src/Draw/drawPolygon.js Normal file
View File

@ -0,0 +1,276 @@
import MouseTip from '../MouseTip'
import MouseEvent from '../Event'
import Draw from './draw'
/**
* @extends Draw*/
class DrawPolygon extends Draw {
/**
* @constructor
* @param [options] {object} 面属性
* @param [options.color=rgba(185,14,14,0.58)] {object} 线属性
* */
constructor(sdk, options = {}) {
super(sdk, options)
this.polygonHasCreated = false
}
static create_polygon(that, viewer = that.viewer) {
that.polygonHasCreated = true
let id = that.randomString()
viewer.entities.add(
new Cesium.Entity({
id: id,
polygon: {
classificationType: Cesium.ClassificationType.BOTH,
hierarchy: new Cesium.CallbackProperty((e) => {
return new Cesium.PolygonHierarchy(that.positions)
}),
material: Cesium.Color.fromCssColorString(that.color),
zIndex: 99999999
},
polyline: {
positions: new Cesium.CallbackProperty((e) => {
return that.positions.concat(that.positions[0])
}),
width: 2,
material: Cesium.Color.fromCssColorString('#c1c505').withAlpha(0.5),
clampToGround: true,
zIndex: 99999999
},
})
)
return id
}
/**
* @desc 开始动态绘制面
* @method start
* @param cb {function} 回调函数
* @memberOf DrawPolygon
* @example draw.start((err,positions)=>{
*
* })
* */
start(cb) {
if (YJ.Measure.GetMeasureStatus()) {
cb('上一次测量未结束')
} else {
this.polygonHasCreated = false
super.start()
YJ.Measure.SetMeasureStatus(true)
let into
this.tip = new MouseTip('左键确定右键结束CTRL+右键撤销', this.sdk)
this.event = new MouseEvent(this.sdk)
this.positions = []
this.points_ids = [] //存放左键点击时临时添加的point的id
let cache_positions = []
let cache_84_position = []
this.event.mouse_left((movement, cartesian) => {
if(into === '2D') {
return
}
into = '3D'
this.positions = cache_positions.concat({ ...cartesian })
this.tip.setPosition(
cartesian,
movement.position.x,
movement.position.y
)
if (!this.polygonHasCreated) {
let polyline_id = DrawPolygon.create_polygon(this)
this.points_ids.push(polyline_id)
}
cache_positions.push(cartesian)
// console.log(cache_positions)
cache_84_position.push(this.cartesian3Towgs84(cartesian, this.viewer))
// console.log(this.cartesian3Towgs84(cartesian))
this.points_ids.push(this.create_point(cartesian))
})
this.event.mouse_right((movement, cartesian) => {
if(into === '2D') {
return
}
// let positions = []
// console.log(cache_positions)
// cache_positions.forEach((item) => {
// let p = this.cartesian3Towgs84(item)
// console.log(item)
// positions.push(p)
// })
cb(null, cache_84_position)
this.end()
})
this.event.mouse_move((movement, cartesian) => {
if(into === '2D') {
return
}
this.positions = cache_positions.concat({ ...cartesian })
this.tip.setPosition(
cartesian,
movement.endPosition.x,
movement.endPosition.y
)
})
this.event.mouse_right_keyboard_ctrl((movement, cartesian) => {
if(into === '2D') {
return
}
if (this.points_ids.length > 1) {
this.remove_entity(this.points_ids.pop()) //移除point
cache_positions.pop()
cache_84_position.pop()
}
})
this.event.gesture_pinck_start_keyboard_ctrl(() => {
if(into === '2D') {
return
}
if (this.points_ids.length > 1) {
this.remove_entity(this.points_ids.pop()) //移除point
cache_positions.pop()
cache_84_position.pop()
this.positions = cache_positions.concat(cartesian)
}
})
this.event.gesture_pinck_start((movement, cartesian) => {
if(into === '2D') {
return
}
let startTime = new Date()
this.event.gesture_pinck_end(() => {
let endTime = new Date()
if (endTime - startTime >= 500) {
cb(null, cache_84_position)
this.end()
}
else {
this.tip.setPosition(
cartesian,
(movement.position1.x + movement.position2.x) / 2,
(movement.position1.y + movement.position2.y) / 2
)
if (!this.polygonHasCreated) {
let polyline_id = DrawPolygon.create_polygon(this)
this.points_ids.push(polyline_id)
}
cache_positions.push(cartesian)
// console.log(cache_positions)
cache_84_position.push(this.cartesian3Towgs84(cartesian, this.viewer))
// console.log(this.cartesian3Towgs84(cartesian))
this.points_ids.push(this.create_point(cartesian))
this.positions = cache_positions.concat(cartesian)
}
})
})
if (!this._is2D && this._sdk2D) {
this.event2D = new MouseEvent(this._sdk2D)
this.event2D.mouse_left((movement, cartesian) => {
if(into === '3D') {
return
}
into = '2D'
this.positions = cache_positions.concat({ ...cartesian })
this.tip.setPosition(
cartesian,
movement.position.x + this.viewer.canvas.width,
movement.position.y
)
if (!this.polygonHasCreated) {
let polyline_id = DrawPolygon.create_polygon(this, this._sdk2D.viewer)
this.points_ids.push(polyline_id)
}
cache_positions.push(cartesian)
// console.log(cache_positions)
cache_84_position.push(this.cartesian3Towgs84(cartesian, this.viewer))
// console.log(this.cartesian3Towgs84(cartesian))
this.points_ids.push(this.create_point(cartesian, this._sdk2D.viewer))
})
this.event2D.mouse_right((movement, cartesian) => {
if(into === '3D') {
return
}
// let positions = []
// console.log(cache_positions)
// cache_positions.forEach((item) => {
// let p = this.cartesian3Towgs84(item)
// console.log(item)
// positions.push(p)
// })
cb(null, cache_84_position)
this.end()
})
this.event2D.mouse_move((movement, cartesian) => {
if(into === '3D') {
return
}
this.positions = cache_positions.concat({ ...cartesian })
this.tip.setPosition(
cartesian,
movement.endPosition.x + this.viewer.canvas.width,
movement.endPosition.y
)
})
this.event2D.mouse_right_keyboard_ctrl((movement, cartesian) => {
if(into === '3D') {
return
}
if (this.points_ids.length > 1) {
this.remove_entity(this.points_ids.pop()) //移除point
cache_positions.pop()
cache_84_position.pop()
}
})
this.event2D.gesture_pinck_start_keyboard_ctrl(() => {
if(into === '3D') {
return
}
if (this.points_ids.length > 1) {
this.remove_entity(this.points_ids.pop()) //移除point
cache_positions.pop()
cache_84_position.pop()
this.positions = cache_positions.concat(cartesian)
}
})
this.event2D.gesture_pinck_start((movement, cartesian) => {
if(into === '3D') {
return
}
let startTime = new Date()
this.event2D.gesture_pinck_end(() => {
let endTime = new Date()
if (endTime - startTime >= 500) {
cb(null, cache_84_position)
this.end()
}
else {
this.tip.setPosition(
cartesian,
((movement.position1.x + movement.position2.x) / 2) + this.viewer.canvas.width,
(movement.position1.y + movement.position2.y) / 2
)
if (!this.polygonHasCreated) {
let polyline_id = DrawPolygon.create_polygon(this, this._sdk2D.viewer)
this.points_ids.push(polyline_id)
}
cache_positions.push(cartesian)
// console.log(cache_positions)
cache_84_position.push(this.cartesian3Towgs84(cartesian, this.viewer))
// console.log(this.cartesian3Towgs84(cartesian))
this.points_ids.push(this.create_point(cartesian, this._sdk2D.viewer))
this.positions = cache_positions.concat(cartesian)
}
})
})
}
}
}
}
export default DrawPolygon

348
src/Draw/drawPolyline.js Normal file
View File

@ -0,0 +1,348 @@
import MouseTip from '../MouseTip'
import MouseEvent from '../Event'
import Draw from './draw'
/**
* @extends Draw
*/
class DrawPolyline extends Draw {
/**
* @constructor
* @param [options] {object} 线属性
* @param [options.color=rgba(185,14,14,0.58)] {object} 线属性
*
* */
constructor(sdk, options = {}) {
super(sdk, options)
this.options.curve = options.curve || false
let number = Number(options.number)
if (!isNaN(number)) {
if (number < 2) {
this.options.number = 2
}
else {
this.options.number = number
}
}
else {
this.options.number = Infinity
}
}
static create_polyline(that, viewer = that.viewer) {
that.entityHasCreated = true
let id = that.randomString()
viewer.entities.add(
new Cesium.Entity({
id: id,
polyline: {
positions: new Cesium.CallbackProperty(() => {
if (that.options.curve) {
let positions = that.smoothHandle(that.positions)
return positions
}
else {
return that.positions
}
}, false),
width: 5,
material: Cesium.Color.fromCssColorString(that.color),
clampToGround: true,
zIndex: 99999999
}
})
)
return id
}
// 平滑处理
smoothHandle(positions) {
if (positions.length > 1) {
let newPositions = []
let time = []
for (let i = 0; i < positions.length; i++) {
time.push(i / (positions.length - 1))
}
let spline = new Cesium.CatmullRomSpline({
times: time,
points: positions
});
let length = positions.length * 20
for (let i = 0; i <= length; i++) {
let cartesian3 = spline.evaluate(i / length);
newPositions.push(cartesian3);
}
return newPositions
}
else {
return positions
}
}
/**
* @desc 开始动态获绘制线
* @method start
* @param cb {function} 回调函数
* @memberOf DrawPolyline
* @example draw.start((err,positions)=>{
*
* })
* */
start(cb) {
if (YJ.Measure.GetMeasureStatus()) {
cb('上一次测量未结束')
} else {
super.start()
let into
YJ.Measure.SetMeasureStatus(true)
this.tip = new MouseTip('左键确定右键结束CTRL+右键撤销', this.sdk)
this.event = new MouseEvent(this.sdk)
this.positions = []
this.points_ids = [] //存放左键点击时临时添加的point的id
let cache_positions = []
let car = undefined
this.event.mouse_left((movement, cartesian) => {
if(into === '2D') {
return
}
into = '3D'
this.positions = cache_positions.concat(cartesian)
this.tip.setPosition(
cartesian,
movement.position.x,
movement.position.y
)
if (!this.entityHasCreated) {
let polyline_id = DrawPolyline.create_polyline(this, this.viewer)
this.points_ids.push(polyline_id)
}
cache_positions.push(cartesian)
this.points_ids.push(this.create_point(cartesian, this.viewer))
if (cache_positions.length >= this.options.number) {
let positions = []
cache_positions.forEach((item) => {
positions.push(this.cartesian3Towgs84(item, this.viewer))
})
let smoothPos
if (this.options.curve) {
let pos = this.smoothHandle(cache_positions)
smoothPos = []
for (let i = 0; i < pos.length; i++) {
smoothPos[i] = this.cartesian3Towgs84(pos[i], this.viewer)
}
}
cb(null, positions, smoothPos)
this.end()
}
})
this.event.mouse_right((movement, cartesian) => {
if(into === '2D') {
return
}
let positions = []
cache_positions.forEach((item) => {
positions.push(this.cartesian3Towgs84(item, this.viewer))
})
let smoothPos
if (this.options.curve) {
let pos = this.smoothHandle(cache_positions)
smoothPos = []
for (let i = 0; i < pos.length; i++) {
smoothPos[i] = this.cartesian3Towgs84(pos[i], this.viewer)
}
}
cb(null, positions, smoothPos)
this.end()
})
this.event.mouse_move((movement, cartesian) => {
if(into === '2D') {
return
}
this.positions = cache_positions.concat(cartesian)
this.tip.setPosition(
cartesian,
movement.endPosition.x,
movement.endPosition.y
)
})
this.event.mouse_right_keyboard_ctrl((movement, cartesian) => {
if(into === '2D') {
return
}
if (this.points_ids.length > 1) {
this.remove_entity(this.points_ids.pop()) //移除point
cache_positions.pop()
}
})
this.event.gesture_pinck_start_keyboard_ctrl(() => {
if(into === '2D') {
return
}
if (this.points_ids.length > 1) {
this.remove_entity(this.points_ids.pop()) //移除point
cache_positions.pop()
this.positions = cache_positions.concat(cartesian)
}
})
this.event.gesture_pinck_start((movement, cartesian) => {
if(into === '2D') {
return
}
let startTime = new Date()
this.event.gesture_pinck_end(() => {
let endTime = new Date()
if (endTime - startTime >= 500) {
let positions = []
cache_positions.forEach((item) => {
positions.push(this.cartesian3Towgs84(item, this.viewer))
})
let smoothPos
if (this.options.curve) {
let pos = this.smoothHandle(cache_positions)
smoothPos = []
for (let i = 0; i < pos.length; i++) {
smoothPos[i] = this.cartesian3Towgs84(pos[i], this.viewer)
}
}
cb(null, positions, smoothPos)
this.end()
}
else {
this.tip.setPosition(
cartesian,
(movement.position1.x + movement.position2.x) / 2,
(movement.position1.y + movement.position2.y) / 2
)
if (!this.entityHasCreated) {
let polyline_id = DrawPolyline.create_polyline(this, this.viewer)
this.points_ids.push(polyline_id)
}
cache_positions.push(cartesian)
this.points_ids.push(this.create_point(cartesian, this.viewer))
this.positions = cache_positions.concat(cartesian)
}
})
})
if (!this._is2D && this._sdk2D) {
this.event2D = new MouseEvent(this._sdk2D)
this.event2D.mouse_left((movement, cartesian) => {
if(into === '3D') {
return
}
into = '2D'
this.positions = cache_positions.concat(cartesian)
this.tip.setPosition(
cartesian,
movement.position.x + this.viewer.canvas.width,
movement.position.y
)
if (!this.entityHasCreated) {
let polyline_id = DrawPolyline.create_polyline(this, this._sdk2D.viewer)
this.points_ids.push(polyline_id)
}
cache_positions.push(cartesian)
this.points_ids.push(this.create_point(cartesian, this._sdk2D.viewer))
})
this.event2D.mouse_right((movement, cartesian) => {
if(into === '3D') {
return
}
let positions = []
cache_positions.forEach((item) => {
positions.push(this.cartesian3Towgs84(item, this.viewer))
})
let smoothPos
if (this.options.curve) {
let pos = this.smoothHandle(cache_positions)
smoothPos = []
for (let i = 0; i < pos.length; i++) {
smoothPos[i] = this.cartesian3Towgs84(pos[i], this.viewer)
}
}
cb(null, positions, smoothPos)
this.end()
})
this.event2D.mouse_move((movement, cartesian) => {
if(into === '3D') {
return
}
this.positions = cache_positions.concat(cartesian)
this.tip.setPosition(
cartesian,
movement.endPosition.x + this.viewer.canvas.width,
movement.endPosition.y
)
})
this.event2D.mouse_right_keyboard_ctrl((movement, cartesian) => {
if(into === '3D') {
return
}
if (this.points_ids.length > 1) {
this.remove_entity(this.points_ids.pop()) //移除point
cache_positions.pop()
}
})
this.event2D.gesture_pinck_start_keyboard_ctrl(() => {
if(into === '3D') {
return
}
if (this.points_ids.length > 1) {
this.remove_entity(this.points_ids.pop()) //移除point
cache_positions.pop()
this.positions = cache_positions.concat(cartesian)
}
})
this.event2D.gesture_pinck_start((movement, cartesian) => {
if(into === '3D') {
return
}
let startTime = new Date()
this.event2D.gesture_pinck_end(() => {
let endTime = new Date()
if (endTime - startTime >= 500) {
let positions = []
cache_positions.forEach((item) => {
positions.push(this.cartesian3Towgs84(item, this.viewer))
})
let smoothPos
if (this.options.curve) {
let pos = this.smoothHandle(cache_positions)
smoothPos = []
for (let i = 0; i < pos.length; i++) {
smoothPos[i] = this.cartesian3Towgs84(pos[i], this.viewer)
}
}
cb(null, positions, smoothPos)
this.end()
}
else {
this.tip.setPosition(
cartesian,
((movement.position1.x + movement.position2.x) / 2) + this.viewer.canvas.width,
(movement.position1.y + movement.position2.y) / 2
)
if (!this.entityHasCreated) {
let polyline_id = DrawPolyline.create_polyline(this, this._sdk2D.viewer)
this.points_ids.push(polyline_id)
}
cache_positions.push(cartesian)
this.points_ids.push(this.create_point(cartesian, this._sdk2D.viewer))
this.positions = cache_positions.concat(cartesian)
}
})
})
}
}
}
}
export default DrawPolyline

278
src/Draw/drawRect.js Normal file
View File

@ -0,0 +1,278 @@
import MouseTip from '../MouseTip'
import MouseEvent from '../Event'
import Draw from './draw'
/**
* @extends Draw*/
class DrawRect extends Draw {
/**
* @constructor
* @param [options] {object} 面属性
* @param [options.color=rgba(185,14,14,0.58)] {object} 线属性
* */
constructor(sdk, options = {}) {
super(sdk, options)
this.rhumb = options.rhumb
this.polygonHasCreated = false
this.rect = []
this.rectObj = []
this.entity = null
}
static create_polygon(that, viewer = that.viewer) {
let id = that.randomString()
viewer.entities.add(
(this.entity = new Cesium.Entity({
id: id,
polygon: {
// classificationType: Cesium.ClassificationType.BOTH,
hierarchy: new Cesium.CallbackProperty(e => {
return new Cesium.PolygonHierarchy(
Cesium.Cartesian3.fromDegreesArray(that.rect)
)
},false),
material: Cesium.Color.fromCssColorString(that.color),
arcType: that.rhumb ? Cesium.ArcType.RHUMB : Cesium.ArcType.GEODESIC,
zIndex: 99999999
}
}))
)
return id
}
/**
* @desc 开始动态绘制面
* @method start
* @param cb {function} 回调函数
* @memberOf DrawRect
* @example draw.start((err,positions)=>{
*
* })
* */
start(cb) {
let that = this
if (YJ.Measure.GetMeasureStatus()) {
cb('上一次测量未结束')
} else {
super.start()
let into
YJ.Measure.SetMeasureStatus(true)
this.tip = new MouseTip('左键确定,右键取消', that.sdk)
this.event = new MouseEvent(that.sdk)
this.positions = []
this.points_ids = [] //存放左键点击时临时添加的point的id
let cache_positions = []
let cache_84_position = []
let cnt = 0
let firstPoint = null
let secondtPoint = null
this.event.mouse_left((movement, cartesian) => {
if(into === '2D') {
return
}
into = '3D'
cnt++
let wgs84 = this.cartesian3Towgs84(cartesian, this.viewer)
if (!this.polygonHasCreated) {
this.polygonHasCreated = true
let polyline_id = DrawRect.create_polygon(this)
this.points_ids.push(polyline_id)
firstPoint = wgs84
}
if (cnt == 2) {
secondtPoint = wgs84
this.end()
cb(null, that.rectObj, [firstPoint, secondtPoint])
}
})
this.event.mouse_right((movement, cartesian) => {
if(into === '2D') {
return
}
this.end()
cb('取消', '')
})
this.event.mouse_move((movement, cartesian) => {
if(into === '2D') {
return
}
this.tip.setPosition(
cartesian,
movement.endPosition.x,
movement.endPosition.y
)
if (cnt == 1) {
let wgs84 = this.cartesian3Towgs84(cartesian, this.viewer)
this.calrect(firstPoint, wgs84)
}
})
this.event.gesture_pinck_start((movement, cartesian) => {
if(into === '2D') {
return
}
let startTime = new Date()
this.event.gesture_pinck_end(() => {
let endTime = new Date()
if (endTime - startTime >= 500) {
cb('取消', '')
this.end()
}
else {
this.tip.setPosition(
cartesian,
(movement.position1.x + movement.position2.x) / 2,
(movement.position1.y + movement.position2.y) / 2
)
cnt++
let wgs84 = this.cartesian3Towgs84(cartesian)
if (!this.polygonHasCreated) {
this.polygonHasCreated = true
let polyline_id = DrawRect.create_polygon(this)
this.points_ids.push(polyline_id)
firstPoint = wgs84
}
if (cnt == 2) {
this.calrect(firstPoint, wgs84)
secondtPoint = wgs84
this.end()
cb(null, that.rectObj, [firstPoint, secondtPoint])
}
}
})
})
if (!this._is2D && this._sdk2D) {
this.event2D = new MouseEvent(this._sdk2D)
this.event2D.mouse_left((movement, cartesian) => {
if(into === '3D') {
return
}
into = '2D'
cnt++
let wgs84 = this.cartesian3Towgs84(cartesian, this.viewer)
if (!this.polygonHasCreated) {
this.polygonHasCreated = true
let polyline_id = DrawRect.create_polygon(this, this._sdk2D.viewer)
this.points_ids.push(polyline_id)
firstPoint = wgs84
}
if (cnt == 2) {
secondtPoint = wgs84
this.end()
cb(null, that.rectObj, [firstPoint, secondtPoint])
}
})
this.event2D.mouse_right((movement, cartesian) => {
if(into === '3D') {
return
}
this.end()
cb('取消', '')
})
this.event2D.mouse_move((movement, cartesian) => {
if(into === '3D') {
return
}
this.tip.setPosition(
cartesian,
movement.endPosition.x + this.viewer.canvas.width,
movement.endPosition.y
)
if (cnt == 1) {
let wgs84 = this.cartesian3Towgs84(cartesian, this.viewer)
this.calrect(firstPoint, wgs84)
}
})
this.event2D.gesture_pinck_start((movement, cartesian) => {
if(into === '3D') {
return
}
let startTime = new Date()
this.event2D.gesture_pinck_end(() => {
let endTime = new Date()
if (endTime - startTime >= 500) {
cb('取消', '')
this.end()
}
else {
this.tip.setPosition(
cartesian,
((movement.position1.x + movement.position2.x) / 2) + this.viewer.canvas.width,
(movement.position1.y + movement.position2.y) / 2
)
cnt++
let wgs84 = this.cartesian3Towgs84(cartesian)
if (!this.polygonHasCreated) {
this.polygonHasCreated = true
let polyline_id = DrawRect.create_polygon(this, this._sdk2D.viewer)
this.points_ids.push(polyline_id)
firstPoint = wgs84
}
if (cnt == 2) {
this.calrect(firstPoint, wgs84)
secondtPoint = wgs84
this.end()
cb(null, that.rectObj, [firstPoint, secondtPoint])
}
}
})
})
}
}
}
calrect(firstPoint, secondPoint) {
let positions = []
let arr = []
let arr2 = []
positions.push(
[firstPoint.lng, firstPoint.lat, firstPoint.alt],
[secondPoint.lng, secondPoint.lat, secondPoint.alt]
)
let bboxPolygon
if (positions.length === 2) {
let line = turf.lineString(positions)
let bbox = turf.bbox(line)
bboxPolygon = turf.bboxPolygon(bbox)
}
if (bboxPolygon) {
// console.log('bboxPolygon',bboxPolygon.geometry.coordinates[0])
bboxPolygon.geometry.coordinates[0].forEach(item => {
arr.push(item[0])
arr.push(item[1])
let obj = {
lng: item[0],
lat: item[1],
alt: firstPoint.alt
}
arr2.push(obj)
})
this.rect = [...arr]
this.rectObj = [...arr2]
this.rectObj.pop()
}
}
}
export default DrawRect

268
src/Draw/drawSector.js Normal file
View File

@ -0,0 +1,268 @@
import MouseTip from '../MouseTip'
import MouseEvent from '../Event'
import Draw from './draw'
/**
* @extends Draw*/
class DrawSector extends Draw {
constructor(sdk, options = {}) {
super(sdk, options)
}
/**
* @desc 开始动态绘制面
* @method start
* @param cb {function} 回调函数
* @memberOf DrawRect
* @example draw.start((err,positions)=>{
*
* })
* */
start(cb) {
let that = this
if (YJ.Measure.GetMeasureStatus()) {
cb('上一次测量未结束')
} else {
super.start()
let into
YJ.Measure.SetMeasureStatus(true)
this.tip = new MouseTip('左键确认,右键取消', that.sdk)
this.event = new MouseEvent(that.sdk)
this._sector_id = null; //扇形
this._positions = []; //活动点
this.points_ids = []; //脏数据
this._entities_sector = []; //脏数据
this._radius = 0; //半径
this._startAngle = 0; //起始角度
this._endAngle = 0; //结束角度
this.event.mouse_left((movement, cartesian) => {
if(into === '2D') {
return
}
into = '3D'
// if(that._positions.length == 3) return
if (this._positions.length < 3) {
this.points_ids.push(this.create_point(cartesian));
this._positions.push(this.cartesian3Towgs84(cartesian, this.viewer));
}
else {
this.end()
cb(null, { center: this._positions[0], radius: this._radius, startAngle: this._startAngle, endAngle: this._endAngle })
}
if (this._positions.length === 2) {
let pointA = Cesium.Cartesian3.fromDegrees(this._positions[0].lng, this._positions[0].lat, this._positions[0].alt);
let pointB = cartesian;
this._radius = Cesium.Cartesian3.distance(pointA, pointB);
}
})
this.event.mouse_move((movement, cartesian) => {
if(into === '2D') {
return
}
this.tip.setPosition(
cartesian,
movement.endPosition.x,
movement.endPosition.y
)
if (this._positions.length < 2) return;
if (this._positions.length == 2) {
this._positions.push(this.cartesian3Towgs84(cartesian, this.viewer));
}
if (this._positions.length == 3) {
this._positions.pop();
this._positions.push(this.cartesian3Towgs84(cartesian, this.viewer));
if (!Cesium.defined(this._sector_id)) {
this._sector_id = this.createsector();
this.points_ids.push(this._sector_id);
}
let options = that.calculateAangle(that._positions)
that._startAngle = options.angle1;
that._endAngle = options.angle2;
}
})
this.event.mouse_right((movement, cartesian) => {
if(into === '2D') {
return
}
this.end()
cb(null)
})
if (!this._is2D && this._sdk2D) {
this.event2D = new MouseEvent(this._sdk2D)
this.event2D.mouse_left((movement, cartesian) => {
if(into === '3D') {
return
}
into = '2D'
// if(that._positions.length == 3) return
if (this._positions.length < 3) {
this.points_ids.push(this.create_point(cartesian, this._sdk2D.viewer));
this._positions.push(this.cartesian3Towgs84(cartesian, this.viewer));
}
else {
this.end()
cb(null, { center: this._positions[0], radius: this._radius, startAngle: this._startAngle, endAngle: this._endAngle })
}
if (this._positions.length === 2) {
let pointA = Cesium.Cartesian3.fromDegrees(this._positions[0].lng, this._positions[0].lat, this._positions[0].alt);
let pointB = cartesian;
this._radius = Cesium.Cartesian3.distance(pointA, pointB);
}
})
this.event2D.mouse_move((movement, cartesian) => {
if(into === '3D') {
return
}
this.tip.setPosition(
cartesian,
movement.endPosition.x + this.viewer.canvas.width,
movement.endPosition.y
)
if (this._positions.length < 2) return;
if (this._positions.length == 2) {
this._positions.push(this.cartesian3Towgs84(cartesian, this.viewer));
}
if (this._positions.length == 3) {
this._positions.pop();
this._positions.push(this.cartesian3Towgs84(cartesian, this.viewer));
if (!Cesium.defined(this._sector_id)) {
this._sector_id = this.createsector(this._sdk2D.viewer);
this.points_ids.push(this._sector_id);
}
let options = that.calculateAangle(that._positions)
that._startAngle = options.angle1;
that._endAngle = options.angle2;
}
})
this.event2D.mouse_right((movement, cartesian) => {
if(into === '3D') {
return
}
this.end()
cb(null)
})
}
}
}
//创建直线扇形
createsector(viewer = this.viewer) {
// console.log(this._positions)
let that = this;
let angle
let hierarchy = new Cesium.CallbackProperty(
() => {
let pList = that.calSector(that._positions[0], that._radius, that._startAngle, that._endAngle)
return new Cesium.PolygonHierarchy(pList);
})
// let text = new Cesium.CallbackProperty(
// () => {
// angle = that._endAngle - that._startAngle
// if (angle < 0) {
// angle = 360 + angle
// }
// return angle.toFixed(2) + '°';
// })
let id = that.randomString()
let arrowEntity = viewer.entities.add({
id: id,
position: Cesium.Cartesian3.fromDegrees(that._positions[0].lng, that._positions[0].lat),
// label: {
// text,
// font: "24px Helvetica",
// fillColor: Cesium.Color.SKYBLUE,
// outlineColor: Cesium.Color.BLACK,
// outlineWidth: 2,
// style: Cesium.LabelStyle.FILL_AND_OUTLINE,
// pixelOffset: new Cesium.Cartesian2(0, -12),
// horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
// verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
// disableDepthTestDistance: Number.POSITIVE_INFINITY
// },
polygon: {
hierarchy,
show: true,
fill: true,
clampToGround: true,
material: Cesium.Color.fromCssColorString(that.color),
zIndex: 99999999
}
}
)
that._entities_sector.push(arrowEntity);
return id
}
cartesianToLatlng(cartesian) {
let latlng = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian);
let lat = Cesium.Math.toDegrees(latlng.latitude);
let lng = Cesium.Math.toDegrees(latlng.longitude);
return [lng, lat];
}
/**
* 经纬度坐标转墨卡托坐标
*/
// 墨卡托坐标系展开地球赤道作为x轴向东为x轴正方本初子午线作为y轴向北为y轴正方向。
// 数字20037508.34是地球赤道周长的一半地球半径6378137米赤道周长2*PI*r = 2 * 20037508.3427892墨卡托坐标x轴区间[-20037508.3427892,20037508.3427892]
lonLatToMercator(Latlng) {
let E = Latlng[0];
let N = Latlng[1];
let x = E * 20037508.34 / 180;
let y = Math.log(Math.tan((90 + N) * Math.PI / 360)) / (Math.PI / 180);
y = y * 20037508.34 / 180;
return [x, y]
}
WebMercator2lonLat(mercator) {
let x = mercator[0] / 20037508.34 * 180;
let ly = mercator[1] / 20037508.34 * 180;
let y = 180 / Math.PI * (2 * Math.atan(Math.exp(ly * Math.PI / 180)) - Math.PI / 2)
return [x, y];
}
//计算角度
calculateAangle(arr) {
function getAangle(start, end) {
let rad = Math.PI / 180,
lat1 = start.y * rad,
lat2 = end.y * rad,
lon1 = start.x * rad,
lon2 = end.x * rad;
const a = Math.sin(lon2 - lon1) * Math.cos(lat2);
const b =
Math.cos(lat1) * Math.sin(lat2) -
Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon2 - lon1);
const radians = Math.atan2(a, b)
const degrees = radians % (2 * Math.PI);
let bearing = 450 - ((degrees * 180) / Math.PI < 0
? 360 + (degrees * 180) / Math.PI
: (degrees * 180) / Math.PI) - 90;
return 360 - (bearing % 360)
}
let center = arr[0]
let pos84_1 = arr[1]
let pos84_2 = arr[2]
let start = { x: center.lng, y: center.lat }
let end1 = { x: pos84_1.lng, y: pos84_1.lat }
let end2 = { x: pos84_2.lng, y: pos84_2.lat }
let angle1 = getAangle(start, end1)
let angle2 = getAangle(start, end2)
return {
angle1,
angle2
}
}
}
export default DrawSector

View File

@ -0,0 +1,262 @@
import MouseTip from '../MouseTip'
import MouseEvent from '../Event'
import Draw from './draw'
const transformCartesianToWGS84 = cartesian => {
let ellipsoid = Cesium.Ellipsoid.WGS84
let cartographic = ellipsoid.cartesianToCartographic(cartesian)
const x = Cesium.Math.toDegrees(cartographic.longitude)
const y = Cesium.Math.toDegrees(cartographic.latitude)
const z = cartographic.height
return { x, y, z }
}
/**
* @extends Draw*/
class DrawStraightArrow extends Draw {
/**
* @constructor
* @param sdk
* @param [options] {object} 面属性
* @param [options.color=rgba(185,14,14,0.58)] {object} 线属性
* */
constructor(sdk, options = {}) {
super(sdk, options)
this.points = null
this.polygonHasCreated = false
}
static polygon(that, viewer = that.viewer) {
let id = that.randomString()
return viewer.entities.add(
new Cesium.Entity({
name: 'ArrowPolygon',
id,
polygon: {
hierarchy: new Cesium.CallbackProperty(e => {
let arr = that.computeStraightArrow(that.positions)
for (let i = 0; i < arr.length; i++) {
if (isNaN(arr[i].x)) {
arr = []
break
}
}
return new Cesium.PolygonHierarchy(arr)
}, false),
material: Cesium.Color.fromCssColorString(that.color),
outline: true,
outlineColor: Cesium.Color.GREEN,
zIndex: 99999999
}
})
)
}
/**
* @desc 开始动态绘制面
* @method start
* @param cb {function} 回调函数
* @memberOf DrawPolygon
* @example draw.start((err,positions)=>{
*
* })
* */
start(cb) {
let that = this
// eslint-disable-next-line no-undef
if (YJ.Measure.GetMeasureStatus()) {
cb('上一次测量未结束')
} else {
super.start()
// eslint-disable-next-line no-undef
let into
YJ.Measure.SetMeasureStatus(true)
this.tip = new MouseTip('左键确定,右键取消;', that.sdk)
this.event = new MouseEvent(that.sdk)
this.positions = []
this.points_ids = [] //存放左键点击时临时添加的point的id
let cache_positions = []
let cache_84_position = []
this.anchorpoints = []
this.event.mouse_left((movement, cartesian) => {
if(into === '2D') {
return
}
into = '3D'
if (!cartesian || this.anchorpoints[0]===cartesian) return
this.anchorpoints.push(cartesian)
let p = this.cartesian3Towgs84(cartesian, this.viewer)
p.lng = Number(p.lng.toFixed(8))
p.lat = Number(p.lat.toFixed(8))
if(cache_positions[0] && (p.lng === cache_positions[0].lng && p.lat === cache_positions[0].lat)) return;
cache_positions.push(p)
this.positions.push(p)
// console.log(this.cartesian3Towgs84(cartesian))
this.points_ids.push(this.create_point(cartesian))
if (this.points_ids.length === 2) {
let array = [cache_positions[0], cache_positions[1]]
cb(null, array)
this.end()
}
})
this.event.mouse_move((movement, cartesian) => {
if(into === '2D') {
return
}
this.tip.setPosition(
cartesian,
movement.endPosition.x,
movement.endPosition.y
)
if (!cartesian || this.points_ids.length === 0) {
return
}
let p = this.cartesian3Towgs84(cartesian, this.viewer)
this.positions = [this.positions[0], p];
if (this.points_ids.length === 1 && !Cesium.defined(this.arrowPolygon)) {
this.arrowPolygon = DrawStraightArrow.polygon(this)
}
})
this.event.mouse_right((movement, cartesian) => {
if(into === '2D') {
return
}
cb(null)
this.end()
})
this.event.gesture_pinck_start((movement, cartesian) => {
if(into === '2D') {
return
}
let startTime = new Date()
this.event.gesture_pinck_end(() => {
let endTime = new Date()
if (endTime - startTime >= 500) {
this.end()
cb(false)
}
else {
if (this.anchorpoints.length === 2) {
this.anchorpoints.push(cartesian)
cb(null, this.positions)
this.end()
}
else {
if (!cartesian || Cesium.defined(this.arrowPolygon)) return
this.tip.setPosition(
cartesian,
(movement.position1.x + movement.position2.x) / 2,
(movement.position1.y + movement.position2.y) / 2
)
this.anchorpoints.push(cartesian)
this.arrowPolygon = DrawStraightArrow.polygon(this)
cache_positions.push(this.cartesian3Towgs84(cartesian))
// console.log(this.cartesian3Towgs84(cartesian))
this.points_ids.push(this.create_point(cartesian))
}
}
})
})
if (!this._is2D && this._sdk2D) {
this.event2D = new MouseEvent(this._sdk2D)
this.event2D.mouse_left((movement, cartesian) => {
if(into === '3D') {
return
}
into = '2D'
if (!cartesian || this.anchorpoints[0]===cartesian) return
this.anchorpoints.push(cartesian)
let p = this.cartesian3Towgs84(cartesian, this.viewer)
p.lng = Number(p.lng.toFixed(8))
p.lat = Number(p.lat.toFixed(8))
if(cache_positions[0] && (p.lng === cache_positions[0].lng && p.lat === cache_positions[0].lat)) return;
cache_positions.push(p)
this.positions.push(p)
// console.log(this.cartesian3Towgs84(cartesian))
this.points_ids.push(this.create_point(cartesian, this._sdk2D.viewer))
if (this.points_ids.length === 2) {
let array = [cache_positions[0], cache_positions[1]]
cb(null, array)
this.end()
}
})
this.event2D.mouse_move((movement, cartesian) => {
if(into === '3D') {
return
}
this.tip.setPosition(
cartesian,
movement.endPosition.x + this.viewer.canvas.width,
movement.endPosition.y
)
if (!cartesian || this.points_ids.length === 0) {
return
}
let p = this.cartesian3Towgs84(cartesian, this.viewer)
this.positions = [this.positions[0], p];
if (this.points_ids.length === 1 && !Cesium.defined(this.arrowPolygon)) {
this.arrowPolygon = DrawStraightArrow.polygon(this, this._sdk2D.viewer)
}
})
this.event2D.mouse_right((movement, cartesian) => {
if(into === '3D') {
return
}
cb(null)
this.end()
})
this.event2D.gesture_pinck_start((movement, cartesian) => {
if(into === '3D') {
return
}
let startTime = new Date()
this.event2D.gesture_pinck_end(() => {
let endTime = new Date()
if (endTime - startTime >= 500) {
this.end()
cb(false)
}
else {
if (this.anchorpoints.length === 2) {
this.anchorpoints.push(cartesian)
cb(null, this.positions)
this.end()
}
else {
if (!cartesian || Cesium.defined(this.arrowPolygon)) return
this.tip.setPosition(
cartesian,
(movement.position1.x + movement.position2.x) / 2 + this.viewer.canvas.width,
(movement.position1.y + movement.position2.y) / 2
)
this.anchorpoints.push(cartesian)
this.arrowPolygon = DrawStraightArrow.polygon(this, this._sdk2D.viewer)
cache_positions.push(this.cartesian3Towgs84(cartesian))
// console.log(this.cartesian3Towgs84(cartesian))
this.points_ids.push(this.create_point(cartesian, this._sdk2D.viewer))
}
}
})
})
}
}
}
end() {
super.end();
this.viewer.entities.remove(this.arrowPolygon)
if (!this._is2D && this._sdk2D) {
this._sdk2D.viewer.entities.remove(this.arrowPolygon)
}
}
}
export default DrawStraightArrow

196
src/Event/index.js Normal file
View File

@ -0,0 +1,196 @@
/**
* @name: index
* @author: Administrator
* @date: 2022-06-14 14:44
* @descriptionindex
* @update: 2022-06-14 14:44
*/
export default class MouseEvent {
constructor(sdk) {
this.sdk = sdk
this.viewer = sdk.viewer
this.handler = new Cesium.ScreenSpaceEventHandler(
this.viewer.canvas
)
}
/*事件*/
mouse_left(cb) {
// //左键点击事件
this.handler && this.handler.setInputAction((movement) => {
let cartesian = this.getcartesian(movement)
// cartesian = this.earth.czm.viewer.scene.pickPosition(movement.position)
// if (!cartesian) {
// cartesian = this.viewer.scene.camera.pickEllipsoid(
// movement.position,
// this.viewer.scene.globe.ellipsoid
// )
// }
// if (cartesian) {
// cb(movement, cartesian)
// }
if (cartesian) {
cb(movement, cartesian)
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
}
mouse_left_down(cb) {
// //左键按下事件
this.handler && this.handler.setInputAction((movement) => {
let cartesian = this.getcartesian(movement)
if (cartesian) {
cb(movement, cartesian)
}
}, Cesium.ScreenSpaceEventType.LEFT_DOWN)
}
mouse_left_up(cb) {
// //左键抬起事件
this.handler && this.handler.setInputAction((movement) => {
let cartesian = this.getcartesian(movement)
if (cartesian) {
cb(movement, cartesian)
}
}, Cesium.ScreenSpaceEventType.LEFT_UP)
}
mouse_move(cb, allowNull = false) {
this.handler && this.handler.setInputAction((movement) => {
let cartesian = this.getcartesian(movement)
if (cartesian || allowNull) {
cb(movement, cartesian)
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
}
mouse_right(cb, allowNull = false) {
this.handler && this.handler.setInputAction((movement) => {
let cartesian = this.getcartesian(movement)
if (cartesian || allowNull) {
cb(movement, cartesian)
}
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
}
mouse_right_down(cb, allowNull = false) {
this.handler && this.handler.setInputAction((movement) => {
let cartesian = this.getcartesian(movement)
if (cartesian || allowNull) {
cb(movement, cartesian)
}
}, Cesium.ScreenSpaceEventType.RIGHT_DOWN)
}
mouse_right_up(cb, allowNull = false) {
this.handler && this.handler.setInputAction((movement) => {
let cartesian = this.getcartesian(movement)
if (cartesian || allowNull) {
cb(movement, cartesian)
}
}, Cesium.ScreenSpaceEventType.RIGHT_UP)
}
mouse_wheel(cb) {
this.handler && this.handler.setInputAction(() => {
cb()
}, Cesium.ScreenSpaceEventType.WHEEL)
}
getcartesian(movement) {
// if (movement.endPosition) {
// movement.endPosition.y -= 2
// }
let position = movement.position || movement.endPosition
if(movement.position1 && movement.position2) {
position = {
x: (movement.position1.x + movement.position2.x) / 2,
y: (movement.position1.y + movement.position2.y) / 2,
}
}
let cartesian = this.viewer.scene.pickPosition(position)
if (!cartesian) {
const ray = this.viewer.camera.getPickRay(position); //相交的射线
let pickedObjects = this.viewer.scene.drillPickFromRay(ray, 10);
let result = {}
for (let i = 0; i < pickedObjects.length; i++) {
if (pickedObjects[i].position) {
result = pickedObjects[i]
break
}
}
cartesian = result.position
if(!cartesian) {
cartesian = this.viewer.scene.globe.pick(ray, this.viewer.scene);
}
}
// console.log(cartesian)
// const updatedPositions = await Cesium.sampleTerrainMostDetailed(this.sdk.viewer.terrainProvider, Cesium.Cartographic.fromCartesian(cartesian, this.viewer.scene.globe.ellipsoid));
// console.log(updatedPositions)
return cartesian
// return this.earth.czm.viewer.scene.pickPosition(position)
}
//鼠标右键+键盘ctrl
mouse_right_keyboard_ctrl(cb) {
// //左键点击事件
this.handler && this.handler.setInputAction(
(movement) => {
let cartesian = this.getcartesian(movement)
if (cartesian) {
cb(movement, cartesian)
}
},
Cesium.ScreenSpaceEventType.RIGHT_CLICK,
Cesium.KeyboardEventModifier.CTRL
)
}
// 手势-双指触摸开始
gesture_pinck_start(cb) {
this.handler && this.handler.setInputAction((movement) => {
let cartesian = this.getcartesian(movement)
if (cartesian) {
cb(movement, cartesian)
}
}, Cesium.ScreenSpaceEventType.PINCH_START)
}
//手势-双指触摸开始+键盘ctrl
gesture_pinck_start_keyboard_ctrl(cb) {
this.handler && this.handler.setInputAction(
(movement) => {
let cartesian = this.getcartesian(movement)
if (cartesian) {
cb(movement, cartesian)
}
},
Cesium.ScreenSpaceEventType.PINCH_START,
Cesium.KeyboardEventModifier.CTRL
)
}
// 手势-双指触摸结束
gesture_pinck_end(cb) {
this.handler && this.handler.setInputAction((movement) => {
cb()
}, Cesium.ScreenSpaceEventType.PINCH_END)
}
// 手势-双指触摸修改
gesture_pinck_move(cb) {
this.handler && this.handler.setInputAction((movement) => {
// let cartesian = this.getcartesian(movement)
// if (cartesian) {
// cb(movement, cartesian)
// }
}, Cesium.ScreenSpaceEventType.PINCH_MOVE)
}
destroy() {
if (this.handler)
this.handler.destroy() //关闭事件句柄
this.handler = null
}
}

View File

@ -0,0 +1,578 @@
/**
* @name: click
* @author: Administrator
* @date: 2023-05-28 11:05
* @descriptionclick
* @update: 2023-05-28 11:05
*/
let leftClickHandler = null
let rightClickHandler = null
let MoveHandler = null
let leftClickCallbackMap = new Map()
let rightClickCallbackMap = new Map()
let MoveCallbackMap = new Map()
let selectedFeature;
function cartesian3Towgs84(cartesian, viewer) {
var ellipsoid = viewer.scene.globe.ellipsoid
var cartesian3 = new Cesium.Cartesian3(
cartesian.x,
cartesian.y,
cartesian.z
)
var cartographic = ellipsoid.cartesianToCartographic(cartesian3)
var lat = Cesium.Math.toDegrees(cartographic.latitude)
var lng = Cesium.Math.toDegrees(cartographic.longitude)
var alt = cartographic.height < 0 ? 0 : cartographic.height
return {
lng: lng,
lat: lat,
alt: alt,
}
}
function getcartesian(sdk, movement) {
if (movement.endPosition) {
movement.endPosition.y -= 2
}
let position = movement.position || movement.endPosition
// 获取世界坐标系地表坐标,考虑地形,不包括模型,倾斜摄影模型表面;
let cartesian = sdk.viewer.scene.pickPosition(position)
if (!cartesian) {
const ray = sdk.viewer.camera.getPickRay(position); //相交的射线
cartesian = sdk.viewer.scene.globe.pick(ray, sdk.viewer.scene);
}
return cartesian
}
function openLeftClick(sdk, cb) {
if (!sdk || !sdk.viewer) {
return
}
let click = true
leftClickHandler = new Cesium.ScreenSpaceEventHandler(sdk.viewer.canvas)
leftClickHandler.setInputAction((movement) => {
let cartesian = sdk.viewer.scene.pickPosition(movement.position)
if (!cartesian) {
const ray = sdk.viewer.camera.getPickRay(movement.position); //相交的射线
cartesian = sdk.viewer.scene.globe.pick(ray, sdk.viewer.scene);
}
if (!cartesian) {
return
}
let pos84 = cartesian3Towgs84(cartesian, sdk.viewer)
cb && cb(pos84)
if (click) {
click = false
setTimeout(() => {
click = true
}, 600);
if (!YJ.Measure.GetMeasureStatus() && cartesian) {
let flag = false
for (let i = leftClickCallbackMap.size - 1; i >= 0; i--) {
let key = Array.from(leftClickCallbackMap.keys())[i]
let obj = leftClickCallbackMap.get(key)
if (obj) {
if (obj.that) {
// 是否为多边形
if (obj.that.type === 'PolygonObject') {
// 是否可点击y
if (obj.that.picking) {
if (obj.that.options.positions && obj.that.options.positions.length >= 3) {
let pt = turf.point([pos84.lng, pos84.lat]);
let polyPos = []
for (let i = 0; i < obj.that.options.positions.length; i++) {
polyPos.push([
obj.that.options.positions[i].lng,
obj.that.options.positions[i].lat
])
}
polyPos.push([
obj.that.options.positions[0].lng,
obj.that.options.positions[0].lat
])
let poly = turf.polygon([polyPos]);
let contain = turf.booleanPointInPolygon(pt, poly);
if (contain) {
obj.callback(
movement,
obj.that.options.id,
cartesian3Towgs84(getcartesian(sdk, movement), sdk.viewer), obj.that)
flag = true
break
}
}
}
}
// 聚集地
else if (obj.that.type === 'AssembleObject') {
if (obj.that.picking) {
if (obj.that.options.positions && obj.that.options.positions.length >= 3) {
let positions = obj.that.computeAssemble(obj.that.options.positions, true)
let pt = turf.point([pos84.lng, pos84.lat]);
let polyPos = []
for (let i = 0; i < positions.length; i += 2) {
polyPos.push([
positions[i],
positions[i + 1]
])
}
let poly = turf.polygon([polyPos]);
let contain = turf.booleanPointInPolygon(pt, poly);
if (contain) {
obj.callback(
movement,
obj.that.options.id,
cartesian3Towgs84(getcartesian(sdk, movement), sdk.viewer), obj.that)
flag = true
break
}
}
}
}
// 单箭头
else if (obj.that.type === 'AttackArrowObject') {
if (obj.that.picking) {
if (obj.that.options.positions && obj.that.options.positions.length >= 3) {
let pt = turf.point([pos84.lng, pos84.lat]);
let positions = obj.that.computeAttackArrow(obj.that.options.positions)
let polyPos = []
for (let m = 0; m < positions.length; m++) {
let pos84 = cartesian3Towgs84(positions[m], sdk.viewer)
polyPos.push([pos84.lng, pos84.lat])
}
let poly = turf.polygon([polyPos]);
let contain = turf.booleanPointInPolygon(pt, poly);
if (contain) {
obj.callback(
movement,
obj.that.options.id,
cartesian3Towgs84(getcartesian(sdk, movement), sdk.viewer), obj.that)
flag = true
break
}
}
}
}
// 双箭头
else if (obj.that.type === 'PincerArrowObject') {
if (obj.that.picking) {
if (obj.that.options.positions && obj.that.options.positions.length >= 5) {
let pt = turf.point([pos84.lng, pos84.lat]);
let positions = obj.that.computePincerArrow(obj.that.options.positions)
let polyPos = []
for (let m = 0; m < positions.length; m++) {
let pos84 = cartesian3Towgs84(positions[m], sdk.viewer)
polyPos.push([pos84.lng, pos84.lat])
}
let pos84_0 = cartesian3Towgs84(positions[0], sdk.viewer)
polyPos.push([pos84_0.lng, pos84_0.lat])
let poly = turf.polygon([polyPos]);
let contain = turf.booleanPointInPolygon(pt, poly);
if (contain) {
obj.callback(
movement,
obj.that.options.id,
cartesian3Towgs84(getcartesian(sdk, movement), sdk.viewer), obj.that)
flag = true
break
}
}
}
}
// 圆
else if (obj.that.type === 'CircleObject') {
if (obj.that.picking) {
let pt = turf.point([pos84.lng, pos84.lat]);
if (obj.that.options.center && obj.that.options.radius) {
let center = [obj.that.options.center.lng, obj.that.options.center.lat];
let radius = obj.that.options.radius / 1000;
let options = { steps: 360, units: 'kilometers' };
let circle = turf.circle(center, radius, options);
let contain = turf.booleanPointInPolygon(pt, circle);
if (contain) {
obj.callback(
movement,
obj.that.options.id,
cartesian3Towgs84(getcartesian(sdk, movement), sdk.viewer), obj.that)
flag = true
break
}
}
}
}
// 扇形
else if (obj.that.type === 'SectorObject') {
if (obj.that.picking) {
let pt = turf.point([pos84.lng, pos84.lat]);
if (obj.that.options.center && obj.that.options.radius && obj.that.options.startAngle && obj.that.options.endAngle) {
let positions = obj.that.calSector(obj.that.options.center, obj.that.options.radius, obj.that.options.startAngle, obj.that.options.endAngle, undefined, true)
let polyPos = []
for (let m = 0; m < positions.length; m++) {
polyPos.push([positions[m].lng, positions[m].lat])
}
let poly = turf.polygon([polyPos]);
let contain = turf.booleanPointInPolygon(pt, poly);
if (contain) {
obj.callback(
movement,
obj.that.options.id,
cartesian3Towgs84(getcartesian(sdk, movement), sdk.viewer), obj.that)
flag = true
break
}
}
}
}
}
}
}
if (!flag) {
const pick = sdk.viewer.scene.pick(movement.position)
if (pick) {
if (pick.id) {
let entityId
// 矢量
if (pick.id.type && pick.id.type === 'vector' && pick.id.parentId) {
let obj = leftClickCallbackMap.get(pick.id.parentId)
if (obj.that.picking && obj.that.geojson) {
for (let i = 0; i < obj.that.geojson.features.length; i++) {
if (obj.that.geojson.features[i].id === pick.id._id) {
obj.callback(
movement,
obj.that.geojson.features[i].id,
cartesian3Towgs84(getcartesian(sdk, movement), sdk.viewer), obj.that)
}
}
}
}
else if (typeof pick.id.id == 'string') {
let array = pick.id.id.split('-')
array.splice(array.length - 1, 1)
entityId = array.join('-')
}
if (pick.id.properties && pick.id.properties.id && leftClickCallbackMap.has(pick.id.properties.id._value)) {
let obj = leftClickCallbackMap.get(pick.id.properties.id._value)
if (obj.that.picking) {
obj.callback(
movement,
pick.id.properties.id._value,
cartesian3Towgs84(getcartesian(sdk, movement), sdk.viewer), obj.that)
}
}
else if (leftClickCallbackMap.has(pick.id.id)) {
let obj = leftClickCallbackMap.get(pick.id.id)
if (obj.that.picking) {
obj.callback(
movement,
pick.id.id,
cartesian3Towgs84(getcartesian(sdk, movement), sdk.viewer), obj.that)
}
}
else if (entityId && leftClickCallbackMap.has(entityId)) {
let obj = leftClickCallbackMap.get(entityId)
if (obj.that.picking) {
obj.callback(
movement,
entityId,
cartesian3Towgs84(getcartesian(sdk, movement), sdk.viewer), obj.that)
}
}
else if (pick.primitive) {
if (typeof pick.id == 'string' && leftClickCallbackMap.has(pick.id)) {
let obj = leftClickCallbackMap.get(pick.id)
obj.callback(
movement,
pick.id,
cartesian3Towgs84(getcartesian(sdk, movement), sdk.viewer), obj.that)
}
}
}
else {
if (pick.primitive && pick.primitive.id) {
if (leftClickCallbackMap.has(pick.primitive.id)) {
let obj = leftClickCallbackMap.get(pick.primitive.id)
if (obj.that.picking) {
if (obj.that.type === 'bim') {
if (YJ.Global.getBimPickStatus(sdk)) {
obj.callback(
movement,
pick.primitive,
cartesian3Towgs84(getcartesian(sdk, movement), sdk.viewer), obj.that)
}
}
else {
obj.callback(
movement,
pick.primitive.id,
cartesian3Towgs84(getcartesian(sdk, movement), sdk.viewer), obj.that)
}
}
}
}
}
if (pick.content && (!pick.primitive || !pick.primitive.id)) {
if (leftClickCallbackMap.has(pick.content.tileset.id)) {
let obj = leftClickCallbackMap.get(pick.content.tileset.id)
if (obj.that.picking) {
if (obj.that.type === 'bim') {
if (YJ.Global.getBimPickStatus(sdk)) {
obj.callback(
movement,
pick.content.tileset,
cartesian3Towgs84(getcartesian(sdk, movement), sdk.viewer), obj.that)
}
}
else {
obj.callback(
movement,
pick.content.tileset.id,
cartesian3Towgs84(getcartesian(sdk, movement), sdk.viewer), obj.that)
}
}
}
}
}
}
}
}
// if (click) {
// click = false
// setTimeout(() => {
// click = true
// }, 300);
// if (!YJ.Measure.GetMeasureStatus()) {
// }
// }
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
// leftClickHandler.setInputAction(function (movement) {
// const feature = sdk.viewer.scene.pick(movement.endPosition);
// // unselectFeature(selectedFeature);
// if (selectedFeature) {
// selectedFeature.color = Cesium.Color.WHITE;
// }
// selectedFeature = feature
// if (feature) {
// feature.color = Cesium.Color.YELLOW;
// }
// }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
// }
}
function closeLeftClick(sdk) {
leftClickHandler.destroy() //关闭事件句柄
leftClickHandler = null
// }
}
function openRightClick(sdk) {
if (!sdk || !sdk.viewer) {
return
}
rightClickHandler = new Cesium.ScreenSpaceEventHandler(sdk.viewer.canvas)
rightClickHandler.setInputAction((movement) => {
if (!YJ.Measure.GetMeasureStatus()) {
const pick = sdk.viewer.scene.pick(movement.position)
if (pick && pick.id) {
let id
if (pick.id.type && pick.id.type === 'vector' && pick.id.parentId) {
let obj = rightClickCallbackMap.get(pick.id.parentId)
if (obj.that.picking && obj.that.geojson) {
for (let i = 0; i < obj.that.geojson.features.length; i++) {
if (obj.that.geojson.features[i].id === pick.id._id) {
obj.callback(
movement,
obj.that.geojson.features[i].id,
cartesian3Towgs84(getcartesian(sdk, movement), sdk.viewer), obj.that)
}
}
}
}
else {
if (typeof pick.id === 'string') {
id = pick.id
}
else {
id = pick.id.id
}
if (rightClickCallbackMap.has(id)) {
let obj = rightClickCallbackMap.get(id)
if (obj.that.picking) {
let cartesian = getcartesian(sdk, movement)
if (!cartesian) {
return
}
obj.callback(
movement,
id,
cartesian3Towgs84(cartesian, sdk.viewer), obj.that)
}
}
}
}
if (pick && pick.content) {
if (rightClickCallbackMap.has(pick.content.tileset.id)) {
let obj = rightClickCallbackMap.get(pick.content.tileset.id)
if (obj.that.picking) {
if (obj.that.type === 'bim') {
if (YJ.Global.getBimPickStatus(sdk)) {
let cartesian = getcartesian(sdk, movement)
if (!cartesian) {
return
}
obj.callback(
movement,
pick.getProperty('id'),
cartesian3Towgs84(cartesian, sdk.viewer), obj.that)
}
}
else {
let cartesian = getcartesian(sdk, movement)
if (!cartesian) {
return
}
obj.callback(
movement,
pick.content.tileset.id,
cartesian3Towgs84(cartesian, sdk.viewer), obj.that)
}
}
}
}
}
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
}
function closeRightClick() {
if (rightClickHandler) {
rightClickHandler.destroy() //关闭事件句柄
rightClickHandler = null
}
}
function openMove(sdk) {
MoveHandler = new Cesium.ScreenSpaceEventHandler(sdk.viewer.canvas)
MoveHandler.setInputAction(function (movement) {
const pick = sdk.viewer.scene.pick(movement.endPosition);
// unselectFeature(selectedFeature);
// if (selectedFeature) {
// let color = '#fff'
// let state = selectedFeature.getProperty('state')
// switch (state) {
// case '0':
// color = '#fff'
// break;
// case '1':
// color = '#f00'
// break;
// case '2':
// color = '#0f0'
// break;
// case '3':
// color = '#00f'
// break;
// default:
// }
// selectedFeature.color = Cesium.Color.fromCssColorString(color).withAlpha(selectedFeature.tileset.transparency)
// }
// if (pick && pick.id) { }
// if (pick && pick.content) {
// if (MoveCallbackMap.has(pick.content.tileset.id)) {
// let obj = MoveCallbackMap.get(pick.content.tileset.id)
// if (obj.that.picking) {
// if (obj.that.type === 'bim') {
// if (YJ.Global.getBimPickStatus(sdk)) {
// selectedFeature = pick
// pick.color = Cesium.Color.YELLOW;
// }
// else {
// selectedFeature = null
// }
// }
// else {
// selectedFeature = pick
// pick.color = Cesium.Color.YELLOW;
// }
// }
// else {
// selectedFeature = null
// }
// }
// }
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
}
function closeMove() {
if (MoveHandler) {
MoveHandler.destroy() //关闭事件句柄
MoveHandler = null
}
}
/*注册左键回调*/
function regLeftClickCallback(id, callback, that) {
leftClickCallbackMap.set(id, { callback, that })
}/*取消左键回调*/
function unRegLeftClickCallback(id,) {
leftClickCallbackMap.delete(id,)
}
/*注册右键回调*/
function regRightClickCallback(id, callback, that) {
rightClickCallbackMap.set(id, { callback, that })
}/*取消右键回调*/
function unRegRightClickCallback(id,) {
rightClickCallbackMap.delete(id,)
}
/*注册左键回调*/
function regMoveCallback(id, callback, that) {
MoveCallbackMap.set(id, { callback, that })
}/*取消左键回调*/
function unregMoveCallback(id,) {
MoveCallbackMap.delete(id,)
}
function getLeftClickState() {
if (leftClickHandler) {
return true
}
else {
false
}
}
function getRightClickState() {
if (rightClickHandler) {
return true
}
else {
false
}
}
function getMoveState() {
if (MoveHandler) {
return true
}
else {
false
}
}
export { openLeftClick, closeLeftClick, regLeftClickCallback, unRegLeftClickCallback, openRightClick, closeRightClick, regRightClickCallback, unRegRightClickCallback, openMove, closeMove, regMoveCallback, unregMoveCallback, getLeftClickState, getRightClickState, getMoveState }

253
src/Global/Contour/index.js Normal file
View File

@ -0,0 +1,253 @@
/**
* 等高线
*/
import Dialog from "../../Obj/Element/Dialog";
import Tools from "../../Tools";
let _DialogObject = null;
let material = null;
let handler = null;
let activeHeightElm = null;
let tools
activeHeightElm = document.createElement('div')
activeHeightElm.className = 'YJ-customize-active-height-elm'
activeHeightElm.style.position = 'absolute'
activeHeightElm.style.left = '10px'
activeHeightElm.style.top = '10px'
activeHeightElm.style.width = '100px'
// activeHeightElm.style.backgroundColor = 'rgba(0, 0, 0, 0.5)'
activeHeightElm.style.textAlign = 'center'
activeHeightElm.style.pointerEvents = 'none'
activeHeightElm.style.color = '#ff0000'
activeHeightElm.style.display = 'none'
async function dialog(sdk) {
if (!sdk || _DialogObject) {
return
}
if (!material) {
createMaterial()
}
if (!tools) {
tools = new Tools()
}
_DialogObject = await new Dialog(sdk, {}, {
title: "等高线", left: '180px',
top: '100px',
confirmCallBack: options => { },
closeCallBack: () => {
_DialogObject = null
}
});
_DialogObject._element.body.className =
_DialogObject._element.body.className + ' contour'
let contentElm = document.createElement('div')
contentElm.innerHTML = `
<span class="custom-divider"></span>
<div class="div-item">
<div class="row">
<div class="col input-select-unit-box">
<span class="label">高差</span>
<div class="input-number input-number-unit-1">
<input class="input gap" type="number" title="" min="0" max="1000">
<span class="unit">m</span>
<span class="arrow"></span>
</div>
</div>
<div class="col input-select-unit-box" style="flex: 0 0 120px;">
<span class="label">主线颜色</span>
<div class="primary-lice-color"></div>
</div>
</div>
<div class="row">
<div class="col input-select-unit-box">
<span class="label">次线条数</span>
<div class="input-number input-number-unit-1">
<input class="input gap2" type="number" title="" min="0" max="10">
<span class="unit"></span>
<span class="arrow"></span>
</div>
</div>
<div class="col input-select-unit-box" style="flex: 0 0 120px;">
<span class="label">次线颜色</span>
<div class="secondary-lice-color"></div>
</div>
</div>
<div class="row" style="align-items: flex-start;">
<div class="col">
</div>
<div class="col" style="flex: 0 0 120px;">
<span class="label">开关</span>
<input class="btn-switch" type="checkbox">
</div>
</div>
</div>
<span class="custom-divider"></span>
`
contentElm.innerHTML = `
<span class="custom-divider"></span>
<div class="div-item">
<div class="row" style="align-items: flex-start;">
<div class="col" style="flex: 0 0 120px;">
<span class="label">开关</span>
<input class="btn-switch" type="checkbox">
</div>
</div>
</div>
`
_DialogObject.contentAppChild(contentElm)
contentElm.getElementsByClassName('btn-switch')[0].addEventListener('change', (e) => {
if (e.target.checked) {
if (handler) {
handler.destroy()
}
if (!sdk.viewer.container.getElementsByClassName('YJ-customize-active-height-elm')[0]) {
sdk.viewer.container.appendChild(activeHeightElm)
}
handler = new Cesium.ScreenSpaceEventHandler(
sdk.viewer.canvas
)
handler.setInputAction((movement) => {
let cartesian = sdk.viewer.scene.pickPosition(movement.endPosition)
if (cartesian) {
let top = 0
let left = 0
if (sdk.viewer && sdk.viewer._element) {
let element = sdk.viewer._element.getElementsByClassName('cesium-widget')[0].getElementsByTagName('canvas')[0]
top = element.getBoundingClientRect().top + window.scrollY
left = element.getBoundingClientRect().left + window.scrollX
}
activeHeightElm.style.left = movement.endPosition.x - 50 + left + 'px'
activeHeightElm.style.top = movement.endPosition.y - 40 + top + 'px'
activeHeightElm.style.display = 'block'
let pos84 = tools.cartesian3Towgs84(cartesian, sdk.viewer)
let mainContourHeight = Math.floor(pos84.alt / material.uniforms.spacing) * material.uniforms.spacing
let gap = pos84.alt - mainContourHeight
let gap2 = material.uniforms.spacing / (material.uniforms.secondaryLinesCount + 1)
let activeHeight = Math.floor(gap / gap2) * gap2 + mainContourHeight
if ((pos84.alt - activeHeight) > gap2 / 2) {
activeHeight = activeHeight + gap2
}
material.uniforms.mouseHeight = pos84.alt
material.uniforms.mousePosition = cartesian
activeHeightElm.innerHTML = `${activeHeight.toFixed(0)}`
}
else {
activeHeightElm.style.display = 'none'
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
sdk.viewer.scene.globe.material = material;
} else {
if (handler) {
handler.destroy()
handler = null
}
if (sdk.viewer.container.getElementsByClassName('YJ-customize-active-height-elm')[0]) {
activeHeightElm.style.display = 'none'
sdk.viewer.container.removeChild(activeHeightElm)
}
sdk.viewer.scene.globe.material = null;
}
})
}
function createMaterial() {
Cesium.Material._materialCache._materials.ElevationContour.fabric.source = `
uniform vec4 color;
uniform vec4 secondaryLinesColor;
uniform float spacing;
uniform float width;
uniform float secondaryLinesWidth;
uniform float mouseHeight;
uniform float secondaryLinesCount; // 0=无次线, 1=1条次线, 2=2条次线...
czm_material czm_getMaterial(czm_materialInput materialInput)
{
czm_material material = czm_getDefaultMaterial(materialInput);
// 主等高线计算
float distanceToMainContour = mod(materialInput.height, spacing);
// 抗锯齿计算
#if (__VERSION__ == 300 || defined(GL_OES_standard_derivatives))
float dxc = abs(dFdx(materialInput.height));
float dyc = abs(dFdy(materialInput.height));
float dFMain = max(dxc, dyc) * czm_pixelRatio * width;
#else
float dFMain = czm_pixelRatio * width;
#endif
bool isMainContour = distanceToMainContour < dFMain;
bool isSecondaryContour = false;
float dFSecondary = 0.0;
float secondarySpacing = 0.0;
// 只有当存在次线时才计算次线
if(secondaryLinesCount > 0.0) {
secondarySpacing = spacing / (secondaryLinesCount + 1.0);
float distanceToSecondaryContour = mod(materialInput.height, secondarySpacing);
// 确保次线不会与主线重叠
float minDistanceToMain = min(distanceToMainContour, spacing - distanceToMainContour);
bool notCloseToMain = minDistanceToMain > dFMain * 2.0; // 2倍线宽缓冲
#if (__VERSION__ == 300 || defined(GL_OES_standard_derivatives))
dFSecondary = max(dxc, dyc) * czm_pixelRatio * secondaryLinesWidth;
#else
dFSecondary = czm_pixelRatio * secondaryLinesWidth;
#endif
isSecondaryContour = (distanceToSecondaryContour < dFSecondary) && notCloseToMain;
}
// 计算当前高度所属的等高线高度
float mainContourHeight = floor(materialInput.height / spacing) * spacing;
float secondaryContourHeight = floor(materialInput.height / spacing * (secondaryLinesCount + 1.0)) * spacing / (secondaryLinesCount + 1.0);
// 高亮判断
bool shouldHighlight = false;
if(isMainContour && abs(mainContourHeight - mouseHeight) < 0.5 * (spacing/(secondaryLinesCount+1.0))) {
shouldHighlight = true;
} else if(isSecondaryContour && abs(secondaryContourHeight - mouseHeight) < 0.5 * (spacing/(secondaryLinesCount+1.0))) {
shouldHighlight = true;
}
// 颜色输出
vec4 outColor;
if(shouldHighlight) {
outColor = vec4(1.0, 0.0, 0.0, 1.0);
} else if(isMainContour) {
outColor = czm_gammaCorrect(vec4(color.rgb, color.a));
} else if(isSecondaryContour) {
outColor = czm_gammaCorrect(vec4(secondaryLinesColor.rgb, secondaryLinesColor.a));
} else {
outColor = vec4(0.0);
}
material.diffuse = outColor.rgb;
material.alpha = outColor.a;
return material;
}
`
material = new Cesium.Material({
fabric: {
type: "ElevationContour",
uniforms: {
width: 2,
secondaryLinesWidth: 1, // 次级线宽度
spacing: 200,
color: Cesium.Color.fromCssColorString('#ffd000'),
secondaryLinesColor: Cesium.Color.fromCssColorString('#0dff00').withAlpha(0.5),
mouseHeight: -100000,
mousePosition: new Cesium.Cartesian3(0, 0, 0),
secondaryLinesCount: 3
},
}
});
}
export { dialog }

View File

@ -0,0 +1,37 @@
function changeClassificationPrimitive(options, array) {
this.options = options
this.array = array
}
changeClassificationPrimitive.prototype.getGeometry = function () {
return Cesium.PolygonGeometry.createGeometry(this.options);
};
changeClassificationPrimitive.prototype.update = function (context, frameState, commandList) {
var geometry = this.getGeometry();
if (!geometry) {
return;
}
this._primitive = new Cesium.ClassificationPrimitive({
geometryInstances: new Cesium.GeometryInstance({
geometry: geometry,
id: {
type: 'dth',
...this.array,
},
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
Cesium.Color.fromRandom({ alpha: 0.5 })
),
show: new Cesium.ShowGeometryInstanceAttribute(true),
}
}),
classificationType: Cesium.ClassificationType.CESIUM_3D_TILE,
});
var primitive = this._primitive
primitive.update(context, frameState, commandList);
};
export { changeClassificationPrimitive }

538
src/Global/DTH/index.js Normal file
View File

@ -0,0 +1,538 @@
import { getHost, getToken } from "../../on";
class DTH {
constructor(sdk, options = {}) {
this.sdk = sdk
this.primitives = {
building: [],
unit: [],
dth: []
}
this.options = { ...options }
this.options.host = this.options.host || getHost()
this.temporaryDth = []
this.dth = {}
this.PickBuildingEvent = new Cesium.Event();
this.initEvents()
this.activeBuilding
}
/**
* @description 注册点击的事件回调
* @memberOf DTH
* */
PickCallback(that, cb) {
this.PickBuildingEvent.addEventListener(
cb,
that
)
}
//场景事件
initEvents() {
new Cesium.ScreenSpaceEventHandler(this.sdk.viewer.scene.canvas).setInputAction(((e) => {
if (YJ.Measure.GetMeasureStatus()) {
return
}
if (!this.isActivate) return;
let pickFeature = this.sdk.viewer.scene.pick(e.position);
if (pickFeature) {
//点击了已有的分户单体化
if (pickFeature.primitive && pickFeature.primitive instanceof Cesium.ClassificationPrimitive && pickFeature.id && (pickFeature.id.type == "yj-dth-dth" || pickFeature.id.type == "yj-dth-highlight")) {
this.getIDBypickFeature(pickFeature); //处理点击到的楼层
return;
}
if (pickFeature.primitive && pickFeature.primitive instanceof Cesium.ClassificationPrimitive && pickFeature.id && pickFeature.id.type == "yj-dth-unit") {
this.highlightPrimitive && this.sdk.viewer.scene.primitives.remove(this.highlightPrimitive)
this.handlePickEvent(pickFeature.id)
return;
}
// if (pickFeature.id && pickFeature.id.type === 'yj-dth-highlight') {
// return;
// }
}
this.highlightPrimitive && this.sdk.viewer.scene.primitives.remove(this.highlightPrimitive)
let position = this.sdk.viewer.scene.pickPosition(e.position); //屏幕坐标转为笛卡尔空间坐标
if (!position) return;
let c = Cesium.Cartographic.fromCartesian(position); //笛卡尔坐标转为经纬度(弧度)
let point = [Cesium.Math.toDegrees(c.longitude), Cesium.Math.toDegrees(c.latitude)]; //转为经纬度点
this.queryByPoint(point, c.height);
}), Cesium.ScreenSpaceEventType.LEFT_CLICK);
let coverLabelEntity = this.sdk.viewer.entities.getOrCreateEntity('yj-dth-cover-label')
coverLabelEntity.show = false
// this.sdk.viewer.entities.add({
// position: Cesium.Cartesian3.fromDegrees(-75.1641667, 39.9522222),
// label: {
// text: "Philadelphia",
// font: "24px Helvetica",
// fillColor: Cesium.Color.SKYBLUE,
// outlineColor: Cesium.Color.BLACK,
// outlineWidth: 2,
// style: Cesium.LabelStyle.FILL_AND_OUTLINE,
// },
// });
let lastPickTime = 0;
let _this = this
let timeoutEvent
new Cesium.ScreenSpaceEventHandler(this.sdk.viewer.scene.canvas).setInputAction(((movement) => {
if (YJ.Measure.GetMeasureStatus()) {
return
}
try {
const now = Date.now();
if (now - lastPickTime < 100) {
clearTimeout(timeoutEvent)
timeoutEvent = setTimeout(() => {
pick(movement)
}, 100);
return
}
clearTimeout(timeoutEvent)
lastPickTime = now;
pick(movement)
} catch (error) {
}
}), Cesium.ScreenSpaceEventType.MOUSE_MOVE);
function pick(e) {
let pickFeature = _this.sdk.viewer.scene.pick(e.endPosition);
if (pickFeature) {
let labelText = ''
if (pickFeature.primitive && pickFeature.primitive instanceof Cesium.ClassificationPrimitive && pickFeature.id && (pickFeature.id.type === "yj-dth-dth" || pickFeature.id.type === "yj-dth-highlight")) {
labelText = pickFeature.id.build_info.name + ' - ' + pickFeature.id.unit_info.name + ' - ' + pickFeature.id.room_num
}
else if (pickFeature.primitive && pickFeature.primitive instanceof Cesium.ClassificationPrimitive && pickFeature.id && pickFeature.id.type === "yj-dth-unit") {
if (pickFeature.id.build_info.name) {
labelText = pickFeature.id.build_info.name + ' - ' + pickFeature.id.name
}
}
else if (pickFeature.primitive && pickFeature.primitive instanceof Cesium.ClassificationPrimitive && pickFeature.id && pickFeature.id.type === "yj-dth-build") {
if (pickFeature.id.name) {
labelText = pickFeature.id.name
}
}
else if (pickFeature.primitive && pickFeature.primitive.id && pickFeature.primitive.id.id && pickFeature.primitive.id.id === 'yj-dth-cover-label') {
coverLabelEntity.position = _this.sdk.viewer.scene.pickPosition(e.endPosition)
return
}
else {
coverLabelEntity.show = false
return
}
if (labelText) {
coverLabelEntity.position = _this.sdk.viewer.scene.pickPosition(e.endPosition)
coverLabelEntity.label = new Cesium.LabelGraphics({
text: labelText,
font: "20px Helvetica",
pixelOffset: { x: 0, y: -30 },
fillColor: Cesium.Color.fromCssColorString('#ffffff'),
outlineColor: Cesium.Color.BLACK,
outlineWidth: 1,
showBackground: true,
backgroundColor: Cesium.Color.fromCssColorString('#000000').withAlpha(0.8),
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
disableDepthTestDistance: Number.POSITIVE_INFINITY,
})
coverLabelEntity.show = true
}
}
}
}
/*根据用户信息查询单体化*/
queryByUserInfo(data) {
this.queryByPoint([data.position.lng, data.position.lat], data.position.alt, data.id)
}
//点查询 点击查询是查询分层的数据
async queryByPoint(point) {
let url = ""
if (this.options.host.endsWith("yjearth4.0")) {
url = this.options.host + '/api/v1/dth/build/query_by_point'
}
else {
url = this.options.host + '/yjearth4.0/api/v1/dth/build/query_by_point'
}
url += '?point=' + JSON.stringify({ 'lng': point[0], 'lat': point[1] })
let response = await fetch(url, {
method: 'get',
// body: JSON.stringify({point: {'lng': point[0],'lat': point[1]}}),
headers: {
'Content-Type': 'application/json',
"token": getToken(),
"Authorization": "Bearer " + getToken(),
}
})
if (response.status === 200) {
let data = await response.json()
if (data.code === 200 || data.code === 0) {
this.processQueryByPointResults(data.data)
}
else {
window.ELEMENT && window.ELEMENT.Message({
message: data.msg || data.message,
type: 'warning',
duration: 1500
});
}
}
}
// 处理查询结果
async processQueryByPointResults(data, isflyto, offset = { heading: 0.0, pitch: -90.0, roll: 0.0 }) {
data.build_info && this.handlePickEvent(data)
let range
this.clearAllDthPrimitive()
this.clearAllUnitPrimitive()
if (this.activeBuilding) {
this.clearBuildingPrimitive(this.activeBuilding)
this.activeBuilding = null
}
if (data.build_info) {
range = JSON.parse(data.build_info.range)
if (data.dan_yuan.length > 0) {
for (let i = 0; i < data.dan_yuan.length; i++) {
if (data.dan_yuan[i].children.length > 0) {
this.addDthPrimitive(data.dan_yuan[i].children, data.build_info, data.dan_yuan[i])
}
else {
this.addUnitPrimitive([data.dan_yuan[i]], data.build_info, data.dan_yuan[i])
}
}
}
else {
this.activeBuilding = data.build_info.ID || data.build_info.id
this.addBuildingPrimitive([data.build_info])
}
if (isflyto) {
if (data.info && data.info.dan_yuan) {
range = JSON.parse(data.info.dan_yuan.range)
}
if (data.info && data.info.hu) {
range = JSON.parse(data.info.hu.range)
for (let i = 0; i < range.length; i++) {
range[i].alt = data.info.hu.bottom
}
for (let i = 0; i < this.primitives.dth.length; i++) {
await this.primitives.dth[i].readyPromise
let primitivesData = this.primitives.dth[i]._primitiveOptions.geometryInstances[0].id
if (primitivesData.ID === data.info.hu.ID && primitivesData.room_num === data.info.hu.room_num) {
let pickFeature = {
id: { ...data.info.hu, build_info: { ...data.build_info }, unit_info: data.info.dan_yuan },
primitive: this.primitives.dth[i]
}
this.getIDBypickFeature(pickFeature)
break
}
}
}
this.flyTo(range, offset)
}
}
}
// 添加房屋Primitive
async addBuildingPrimitive(array) {
for (let i = 0; i < array.length; i++) {
let fromDegreesArray = []
let extrudedHeight = 0
let positions = JSON.parse(array[i].range)
for (let m = 0; m < positions.length; m++) {
if (extrudedHeight < positions[m].alt) {
extrudedHeight = positions[m].alt
}
fromDegreesArray.push(positions[m].lng, positions[m].lat, 0)
}
let polygonGeometry = new Cesium.PolygonGeometry({
polygonHierarchy: new Cesium.PolygonHierarchy(
Cesium.Cartesian3.fromDegreesArrayHeights(fromDegreesArray)
),
// perPositionHeight: true, //使用z坐标 否则高度从0开始
extrudedHeight: 100000000, //拉伸高度
});
this.primitives.building.push(this.sdk.viewer.scene.primitives.add(
new Cesium.ClassificationPrimitive({
geometryInstances: new Cesium.GeometryInstance({
id: {
type: 'yj-dth-build',
...array[i],
},
geometry: Cesium.PolygonGeometry.createGeometry(polygonGeometry),
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
Cesium.Color.fromCssColorString('rgb(255, 235, 59, 0.4)')
),
show: new Cesium.ShowGeometryInstanceAttribute(true),
}
}),
classificationType: Cesium.ClassificationType.CESIUM_3D_TILE,
})
))
}
}
// 根据id删除房屋Primitive
clearBuildingPrimitive(id) {
for (let i = this.primitives.building.length - 1; i >= 0; i--) {
if (id === this.primitives.building[i]._primitiveOptions.geometryInstances[0].id.ID || id === this.primitives.building[i]._primitiveOptions.geometryInstances[0].id.id) {
this.sdk.viewer.scene.primitives.remove(this.primitives.building[i])
this.primitives.building.splice(i, 1)
break
}
}
}
// 删除全部房屋Primitive
clearAllBuildingPrimitive() {
for (let i = this.primitives.building.length - 1; i >= 0; i--) {
this.sdk.viewer.scene.primitives.remove(this.primitives.building[i])
}
this.primitives.building = []
}
// 添加单元Primitive
async addUnitPrimitive(array, build_info, unit_info) {
for (let i = 0; i < array.length; i++) {
let fromDegreesArray = []
let extrudedHeight = 0
let positions = JSON.parse(array[i].range)
for (let m = 0; m < positions.length; m++) {
if (extrudedHeight < positions[m].alt) {
extrudedHeight = positions[m].alt
}
fromDegreesArray.push(positions[m].lng, positions[m].lat, 0)
}
let polygonGeometry = new Cesium.PolygonGeometry({
polygonHierarchy: new Cesium.PolygonHierarchy(
Cesium.Cartesian3.fromDegreesArrayHeights(fromDegreesArray)
),
// perPositionHeight: true, //使用z坐标 否则高度从0开始
extrudedHeight: 100000000, //拉伸高度
});
this.primitives.unit.push(this.sdk.viewer.scene.primitives.add(
new Cesium.ClassificationPrimitive({
geometryInstances: new Cesium.GeometryInstance({
id: {
type: 'yj-dth-unit',
...array[i],
build_info: { ...build_info },
unit_info: { ...unit_info }
},
geometry: Cesium.PolygonGeometry.createGeometry(polygonGeometry),
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
Cesium.Color.fromCssColorString('rgb(255, 235, 59, 0.4)')
),
show: new Cesium.ShowGeometryInstanceAttribute(true),
}
}),
classificationType: Cesium.ClassificationType.CESIUM_3D_TILE,
})
))
this.primitives.unit.push(this.sdk.viewer.scene.primitives.add(
new Cesium.GroundPolylinePrimitive({
geometryInstances: new Cesium.GeometryInstance({
geometry: new Cesium.GroundPolylineGeometry({
positions: Cesium.Cartesian3.fromDegreesArrayHeights(fromDegreesArray),
width: 2.0
}),
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.fromCssColorString('#00ff0a').withAlpha(0.8))
},
}),
appearance: new Cesium.PolylineColorAppearance()
})
))
}
}
// 根据id删除单元Primitive
clearUnitPrimitive(id) {
for (let i = this.primitives.building.length - 1; i >= 0; i--) {
if (id === this.primitives.building[i]._primitiveOptions.geometryInstances[0].id.ID || id === this.primitives.building[i]._primitiveOptions.geometryInstances[0].id.id) {
this.sdk.viewer.scene.primitives.remove(this.primitives.unit[i])
this.primitives.unit.splice(i, 1)
break
}
}
}
// 删除全部单元Primitive
clearAllUnitPrimitive() {
for (let i = this.primitives.unit.length - 1; i >= 0; i--) {
this.sdk.viewer.scene.primitives.remove(this.primitives.unit[i])
}
this.primitives.unit = []
}
// 添加单体化Primitive
addDthPrimitive(array, build_info, unit_info) {
for (let i = 0; i < array.length; i++) {
let positions = JSON.parse(array[i].range)
let fromDegreesArray = []
for (let m = 0; m < positions.length; m++) {
fromDegreesArray.push(positions[m].lng, positions[m].lat, array[i].bottom + 0.3)
}
let polygonGeometry = new Cesium.PolygonGeometry({
polygonHierarchy: new Cesium.PolygonHierarchy(
Cesium.Cartesian3.fromDegreesArrayHeights(fromDegreesArray)
),
perPositionHeight: true, //使用z坐标 否则高度从0开始
extrudedHeight: array[i].height + array[i].bottom, //拉伸高度
});
let polygonGeometryBorder = new Cesium.PolygonGeometry({
polygonHierarchy: new Cesium.PolygonHierarchy(
Cesium.Cartesian3.fromDegreesArrayHeights(fromDegreesArray)
),
perPositionHeight: true, //使用z坐标 否则高度从0开始
extrudedHeight: array[i].bottom, //拉伸高度
});
this.primitives.dth.push(this.sdk.viewer.scene.primitives.add(
new Cesium.ClassificationPrimitive({
geometryInstances: new Cesium.GeometryInstance({
id: {
type: 'yj-dth-dth',
...array[i],
build_info: { ...build_info },
unit_info: { ...unit_info }
},
geometry: Cesium.PolygonGeometry.createGeometry(polygonGeometry),
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
Cesium.Color.fromCssColorString('rgb(0, 64, 255, 0.4)')
),
show: new Cesium.ShowGeometryInstanceAttribute(true),
}
}),
classificationType: Cesium.ClassificationType.CESIUM_3D_TILE,
})
));
this.primitives.dth.push(this.sdk.viewer.scene.primitives.add(
new Cesium.ClassificationPrimitive({
geometryInstances: new Cesium.GeometryInstance({
id: {
type: 'yj-dth-dth-border',
...array[i],
},
geometry: Cesium.PolygonGeometry.createGeometry(polygonGeometryBorder),
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
Cesium.Color.fromCssColorString('rgb(0, 0, 0, 1)')
),
show: new Cesium.ShowGeometryInstanceAttribute(true),
}
}),
classificationType: Cesium.ClassificationType.CESIUM_3D_TILE,
})
));
}
}
// 根据id删除单体化Primitive
clearDthPrimitive(id) {
for (let i = this.primitives.dth.length - 1; i >= 0; i--) {
if (id === this.primitives.dth[i]._primitiveOptions.geometryInstances[0].id.ID || id === this.primitives.dth[i]._primitiveOptions.geometryInstances[0].id.id) {
this.sdk.viewer.scene.primitives.remove(this.primitives.dth[i])
this.primitives.dth.splice(i, 1)
}
}
}
// 删除全部单体化Primitive
clearAllDthPrimitive() {
this.highlightPrimitive && this.sdk.viewer.scene.primitives.remove(this.highlightPrimitive)
for (let i = this.primitives.dth.length - 1; i >= 0; i--) {
this.sdk.viewer.scene.primitives.remove(this.primitives.dth[i])
}
this.primitives.dth = []
}
getIDBypickFeature(pickFeature) {
//恢复上一个贴对象面显示
if (this.clickHighlightPrimitive) {
this.clickHighlightPrimitive.show = true;
}
this.highlightPrimitive && this.sdk.viewer.scene.primitives.remove(this.highlightPrimitive)
this.highlightPrimitive = this.sdk.viewer.scene.primitives.add(
new Cesium.ClassificationPrimitive({
geometryInstances: new Cesium.GeometryInstance({
id: {
...pickFeature.id,
type: 'yj-dth-highlight',
},
geometry: pickFeature.primitive._primitiveOptions.geometryInstances[0].geometry,
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.fromCssColorString('#ff9800').withAlpha(0.8)),
show: new Cesium.ShowGeometryInstanceAttribute(true),
}
}),
classificationType: Cesium.ClassificationType.CESIUM_3D_TILE,
})
)
this.highlightPrimitive.readyPromise.then(() => {
//设置当前点击的贴对象面不显示
pickFeature.primitive.show = false;
})
this.clickHighlightPrimitive = pickFeature.primitive;
let range = pickFeature.id.range
if (typeof pickFeature.id.range === 'string') {
range = JSON.parse(pickFeature.id.range)
}
this.getHilightArea(range)
this.handlePickEvent(pickFeature.id)
}
//处理点击事件
handlePickEvent(id) {
this.PickBuildingEvent.raiseEvent(id); //触发选中事件 通知界面更新
}
getHilightArea(points, radius = 1) {
let arr = []
points.forEach((point) => {
arr.push([(point.lng), (point.lat)])
})
arr.push(arr[0])
var poly = turf.polygon([arr])
var buffered = turf.buffer(poly, Number(radius) / 1000)
return buffered.geometry.coordinates
}
async flyTo(positions, offset = { heading: 0.0, pitch: -90.0, roll: 0.0 }) {
let tools = new YJ.Tools(this.sdk)
let height = 0
let positionArray = []
for (let i = 0; i < positions.length; i++) {
if (positions[i].alt) {
height = positions[i].alt
}
else {
height = await tools.getClampToHeight(positions[i])
}
let a = Cesium.Cartesian3.fromDegrees(positions[i].lng, positions[i].lat, height)
positionArray.push(a.x, a.y, a.z)
}
let BoundingSphere = await Cesium.BoundingSphere.fromVertices(positionArray)
this.sdk.viewer.camera.flyToBoundingSphere(BoundingSphere, {
offset: {
heading: Cesium.Math.toRadians(offset.heading || 0),
pitch: Cesium.Math.toRadians((offset.pitch || offset.pitch === 0) ? offset.pitch : -90),
roll: Cesium.Math.toRadians(offset.roll || 0)
}
})
}
activate() {
this.isActivate = true;
}
deactivate() {
this.isActivate = false;
}
}
export default DTH

267
src/Global/DTH/index1.js Normal file
View File

@ -0,0 +1,267 @@
import { getHost, getToken } from "../../on";
class DTH {
constructor(sdk, options = {}) {
this.sdk = sdk
this.primitives = {
building: [],
dth: []
}
this.options = {...options}
this.options.host = this.options.host || getHost()
this.temporaryDth = []
this.dth = {}
this.HandlePickHouseEvent = new Cesium.Event();
this.initEvents()
}
/**
* @description 注册分户点击的事件回调
* @memberOf DTH
* */
houseSelectedCallback(that, cb) {
this.HandlePickHouseEvent.addEventListener(
cb,
that
)
}
//场景事件
initEvents() {
new Cesium.ScreenSpaceEventHandler(this.sdk.viewer.scene.canvas).setInputAction(((e) => {
if (!this.isActivate) return;
let pickFeature = this.sdk.viewer.scene.pick(e.position);
if (pickFeature) {
//点击了已有的分户单体化
if (pickFeature.primitive && pickFeature.primitive instanceof Cesium.ClassificationPrimitive && pickFeature.id && pickFeature.id.type == "dth") {
this.getIDBypickFeature(pickFeature); //处理点击到的楼层
return;
}
if (pickFeature.id && pickFeature.id.type === 'highlight') {
return;
}
}
this.highlightPrimitive && this.sdk.viewer.scene.primitives.remove(this.highlightPrimitive)
let position = this.sdk.viewer.scene.pickPosition(e.position); //屏幕坐标转为笛卡尔空间坐标
if (!position) return;
let c = Cesium.Cartographic.fromCartesian(position); //笛卡尔坐标转为经纬度(弧度)
let point = [Cesium.Math.toDegrees(c.longitude), Cesium.Math.toDegrees(c.latitude)]; //转为经纬度点
this.queryByPoint(point, c.height);
}), Cesium.ScreenSpaceEventType.LEFT_CLICK);
}
/*根据用户信息查询单体化*/
queryByUserInfo(data) {
this.queryByPoint([data.position.lng, data.position.lat], data.position.alt, data.id)
}
//点查询 点击查询是查询分层的数据
async queryByPoint(point) {
let url = ""
if (this.options.host.endsWith("yjearth4.0")) {
url = this.options.host + '/api/v1/dth/query_by_point'
}
else {
url = this.options.host + '/yjearth4.0/api/v1/dth/query_by_point'
}
url += '?point=' + JSON.stringify({'lng': point[0],'lat': point[1]})
let response = await fetch(url, {
method: 'get',
headers: {
'Content-Type': 'application/json',
"token": getToken(),
"Authorization": "Bearer " + getToken(),
}
})
if (response.status === 200) {
let data = await response.json()
if (data.code === 200 || data.code === 0) {
this.clearAllDthPrimitive()
this.addDthPrimitive(data.data.list)
}
else {
window.ELEMENT && window.ELEMENT.Message({
message: data.msg || data.message,
type: 'warning',
duration: 1500
});
}
}
}
// 添加房屋Primitive
async addBuildingPrimitive(array) {
for (let i = 0; i < array.length; i++) {
let fromDegreesArray = []
let extrudedHeight = 0
let positions = JSON.parse(array[i].range)
for (let m = 0; m < positions.length; m++) {
if (extrudedHeight < positions[m].alt) {
extrudedHeight = positions[m].alt
}
fromDegreesArray.push(positions[m].lng, positions[m].lat, 0)
}
let polygonGeometry = new Cesium.PolygonGeometry({
polygonHierarchy: new Cesium.PolygonHierarchy(
Cesium.Cartesian3.fromDegreesArrayHeights(fromDegreesArray)
),
// perPositionHeight: true, //使用z坐标 否则高度从0开始
extrudedHeight: 100000000, //拉伸高度
});
this.primitives.building.push(this.sdk.viewer.scene.primitives.add(
new Cesium.ClassificationPrimitive({
geometryInstances: new Cesium.GeometryInstance({
id: {
...array[i],
},
geometry: Cesium.PolygonGeometry.createGeometry(polygonGeometry),
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
Cesium.Color.fromCssColorString('rgb(255, 235, 59, 0.4)')
),
show: new Cesium.ShowGeometryInstanceAttribute(true),
}
}),
classificationType: Cesium.ClassificationType.CESIUM_3D_TILE,
}), 0
))
}
}
// 根据id删除房屋Primitive
clearBuildingPrimitive(id) {
for (let i = this.primitives.building.length - 1; i >= 0; i--) {
if (id === this.primitives.building[i]._primitiveOptions.geometryInstances[0].id.ID) {
this.sdk.viewer.scene.primitives.remove(this.primitives.building[i])
this.primitives.building.splice(i, 1)
break
}
}
}
// 删除全部房屋Primitive
clearAllBuildingPrimitive() {
for (let i = this.primitives.building.length - 1; i >= 0; i--) {
this.sdk.viewer.scene.primitives.remove(this.primitives.building[i])
}
this.primitives.building = []
}
// 添加单体化Primitive
addDthPrimitive(array) {
let readyIndex = 0
let Primitives = []
for (let i = 0; i < array.length; i++) {
let positions = JSON.parse(array[i].range)
let fromDegreesArray = []
for (let m = 0; m < positions.length; m++) {
fromDegreesArray.push(positions[m].lng, positions[m].lat, array[i].bottom)
}
let polygonGeometry = new Cesium.PolygonGeometry({
polygonHierarchy: new Cesium.PolygonHierarchy(
Cesium.Cartesian3.fromDegreesArrayHeights(fromDegreesArray)
),
perPositionHeight: true, //使用z坐标 否则高度从0开始
extrudedHeight: array[i].height + array[i].bottom, //拉伸高度
});
let Primitive = new Cesium.ClassificationPrimitive({
geometryInstances: new Cesium.GeometryInstance({
id: {
type: 'dth',
...array[i],
},
geometry: Cesium.PolygonGeometry.createGeometry(polygonGeometry),
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
Cesium.Color.fromCssColorString('rgb(255, 235, 59, 0.4)')
),
show: new Cesium.ShowGeometryInstanceAttribute(true),
}
}),
classificationType: Cesium.ClassificationType.CESIUM_3D_TILE,
})
Primitives.push(Primitive)
this.sdk.viewer.scene.primitives.add(Primitive)
Primitive._readyPromise.then(()=>{
this.clearDthPrimitive(Primitive._primitiveOptions.geometryInstances[0].id.ID)
readyIndex ++
if(readyIndex >= array.length) {
this.primitives.dth.push(...Primitives);
}
})
}
}
// 根据id删除单体化Primitive
clearDthPrimitive(id) {
for (let i = this.primitives.dth.length - 1; i >= 0; i--) {
if (id === this.primitives.dth[i]._primitiveOptions.geometryInstances[0].id.ID) {
this.sdk.viewer.scene.primitives.remove(this.primitives.dth[i])
this.primitives.dth.splice(i, 1)
}
}
}
getDthPrimitive(id) {
for (let i = this.primitives.dth.length - 1; i >= 0; i--) {
if (id === this.primitives.dth[i]._primitiveOptions.geometryInstances[0].id.ID) {
return this.primitives.dth[i]
}
}
}
// 删除全部单体化Primitive
clearAllDthPrimitive() {
for (let i = this.primitives.dth.length - 1; i >= 0; i--) {
this.sdk.viewer.scene.primitives.remove(this.primitives.dth[i])
}
this.primitives.dth = []
}
getIDBypickFeature(pickFeature) {
//恢复上一个贴对象面显示
if (this.clickHighlightPrimitive) {
this.clickHighlightPrimitive.show = true;
}
this.highlightPrimitive && this.sdk.viewer.scene.primitives.remove(this.highlightPrimitive)
this.highlightPrimitive = this.sdk.viewer.scene.primitives.add(
new Cesium.ClassificationPrimitive({
geometryInstances: new Cesium.GeometryInstance({
id: {
type: 'highlight',
},
geometry: pickFeature.primitive._primitiveOptions.geometryInstances[0].geometry,
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
Cesium.Color.fromCssColorString('rgb(255, 0, 0, 1)')
),
show: new Cesium.ShowGeometryInstanceAttribute(true),
}
}),
classificationType: Cesium.ClassificationType.CESIUM_3D_TILE,
})
)
this.highlightPrimitive.readyPromise.then(() => {
//设置当前点击的贴对象面不显示
pickFeature.primitive.show = false;
})
this.clickHighlightPrimitive = pickFeature.primitive;
this.handlePickHouse(pickFeature.id)
}
//处理拾取到的户室信息
handlePickHouse(id) {
this.HandlePickHouseEvent.raiseEvent({}); //触发选中事件 通知界面更新
}
activate() {
this.isActivate = true;
}
deactivate() {
this.isActivate = false;
}
}
export default DTH

View File

@ -0,0 +1,53 @@
/**
* @name: index
* @author: Administrator
* @date: 2023-09-11 16:41
* @descriptionindex
* @update: 2023-09-11 16:41
*/
import BillboardObject from "../../Obj/Base/BillboardObject";
import PolygonObject from "../../Obj/Base/PolygonObject";
import PolylineObject from "../../Obj/Base/PolylineObject";
import Circle from "../../Obj/Base/CircleDiffuse";
function exportKml(list = []) {
let entities = new Cesium.EntityCollection();
list.forEach(entity => {
if (
entity instanceof BillboardObject ||
entity instanceof PolygonObject ||
entity instanceof Circle ||
entity instanceof PolylineObject
) {
entities.add(entity.entity)
}
})
if (entities.values.length) {
let promise = Cesium.exportKml({entities})
promise.then(e => {
// Cesium.exportKml(e.kml,)
funDownload(e.kml, new Date().getTime() + ".kml")
})
} else {
console.error("允许导出为kml的对象为空")
}
}
function funDownload(content, filename) {
let eleLink = document.createElement("a");
eleLink.download = filename;
eleLink.style.display = "none";
// 字符内容转变成blob地址
let blob = new Blob([content]);
eleLink.href = URL.createObjectURL(blob);
// 触发点击
document.body.appendChild(eleLink);
eleLink.click();
// 然后移除
document.body.removeChild(eleLink);
}
export default exportKml

View File

@ -0,0 +1,67 @@
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" type="text" name="name">
</div>
<div class="col"></div>
</div>
</div>
<span class="custom-divider"></span>
<div class="div-item">
<div class="row">
<div class="col">
<input type="checkbox" name="isTotalTime" style="width: 16px; line-height: 15px; height: 15px; cursor: pointer; width: auto; margin-right: 5px;">
<span class="label">设置总时长</span>
<div class="input-number input-number-unit-3">
<input class="input total-time" type="number" title="" min="0" max="999999.99" step="0.01" name="totalTime" value="0">
<span class="unit" style="top: 6px;">秒(s)</span>
<span class="arrow"></span>
</div>
</div>
<div class="col">
<input type="checkbox" name="repeat" style="width: 16px; line-height: 15px; height: 15px; cursor: pointer; width: auto; margin-right: 5px;">
<span class="label">是否循环播放</span>
</div>
</div>
</div>
<span class="custom-divider"></span>
<div class="div-item">
<div class="row">
<div class="col">
<button class="add-point"><svg class="icon-add"><use xlink:href="#yj-icon-add"></use></svg>增加视点</button>
</div>
<div class="col">
<button class="modify-point"><svg class="icon-edit"><use xlink:href="#yj-icon-edit"></use></svg>调整视点</button>
</div>
<div class="col">
<button class="afreshPlay"><svg class="icon-play"><use xlink:href="#yj-icon-play"></use></svg>播放</button>
</div>
<div class="col">
<button class="cease"><svg class="icon-pause"><use xlink:href="#yj-icon-pause"></use></svg>结束</button>
</div>
</div>
<div class="table">
<div class="table-head">
<div class="tr">
<div class="th">序号</div>
<div class="th">时长(s)</div>
<div class="th">操作</div>
</div>
</div>
<div class="table-body">
<div class="table-empty">
<div class="empty-img"></div>
<p>暂无数据</p>
</div>
</div>
</div>
</div>
<span class="custom-divider"></span>
`
}
export { html }

389
src/Global/FlyRoam/index.js Normal file
View File

@ -0,0 +1,389 @@
/**
* @description 飞行漫游
*/
import Dialog from '../../BaseDialog';
import { html } from "./_element";
import Tools from "../../Tools";
import { closeRotateAround, closeViewFollow} from '../../Global/global'
let _DialogObject = null
let clickHandler
let repeat = 0
let currentRepeat = 0
const open = async (sdk, options = {}, _Dialog = {}) => {
let name = options.name || '漫游路径'
options.points || (options.points = [])
if(options.repeat) {
repeat = Number(options.repeat)
}
let viewer = sdk.viewer
let tools = new Tools(sdk)
let active = 0
if (_DialogObject && _DialogObject.close) {
_DialogObject.close()
_DialogObject = null
}
_DialogObject = await new Dialog(viewer._container, {
title: '飞行漫游', left: '180px', top: '100px',
closeCallBack: () => {
cease({ viewer })
},
})
await _DialogObject.init()
let contentElm = document.createElement('div');
contentElm.className = 'fly-roam'
contentElm.innerHTML = html()
_DialogObject.contentAppChild(contentElm)
let all_elm = contentElm.getElementsByTagName("*")
// EventBinding(all_elm)
let tableBody = contentElm.getElementsByClassName('table-body')[0];
let tableEmpty = contentElm.getElementsByClassName('table-empty')[0]
let handler = {
set: function (target, prop, value) {
target[prop] = value;
if (target.length > 0) {
tableEmpty.style.display = 'none'
}
else {
tableEmpty.style.display = 'flex'
}
return true;
},
};
let i = 0
let points = new Proxy([], handler);
for (i = 0; i < options.points.length; i++) {
points.push(options.points[i])
addTrElm(options.points[i])
}
// let nameImputBoxElm = contentElm.getElementsByClassName('input-box')[0]
// check(nameImputBoxElm, { validator: 'notEmpty', message: '名称不能为空!', trigger: 'input' })
let nameElm = contentElm.querySelector("input[name='name']")
nameElm.value = name
nameElm.addEventListener('input', () => {
name = nameElm.value
})
let addListBtn = document.createElement('button');
addListBtn.innerHTML = '保存'
addListBtn.addEventListener('click', () => {
if (!name) {
name = '漫游路径'
nameElm.value = name
}
let newPoints = []
points.map((item) => {
newPoints.push(item)
})
_Dialog.clickSavePath && _Dialog.clickSavePath(
{
name: name,
points: newPoints,
repeat: repeat+''
}
)
})
_DialogObject.footAppChild(addListBtn)
let endBtn = contentElm.getElementsByClassName('cease')[0]
endBtn.addEventListener('click', () => {
viewer.camera.cancelFlight()
})
let flyBtn = contentElm.getElementsByClassName('afreshPlay')[0]
flyBtn.addEventListener('click', () => {
if (points.length > 0) {
flyTo(sdk, points, 0)
}
})
let addBtn = contentElm.getElementsByClassName('add-point')[0]
addBtn.addEventListener('click', () => {
let position = tools.cartesian3Towgs84(viewer.camera.position, viewer)
let time = 0
let data = {
duration: time,
position: position,
orientation: {
heading: viewer.camera.heading,
pitch: viewer.camera.pitch,
roll: viewer.camera.roll
}
}
points.splice(active, 0, data)
addTrElm(data)
i++
})
let modifyBtn = contentElm.getElementsByClassName('modify-point')[0]
modifyBtn.addEventListener('click', () => {
if (!active) {
return
}
let position = tools.cartesian3Towgs84(viewer.camera.position, viewer)
points[active - 1].position = position
points[active - 1].orientation = {
heading: viewer.camera.heading,
pitch: viewer.camera.pitch,
roll: viewer.camera.roll
}
})
let totalTimeElm = contentElm.querySelector("input[name='totalTime']")
let isTotalTimeElm = contentElm.querySelector("input[name='isTotalTime']")
let repeatElm = contentElm.querySelector("input[name='repeat']")
isTotalTimeElm.addEventListener('change', () => {
let trList = tableBody.getElementsByClassName('tr')
if (isTotalTimeElm.checked && trList.length > 0) {
let time = Number((Number(totalTimeElm.value) / (trList.length - 1)).toFixed(2))
for (let i = 0; i < trList.length - 1; i++) {
points[i].duration = time
trList[i].querySelector("input[name='time']").value = time
}
trList[trList.length - 1].querySelector("input[name='time']").value = 0
}
})
totalTimeElm.addEventListener('blur', () => {
let trList = tableBody.getElementsByClassName('tr')
totalTimeElm.value = Number(totalTimeElm.value)
if (totalTimeElm.value < 0) {
totalTimeElm.value = 0
}
if (isTotalTimeElm.checked && trList.length > 0) {
let time = Number((Number(totalTimeElm.value) / (trList.length - 1)).toFixed(2))
for (let i = 0; i < trList.length - 1; i++) {
points[i].duration = time
trList[i].querySelector("input[name='time']").value = time
}
trList[trList.length - 1].querySelector("input[name='time']").value = 0
}
})
repeatElm.checked = (repeat === Infinity ? true : false)
repeatElm.addEventListener('change', () => {
if (repeatElm.checked) {
repeat = Infinity
}
else {
repeat = 0
}
currentRepeat = repeat
_Dialog.changeRepeatStateCallBack && _Dialog.changeRepeatStateCallBack(repeatElm.checked)
})
// Object.defineProperty(options, 'points', {
// get() {
// return e_allArea.value
// },
// set(value) {
// e_allArea.value = value
// }
// })
function addTrElm(data) {
let trList = tableBody.getElementsByClassName('tr')
if (trList.length > 0) {
trList[trList.length - 1].querySelector("input[name='time']").disabled = undefined
}
let tr_active = tableBody.getElementsByClassName('tr active')[0]
tr_active && (tr_active.className = 'tr')
let tr = document.createElement('div');
tr.className = 'tr active'
tr.innerHTML = `
<div class="td" style="justify-content: center;">视点${i + 1}</div>
<div class="td">
<input class="input time" type="number" title="" min="0" max="999.99" step="0.01" name="time" value="${data.duration}">
</div>
<div class="td action">
<button class="play">播放</span>
<button class="delete">删除</span>
</div>
`
tr.addEventListener('click', (v) => {
if (v.target.parentNode === tr) {
let tr_active = tableBody.getElementsByClassName('tr active')[0]
tr_active && (tr_active.className = 'tr')
tr.className = 'tr active'
for (let m = 0; m < trList.length; m++) {
if (trList[m] === tr) {
active = m + 1
break
}
}
}
})
tr.addEventListener('dblclick', (v) => {
if (v.target.parentNode === tr) {
for (let m = 0; m < trList.length; m++) {
if (trList[m] === tr) {
viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(points[m].position.lng, points[m].position.lat, points[m].position.alt),
orientation: points[m].orientation,
duration: 1
})
break
}
}
}
})
let e_play = tr.getElementsByClassName('play')[0]
let e_delete = tr.getElementsByClassName('delete')[0]
let e_time = tr.querySelector("input[name='time']")
e_play.addEventListener('click', () => {
for (let m = 0; m < trList.length; m++) {
if (trList[m] === e_delete.parentNode.parentNode) {
flyTo(sdk, points, m)
}
}
})
e_delete.addEventListener("click", (v) => {
for (let m = 0; m < trList.length; m++) {
if (trList[m] === e_delete.parentNode.parentNode) {
points.splice(m, 1)
points[points.length-1] && (points[points.length-1].duration = 0)
tableBody.removeChild(tr)
if (active > m + 1) {
active--
trList[active - 1].className = 'tr active'
}
else if (active == m + 1) {
if (trList.length == m) {
active -= 1
}
if (trList.length != 0) {
trList[active - 1].className = 'tr active'
}
}
// else if(active == m) {
// console.log(trList.length-1, active)
// if (trList.length == active-1) {
// trList[active-2].className = 'tr active'
// }
// else {
// trList[active-1].className = 'tr active'
// }
// }
if (trList.length > 0) {
let lastElm = trList[trList.length - 1].querySelector("input[name='time']")
lastElm.disabled = 'disabled'
lastElm.value = 0
}
break
}
}
// points.splice(i, 1)
// tableBody.removeChild(tr)
// if (trList.length > 0) {
// trList[trList.length - 1].querySelector("input[name='time']").disabled = 'disabled'
// }
})
e_time.addEventListener('input', (v) => {
isTotalTimeElm.checked = false
data.duration = Number(e_time.value)
if (data.duration < 0) {
data.duration = 0
}
})
e_time.addEventListener('blur', () => {
e_time.value = Number(Number(e_time.value).toFixed(2))
if (e_time.value < 0) {
e_time.value = 0
}
});
tableBody.insertBefore(tr, trList[active])
active++
trList[trList.length - 1].querySelector("input[name='time']").disabled = 'disabled'
}
}
const close = () => {
if (_DialogObject && _DialogObject.close) {
_DialogObject.close()
_DialogObject = null
}
}
const executeFlyTo = (sdk, points = [], index = 0, noStart) => {
if (clickHandler) {
clickHandler.destroy()
}
clickHandler = new Cesium.ScreenSpaceEventHandler(sdk.viewer.canvas)
clickHandler.setInputAction((movement) => {
cease(sdk)
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
let viewer = sdk.viewer
viewer.camera.cancelFlight()
// function pauseExecution(seconds) {
// return new Promise(resolve => setTimeout(resolve, seconds * 1000));
// }
closeRotateAround(sdk)
closeViewFollow(sdk)
viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(points[index].position.lng, points[index].position.lat, points[index].position.alt),
orientation: points[index].orientation,
duration: noStart ? points[index - 1].duration : 0.5,
maximumHeight: points[index].position.alt,
complete: async () => {
if (!noStart) {
// await pauseExecution(2)
}
index++
if (index <= points.length - 1) {
executeFlyTo(sdk, points, index, true)
}
else if (currentRepeat && points.length > 1) {
currentRepeat--
executeFlyTo(sdk, points, 0)
}
else {
if (clickHandler) {
clickHandler.destroy()
}
}
},
easingFunction: noStart ? Cesium.EasingFunction.LINEAR_NONE : Cesium.EasingFunction.EXPONENTIAL_OUT
})
}
const flyTo = (sdk, points = [], index = 0, noStart) => {
currentRepeat = repeat
executeFlyTo(sdk, points, index, noStart)
}
/**设置循环次数 (Infinity: 无限循环)*/
const setRepeat = (v) => {
if (repeat != Number(v)) {
repeat = Number(v)
currentRepeat = repeat
if (_DialogObject && _DialogObject._element && _DialogObject._element.content) {
let repeatElm = _DialogObject._element.content.querySelector("input[name='repeat']")
if (v === Infinity) {
repeatElm.checked = true
}
else {
repeatElm.checked = false
}
}
}
}
/** 停止 */
const cease = (sdk) => {
sdk && sdk.viewer && sdk.viewer.camera.cancelFlight()
if (clickHandler) {
clickHandler.destroy()
}
}
export { open, close, flyTo, setRepeat, cease }

View File

@ -0,0 +1,235 @@
/*
* @Description: 使用键盘控制地图漫游
* @Version: 1.0
* @Author: Julian
* @Date: 2022-04-07 16:04:07
* @LastEditors: Julian
* @LastEditTime: 2022-04-07 18:40:40
*/
/**
* @description: 使用键盘控制地图漫游初始化
* @param {*} _viewer
* @return {*}
*/
function keyboardMapRoamingInit(_viewer) {
// 添加键盘监听事件
document.addEventListener('keydown', keyDown.bind(_viewer), false);
document.addEventListener('keyup', keyUp.bind(_viewer), false);
// 为每一帧添加监听事件
_viewer && _viewer.clock.onTick.addEventListener(function () {
keyboardMapRoamingRender(_viewer);
});
}
// 定义事件组
let flags = {
// 相机位置
moveForward: false,
moveBackward: false,
moveLeft: false,
moveRight: false,
moveUp: false,
moveDown: false,
// 相机姿态
lookUp: false,
lookDown: false,
lookLeft: false,
lookRight: false,
twistLeft: false,
twistRight: false,
// 缩放
zoomIn: false,
zoomOut: false
}
// 相机位置W向前S向后D向右A向左Q升高E降低
// 相机姿态抬头低头左转右转0顺时针.:逆时针
// 缩放:+:放大,-:缩小;
/**
* @description: 根据键盘输入字符返回事件信息
* @param {*} key
* @return {*}
*/
function getFlagFromKeyboard(key) {
switch (key) {
// 按字符的Unicode编码
// 相机位置
case 87:
return 'moveForward';
case 83:
return 'moveBackward';
case 68:
return 'moveRight';
case 65:
return 'moveLeft';
case 81:
return 'moveUp';
case 69:
return 'moveDown';
// 相机姿态
case 38:
return 'lookUp';
case 40:
return 'lookDown';
case 37:
return 'lookLeft';
case 39:
return 'lookRight';
case 96:
return 'twistLeft';
case 110:
return 'twistRight';
// 缩放
case 107:
return 'zoomIn';
case 109:
return 'zoomOut';
default:
return undefined;
}
}
/**
* @description: 键盘按下
* @param {*} event
* @return {*}
*/
function keyDown(event) {
let _viewer = this
// 判断是否有输入框聚焦
function isInputFocused() {
const activeElement = document.activeElement;
return (activeElement.tagName.toLowerCase() === 'input' && activeElement.type !== 'checkbox') ||
activeElement.tagName.toLowerCase() === 'textarea' ||
activeElement.getAttribute('role') === 'textarea';
}
if (isInputFocused()) {
// console.log('页面上有输入框已经获取焦点');
} else if (_viewer.trackedEntity) {
// console.log('视角跟随中');
} else if (_viewer._firstPersonView) {
// console.log('第一人称视角中');
} else if (_viewer._disableKeyboardEvent) {
// console.log('禁用键盘事件');
} else if (event.ctrlKey && event.altKey) {
if (event.key === 'v' || event.key === 'V') {
let camera = _viewer.camera
_viewer._CAMERA_SHORTCUT_VIEW = {
orientation: { heading: camera.heading, pitch: camera.pitch, roll: camera.roll },
position: { x: camera.position.x, y: camera.position.y, z: camera.position.z }
}
localStorage.setItem('CAMERA_SHORTCUT_VIEW', JSON.stringify(_viewer._CAMERA_SHORTCUT_VIEW))
}
if (event.key === 'f' || event.key === 'F') {
let CAMERA_SHORTCUT_VIEW = localStorage.getItem('CAMERA_SHORTCUT_VIEW')
_viewer._CAMERA_SHORTCUT_VIEW = JSON.parse(CAMERA_SHORTCUT_VIEW)
if (_viewer._CAMERA_SHORTCUT_VIEW && _viewer._CAMERA_SHORTCUT_VIEW.position && _viewer._CAMERA_SHORTCUT_VIEW.orientation) {
_viewer.camera.flyTo({
destination: _viewer._CAMERA_SHORTCUT_VIEW.position,
orientation: _viewer._CAMERA_SHORTCUT_VIEW.orientation
})
}
}
} else {
// console.log('页面上没有输入框获取焦点');
let flagName = getFlagFromKeyboard(event.keyCode);
if (typeof flagName !== 'undefined') {
flags[flagName] = true;
}
}
}
/**
* @description: 键盘弹起
* @param {*} event
* @return {*}
*/
function keyUp(event) {
let flagName = getFlagFromKeyboard(event.keyCode);
if (typeof flagName !== 'undefined') {
flags[flagName] = false;
}
}
/**
* @description: 根据事件调整相机
* @param {*} _viewer
* @return {*}
*/
function keyboardMapRoamingRender(_viewer) {
if(!_viewer.scene.screenSpaceCameraController.enableTilt) {
return
}
let camera = _viewer.camera;
let ellipsoid = _viewer.scene.globe.ellipsoid;
let cameraHeight = ellipsoid.cartesianToCartographic(camera.position).height;
// 根据相机高度设置移动距离,比默认距离移动效果更好
let moveRate = cameraHeight / 20.0;
let rotationRate = moveRate / 500000 / Cesium.Math.toDegrees(camera.pitch);
if (flags.moveForward) {
// camera.moveForward(moveRate);
camera.rotate(camera.right, -rotationRate);
}
if (flags.moveBackward) {
// camera.moveBackward(moveRate);
camera.rotate(camera.right, rotationRate);
}
if (flags.moveLeft) {
// camera.moveLeft(moveRate);
camera.rotate(camera.up, -rotationRate);
}
if (flags.moveRight) {
// camera.moveRight(moveRate);
camera.rotate(camera.up, rotationRate);
}
if (flags.moveUp) {
camera.moveUp(moveRate);
}
if (flags.moveDown) {
camera.moveDown(moveRate);
}
if (flags.lookUp) {
camera.lookUp();
}
if (flags.lookDown) {
camera.lookDown();
}
if (flags.lookLeft) {
camera.lookLeft();
}
if (flags.lookRight) {
camera.lookRight();
}
if (flags.twistLeft) {
camera.twistLeft();
}
if (flags.twistRight) {
camera.twistRight();
}
// 根据相机高度设置缩放参数
if (flags.zoomIn) {
let height = cameraHeight / 2
if (height < 1) {
height = 0
}
camera.zoomIn(height);
}
if (flags.zoomOut) {
let height = cameraHeight / 2
if ((cameraHeight + cameraHeight) >= 50000000) {
height = 50000000 - cameraHeight
}
camera.zoomOut(height);
}
}
export { keyboardMapRoamingInit }

View File

@ -0,0 +1,117 @@
function getTemplateData(tools) {
return [
{
"name": "模板一",
"value": "模板一",
"id": "1",
margin: 0.03,
title: {
text: '标题一',
height: 0.05,
bgColor: '#5d5d5d',
color: '#ffffff',
show: true,
},
border: {
show: false,
url: '/custom/img/map-border1.svg',
width: 0.01,
color: ''
},
plottingScale: {
cell: 2,
color: '#ffffff',
show: true,
isSelected: false,
x: 0.87,
y: 0.97,
},
data: [
{
text: '',
x: 0.02,
y: 0.93,
isSelected: false,
show: true,
color: '#ffffff',
height: 0.03
},
{
text: '',
x: 0.02,
y: 0.97,
isSelected: false,
show: true,
color: '#ffffff',
height: 0.03
},
{
x: 0.02,
y: 0.1,
show: false,
isSelected: false,
url: '/custom/img/icon-compass1.svg',
width: 0.1,
height: 0.1
}
]
},
{
"name": "模板二",
"value": "模板二",
"id": "2",
margin: 0.03,
border: {
show: true,
url: '/custom/img/map-border2.svg',
width: 0.01,
},
title: {
text: '标题二',
height: 0.05,
bgColor: '#5d5d5d',
color: '#ffffff',
show: true,
},
plottingScale: {
cell: 2,
color: '#ffffff',
show: true,
isSelected: false,
x: 0.02,
y: 0.97,
},
data: [
{
text: '',
x: 0.88,
y: 0.93,
isSelected: false,
show: true,
color: '#ffffff',
height: 0.03
},
{
text: '',
x: 0.87,
y: 0.97,
isSelected: false,
show: true,
color: '#ffffff',
height: 0.03
},
{
x: 0.91,
y: 0.1,
show: true,
isSelected: false,
url: '/custom/img/icon-compass4.svg',
width: 0.1,
height: 0.1
}
]
}
]
}
export { getTemplateData };

1449
src/Global/MapPrint/index.js Normal file

File diff suppressed because it is too large Load Diff

170
src/Global/MapX/index.js Normal file
View File

@ -0,0 +1,170 @@
import Tools from '../../Tools'
import Event from '../../Event'
let tools
let Xevent
let mapx = {}
let curRectangle = undefined;
let centerResult = undefined
let mouseStart = false
let syncObject = {}
const init = (sdk) => {
tools = new Tools()
let div = document.createElement('div');
div.id = 'mapxDiv'
div.style.width = '222px';
div.style.height = '112px';
div.style.position = 'absolute';
div.style.right = '10px';
div.style.bottom = '82px';
div.style.zIndex = '1';
document.getElementById(sdk.div_id).appendChild(div)
let options = {
imageryProvider: new Cesium.TileMapServiceImageryProvider({
url: Cesium.buildModuleUrl("Assets/Textures/NaturalEarthII"),
}),
sceneMode: Cesium.SceneMode.SCENE2D,
// mapMode2D: Cesium.MapMode2D.ROTATE,
baseLayerPicker: false,
geocoder: false,
animation: false,
fullscreenButton: false,
navigationHelpButton: false,
// vrButton?: boolean;
homeButton: false,
infoBox: false,
sceneModePicker: false,
selectionIndicator: false,
timeline: false,
shouldAnimate: true
}
mapx.viewer = new Cesium.Viewer('mapxDiv', options);
mapx.viewer.camera.setView({
destination: Cesium.Cartesian3.fromDegrees(0, 0, 40000000),
})
mapx.viewer.trackedEntity = undefined;
mapx.viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(
Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK
);
mapx.viewer.scene.screenSpaceCameraController.enableRotate = false;
mapx.viewer.scene.screenSpaceCameraController.enableTranslate = false;
mapx.viewer.scene.screenSpaceCameraController.enableZoom = false;
mapx.viewer.scene.screenSpaceCameraController.enableTilt = false;
mapx.viewer.scene.screenSpaceCameraController.enableLook = false;
// 创建范围框
let entity = mapx.viewer.entities.add({
name: 'mapX rectangle',
position: new Cesium.CallbackProperty(function () {
return (
centerResult || Cesium.Cartesian3.fromDegrees(0, 0, 0)
);
}, false),
rectangle: {
coordinates: new Cesium.CallbackProperty(function () {
return (
curRectangle || Cesium.Rectangle.fromDegrees(0.0, 0.0, 0.01, 0.01)
);
}, false),
material: Cesium.Color.RED.withAlpha(0.01),
outline: true,
outlineColor: Cesium.Color.RED,
outlineWidth: 2,
height: 1,
},
billboard: {
image: tools.getSourceRootPath() + '/img/cross.svg',
scale: 1,
width: 16,
height: 16
},
});
syncObject = { sdk, entity }
mapx.viewer.camera.percentageChanged = 0.001;
sdk.viewer.scene.preRender.addEventListener(syncViewer, syncObject); // 鹰眼与主图同步
let pick
Xevent = new Event({ viewer: mapx.viewer })
Xevent.mouse_left_down((movement, cartesian) => {
mouseStart = true
pick = mapx.viewer.scene.pick(movement.position)
})
Xevent.mouse_left_up((movement, cartesian) => {
mouseStart = false
})
Xevent.mouse_move((movement, cartesian) => {
if (pick && mouseStart) {
let sdkCH = tools.cartesian3Towgs84(sdk.viewer.camera.position, sdk.viewer).alt
let pos84 = tools.cartesian3Towgs84(cartesian, mapx.viewer)
// sdk.viewer.camera.position = Cesium.Cartesian3.fromDegrees(pos84.lng, pos84.lat, sdkCH)
sdk.viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(pos84.lng, pos84.lat, sdkCH),
duration: 0
})
}
})
}
function syncViewer() {
if(!this.sdk || !this.sdk.viewer) {
return
}
// 视角中心点(伪)
centerResult = this.sdk.viewer.camera.pickEllipsoid(
new Cesium.Cartesian2(
this.sdk.viewer.canvas.clientWidth / 2,
this.sdk.viewer.canvas.clientHeight / (2 - ((90 + this.sdk.viewer.camera.pitch / (Cesium.Math.PI / 180)) / 110)),
),
)
if (!centerResult) {
centerResult = this.sdk.viewer.camera.position
}
let height = tools.cartesian3Towgs84(this.sdk.viewer.camera.position, this.sdk.viewer).alt
let centerResult84 = tools.cartesian3Towgs84(centerResult, this.sdk.viewer)
let stepX = 120000
let stepY = 280000
if (height > 9000000) {
height = 9000000
}
if (height < 100000) {
this.entity.billboard.show = true
this.entity.rectangle.show = false
}
else {
this.entity.billboard.show = false
this.entity.rectangle.show = true
}
curRectangle = new Cesium.Rectangle(Cesium.Math.toRadians(centerResult84.lng - (height / stepX)), Cesium.Math.toRadians(centerResult84.lat - (height / stepY)), Cesium.Math.toRadians(centerResult84.lng + (height / stepX)), Cesium.Math.toRadians(centerResult84.lat + (height / stepY)))
};
function open(sdk) {
if (!mapx.viewer) {
init(sdk)
}
else {
mapx.viewer.container.style.display = 'block';
let entity
let entities = mapx.viewer.entities.values
for (let i = 0; i < entities.length; i++) {
if (entities[i].name === 'mapX rectangle') {
entity = entities[i]
break
}
}
sdk.viewer.scene.preRender.addEventListener(syncViewer, syncObject); // 鹰眼与主图同步
}
}
function close(sdk) {
if (!mapx.viewer) {
return
}
mapx.viewer.container.style.display = 'none';
let entity
let entities = mapx.viewer.entities.values
for (let i = 0; i < entities.length; i++) {
if (entities[i].name === 'mapX rectangle') {
entity = entities[i]
break
}
}
sdk.viewer.scene.preRender.removeEventListener(syncViewer, syncObject)
}
export { open, close }

View File

@ -0,0 +1,112 @@
/**
* 鼠标坐标
*/
import Tools from "../../Tools";
import { getCoordinateSystem } from "../../Global/global";
import MouseEvent from '../../Event/index'
let event
let MouseCoordinateElm
let requestAnimationFrameEventId
const MouseCoordinate = (sdk, status) => {
let tools = new Tools(sdk)
if (status) {
if (event) {
event.destroy()
}
event = new MouseEvent(sdk)
let position = {
x: '',
y: '',
z: ''
}
let contentElm
if (MouseCoordinateElm) {
contentElm = MouseCoordinateElm
}
else {
contentElm = document.createElement('div');
contentElm.style.position = 'absolute';
contentElm.style['z-index'] = 777;
contentElm.style.color = '#ff0000';
contentElm.style.left = '0px';
contentElm.style.top = '0px';
contentElm.style.width = '100%';
contentElm.style.height = '100%';
contentElm.style['font-size'] = '12px';
contentElm.style['pointer-events'] = 'none';
contentElm.style.background = `url(${tools.getSourceRootPath()}/img/cross.png) no-repeat 100% 100%`;
contentElm.style['background-size'] = `200% 200%`;
MouseCoordinateElm = contentElm
}
sdk.viewer._element.appendChild(contentElm)
let tmovement
event.mouse_move((movement, cartesian) => {
tmovement = { ...movement }
})
const getPosition = () => {
if(!tmovement) {
return
}
let canvas = sdk.viewer._element.getElementsByTagName('canvas')[0]
let left = tmovement.endPosition.x;
let top = tmovement.endPosition.y;
let cartesian = event.getcartesian(tmovement)
contentElm.style['background-position-x'] = `${-canvas.width + left + 4}px`;
contentElm.style['background-position-y'] = `${-canvas.height + top - 2}px`;
// this.entity.position = cartesian
if (cartesian) {
let degrees = tools.cartesian3Towgs84(cartesian, sdk.viewer)
let coordinateSystem = getCoordinateSystem()
if (coordinateSystem === 'EPSG:4326') {
position = {
x: degrees.lng,
y: degrees.lat,
z: degrees.alt
}
contentElm.innerHTML = `<div style='width: 150px;position: absolute; z-index: 777; color: #ff0000; font-size: 12px; left:${left + 20}px; top:${top + 10}px;'><p style='margin: 0;'>经度:${degrees.lng.toFixed(6)}°</p><p style='margin: 0;'>维度:${degrees.lat.toFixed(6)}°</p><p style='margin: 0;'>海拔:${degrees.alt.toFixed(2)} m</p></div>`
}
else {
let result = tools.convert([{ x: degrees.lng, y: degrees.lat, z: degrees.alt }], 'EPSG:4326', coordinateSystem)
position = result.points[0]
contentElm.innerHTML = `<div style='width: 150px;position: absolute; z-index: 777; color: #ff0000; font-size: 12px; left:${left + 20}px; top:${top + 10}px;'><p style='margin: 0;'>x${position.x.toFixed(6)}</p><p style='margin: 0;'>y${position.y.toFixed(6)}</p><p style='margin: 0;'>z${position.z.toFixed(6)}</p></div>`
}
}
else {
let coordinateSystem = getCoordinateSystem()
if (coordinateSystem === 'EPSG:4326') {
contentElm.innerHTML = `<div style='width: 150px;position: absolute; z-index: 777; color: #ff0000; font-size: 12px; left:${left + 20}px; top:${top + 10}px;'><p style='margin: 0;'>经度:-</p><p style='margin: 0;'>维度:-</p><p style='margin: 0;'>海拔:-</p></div>`
}
else {
contentElm.innerHTML = `<div style='width: 150px;position: absolute; z-index: 777; color: #ff0000; font-size: 12px; left:${left + 20}px; top:${top + 10}px;'><p style='margin: 0;'>x-</p><p style='margin: 0;'>y-</p><p style='margin: 0;'>z-</p></div>`
}
}
}
animateUpdate()
function animateUpdate() {
requestAnimationFrameEventId = requestAnimationFrame(
animateUpdate
)
getPosition()
}
}
else {
if (event) {
event.destroy()
event = undefined
}
if (MouseCoordinateElm) {
sdk.viewer._element.removeChild(MouseCoordinateElm)
MouseCoordinateElm = undefined
}
if (requestAnimationFrameEventId) {
cancelAnimationFrame(requestAnimationFrameEventId)
}
}
}
export { MouseCoordinate }

View File

@ -0,0 +1,561 @@
/**
* 多视口模式
* */
import Tools from "../../Tools";
import MouseEvent from '../../Event'
import { CesiumContainer } from '../global'
import { off as offSplitScreen } from "../SplitScreen";
import { FlwStatusSwitch, JwwStatusSwitch, getFlwStatus, getJwwStatus } from "../global"
import { SheetIndexStatusSwitch, getStatus } from '../SheetIndex'
let sdk2D
let sdk3D
let activeViewer
let controlViewer
let syncObject = {}
let handlers = []
async function init(sdk) {
sdk3D = sdk
activeViewer = 0
let tools = new Tools()
let sdk2 = await new YJ.YJEarth(sdk.div_id)
sdk2.viewer._element.className = 'cesium-viewer 2d'
SheetIndexStatusSwitch(sdk2, getStatus())
// setTimeout(() => {
// let switchCluster = new YJ.Global.switchCluster(sdk2, true)
// }, 500);
CesiumContainer(sdk2, {
compass: false, // 罗盘
// legend: false, // 比例尺
info: false, // 信息栏
frame: false // 刷新率
})
sdk2.viewer.scene.mode = Cesium.SceneMode.SCENE2D
sdk2D = await sdk2
// window.sdk2D = sdk2D
solveBug()
syncObject = { sdks: [sdk, sdk2], tools }
await eventBind(sdk, 0, syncObject)
await eventBind(sdk2, 1, syncObject)
await syncData(sdk)
sdk.viewer.scene.preRender.addEventListener(syncViewer, syncObject)
sdk.viewer.imageryLayers.layerAdded.addEventListener(syncImageryLayerAdded);
sdk.viewer.imageryLayers.layerMoved.addEventListener(syncImageryLayerMoved);
sdk.viewer.imageryLayers.layerRemoved.addEventListener(syncImageryLayerRemoved);
sdk.viewer.imageryLayers.layerShownOrHidden.addEventListener(syncImageryLayerShownOrHidden);
let imageryLayers = [...sdk.viewer.imageryLayers._layers]
imageryLayers.sort((a, b) => a._layerIndex - b._layerIndex);
sdk2D.viewer.imageryLayers.removeAll()
for (let i = 0; i < imageryLayers.length; i++) {
let entity = sdk2D.viewer.imageryLayers.addImageryProvider(imageryLayers[i].imageryProvider, imageryLayers[i]._layerIndex)
entity.show = imageryLayers[i].show
}
// sdk.viewer.entities.collectionChanged.addEventListener(syncEntities)
// sdk.viewer.dataSources.dataSourceAdded.addEventListener(syncDataSources)
if (getFlwStatus(sdk)) {
FlwStatusSwitch(sdk2, true)
}
if (getJwwStatus(sdk)) {
JwwStatusSwitch(sdk2, true)
}
}
async function on(sdk) {
if (sdk2D) {
}
else {
init(sdk)
offSplitScreen()
}
}
function off(sdk) {
sdk.viewer.scene.preRender.removeEventListener(syncViewer, syncObject)
sdk.viewer.imageryLayers.layerAdded.removeEventListener(syncImageryLayerAdded);
sdk.viewer.imageryLayers.layerMoved.removeEventListener(syncImageryLayerMoved);
sdk.viewer.imageryLayers.layerRemoved.removeEventListener(syncImageryLayerRemoved);
sdk.viewer.imageryLayers.layerShownOrHidden.removeEventListener(syncImageryLayerShownOrHidden);
// sdk.viewer.entities.collectionChanged.removeEventListener(syncEntities)
// sdk.viewer.dataSources.dataSourceAdded.removeEventListener(syncDataSources)
//primitiveAdded=undefined基元同步设置在add位置
// sdk.viewer.scene.primitives.primitiveAdded.removeEventListener(syncPrimitivesAdded)
for (let i = 0; i < handlers.length; i++) {
handlers[i].destroy()
}
if (sdk2D) {
sdk2D.destroy()
handlers = []
sdk2D = null
sdk3D = null
activeViewer = null
syncObject = {}
}
}
async function syncData2(sdk, id, entityId) {
if (sdk && sdk.viewer && sdk.viewer._element && sdk.viewer._element.className === 'cesium-viewer 2d') {
return
}
if (!sdk3D || !sdk2D) {
return
}
let entityMap = sdk3D.entityMap
if (id) {
let that = entityMap.get(id)
if (that) {
let that2 = sdk2D.entityMap.get(id)
if (that2) {
await that2.remove()
}
let options = syncObject.tools.deepCopyObj(that.options)
if (that.type === 'BillboardObject') {
options.heightReference = 1
}
if (that.type === 'PolygonObject') {
options.heightMode = 0
options.height = 0
}
if (!that.type || (that.type !== 'tileset' && that.type !== 'bim' && that.type !== 'glb' && that.type !== 'layer')) {
let newObject = await new that.constructor(sdk2D, options)
newObject.onClick = that.onClick
newObject.onRightClick = that.onRightClick
newObject.onMouseMove = that.onMouseMove
if (that.type === 'TrajectoryMotion') {
that.firstPersonView = false
if (that.TweenAnimate) {
let state = that.state
if (state) {
that.state = false
}
if (!newObject.state) {
setTimeout(() => {
newObject.setMovePositionByDistance(Number(that.TweenAnimate._object.distance.toFixed(8)) + 0.00000001)
setTimeout(() => {
newObject.setMovePositionByDistance(Number(that.TweenAnimate._object.distance.toFixed(8)) + 0.00000002)
}, 500);
}, 500);
}
else {
newObject.setMovePositionByDistance(Number(that.TweenAnimate._object.distance.toFixed(8)))
}
that.state = state
}
else {
setTimeout(() => {
newObject.setMovePositionByDistance(0.00000001)
setTimeout(() => {
newObject.setMovePositionByDistance(0.00000002)
}, 500)
}, 500)
}
if (that.viewFollow) {
newObject.viewFollow = true
}
}
if (that.type === 'AttackArrowObject' || that.type === 'StraightArrowObject') {
if (that.spreadState && that.TweenAnimate && that.TweenAnimate._object) {
newObject.setSpreadProgressByTime(that.TweenAnimate._object.distance / that.TweenAnimate._valuesEnd.distance * that.spreadTime)
}
}
if (that.type === 'PincerArrowObject') {
if (that.spreadState && that.TweenAnimate && that.TweenAnimate._object) {
newObject.setSpreadProgressByTime(that.TweenAnimate._object.distance1 / that.TweenAnimate._valuesEnd.distance1 * that.spreadTime)
}
}
if (newObject.on && newObject.type !== 'glb') {
if (newObject.type === 'vector') {
newObject.data = that.data
newObject.load(() => {
if (newObject.entity) {
for (let i = 0; i < newObject.entity.entities.values.length; i++) {
newObject.entity.entities.values[i].show = that.entity.entities.values[i]._customShow === false ? false : true
}
}
})
}
await newObject.on()
}
// if (newObject.type && (newObject.type === 'tileset' || newObject.type === 'bim')) {
// newObject.height = -10000
// }
// // Cesium1.98版本二维模式下初次显示有问题1.110以上版本正常
// if (newObject.type && (newObject.type === 'glb')) {
// newObject.options.position.alt = 0
// }
}
}
else {
let that2 = sdk2D.entityMap.get(id)
if (that2) {
await that2.remove()
}
}
}
else {
for (let [key, obj] of sdk2D.entityMap) {
let that = sdk2D.entityMap.get(key)
if (that) {
await that.remove()
}
}
for (let [key, obj] of entityMap) {
if (obj.type === 'BillboardObject') {
obj.options.heightReference = 1
}
let options = syncObject.tools.deepCopyObj(obj.options)
if (!obj.type || (obj.type !== 'tileset' && obj.type !== 'bim' && obj.type !== 'glb' && obj.type !== 'layer')) {
let target = await new obj.constructor(sdk2D, options)
target.onClick = obj.onClick
target.onRightClick = obj.onRightClick
target.onMouseMove = obj.onMouseMove
if (obj.type === 'TrajectoryMotion') {
obj.firstPersonView = false
if (obj.TweenAnimate) {
let state = obj.state
if (state) {
obj.state = false
}
if (!target.state) {
setTimeout(() => {
target.setMovePositionByDistance(Number(obj.TweenAnimate._object.distance.toFixed(8)) + 0.000000001)
setTimeout(() => {
target.setMovePositionByDistance(Number(obj.TweenAnimate._object.distance.toFixed(8)) + 0.000000002)
}, 1500);
}, 1500);
}
else {
target.setMovePositionByDistance(Number(obj.TweenAnimate._object.distance.toFixed(8)))
}
obj.state = state
}
else {
setTimeout(() => {
target.setMovePositionByDistance(0.000000001)
setTimeout(() => {
target.setMovePositionByDistance(0.000000002)
}, 1500);
}, 1500);
}
if (obj.viewFollow) {
target.viewFollow = true
}
// else {
// newObject.viewFollow = false
// }
}
if (obj.type === 'AttackArrowObject' || obj.type === 'StraightArrowObject') {
if (obj.spreadState && obj.TweenAnimate && obj.TweenAnimate._object) {
target.setSpreadProgressByTime(obj.TweenAnimate._object.distance / obj.TweenAnimate._valuesEnd.distance * obj.spreadTime)
}
}
if (obj.type === 'PincerArrowObject') {
if (obj.spreadState && obj.TweenAnimate && obj.TweenAnimate._object) {
target.setSpreadProgressByTime(obj.TweenAnimate._object.distance1 / obj.TweenAnimate._valuesEnd.distance1 * obj.spreadTime)
}
}
if (target.on && obj.type !== 'glb') {
if (target.type === 'vector') {
target.data = obj.data
target.load(() => {
if (target.entity) {
for (let i = 0; i < target.entity.entities.values.length; i++) {
target.entity.entities.values[i].show = obj.entity.entities.values[i]._customShow === false ? false : true
}
}
})
}
await target.on()
}
// if (obj.type && (obj.type === 'tileset' || obj.type === 'bim')) {
// target.height = -10000
// }
// if (obj.type && (obj.type === 'glb')) {
// target.options.position.alt = 0
// }
}
}
}
}
async function syncData(sdk, id, entityId) {
syncData2(sdk, id, entityId)
// syncEntities()
// syncDataSources()
}
function syncEntities(entities1, entities2) {
if (!sdk3D) {
return
}
if (sdk2D) {
if (Array.isArray(entities1) || Array.isArray(entities2)) {
entities1 = null
entities2 = null
}
if (!entities1) {
entities1 = sdk2D.viewer.entities
}
if (!entities2) {
entities2 = sdk3D.viewer.entities
}
let entities2D = entities1
let entities3D = entities2
for (let i = entities2D.values.length - 1; i >= 0; i--) {
let flag = false
for (let m = entities3D.values.length - 1; m >= 0; m--) {
if (entities2D.values[i].id === entities3D.values[m].id) {
flag = true
entities2D.values[i] === entities3D.values[m]
}
}
if (!flag) {
entities2D.remove(entities2D.values[i])
}
}
for (let m = entities3D.values.length - 1; m >= 0; m--) {
let flag = false
for (let i = entities2D.values.length - 1; i >= 0; i--) {
if (entities2D.values[i].id === entities3D.values[m].id) {
flag = true
break
}
}
if (!flag) {
let entity = entities2D.add(entities3D.values[m])
// if (entity.rectangle) {
// // 设置高度,否则在某些位置无法显示,但色彩会变暗
// entity.rectangle.height = 0
// console.log('242342354235',entities3D.values[m])
// }
}
}
}
}
function syncDataSources(dataSources, type) {
if (!sdk3D) {
return
}
if (sdk2D) {
let dataSources2D = sdk2D.viewer.dataSources
if (dataSources) {
for (let i = dataSources2D._dataSources.length - 1; i >= 0; i--) {
if (dataSources2D._dataSources[i].name === dataSources.name) {
if (type === 'entities') {
syncEntities(dataSources2D._dataSources[i].entities, dataSources.entities)
}
if (type === 'clustering') {
dataSources2D._dataSources[i].clustering.enabled = dataSources.clustering.enabled
}
}
}
}
// for (let m = dataSources3D._dataSources.length - 1; m >= 0; m--) {
// let flag = false
// for (let i = dataSources2D._dataSources.length - 1; i >= 0; i--) {
// console.log(dataSources2D._dataSources[i].name, dataSources3D._dataSources[m].name)
// if (dataSources2D._dataSources[i].name === dataSources3D._dataSources[m].name) {
// flag = true
// break
// }
// }
// if (!flag) {
// dataSources2D.add(dataSources3D._dataSources[m])
// }
// }
}
}
function syncImageryLayerAdded(layer, index) {
sdk2D.viewer.imageryLayers.addImageryProvider(layer.imageryProvider, index)
}
function syncImageryLayerMoved(layer, newindxe, oldindex) {
let layer2d = sdk2D.viewer.imageryLayers._layers[oldindex]
if (!layer2d) {
return
}
// 移到最底层
if (newindxe === 0) {
sdk2D.viewer.imageryLayers.lowerToBottom(layer2d)
}
// 移到最高层
else if (newindxe === sdk3D.viewer.imageryLayers._layers.length - 1) {
sdk2D.viewer.imageryLayers.raiseToTop(layer2d)
}
else {
if (newindxe < oldindex) {
sdk2D.viewer.imageryLayers.lower(layer2d)
}
else {
sdk2D.viewer.imageryLayers.raise(layer2d)
}
}
}
function syncImageryLayerRemoved(layer, index) {
let layer2d = sdk2D.viewer.imageryLayers._layers[index]
if (!layer2d) {
return
}
sdk2D.viewer.imageryLayers.remove(layer2d)
}
function syncImageryLayerShownOrHidden(layer, index, state) {
let layer2d = sdk2D.viewer.imageryLayers._layers[index]
if (!layer2d) {
return
}
layer2d.show = state
}
async function syncPrimitives(primitive) {
if (!sdk3D) {
return
}
if (sdk2D) {
// await sdk2D.viewer.scene.primitives.remove(primitive)
// await sdk2D.viewer.scene.primitives.add(primitive)
let primitives2D = sdk2D.viewer.scene.primitives._primitives
let primitives3D = sdk3D.viewer.scene.primitives._primitives
// console.log(primitives2D, primitives3D)
// setTimeout(() => {
// sdk2D.viewer.scene.primitives._primitives[1] = sdk3D.viewer.scene.primitives._primitives[1]
// }, 2000);
for (let i = primitives2D.length - 1; i >= 1; i--) {
let flag = false
for (let m = primitives3D.length - 1; m >= 1; m--) {
if (primitives3D[m].id && primitives2D[m].id && (primitives3D[m].id === primitives2D[i].id)) {
flag = true
}
}
if (!flag) {
sdk2D.viewer.scene.primitives.remove(primitives2D[i])
}
}
for (let m = primitives3D.length - 1; m >= 1; m--) {
let flag = false
for (let i = primitives2D.length - 1; i >= 1; i--) {
if (primitives3D[m].id && primitives2D[m].id && (primitives3D[m].id === primitives2D[i].id)) {
flag = true
primitives2D[i].show = primitives3D[m].show
primitives2D[i].startColor = primitives3D[m].startColor
primitives2D[i].endColor = primitives3D[m].endColor
primitives2D[i].minimumSpeed = primitives3D[m].minimumSpeed
primitives2D[i].maximumSpeed = primitives3D[m].maximumSpeed
primitives2D[i].minimumParticleLife = primitives3D[m].minimumParticleLife
primitives2D[i].maximumParticleLife = primitives3D[m].maximumParticleLife
primitives2D[i].startScale = primitives3D[m].startScale
primitives2D[i].endScale = primitives3D[m].endScale
primitives2D[i].emissionRate = primitives3D[m].emissionRate
primitives2D[i].particleSize = primitives3D[m].particleSize
primitives2D[i].modelMatrix = primitives3D[m].modelMatrix
}
}
if (!flag) {
sdk2D.viewer.scene.primitives.add(primitives3D[m])
}
}
}
}
function eventBind(sdk, i, syncObject) {
let handler = new Cesium.ScreenSpaceEventHandler(
sdk.viewer.canvas
)
handler.setInputAction(() => {
activeViewer = i
}, Cesium.ScreenSpaceEventType.LEFT_DOWN)
handler.setInputAction(() => {
activeViewer = i
}, Cesium.ScreenSpaceEventType.RIGHT_DOWN)
handler.setInputAction(() => {
activeViewer = i
}, Cesium.ScreenSpaceEventType.WHEEL)
handlers.push(handler)
}
function syncViewer() {
let sdk = this.sdks[activeViewer]
let sdk2
if (activeViewer === 0) {
sdk2 = this.sdks[1]
}
else if (activeViewer === 1) {
sdk2 = this.sdks[0]
}
// this.sdks[0].viewer.trackedEntity = null
// this.sdks[1].viewer.trackedEntity = null
if (sdk.viewer.scene.mode === 2) {
if (this.sdks[0].viewer.trackedEntity) {
let distance = sdk.viewer.camera.positionCartographic.height
sdk2.viewer.camera.lookAt(
Cesium.Cartesian3.fromRadians(sdk.viewer.camera.positionCartographic.longitude, sdk.viewer.camera.positionCartographic.latitude, 0),
new Cesium.HeadingPitchRange(0, Cesium.Math.toRadians(-90), distance)
)
}
else {
if (this.sdks[1].viewer.trackedEntity) {
this.sdks[1].viewer.entities.remove(this.sdks[1].viewer.trackedEntity)
this.sdks[1].viewer.trackedEntity = null
}
let centerResult84 = this.tools.cartesian3Towgs84(Cesium.Cartesian3.fromRadians(sdk.viewer.camera.positionCartographic.longitude, sdk.viewer.camera.positionCartographic.latitude, sdk.viewer.camera.positionCartographic.height), sdk.viewer)
sdk2.viewer.camera.setView({
destination: Cesium.Cartesian3.fromDegrees(centerResult84.lng, centerResult84.lat, centerResult84.alt),
})
}
}
else {
// 视角中心点(伪)
let centerResult = sdk.viewer.camera.pickEllipsoid(
new Cesium.Cartesian2(
sdk.viewer.canvas.clientWidth / 2,
sdk.viewer.canvas.clientHeight / (2 - ((90 + sdk.viewer.camera.pitch / (Cesium.Math.PI / 180)) / 110)),
),
)
if (!centerResult) {
centerResult = sdk.viewer.camera.positionWC
}
let height = this.tools.cartesian3Towgs84(sdk.viewer.camera.positionWC, sdk.viewer).alt
let centerResult84 = this.tools.cartesian3Towgs84(centerResult, sdk.viewer)
// console.log('--------------', sdk.viewer.camera.position, sdk.viewer.camera.positionWC, centerResult84, height)
sdk2.viewer.camera.setView({
destination: Cesium.Cartesian3.fromDegrees(centerResult84.lng, centerResult84.lat, height),
// orientation: {
// heading: sdk2.viewer.camera.heading,
// pitch: sdk2.viewer.camera.pitch,
// roll: sdk2.viewer.camera.roll
// }
})
}
}
function get2DView() {
return sdk2D
}
function get3DView() {
return sdk3D
}
function solveBug() {
// 在能显示的地方加载一个多边形解决二维模式下某些地方无法显示多边形的bug原因不明
sdk2D && sdk2D.viewer.entities.add({
show: false,
polygon: {
hierarchy: new Cesium.PolygonHierarchy(Cesium.Cartesian3.fromDegreesArray([100, 50, 100.0001, 50, 100.0001, 50.0001]))
}
})
}
function setActiveViewer(v) {
activeViewer = v
}
export { on, off, syncData, syncEntities, syncDataSources, syncPrimitives, get2DView, get3DView, setActiveViewer }

View File

@ -0,0 +1,92 @@
class ScreenRecord {
constructor() {
this.start()
}
start() {
navigator.mediaDevices.getDisplayMedia({
video: true
})
.then((stream) => {
// 需要更好的浏览器支持
// const mime = MediaRecorder.isTypeSupported('video/webm; codecs=vp9')
// ? 'video/webm; codecs=vp9'
// : 'video/webm'
this.mediaRecorder = new MediaRecorder(stream, {
// mimeType: mime,
mimeType: 'video/webm',
})
let chunks = []
this.mediaRecorder.addEventListener('dataavailable', function (e) {
chunks.push(e.data)
})
this.mediaRecorder.addEventListener('stop', async () => {
try {
let blob = new Blob(chunks, {
type: 'video/mp4',
})
const opts = {
suggestedName: '视频录制.mp4',
types: [
{
description: '文件类型',
accept: {
'video/mp4': ['.mp4'],
}
}
],
excludeAcceptAllOption: true
};
const handle = await window.showSaveFilePicker(opts); // 打开保存文件对话框
const writable = await handle.createWritable(); // 创建可写入的文件对象
// 写入视频内容
writable.write(blob);
await writable.close();
YJ.Global.ScreenRecord.screenRecord = null
} catch (error) {
console.info('文件保存失败:', error);
}
// let blob = new Blob(chunks, {
// type: chunks[0].type,
// })
// let url = URL.createObjectURL(blob)
// let a = document.createElement('a')
// a.href = url
// a.download = 'video.webm'
// a.click()
// this.recording = false
// YJ.Global.ScreenRecord.screenRecord = null
})
// 必须手动启动
this.mediaRecorder.start()
})
.catch((e) => {
console.info('取消录屏')
console.info(e)
YJ.Global.ScreenRecord.screenRecord = null
})
}
}
function startScreenRecord() {
if (YJ.Global.ScreenRecord.screenRecord) {
return '录屏任务进行中'
} else {
YJ.Global.ScreenRecord.screenRecord = new ScreenRecord()
}
}
function stopScreenRecord() {
if (YJ.Global.ScreenRecord && YJ.Global.ScreenRecord.screenRecord && YJ.Global.ScreenRecord.screenRecord) {
YJ.Global.ScreenRecord.screenRecord.mediaRecorder.stop()
YJ.Global.ScreenRecord.screenRecord = null
}
}
export { startScreenRecord, stopScreenRecord }

View File

@ -0,0 +1,707 @@
import Tools from '../../Tools'
import Dialog from '../../Obj/Element/Dialog';
import { legp } from '../../Obj/Element/datalist';
import MapPrint from '../MapPrint';
import { off as offSplitScreen } from "../SplitScreen";
import { off as offMultiViewportMode } from "../MultiViewportMode";
// 生成快照
const convertToImage = (container, options = {}) => {
// 设置放大倍数
const scale = window.devicePixelRatio;
// 传入节点原始宽高
const width = container.offsetWidth;
const height = container.offsetHeight;
// html2canvas配置项
const ops = {
scale,//比例,越大分辨率越高,图片越小
width,
height,
async: false,
x: 0,
y: 0,
backgroundColor: 'rgb(20,47,65)',
imageTimeout: 0,
useCORS: true,//允许跨域
allowTaint: false, //允许跨域数据污染'被污染'的canvas
tainttest: true,
foreignObjectRendering: true, //在浏览器支持的情况下使用ForeignObject模式渲染图片
...options
};
return html2canvas(container, ops).then(canvas => {
// 返回图片的二进制数据
return canvas.toDataURL("image/png");
});
}
async function ScreenShot(sdk, cd = () => { }) {
// const imgBlobData = await convertToImage(sdk.viewer.canvas);
const imgBlobData = sdk.viewer.canvas.toDataURL()
cd && cd(imgBlobData)
// try {
// const imgBlobData = await convertToImage(sdk.viewer.canvas);
// let arr = imgBlobData.split(','), mime = arr[0].match(/:(.*?);/)[1],
// bstr = atob(arr[1]), i = bstr.length, u8arr = new Uint8Array(i);
// while (i--) {
// u8arr[i] = bstr.charCodeAt(i);
// }
// let blob = new Blob([u8arr], { type: mime });
// const opts = {
// suggestedName: '截图.png',
// types: [
// {
// description: '文件类型',
// accept: {
// 'image/png': ['.png'],
// 'image/jpg': ['.jpg']
// }
// }
// ],
// excludeAcceptAllOption: true
// };
// const handle = await window.showSaveFilePicker(opts); // 打开保存文件对话框
// const writable = await handle.createWritable(); // 创建可写入的文件对象
// // 写入视频内容
// writable.write(blob);
// await writable.close();
// YJ.Global.ScreenRecord.screenRecord = null
// } catch (error) {
// console.info('文件保存失败:', error);
// }
}
let _DialogObject
async function ScreenShotHD(sdk, options = {}, cd = () => { }) {
if (!sdk) {
return
}
offSplitScreen(sdk)
offMultiViewportMode(sdk)
if (_DialogObject) {
_DialogObject.close()
_DialogObject = null
}
let enableTranslate = sdk.viewer.scene.screenSpaceCameraController.enableTranslate
let enableTilt = sdk.viewer.scene.screenSpaceCameraController.enableTilt
let enableLook = sdk.viewer.scene.screenSpaceCameraController.enableLook
let scale = 1
let level
let progressInputElm
let progressBarElm
let rangeNodeActive
let rangeNodeActiveText
let startScreenShotObject
let tools = new Tools();
_DialogObject = await new Dialog(sdk, {}, {
title: '高清出图', left: '180px', top: '100px',
confirmCallBack: (options) => {
if (startScreenShotObject) {
startScreenShotObject.desist()
startScreenShotObject = null
}
progressInputElm && (progressInputElm.style.width = '0%')
rangeNodeActive && (rangeNodeActive.style.left = '0%')
progressBarElm && (progressBarElm.style.width = '0%')
rangeNodeActiveText && (rangeNodeActiveText.innerHTML = '0%')
startScreenShotObject = new startScreenShot()
},
closeCallBack: () => {
sdk.viewer.scene.screenSpaceCameraController.enableTranslate = enableTranslate;
sdk.viewer.scene.screenSpaceCameraController.enableTilt = enableTilt;
sdk.viewer.scene.screenSpaceCameraController.enableLook = enableLook;
sdk.viewer._element.getElementsByClassName('compass')[0].style.pointerEvents = 'auto'
if (startScreenShotObject) {
startScreenShotObject.desist()
startScreenShotObject = null
}
_DialogObject = undefined
}
})
_DialogObject._element.body.className = _DialogObject._element.body.className + ' screenShotHD'
let contentElm = document.createElement('div');
contentElm.innerHTML = `
<span class="custom-divider"></span>
<div class="div-item">
<div class="row text" style="align-items: flex-start;">
<div class="col">
<span>当前窗口长宽:<span class="input-width">${sdk.viewer.canvas.width}</span>*<span class="input-height">${sdk.viewer.canvas.height}</span>像素</span>
</div>
</div>
<div class="row scale-box" style="align-items: flex-start;">
<div class="col">
<span class="label">图片大小</span>
<div class="input input-select scale"></div>
<span>倍窗口</span>
</div>
</div>
<div class="row text" style="align-items: flex-start;">
<div class="col">
<span>输出图片长宽:<span class="output-width">${sdk.viewer.canvas.width * scale}</span>*<span class="output-height">${sdk.viewer.canvas.height * scale}</span>像素</span>
</div>
</div>
<div class="row" style="align-items: flex-start; margin-bottom: 20px;">
<div class="col">
<span class="label">输出进度</span>
<div class="range-box">
<div class="range-bg">
<div class="range-process-box">
<div class="range-process"></div>
</div>
</div>
<div class="range-node-box">
<span class="range-node-text">0%</span>
<span class="range-node-text">100%</span>
<div class="range-node-active"><span class="range-node-active-text">0%</span></div>
</div>
<input class="progress-input" type="range" max="100" min="0" step="0.01">
</div>
</div>
</div>
</div>
<span class="custom-divider"></span>
`
_DialogObject.contentAppChild(contentElm)
sdk.viewer.scene.screenSpaceCameraController.enableTranslate = false;
sdk.viewer.scene.screenSpaceCameraController.enableTilt = false;
sdk.viewer.scene.screenSpaceCameraController.enableLook = false;
sdk.viewer._element.getElementsByClassName('compass')[0].style.pointerEvents = 'none'
let centerResult = sdk.viewer.camera.pickEllipsoid(
new Cesium.Cartesian2(
sdk.viewer.canvas.clientWidth / 2,
sdk.viewer.canvas.clientHeight / 2,
),
)
if (!centerResult) {
centerResult = sdk.viewer.camera.pickEllipsoid(
new Cesium.Cartesian2(
sdk.viewer.canvas.clientWidth / 2,
sdk.viewer.canvas.clientHeight / (2 - ((90 + sdk.viewer.camera.pitch / (Cesium.Math.PI / 180)) / 110)),
),
)
if (!centerResult) {
centerResult = sdk.viewer.camera.position
}
}
let height = tools.cartesian3Towgs84(sdk.viewer.camera.position, sdk.viewer).alt
let centerResult84 = tools.cartesian3Towgs84(centerResult, sdk.viewer)
sdk.viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(centerResult84.lng, centerResult84.lat, height),
orientation: { heading: 0, pitch: Cesium.Math.toRadians(-90), roll: 0 },
duration: 1,
})
let scaleData = []
for (let i = 1; i <= 10; i++) {
scaleData.push({
name: i,
value: i
})
}
progressInputElm = document.getElementsByClassName('progress-input')[0]
progressBarElm = document.getElementsByClassName('range-process')[0]
rangeNodeActive = contentElm.getElementsByClassName('range-node-active')[0]
rangeNodeActiveText = contentElm.getElementsByClassName('range-node-active-text')[0]
let scaleDataLegpObject = legp(_DialogObject._element.content.getElementsByClassName('scale-box')[0], ".scale")
if (scaleDataLegpObject) {
scaleDataLegpObject.legp_search(scaleData)
let scaleDataLegpElm = _DialogObject._element.content.getElementsByClassName('scale')[0].getElementsByTagName('input')[0]
scale = scaleData[0].value
scaleDataLegpObject.legp_searchActive(scaleData[0].value)
scaleDataLegpElm.value = scaleData[0].value
scaleDataLegpElm.addEventListener('input', () => {
for (let i = 0; i < scaleData.length; i++) {
if (scaleData[i].value == scaleDataLegpElm.value) {
scale = scaleData[i].value
_DialogObject._element.content.getElementsByClassName('output-width')[0].innerHTML = sdk.viewer.canvas.width * scale
_DialogObject._element.content.getElementsByClassName('output-height')[0].innerHTML = sdk.viewer.canvas.height * scale
break
}
}
})
}
class startScreenShot {
constructor() {
this.state = false
this.start()
}
start() {
if (sdk.viewer.scene.imageryLayers._layers.length <= 1) {
this.error = '未加载底图!'
window.ELEMENT && window.ELEMENT.Message({
message: this.error,
type: 'warning',
duration: 1500
});
console.warn(this.error)
return
}
let haveBaseMap = false
for (let i = 0; i < sdk.viewer.scene.imageryLayers._layers.length; i++) {
let layer = sdk.viewer.scene.imageryLayers._layers[i];
if (layer && layer.show && (!layer.notes || layer.notes !== 'default-base-map')) {
haveBaseMap = true
}
}
if (!haveBaseMap) {
this.error = '未加载底图!'
window.ELEMENT && window.ELEMENT.Message({
message: this.error,
type: 'warning',
duration: 1500
});
console.warn(this.error)
return
}
let scaleZoom = 0;
this.state = true;
let _this = this
computeLayers(1);
function computeLayers(s) {
let num = s * 2;
if (num <= scale) {
scaleZoom++;
computeLayers(num);
}
}
scaleZoom = scaleZoom + 1;
let centerResult = sdk.viewer.camera.pickEllipsoid(
new Cesium.Cartesian2(
sdk.viewer.canvas.width / 2,
sdk.viewer.canvas.height / (2 - ((90 + sdk.viewer.camera.pitch / (Cesium.Math.PI / 180)) / 110))
)
);
if (!centerResult) {
centerResult = sdk.viewer.camera.position;
}
function altitudeToZoom(altitude) {
let A = 40487.57;
let B = 0.00007096758;
let C = 91610.74;
let D = -40467.74;
return Math.round(D + (A - D) / (1 + Math.pow(altitude / C, B)));
}
let height = tools.cartesian3Towgs84(sdk.viewer.camera.position, sdk.viewer).alt;
let zoom = altitudeToZoom(height) + 1;
let rectangle = sdk.viewer.camera.computeViewRectangle();
// if (height > 9000000) {
// height = 9000000
// }
// let curRectangle = new Cesium.Rectangle(Cesium.Math.toRadians(centerResult84.lng - (height / stepX)), Cesium.Math.toRadians(centerResult84.lat - (height / stepY)), Cesium.Math.toRadians(centerResult84.lng + (height / stepX)), Cesium.Math.toRadians(centerResult84.lat + (height / stepY)))
// for (let i = 1; i < sdk.viewer.scene.imageryLayers._layers.length; i++) {
// let layer = sdk.viewer.scene.imageryLayers._layers[i]
// createCanvas(layer)
// }
let total;
let totalCount = 0;
let progress = {};
let index = 0;
let layerLength = 0
let countIndex = 0
for (let i = 0; i < sdk.viewer.scene.imageryLayers._layers.length; i++) {
let layer = sdk.viewer.scene.imageryLayers._layers[i];
if (layer && layer.show && layer.imageryProvider && layer.imageryProvider.url && Cesium.Rectangle.intersection(rectangle, layer.imageryProvider.rectangle) && (!layer.notes || layer.notes !== 'default-base-map')) {
layerLength++
}
}
let itemTotalProgress = 100 / layerLength
let flag = false
createCanvas(index);
function createCanvas(i, totalCanvas) {
let layer = sdk.viewer.scene.imageryLayers._layers[i];
if (!layer) {
if (!flag) {
_this.error = '当前范围内未找到底图数据!'
window.ELEMENT && window.ELEMENT.Message({
message: _this.error,
type: 'warning',
duration: 1500
});
console.warn(_this.error)
}
return
}
if (!layer.show || !layer.imageryProvider || !layer.imageryProvider.url || !Cesium.Rectangle.intersection(rectangle, layer.imageryProvider.rectangle) || (layer.notes && layer.notes === 'default-base-map')) {
let m = i += 1;
createCanvas(m, totalCanvas);
return;
}
flag = true
countIndex++
progress[i] = {
value: 0
}
let itemTotalCount = 0;
let targetLevel
let imageryProvider = layer.imageryProvider;
if (level || level === 0) {
targetLevel = level
}
else {
targetLevel = (zoom + scaleZoom - 1)
if (targetLevel > imageryProvider.maximumLevel) {
targetLevel = imageryProvider.maximumLevel
}
if (targetLevel < imageryProvider.minimumLevel) {
targetLevel = imageryProvider.minimumLevel
}
}
function readyPromise() {
let MinTile = imageryProvider.tilingScheme.positionToTileXY(
Cesium.Rectangle.northwest(rectangle),
targetLevel
);
let MaxTile = imageryProvider.tilingScheme.positionToTileXY(
Cesium.Rectangle.southeast(rectangle),
targetLevel
);
if (!MinTile || !MaxTile) {
let error = '超出地球范围!'
window.ELEMENT && window.ELEMENT.Message({
message: error,
type: 'warning',
duration: 1500
});
console.warn(error)
return
}
let OfXTilesAtLevel = imageryProvider.tilingScheme.getNumberOfXTilesAtLevel(targetLevel)
let OfYTilesAtLevel = imageryProvider.tilingScheme.getNumberOfYTilesAtLevel(targetLevel)
let MinTileX = MinTile.x;
let MinTileY = MinTile.y;
let MaxTileX = MaxTile.x;
let MaxTileY = MaxTile.y;
// if (MinTileX > MaxTileX) {
// MinTileX = MinTileX - OfXTilesAtLevel
// }
let imgWidth = 256;
let imgHeight = 256;
let itemTotal = (MaxTileX - MinTileX + 1) * (MaxTileY - MinTileY + 1);
// var canvas = new fabric.Canvas();
let canvas = document.createElement('canvas');
canvas.width = (MaxTileX - MinTileX + 1) * imgWidth;
canvas.height = (MaxTileY - MinTileY + 1) * imgHeight;
let ctx = canvas.getContext('2d');
let maxRectangle = imageryProvider.tilingScheme.tileXYToRectangle(MaxTileX, MaxTileY, targetLevel);
let minRectangle = imageryProvider.tilingScheme.tileXYToRectangle(MinTileX, MinTileY, targetLevel);
let canvasNativeRectangle = new Cesium.Rectangle(minRectangle.west, maxRectangle.south, maxRectangle.east, minRectangle.north);
// sdk.viewer.entities.add({
// rectangle: {
// coordinates: canvasNativeRectangle,
// material: Cesium.Color.YELLOW.withAlpha(0.2),
// },
// });
// sdk.viewer.entities.add({
// rectangle: {
// coordinates: rectangle,
// material: Cesium.Color.BLACK.withAlpha(0.2),
// },
// });
let nativeRectangle = rectangle;
let x1 = nativeRectangle.west - canvasNativeRectangle.west;
let x2 = canvasNativeRectangle.east - nativeRectangle.east;
let y1 = canvasNativeRectangle.north - nativeRectangle.north;
let y2 = nativeRectangle.south - canvasNativeRectangle.south;
let ratioX1 = x1 / (canvasNativeRectangle.east - canvasNativeRectangle.west);
if (ratioX1 === Infinity) {
ratioX1 = 0;
}
let ratioX2 = x2 / (canvasNativeRectangle.east - canvasNativeRectangle.west);
if (ratioX2 === Infinity) {
ratioX2 = 0;
}
let ratioY1 = y1 / (canvasNativeRectangle.north - canvasNativeRectangle.south);
if (ratioY1 === Infinity) {
ratioY1 = 0;
}
let ratioY2 = y2 / (canvasNativeRectangle.north - canvasNativeRectangle.south);
if (ratioY2 === Infinity) {
ratioY2 = 0;
}
let differenceX1 = canvas.width * ratioX1;
let differenceY1 = canvas.height * ratioY1;
let differenceX2 = canvas.width * ratioX2;
let differenceY2 = canvas.height * ratioY2;
canvas.width = canvas.width - differenceX1 - differenceX2;
canvas.height = canvas.height - differenceY1 - differenceY2;
if (canvas.width == 0) {
canvas.width = 1
}
if (canvas.height == 0) {
canvas.height = 1
}
let y = MaxTileY;
let x = MaxTileX;
let tileArray = []
for (let y = MaxTileY; y >= MinTileY; y--) {
for (let x = MaxTileX; x >= MinTileX; x--) {
tileArray.push({ x, y })
}
}
let speed = 30
let obj = {
count: 0
};
let count = 0;
let times = -1
let obj2 = {
count: 0
}
let count2 = 0
Object.defineProperty(obj2, 'count', {
get: function () {
return count2;
},
set: function (newValue) {
count2 = newValue;
if (count2 >= speed) {
traversal10()
}
}
});
Object.defineProperty(obj, 'count', {
get: function () {
return count;
},
set: function (newValue) {
count = newValue;
progress[i].value = itemTotalCount / itemTotal * itemTotalProgress;
let totalProgress = 0
for (const key in progress) {
totalProgress = totalProgress + progress[key].value
}
progressBarElm.style.width = totalProgress * 0.99 + '%';
rangeNodeActive.style.left = totalProgress * 0.99 + '%';
rangeNodeActiveText.innerHTML = Math.floor(totalProgress * 0.99 * 100) / 100 + '%';
if (count === (MaxTileX - MinTileX + 1) * (MaxTileY - MinTileY + 1)) {
let ctx = canvas.getContext('2d');
let cloneCanvas = canvas.cloneNode(true);
let cloneCtx = cloneCanvas.getContext('2d');
let imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
cloneCtx.putImageData(imageData, 0, 0);
canvas.width = sdk.viewer.canvas.width * scale;
canvas.height = sdk.viewer.canvas.height * scale;
ctx.drawImage(cloneCanvas, 0, 0, canvas.width, canvas.height);
if (totalCanvas) {
let ctx = totalCanvas.getContext('2d');
ctx.drawImage(canvas, 0, 0);
if (countIndex != layerLength) {
let m = i += 1;
createCanvas(m, totalCanvas);
return;
}
else {
let imgBlobData = totalCanvas.toDataURL('image/jpeg', 0.95);
const tempCanvas = document.createElement('canvas');
const tempCtx = tempCanvas.getContext('2d');
tempCanvas.width = totalCanvas.width / scale
tempCanvas.height = totalCanvas.height / scale
tempCtx.drawImage(totalCanvas, 0, 0, tempCanvas.width, tempCanvas.height);
MapPrint(sdk, tempCanvas.toDataURL('image/jpeg', 0.95), rectangle, imgBlobData)
progressBarElm.style.width = '100%';
rangeNodeActive.style.left = '100%';
rangeNodeActiveText.innerHTML = '100%';
_this.state = false
}
}
else {
if (countIndex != layerLength) {
let m = i += 1;
createCanvas(m, canvas);
return;
}
else {
let imgBlobData = canvas.toDataURL('image/jpeg', 0.95);
const tempCanvas = document.createElement('canvas');
const tempCtx = tempCanvas.getContext('2d');
tempCanvas.width = canvas.width / scale;
tempCanvas.height = canvas.height / scale;
tempCtx.drawImage(canvas, 0, 0, tempCanvas.width, tempCanvas.height);
// canvas.width = canvas.width / scale
// canvas.height = canvas.height / scale
MapPrint(sdk, tempCanvas.toDataURL('image/jpeg', 0.95), rectangle, imgBlobData)
progressBarElm.style.width = '100%';
rangeNodeActive.style.left = '100%';
rangeNodeActiveText.innerHTML = '100%';
_this.state = false
}
}
}
}
});
if (imageryProvider._readyError) {
obj.count = (MaxTileX - MinTileX + 1) * (MaxTileY - MinTileY + 1)
}
else {
traversal10()
}
function traversal10() {
obj2.count = 0
count2 = 0
times++
for (let i = times * speed; i < (times + 1) * speed; i++) {
if (i >= tileArray.length) {
return
}
traversal(i)
}
}
function traversal(i) {
if (!_this.state) {
return
}
try {
let x = tileArray[i].x
if (x < 0) {
x = x + OfXTilesAtLevel
}
const img = new Image();
img.setAttribute('crossOrigin', 'anonymous');
img.onload = async function () {
ctx.drawImage(img, ((tileArray[i].x - MinTileX) * imgWidth) - parseFloat(differenceX1.toFixed(0)), ((tileArray[i].y - MinTileY) * imgHeight) - parseFloat(differenceY1.toFixed(0)), imgWidth, imgHeight);
itemTotalCount++;
obj.count++;
obj2.count++;
};
img.onerror = function () {
itemTotalCount++;
obj.count++;
obj2.count++;
};
let url;
if (imageryProvider.url.indexOf('{x}') !== -1 && imageryProvider.url.indexOf('{y}') !== -1 && imageryProvider.url.indexOf('{z}') !== -1) {
url = imageryProvider.url.replace(/\{x\}/g, x).replace(/\{y\}/g, tileArray[i].y).replace(/\{z\}/g, targetLevel);
}
else if (imageryProvider.url.indexOf('{TileMatrix}') !== -1 && imageryProvider.url.indexOf('{TileRow}') !== -1 && imageryProvider.url.indexOf('{TileCol}') !== -1) {
url = imageryProvider.url.replace(/\{TileCol\}/g, x).replace(/\{TileRow\}/g, tileArray[i].y).replace(/\{TileMatrix\}/g, targetLevel);
}
else if (imageryProvider._layer && imageryProvider._style && imageryProvider._tileMatrixSetID && imageryProvider._format) {
url = imageryProvider.url + `&tilematrix=${targetLevel}&layer=${imageryProvider._layer}&style=${imageryProvider._style}&tilerow=${y}&tilecol=${x}&tilematrixset=${imageryProvider._tileMatrixSetID}&format=${imageryProvider._format}`;
}
else {
url = imageryProvider.url + `tile/${targetLevel}/${tileArray[i].y}/${x}`;
}
img.src = url;
} catch (error) {
itemTotalCount++;
obj.count++;
obj2.count++;
}
}
function traversal2() {
if (!_this.state) {
return
}
try {
const img = new Image();
img.setAttribute('crossOrigin', 'anonymous');
img.onload = async function () {
ctx.drawImage(img, ((x - MinTileX) * imgWidth) - parseFloat(differenceX1.toFixed(0)), ((y - MinTileY) * imgHeight) - parseFloat(differenceY1.toFixed(0)), imgWidth, imgHeight);
itemTotalCount++;
obj.count++;
if (x > MinTileX) {
x--
}
else {
if (y > MinTileY) {
y--
x = MaxTileX
}
else {
return
}
}
traversal()
};
let url;
if (imageryProvider.url.indexOf('{x}') !== -1 && imageryProvider.url.indexOf('{y}') !== -1 && imageryProvider.url.indexOf('{z}') !== -1) {
url = imageryProvider.url.replace(/\{x\}/g, x).replace(/\{y\}/g, y).replace(/\{z\}/g, targetLevel);
}
else if (imageryProvider.url.indexOf('{TileMatrix}') !== -1 && imageryProvider.url.indexOf('{TileRow}') !== -1 && imageryProvider.url.indexOf('{TileCol}') !== -1) {
url = imageryProvider.url.replace(/\{TileCol\}/g, x).replace(/\{TileRow\}/g, y).replace(/\{TileMatrix\}/g, targetLevel);
}
else if (imageryProvider._layer && imageryProvider._style && imageryProvider._tileMatrixSetID && imageryProvider._format) {
url = imageryProvider.url + `&tilematrix=${targetLevel}&layer=${imageryProvider._layer}&style=${imageryProvider._style}&tilerow=${y}&tilecol=${x}&tilematrixset=${imageryProvider._tileMatrixSetID}&format=${imageryProvider._format}`;
}
else {
url = imageryProvider.url + `tile/${targetLevel}/${y}/${x}`;
}
img.src = url;
} catch (error) {
itemTotalCount++;
obj.count++;
if (x >= MinTileX) {
x--
}
else {
if (y >= MinTileY) {
y--
x = MaxTileX
}
else {
return
}
}
traversal()
}
}
}
if (imageryProvider._readyError) {
progress[i] = {
value: itemTotalProgress
}
readyPromise()
return
}
imageryProvider.readyPromise.then(() => {
readyPromise()
}).catch((e) => {
imageryProvider._readyError = true
progress[i] = {
value: itemTotalProgress
}
readyPromise()
});
}
}
desist() {
this.state = false
}
}
}
export { ScreenShot, ScreenShotHD }

View File

@ -0,0 +1,655 @@
import { get2DView } from '../MultiViewportMode'
import { getSdk } from '../SplitScreen'
import { flyTo } from '../global'
import Tools from '../../Tools'
let tools
let state = false
let scale = '1:100万'
function SheetIndexStatusSwitch(sdk, s = false) {
if(!sdk) {
return
}
if (!tools) {
tools = new Tools()
}
state = s ? true : false
if (state) {
changeScale(sdk, scale)
} else {
close(sdk)
}
let sdk2D = get2DView()
if (sdk2D) {
if (state) {
changeScale(sdk, scale)
} else {
close(sdk2D)
}
}
let sdkD = getSdk().sdkD
if(sdkD && sdk !== sdkD) {
SheetIndexStatusSwitch(sdkD, s)
}
// return new Promise(async (resolve, reject) => {
// setTimeout(() => {
// resolve()
// }, 1000);
// })
}
function changeScale(sdk, v) {
scale = v
if (state) {
open(sdk)
}
let sdk2D = get2DView()
if (sdk2D) {
if (state) {
open(sdk2D)
}
}
return new Promise(async (resolve, reject) => {
setTimeout(() => {
resolve()
}, 1000);
})
}
function getStatus() {
return state
}
function open(sdk) {
close(sdk)
let cartographic = sdk.viewer.camera.positionCartographic
let options = {
position: {
lng: Cesium.Math.toDegrees(cartographic.longitude),
lat: Cesium.Math.toDegrees(cartographic.latitude),
alt: cartographic.height,
},
}
let viewer = sdk.viewer;
switch (scale) {
case '1:100万':
options.position.alt = 16000000
break
case '1:50万':
options.position.alt = 5000000
break
case '1:25万':
options.position.alt = 2300000
break
case '1:10万':
options.position.alt = 680000
break
case '1:5万':
options.position.alt = 385000
break
case '1:2.5万':
options.position.alt = 180000
break
case '1:1万':
options.position.alt = 90000
break
case '1:5000':
options.position.alt = 46000
break
}
let gridPrimitives
let labelCollection
for (let i = 0; i < viewer.scene.primitives._primitives.length; i++) {
if (viewer.scene.primitives._primitives[i].name === 'SheetIndexGridPrimitives') {
gridPrimitives = viewer.scene.primitives._primitives[i];
for (let j = 0; j < gridPrimitives._primitives.length; j++) {
if (gridPrimitives._primitives[j].name === 'SheetIndexLabelCollection') {
labelCollection = gridPrimitives._primitives[j];
break;
}
}
break;
}
}
if (!gridPrimitives) {
gridPrimitives = new Cesium.PrimitiveCollection();
gridPrimitives.name = 'SheetIndexGridPrimitives';
viewer.scene.primitives.add(gridPrimitives);
}
if (!labelCollection) {
labelCollection = new Cesium.LabelCollection();
labelCollection.name = 'SheetIndexLabelCollection';
}
let stationaryFrames = 0;
let maxRectangle = null;
gridPrimitives.postRenderEvent = () => {
let height = sdk.viewer.camera.positionCartographic.height
switch (scale) {
case '1:100万':
options.position.alt = 16000000
break
case '1:50万':
options.position.alt = 5000000
break
case '1:25万':
options.position.alt = 2300000
break
case '1:10万':
options.position.alt = 680000
break
case '1:5万':
options.position.alt = 385000
break
case '1:2.5万':
options.position.alt = 180000
break
case '1:1万':
options.position.alt = 90000
break
case '1:5000':
options.position.alt = 46000
break
}
if (height > options.position.alt * 5) {
maxRectangle = null;
gridPrimitives.removeAll();
return
}
let isChanged = false
let rectangle = getViewExtend();
let minLng = Cesium.Math.toDegrees(rectangle.west)
let minLat = Cesium.Math.toDegrees(rectangle.south)
let maxLng = Cesium.Math.toDegrees(rectangle.east)
let maxLat = Cesium.Math.toDegrees(rectangle.north)
if (minLng > maxLng) {
maxLng += 360
}
rectangle = { minLng, minLat, maxLng, maxLat }
if (maxRectangle) {
if ((maxRectangle.minLng > rectangle.minLng || maxRectangle.minLat > rectangle.minLat || maxRectangle.maxLng < rectangle.maxLng || maxRectangle.maxLat < rectangle.maxLat) && Cesium.Math.toDegrees(sdk.viewer.camera.pitch) < 0) {
isChanged = true
}
}
else {
countMapSheet(scale)
}
if (isChanged) {
stationaryFrames++;
// 确认相机已经静止足够多帧
if (stationaryFrames >= 50) {
countMapSheet(scale)
isChanged = false
}
} else {
stationaryFrames = 0;
}
}
options.complete = () => {
viewer.scene.postRender.addEventListener(gridPrimitives.postRenderEvent);
}
flyTo(sdk, options, 0.5)
/**
* 根据比例尺创建图幅线
* @param {string} scale - 比例尺(可选值:'1:100万', '1:50万', '1:25万', '1:10万', '1:5万', '1:2.5万', '1:1万', '1:5000'
*/
function countMapSheet(scale) {
labelCollection.removeAll();
gridPrimitives.removeAll();
labelCollection = new Cesium.LabelCollection();
labelCollection.name = 'SheetIndexLabelCollection';
gridPrimitives.add(labelCollection);
let rectangle = getViewExtend();
let lngStep // 经度步长
let latStep // 纬度步长
// let limitLng // 显示界限(根据图幅线数量显隐)
// let limitLat
// Math.abs(maxLng-minLng)/lngStep, Math.abs(maxLat-minLat)/latStep
let scaleByDistance
switch (scale) {
case '1:100万':
lngStep = 6;
latStep = 4;
scaleByDistance = new Cesium.NearFarScalar(
20000000,
1,
80000000,
0
)
break
case '1:50万':
lngStep = 3;
latStep = 2;
scaleByDistance = new Cesium.NearFarScalar(
5000000,
1,
30000000,
0
)
break
case '1:25万':
lngStep = 1.5;
latStep = 1;
scaleByDistance = new Cesium.NearFarScalar(
2300000,
1,
20000000,
0
)
break
case '1:10万':
lngStep = 0.5;
latStep = 1 / 3;
scaleByDistance = new Cesium.NearFarScalar(
680000,
1,
5000000,
0
)
break
case '1:5万':
lngStep = 0.25;
latStep = 1 / 6;
scaleByDistance = new Cesium.NearFarScalar(
385000,
1,
2400000,
0
)
break
case '1:2.5万':
lngStep = 0.125;
latStep = 1 / 12;
scaleByDistance = new Cesium.NearFarScalar(
180000,
1,
1200000,
0
)
break
case '1:1万':
lngStep = 0.0625;
latStep = 1 / 24;
scaleByDistance = new Cesium.NearFarScalar(
90000,
1,
700000,
0
)
break
case '1:5000':
lngStep = 0.03125;
latStep = 1 / 48;
scaleByDistance = new Cesium.NearFarScalar(
46000,
1,
300000,
0
)
break
// case '1:1000':
// lngStep = 0.01041667;
// latStep = 0.00694444;
// break
// case '1:2000':
// lngStep = 0.00520833;
// latStep = 0.00347222;
// break
}
let minLng = Math.floor((180 + Cesium.Math.toDegrees(rectangle.west)) / lngStep) * lngStep - 180;
let minLat = Math.floor((88 + Cesium.Math.toDegrees(rectangle.south)) / latStep) * latStep - 88;
let maxLng = Math.ceil((180 + Cesium.Math.toDegrees(rectangle.east)) / lngStep) * lngStep - 180;
let maxLat = Math.ceil((88 + Cesium.Math.toDegrees(rectangle.north)) / latStep) * latStep - 88;
if (minLng > maxLng) {
maxLng += 360
}
maxRectangle = { minLng, minLat, maxLng, maxLat }
if (minLat < -88) {
minLat = -88
}
if (maxLat > 88) {
maxLat = 88
}
if (((maxRectangle.maxLng - maxRectangle.minLng) / lngStep) * ((maxRectangle.maxLat - maxRectangle.minLat) / latStep) > 7000) {
maxRectangle = null
return
}
// 绘制经线
for (let lng = minLng; lng <= maxLng; lng += lngStep) {
const positions = [];
let a = []
for (let lat = minLat; Math.floor(lat * 1000000000) / 1000000000 <= maxLat; lat += (latStep / 2)) {
a.push([lng, lat])
positions.push(Cesium.Cartesian3.fromDegrees(lng, lat, 8848));
}
if (maxLat != 88 && maxLat + (latStep / 2) >= 88) {
positions.push(Cesium.Cartesian3.fromDegrees(lng, 88, 8848));
}
const geometryInstances = new Cesium.GeometryInstance({
geometry: new Cesium.PolylineGeometry({
positions: positions,
width: 1,
vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT,
arcType: Cesium.ArcType.RHUMB,
})
});
gridPrimitives.add(new Cesium.Primitive({
geometryInstances: geometryInstances,
appearance: new Cesium.PolylineMaterialAppearance({
material: Cesium.Material.fromType('Color', {
color: Cesium.Color.fromCssColorString('#fcfc00')
})
})
}));
if (lng < maxLng) {
// 计算图幅中心坐标
for (let lat = minLat; lat < maxLat; lat += latStep) {
let position = { lng: lng + (lngStep / 2), lat: lat + (latStep / 2) };
if (position.lat > maxLat) {
break
}
let sheetNumber = calculateMapSheetNumber(position.lng, position.lat, scale);
labelCollection.add({
position: Cesium.Cartesian3.fromDegrees(position.lng, position.lat, 8848),
text: sheetNumber,
font: '16px Inter, sans-serif',
fillColor: Cesium.Color.fromCssColorString('#fcfc00'),
// backgroundColor: Cesium.Color.fromCssColorString('#FFA145'),
// backgroundPadding: new Cesium.Cartesian2(8, 4),
pixelOffset: new Cesium.Cartesian2(0, 0),
showBackground: false,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
scale: 1.0,
distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 80000000),
scaleByDistance: scaleByDistance
})
// labelCollection.add({
// position: Cesium.Cartesian3.fromDegrees(position.lng, position.lat, 10000),
// text: position.lng + ' , ' + position.lat,
// font: '16px Inter, sans-serif',
// fillColor: Cesium.Color.WHITE,
// backgroundColor: Cesium.Color.fromCssColorString('#165DFF').withAlpha(0.8),
// backgroundPadding: new Cesium.Cartesian2(8, 4),
// pixelOffset: new Cesium.Cartesian2(0, 30),
// showBackground: true,
// verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
// horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
// scale: 1.0,
// distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 20000000),
// scaleByDistance: new Cesium.NearFarScalar(
// 5000000,
// 1,
// 20000000,
// 0
// )
// })
}
}
}
// 绘制纬线
for (let lat = minLat; Math.floor(lat * 1000000000) / 1000000000 <= maxLat; lat += latStep) {
const positions = [];
let a = []
for (let lng = minLng; lng <= maxLng; lng += (lngStep / 2)) {
a.push([lng, lat])
positions.push(Cesium.Cartesian3.fromDegrees(lng, lat, 8848));
}
const geometryInstances = new Cesium.GeometryInstance({
geometry: new Cesium.PolylineGeometry({
positions: positions,
width: 1,
vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT,
arcType: Cesium.ArcType.RHUMB,
})
});
gridPrimitives.add(new Cesium.Primitive({
geometryInstances: geometryInstances,
appearance: new Cesium.PolylineMaterialAppearance({
material: Cesium.Material.fromType('Color', {
color: Cesium.Color.fromCssColorString('#fcfc00')
})
})
}));
}
}
/**
* 根据经纬度和比例尺计算地图图幅编号
* @param {number} longitude - 经度(十进制格式)
* @param {number} latitude - 纬度(十进制格式)
* @param {string} scale - 比例尺(可选值:'1:100万', '1:50万', '1:25万', '1:10万', '1:5万', '1:2.5万', '1:1万', '1:5000'
* @returns {string} 对应的图幅编号
*/
function calculateMapSheetNumber(lng, lat, scale) {
let lngStep // 经度步长
let latStep // 纬度步长
switch (scale) {
case '1:100万':
lngStep = 6;
latStep = 4;
break
case '1:50万':
lngStep = 3;
latStep = 2;
break
case '1:25万':
lngStep = 1.5;
latStep = 1;
break
case '1:10万':
lngStep = 0.5;
latStep = 1 / 3;
break
case '1:5万':
lngStep = 0.25;
latStep = 1 / 6;
break
case '1:2.5万':
lngStep = 0.125;
latStep = 1 / 12;
break
case '1:1万':
lngStep = 0.0625;
latStep = 1 / 24;
break
case '1:5000':
lngStep = 0.03125;
latStep = 1 / 48;
break
// case '1:1000':
// lngStep = 0.01041667;
// latStep = 0.00694444;
// break
// case '1:2000':
// lngStep = 0.00520833;
// latStep = 0.00347222;
// break
}
// 确保纬度在 -88 到 88 度之间(因为 88° 以上采用特殊分幅)
lat = Math.max(-88, Math.min(88, lat));
lat = Math.abs(lat); // 取绝对值
let B6 = 'ABCDEFGHIJKLMNOPQRSTUV'
let B2 = lng
let B3 = lat
// 计算 1:100 万地形图的列号
const col100W = Math.floor(B2 / 6 + 31);
// 1:100 万地形图的行号对应的字母A-V
const rowChar = B6.charAt(Math.floor(B3 / 4 + 1) - 1);
// 比例尺代码映射
const scaleCodeMap = {
'1:100万': '', // 1:100万不需要额外代码
'1:50万': 'B',
'1:25万': 'C',
'1:10万': 'D',
'1:5万': 'E',
'1:2.5万': 'F',
'1:1万': 'G',
'1:5000': 'H'
};
// 获取比例尺代码
const scaleCode = scaleCodeMap[scale];
if (!scaleCode && scale !== '1:100万') {
throw new Error('不支持的比例尺,请使用: 1:100万, 1:50万, 1:25万, 1:10万, 1:5万, 1:2.5万, 1:1万, 1:5000');
}
// 计算在 1:100 万图幅内的行列号(根据不同比例尺)
let rowIn100W, colIn100W;
rowIn100W = rowChar + col100W;
const num1 = Math.floor((Math.ceil(B3 / 4) * 4 - B3) / latStep) + 1;
const rowNum = ("000" + num1).slice(-3);
const remainder = B2 - Math.floor(B2 / 6) * 6;
const num2 = Math.floor(remainder / lngStep) + 1;
const colNum = ("000" + num2).slice(-3);
switch (scale) {
case '1:100万':
// 1:100万直接使用行号和列号
return rowIn100W;
case '1:50万':
break;
case '1:25万':
break;
case '1:10万':
break;
case '1:5万':
break;
case '1:2.5万':
break;
case '1:1万':
break;
case '1:5000':
break;
default:
throw new Error('不支持的比例尺');
}
// 生成最终编号
return rowIn100W + scaleCode + rowNum + colNum;
}
// 获取当前视角矩形范围(二维模式)
function getViewExtend() {
let params = {};
let extend = viewer.camera.computeViewRectangle();
if (viewer.scene.mode == 2) {
//2D下会可能拾取不到坐标extend返回undefined,所以做以下转换
let canvas = viewer.scene.canvas;
let upperLeft = new Cesium.Cartesian2(0, 0);//canvas左上角坐标转2d坐标
let lowerRight = new Cesium.Cartesian2(
canvas.clientWidth,
canvas.clientHeight
);//canvas右下角坐标转2d坐标
let ellipsoid = viewer.scene.globe.ellipsoid;
let upperLeft3 = viewer.camera.pickEllipsoid(
upperLeft,
ellipsoid
);//2D转3D世界坐标
let lowerRight3 = viewer.camera.pickEllipsoid(
lowerRight,
ellipsoid
);//2D转3D世界坐标
if (!upperLeft3) {
let cartesian2 = Cesium.SceneTransforms.wgs84ToWindowCoordinates(viewer.scene, { x: 0, y: 0, z: 6356755 });
upperLeft.y = cartesian2.y + 5
upperLeft3 = viewer.camera.pickEllipsoid(
upperLeft,
ellipsoid
);
}
if (!lowerRight3) {
let cartesian2 = Cesium.SceneTransforms.wgs84ToWindowCoordinates(viewer.scene, { x: 0, y: 0, z: -6356755 });
lowerRight.y = cartesian2.y - 5
lowerRight3 = viewer.camera.pickEllipsoid(
lowerRight,
ellipsoid
);
// console.log('lowerRight3', lowerRight, lowerRight3)
}
let upperLeftCartographic = viewer.scene.globe.ellipsoid.cartesianToCartographic(
upperLeft3
);//3D世界坐标转弧度
let lowerRightCartographic = viewer.scene.globe.ellipsoid.cartesianToCartographic(
lowerRight3
);//3D世界坐标转弧度
if ((lowerRight.y - upperLeft.y) / (lowerRight.x - upperLeft.x) <= 0.49998752339363695) {
extend = new Cesium.Rectangle(Cesium.Math.toRadians(-180), Cesium.Math.toRadians(-90), Cesium.Math.toRadians(180), Cesium.Math.toRadians(90))
}
else {
extend = new Cesium.Rectangle(upperLeftCartographic.longitude, lowerRightCartographic.latitude, lowerRightCartographic.longitude, upperLeftCartographic.latitude);
}
// console.log("经度:" + minx + "----" + maxx);
// console.log("纬度:" + miny + "----" + maxy);
return extend;
} else {
//3D获取方式
return extend;
}
}
}
function close(sdk) {
let viewer = sdk.viewer;
let gridPrimitives
let labelCollection
for (let i = 0; i < viewer.scene.primitives._primitives.length; i++) {
if (viewer.scene.primitives._primitives[i].name === 'SheetIndexGridPrimitives') {
gridPrimitives = viewer.scene.primitives._primitives[i];
for (let j = 0; j < gridPrimitives._primitives.length; j++) {
if (gridPrimitives._primitives[j].name === 'SheetIndexLabelCollection') {
labelCollection = gridPrimitives._primitives[j];
break;
}
}
break;
}
}
labelCollection && (labelCollection.removeAll());
gridPrimitives && (gridPrimitives.removeAll());
gridPrimitives && (viewer.scene.postRender.removeEventListener(gridPrimitives.postRenderEvent));
}
export { SheetIndexStatusSwitch, changeScale, getStatus }

30
src/Global/Skin/index.js Normal file
View File

@ -0,0 +1,30 @@
let theme = {
"yingguangse": new Map(),
"gonganlan": new Map(),
"hong": new Map(),
}
// 主色
theme.yingguangse.set("--color-sdk-base", "#00ffff")
// 辅色
theme.yingguangse.set("--color-sdk-auxiliary", "#004242")
theme.yingguangse.set("--color-sdk-auxiliary-public", "#ffffff")
// 预警色
theme.yingguangse.set("--color-sdk-warning-0", "#1BF8C3")
theme.yingguangse.set("--color-sdk-warning-1", "#F16C55")
theme.yingguangse.set("--color-sdk-warning-2", "#FFA145")
theme.yingguangse.set("--color-sdk-warning-3", "#FFDF53")
// 文本色
theme.yingguangse.set("--color-sdk-text-head", "#FFFFFF")
theme.yingguangse.set("--color-sdk-text-head-1", "#E6F7FF")
theme.yingguangse.set("--color-sdk-text-head-2", "#ADF1FF")
// 渐变色
theme.yingguangse.set("--color-sdk-gradual", "#00ffff 6.25%, #00ffff 100%")
theme.yingguangse.set("--color-sdk-bg-gradual", "#00ffff33 0%, #00ffff00 100%")
export default theme;
function setSkin(name) {
document.documentElement.style.setProperty('--color-sdk-base', 'rgba(0, 55, 55, 1)');
}
export { setSkin }

View File

@ -0,0 +1,578 @@
/**
* @name: click
* @author: Administrator
* @date: 2023-05-28 11:05
* @descriptionclick
* @update: 2023-05-28 11:05
*/
let leftClickHandler = null
let rightClickHandler = null
let MoveHandler = null
let leftClickCallbackMap = new Map()
let rightClickCallbackMap = new Map()
let MoveCallbackMap = new Map()
let selectedFeature;
function cartesian3Towgs84(cartesian, viewer) {
var ellipsoid = viewer.scene.globe.ellipsoid
var cartesian3 = new Cesium.Cartesian3(
cartesian.x,
cartesian.y,
cartesian.z
)
var cartographic = ellipsoid.cartesianToCartographic(cartesian3)
var lat = Cesium.Math.toDegrees(cartographic.latitude)
var lng = Cesium.Math.toDegrees(cartographic.longitude)
var alt = cartographic.height < 0 ? 0 : cartographic.height
return {
lng: lng,
lat: lat,
alt: alt,
}
}
function getcartesian(sdk, movement) {
if (movement.endPosition) {
movement.endPosition.y -= 2
}
let position = movement.position || movement.endPosition
// 获取世界坐标系地表坐标,考虑地形,不包括模型,倾斜摄影模型表面;
let cartesian = sdk.viewer.scene.pickPosition(position)
if (!cartesian) {
const ray = sdk.viewer.camera.getPickRay(position); //相交的射线
cartesian = sdk.viewer.scene.globe.pick(ray, sdk.viewer.scene);
}
return cartesian
}
function openLeftClick(sdk, cb) {
if (!sdk || !sdk.viewer) {
return
}
let click = true
leftClickHandler = new Cesium.ScreenSpaceEventHandler(sdk.viewer.canvas)
leftClickHandler.setInputAction((movement) => {
let cartesian = sdk.viewer.scene.pickPosition(movement.position)
if (!cartesian) {
const ray = sdk.viewer.camera.getPickRay(movement.position); //相交的射线
cartesian = sdk.viewer.scene.globe.pick(ray, sdk.viewer.scene);
}
if (!cartesian) {
return
}
let pos84 = cartesian3Towgs84(cartesian, sdk.viewer)
cb && cb(pos84)
if (click) {
click = false
setTimeout(() => {
click = true
}, 600);
if (!YJ.Measure.GetMeasureStatus() && cartesian) {
let flag = false
for (let i = leftClickCallbackMap.size - 1; i >= 0; i--) {
let key = Array.from(leftClickCallbackMap.keys())[i]
let obj = leftClickCallbackMap.get(key)
if (obj) {
if (obj.that) {
// 是否为多边形
if (obj.that.type === 'PolygonObject') {
// 是否可点击y
if (obj.that.picking) {
if (obj.that.options.positions && obj.that.options.positions.length >= 3) {
let pt = turf.point([pos84.lng, pos84.lat]);
let polyPos = []
for (let i = 0; i < obj.that.options.positions.length; i++) {
polyPos.push([
obj.that.options.positions[i].lng,
obj.that.options.positions[i].lat
])
}
polyPos.push([
obj.that.options.positions[0].lng,
obj.that.options.positions[0].lat
])
let poly = turf.polygon([polyPos]);
let contain = turf.booleanPointInPolygon(pt, poly);
if (contain) {
obj.callback(
movement,
obj.that.options.id,
cartesian3Towgs84(getcartesian(sdk, movement), sdk.viewer), obj.that)
flag = true
break
}
}
}
}
// 聚集地
else if (obj.that.type === 'AssembleObject') {
if (obj.that.picking) {
if (obj.that.options.positions && obj.that.options.positions.length >= 3) {
let positions = obj.that.computeAssemble(obj.that.options.positions, true)
let pt = turf.point([pos84.lng, pos84.lat]);
let polyPos = []
for (let i = 0; i < positions.length; i += 2) {
polyPos.push([
positions[i],
positions[i + 1]
])
}
let poly = turf.polygon([polyPos]);
let contain = turf.booleanPointInPolygon(pt, poly);
if (contain) {
obj.callback(
movement,
obj.that.options.id,
cartesian3Towgs84(getcartesian(sdk, movement), sdk.viewer), obj.that)
flag = true
break
}
}
}
}
// 单箭头
else if (obj.that.type === 'AttackArrowObject') {
if (obj.that.picking) {
if (obj.that.options.positions && obj.that.options.positions.length >= 3) {
let pt = turf.point([pos84.lng, pos84.lat]);
let positions = obj.that.computeAttackArrow(obj.that.options.positions)
let polyPos = []
for (let m = 0; m < positions.length; m++) {
let pos84 = cartesian3Towgs84(positions[m], sdk.viewer)
polyPos.push([pos84.lng, pos84.lat])
}
let poly = turf.polygon([polyPos]);
let contain = turf.booleanPointInPolygon(pt, poly);
if (contain) {
obj.callback(
movement,
obj.that.options.id,
cartesian3Towgs84(getcartesian(sdk, movement), sdk.viewer), obj.that)
flag = true
break
}
}
}
}
// 双箭头
else if (obj.that.type === 'PincerArrowObject') {
if (obj.that.picking) {
if (obj.that.options.positions && obj.that.options.positions.length >= 5) {
let pt = turf.point([pos84.lng, pos84.lat]);
let positions = obj.that.computePincerArrow(obj.that.options.positions)
let polyPos = []
for (let m = 0; m < positions.length; m++) {
let pos84 = cartesian3Towgs84(positions[m], sdk.viewer)
polyPos.push([pos84.lng, pos84.lat])
}
let pos84_0 = cartesian3Towgs84(positions[0], sdk.viewer)
polyPos.push([pos84_0.lng, pos84_0.lat])
let poly = turf.polygon([polyPos]);
let contain = turf.booleanPointInPolygon(pt, poly);
if (contain) {
obj.callback(
movement,
obj.that.options.id,
cartesian3Towgs84(getcartesian(sdk, movement), sdk.viewer), obj.that)
flag = true
break
}
}
}
}
// 圆
else if (obj.that.type === 'CircleObject') {
if (obj.that.picking) {
let pt = turf.point([pos84.lng, pos84.lat]);
if (obj.that.options.center && obj.that.options.radius) {
let center = [obj.that.options.center.lng, obj.that.options.center.lat];
let radius = obj.that.options.radius / 1000;
let options = { steps: 360, units: 'kilometers' };
let circle = turf.circle(center, radius, options);
let contain = turf.booleanPointInPolygon(pt, circle);
if (contain) {
obj.callback(
movement,
obj.that.options.id,
cartesian3Towgs84(getcartesian(sdk, movement), sdk.viewer), obj.that)
flag = true
break
}
}
}
}
// 扇形
else if (obj.that.type === 'SectorObject') {
if (obj.that.picking) {
let pt = turf.point([pos84.lng, pos84.lat]);
if (obj.that.options.center && obj.that.options.radius && obj.that.options.startAngle && obj.that.options.endAngle) {
let positions = obj.that.calSector(obj.that.options.center, obj.that.options.radius, obj.that.options.startAngle, obj.that.options.endAngle, undefined, true)
let polyPos = []
for (let m = 0; m < positions.length; m++) {
polyPos.push([positions[m].lng, positions[m].lat])
}
let poly = turf.polygon([polyPos]);
let contain = turf.booleanPointInPolygon(pt, poly);
if (contain) {
obj.callback(
movement,
obj.that.options.id,
cartesian3Towgs84(getcartesian(sdk, movement), sdk.viewer), obj.that)
flag = true
break
}
}
}
}
}
}
}
if (!flag) {
const pick = sdk.viewer.scene.pick(movement.position)
if (pick) {
if (pick.id) {
let entityId
// 矢量
if (pick.id.type && pick.id.type === 'vector' && pick.id.parentId) {
let obj = leftClickCallbackMap.get(pick.id.parentId)
if (obj.that.picking && obj.that.geojson) {
for (let i = 0; i < obj.that.geojson.features.length; i++) {
if (obj.that.geojson.features[i].id === pick.id._id) {
obj.callback(
movement,
obj.that.geojson.features[i].id,
cartesian3Towgs84(getcartesian(sdk, movement), sdk.viewer), obj.that)
}
}
}
}
else if (typeof pick.id.id == 'string') {
let array = pick.id.id.split('-')
array.splice(array.length - 1, 1)
entityId = array.join('-')
}
if (pick.id.properties && pick.id.properties.id && leftClickCallbackMap.has(pick.id.properties.id._value)) {
let obj = leftClickCallbackMap.get(pick.id.properties.id._value)
if (obj.that.picking) {
obj.callback(
movement,
pick.id.properties.id._value,
cartesian3Towgs84(getcartesian(sdk, movement), sdk.viewer), obj.that)
}
}
else if (leftClickCallbackMap.has(pick.id.id)) {
let obj = leftClickCallbackMap.get(pick.id.id)
if (obj.that.picking) {
obj.callback(
movement,
pick.id.id,
cartesian3Towgs84(getcartesian(sdk, movement), sdk.viewer), obj.that)
}
}
else if (entityId && leftClickCallbackMap.has(entityId)) {
let obj = leftClickCallbackMap.get(entityId)
if (obj.that.picking) {
obj.callback(
movement,
entityId,
cartesian3Towgs84(getcartesian(sdk, movement), sdk.viewer), obj.that)
}
}
else if (pick.primitive) {
if (typeof pick.id == 'string' && leftClickCallbackMap.has(pick.id)) {
let obj = leftClickCallbackMap.get(pick.id)
obj.callback(
movement,
pick.id,
cartesian3Towgs84(getcartesian(sdk, movement), sdk.viewer), obj.that)
}
}
}
else {
if (pick.primitive && pick.primitive.id) {
if (leftClickCallbackMap.has(pick.primitive.id)) {
let obj = leftClickCallbackMap.get(pick.primitive.id)
if (obj.that.picking) {
if (obj.that.type === 'bim') {
if (YJ.Global.getBimPickStatus(sdk)) {
obj.callback(
movement,
pick.primitive,
cartesian3Towgs84(getcartesian(sdk, movement), sdk.viewer), obj.that)
}
}
else {
obj.callback(
movement,
pick.primitive.id,
cartesian3Towgs84(getcartesian(sdk, movement), sdk.viewer), obj.that)
}
}
}
}
}
if (pick.content && (!pick.primitive || !pick.primitive.id)) {
if (leftClickCallbackMap.has(pick.content.tileset.id)) {
let obj = leftClickCallbackMap.get(pick.content.tileset.id)
if (obj.that.picking) {
if (obj.that.type === 'bim') {
if (YJ.Global.getBimPickStatus(sdk)) {
obj.callback(
movement,
pick.content.tileset,
cartesian3Towgs84(getcartesian(sdk, movement), sdk.viewer), obj.that)
}
}
else {
obj.callback(
movement,
pick.content.tileset.id,
cartesian3Towgs84(getcartesian(sdk, movement), sdk.viewer), obj.that)
}
}
}
}
}
}
}
}
// if (click) {
// click = false
// setTimeout(() => {
// click = true
// }, 300);
// if (!YJ.Measure.GetMeasureStatus()) {
// }
// }
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
// leftClickHandler.setInputAction(function (movement) {
// const feature = sdk.viewer.scene.pick(movement.endPosition);
// // unselectFeature(selectedFeature);
// if (selectedFeature) {
// selectedFeature.color = Cesium.Color.WHITE;
// }
// selectedFeature = feature
// if (feature) {
// feature.color = Cesium.Color.YELLOW;
// }
// }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
// }
}
function closeLeftClick(sdk) {
leftClickHandler.destroy() //关闭事件句柄
leftClickHandler = null
// }
}
function openRightClick(sdk) {
if (!sdk || !sdk.viewer) {
return
}
rightClickHandler = new Cesium.ScreenSpaceEventHandler(sdk.viewer.canvas)
rightClickHandler.setInputAction((movement) => {
if (!YJ.Measure.GetMeasureStatus()) {
const pick = sdk.viewer.scene.pick(movement.position)
if (pick && pick.id) {
let id
if (pick.id.type && pick.id.type === 'vector' && pick.id.parentId) {
let obj = rightClickCallbackMap.get(pick.id.parentId)
if (obj.that.picking && obj.that.geojson) {
for (let i = 0; i < obj.that.geojson.features.length; i++) {
if (obj.that.geojson.features[i].id === pick.id._id) {
obj.callback(
movement,
obj.that.geojson.features[i].id,
cartesian3Towgs84(getcartesian(sdk, movement), sdk.viewer), obj.that)
}
}
}
}
else {
if (typeof pick.id === 'string') {
id = pick.id
}
else {
id = pick.id.id
}
if (rightClickCallbackMap.has(id)) {
let obj = rightClickCallbackMap.get(id)
if (obj.that.picking) {
let cartesian = getcartesian(sdk, movement)
if (!cartesian) {
return
}
obj.callback(
movement,
id,
cartesian3Towgs84(cartesian, sdk.viewer), obj.that)
}
}
}
}
if (pick && pick.content) {
if (rightClickCallbackMap.has(pick.content.tileset.id)) {
let obj = rightClickCallbackMap.get(pick.content.tileset.id)
if (obj.that.picking) {
if (obj.that.type === 'bim') {
if (YJ.Global.getBimPickStatus(sdk)) {
let cartesian = getcartesian(sdk, movement)
if (!cartesian) {
return
}
obj.callback(
movement,
pick.getProperty('id'),
cartesian3Towgs84(cartesian, sdk.viewer), obj.that)
}
}
else {
let cartesian = getcartesian(sdk, movement)
if (!cartesian) {
return
}
obj.callback(
movement,
pick.content.tileset.id,
cartesian3Towgs84(cartesian, sdk.viewer), obj.that)
}
}
}
}
}
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
}
function closeRightClick() {
if (rightClickHandler) {
rightClickHandler.destroy() //关闭事件句柄
rightClickHandler = null
}
}
function openMove(sdk) {
MoveHandler = new Cesium.ScreenSpaceEventHandler(sdk.viewer.canvas)
MoveHandler.setInputAction(function (movement) {
const pick = sdk.viewer.scene.pick(movement.endPosition);
// unselectFeature(selectedFeature);
// if (selectedFeature) {
// let color = '#fff'
// let state = selectedFeature.getProperty('state')
// switch (state) {
// case '0':
// color = '#fff'
// break;
// case '1':
// color = '#f00'
// break;
// case '2':
// color = '#0f0'
// break;
// case '3':
// color = '#00f'
// break;
// default:
// }
// selectedFeature.color = Cesium.Color.fromCssColorString(color).withAlpha(selectedFeature.tileset.transparency)
// }
// if (pick && pick.id) { }
// if (pick && pick.content) {
// if (MoveCallbackMap.has(pick.content.tileset.id)) {
// let obj = MoveCallbackMap.get(pick.content.tileset.id)
// if (obj.that.picking) {
// if (obj.that.type === 'bim') {
// if (YJ.Global.getBimPickStatus(sdk)) {
// selectedFeature = pick
// pick.color = Cesium.Color.YELLOW;
// }
// else {
// selectedFeature = null
// }
// }
// else {
// selectedFeature = pick
// pick.color = Cesium.Color.YELLOW;
// }
// }
// else {
// selectedFeature = null
// }
// }
// }
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
}
function closeMove() {
if (MoveHandler) {
MoveHandler.destroy() //关闭事件句柄
MoveHandler = null
}
}
/*注册左键回调*/
function regLeftClickCallback(id, callback, that) {
leftClickCallbackMap.set(id, { callback, that })
}/*取消左键回调*/
function unRegLeftClickCallback(id,) {
leftClickCallbackMap.delete(id,)
}
/*注册右键回调*/
function regRightClickCallback(id, callback, that) {
rightClickCallbackMap.set(id, { callback, that })
}/*取消右键回调*/
function unRegRightClickCallback(id,) {
rightClickCallbackMap.delete(id,)
}
/*注册左键回调*/
function regMoveCallback(id, callback, that) {
MoveCallbackMap.set(id, { callback, that })
}/*取消左键回调*/
function unregMoveCallback(id,) {
MoveCallbackMap.delete(id,)
}
function getLeftClickState() {
if (leftClickHandler) {
return true
}
else {
false
}
}
function getRightClickState() {
if (rightClickHandler) {
return true
}
else {
false
}
}
function getMoveState() {
if (MoveHandler) {
return true
}
else {
false
}
}
export { openLeftClick, closeLeftClick, regLeftClickCallback, unRegLeftClickCallback, openRightClick, closeRightClick, regRightClickCallback, unRegRightClickCallback, openMove, closeMove, regMoveCallback, unregMoveCallback, getLeftClickState, getRightClickState, getMoveState }

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,366 @@
/*
let datasource=null
let dataSourcePromise = null
// let enabled = true
let dataSourcexg = null
function createCluster(viewer) {
datasource = new Cesium.CustomDataSource("dataSource1");
dataSourcePromise = viewer.dataSources.add(datasource);
dataSourcePromise.then((dataSource)=> {
// return;
const pixelRange = 15;
const minimumClusterSize = 3;
const enabled = false;
dataSourcexg = dataSource
dataSource.clustering.enabled = enabled; //聚合开启
dataSource.clustering.pixelRange = pixelRange; //设置像素范围,以扩展显示边框
dataSource.clustering.minimumClusterSize = minimumClusterSize; //设置最小的聚合点数目,超过此数目才能聚合
let removeListener;
//按聚合层级创建对应图标
const pinBuilder = new Cesium.PinBuilder();
// console.log('pinBuilder',pinBuilder);
var pin100 = pinBuilder
.fromText("100+", Cesium.Color.BLUE, 48)
.toDataURL();
var pin50 = pinBuilder
.fromText("50+", Cesium.Color.BLUE, 48)
.toDataURL();
var pin40 = pinBuilder
.fromText("40+", Cesium.Color.RED, 48)
.toDataURL();
var pin30 = pinBuilder
.fromText("30+", Cesium.Color.RED, 48)
.toDataURL();
var pin20 = pinBuilder
.fromText("20+", Cesium.Color.RED, 48)
.toDataURL();
var pin10 = pinBuilder
.fromText("10+", Cesium.Color.RED, 48)
.toDataURL();
// 10以内聚合图标
const singleDigitPins = new Array(8);
for (let i = 0; i < singleDigitPins.length; ++i) {
singleDigitPins[i] = pinBuilder
.fromText(`${i + 2}`, Cesium.Color.VIOLET, 48)
.toDataURL();
}
function customStyle() {
if (Cesium.defined(removeListener)) {
removeListener();
removeListener = undefined;
} else {
removeListener = dataSource.clustering.clusterEvent.addEventListener(
function(clusteredEntities, cluster) {
cluster.label.show = false;
cluster.billboard.show = true;
cluster.billboard.id = cluster.label.id;
cluster.billboard.verticalOrigin = Cesium.VerticalOrigin.BOTTOM;
if (clusteredEntities.length >= 100) {
cluster.billboard.image = pin100;
} else if (clusteredEntities.length >= 50) {
cluster.billboard.image = pin50;
} else if (clusteredEntities.length >= 40) {
cluster.billboard.image = pin40;
} else if (clusteredEntities.length >= 30) {
cluster.billboard.image = pin30;
} else if (clusteredEntities.length >= 20) {
cluster.billboard.image = pin20;
} else if (clusteredEntities.length >= 10) {
cluster.billboard.image = pin10;
} else {
cluster.billboard.image =
singleDigitPins[clusteredEntities.length - 2];
}
}
);
}
// force a re-cluster with the new styling
const pixelRange = dataSource.clustering.pixelRange;
dataSource.clustering.pixelRange = 0;
dataSource.clustering.pixelRange = pixelRange;
}
customStyle();
var viewModel = {
pixelRange: pixelRange,
minimumClusterSize: minimumClusterSize,
};
Cesium.knockout.track(viewModel);
function subscribeParameter(name) {
Cesium.knockout
.getObservable(viewModel, name)
.subscribe(function (newValue) {
dataSource.clustering[name] = newValue;
});
}
subscribeParameter("pixelRange");
subscribeParameter("minimumClusterSize");
});
}
function addCluster(entity) {
datasource.entities.add(entity)
}
function remove_entity_from_cluster(entity) {
datasource.entities.remove(entity)
}
function switchCluster(status){
dataSourcexg.clustering.enabled = status
}
*/
import Tools from '../../Tools'
import {
getGroundCover
} from '../../Global/global'
/*创建聚合,只能聚合point billboardlabel*/
function createCluster(viewer) {
let tools = new Tools()
let cluster = new Cesium.CustomDataSource("sdk-dataSource1")
let dataSourcePromise = viewer.dataSources.add(cluster)
dataSourcePromise.then(dataSource => {
// if (!get2DView()) {
// dataSource.entities.collectionChanged.addEventListener((entities) => {
// syncDataSources(dataSource, 'entities')
// })
// }
var pixelRange = 15;
var minimumClusterSize = 2;
var enabled = false;
dataSource.clustering.enabled = enabled;
dataSource.clustering.pixelRange = pixelRange;
dataSource.clustering.minimumClusterSize = minimumClusterSize;
var removeListener;
var pinBuilder = new Cesium.PinBuilder();
var pin50 = pinBuilder
.fromText("50+", Cesium.Color.RED, 48)
.toDataURL();
var pin40 = pinBuilder
.fromText("40+", Cesium.Color.ORANGE, 48)
.toDataURL();
var pin30 = pinBuilder
.fromText("30+", Cesium.Color.YELLOW, 48)
.toDataURL();
var pin20 = pinBuilder
.fromText("20+", Cesium.Color.GREEN, 48)
.toDataURL();
var pin10 = pinBuilder
.fromText("10+", Cesium.Color.BLUE, 48)
.toDataURL();
var singleDigitPins = new Array(8);
for (var i = 0; i < singleDigitPins.length; ++i) {
singleDigitPins[i] = pinBuilder
.fromText("" + (i + 2), Cesium.Color.VIOLET, 48)
.toDataURL();
}
function customStyle() {
if (Cesium.defined(removeListener)) {
removeListener();
removeListener = undefined;
} else {
removeListener = dataSource.clustering.clusterEvent.addEventListener(
function (clusteredEntities, cluster) {
// cluster.label.show = false;
// cluster.label.verticalOrigin = false;
cluster.billboard.show = true;
cluster.billboard.id = cluster.label.id;
cluster.billboard.verticalOrigin =
Cesium.VerticalOrigin.BOTTOM;
// 根据聚合数量的多少设置不同层级的图片以及大小
/*if (clusteredEntities.length >= 50) {
cluster.billboard.image = that.combineIconAndLabel(host + '1_大红.png', clusteredEntities.length, 64);
cluster.billboard.width = 72;
cluster.billboard.height = 72;
} else if (clusteredEntities.length >= 40) {
cluster.billboard.image = that.combineIconAndLabel(host + '1_大黄.png', clusteredEntities.length, 64);
cluster.billboard.width = 56;
cluster.billboard.height = 56;
} else if (clusteredEntities.length >= 30) {
cluster.billboard.image = that.combineIconAndLabel(host + '1_大蓝.png', clusteredEntities.length, 64);
cluster.billboard.width = 48;
cluster.billboard.height = 48;
} else if (clusteredEntities.length >= 20) {
cluster.billboard.image = that.combineIconAndLabel(host + '1_小红.png', clusteredEntities.length, 64);
cluster.billboard.width = 48;
cluster.billboard.height = 48;
} else if (clusteredEntities.length >= 10) {
cluster.billboard.image = that.combineIconAndLabel(host + '1_小黄.png', clusteredEntities.length, 64);
cluster.billboard.width = 48;
cluster.billboard.height = 48;
} else {
cluster.billboard.image = that.combineIconAndLabel(host + '1_小蓝.png', clusteredEntities.length, 64);
cluster.billboard.width = 40;
cluster.billboard.height = 40;
}*/
cluster.billboard.image = tools.getSourceRootPath() + '/img/cluster.png'
cluster.billboard.disableDepthTestDistance = getGroundCover() ? undefined : Number.POSITIVE_INFINITY
cluster.label.verticalOrigin = Cesium.VerticalOrigin.CENTER
cluster.label.font = "18px Arial,sans-serif",
// cluster.label.scale = 0.5
cluster.label.disableDepthTestDistance = getGroundCover() ? undefined : Number.POSITIVE_INFINITY
cluster.label.style = Cesium.LabelStyle.FILL
cluster.label.showBackground = true
cluster.label.backgroundColor = Cesium.Color.WHITE.withAlpha(0.0)
if (clusteredEntities.length >= 1000) {
cluster.billboard.scale = 1.5;
cluster.label.pixelOffset = new Cesium.Cartesian2(-28, -46)
} else if (clusteredEntities.length >= 100) {
cluster.billboard.scale = 1.25;
cluster.label.pixelOffset = new Cesium.Cartesian2(-21, -40)
} else if (clusteredEntities.length >= 50) {
cluster.billboard.scale = 1.1;
cluster.label.pixelOffset = new Cesium.Cartesian2(-16, -36)
} else if (clusteredEntities.length >= 40) {
cluster.billboard.scale = 1.05;
cluster.label.pixelOffset = new Cesium.Cartesian2(-16, -34)
} else if (clusteredEntities.length >= 30) {
cluster.billboard.scale = 1;
cluster.label.pixelOffset = new Cesium.Cartesian2(-16, -32)
} else if (clusteredEntities.length >= 20) {
cluster.billboard.scale = 0.95;
cluster.label.pixelOffset = new Cesium.Cartesian2(-16, -30)
} else if (clusteredEntities.length >= 10) {
cluster.billboard.scale = 0.9;
cluster.label.pixelOffset = new Cesium.Cartesian2(-16, -28)
} else {
cluster.billboard.scale = 0.8;
cluster.label.pixelOffset = new Cesium.Cartesian2(-11, -25)
}
// if (clusteredEntities.length >= 50) {
// cluster.billboard.image = pin50;
// } else if (clusteredEntities.length >= 40) {
// cluster.billboard.image = pin40;
// } else if (clusteredEntities.length >= 30) {
// cluster.billboard.image = pin30;
// } else if (clusteredEntities.length >= 20) {
// cluster.billboard.image = pin20;
// } else if (clusteredEntities.length >= 10) {
// cluster.billboard.image = pin10;
// } else {
// cluster.billboard.image =
// singleDigitPins[clusteredEntities.length - 2];
// }
}
);
}
// force a re-cluster with the new styling
var pixelRange = dataSource.clustering.pixelRange;
dataSource.clustering.pixelRange = 0;
dataSource.clustering.pixelRange = pixelRange;
}
// start with custom style
customStyle();
var viewModel = {
pixelRange: pixelRange,
minimumClusterSize: minimumClusterSize,
};
Cesium.knockout.track(viewModel);
function subscribeParameter(name) {
Cesium.knockout
.getObservable(viewModel, name)
.subscribe(function (newValue) {
dataSource.clustering[name] = newValue;
});
}
subscribeParameter("pixelRange");
subscribeParameter("minimumClusterSize");
// var handler = new Cesium.ScreenSpaceEventHandler(this.sdk.viewer.scene.canvas);
// handler.setInputAction((movement) => {
// var pickedLabel = this.sdk.viewer.scene.pick(movement.position);
//
// if (Cesium.defined(pickedLabel)) {
// this.log(pickedLabel)
// var ids = pickedLabel.id;
// if (Array.isArray(ids)) {
// for (var i = 0; i < ids.length; ++i) {
// ids[i].billboard.color = Cesium.Color.RED;
// }
// }
// }
// }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
})
}
/**
* @description 开启/关闭聚合效果
* @method set_cluster_status
* @param [enable=false] {boolean}默认关闭
* @memberOf Tool-3D
* */
function switchCluster(sdk, enable = false) {
let viewer = sdk.viewer
for (let i = 0; i < viewer.dataSources._dataSources.length; i++) {
if (viewer.dataSources._dataSources[i].name === "sdk-dataSource1") {
viewer.dataSources._dataSources[i].clustering.enabled = enable
// syncDataSources(viewer.dataSources._dataSources[i], 'clustering')
break
}
}
}
function addCluster(sdk, entity) {
let viewer = sdk.viewer
if(!viewer) {
return
}
for (let i = 0; i < viewer.dataSources._dataSources.length; i++) {
if (viewer.dataSources._dataSources[i].name === "sdk-dataSource1") {
viewer.dataSources._dataSources[i].entities.add(entity)
break
}
}
}
function remove_entity_from_cluster(viewer, entity) {
for (let i = 0; i < viewer.dataSources._dataSources.length; i++) {
if (viewer.dataSources._dataSources[i].name === "sdk-dataSource1") {
viewer.dataSources._dataSources[i].entities.remove(entity)
break
}
}
}
function updateCluster(viewer) {
if(!viewer) {
return
}
for (let i = 0; i < viewer.dataSources._dataSources.length; i++) {
if (viewer.dataSources._dataSources[i].name === "sdk-dataSource1") {
viewer.dataSources._dataSources[i].clustering._cluster()
break
}
}
}
export { createCluster, addCluster, switchCluster, remove_entity_from_cluster, updateCluster }

159
src/Global/efflect/index.js Normal file
View File

@ -0,0 +1,159 @@
/*全局特效*/
let rainStages = null;
let snowStages = null;
let fogStages = null;
let nightVisionStages = null;
// 雨
const FS_Rain = `uniform sampler2D colorTexture;//输入的场景渲染照片
varying vec2 v_textureCoordinates;
uniform float tiltAngle;
uniform float rainSize;
uniform float rainWidth;
uniform float rainSpeed;
float hash(float x){
return fract(sin(x*133.3)*13.13);
}
void main(void){
float time = czm_frameNumber / rainSpeed;
vec2 resolution = czm_viewport.zw;
vec2 uv=(gl_FragCoord.xy*2.-resolution.xy)/min(resolution.x,resolution.y);
vec3 c=vec3(.6,.7,.8);
float a= tiltAngle;
float si=sin(a),co=cos(a);
uv*=mat2(co,-si,si,co);
uv*=length(uv+vec2(0,4.9))*rainSize+1.;
float v=1.-sin(hash(floor(uv.x*rainWidth))*2.);
float b=clamp(abs(sin(20.*time*v+uv.y*(5./(2.+v))))-.95,0.,1.)*20.;
c*=v*b; //屏幕上雨的颜色
gl_FragColor = mix(texture2D(colorTexture, v_textureCoordinates), vec4(c,1), 0.5); //将雨和三维场景融合
}`
// 雪
const FS_Snow = `uniform sampler2D colorTexture;
varying vec2 v_textureCoordinates;
uniform float snowSize;
uniform float snowSpeed;
float snow(vec2 uv,float scale)
{
float time = czm_frameNumber / snowSpeed;
float w=smoothstep(1.,0.,-uv.y*(scale/10.));if(w<.1)return 0.;
uv+=time/scale;uv.y+=time*2./scale;uv.x+=sin(uv.y+time*.5)/scale;
uv*=scale;vec2 s=floor(uv),f=fract(uv),p;float k=3.,d;
p=.5+.35*sin(11.*fract(sin((s+p+scale)*mat2(7,3,6,5))*5.))-f;d=length(p);k=min(d,k);
k=smoothstep(0.,k,sin(f.x+f.y)*0.01*snowSize);
return k*w;
}
void main(void){
vec2 resolution = czm_viewport.zw;
vec2 uv=(gl_FragCoord.xy*2.-resolution.xy)/min(resolution.x,resolution.y);
vec3 finalColor=vec3(0);
//float c=smoothstep(1.,0.3,clamp(uv.y*.3+.8,0.,.75));
float c = 0.0;
c+=snow(uv,30.)*.0;
c+=snow(uv,20.)*.0;
c+=snow(uv,15.)*.0;
c+=snow(uv,10.);
c+=snow(uv,8.);
c+=snow(uv,6.);
c+=snow(uv,5.);
finalColor=(vec3(c));
gl_FragColor = mix(texture2D(colorTexture, v_textureCoordinates), vec4(finalColor,1), 0.5);
}
`;
// 雾
const FS_Fog = `
uniform sampler2D colorTexture;
uniform sampler2D depthTexture;
uniform float visibility;
uniform vec4 fogColor;
varying vec2 v_textureCoordinates;
void main(void)
{
vec4 origcolor = texture2D(colorTexture, v_textureCoordinates);
float depth = czm_readDepth(depthTexture, v_textureCoordinates);
vec4 depthcolor = texture2D(depthTexture, v_textureCoordinates);
float f = visibility * (depthcolor.r - 0.3) / 0.2;
if (f < 0.0) f = 0.0;
else if (f > 1.0) f = 1.0;
gl_FragColor = mix(origcolor, fogColor, f);
}
`;
/*雨天*/
function rain(sdk, status = false) {
rainStages && sdk.viewer.scene.postProcessStages.remove(rainStages)
if (status) {
rainStages = new Cesium.PostProcessStage({
name: "rain",
fragmentShader: FS_Rain,
uniforms: {
tiltAngle: -0.4, // 倾斜角度
rainSize: 0.3, // 雨大小
rainWidth: 40, //雨长度
rainSpeed: 100, //雨速
},
});
sdk.viewer.scene.postProcessStages.add(rainStages);
}
}
// 雪
function snow(sdk, status = false) {
snowStages && sdk.viewer.scene.postProcessStages.remove(snowStages)
if (status) {
snowStages = new Cesium.PostProcessStage({
name: "snow",
fragmentShader: FS_Snow,
uniforms: {
snowSize: 2, // 大小
snowSpeed: 60, //速度
},
});
sdk.viewer.scene.postProcessStages.add(snowStages);
}
}
// 雾天
function fog(sdk, status = false) {
fogStages && sdk.viewer.scene.postProcessStages.remove(fogStages)
if (status) {
fogStages = new Cesium.PostProcessStage({
name: "fog",
fragmentShader: FS_Fog,
uniforms: {
visibility: 0.2, //
fogColor: Cesium.Color.WHITE,
},
});
sdk.viewer.scene.postProcessStages.add(fogStages);
}
}
// 夜视
function nightVision(sdk, status = false) {
nightVisionStages && sdk.viewer.scene.postProcessStages.remove(nightVisionStages)
if (status) {
nightVisionStages = Cesium.PostProcessStageLibrary.createNightVisionStage();
sdk.viewer.scene.postProcessStages.add(nightVisionStages);
}
}
// 星空
function skyStarry(sdk, status = false) {
sdk.viewer.scene.skyAtmosphere.show = !status
}
// 光照
function illumination(sdk, status = false) {
sdk.viewer.shadows = status
sdk.viewer._shadows = status
}
export { rain, snow, fog, nightVision, skyStarry, illumination }

825
src/Global/global.js Normal file
View File

@ -0,0 +1,825 @@
/**
* @name: global
* @author: Administrator
* @date: 2023-12-01 14:15
* @descriptionglobal
* @update: 2023-12-01 14:15
*/
/*获取当前视角*/
import MouseEvent from '../Event/index'
import Tools from "../Tools";
import { Proj } from "../Tools/proj";
import { getTheme, setTheme } from "../Obj/Element/theme";
import { setActiveViewer as setMultiViewportActiveViewer } from './MultiViewportMode'
import { setActiveViewer as setSplitActiveViewer, getSdk } from './SplitScreen'
import { updateCluster } from './cluster/cluster'
let coordinateSystem = 'EPSG:4326'
let _cartesian
let GroundCover = false
let bimPickObject = {}
let containerObject = {}
let rotateAroundObject = {}
function getCurrentView(sdk) {
let tools = new Tools()
let viewer = sdk.viewer
return JSON.parse(JSON.stringify({
// heading: viewer.camera.heading,
// pitch: viewer.camera.pitch,
// roll: viewer.camera.roll,
position: tools.cartesian3Towgs84(viewer.camera.position, viewer),
orientation: {
heading: Cesium.Math.toDegrees(viewer.camera.heading),
pitch: Cesium.Math.toDegrees(viewer.camera.pitch),
roll: Cesium.Math.toDegrees(viewer.camera.roll)
}
}))
}
/*设置默认视角*/
function setDefaultView(sdk, options) {
let viewer = sdk.viewer
if (options) {
viewer.CAMERA_DEFAULT_VIEW_RECTANGLE = {
destination: options.destination || {},
orientation: options.orientation || {}
}
}
else {
viewer.CAMERA_DEFAULT_VIEW_RECTANGLE = undefined
//设置cesium的默认视角
Cesium.Camera.DEFAULT_VIEW_RECTANGLE = Cesium.Rectangle.fromDegrees(
//西边的经度
89.5,
//南边的纬度
10.4,
//东边的经度
110.4,
//北边的维度
61.2
)
}
}
/*定位到指定视角*/
async function flyTo(sdk, options, duration = 3) {
let tools = new Tools(sdk)
let destination
let orientation = options.orientation
if (options.position) {
if (options.position.alt !== 0 && !options.position.alt) {
options.position.alt = await tools.getClampToHeight(options.position)
}
let h = 0
if (!orientation) {
h = 500
}
destination = Cesium.Cartesian3.fromDegrees(options.position.lng, options.position.lat, options.position.alt + h)
}
else {
let bbox = tools.cal_envelope(options.positions)
destination = new Cesium.Rectangle(
Cesium.Math.toRadians(bbox[3][0]),
Cesium.Math.toRadians(bbox[3][1]),
Cesium.Math.toRadians(bbox[1][0]),
Cesium.Math.toRadians(bbox[1][1])
)
}
closeRotateAround(sdk)
sdk.viewer.camera.flyTo({ destination, duration, orientation, complete: options.complete, })
}
/*相机锁定*/
function CameraController(sdk, status = true) {
if (!sdk || !sdk.viewer) {
return
}
let viewer = sdk.viewer
viewer.scene.screenSpaceCameraController.enableRotate = status;
viewer.scene.screenSpaceCameraController.enableTranslate = status;
viewer.scene.screenSpaceCameraController.enableZoom = status;
viewer.scene.screenSpaceCameraController.enableTilt = status;
viewer.scene.screenSpaceCameraController.enableLook = status;
}
/*控件显隐*/
function CesiumContainer(sdk, options) {
if (!sdk || !sdk.viewer) {
return
}
containerObject[sdk.viewer._element.className] || (containerObject[sdk.viewer._element.className] = {})
containerObject[sdk.viewer._element.className].event && containerObject[sdk.viewer._element.className].event.destroy()
let tools = new Tools()
let element = sdk.viewer._element
let proj = sdk.proj
for (let key in options) {
switch (key) {
case 'compass':
let compass = element.getElementsByClassName('compass')[0]
let navigation = element.getElementsByClassName('navigation-controls')[0]
if (options[key]) {
compass && (compass.style.display = 'block')
navigation && (navigation.style.display = 'flex')
}
else {
compass && (compass.style.display = 'none')
navigation && (navigation.style.display = 'none')
}
break;
case 'legend':
let distanceLegend = element.getElementsByClassName('distance-legend')[0]
if (options[key]) {
distanceLegend && (distanceLegend.parentNode.style.display = 'block')
}
else {
distanceLegend && (distanceLegend.parentNode.style.display = 'none')
}
break;
case 'info':
let infoElm = element.getElementsByClassName('cesium-info')[0]
if (options[key]) {
if (infoElm) {
update()
infoElm.style.display = 'block'
}
else {
infoElm = document.createElement('div');
infoElm.className = "cesium-info"
infoElm.style.position = 'absolute';
infoElm.style.bottom = '32px';
infoElm.style.right = '240px';
infoElm.style['font-size'] = '14px';
infoElm.style['background-color'] = 'rgba(47,53,60,.8)';
infoElm.style.color = '#fff';
infoElm.style.padding = '4px 10px';
infoElm.style['border-radius'] = '18px';
if (coordinateSystem === 'EPSG:4326') {
infoElm.innerHTML = `
<span>经度:</span><span>-</span>
<span>纬度:</span><span>-</span>
<span>海拔高度:</span><span>-</span>
`
}
else {
infoElm.innerHTML = `
<span>x</span><span>-</span>
<span>y</span><span>-</span>
<span>z</span><span>-</span>
`
}
sdk.viewer._element.appendChild(infoElm)
}
let event = new MouseEvent(sdk)
containerObject[sdk.viewer._element.className].event = event
event.mouse_move((movement, cartesian) => {
_cartesian = cartesian
update()
})
function update() {
if (!_cartesian) {
return
}
let position = tools.cartesian3Towgs84(_cartesian, sdk.viewer)
if (coordinateSystem === 'EPSG:4326') {
infoElm.innerHTML = `
<span>经度:</span><span>${Number(position.lng.toFixed(6))}° </span>
<span>纬度:</span><span>${Number(position.lat.toFixed(6))}° </span>
<span>海拔高度:</span><span>${Number(position.alt.toFixed(2))}米</span>
`
}
else {
let result = proj.convert([{ x: position.lng, y: position.lat, z: position.alt }], 'EPSG:4326', coordinateSystem)
infoElm.innerHTML = `
<span>x</span><span>${Number(result.points[0].x.toFixed(6))}</span>
<span style="margin-left: 5px;">y</span><span>${Number(result.points[0].y.toFixed(6))}</span>
<span style="margin-left: 5px;">z</span><span>${Number(result.points[0].z.toFixed(6))}</span>
`
}
}
}
else {
infoElm && (infoElm.style.display = 'none')
}
break;
case 'frame':
if (options[key]) {
sdk.viewer.scene.debugShowFramesPerSecond = true;
setTimeout(() => {
let cesiumWidgetContainerElm = sdk.viewer._element.getElementsByClassName('cesium-viewer-cesiumWidgetContainer')[0]
let defaultContainer = cesiumWidgetContainerElm.getElementsByClassName('cesium-performanceDisplay-defaultContainer')[0]
if (defaultContainer) {
cesiumWidgetContainerElm.appendChild(defaultContainer)
}
}, 50);
}
else {
sdk.viewer.scene.debugShowFramesPerSecond = false;
}
break;
}
}
// let compass = element.getElementsByClassName('compass')[0]
// let navigation = element.getElementsByClassName('navigation-controls')[0]
// let distanceLegend = element.getElementsByClassName('distance-legend')[0]
// if(status) {
// compass && (compass.style.display = 'block')
// navigation && (navigation.style.display = 'block')
// distanceLegend && (distanceLegend.style.display = 'block')
// }
// else {
// compass && (compass.style.display = 'none')
// navigation && (navigation.style.display = 'none')
// distanceLegend && (distanceLegend.style.display = 'none')
// viewer.cesiumNavigation.distanceLegendViewModel.destroy()
// }
}
/*设置广告牌默认图标*/
function setBillboardDefaultUrl(url, name) {
if (name) {
name = 'billboard_default_url_' + name
}
else {
name = 'billboard_default_url'
}
localStorage.setItem(name, url);
}
/*获取广告牌默认图标*/
function getBillboardDefaultUrl(name) {
if (name) {
name = 'billboard_default_url_' + name
}
else {
name = 'billboard_default_url'
}
return localStorage.getItem(name);
}
/*设置高度参考*/
function setGroundCover(sdk, status) {
GroundCover = status ? true : false
updateCluster(sdk.viewer)
}
/*获取高度参考*/
function getGroundCover() {
return GroundCover
}
function setBimPickStatus(sdk, status) {
if (!sdk || !sdk.viewer) {
return
}
bimPickObject[sdk.viewer._element.className] || (bimPickObject[sdk.viewer._element.className] = {})
bimPickObject[sdk.viewer._element.className].status = status
if (bimPickObject[sdk.viewer._element.className].MoveHandler) {
bimPickObject[sdk.viewer._element.className].MoveHandler.destroy()
}
if (!status) {
return
}
bimPickObject[sdk.viewer._element.className].MoveHandler = new Cesium.ScreenSpaceEventHandler(sdk.viewer.canvas)
bimPickObject[sdk.viewer._element.className].MoveHandler.setInputAction(function (movement) {
const pick = sdk.viewer.scene.pick(movement.endPosition);
let selectedId = bimPickObject[sdk.viewer._element.className].selectedId
let that = sdk.entityMap.get(bimPickObject[sdk.viewer._element.className].id)
// if (selectedFeatureId) {
// let color = '#fff'
// let state = selectedFeature.getProperty('state')
// switch (state) {
// case '0':
// color = '#fff'
// break;
// case '1':
// color = '#f00'
// break;
// case '2':
// color = '#0f0'
// break;
// case '3':
// color = '#00f'
// break;
// default:
// }
// selectedFeature.color = Cesium.Color.fromCssColorString(color).withAlpha(selectedFeature.tileset.transparency)
// }
if (that) {
if (that.features.has(selectedId)) {
let features = that.features.get(selectedId).features
for (let key in features) {
if (features[key].content._model) {
let color = features[key].customColor || Cesium.Color.fromCssColorString('#fff')
features[key].color = Cesium.Color.fromCssColorString(`rgba(${Cesium.Color.floatToByte(color.red)},${Cesium.Color.floatToByte(color.green)},${Cesium.Color.floatToByte(color.blue)},${color.alpha * ((features[key].customAlpha || features[key].customAlpha === 0) ? features[key].customAlpha : 1)})`)
}
}
}
}
if (pick && pick.content) {
let obj = sdk.getIncetance(pick.content.tileset.id)
if (obj.type === 'bim') {
if (pick.primitive && pick.primitive.id) {
let that = sdk.entityMap.get(pick.primitive.id)
selectedId = pick.getProperty('id')
if (that.features.has(selectedId)) {
let features = that.features.get(selectedId).features
for (let key in features) {
if (features[key].content._model) {
features[key].color = Cesium.Color.fromCssColorString('#ffeb3b')
}
}
}
bimPickObject[sdk.viewer._element.className].id = pick.primitive.id
bimPickObject[sdk.viewer._element.className].selectedId = selectedId
}
}
else {
pick.primitive.id = null
}
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
}
function getBimPickStatus(sdk) {
if (!sdk || !sdk.viewer) {
return
}
return bimPickObject[sdk.viewer._element.className] ? bimPickObject[sdk.viewer._element.className].status : false
}
/* 围绕坐标旋转 */
function rotateAround(sdk, position) {
if (!sdk || !sdk.viewer) {
return
}
setActiveViewer(0)
sdk.viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
// 关闭Controller
sdk.entityMap.forEach((item) => {
item.editObj && item.editObj.destroy()
item.ControllerObject && item.ControllerObject.destroy()
})
rotateAroundObject[sdk.viewer._element.className] || (rotateAroundObject[sdk.viewer._element.className] = {})
rotateAroundObject[sdk.viewer._element.className].animate && TWEEN.remove(rotateAroundObject[sdk.viewer._element.className].animate)
rotateAroundObject[sdk.viewer._element.className].event && rotateAroundObject[sdk.viewer._element.className].event.destroy()
if (!position) {
CameraController(sdk, true)
return
}
let point = Cesium.Cartesian3.fromDegrees(position.lng, position.lat, position.alt)
let angle = Cesium.Math.toDegrees(sdk.viewer.camera.heading)
let range = Cesium.Cartesian3.distance(sdk.viewer.camera.position, point);
CameraController(sdk, false)
let pitch = sdk.viewer.camera.pitch
let degrees = Cesium.Math.toDegrees(pitch)
if (degrees < -89.99) {
pitch = Cesium.Math.toRadians(-89.99)
}
rotateAroundObject[sdk.viewer._element.className].animate = new TWEEN.Tween({ angle: angle }).to({ angle: angle - 360 }, 30000).easing(TWEEN.Easing.Linear.None).repeat(Infinity).onUpdate(async (r, a) => {
if (!sdk.viewer) {
TWEEN.remove(rotateAroundObject[sdk.viewer._element.className].animate)
return
}
sdk.viewer.camera.lookAt(
point,
new Cesium.HeadingPitchRange(Cesium.Math.toRadians(r.angle), pitch, range)
)
sdk.viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
}).start()
let event = new MouseEvent(sdk)
rotateAroundObject[sdk.viewer._element.className].event = event
event.mouse_left_down(() => {
rotateAroundObject[sdk.viewer._element.className].animate && TWEEN.remove(rotateAroundObject[sdk.viewer._element.className].animate)
rotateAroundObject[sdk.viewer._element.className].event && rotateAroundObject[sdk.viewer._element.className].event.destroy()
CameraController(sdk, true)
sdk.viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
})
}
/* 关闭围绕坐标旋转 */
function closeRotateAround(sdk) {
if (!sdk || !sdk.viewer) {
return
}
if (rotateAroundObject[sdk.viewer._element.className]) {
rotateAroundObject[sdk.viewer._element.className].animate && TWEEN.remove(rotateAroundObject[sdk.viewer._element.className].animate)
rotateAroundObject[sdk.viewer._element.className].event && rotateAroundObject[sdk.viewer._element.className].event.destroy()
CameraController(sdk, true)
sdk.viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
}
}
function closeViewFollow(sdk) {
if (sdk && sdk.entityMap) {
let entityMap = sdk.entityMap
for (let [key, value] of entityMap) {
if (value.type === 'TrajectoryMotion' && value.viewFollow) {
value.viewFollow = false
}
}
}
}
/* 方里网状态开关 */
function FlwStatusSwitch(sdk, status) {
if(!sdk) {
return
}
let layer
let sdkD = getSdk().sdkD
if(sdkD && sdk !== sdkD) {
FlwStatusSwitch(sdkD, status)
}
for (let i = 0; i < sdk.viewer.imageryLayers._layers.length; i++) {
if (sdk.viewer.imageryLayers._layers[i]._imageryProvider && sdk.viewer.imageryLayers._layers[i]._imageryProvider._type && sdk.viewer.imageryLayers._layers[i]._imageryProvider._type === 'flw') {
layer = sdk.viewer.imageryLayers._layers[i]
break
}
}
if (layer) {
sdk.viewer.imageryLayers.remove(layer)
}
if (status) {
sdk.viewer.imageryLayers.addImageryProvider(new Cesium.TileCoordinatesImageryProviderFlw(
{
tileWidth: 128,
tileHeight: 128,
}
));
}
}
function getFlwStatus(sdk) {
let status = false
for (let i = 0; i < sdk.viewer.imageryLayers._layers.length; i++) {
if (sdk.viewer.imageryLayers._layers[i]._imageryProvider && sdk.viewer.imageryLayers._layers[i]._imageryProvider._type && sdk.viewer.imageryLayers._layers[i]._imageryProvider._type === 'flw') {
status = true
break
}
}
return status
}
/* 经纬网状态开关 */
function JwwStatusSwitch(sdk, status) {
if(!sdk) {
return
}
let layer
let sdkD = getSdk().sdkD
if(sdkD && sdk !== sdkD) {
JwwStatusSwitch(sdkD, status)
}
for (let i = 0; i < sdk.viewer.imageryLayers._layers.length; i++) {
if (sdk.viewer.imageryLayers._layers[i]._imageryProvider && sdk.viewer.imageryLayers._layers[i]._imageryProvider._type && sdk.viewer.imageryLayers._layers[i]._imageryProvider._type === 'jww') {
layer = sdk.viewer.imageryLayers._layers[i]
break
}
}
if (layer) {
sdk.viewer.imageryLayers.remove(layer)
}
if (status) {
sdk.viewer.imageryLayers.addImageryProvider(new Cesium.TileCoordinatesImageryProviderJww());
}
}
function getJwwStatus(sdk) {
let status = false
for (let i = 0; i < sdk.viewer.imageryLayers._layers.length; i++) {
if (sdk.viewer.imageryLayers._layers[i]._imageryProvider && sdk.viewer.imageryLayers._layers[i]._imageryProvider._type && sdk.viewer.imageryLayers._layers[i]._imageryProvider._type === 'jww') {
status = true
break
}
}
return status
}
function splitScreen2(sdk, status) {
let sliderElm = sdk.viewer._element.getElementsByClassName('YJ-custom-slider')[0]
let leftElm = sdk.viewer._element.getElementsByClassName('YJ-custom-checkbox-left')[0]
let rightElm = sdk.viewer._element.getElementsByClassName('YJ-custom-checkbox-right')[0]
if (sliderElm) {
sdk.viewer._element.removeChild(sliderElm)
sdk.viewer._element.removeChild(leftElm)
sdk.viewer._element.removeChild(rightElm)
}
if (status) {
sliderElm = document.createElement('div');
sliderElm.className = 'YJ-custom-slider'
sliderElm.style.position = 'absolute'
sliderElm.style.left = '50%'
sliderElm.style.top = '0px'
leftElm = document.createElement('input');
leftElm.className = 'YJ-custom-checkbox-left'
leftElm.type = 'checkbox'
leftElm.style.position = 'absolute'
leftElm.style.left = 'calc(50% - 50px)'
rightElm = document.createElement('input');
rightElm.className = 'YJ-custom-checkbox-right'
rightElm.type = 'checkbox'
rightElm.style.position = 'absolute'
rightElm.style.right = 'calc(50% - 50px)'
sdk.viewer._element.appendChild(leftElm)
sdk.viewer._element.appendChild(rightElm)
leftElm.checked = true
leftElm.addEventListener('change', (e) => {
if (!e.target.checked) {
if (!rightElm.checked) {
rightElm.checked = true
}
}
changeEntitySplitStatus()
})
rightElm.addEventListener('change', (e) => {
if (!e.target.checked) {
if (!leftElm.checked) {
leftElm.checked = true
}
}
changeEntitySplitStatus()
})
sliderElm.addEventListener('mousedown', () => {
document.body.addEventListener('mousemove', mousemove)
sliderElm.addEventListener('mouseup', () => {
document.body.removeEventListener('mousemove', mousemove)
})
})
function mousemove(a, b) {
if (sdk.viewer._element.getElementsByTagName('canvas')[0] === a.target) {
sliderElm.style.left = (a.offsetX / sdk.viewer._element.scrollWidth * 100) + '%'
sdk.viewer.scene.splitPosition = a.offsetX / sdk.viewer._element.scrollWidth
}
}
sdk.viewer._element.appendChild(sliderElm)
sdk.viewer.scene.splitStatus = status
sdk.viewer.scene.splitPosition = 0.5
changeEntitySplitStatus()
}
else {
sdk.viewer.scene.splitPosition = 0
changeEntitySplitStatus(0)
sdk.viewer.scene.splitStatus = status
}
function changeEntitySplitStatus(v) {
let value
if (v === undefined || v === null) {
if (leftElm.checked && rightElm.checked) {
value = 0
}
else {
if (leftElm.checked) {
value = -1
}
if (rightElm.checked) {
value = 1
}
}
}
else {
value = v
}
sdk.entityMap.forEach((item, key) => {
if (sdk.viewer.scene.splitStatus) {
if (item.entity.billboard) {
item.entity.billboard.splitDirection = value
}
else {
item.entity && (item.entity.splitDirection = value)
}
}
console.log()
})
}
}
function splitScreen(sdk, status) {
let sliderElm = sdk.viewer._element.getElementsByClassName('YJ-custom-slider')[0]
let leftElm = sdk.viewer._element.getElementsByClassName('YJ-custom-checkbox-left')[0]
let rightElm = sdk.viewer._element.getElementsByClassName('YJ-custom-checkbox-right')[0]
if (sliderElm) {
sdk.viewer._element.removeChild(sliderElm)
sdk.viewer._element.removeChild(leftElm)
sdk.viewer._element.removeChild(rightElm)
}
if (status) {
sliderElm = document.createElement('div');
sliderElm.className = 'YJ-custom-slider'
sliderElm.style.position = 'absolute'
sliderElm.style.left = '50%'
sliderElm.style.top = '0px'
leftElm = document.createElement('input');
leftElm.className = 'YJ-custom-checkbox-left'
leftElm.type = 'checkbox'
leftElm.style.position = 'absolute'
leftElm.style.left = 'calc(50% - 50px)'
rightElm = document.createElement('input');
rightElm.className = 'YJ-custom-checkbox-right'
rightElm.type = 'checkbox'
rightElm.style.position = 'absolute'
rightElm.style.right = 'calc(50% - 50px)'
sdk.viewer._element.appendChild(leftElm)
sdk.viewer._element.appendChild(rightElm)
leftElm.checked = true
leftElm.addEventListener('change', (e) => {
if (!e.target.checked) {
if (!rightElm.checked) {
rightElm.checked = true
}
}
changeEntitySplitStatus()
})
rightElm.addEventListener('change', (e) => {
if (!e.target.checked) {
if (!leftElm.checked) {
leftElm.checked = true
}
}
changeEntitySplitStatus()
})
sliderElm.addEventListener('mousedown', () => {
document.body.addEventListener('mousemove', mousemove)
sliderElm.addEventListener('mouseup', () => {
document.body.removeEventListener('mousemove', mousemove)
})
})
function mousemove(a, b) {
if (sdk.viewer._element.getElementsByTagName('canvas')[0] === a.target) {
sliderElm.style.left = (a.offsetX / sdk.viewer._element.scrollWidth * 100) + '%'
sdk.viewer.scene.splitPosition = a.offsetX / sdk.viewer._element.scrollWidth
}
}
sdk.viewer._element.appendChild(sliderElm)
sdk.viewer.scene.splitStatus = status
sdk.viewer.scene.splitPosition = 0.5
changeEntitySplitStatus()
}
else {
sdk.viewer.scene.splitPosition = 0
changeEntitySplitStatus(0)
sdk.viewer.scene.splitStatus = status
}
function changeEntitySplitStatus(v) {
let value
if (v === undefined || v === null) {
if (leftElm.checked && rightElm.checked) {
value = 0
}
else {
if (leftElm.checked) {
value = -1
}
if (rightElm.checked) {
value = 1
}
}
}
else {
value = v
}
sdk.entityMap.forEach((item, key) => {
if (sdk.viewer.scene.splitStatus) {
if (item.entity.billboard) {
item.entity.billboard.splitDirection = value
}
else {
item.entity && (item.entity.splitDirection = value)
}
}
console.log()
})
}
}
function getCoordinateSystem() {
return coordinateSystem
}
function setCoordinateSystem(sdk, epsg) {
coordinateSystem = epsg || 'EPSG:4326'
if (!sdk || !sdk.viewer || !sdk.viewer._element) {
return
}
let infoElm = sdk.viewer._element.getElementsByClassName('cesium-info')[0]
if (!_cartesian || !infoElm) {
return
}
let tools = new Tools()
let proj = sdk.proj
let position = tools.cartesian3Towgs84(_cartesian, sdk.viewer)
if (coordinateSystem === 'EPSG:4326') {
infoElm.innerHTML = `
<span>经度:</span><span>${Number(position.lng.toFixed(6))}° </span>
<span>纬度:</span><span>${Number(position.lat.toFixed(6))}° </span>
<span>海拔高度:</span><span>${Number(position.alt.toFixed(2))}米</span>
`
}
else {
let result = proj.convert([{ x: position.lng, y: position.lat, z: position.alt }], 'EPSG:4326', coordinateSystem)
infoElm.innerHTML = `
<span>x</span><span>${Number(result.points[0].x.toFixed(6))}</span>
<span style="margin-left: 5px;">y</span><span>${Number(result.points[0].y.toFixed(6))}</span>
<span style="margin-left: 5px;">z</span><span>${Number(result.points[0].z.toFixed(6))}</span>
`
}
}
function cameraChanged(sdk, cb) {
let tools = new Tools()
//设置相机变化的监听事件
let removeChanged = sdk.viewer.camera.changed.addEventListener(percentage => {
cb({
position: tools.cartesian3Towgs84(sdk.viewer.camera.position, sdk.viewer),
orientation: {
heading: sdk.viewer.camera.heading,
pitch: sdk.viewer.camera.pitch,
roll: sdk.viewer.camera.roll
}
})
})
return removeChanged
}
function setMaximumRequestsPerServer(v) {
if (typeof v == 'number')
Cesium.RequestScheduler.maximumRequestsPerServer = v
}
/* 键盘事件 */
function setKeyboardEventActive(sdk, status) {
if (!sdk) {
return
}
if (status) {
sdk.viewer._disableKeyboardEvent = false
}
else {
sdk.viewer._disableKeyboardEvent = true
}
}
function getCesiumIndexedDBMaxSize() {
const baseUnit = 1024 * 1024 * 1024
let size = Number(Number(localStorage.getItem('IndexedDBMaxSize')).toFixed(0))
if (isNaN(size) || size < baseUnit) {
size = baseUnit
}
return size
}
function setCesiumIndexedDBMaxSize(v) {
const baseUnit = 1024 * 1024 * 1024
let maxSize = Number(Number(v).toFixed(0))
if (isNaN(maxSize) || maxSize < baseUnit) {
maxSize = baseUnit
}
Cesium.ManageIndexedDB && Cesium.ManageIndexedDB.SetIndexedDBMaxSize(maxSize)
localStorage.setItem('IndexedDBMaxSize', maxSize)
}
function getCesiumManageIndexexDBState() {
let state = localStorage.getItem('ManageIndexexDBState')
if (state === 'false') {
return false
}
return Boolean(state)
}
function setCesiumManageIndexexDBState(v) {
if (typeof v === "boolean") {
Cesium.ManageIndexedDB && Cesium.ManageIndexedDB.SetManageIndexexDBState(v)
localStorage.setItem('ManageIndexexDBState', v)
} else {
console.error("参数必须为boolean")
}
}
function getCesiumIndexedDBCurrentSize() {
return Cesium.ManageIndexedDB && Cesium.ManageIndexedDB.GetIndexedDBCurrentSize()
}
function setActiveViewer(v) {
setMultiViewportActiveViewer(v)
setSplitActiveViewer(v)
}
// 设置地球透明度
function enablePerspective(sdk, alpha = 1) {
if (!alpha && alpha != 0) {
alpha = 1
}
sdk.viewer.scene.globe.translucency.frontFaceAlpha = alpha
}
export { getCurrentView, setDefaultView, flyTo, CameraController, CesiumContainer, setBillboardDefaultUrl, getBillboardDefaultUrl, setGroundCover, getGroundCover, getBimPickStatus, setBimPickStatus, rotateAround, closeRotateAround, closeViewFollow, FlwStatusSwitch, JwwStatusSwitch, getFlwStatus, getJwwStatus, getCoordinateSystem, setCoordinateSystem, cameraChanged, setMaximumRequestsPerServer, setKeyboardEventActive, getTheme, setTheme, getCesiumIndexedDBMaxSize, setCesiumIndexedDBMaxSize, getCesiumManageIndexexDBState, setCesiumManageIndexexDBState, getCesiumIndexedDBCurrentSize, setActiveViewer, enablePerspective }

View File

@ -0,0 +1,218 @@
/* 右键点击菜单 */
import MouseEvent from '../../Event/index'
import Tools from '../../Tools'
import { rotateAround } from '../../Global/global'
import { getSdk } from '../SplitScreen'
let eventListener = {}
function MouseRightMenu(sdk, status, callBack) {
if (!sdk || !sdk.div_id) {
return
}
let sdkD = getSdk().sdkD
let _element = document.getElementById(sdk.div_id).getElementsByClassName('cesium-viewer')[0]
let tools = new Tools()
if (!eventListener[sdk.div_id]) {
eventListener[sdk.div_id] = {}
}
if (eventListener[sdk.div_id].mousedown) {
document.removeEventListener(
'mousedown',
eventListener[sdk.div_id].mousedown
)
}
if (eventListener[sdk.div_id].click) {
document.removeEventListener('click', eventListener[sdk.div_id].click)
}
if(!eventListener[sdk.div_id].callBack) {
eventListener[sdk.div_id].callBack = callBack
}
if(sdk !== sdkD) {
eventListener[sdk.div_id].mouseRightMenuEvent &&
eventListener[sdk.div_id].mouseRightMenuEvent.destroy()
}
let menuElm = document.getElementById('custom-menu')
if (menuElm) {
_element.removeChild(menuElm)
}
eventListener[sdk.div_id].status = status
if (status) {
eventListener[sdk.div_id].mousedown = e => {
if (
(e.target.parentNode && e.target.parentNode.id == 'custom-menu') ||
(e.target.parentNode &&
e.target.parentNode.parentNode &&
e.target.parentNode.parentNode.id == 'custom-menu')
) {
return
}
let menuElm = document.getElementById('custom-menu')
if (menuElm) {
_element.removeChild(menuElm)
}
}
document.addEventListener('mousedown', eventListener[sdk.div_id].mousedown)
eventListener[sdk.div_id].click = e => {
if (
(e.target.parentNode && e.target.parentNode.id == 'custom-menu') ||
(e.target.parentNode &&
e.target.parentNode.parentNode &&
e.target.parentNode.parentNode.id == 'custom-menu')
) {
return
}
let menuElm = document.getElementById('custom-menu')
if (menuElm) {
_element.removeChild(menuElm)
}
}
document.addEventListener('click', eventListener[sdk.div_id].click)
eventListener[sdk.div_id].mouseRightMenuEvent = new MouseEvent(sdk)
eventListener[sdk.div_id].mouseRightMenuEvent.mouse_right(
(movement, cartesian) => {
if (YJ.Measure.GetMeasureStatus() || sdk.viewer.trackedEntity) {
return
}
let entity = sdk.viewer.entities.getById('svg-control-points_0')
if (entity && entity.show) {
return
}
let menuElm = document.getElementById('custom-menu')
if (menuElm) {
_element.removeChild(menuElm)
}
let entityId = getEntityId(movement)
let targetId
if(Object.prototype.toString.call(entityId) === '[object Object]') {
targetId = entityId.id
entityId = entityId.parentId
}
let addedMenu = ''
let that = sdk.entityMap.get(entityId)
if (!that && entityId) {
let array = entityId.split('-')
array.splice(array.length - 1, 1)
entityId = array.join('-')
that = sdk.entityMap.get(entityId)
}
if (that && that.picking) {
addedMenu = `
<span class="divider" style="display: block;border-top: 1px solid #ddd;margin: 5px;"></span>
<ul class="added" style="list-style: none;padding: 0;margin: 0;font-size: 12px;">
<li style="padding: 3px 10px;cursor: pointer;">属性</li>
</ul>
`
}
let position = tools.cartesian3Towgs84(cartesian, sdk.viewer)
menuElm = document.createElement('div')
menuElm.id = 'custom-menu'
menuElm.style.position = 'absolute'
menuElm.style.width = '110px'
menuElm.style.backgroundColor = '#00000085'
menuElm.style.color = '#ffffff'
menuElm.style.padding = '6px 0'
menuElm.style.boxShadow = '4px 4px 4px 0px rgba(0, 0, 0, 0.8)'
menuElm.innerHTML = `
<ul class="base" style="list-style: none;padding: 0;margin: 0;font-size: 12px;">
<li style="padding: 3px 10px;cursor: pointer;">绕鼠标点旋转</li>
</ul>
${addedMenu}
`
_element.appendChild(menuElm)
let left = movement.position.x
let top = movement.position.y
if (
movement.position.x + menuElm.offsetWidth >
_element.offsetWidth
) {
left = movement.position.x - menuElm.offsetWidth
}
if (
movement.position.y + menuElm.offsetHeight >
_element.offsetHeight
) {
top = movement.position.y - menuElm.offsetHeight
}
menuElm.style.left = left + 'px'
menuElm.style.top = top + 'px'
menuElm.addEventListener('contextmenu', function(event) {
event.preventDefault()
})
let liElms = menuElm.getElementsByTagName('li')
let object = {}
for (let i = 0; i < liElms.length; i++) {
liElms[i].addEventListener('mouseover', () => {
liElms[i].style.backgroundColor = '#5e5e5e'
})
liElms[i].addEventListener('mouseout', () => {
liElms[i].style.backgroundColor = 'unset'
})
liElms[i].addEventListener('click', () => {
let key = ''
switch (liElms[i].innerHTML) {
case '绕鼠标点旋转':
object.position = position
key = 'rotateAround'
// this.rotateAround(position)
break
case '属性':
if(targetId) {
object.id = targetId
object.parentId = that.options.id
}
else {
object.id = that.options.id
}
key = 'attribute'
// that.edit(true)
// this.attribute(entityId)
break
}
eventListener[sdk.div_id].callBack(key, object)
_element.removeChild(menuElm)
})
}
}
)
}
function getEntityId(movement) {
let pick = sdk.viewer.scene.pick(movement.position)
if (pick) {
if (pick.id) {
if (pick.id.type && pick.id.type === 'vector' && pick.id.parentId) {
return {
parentId: pick.id.parentId,
id: pick.id.id
}
}
else if (pick.id.id) {
return pick.id.id
} else if (typeof pick.id == 'string') {
return pick.id
}
} else {
if (pick.primitive && pick.primitive.id) {
return pick.primitive.id
}
}
}
}
}
function getMouseRightMenuStatus(sdk) {
if (!sdk || !sdk.div_id || !eventListener[sdk.div_id]) {
return
}
else {
return eventListener[sdk.div_id].status
}
}
export { MouseRightMenu, getMouseRightMenuStatus }

View File

@ -0,0 +1,156 @@
/* 右键点击菜单 */
import MouseEvent from '../../Event/index'
import Tools from '../../Tools';
import { rotateAround } from '../../Global/global'
class mouseRightMenu {
constructor(sdk, cd) {
this.sdk = sdk
this.callBack = cd
this.mouseRightMenuEvent
this.tools = new Tools()
document.addEventListener('mousedown', (e)=>{
if((e.target.parentNode && e.target.parentNode.id == "custom-menu") || (e.target.parentNode && e.target.parentNode.parentNode && e.target.parentNode.parentNode.id == "custom-menu")) {
return
}
let menuElm = document.getElementById('custom-menu')
if (menuElm) {
this.sdk.viewer._element.removeChild(menuElm)
}
})
document.addEventListener('click', (e)=>{
if((e.target.parentNode && e.target.parentNode.id == "custom-menu") || (e.target.parentNode && e.target.parentNode.parentNode && e.target.parentNode.parentNode.id == "custom-menu")) {
return
}
let menuElm = document.getElementById('custom-menu')
if (menuElm) {
this.sdk.viewer._element.removeChild(menuElm)
}
})
}
open() {
this.mouseRightMenuEvent && this.mouseRightMenuEvent.destroy()
this.mouseRightMenuEvent = new MouseEvent(this.sdk)
this.mouseRightMenuEvent.mouse_right((movement, cartesian) => {
if (YJ.Measure.GetMeasureStatus()) {
return
}
let menuElm = document.getElementById('custom-menu')
if (menuElm) {
this.sdk.viewer._element.removeChild(menuElm)
}
let entityId = this.getEntityId(movement)
let addedMenu = ''
let that = this.sdk.entityMap.get(entityId)
if(!that && entityId) {
let array = entityId.split("-");
array.splice(array.length - 1, 1)
entityId = array.join('-')
that = this.sdk.entityMap.get(entityId)
}
if (that && that.picking) {
addedMenu = `
<span class="divider" style="display: block;border-top: 1px solid #ddd;margin: 5px;"></span>
<ul class="added" style="list-style: none;padding: 0;margin: 0;font-size: 12px;">
<li style="padding: 3px 10px;cursor: pointer;">属性</li>
</ul>
`
}
let position = this.tools.cartesian3Towgs84(cartesian, this.sdk.viewer)
menuElm = document.createElement('div');
menuElm.id = 'custom-menu'
menuElm.style.position = 'absolute'
menuElm.style.width = '110px'
menuElm.style.backgroundColor = '#00000085'
menuElm.style.color = '#ffffff'
menuElm.style.padding = '6px 0'
menuElm.style.boxShadow = '4px 4px 4px 0px rgba(0, 0, 0, 0.8)'
menuElm.innerHTML = `
<ul class="base" style="list-style: none;padding: 0;margin: 0;font-size: 12px;">
<li style="padding: 3px 10px;cursor: pointer;">绕鼠标点旋转</li>
</ul>
${addedMenu}
`
this.sdk.viewer._element.appendChild(menuElm)
let left = movement.position.x
let top = movement.position.y
if ((movement.position.x + menuElm.offsetWidth) > this.sdk.viewer._element.offsetWidth) {
left = movement.position.x - menuElm.offsetWidth
}
if ((movement.position.y + menuElm.offsetHeight) > this.sdk.viewer._element.offsetHeight) {
top = movement.position.y - menuElm.offsetHeight
}
menuElm.style.left = left + 'px'
menuElm.style.top = top + 'px'
menuElm.addEventListener('contextmenu', function (event) {
event.preventDefault();
})
let liElms = menuElm.getElementsByTagName('li')
let object = {}
for (let i = 0; i < liElms.length; i++) {
liElms[i].addEventListener('mouseover', () => {
liElms[i].style.backgroundColor = '#5e5e5e'
})
liElms[i].addEventListener('mouseout', () => {
liElms[i].style.backgroundColor = 'unset'
})
liElms[i].addEventListener('click', () => {
switch (liElms[i].innerHTML) {
case '绕中心点旋转':
object.position = position
// this.rotateAround(position)
break
case '属性':
object.id = that.options.id
// that.edit(true)
// this.attribute(entityId)
break
}
this.callBack(liElms[i].innerHTML, object)
this.sdk.viewer._element.removeChild(menuElm)
})
}
})
}
getEntityId(movement) {
let pick = this.sdk.viewer.scene.pick(movement.position)
if (pick) {
if (pick.id) {
if (pick.id.id) {
return pick.id.id
}
else if (typeof pick.id == 'string') {
return pick.id
}
}
else {
if (pick.primitive && pick.primitive.id) {
return pick.primitive.id
}
}
}
}
rotateAround(position) {
rotateAround(this.sdk, position)
}
attribute(entityId) {
if(entityId.endsWith('-label')) {
entityId = entityId.replace('-label', '')
}
let that = this.sdk.entityMap.get(entityId)
that && that.edit(true)
}
close() {
this.mouseRightMenuEvent && this.mouseRightMenuEvent.destroy()
}
}
export default mouseRightMenu

397
src/In/index.js Normal file
View File

@ -0,0 +1,397 @@
import { on } from '../on'
import YJEarth from '../YJEarth'
import {
getCurrentView,
setDefaultView,
flyTo,
CameraController,
CesiumContainer,
setBillboardDefaultUrl,
getBillboardDefaultUrl,
setGroundCover,
getGroundCover,
setBimPickStatus,
getBimPickStatus,
FlwStatusSwitch,
JwwStatusSwitch,
rotateAround,
getCoordinateSystem,
setCoordinateSystem,
cameraChanged,
setMaximumRequestsPerServer,
setKeyboardEventActive,
getTheme,
setTheme,
getCesiumManageIndexexDBState,
setCesiumManageIndexexDBState,
getCesiumIndexedDBMaxSize,
setCesiumIndexedDBMaxSize,
getCesiumIndexedDBCurrentSize,
enablePerspective,
closeRotateAround
} from '../Global/global'
import { SheetIndexStatusSwitch, changeScale as SheetIndexShangeScale } from '../Global/SheetIndex'
import { switchCluster } from '../Global/cluster/cluster'
import DTH from '../Global/DTH'
import {
closeLeftClick,
openLeftClick,
closeRightClick,
openRightClick,
openMove,
closeMove
} from '../Global/ClickCallback'
import { startScreenRecord, stopScreenRecord } from '../Global/ScreenRecord'
import { ScreenShot, ScreenShotHD } from '../Global/ScreenShot'
import ExportKml from '../Global/ExportKml'
import { setSkin } from '../Global/Skin'
import {
open as FlyRoamOpen,
close as FlyRoamClose,
flyTo as FlyRoamFlyTo,
setRepeat as FlyRoamSetRepeat,
cease as FlyRoamCease
} from '../Global/FlyRoam'
import {
rain,
snow,
fog,
nightVision,
skyStarry,
illumination
} from '../Global/efflect'
import { open as mapxOpen, close as mapxClose } from '../Global/MapX'
import {
on as multiViewportModeOn,
off as multiViewportModeOff,
get2DView
} from '../Global/MultiViewportMode'
import { MouseCoordinate } from '../Global/MouseCoordinate'
import { MouseRightMenu } from '../Global/mouseRightMenu'
import { dialog as ContourDialog } from '../Global/Contour'
import { on as SplitScreenOn, off as SplitScreenOff, setActiveId as SplitScreenSetActiveId } from '../Global/SplitScreen'
import LocateCurrent from '../Obj/Base/LocateCurrent'
import { Clear as AnalysisClear } from '../Obj/Analysis/clear'
import CutFillAnalysis from '../Obj/Analysis/CutFill'
import Submerge from '../Obj/Analysis/Submerge'
import ViewShed from '../Obj/Analysis/ViewShed'
import CircleViewShed from '../Obj/Analysis/CircleViewShed'
// import Test2 from '../Obj/Analysis/test2'
import SlopeAspect from '../Obj/Analysis/SlopeAspect'
import Profile from '../Obj/Analysis/Profile'
import Visibility from '../Obj/Analysis/Visibility'
import Contour from '../Obj/Analysis/Contour'
import Section from '../Obj/Analysis/Section'
import TerrainExcavation from '../Obj/Analysis/TerrainExcavation'
import Flat from '../Obj/Analysis/Flat'
import MeasureDistance from '../Measure/MeasureDistance'
import MeasureProjectionDistance from '../Measure/MeasureProjectionDistance'
import MeasureSlopeDistance from '../Measure/MeasureSlopeDistance'
import { Clear } from '../Measure/clear'
import MeasureTyArea from '../Measure/MeasureTyArea'
import MeasureTdArea from '../Measure/MeasureTdArea'
import MeasureTriangle from '../Measure/MeasureTriangle'
import MeasureLocation from '../Measure/MeasureLocation'
import MeasureHeight from '../Measure/MeasureHeight'
import MeasureAngle from '../Measure/MeasureAngle'
import MeasureAzimuth from '../Measure/MeasureAzimuth'
import DrawPolyline from '../Draw/drawPolyline'
import DrawPolygon from '../Draw/drawPolygon'
import DrawPoint from '../Draw/drawPoint'
import DrawCircle from '../Draw/drawCircle'
import DrawElliptic from '../Draw/drawElliptic'
import DrawAttackArrow from '../Draw/drawAttackArrow'
import DrawPincerArrow from '../Draw/drawPincerArrow'
import DrawStraightArrow from '../Draw/drawStraightArrow'
import DrawRect from '../Draw/drawRect'
import DrawAssemble from '../Draw/drawAssemble'
import DrawSector from '../Draw/drawSector'
import {
ArcgisBLUEImagery,
ArcgisLWImagery,
ArcgisWXImagery
} from '../Obj/Base/BaseSource/BaseLayer/ArcgisImagery'
import {
GDLWImagery,
GDSLImagery,
GDWXImagery
} from '../Obj/Base/BaseSource/BaseLayer/GdImagery'
import Tileset from '../Obj/Base/BaseSource/BaseTileset/Tileset'
import BIM from '../Obj/Base/BaseSource/BaseTileset/BIM'
import Model from '../Obj/Base/BaseSource/BaseModel/Model'
import Model2 from '../Obj/Base/BaseSource/BaseModel/Model2'
import Layer from '../Obj/Base/BaseSource/BaseLayer/Layer'
import Layer3rdparty from '../Obj/Base/BaseSource/BaseLayer/Layer3rdparty'
import Terrain from '../Obj/Base/BaseSource/BaseTerrain'
import Flame from '../Obj/Base/ParticleEffects/Flame'
import Smoke from '../Obj/Base/ParticleEffects/Smoke'
import Fountain from '../Obj/Base/ParticleEffects/Fountain'
import Spout from '../Obj/Base/ParticleEffects/Spout'
import PolygonObject from '../Obj/Base/PolygonObject'
import PolyhedronObject from '../Obj/Base/PolyhedronObject'
// import PolyhedronObject2 from '../Obj/Base/PolyhedronObject2'
import AssembleObject from '../Obj/Base/AssembleObject'
import AttackArrowObject from '../Obj/Base/AttackArrowObject'
import PincerArrowObject from '../Obj/Base/PincerArrowObject'
import StraightArrowObject from '../Obj/Base/StraightArrowObject'
import CircleDiffuse from '../Obj/Base/CircleDiffuse'
import CircleObject from '../Obj/Base/CircleObject'
import EllipseObject from '../Obj/Base/EllipseObject'
import WallStereoscopic from '../Obj/Base/WallStereoscopic'
import WallRealStereoscopic from '../Obj/Base/WallRealStereoscopic'
// import Corridor from '../Obj/Base/Corridor'
import BillboardObject from '../Obj/Base/BillboardObject'
import PolylineObject from '../Obj/Base/PolylineObject'
import CurvelineObject from '../Obj/Base/CurvelineObject'
// import EllipseObject from '../Obj/Base/EllipseObject'
import Explosion from '../Obj/Base/Explosion'
import RadarScan from '../Obj/Base/RadarScan'
import RadarScanStereoscopic from '../Obj/Base/RadarScanStereoscopic'
import SectorObject from '../Obj/Base/SectorObject'
import KML from '../Obj/Base/KML'
import GeoJson from '../Obj/Base/GeoJson'
import WaterSurface from '../Obj/Base/WaterSurface'
// import ItineraryMove from '../Obj/Base/ItineraryMove'
import TrajectoryMotion from '../Obj/Base/TrajectoryMotion'
import TrajectoryMotionObject from '../Obj/Base/TrajectoryMotionObject'
import Road from '../Obj/Base/Road'
import Graffiti from '../Obj/Base/Graffiti'
import GroundImage from '../Obj/Base/GroundImage'
import GroundSvg from '../Obj/Base/GroundSvg'
import RoutePlanning from '../Obj/Base/RoutePlanning'
import Shp from '../Obj/Base/Shp'
import Vector from '../Obj/Base/Vector'
// import Text3D from "../Obj/Base/TextObject/3DText";
import GroundText from '../Obj/Base/TextObject/GroundText'
import StandText from '../Obj/Base/TextObject/StandText'
import { Clear as ClearAllRoutePlanning } from '../Obj/Base/RoutePlanning/clear'
import RichText from '../Obj/Element/richText'
import Tools from '../Tools'
import { Proj } from '../Tools/proj'
import CoordTransform from '../transform/CoordTransform'
import LoadObjModel from '../Obj/Base/LoadObjModel'
import DZXJLoadObjModel from '../DZ/XJ/LoadObjModel'
import BatchLoadObjModel from '../DZ/XJ/BatchLoadObjModel'
import Heatmap from '../Obj/Base/Heatmap'
import FlyRoam from '../Obj/Base/FlyRoam'
import Dialog from '../Obj/Element/Dialog'
// import AirLine from '../Obj/AirLine'
// import GenerateRoute from '../Obj/AirLine/GenerateRoute'
import newAirLine from '../Obj/AirLine/pointRoute.js'
import Frustum from '../Obj/AirLine/frustum'
import DrawTakeOff from '../Obj/AirLine/DrawTakeOff'
const YJEarthismeasuring = Symbol('测量状态')
const screenRecord = Symbol('录屏对象')
if (!window.YJ) {
window.YJ = {
on,
Obj: {
ArcgisWXImagery,
ArcgisBLUEImagery,
ArcgisLWImagery,
GDLWImagery,
GDWXImagery,
GDSLImagery,
Tileset,
BIM,
Layer,
Layer3rdparty,
Terrain,
Flame,
Smoke,
Fountain,
Spout,
WaterSurface,
CircleDiffuse,
CircleObject,
EllipseObject,
RadarScan,
RadarScanStereoscopic,
SectorObject,
WallStereoscopic,
WallRealStereoscopic,
KML,
GeoJson,
// ItineraryMove,
BillboardObject,
PolygonObject,
PolyhedronObject,
// PolyhedronObject2,
AssembleObject,
AttackArrowObject,
PincerArrowObject,
StraightArrowObject,
// Corridor,
PolylineObject,
CurvelineObject,
// EllipseObject,
Explosion,
Model,
Model2,
TrajectoryMotion,
TrajectoryMotionObject,
Road,
Graffiti,
GroundImage,
GroundSvg,
RoutePlanning,
Shp,
Vector,
// Text3D,
GroundText,
StandText,
RichText,
LocateCurrent,
LoadObjModel,
Heatmap,
FlyRoam,
// AirLine,
newAirLine,
FRUSTUN: Frustum,
// GenerateRoute
Dialog
},
YJEarth,
Tools,
Proj,
Global: {
getCurrentView,
setDefaultView,
switchCluster,
openLeftClick,
closeLeftClick,
closeRightClick,
openRightClick,
openMove,
closeMove,
ScreenRecord: {
start: () => {
return startScreenRecord(screenRecord)
},
stop: () => {
return stopScreenRecord()
},
screenRecord: null
},
MapX: {
open: mapxOpen,
close: mapxClose
},
ScreenShot,
ScreenShotHD,
ExportKml,
FlyRoam: {
open: FlyRoamOpen,
close: FlyRoamClose,
flyTo: FlyRoamFlyTo,
setRepeat: FlyRoamSetRepeat,
cease: FlyRoamCease
},
flyTo,
efflect: { rain, snow, fog, nightVision, skyStarry, illumination },
CameraController,
CesiumContainer,
setBillboardDefaultUrl,
getBillboardDefaultUrl,
multiViewportMode: {
on: multiViewportModeOn,
off: multiViewportModeOff,
get2DView
},
MouseCoordinate,
MouseRightMenu,
setGroundCover,
getGroundCover,
setBimPickStatus,
getBimPickStatus,
FlwStatusSwitch,
JwwStatusSwitch,
rotateAround,
getCoordinateSystem,
setCoordinateSystem,
DTH,
cameraChanged,
setMaximumRequestsPerServer,
setKeyboardEventActive,
setSkin,
getTheme,
setTheme,
getCesiumManageIndexexDBState,
setCesiumManageIndexexDBState,
getCesiumIndexedDBMaxSize,
setCesiumIndexedDBMaxSize,
getCesiumIndexedDBCurrentSize,
enablePerspective,
closeRotateAround,
SheetIndexStatusSwitch,
SheetIndexShangeScale,
splitScreen: {
on: SplitScreenOn,
off: SplitScreenOff,
setActiveId: SplitScreenSetActiveId
},
Contour: ContourDialog
}, //测量
Measure: {
GetMeasureStatus: () => {
return YJ.Measure[YJEarthismeasuring]
},
SetMeasureStatus: (status = false) => {
YJ.Measure[YJEarthismeasuring] = status
},
Clear,
Measures: [],
MeasureDistance,
MeasureProjectionDistance,
MeasureSlopeDistance,
MeasureTyArea,
MeasureTdArea,
MeasureTriangle,
MeasureLocation,
MeasureHeight,
MeasureAngle,
MeasureAzimuth
},
Draw: {
DrawPolyline,
DrawPolygon,
DrawPoint,
DrawCircle,
DrawElliptic,
DrawAttackArrow,
DrawPincerArrow,
DrawStraightArrow,
DrawRect,
DrawAssemble,
DrawSector,
DrawTakeOff,
},
// 分析
Analysis: {
Clear: AnalysisClear,
CutFillAnalysis,
Submerge,
ViewShed,
CircleViewShed,
// Test2,
SlopeAspect,
Profile,
Visibility,
Contour,
Section,
TerrainExcavation,
Flat,
Analyses: []
},
CoordTransform,
RoutePlanningArrays: [],
ClearAllRoutePlanning
}
if (process.env.DZ === 'xj') {
window.YJ.Obj.LoadObjModel = DZXJLoadObjModel
window.YJ.Obj.BatchLoadObjModel = BatchLoadObjModel
}
}

View File

@ -0,0 +1,209 @@
/**
* @name: index
* @author: Administrator
* @date: 2023-12-29 10:11
* @descriptionindex
* @update: 2023-12-29 10:11
*/
import Measure from "../index";
class MeasureAngle extends Measure {
constructor(sdk) {
super(sdk, { text: "左键开始,右键取消" });
this.cachePositions = []
this.positions = []
this.arcPositions = []
this.line_id = ""
this.label_id = ""
this.arc_id = ""
this.bearing = 0
}
createPolyline() {
let that = this
let id = that.randomString()
that.viewer.entities.add(new Cesium.Entity({
id,
polyline: {
positions: new Cesium.CallbackProperty(() => {
return that.positions
}, false),
clampToGround: true,
width: 5,
material: new Cesium.Color.fromCssColorString(that.options.color || that.defaultColor),
zIndex: 99999999
}
}))
return id
}
end() {
super.end();
}
destroy() {
super.destroy();
let arr = [this.line_id, this.label_id, this.arc_id]
arr.forEach(id => {
if (id)
this.remove_entity(id)
})
}
cancel() {
this.end()
this.destroy()
}
caculateAngle(points = []) {
let p1 = this.cartesian3Towgs84(points[0], this.viewer)
let p2 = this.cartesian3Towgs84(points[1], this.viewer)
let p3 = this.cartesian3Towgs84(points[2], this.viewer)
let point1 = turf.point([p1.lng, p1.lat]);
let point2 = turf.point([p2.lng, p2.lat]);
let point3 = turf.point([p3.lng, p3.lat]);
let options = { units: 'kilometers' };
let distance1 = turf.rhumbDistance(point1, point2, options);
let distance2 = turf.rhumbDistance(point3, point2, options);
let distance = distance1
if (distance1 > distance2) {
distance = distance2
}
let bearing1 = turf.rhumbBearing(point1, point2)
let bearing2 = turf.rhumbBearing(point3, point2)
let bearing = Math.abs(((bearing1 - bearing2) + 360) % 360)
if (bearing > 180) {
this.bearing = 360 - bearing
} else {
this.bearing = bearing
}
this.bearing = this.bearing.toFixed(2)
let b1 = (bearing1 - 180)
let b2 = (bearing2 - 180)
let arc = turf.lineArc(point2, (distance / 3), b2, b1);
if (bearing > 180) {
arc = turf.lineArc(point2, (distance / 3), b1, b2);
}
let arcPos = []
for (let i = 0; i < arc.geometry.coordinates.length; i++) {
arcPos.push(Cesium.Cartesian3.fromDegrees(arc.geometry.coordinates[i][0], arc.geometry.coordinates[i][1]))
}
this.arcPositions = arcPos
// if (bearing1 > 0 && bearing2 > 0) {
// this.bearing = Math.abs(bearing1 - bearing2).toFixed(1)
// } else if (bearing1 < 0 && bearing2 < 0) {
// this.bearing = Math.abs(bearing1 - bearing2).toFixed(1)
// } else if (bearing1 > 0 && bearing2 < 0) {
// this.bearing = Math.abs(360 - Math.abs(bearing2) - bearing1).toFixed(1)
// } else {
// this.bearing = Math.abs(360 - Math.abs(bearing1) - bearing2).toFixed(1)
// }
}
start() {
if (!YJ.Measure.GetMeasureStatus()) {
super.start();
let leftEvent = (movement, car) => {
if (this.ids.length === 0) {
//需要创建一个线
this.line_id = this.createPolyline()
}
this.ids.push(this.create_point(car))
this.tip.setPosition(car, movement.position.x, movement.position.y)
this.cachePositions.push(car)
if (this.cachePositions.length) {
this.positions = this.cachePositions.concat(car)
}
if (this.ids.length === 2) {
this.label_id = Cesium.createGuid()
this.arc_id = Cesium.createGuid()
let p = this.cartesian3Towgs84(car, this.viewer)
this.sampleHeightMostDetailed([p]).then((res) => {
let arc = this.viewer.entities.add({
id: this.arc_id,
polyline: {
positions: new Cesium.CallbackProperty(() => {
return this.arcPositions
}, false),
clampToGround: true,
width: 5,
material: new Cesium.Color.fromCssColorString(this.options.color || this.defaultColor),
zIndex: 99999999
}
})
let label = this.viewer.entities.add({
id: this.label_id,
position: Cesium.Cartesian3.fromDegrees(p.lng, p.lat, (res[0].height || 0) + 0.1),
label: {
text: new Cesium.CallbackProperty(() => {
return "夹角:" + this.bearing + "°"
}, false),
font: '20px Microsoft YaHei',
fillColor: Cesium.Color.fromCssColorString('#f1e605'),
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
//标注的遮挡距离设置为100则视角与标注的距离大于100米时会有遮挡
// distanceDisplayCondition: this.distanceDisplayCondition,
scale: 1,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
disableDepthTestDistance: Number.POSITIVE_INFINITY,
}
})
})
}
if (this.ids.length === 3) {
this.caculateAngle([this.positions[0], this.positions[1], this.positions[2]])
//需要停止绘制
this.end()
}
}
this.event.mouse_left(leftEvent)
this.event.mouse_move((movement, car) => {
this.tip.setPosition(car, movement.endPosition.x, movement.endPosition.y)
if (this.cachePositions.length) {
this.positions = this.cachePositions.concat(car)
}
if (this.positions.length > 2) {
//需要开始计算夹角
this.caculateAngle([this.positions[0], this.positions[1], this.positions[2]])
}
})
this.event.mouse_right((movement, car) => {
this.cancel()
})
this.event.gesture_pinck_start((movement, cartesian) => {
let startTime = new Date()
let pos = {
position: {
x: (movement.position1.x + movement.position2.x) / 2,
y: (movement.position1.y + movement.position2.y) / 2
}
}
this.event.gesture_pinck_end(() => {
let endTime = new Date()
if (endTime - startTime >= 500) {
// 长按取消
this.cancel()
}
else {
leftEvent(pos, cartesian)
}
})
})
}
}
}
export default MeasureAngle

View File

@ -0,0 +1,206 @@
import Measure from "../index";
class MeasureAzimuth extends Measure {
/**
* @constructor
* @param sdk
* @description 方位角测量
* */
constructor(sdk) {
super(sdk, { text: "左键开始,右键取消" });
this.cachePositions = []
this.positions = []
this.arcPositions = []
this.line_id = ""
this.label_id = ""
this.arc_id = ""
this.bearing = 0
}
createPolyline() {
let that = this
let id = that.randomString()
that.viewer.entities.add(new Cesium.Entity({
id,
polyline: {
positions: new Cesium.CallbackProperty(() => {
return that.positions
}, false),
clampToGround: true,
width: 5,
material: new Cesium.Color.fromCssColorString(that.options.color || that.defaultColor),
zIndex: 99999999
}
}))
return id
}
end() {
super.end();
}
destroy() {
super.destroy();
let arr = [this.line_id, this.label_id, this.arc_id]
arr.forEach(id => {
if (id)
this.remove_entity(id)
})
}
cancel() {
this.end()
this.destroy()
}
caculateAngle(line1 = [], line2 = []) {
let c = this.cartesian3Towgs84(line2[1], this.viewer)
let p2 = this.cartesian3Towgs84(line2[0], this.viewer)
let center = turf.point([c.lng, c.lat])
let point2 = turf.point([p2.lng, p2.lat])
let bearing = this.rhumbBearing(p2, c)
this.bearing = (180 + bearing).toFixed(2)
let distance = turf.rhumbDistance(center, point2, { units: 'kilometers' });
let arc = turf.lineArc(center, (distance/3), 0, this.bearing);
let arcPos = []
for (let i = 0; i < arc.geometry.coordinates.length; i++) {
arcPos.push(Cesium.Cartesian3.fromDegrees(arc.geometry.coordinates[i][0], arc.geometry.coordinates[i][1]))
}
this.arcPositions = arcPos
}
start() {
if (!YJ.Measure.GetMeasureStatus()) {
super.start();
let leftEvent = async (movement, car) => {
if (this.ids.length === 0) {
//需要创建一个线
this.line_id = this.createPolyline()
}
this.tip.setPosition(car, movement.position.x, movement.position.y)
if (this.cachePositions.length) {
this.positions = this.cachePositions.concat(car)
let p = this.cartesian3Towgs84(car, this.viewer)
let pc = this.cartesian3Towgs84(this.positions[1], this.viewer)
let from = turf.point([pc.lng, pc.lat]);
let to = turf.point([p.lng, p.lat]);
let options = { units: 'kilometers' };
let distance = turf.rhumbDistance(from, to, options);
let bearing = 0;
let destination = turf.destination(from, distance, bearing, options);
this.positions[0] = Cesium.Cartesian3.fromDegrees(...destination.geometry.coordinates)
}
this.cachePositions.push(car)
this.cachePositions.push(car)
if (this.positions.length > 2) {
//需要开始计算夹角
this.caculateAngle(
[this.positions[0], this.positions[1]],
[this.positions[2], this.positions[1]])
}
if (this.ids.length >= 2) {
//需要停止绘制
this.end()
return
}
this.ids.push(this.create_point(car))
this.ids.push(this.create_point(car))
if (this.ids.length === 2) {
this.label_id = Cesium.createGuid()
this.arc_id = Cesium.createGuid()
let p = this.cartesian3Towgs84(car, this.viewer)
let res = await this.sampleHeightMostDetailed([p])
let arc = this.viewer.entities.add({
id: this.arc_id,
polyline: {
positions: new Cesium.CallbackProperty(() => {
return this.arcPositions
}, false),
clampToGround: true,
width: 5,
material: new Cesium.Color.fromCssColorString(this.options.color || this.defaultColor),
zIndex: 99999999
}
})
let label = this.viewer.entities.add({
id: this.label_id,
position: Cesium.Cartesian3.fromDegrees(p.lng, p.lat, (res[0].height || 0) + 0.1),
label: {
text: new Cesium.CallbackProperty(() => {
return "方位夹角:" + this.bearing + "°"
}, false),
font: '20px Microsoft YaHei',
fillColor: Cesium.Color.fromCssColorString('#f1e605'),
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
//标注的遮挡距离设置为100则视角与标注的距离大于100米时会有遮挡
// distanceDisplayCondition: this.distanceDisplayCondition,
scale: 1,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
disableDepthTestDistance: Number.POSITIVE_INFINITY,
}
})
//需要创建夹角的显示效果
}
}
this.event.mouse_left(leftEvent)
this.event.mouse_move((movement, car) => {
this.tip.setPosition(car, movement.endPosition.x, movement.endPosition.y)
if (this.cachePositions.length) {
this.positions = this.cachePositions.concat(car)
let p = this.cartesian3Towgs84(car, this.viewer)
let pc = this.cartesian3Towgs84(this.positions[1], this.viewer)
let from = turf.point([pc.lng, pc.lat]);
let to = turf.point([p.lng, p.lat]);
let options = { units: 'kilometers' };
let distance = turf.rhumbDistance(from, to, options);
let bearing = 0;
let destination = turf.destination(from, distance, bearing, options);
this.positions[0] = Cesium.Cartesian3.fromDegrees(...destination.geometry.coordinates)
}
if (this.positions.length > 2) {
//需要开始计算夹角
this.caculateAngle(
[this.positions[0], this.positions[1]],
[this.positions[2], this.positions[1]])
}
})
this.event.mouse_right((movement, car) => {
this.cancel()
})
this.event.gesture_pinck_start((movement, cartesian) => {
let startTime = new Date()
let pos = {
position: {
x: (movement.position1.x + movement.position2.x) / 2,
y: (movement.position1.y + movement.position2.y) / 2
}
}
this.event.gesture_pinck_end(() => {
let endTime = new Date()
if (endTime - startTime >= 500) {
// 长按取消
this.cancel()
}
else {
leftEvent(pos, cartesian)
}
})
})
}
}
}
export default MeasureAzimuth

View File

@ -0,0 +1,18 @@
import Measure from '../index'
/**@extends Measure*/
class MeasureCircle extends Measure {
constructor(sdk, options = {}) {
super(sdk, options)
}
start() {
super.start();
}
end() {
super.end();
}
}
export default MeasureCircle

View File

@ -0,0 +1,326 @@
/**
* @name: index
* @author: Administrator
* @date: 2022-07-11 10:31
* @descriptionindex
* @update: 2022-07-11 10:31
*/
import Measure from "../index"
class MeasureDistance extends Measure {
/**
* @constructor
* @param sdk
* @description 距离测量
* */
constructor(sdk, options = {}) {
super(sdk, options)
this.options.color = this.options.color || "#00ffff"
this.start_id = ""
this.end_id = ""
this.polyline_id = ""
this.clampPositions = []
}
async clampToGroundMeasure(meters, cb) {
let positions = []
this.ids.forEach((id, index) => {
let p = this.viewer.entities.getById(id).position.getValue()
positions.push(this.cartesian3Towgs84(p, this.viewer))
})
let res = this.chunkLine(positions, meters)
let coordinates = []
res.forEach((Feature, index) => {
if (index === 0) {
coordinates = [...Feature.geometry.coordinates]
} else {
coordinates.push(Feature.geometry.coordinates[1])
}
})
let total = coordinates.length
for (const item of coordinates) {
const index = coordinates.indexOf(item);
let r = await this.getHeight({lng: item[0], lat: item[1], alt: 0}, index, total,)
cb(null, r)
}
}
async computeDisByTowPoint(p1, p2) {
let d = this.computeDistance([p1, p2])
let meters = 10
let createLabel = (distance) => {
if(this._isDestroy) {
return
}
let label = this.getLabel("贴地距离:" + Number(distance).toFixed(2) + "米")
label.pixelOffset = new Cesium.Cartesian2(
0, -(32)
)
this.ids.push(MeasureDistance.create_point(Cesium.Cartesian3.fromDegrees(p2.lng, p2.lat, p2.alt), {label: label}, this))
}
let start = async (meters) => {
let res = this.chunkLine([p1, p2], meters)
let coordinates = []
res.forEach((Feature, index) => {
if (index === 0) {
coordinates = [...Feature.geometry.coordinates]
} else {
coordinates.push(Feature.geometry.coordinates[1])
}
})
let arr = []
for (const item of coordinates) {
const index = coordinates.indexOf(item);
let r = await this.sampleHeight({lng: item[0], lat: item[1], alt: 0}, index)
arr.push(r)
}
let total_length = 0
let l = arr.length - 1
arr.forEach((item, index) => {
if (index !== l) {
let d1 = this.computeDistance([item.position, arr[index + 1].position])
let d2 = Math.abs(item.position.alt - arr[index + 1].position.alt)
let d3 = Math.sqrt(d1 * d1 + d2 * d2)
total_length += d3
}
})
createLabel(total_length)
}
//暂时固定取20个点
if (d > 20) {//大于20m时固定取20个点
meters = d / 20
await start(meters)
} else if (d < 1) {
//不计算
createLabel(d)
} else {//小于20m的时候
meters = 1
await start(meters)
}
}
async sampleHeight(p1, index) {
let p2 = await this.sampleHeightMostDetailed([p1])
p1.alt = p2[0].height
return {position: p1, index}
}
async getHeight(p1, index, total) {
let p2 = await this.sampleHeightMostDetailed([p1])
p1.alt = p2[0].height
this.clampPositions.push({position: p1, index})
if (total === this.clampPositions.length) {
let total_length = this.startCompute()
return {total, current: this.clampPositions.length, total_length}
}
return {total, current: this.clampPositions.length,}
}
startCompute() {
this.clampPositions.sort(function (a, b) {
return a.index < b.index
})
let total_length = 0
let l = this.clampPositions.length - 1
this.clampPositions.forEach((item, index) => {
if (index !== l) {
let d1 = this.computeDistance([item.position, this.clampPositions[index + 1].position])
let d2 = Math.abs(item.position.alt - this.clampPositions[index + 1].position.alt)
let d3 = Math.sqrt(d1 * d1 + d2 * d2)
total_length += d3
}
})
return Number(total_length.toFixed(2))
}
static createPolyline(that) {
let id = that.randomString()
that.viewer.entities.add(new Cesium.Entity({
id,
polyline: {
positions: new Cesium.CallbackProperty(() => {
return that.positions
}, false),
clampToGround: true,
width: 3,
material: new Cesium.PolylineDashMaterialProperty({
color: new Cesium.Color.fromCssColorString(that.options.color || that.defaultColor),
dashLength: 20, //短划线长度
}),
zIndex: 99999999
}
}))
return id
}
static create_point(cartesian, {
label, image = "point.png",
width,
height
}, that) {
let id = that.randomString()
let p = that.cartesian3Towgs84(cartesian, that.viewer)
if (label) {
label.pixelOffset = new Cesium.Cartesian2(
0, -(height || 32)
)
}
that.viewer.entities.add(
new Cesium.Entity({
id: id,
label,
position: Cesium.Cartesian3.fromDegrees(p.lng, p.lat, p.alt),
billboard: {
image: that.getSourceRootPath() + '/img/' + image,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
disableDepthTestDistance: Number.POSITIVE_INFINITY,
width,
height
}
})
)
return id
}
getLabel(text) {
return {
text: text || '',
//标注文字描述
font: '20px Microsoft YaHei',
fillColor: Cesium.Color.fromCssColorString('#f1e605'),
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
//标注的遮挡距离设置为100则视角与标注的距离大于100米时会有遮挡
// distanceDisplayCondition: this.distanceDisplayCondition,
scale: 1,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
disableDepthTestDistance: Number.POSITIVE_INFINITY,
// disableDepthTestDistance: this.disableDepthTestDistance,
}
}
/**
* 开始测量
*/
start() {
if (!YJ.Measure.GetMeasureStatus()) {
super.start()
this.positions = []
this.cachePositions = []
let leftEvent = async (movement, car) => {
if (this.ids.length === 0) {
this.polyline_id = (MeasureDistance.createPolyline(this))
this.start_id = MeasureDistance.create_point(car, {
image: "start1.png", width: 30, height: 38, label: this.getLabel("")
}, this)
//创建起点
}
this.tip.setPosition(car, movement.position.x, movement.position.y)
this.positions = this.cachePositions.concat(car)
if (this.ids.length !== 0) {
let cur_point = this.cartesian3Towgs84(car, this.viewer)
let pre_p = this.cartesian3Towgs84(this.cachePositions[this.cachePositions.length - 1], this.viewer)
this.cachePositions.push(car)
await this.computeDisByTowPoint(pre_p, cur_point)
} else {
this.cachePositions.push(car)
this.ids.push(MeasureDistance.create_point(car, {}, this))
let startPoint = this.viewer.entities.getById(this.ids[0])
if(startPoint) {
startPoint.billboard.show = false
}
}
}
let rightEvent = (movement, car) => {
if (this.cachePositions.length) {
this.positions = this.cachePositions
this.end_id = MeasureDistance.create_point(this.cachePositions[this.cachePositions.length - 1], {
image: "end1.png",
width: 30,
height: 38,
}, this)
let endPoint = this.viewer.entities.getById(this.ids[this.ids.length-1])
if(endPoint) {
endPoint.billboard.show = false
}
}
if (this.cachePositions.length < 2) {
this.destroy()
YJ.Measure.Measures.pop()//弹出测量实体
}
this.end()
}
this.event.mouse_left(leftEvent)
this.event.mouse_move((movement, car) => {
this.tip.setPosition(car, movement.endPosition.x, movement.endPosition.y)
this.positions = this.cachePositions.concat(car)
// if (this.cachePositions.length) {
// let cur_point = this.cartesian3Towgs84(car, this.viewer)
// let pre_p = this.cartesian3Towgs84(this.cachePositions[this.cachePositions.length - 1], this.viewer)
// let cur_len = this.computeDistance([cur_point, pre_p])
// let text = "当前投影距离:" + cur_len + " 米"
// // this.tip.set_text(text)
// }
})
this.event.mouse_right(rightEvent)
this.event.gesture_pinck_start((movement, cartesian) => {
let startTime = new Date()
let pos = {
position: {
x: (movement.position1.x + movement.position2.x) / 2,
y: (movement.position1.y + movement.position2.y) / 2
}
}
this.event.gesture_pinck_end(() => {
let endTime = new Date()
if (endTime - startTime >= 500) {
// 长按取消
rightEvent(pos, cartesian)
}
else {
leftEvent(pos, cartesian)
}
})
})
}
}
/**
* 清除测量
*/
destroy() {
[this.polyline_id, this.end_id, this.start_id, ...this.ids].forEach(id => {
this.remove_entity(id)
})
super.destroy()
}
/**
* 结束测量
*/
end() {
// YJ.Measure.SetMeasureStatus(false)
// this.tip.destroy()
// this.event.destroy()
super.end()
// this.setPickStatus(this.pickStatus.pick)
}
}
export default MeasureDistance

View File

@ -0,0 +1,327 @@
/**
* @name: index
* @author: Administrator
* @date: 2022-07-11 10:31
* @descriptionindex
* @update: 2022-07-11 10:31
*/
import Measure from "../index"
class MeasureDistance extends Measure {
/**
* @constructor
* @param sdk
* @description 距离测量
* */
constructor(sdk, options = {}) {
super(sdk, options)
this.start_id = ""
this.end_id = ""
this.polyline_id = ""
this.clampPositions = []
}
async clampToGroundMeasure(meters, cb) {
let positions = []
this.ids.forEach((id, index) => {
let p = this.viewer.entities.getById(id).position.getValue()
positions.push(this.cartesian3Towgs84(p, this.viewer))
})
let res = this.chunkLine(positions, meters)
let coordinates = []
res.forEach((Feature, index) => {
if (index === 0) {
coordinates = [...Feature.geometry.coordinates]
} else {
coordinates.push(Feature.geometry.coordinates[1])
}
})
let total = coordinates.length
for (const item of coordinates) {
const index = coordinates.indexOf(item);
let r = await this.getHeight({lng: item[0], lat: item[1], alt: 0}, index, total,)
cb(null, r)
}
}
async computeDisByTowPoint(p1, p2) {
let d = this.computeDistance([p1, p2])
let meters = 10
let createLabel = (distance) => {
let label = this.getLabel("贴地距离:" + distance.toFixed(2) + "米")
label.pixelOffset = new Cesium.Cartesian2(
0, -(84)
)
let id = this.randomString()
this.viewer.entities.add(
new Cesium.Entity({
id: id,
label,
position: Cesium.Cartesian3.fromDegrees(p2.lng, p2.lat, p2.alt),
})
)
this.ids.push(id)
}
let start = async (meters) => {
let res = this.chunkLine([p1, p2], meters)
let coordinates = []
res.forEach((Feature, index) => {
if (index === 0) {
coordinates = [...Feature.geometry.coordinates]
} else {
coordinates.push(Feature.geometry.coordinates[1])
}
})
let arr = []
for (const item of coordinates) {
const index = coordinates.indexOf(item);
let r = await this.sampleHeight({lng: item[0], lat: item[1], alt: 0}, index)
arr.push(r)
}
let total_length = 0
let l = arr.length - 1
arr.forEach((item, index) => {
if (index !== l) {
let d1 = this.computeDistance([item.position, arr[index + 1].position])
let d2 = Math.abs(item.position.alt - arr[index + 1].position.alt)
let d3 = Math.sqrt(d1 * d1 + d2 * d2)
total_length += d3
}
})
createLabel(total_length)
}
//暂时固定取20个点
if (d > 20) {//大于20m时固定取20个点
meters = d / 20
await start(meters)
} else if (d < 1) {
//不计算
createLabel(d)
} else {//小于20m的时候
meters = 1
await start(meters)
}
}
async sampleHeight(p1, index) {
let p2 = await this.sampleHeightMostDetailed([p1])
p1.alt = p2[0].height
return {position: p1, index}
}
async getHeight(p1, index, total) {
let p2 = await this.sampleHeightMostDetailed([p1])
p1.alt = p2[0].height
this.clampPositions.push({position: p1, index})
if (total === this.clampPositions.length) {
let total_length = this.startCompute()
return {total, current: this.clampPositions.length, total_length}
}
return {total, current: this.clampPositions.length,}
}
startCompute() {
this.clampPositions.sort(function (a, b) {
return a.index < b.index
})
let total_length = 0
let l = this.clampPositions.length - 1
this.clampPositions.forEach((item, index) => {
if (index !== l) {
let d1 = this.computeDistance([item.position, this.clampPositions[index + 1].position])
let d2 = Math.abs(item.position.alt - this.clampPositions[index + 1].position.alt)
let d3 = Math.sqrt(d1 * d1 + d2 * d2)
total_length += d3
}
})
return Number(total_length.toFixed(2))
}
static createPolyline(that) {
let id = that.randomString()
that.viewer.entities.add(new Cesium.Entity({
id,
polyline: {
positions: new Cesium.CallbackProperty(() => {
return that.positions
}, false),
clampToGround: true,
width: 5,
material: new Cesium.Color.fromCssColorString(that.options.color || that.defaultColor),
zIndex: 99999999
}
}))
return id
}
static create_point(cartesian, {
label, image = "point.png",
width,
height
}, that) {
let id = that.randomString()
let p = that.cartesian3Towgs84(cartesian, that.viewer)
if (label) {
label.pixelOffset = new Cesium.Cartesian2(
0, -(height || 32)
)
}
that.viewer.entities.add(
new Cesium.Entity({
id: id,
label,
position: Cesium.Cartesian3.fromDegrees(p.lng, p.lat, p.alt),
billboard: {
image: that.getSourceRootPath() + '/img/' + image,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
disableDepthTestDistance: Number.POSITIVE_INFINITY,
width,
height
}
})
)
return id
}
getLabel(text) {
return {
text: text || '',
//标注文字描述
font: '20px Microsoft YaHei',
fillColor: Cesium.Color.fromCssColorString('#f1e605'),
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
//标注的遮挡距离设置为100则视角与标注的距离大于100米时会有遮挡
// distanceDisplayCondition: this.distanceDisplayCondition,
scale: 1,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
disableDepthTestDistance: Number.POSITIVE_INFINITY,
// disableDepthTestDistance: this.disableDepthTestDistance,
}
}
/**
* 开始测量
*/
start() {
if (!YJ.Measure.GetMeasureStatus()) {
super.start()
this.positions = []
this.cachePositions = []
this.event.mouse_left(async (movement, car) => {
if (this.ids.length === 0) {
this.polyline_id = (MeasureDistance.createPolyline(this))
this.start_id = MeasureDistance.create_point(car, {
image: "start.png", width: 32, height: 32, label: this.getLabel("")
}, this)
//创建起点
}
if (this.ids.length !== 0) {
let cur_point = this.cartesian3Towgs84(car, this.viewer)
let pre_p = this.cartesian3Towgs84(this.cachePositions[this.cachePositions.length - 1], this.viewer)
let cur_len = this.computeDistance([cur_point, pre_p])
let text = "投影距离:" + cur_len + " 米"
this.ids.push(MeasureDistance.create_point(car, {label: this.getLabel(text)}, this))
this.cachePositions.push(car)
//计算坡度
this.computeAngle(pre_p, cur_point)
await this.computeDisByTowPoint(pre_p, cur_point)
} else {
this.cachePositions.push(car)
this.ids.push(MeasureDistance.create_point(car, {}, this))
}
})
this.event.mouse_move((movement, car) => {
this.tip.setPosition(car, movement.endPosition.x, movement.endPosition.y)
this.positions = this.cachePositions.concat(car)
if (this.cachePositions.length) {
let cur_point = this.cartesian3Towgs84(car, this.viewer)
let pre_p = this.cartesian3Towgs84(this.cachePositions[this.cachePositions.length - 1], this.viewer)
let cur_len = this.computeDistance([cur_point, pre_p])
let text = "当前投影距离:" + cur_len + " 米"
this.tip.set_text(text)
}
})
this.event.mouse_right((movement, car) => {
if (this.cachePositions.length) {
this.positions = this.cachePositions
this.end_id = MeasureDistance.create_point(this.cachePositions[this.cachePositions.length - 1], {
image: "end.png",
width: 32,
height: 32,
}, this)
}
if (this.cachePositions.length === 0) {
this.destroy()
YJ.Measure.Measures.pop()//弹出测量实体
}
this.end()
})
this.event.mouse_right_keyboard_ctrl((movement, car) => {
if (this.cachePositions.length) {
this.cachePositions.pop()
this.remove_entity(this.ids.pop())
}
})
}
}
computeAngle(start, end) {
let d1 = this.computeDistance([start, end])
let d2 = Math.abs(start.alt - end.alt)
let d3 = Math.sqrt(d1 * d1 + d2 * d2)
let cosAlpha = d1 / d3
let acos = Math.acos(cosAlpha)
let angle = this.radiansToDegrees(acos)
let label = this.getLabel("坡度:" + angle.toFixed(1) + "°")
label.pixelOffset = new Cesium.Cartesian2(
0, -(58)
)
let id = this.randomString()
this.viewer.entities.add(
new Cesium.Entity({
id: id,
label,
position: Cesium.Cartesian3.fromDegrees(end.lng, end.lat, end.alt),
})
)
this.ids.push(id)
}
/**
* 清除测量
*/
destroy() {
[this.polyline_id, this.end_id, this.start_id, ...this.ids].forEach(id => {
this.remove_entity(id)
})
}
/**
* 结束测量
*/
end() {
// YJ.Measure.SetMeasureStatus(false)
// this.tip.destroy()
// this.event.destroy()
super.end()
// this.setPickStatus(this.pickStatus.pick)
}
}
export default MeasureDistance

View File

@ -0,0 +1,197 @@
/**
* @name: index
* @author: Administrator
* @date: 2022-07-22 17:15
* @descriptionindex
* @update: 2022-07-22 17:15
*/
import Measure from "../index";
class MeasureHeight extends Measure {
/**
* @constructor
* @param sdk
* @description 高度测量
* */
constructor(sdk) {
super(sdk, {text: "左键开始,右键取消"});
}
static create_polygon(that) {
let id = that.randomString()
let a = that.viewer.entities.add(new Cesium.Entity({
id,
billboard: {
image: that.getSourceRootPath() + '/img/point.png',
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
disableDepthTestDistance: Number.POSITIVE_INFINITY,
color: Cesium.Color.WHITE.withAlpha(0.99)
},
position: new Cesium.CallbackProperty(() => {
return that.position
}, false),
label: {
text: new Cesium.CallbackProperty(() => {
return that.text
}, false),
scale: 1,
// fillColor: Cesium.Color.RED,
font: 'normal 20px MicroSoft YaHei',
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
pixelOffset: new Cesium.Cartesian2(0, -15),
disableDepthTestDistance: Number.POSITIVE_INFINITY,
},
polyline: {
positions: new Cesium.CallbackProperty(e => {
return that.positions;
}, false),
width: 2,
material: Cesium.Color.YELLOW,
zIndex: 99999999
},
ellipse: {
height: new Cesium.CallbackProperty(() => {
return that.height + that.firstpoint.alt;
}, false),
semiMinorAxis: new Cesium.CallbackProperty(e => {
return that.circleRadius;
}, false),
semiMajorAxis: new Cesium.CallbackProperty(e => {
return that.circleRadius;
}, false),
material: new Cesium.Color.fromCssColorString(that.defaultColor)
},
}))
return id
}
static create_point(that, cartesian, option = {}) {
let id = that.randomString()
let p = that.cartesian3Towgs84(cartesian, that.viewer)
let params = {
id: id,
position: Cesium.Cartesian3.fromDegrees(p.lng, p.lat, p.alt),
billboard: {
image: that.getSourceRootPath() + '/img/point.png',
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
disableDepthTestDistance: Number.POSITIVE_INFINITY,
color: Cesium.Color.WHITE.withAlpha(0.99)
}
}
if (option.label) {
params.label = {
text: option.label.text,
scale: 1,
// fillColor: Cesium.Color.fromCssColorString("#06eee5"),
font: 'normal 20px MicroSoft YaHei',
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
pixelOffset: new Cesium.Cartesian2(0, -15),
}
}
that.viewer.entities.add(
new Cesium.Entity(params)
)
return id
}
/**
* 开始测量
*/
start() {
if (!YJ.Measure.GetMeasureStatus()) {
super.start()
this.positions = []
this.position = new Cesium.Cartesian3()
this.height = 0
this.text = ""
this.circleRadius = 0
let count = 0;
this.firstpoint = null
let leftEvent = (movement, cartesian) => {
if (this.firstpoint === null) {
this.positions.push(cartesian)
this.firstpoint = this.cartesian3Towgs84(cartesian, this.viewer)
this.ids.push(MeasureHeight.create_polygon(this))
this.ids.push(MeasureHeight.create_point(this, cartesian))
}
count++
this.tip.setPosition(cartesian, movement.position.x, movement.position.y)
if (count === 2) {
if (this.firstpoint) {
let cur_point = this.cartesian3Towgs84(cartesian, this.viewer)
this.positions[1] = Cesium.Cartesian3.fromDegrees(this.firstpoint.lng, this.firstpoint.lat, cur_point.alt)
this.positions[2] = cartesian
this.position = this.positions[1]
this.circleRadius = this.computeDistance([this.firstpoint, cur_point])
this.height = Number((cur_point.alt - this.firstpoint.alt).toFixed(2))
this.text = "相对高度:" + this.height + " 米"
this.tip.set_text("左键完成,右键取消;半径:" + this.circleRadius + " 米")
}
this.ids.push(MeasureHeight.create_point(this, cartesian, {label: {text: "半径:" + this.circleRadius + " 米"}}))
this.end()
}
}
this.event.mouse_left(leftEvent)
this.event.mouse_move((movement, cartesian) => {
this.tip.setPosition(cartesian, movement.endPosition.x, movement.endPosition.y)
if (this.firstpoint) {
let cur_point = this.cartesian3Towgs84(cartesian, this.viewer)
this.positions[1] = Cesium.Cartesian3.fromDegrees(this.firstpoint.lng, this.firstpoint.lat, cur_point.alt)
this.positions[2] = cartesian
this.position = this.positions[1]
this.circleRadius = this.computeDistance([this.firstpoint, cur_point])
this.height = Number((cur_point.alt - this.firstpoint.alt).toFixed(2))
this.text = "相对高度:" + this.height + " 米"
this.tip.set_text("左键完成,右键取消;半径:" + this.circleRadius + " 米")
}
})
this.event.mouse_right((movement, cartesian) => {
this.end()
this.destroy()
})
this.event.gesture_pinck_start((movement, cartesian) => {
let startTime = new Date()
let pos = {
position: {
x: (movement.position1.x + movement.position2.x) / 2,
y: (movement.position1.y + movement.position2.y) / 2
}
}
this.event.gesture_pinck_end(() => {
let endTime = new Date()
if (endTime - startTime >= 500) {
// 长按取消
this.end()
this.destroy()
}
else {
leftEvent(pos, cartesian)
}
})
})
}
}
/**
* 结束测量
*/
end() {
super.end()
}
/**
* 清除测量
*/
destroy() {
super.destroy()
}
}
export default MeasureHeight

View File

@ -0,0 +1,182 @@
/**
* @name: index
* @author: Administrator
* @date: 2022-07-22 16:13
* @descriptionindex
* @update: 2022-07-22 16:13
*/
import Measure from "../index";
import { Proj } from "../../Tools/proj";
import { getCoordinateSystem } from "../../Global/global";
class MeasureLocation extends Measure {
/**
* @constructor
* @param sdk
* @description 坐标测量
* */
constructor(sdk) {
super(sdk, {text: ""});
this.defaultColor = "#f11515"
this.locationID = this.randomString()
this.position = new Cesium.Cartesian3()
this.text = ""
}
static createLocation(that) {
that.viewer.entities.add(new Cesium.Entity({
id: that.locationID,
show: false,
position: new Cesium.CallbackProperty(() => {
return that.position
}, false),
label: {
text: new Cesium.CallbackProperty(() => {
return that.text
}, false),
//标注文字描述
font: '22px Microsoft YaHei',
fillColor: new Cesium.Color.fromCssColorString(that.defaultColor),
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
//标注的遮挡距离设置为100则视角与标注的距离大于100米时会有遮挡
// distanceDisplayCondition: this.distanceDisplayCondition,
// scale: this.options.label.scale,
horizontalOrigin: Cesium.HorizontalOrigin.LEFT,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
disableDepthTestDistance: Number.POSITIVE_INFINITY,
pixelOffset: new Cesium.Cartesian2(
-100,
-50
),
// disableDepthTestDistance: this.disableDepthTestDistance,
},
billboard: {
image: that.getSourceRootPath() + "/img/location.png",
color: Cesium.Color.fromCssColorString(`rgba(255,255,255,0.99)`),
disableDepthTestDistance: Number.POSITIVE_INFINITY,
// scaleByDistance: new Cesium.NearFarScalar(
// 2000,
// 1,
// 1000000,
// 0
// ),
scale: 1,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
width: 48,
height: 48
}
}))
}
static create_point(that) {
let id = that.randomString()
that.viewer.entities.add(
new Cesium.Entity({
id: id,
position: new Cesium.CallbackProperty(() => {
return that.position
}, false),
billboard: {
image: that.getSourceRootPath() + '/img/point.png',
color: Cesium.Color.fromCssColorString(`rgba(255,255,255,0.99)`),
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
disableDepthTestDistance: Number.POSITIVE_INFINITY,
color: Cesium.Color.WHITE.withAlpha(0.99)
}
})
)
return id
}
/**
* 开始测量
*/
start() {
if (!YJ.Measure.GetMeasureStatus()) {
super.start()
this.cache_id = MeasureLocation.create_point(this)
MeasureLocation.createLocation(this)
let leftEvent = (movement, cartesian) => {
this.position = cartesian
let entity = this.viewer.entities.getById(this.locationID)
if(entity) {
entity.show = true
}
let p = this.cartesian3Towgs84(cartesian, this.viewer)
let coordinateSystem = getCoordinateSystem()
if(coordinateSystem==='EPSG:4326') {
this.text = `经度:${Number(p.lng.toFixed(8))}\n纬度:${Number(p.lat.toFixed(8))}\n海拔:${Number(p.alt.toFixed(2))}`
}
else {
let result = this.convert([{x: p.lng, y: p.lat, z: p.alt}], 'EPSG:4326', coordinateSystem)
this.text = `x${Number(result.points[0].x.toFixed(8))}\ny${Number(result.points[0].y.toFixed(8))}\nz${Number(result.points[0].z.toFixed(2))}`
}
this.end()
}
this.event.mouse_left(leftEvent)
this.event.mouse_right((movement, cartesian) => {
this.destroy()
this.end()
})
this.event.mouse_move((movement, cartesian) => {
this.tip.setPosition(cartesian, movement.endPosition.x, movement.endPosition.y)
let entity = this.viewer.entities.getById(this.locationID)
if(entity) {
entity.show = true
}
this.position = cartesian
let p = this.cartesian3Towgs84(cartesian, this.viewer)
let coordinateSystem = getCoordinateSystem()
if(coordinateSystem==='EPSG:4326') {
this.text = `经度:${Number(p.lng.toFixed(8))}\n纬度:${Number(p.lat.toFixed(8))}\n海拔:${Number(p.alt.toFixed(2))}`
}
else {
let result = this.convert([{x: p.lng, y: p.lat, z: p.alt}], 'EPSG:4326', coordinateSystem)
this.text = `x${Number(result.points[0].x.toFixed(8))}\ny${Number(result.points[0].y.toFixed(8))}\nz${Number(result.points[0].z.toFixed(2))}`
}
})
this.event.gesture_pinck_start((movement, cartesian) => {
let startTime = new Date()
let pos = {
position: {
x: (movement.position1.x + movement.position2.x) / 2,
y: (movement.position1.y + movement.position2.y) / 2
}
}
this.event.gesture_pinck_end(() => {
let endTime = new Date()
if (endTime - startTime >= 500) {
// 长按取消
this.destroy()
this.end()
}
else {
leftEvent(pos, cartesian)
}
})
})
}
}
/**
* 清除测量
*/
destroy() {
this.remove_entity(this.locationID)
this.remove_entity(this.cache_id)
super.destroy()
}
/**
* 结束测量
*/
end() {
super.end()
}
}
export default MeasureLocation

View File

@ -0,0 +1,276 @@
/**
* @name: index
* @author: Administrator
* @date: 2022-07-11 10:31
* @descriptionindex
* @update: 2022-07-11 10:31
*/
import Measure from "../index"
class MeasureProjectionDistance extends Measure {
/**
* @constructor
* @param sdk
* @description 投影距离测量
* */
constructor(sdk, options = {}) {
super(sdk, options)
this.options.color = this.options.color || "#00ffff"
this.start_id = ""
this.end_id = ""
this.polyline_id = ""
this.clampPositions = []
}
async clampToGroundMeasure(meters, cb) {
let positions = []
this.ids.forEach((id, index) => {
let p = this.viewer.entities.getById(id).position.getValue()
positions.push(this.cartesian3Towgs84(p, this.viewer))
})
let res = this.chunkLine(positions, meters)
let coordinates = []
res.forEach((Feature, index) => {
if (index === 0) {
coordinates = [...Feature.geometry.coordinates]
} else {
coordinates.push(Feature.geometry.coordinates[1])
}
})
let total = coordinates.length
for (const item of coordinates) {
const index = coordinates.indexOf(item);
let r = await this.getHeight({lng: item[0], lat: item[1], alt: 0}, index, total,)
cb(null, r)
}
}
async sampleHeight(p1, index) {
let p2 = await this.sampleHeightMostDetailed([p1])
p1.alt = p2[0].height
return {position: p1, index}
}
async getHeight(p1, index, total) {
let p2 = await this.sampleHeightMostDetailed([p1])
p1.alt = p2[0].height
this.clampPositions.push({position: p1, index})
if (total === this.clampPositions.length) {
let total_length = this.startCompute()
return {total, current: this.clampPositions.length, total_length}
}
return {total, current: this.clampPositions.length,}
}
startCompute() {
this.clampPositions.sort(function (a, b) {
return a.index < b.index
})
let total_length = 0
let l = this.clampPositions.length - 1
this.clampPositions.forEach((item, index) => {
if (index !== l) {
let d1 = this.computeDistance([item.position, this.clampPositions[index + 1].position])
let d2 = Math.abs(item.position.alt - this.clampPositions[index + 1].position.alt)
let d3 = Math.sqrt(d1 * d1 + d2 * d2)
total_length += d3
}
})
return Number(total_length.toFixed(2))
}
static createPolyline(that) {
let id = that.randomString()
that.viewer.entities.add(new Cesium.Entity({
id,
polyline: {
positions: new Cesium.CallbackProperty(() => {
return that.positions
}, false),
clampToGround: true,
width: 3,
material: new Cesium.PolylineDashMaterialProperty({
color: new Cesium.Color.fromCssColorString(that.options.color || that.defaultColor),
dashLength: 20, //短划线长度
}),
},
zIndex: 99999999
}))
return id
}
static create_point(cartesian, {
label, image = "point.png",
width,
height
}, that) {
let id = that.randomString()
let p = that.cartesian3Towgs84(cartesian, that.viewer)
if (label) {
label.pixelOffset = new Cesium.Cartesian2(
0, -(height || 32)
)
}
that.viewer.entities.add(
new Cesium.Entity({
id: id,
label,
position: Cesium.Cartesian3.fromDegrees(p.lng, p.lat, p.alt),
billboard: {
image: that.getSourceRootPath() + '/img/' + image,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
disableDepthTestDistance: Number.POSITIVE_INFINITY,
width,
height
}
})
)
return id
}
getLabel(text) {
return {
text: text || '',
//标注文字描述
font: '20px Microsoft YaHei',
fillColor: Cesium.Color.fromCssColorString('#f1e605'),
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
//标注的遮挡距离设置为100则视角与标注的距离大于100米时会有遮挡
// distanceDisplayCondition: this.distanceDisplayCondition,
scale: 1,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
disableDepthTestDistance: Number.POSITIVE_INFINITY,
// disableDepthTestDistance: this.disableDepthTestDistance,
}
}
/**
* 开始测量
*/
start() {
if (!YJ.Measure.GetMeasureStatus()) {
super.start()
this.positions = []
this.cachePositions = []
let leftEvent = async (movement, car) => {
if (this.ids.length === 0) {
this.polyline_id = (MeasureProjectionDistance.createPolyline(this))
this.start_id = MeasureProjectionDistance.create_point(car, {
image: "start1.png", width: 30, height: 38, label: this.getLabel("")
}, this)
//创建起点
}
this.positions = this.cachePositions.concat(car)
this.tip.setPosition(car, movement.position.x, movement.position.y)
if (this.ids.length !== 0) {
let cur_point = this.cartesian3Towgs84(car, this.viewer)
let pre_p = this.cartesian3Towgs84(this.cachePositions[this.cachePositions.length - 1], this.viewer)
let cur_len = this.computeDistance([cur_point, pre_p])
let text = "投影距离:" + cur_len + " 米"
this.ids.push(MeasureProjectionDistance.create_point(car, {label: this.getLabel(text)}, this))
this.cachePositions.push(car)
} else {
this.cachePositions.push(car)
this.ids.push(MeasureProjectionDistance.create_point(car, {show: false}, this))
let startPoint = this.viewer.entities.getById(this.ids[0])
if(startPoint) {
startPoint.billboard.show = false
}
}
}
let rightEvent = (movement, car) => {
if (this.cachePositions.length) {
this.positions = this.cachePositions
this.end_id = MeasureProjectionDistance.create_point(this.cachePositions[this.cachePositions.length - 1], {
image: "end1.png",
width: 30,
height: 38,
}, this)
let endPoint = this.viewer.entities.getById(this.ids[this.ids.length-1])
if(endPoint) {
endPoint.billboard.show = false
}
}
if (this.cachePositions.length < 2) {
this.destroy()
YJ.Measure.Measures.pop()//弹出测量实体
}
this.end()
}
this.event.mouse_left(leftEvent)
this.event.mouse_move((movement, car) => {
this.tip.setPosition(car, movement.endPosition.x, movement.endPosition.y)
this.positions = this.cachePositions.concat(car)
if (this.cachePositions.length) {
let cur_point = this.cartesian3Towgs84(car, this.viewer)
let pre_p = this.cartesian3Towgs84(this.cachePositions[this.cachePositions.length - 1], this.viewer)
let cur_len = this.computeDistance([cur_point, pre_p])
let text = "当前投影距离:" + cur_len + " 米"
this.tip.set_text(text)
}
})
this.event.mouse_right(rightEvent)
this.event.mouse_right_keyboard_ctrl((movement, car) => {
if (this.cachePositions.length) {
this.cachePositions.pop()
this.remove_entity(this.ids.pop())
}
})
this.event.gesture_pinck_start((movement, cartesian) => {
let startTime = new Date()
let pos = {
position: {
x: (movement.position1.x + movement.position2.x) / 2,
y: (movement.position1.y + movement.position2.y) / 2
}
}
this.event.gesture_pinck_end(() => {
let endTime = new Date()
if (endTime - startTime >= 500) {
// 长按取消
rightEvent(pos, cartesian)
}
else {
leftEvent(pos, cartesian)
}
})
})
}
}
/**
* 清除测量
*/
destroy() {
[this.polyline_id, this.end_id, this.start_id, ...this.ids].forEach(id => {
this.remove_entity(id)
})
super.destroy()
}
/**
* 结束测量
*/
end() {
// YJ.Measure.SetMeasureStatus(false)
// this.tip.destroy()
// this.event.destroy()
super.end()
// this.setPickStatus(this.pickStatus.pick)
}
}
export default MeasureProjectionDistance

View File

@ -0,0 +1,316 @@
/**
* @name: index
* @author: Administrator
* @date: 2022-07-11 10:31
* @descriptionindex
* @update: 2022-07-11 10:31
*/
import Measure from "../index"
import MouseEvent from "../../Event";
class MeasureSlopeDistance extends Measure {
/**
* @constructor
* @param sdk
* @description 坡度测量
* */
constructor(sdk, options = {}) {
super(sdk, options)
this.options.color = this.options.color || "#00ffff"
this.start_id = ""
this.end_id = ""
this.polyline_id = ""
this.clampPositions = []
this.event = new MouseEvent(sdk)
}
async clampToGroundMeasure(meters, cb) {
let positions = []
this.ids.forEach((id, index) => {
let p = this.viewer.entities.getById(id).position.getValue()
positions.push(this.cartesian3Towgs84(p, this.viewer))
})
let res = this.chunkLine(positions, meters)
let coordinates = []
res.forEach((Feature, index) => {
if (index === 0) {
coordinates = [...Feature.geometry.coordinates]
} else {
coordinates.push(Feature.geometry.coordinates[1])
}
})
let total = coordinates.length
for (const item of coordinates) {
const index = coordinates.indexOf(item);
let r = await this.getHeight({ lng: item[0], lat: item[1], alt: 0 }, index, total,)
cb(null, r)
}
}
async sampleHeight(p1, index) {
let p2 = await this.sampleHeightMostDetailed([p1])
p1.alt = p2[0].height
return { position: p1, index }
}
async getHeight(p1, index, total) {
let p2 = await this.sampleHeightMostDetailed([p1])
p1.alt = p2[0].height
this.clampPositions.push({ position: p1, index })
if (total === this.clampPositions.length) {
let total_length = this.startCompute()
return { total, current: this.clampPositions.length, total_length }
}
return { total, current: this.clampPositions.length, }
}
startCompute() {
this.clampPositions.sort(function (a, b) {
return a.index < b.index
})
let total_length = 0
let l = this.clampPositions.length - 1
this.clampPositions.forEach((item, index) => {
if (index !== l) {
let d1 = this.computeDistance([item.position, this.clampPositions[index + 1].position])
let d2 = Math.abs(item.position.alt - this.clampPositions[index + 1].position.alt)
let d3 = Math.sqrt(d1 * d1 + d2 * d2)
total_length += d3
}
})
return Number(total_length.toFixed(2))
}
static createPolyline(that) {
let id = that.randomString()
that.viewer.entities.add(new Cesium.Entity({
id,
polyline: {
positions: new Cesium.CallbackProperty(() => {
return that.positions
}, false),
clampToGround: true,
width: 3,
material: new Cesium.PolylineDashMaterialProperty({
color: new Cesium.Color.fromCssColorString(that.options.color || that.defaultColor),
dashLength: 20, //短划线长度
}),
zIndex: 99999999
}
}))
return id
}
static create_point(cartesian, {
label, image = "point.png",
width,
height
}, that) {
let id = that.randomString()
let p = that.cartesian3Towgs84(cartesian, that.viewer)
if (label) {
label.pixelOffset = new Cesium.Cartesian2(
0, -(height || 32)
)
}
that.viewer.entities.add(
new Cesium.Entity({
id: id,
label,
position: Cesium.Cartesian3.fromDegrees(p.lng, p.lat, p.alt),
billboard: {
image: that.getSourceRootPath() + '/img/' + image,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
disableDepthTestDistance: Number.POSITIVE_INFINITY,
width,
height
}
})
)
return id
}
getLabel(text) {
return {
text: text || '',
//标注文字描述
font: '20px Microsoft YaHei',
fillColor: Cesium.Color.fromCssColorString('#f1e605'),
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
//标注的遮挡距离设置为100则视角与标注的距离大于100米时会有遮挡
// distanceDisplayCondition: this.distanceDisplayCondition,
scale: 1,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
disableDepthTestDistance: Number.POSITIVE_INFINITY,
// disableDepthTestDistance: this.disableDepthTestDistance,
}
}
/**
* 开始测量
*/
start() {
if (!YJ.Measure.GetMeasureStatus()) {
super.start()
this.positions = []
this.cachePositions = []
let leftEvent = (movement, car) => {
if (this.ids.length === 0) {
this.polyline_id = (MeasureSlopeDistance.createPolyline(this))
this.start_id = MeasureSlopeDistance.create_point(car, {
image: "start1.png", width: 30, height: 38, label: this.getLabel("")
}, this)
//创建起点
}
this.tip.setPosition(car, movement.position.x, movement.position.y)
this.positions = this.cachePositions.concat(car)
if (this.ids.length !== 0) {
let cur_point = this.cartesian3Towgs84(car, this.viewer)
let pre_p = this.cartesian3Towgs84(this.cachePositions[this.cachePositions.length - 1], this.viewer)
if (cur_point.lng !== pre_p.lng || cur_point.lat !== pre_p.lat || cur_point.alt !== pre_p.alt) {
this.cachePositions.push(car)
//计算坡度
this.computeAngle(pre_p, cur_point)
}
} else {
this.cachePositions.push(car)
this.ids.push(MeasureSlopeDistance.create_point(car, {}, this))
let startPoint = this.viewer.entities.getById(this.ids[0])
if(startPoint) {
startPoint.billboard.show = false
}
}
}
let rightEvent = (movement, car) => {
if (this.ids.length !== 0) {
// let cur_point = this.cartesian3Towgs84(car, this.viewer)
// let pre_p = this.cartesian3Towgs84(this.cachePositions[this.cachePositions.length - 1], this.viewer)
// if (cur_point.lng !== pre_p.lng || cur_point.lat !== pre_p.lat || cur_point.alt !== pre_p.alt) {
// this.cachePositions.push(car)
// //计算坡度
// this.computeAngle(pre_p, cur_point)
// }
} else {
// this.cachePositions.push(car)
this.ids.push(MeasureSlopeDistance.create_point(car, {}, this))
}
if (this.cachePositions.length) {
this.positions = this.cachePositions
this.end_id = MeasureSlopeDistance.create_point(this.cachePositions[this.cachePositions.length - 1], {
image: "end1.png",
width: 30,
height: 38,
}, this)
let endPoint = this.viewer.entities.getById(this.ids[this.ids.length-1])
if(endPoint) {
endPoint.billboard.show = false
}
}
if (this.cachePositions.length < 2) {
this.destroy()
YJ.Measure.Measures.pop()//弹出测量实体
}
this.end()
}
this.event.mouse_left(leftEvent)
this.event.mouse_move((movement, car) => {
movement.endPosition.y += 2
let position = movement.endPosition
let cartesian = this.viewer.scene.pickPosition(position)
if (!cartesian) {
const ray = this.viewer.camera.getPickRay(position); //相交的射线
cartesian = this.viewer.scene.globe.pick(ray, this.viewer.scene);
}
this.tip.setPosition(car, movement.endPosition.x, movement.endPosition.y)
this.positions = this.cachePositions.concat(cartesian)
if (this.cachePositions.length) {
let cur_point = this.cartesian3Towgs84(cartesian, this.viewer)
let pre_p = this.cartesian3Towgs84(this.cachePositions[this.cachePositions.length - 1], this.viewer)
let d1 = this.computeDistance([pre_p, cur_point])
let d2 = Math.abs(pre_p.alt - cur_point.alt)
let d3 = Math.sqrt(d1 * d1 + d2 * d2)
let cosAlpha = d1 / d3
let acos = Math.acos(cosAlpha)
let angle = this.radiansToDegrees(acos)
let label = "坡度:" + angle.toFixed(2) + "°"
this.tip.set_text(label)
}
})
this.event.mouse_right(rightEvent)
this.event.mouse_right_keyboard_ctrl((movement, car) => {
if (this.cachePositions.length) {
this.cachePositions.pop()
this.remove_entity(this.ids.pop())
}
})
this.event.gesture_pinck_start((movement, cartesian) => {
let startTime = new Date()
let pos = {
position: {
x: (movement.position1.x + movement.position2.x) / 2,
y: (movement.position1.y + movement.position2.y) / 2
}
}
this.event.gesture_pinck_end(() => {
let endTime = new Date()
if (endTime - startTime >= 500) {
// 长按取消
rightEvent(pos, cartesian)
}
else {
leftEvent(pos, cartesian)
}
})
})
}
}
computeAngle(start, end) {
let d1 = this.computeDistance([start, end])
let d2 = Math.abs(start.alt - end.alt)
let d3 = Math.sqrt(d1 * d1 + d2 * d2)
let cosAlpha = d1 / d3
let acos = Math.acos(cosAlpha)
let angle = this.radiansToDegrees(acos)
let label = this.getLabel("坡度:" + angle.toFixed(2) + "°")
label.pixelOffset = new Cesium.Cartesian2(
0, -(32)
)
this.ids.push(MeasureSlopeDistance.create_point(Cesium.Cartesian3.fromDegrees(end.lng, end.lat, end.alt), {label: label}, this))
}
/**
* 清除测量
*/
destroy() {
[this.polyline_id, this.end_id, this.start_id, ...this.ids].forEach(id => {
this.remove_entity(id)
})
super.destroy()
}
/**
* 结束测量
*/
end() {
// YJ.Measure.SetMeasureStatus(false)
// this.tip.destroy()
// this.event.destroy()
super.end()
// this.setPickStatus(this.pickStatus.pick)
}
}
export default MeasureSlopeDistance

View File

@ -0,0 +1,173 @@
import Measure from "../index"
/**@extends Measure*/
class MeasureTdArea extends Measure {
/**
* @constructor
* @param sdk
* @description 贴地面积测量
* */
constructor(sdk, options = {}) {
super(sdk, options);
this.options.lineColor = '#ffdf53'
this.polygon_id = ""
}
static create_polygon(that) {
let id = that.randomString()
let scaleByDistance = new Cesium.NearFarScalar(2000, 1, 100000, 0)
let e = that.viewer.entities.add(
new Cesium.Entity({
id: id,
label: {
text: new Cesium.CallbackProperty(() => {
return that.text
}, false),
//标注文字描述
font: '20px Microsoft YaHei',
fillColor: Cesium.Color.fromCssColorString('#ffffff'),
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
//标注的遮挡距离设置为100则视角与标注的距离大于100米时会有遮挡
// distanceDisplayCondition: this.distanceDisplayCondition,
disableDepthTestDistance: Number.POSITIVE_INFINITY,
// scaleByDistance,
scale: 1,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
},
position: new Cesium.CallbackProperty(() => {
return that.center
}, false),
polygon: {
classificationType: Cesium.ClassificationType.BOTH,
hierarchy: new Cesium.CallbackProperty((e) => {
return new Cesium.PolygonHierarchy(that.positions)
}, false),
material: new Cesium.Color.fromCssColorString(that.options.color || that.defaultColor),
zIndex: 99999999
},
polyline: {
positions: new Cesium.CallbackProperty(() => {
if (that.positions.length)
return that.positions.concat(that.positions[0])
return that.positions
}, false),
width: 2,
material: new Cesium.PolylineDashMaterialProperty({
color: new Cesium.Color.fromCssColorString(that.options.lineColor || that.defaultColor),
dashLength: 20, //短划线长度
}),
clampToGround: true,
zIndex: 99999999
}
})
)
return id
}
/**
* 开始测量
*/
start() {
if (!YJ.Measure.GetMeasureStatus()) {
super.start()
this.ids = []
this.positions = []
this.text = ""
this.center = new Cesium.Cartesian3()
this.cachePositions = []
let height = 0
let text
let leftEvent = (movement, car) => {
if (this.ids.length === 0) {
this.polygon_id = MeasureTdArea.create_polygon(this)
}
this.cachePositions.push({ ...car })
this.ids.push(this.create_point({ ...car }, false))
let po = this.cartesian3Towgs84({ ...car }, this.viewer)
if (po.alt > height) {
height = po.alt
}
this.positions = this.cachePositions.concat({ ...car })
this.tip.setPosition({ ...car }, movement.position.x, movement.position.y)
}
let rightEvent = (movement, car) => {
this.positions = this.cachePositions
if (this.positions.length > 2) {
let arr = []
this.positions.forEach(item => {
let p = this.cartesian3Towgs84(item, this.viewer)
arr.push({ lng: p.lng, lat: p.lat })
})
setTimeout(() => {
let center = this.computeCenter(arr)
let area = this.computeSignedArea(this.viewer, arr)
this.center = new Cesium.Cartesian3.fromDegrees(center.lng, center.lat, height)
this.text = "贴地面积:" + area + " ㎡"
}, 0);
}
else {
let error = '面积计算至少需要三个坐标!'
console.warn(error)
window.ELEMENT && window.ELEMENT.Message({
message: error,
type: 'warning',
duration: 1500
});
this.destroy()
}
this.end()
}
this.event.mouse_left(leftEvent)
this.event.mouse_move((movement, car) => {
this.tip.setPosition({ ...car }, movement.endPosition.x, movement.endPosition.y)
this.positions = this.cachePositions.concat({ ...car })
})
this.event.mouse_right(rightEvent)
this.event.gesture_pinck_start((movement, cartesian) => {
let startTime = new Date()
let pos = {
position: {
x: (movement.position1.x + movement.position2.x) / 2,
y: (movement.position1.y + movement.position2.y) / 2
}
}
this.event.gesture_pinck_end(() => {
let endTime = new Date()
if (endTime - startTime >= 500) {
// 长按取消
rightEvent(pos, cartesian)
}
else {
leftEvent(pos, cartesian)
}
})
})
}
}
/**
* 清除测量
*/
destroy() {
[this.polygon_id, ...this.ids].forEach(id => {
this.remove_entity(id)
})
super.destroy()
}
/**
* 结束测量
*/
end() {
super.end()
}
}
export default MeasureTdArea

View File

@ -0,0 +1,290 @@
/**
* @name: index
* @author: Administrator
* @date: 2022-07-21 15:22
* @descriptionindex
* @update: 2022-07-21 15:22
*/
import Measure from "../index";
class MeasureTriangle extends Measure {
/**
* @constructor
* @param sdk
* @description 三角测量
* */
constructor(sdk) {
super(sdk);
}
cal_center(positions) {
let p1 = this.cartesian3Towgs84(positions[0], this.viewer)
let p2 = this.cartesian3Towgs84(positions[1], this.viewer)
let center = this.computeCenter([p1, p2]);
return Cesium.Cartesian3.fromDegrees(center.lng, center.lat, (p1.alt + p2.alt) / 2)
}
cal_distance(positions) {
let p1 = this.cartesian3Towgs84(positions[0], this.viewer)
let p2 = this.cartesian3Towgs84(positions[1], this.viewer)
let dis = this.computeDistance([p1, p2])
p1.alt = p1.alt.toFixed(2)
p2.alt = p2.alt.toFixed(2)
if (p1.alt === p2.alt) {//水平边
return dis
} else if (Number(dis) === 0.00) {//竖直边
return Math.abs(p1.alt - p2.alt).toFixed(2)
} else {//斜边
return Math.sqrt(dis * dis + Math.pow(Math.abs(p1.alt - p2.alt).toFixed(2), 2)).toFixed(2)
}
}
createPolyline(id) {
let obj = this.id_map.get(id)
this.viewer.entities.add(new Cesium.Entity({
id,
position: new Cesium.CallbackProperty(() => {
if (obj.positions.length === 2)
return this.cal_center(obj.positions)
else
return Cesium.Cartesian3()
}, false),
label: {
text: new Cesium.CallbackProperty(() => {
if (obj.positions.length === 2)
return this.cal_distance(obj.positions) + "米"
else
return "0米"
}, false),
scale: 1,
fillColor: Cesium.Color.RED,
font: 'normal 20px MicroSoft YaHei',
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
pixelOffset: new Cesium.Cartesian2(0, -10),
disableDepthTestDistance: Number.POSITIVE_INFINITY,
},
polyline: {
positions: new Cesium.CallbackProperty(() => {
return obj.positions
}, false),
width: 2,
material: Cesium.Color.YELLOW,
zIndex: 99999999
}
}))
this.ids.push(id)
}
create_angle_label(positions1, positions2, id, type) {
let entity = new Cesium.Entity({
id,
position: new Cesium.CallbackProperty(() => {
if (positions1.length === 2)
return this.cal_point(positions1, positions2)
else
return Cesium.Cartesian3()
}),
label: {
text: new Cesium.CallbackProperty(() => {
if (positions1.length === 2)
return this.cal_angle(positions1, positions2, type) + "°"
else
return "0°"
}, false),
scale: 1,
fillColor: Cesium.Color.RED,
font: 'normal 20px MicroSoft YaHei',
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
pixelOffset: new Cesium.Cartesian2(15, -10),
}
})
this.viewer.entities.add(entity)
}
cal_point(positions1, positions2) {
for (let i = 0; i < positions1.length; i++) {
for (let j = 0; j < positions2.length; j++) {
if (positions1[i].x === positions2[j].x &&
positions1[i].y === positions2[j].y &&
positions1[i].z === positions2[j].z
) {
return positions1[i]
}
}
}
}
cal_angle(id1, id2, type) {
if (type === 1) {//水平&竖直
return 90
} else if (type === 2 || type === 3) {//水平&斜边 竖直&斜边
let positions1 = this.id_map.get(id1).positions
let positions2 = this.id_map.get(id2).positions
let p1 = this.cartesian3Towgs84(positions1[0], this.viewer)
let p2 = this.cartesian3Towgs84(positions1[1], this.viewer)
let shuiping = this.computeDistance([p2, p1])
let p3 = this.cartesian3Towgs84(positions2[0], this.viewer)
let p4 = this.cartesian3Towgs84(positions2[1], this.viewer)
let d = this.computeDistance([p3, p4])
let h = Math.abs(p3.alt - p4.alt)
let x = Math.sqrt(Math.pow(h, 2) + Math.pow(d, 2))
if (shuiping == 0.00) {
shuiping = Math.abs(p2.alt - p1.alt)
}
return (Math.acos(shuiping / x) * 180 / Math.PI).toFixed(2)
}
}
/**
* 开始测量
*/
start() {
if (!YJ.Measure.GetMeasureStatus()) {
super.start()
this.positions = []
this.cachePositions = []
let shuiping_line_id = this.randomString();//水平线
let shuizhi_line_id = this.randomString();//竖直边
let xiebian_line_id = this.randomString();//斜边
let angle1 = this.randomString();//角度1
let angle2 = this.randomString();//角度2
let angle3 = this.randomString();//角度3
let xiebian_line_positions = [];//斜边
this.id_map = new Map()
let first_point = {}
this.id_map.set(xiebian_line_id, {positions: []})
this.id_map.set(shuiping_line_id, {positions: []})
this.id_map.set(shuizhi_line_id, {positions: []})
let leftEvent = (movement, car) => {
xiebian_line_positions.push(car)
if (this.ids.length === 0) {//创建三角形
first_point = this.cartesian3Towgs84(car, this.viewer)
this.createPolyline(shuiping_line_id,)
this.createPolyline(shuizhi_line_id,)
this.createPolyline(xiebian_line_id,)
// this.cal_angle(shuiping_line_id, shuizhi_line_id, 1)
// this.cal_angle(shuiping_line_id, xiebian_line_id, 2)
// this.cal_angle(shuizhi_line_id, xiebian_line_id, 3)
// this.ids.push(shuiping_line_id)
// this.ids.push(shuizhi_line_id)
// this.ids.push(xiebian_line_id)
}
this.ids.push(this.create_point(car))
this.tip.setPosition(car, movement.position.x, movement.position.y)
// // 隐藏斜边文字
// let xiebian = this.id_map.get(xiebian_line_id)
// let xbEntity = this.viewer.entities.getById(xiebian_line_id)
// if(xbEntity) {
// xbEntity.label.show = false
// }
if (xiebian_line_positions.length) {
// xiebian.positions = xiebian_line_positions.concat(car)
let p = this.cartesian3Towgs84(car, this.viewer)
let shuzhi = this.id_map.get(shuizhi_line_id)
let shuiping = this.id_map.get(shuiping_line_id)
if (p.alt < first_point.alt) {
shuzhi.positions[0] = car
shuzhi.positions[1] = Cesium.Cartesian3.fromDegrees(p.lng, p.lat, first_point.alt)
shuiping.positions[0] = Cesium.Cartesian3.fromDegrees(p.lng, p.lat, first_point.alt)
shuiping.positions[1] = Cesium.Cartesian3.fromDegrees(first_point.lng, first_point.lat, first_point.alt)
} else {
shuzhi.positions[0] = Cesium.Cartesian3.fromDegrees(first_point.lng, first_point.lat, p.alt)
shuzhi.positions[1] = car
shuiping.positions[0] = Cesium.Cartesian3.fromDegrees(first_point.lng, first_point.lat, p.alt)
shuiping.positions[1] = Cesium.Cartesian3.fromDegrees(first_point.lng, first_point.lat, first_point.alt)
}
// shuizhi.positions = shuizhi_positions
}
if (xiebian_line_positions.length === 2) {
this.end()
}
}
this.event.mouse_left(leftEvent)
this.event.mouse_move((movement, car) => {
this.tip.setPosition(car, movement.endPosition.x, movement.endPosition.y)
let xiebian = this.id_map.get(xiebian_line_id)
if (xiebian_line_positions.length) {
xiebian.positions = xiebian_line_positions.concat(car)
let p = this.cartesian3Towgs84(car, this.viewer)
let shuzhi = this.id_map.get(shuizhi_line_id)
let shuiping = this.id_map.get(shuiping_line_id)
if (p.alt < first_point.alt) {
shuzhi.positions[0] = car
shuzhi.positions[1] = Cesium.Cartesian3.fromDegrees(p.lng, p.lat, first_point.alt)
shuiping.positions[0] = Cesium.Cartesian3.fromDegrees(p.lng, p.lat, first_point.alt)
shuiping.positions[1] = Cesium.Cartesian3.fromDegrees(first_point.lng, first_point.lat, first_point.alt)
} else {
shuzhi.positions[0] = Cesium.Cartesian3.fromDegrees(first_point.lng, first_point.lat, p.alt)
shuzhi.positions[1] = car
shuiping.positions[0] = Cesium.Cartesian3.fromDegrees(first_point.lng, first_point.lat, p.alt)
shuiping.positions[1] = Cesium.Cartesian3.fromDegrees(first_point.lng, first_point.lat, first_point.alt)
}
// shuizhi.positions = shuizhi_positions
}
})
this.event.mouse_right((movement, car) => {
this.end()
})
this.event.gesture_pinck_start((movement, cartesian) => {
let startTime = new Date()
let pos = {
position: {
x: (movement.position1.x + movement.position2.x) / 2,
y: (movement.position1.y + movement.position2.y) / 2
}
}
this.event.gesture_pinck_end(() => {
let endTime = new Date()
if (endTime - startTime >= 500) {
// 长按取消
this.end()
}
else {
leftEvent(pos, cartesian)
}
})
})
}
}
/**
* 结束测量
*/
end() {
super.end();
}
/**
* 清除测量
*/
destroy() {
super.destroy()
}
}
export default MeasureTriangle

View File

@ -0,0 +1,197 @@
/**
* @name: index
* @author: Administrator
* @date: 2022-07-11 17:28
* @descriptionindex
* @update: 2022-07-11 17:28
*/
import Measure from "../index"
/**@extends Measure*/
class MeasureTyArea extends Measure {
/**
* @constructor
* @param sdk
* @description 投影面积测量
* */
constructor(sdk, options = {}) {
super(sdk, options);
this.options.lineColor = '#ffdf53'
this.polygon_id = ""
}
static create_polygon(that) {
let id = that.randomString()
let scaleByDistance = new Cesium.NearFarScalar(2000, 1, 100000, 0)
let e = that.viewer.entities.add(
new Cesium.Entity({
id: id,
label: {
text: new Cesium.CallbackProperty(() => {
return that.text
}, false),
//标注文字描述
font: '20px Microsoft YaHei',
fillColor: Cesium.Color.fromCssColorString('#ffffff'),
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
//标注的遮挡距离设置为100则视角与标注的距离大于100米时会有遮挡
// distanceDisplayCondition: this.distanceDisplayCondition,
disableDepthTestDistance: Number.POSITIVE_INFINITY,
// scaleByDistance,
scale: 1,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
},
position: new Cesium.CallbackProperty(() => {
return that.center
}, false),
polygon: {
classificationType: Cesium.ClassificationType.BOTH,
hierarchy: new Cesium.CallbackProperty((e) => {
return new Cesium.PolygonHierarchy(that.positions)
}, false),
material: new Cesium.Color.fromCssColorString(that.options.color || that.defaultColor),
zIndex: 99999999
},
polyline: {
positions: new Cesium.CallbackProperty(() => {
if (that.positions.length)
return that.positions.concat(that.positions[0])
return that.positions
}, false),
width: 2,
material: new Cesium.PolylineDashMaterialProperty({
color: new Cesium.Color.fromCssColorString(that.options.lineColor || that.defaultColor),
dashLength: 20, //短划线长度
}),
clampToGround: true,
zIndex: 99999999
}
})
)
return id
}
/**
* 开始测量
*/
start() {
if (!YJ.Measure.GetMeasureStatus()) {
super.start()
this.ids = []
this.positions = []
this.text = ""
this.center = new Cesium.Cartesian3()
this.cachePositions = []
let height = 0
let lastArea = 0
let lastcneter
let leftEvent = (movement, car) => {
if (this.ids.length === 0) {
this.polygon_id = MeasureTyArea.create_polygon(this)
}
this.cachePositions.push({ ...car })
this.ids.push(this.create_point({ ...car }, false))
let po = this.cartesian3Towgs84({ ...car }, this.viewer)
if (po.alt > height) {
height = po.alt
}
this.positions = this.cachePositions.concat({ ...car })
this.tip.setPosition({ ...car }, movement.position.x, movement.position.y)
if (this.positions.length > 2) {
let arr = []
this.positions.forEach(item => {
let p = this.cartesian3Towgs84(item, this.viewer)
arr.push({ lng: p.lng, lat: p.lat })
})
let center = this.computeCenter(arr)
let area = this.computeArea(arr)
lastArea = area
this.center = new Cesium.Cartesian3.fromDegrees(center.lng, center.lat, height)
lastcneter = this.center
this.text = "投影面积:" + area + " ㎡"
}
}
this.event.mouse_left(leftEvent)
this.event.mouse_move((movement, car) => {
this.tip.setPosition({ ...car }, movement.endPosition.x, movement.endPosition.y)
this.positions = this.cachePositions.concat({ ...car })
if (this.positions.length > 2) {
let arr = []
this.positions.forEach(item => {
let p = this.cartesian3Towgs84(item, this.viewer)
arr.push({ lng: p.lng, lat: p.lat })
})
let center = this.computeCenter(arr)
let area = this.computeArea(arr)
this.center = new Cesium.Cartesian3.fromDegrees(center.lng, center.lat, height)
this.text = "投影面积:" + area + " ㎡"
}
})
this.event.mouse_right((movement, car) => {
this.positions = this.cachePositions
this.center = lastcneter
if (this.positions.length < 3) {
this.text = ""
let error = '面积计算至少需要三个坐标!'
console.warn(error)
window.ELEMENT && window.ELEMENT.Message({
message: error,
type: 'warning',
duration: 1500
});
this.destroy()
}
else {
this.text = "投影面积:" + lastArea + " ㎡"
}
this.end()
})
this.event.gesture_pinck_start((movement, cartesian) => {
let startTime = new Date()
let pos = {
position: {
x: (movement.position1.x + movement.position2.x) / 2,
y: (movement.position1.y + movement.position2.y) / 2
}
}
this.event.gesture_pinck_end(() => {
let endTime = new Date()
if (endTime - startTime >= 500) {
// 长按取消
this.positions = this.cachePositions
this.end()
}
else {
leftEvent(pos, cartesian)
}
})
})
}
}
/**
* 清除测量
*/
destroy() {
[this.polygon_id, ...this.ids].forEach(id => {
this.remove_entity(id)
})
super.destroy()
}
/**
* 结束测量
*/
end() {
super.end()
}
}
export default MeasureTyArea

16
src/Measure/clear.js Normal file
View File

@ -0,0 +1,16 @@
/**
* @name: clear
* @author: Administrator
* @date: 2022-07-11 15:28
* @descriptionclear
* @update: 2022-07-11 15:28
*/
function Clear() {
YJ.Measure.Measures.forEach(m => {
m.destroy()
})
YJ.Measure.Measures = []
}
export {Clear}

80
src/Measure/index.js Normal file
View File

@ -0,0 +1,80 @@
import MouseEvent from "../Event";
import MouseTip from "../MouseTip";
import Tools from "../Tools";
/**
* @name: measure
* @author: Administrator
* @date: 2022-07-11 10:52
* @descriptionmeasure
* @update: 2022-07-11 10:52
*/
class Measure extends Tools {
constructor(sdk, options = {text: "左键开始,右键结束;"}) {
super(sdk, options)
this.options = {...options}
this.event = new MouseEvent(sdk)
this.tip = new MouseTip(options.text, sdk)
this.viewer = sdk.viewer
this.defaultColor = 'rgba(246,49,49,0.55)'
this.ids = []
YJ.Measure.Measures.push(this)
this._isDestroy = false
// this.pickStatus = {pick: YJ.getEarth().interaction.picking.enabled}
}
start() {
this.setPickStatus(false)
YJ.Measure.SetMeasureStatus(true)
}
destroy() {
// YJ.Measure.Measures.pop()
this._isDestroy = true
this.end()
this.ids.forEach(id => {
this.remove_entity(id)
})
}
end() {
// this.ids.forEach(id => {
// this.remove_entity(id)
// })
//还原上一次的状态
// this.setPickStatus(this.pickStatus.pick)
YJ.Measure.SetMeasureStatus(false)
this.tip && this.tip.destroy()
this.event && this.event.destroy()
this.tip = null
this.event = null
}
create_point(cartesian,show = true) {
let id = this.randomString()
let p = this.cartesian3Towgs84(cartesian, this.viewer)
this.viewer.entities.add(
new Cesium.Entity({
id: id,
position: Cesium.Cartesian3.fromDegrees(p.lng, p.lat, p.alt),
billboard: {
show: show,
image: this.getSourceRootPath() + '/img/point.png',
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
disableDepthTestDistance: Number.POSITIVE_INFINITY,
color: Cesium.Color.WHITE.withAlpha(0.99)
}
})
)
return id
}
remove_entity(id) {
this.viewer.entities.removeById(id)
}
}
export default Measure

123
src/MouseTip/index.js Normal file
View File

@ -0,0 +1,123 @@
/**
* @name: index
* @author: Administrator
* @date: 2022-06-14 14:37
* @descriptionindex
* @update: 2022-06-14 14:37
*/
import Tools from "../Tools";
//鼠标tip
export default class MouseTip {
constructor(text = '左键开始,右键结束', sdk) {
this.point = undefined
this.text = text
this.div = undefined
this.mouse_type = 0
this.position = new Cesium.Cartesian3()
this.viewer = sdk.viewer
this.create_tip(this.viewer)
}
set_text(text) {
let textElm = this.div.getElementsByTagName('p')[0]
textElm.innerText = text
}
get_mouse_style(type) {
let url = 'lib/img/'
let style = '' //默认的鼠标箭头样式
switch (type) {
case 1:
style = 'move.png' //移动样式
break
default:
style = 'arrow.png'
break
}
return 'url(' + url + style + '),auto'
}
create_tip(viewer) {
// let tool = new Tools()
// this.point = viewer.entities.add(
// new Cesium.Entity({
// position: new Cesium.CallbackProperty(() => {
// return this.position
// }, false),
// billboard: {
// image: tool.getSourceRootPath() + '/img/point.png',
// verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
// disableDepthTestDistance: 100000000
// }
// })
// )
// tool = null
// this.style_tip(viewer, this.mouse_type)
this.create_tooltip()
}
setPosition(position, x, y) {
this.position = position
this.move_tooltip(x, y)
}
destroy() {
this.viewer.entities.remove(this.point)
this.remove_tooltip()
// this.style_tip(viewer)
}
create_tooltip() {
let tool = new Tools()
this.div = document.createElement('div')
let c = "#ec131a"
this.div.setAttribute(
'style',
'position: absolute;z-index: 777;color: ' + c + ';left:10px;top:0px;pointer-events: none;'
)
let textElm = document.createElement('p')
textElm.style.margin = '0px'
textElm.style.padding = '0px'
textElm.innerText = this.text
this.div.appendChild(textElm)
let imgElm = document.createElement('div')
imgElm.style.width = '12px'
imgElm.style.height = '12px'
imgElm.style.background = `url(${tool.getSourceRootPath() + '/img/point.png'}) 100% 100% no-repeat`
imgElm.style.backgroundSize = '100% 100%'
imgElm.style.position = 'absolute'
imgElm.style.left = '-36px'
imgElm.style.top = '-4px'
this.div.style.display = 'none'
this.div.appendChild(imgElm)
tool = null
document.querySelector('body').appendChild(this.div)
}
/*移动时的鼠标样式*/
style_tip(viewer, type = 0) {
viewer._element.style.cursor = this.get_mouse_style(type)
}
remove_tooltip() {
document.querySelector('body').contains(this.div) && document.querySelector('body').removeChild(this.div)
}
move_tooltip(x, y) {
let top = 0
let left = 0
this.div.style.display = 'block'
if (this.viewer && this.viewer._element) {
let element = this.viewer._element.getElementsByClassName('cesium-widget')[0].getElementsByTagName('canvas')[0]
top = element.getBoundingClientRect().top + window.scrollY
left = element.getBoundingClientRect().left + window.scrollX
}
this.div.style.left = x + 30 + left + 'px'
this.div.style.top = y + top + 'px'
}
}

View File

@ -0,0 +1,89 @@
import MouseTip from '../../MouseTip/index'
import MouseEvent from '../../Event/index'
import Draw from '../../Draw/draw'
class DrawTakeOff extends Draw {
/**
* @constructor
* @desc 获取坐标点
* */
constructor(sdk, options = {}) {
super(sdk, options)
this.options.tipText = options.tipText
? options.tipText
: '左键确定,右键结束;'
}
/**
* @desc 开始动态获取坐标点
* @method start
* @param cb {function} 回调函数
* @memberOf DrawPoint
* @example draw.start((err,position)=>{
*
* })
* */
start(cb) {
// eslint-disable-next-line no-undef
if (YJ.Measure.GetMeasureStatus()) {
cb('上一次测量未结束')
} else {
let car = undefined
// eslint-disable-next-line no-undef
YJ.Measure.SetMeasureStatus(true)
// this.options
this.tip = new MouseTip(this.options.tipText, this.sdk)
this.event = new MouseEvent(this.sdk)
this.isEntity = false
this.event.mouse_left((movement, cartesian) => {
this.end()
let p = this.cartesian3Towgs84(car || cartesian, this.viewer)
var pickedObject = this.viewer.scene.pick(movement.position)
if (
Cesium.defined(pickedObject) &&
Cesium.defined(pickedObject.id) &&
pickedObject.id.id === window.airportEntity.options.id
) {
this.isEntity = true
}
cb(null, p, this.isEntity)
})
this.event.mouse_right((movement, cartesian) => {
this.end()
cb(false)
})
this.event.mouse_move((movement, cartesian) => {
car = cartesian
this.tip.setPosition(
cartesian,
movement.endPosition.x,
movement.endPosition.y
)
})
this.event.gesture_pinck_start((movement, cartesian) => {
let startTime = new Date()
this.event.gesture_pinck_end(() => {
let endTime = new Date()
if (endTime - startTime >= 500) {
this.end()
cb(false)
} else {
this.end()
let p = this.cartesian3Towgs84(car || cartesian, this.viewer)
cb(null, p)
}
})
})
}
}
end() {
YJ.Measure.SetMeasureStatus(false)
this.event.destroy()
this.tip.destroy()
}
}
export default DrawTakeOff

View File

@ -0,0 +1,112 @@
// 根据米生成航线
function flyLine(earth, positions, unit) {
let arr = []
positions.forEach(item => {
arr.push([item.lng, item.lat])
})
arr.push(arr[0])
// eslint-disable-next-line no-undef
const turfPolygon = turf.polygon([arr])
// 获取四至
// eslint-disable-next-line no-undef
const turfExtent = turf.bbox(turfPolygon)
// 在turfPolygon中按网格取样点网格间距3米
// eslint-disable-next-line no-undef
const turfSamplePoints = turf.pointGrid(turfExtent, unit / 1000, {
units: 'kilometers',
mask: turfPolygon
})
// 将turf取样点转为Cesium的取样点
const cesiumSamplePoints = []
for (let i = 0; i < turfSamplePoints.features.length; i++) {
const coord = turfSamplePoints.features[i].geometry.coordinates
cesiumSamplePoints.push([coord[0], coord[1]])
}
// 计算两点的距离
function fromTo(point1, point2) {
if (!point2) {
return
}
// eslint-disable-next-line no-undef
let from = turf.point(point1)
// eslint-disable-next-line no-undef
let to = turf.point(point2)
// eslint-disable-next-line no-undef
return Math.round(turf.distance(from, to) * 1000)
}
// 进行分组并进行奇数反转
let polylinePosition = []
let flag = 0
let index = -1
for (let i = 0; i < cesiumSamplePoints.length; i++) {
if (fromTo(cesiumSamplePoints[i], cesiumSamplePoints[i + 1]) > unit) {
index++
let arr = cesiumSamplePoints.slice(flag, i + 1)
if (index % 2 !== 0) {
arr.reverse()
}
polylinePosition.push(arr)
flag = i + 1
}
}
let arr2 = cesiumSamplePoints.slice(flag, cesiumSamplePoints.length)
if ((index + 1) % 2 !== 0) {
arr2.reverse()
}
polylinePosition.push(arr2)
return polylinePosition.flat()
}
// 获取高程
function sampleHeightMostDetailed(earth, positions) {
return earth.viewer.scene.sampleHeightMostDetailed([
new Cesium.Cartographic.fromDegrees(positions[0], positions[1])
])
}
// 计算高程
async function countHeight(earth, item) {
return await sampleHeightMostDetailed(earth, item)
}
function cartesian3Towgs84(earth, cartesian) {
const viewer = earth.viewer
var ellipsoid = viewer.scene.globe.ellipsoid
var cartesian3 = new Cesium.Cartesian3(cartesian.x, cartesian.y, cartesian.z)
var cartographic = ellipsoid.cartesianToCartographic(cartesian3)
var lat = Cesium.Math.toDegrees(cartographic.latitude)
var lng = Cesium.Math.toDegrees(cartographic.longitude)
var alt = cartographic.height < 0 ? 0 : cartographic.height
return {
longitude: lng,
latitude: lat,
height: alt
}
}
//更新路径高度
async function updateHeight(earth, height, positions, cb) {
let Cartesian = []
let locationList = []
for (let i = 0; i < positions.length; i++) {
const element = positions[i]
let Cartographic = await countHeight(earth, element)
if (isNaN(Cartographic[0].height)) {
Cartographic[0].height = 0
}
Cartographic[0].height = Cartographic[0].height + height
Cartesian.push(Cesium.Cartographic.toCartesian(Cartographic[0]))
if (i < positions.length) {
cb({
cur: i + 1,
total: positions.length
})
}
}
for (let i = 0; i < Cartesian.length; i++) {
locationList.push(cartesian3Towgs84(earth, Cartesian[i]))
}
let arr = [locationList, Cartesian]
cb(arr)
}
let GenerateRoute = {
flyLine,
updateHeight
}
export default GenerateRoute

View File

@ -0,0 +1,272 @@
export default class BillordPointLine {
constructor(options, viewer) {
this.options = { ...options }
this.pointEntity = null
this.billboardEntity = null
this.lineEntity = null
this.updatedPosition = []
this.pointUpdatedPosition = []
this.viewer = viewer
this.handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
this.pinBuilder = new Cesium.PinBuilder()
this.index = null
//定义屏幕点击事件处理器
BillordPointLine.setDefaultValue(this)
BillordPointLine.init(this)
}
static setDefaultValue(that) {
that.options.positions = that.options.positions || {}
that.options.normalHeight = that.options.normalHeight || 100
that.options.airHeight = that.options.airHeight || 100
that.options.image = that.options.image || '/static/img/cluster2.png'
that.options.show = that.options.show || true
that.options.index = that.options.index || 1
that.options.saveFun = that.options.saveFun || null
that.options.selectFun = that.options.selectFun || null
that.options.keyboard = that.options.keyboard ?? true
that.options.updateFrustumFun = that.options.updateFrustumFun || null
that.options.frustum = that.options.frustum || null
}
static init(that) {
let positions = that.options.positions
// 添加一个Point稍微偏离地面高度使其完全可见
that.pointEntity = that.viewer.entities.add({
show: that.options.show,
position: Cesium.Cartesian3.fromDegrees(positions.lng, positions.lat, 0), // 地面上
point: {
pixelSize: 8,
color: Cesium.Color.WITHE,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, // 使用相对地面或贴地,
disableDepthTestDistance: 0
}
})
//
let pinIndex = that.pinBuilder
.fromText(
that.options.index,
Cesium.Color.fromCssColorString('#00d590'),
36
)
.toDataURL()
let altitude = 0
if (positions.altitude) {
altitude = positions.altitude
} else {
altitude = that.options.normalHeight
}
// 添加一个Billboard
that.billboardEntity = that.viewer.entities.add({
show: that.options.show,
position: Cesium.Cartesian3.fromDegrees(
positions.lng,
positions.lat,
positions.alt + that.options.normalHeight
),
// 判断altitude是否有值
label: {
text: `Lat: ${positions.lng.toFixed(8)}\nLon: ${positions.lat.toFixed(
8
)}\nAlt: ${altitude.toFixed(8)}m`,
font: '14px sans-serif',
fillColor: Cesium.Color.YELLOW,
outlineColor: Cesium.Color.BLACK,
outlineWidth: 2,
pixelOffset: new Cesium.Cartesian2(0, -60), // 标签偏移量,防止重叠
heightReference: Cesium.HeightReference.RELATIVE_TO_TERRAIN, // 确保标签与地面贴合
show: false
},
billboard: {
image: pinIndex, // 示例图像路径
verticalOrigin: Cesium.VerticalOrigin.BOTTOM, // 图像底部对齐
width: 36,
height: 36
},
index: that.options.index
})
// 创建一个连接Point和Billboard的竖线
that.lineEntity = that.viewer.entities.add({
show: that.options.show,
polyline: {
positions: new Cesium.CallbackProperty(() => {
return [
that.pointEntity.position.getValue(),
that.billboardEntity.position.getValue()
]
}, false),
width: 1,
material: new Cesium.PolylineOutlineMaterialProperty({
outlineColor: Cesium.Color.GAINSBORO,
outlineWidth: 1,
color: Cesium.Color.WITHE
}),
zIndex: 99999999
}
})
if (that.options.keyboard) {
that.changeAltitude()
}
that.handler.setInputAction(function(movement) {
var pickedObject = that.viewer.scene.pick(movement.position)
if (
Cesium.defined(pickedObject) &&
Cesium.defined(pickedObject.id) &&
pickedObject.id === that.billboardEntity
) {
if (that.options.selectFun) {
that.options.selectFun(that.billboardEntity.index - 1)
}
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
}
// 改变高度
changeAltitude() {
var isMouseDown = false
var startPosition
var initialHeight
let that = this
let HHH = false
// 标识Alt键是否被按下
document.addEventListener('keydown', function(event) {
const key = event.key // 获取按下的键名
// 检查特定键是否被按下
if (key === 'h') {
HHH = true
}
})
document.addEventListener('keyup', function(event) {
HHH = false
})
// 按下鼠标左键
this.handler.setInputAction(function(movement) {
var pickedObject = that.viewer.scene.pick(movement.position)
if (
Cesium.defined(pickedObject) &&
Cesium.defined(pickedObject.id) &&
pickedObject.id === that.billboardEntity
) {
isMouseDown = true
startPosition = movement.position
// 获取Billboard当前的地理高度
var positionCartographic = Cesium.Cartographic.fromCartesian(
that.billboardEntity.position.getValue()
)
initialHeight = positionCartographic.height
}
}, Cesium.ScreenSpaceEventType.LEFT_DOWN)
// 移动鼠标
this.handler.setInputAction(function(movement) {
if (isMouseDown && HHH == false) {
// 移动位置
var newCartesian = that.viewer.scene.pickPosition(movement.endPosition)
that.disableCameraDrag(that.viewer, false)
if (newCartesian) {
var newCartographic = Cesium.Cartographic.fromCartesian(newCartesian)
// 保持高度不变
var newLongitude = newCartographic.longitude
var newLatitude = newCartographic.latitude
var updatedPosition = Cesium.Cartesian3.fromRadians(
newLongitude,
newLatitude,
initialHeight
)
var pointUpdatedPosition = Cesium.Cartesian3.fromRadians(
newLongitude,
newLatitude,
0
)
that.billboardEntity.position = new Cesium.CallbackProperty(() => {
return updatedPosition
}, false)
that.billboardEntity.label.text = `Lat: ${Cesium.Math.toDegrees(
newLongitude
).toFixed(6)}\nLon: ${Cesium.Math.toDegrees(newLatitude).toFixed(
6
)}\nAlt: ${initialHeight.toFixed(2)}m`
that.pointEntity.position = new Cesium.CallbackProperty(() => {
return pointUpdatedPosition
}, false)
}
}
if (isMouseDown && HHH) {
console.log(HHH)
// 改变高度
var endPosition = movement.endPosition
var deltaY = startPosition.y - endPosition.y // 计算Y轴方向上的移动距离
// 根据鼠标移动的距离来调整高度
var newHeight = initialHeight + deltaY
// 更新billboard位置
var positionCartographic = Cesium.Cartographic.fromCartesian(
that.billboardEntity.position.getValue()
)
var newPosition = Cesium.Cartesian3.fromDegrees(
Cesium.Math.toDegrees(positionCartographic.longitude),
Cesium.Math.toDegrees(positionCartographic.latitude),
newHeight
)
// 禁用相机
that.disableCameraDrag(that.viewer, false)
that.billboardEntity.position = new Cesium.CallbackProperty(() => {
return newPosition
}, false)
that.billboardEntity.label.text = `Lat: ${Cesium.Math.toDegrees(
positionCartographic.longitude
).toFixed(6)}\nLon: ${Cesium.Math.toDegrees(
positionCartographic.latitude
).toFixed(6)}\nAlt: ${newHeight.toFixed(2)}m`
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
// 松开鼠标左键
this.handler.setInputAction(function(movement) {
var pickedObject = that.viewer.scene.pick(movement.position)
isMouseDown = false // 禁用相机
HHH = false //
that.disableCameraDrag(that.viewer, true)
// 更新frustum的位置
if (
Cesium.defined(pickedObject) &&
Cesium.defined(pickedObject.id) &&
pickedObject.id === that.billboardEntity
) {
if (that.options.saveFun) {
that.options.saveFun(null, false)
}
if (that.options.selectFun) {
that.options.selectFun(that.billboardEntity.index - 1)
}
that.options.frustum.updatePositionHeight(
that.billboardEntity.position.getValue()
)
}
}, Cesium.ScreenSpaceEventType.LEFT_UP)
}
disableCameraDrag(viewer, bool) {
viewer.scene.screenSpaceCameraController.enableRotate = bool
viewer.scene.screenSpaceCameraController.enableTranslate = bool
viewer.scene.screenSpaceCameraController.enableZoom = bool
viewer.scene.screenSpaceCameraController.enableTilt = bool
viewer.scene.screenSpaceCameraController.enableLook = bool
}
get show() {
return this.options.show
}
/**
* @param {boolean} bool
*/
set show(bool) {
if (typeof bool === 'boolean') {
this.pointEntity.show = bool
this.billboardEntity.show = bool
this.lineEntity.show = bool
}
}
remove() {
this.viewer.entities.remove(this.pointEntity)
this.viewer.entities.remove(this.billboardEntity)
this.viewer.entities.remove(this.lineEntity)
}
}

673
src/Obj/AirLine/frustum.js Normal file
View File

@ -0,0 +1,673 @@
export default class Frustum {
constructor(options, viewer, viewer1) {
this.options = { ...options }
this.viewer = viewer
this.viewer1 = viewer1
this.head = 0
this.pitch = 90
this.po = 0.00001
this.position = null
this.hpr = null
this.currentFrustumOutline = null
this.frustum = null
this.setInterval1 = null
this.webrtc = null
// 设置默认值
Frustum.setDefaultValue(this)
this.create()
}
static setDefaultValue(that) {
that.options.position = that.options.position || {}
that.options.fov = that.options.fov || 30
that.options.aspectRatio = that.options.aspectRatio || 1
that.options.near = that.options.near || 1
that.options.far = that.options.far || 120
that.options.heading = that.options.heading || 0
that.options.pitch = that.options.pitch || 90
that.options.roll = that.options.roll || 0
that.options.show = that.options.show ?? true
that.options.videoUrl = that.options.videoUrl || ''
that.options.index = that.options.index || 0
that.options.arr = that.options.arr || []
that.options.normalHeight = that.options.normalHeight || 100
}
// 初始化视锥体
create() {
this.frustum = new Cesium.PerspectiveFrustum({
fov: Cesium.Math.toRadians(this.options.fov),
aspectRatio: this.options.aspectRatio,
near: this.options.near,
far: this.options.far
})
const { lng, lat, alt } = this.options.position
const { heading, pitch, roll } = this.options
this.position = Cesium.Cartesian3.fromDegrees(
lng,
lat,
alt + this.options.normalHeight
)
this.hpr = new Cesium.HeadingPitchRoll(
Cesium.Math.toRadians(heading),
Cesium.Math.toRadians(pitch),
Cesium.Math.toRadians(roll)
)
this.drawFrustumOutline()
this.drawFrustumFilled()
this.monitorKeyboard()
this.updateFrustumSquareBase(40)
this.syncHpr()
if (this.options.videoUrl) {
this.addVideoToFrustumTop2()
}
}
// 监听键盘事件
monitorKeyboard() {
const keyActions = {
KeyQ: () => this.setIntervalhpr(-0.45),
KeyE: () => this.setIntervalhpr(0.45),
KeyB: () => this.setIntervalhprr(-0.45),
KeyN: () => this.setIntervalhprr(0.45),
KeyW: () => this.updateFrustumPosition('move', -0.00001),
KeyS: () => this.updateFrustumPosition('move', 0.00001),
KeyA: () => this.updateFrustumPosition('move', -0.00001, 0),
KeyD: () => this.updateFrustumPosition('move', 0.00001, 0),
KeyC: () => this.updateFrustumHeight(1), // 增加高度
KeyZ: () => this.updateFrustumHeight(-1) // 降低高度
}
this.keydownHandler = event => {
if (keyActions[event.code]) keyActions[event.code]()
}
this.keyupHandler = () => this.stopFrustumRotation()
document.addEventListener('keydown', this.keydownHandler)
document.addEventListener('keyup', this.keyupHandler)
}
// 渲染视频
addVideoToFrustumTop() {
// 创建视频元素
const videoElement = document.createElement('video')
videoElement.width = 640
videoElement.height = 360
videoElement.autoplay = true
videoElement.loop = true
videoElement.muted = true
// videoElement.style.display = 'none'; // 隐藏视频元素
document.body.appendChild(videoElement)
// 使用 flv.js 播放 FLV 视频
if (flvjs.isSupported()) {
const flvPlayer = flvjs.createPlayer({
// url: 'http://zmkg.cqet.top:9991/live/2pUbcgTrly3mIDuxsDXN9h3hqcEKU6TlsV_YeIDyqHqXGzXafqWokXdU1q6j_S7hTCP7HynZQIsuNM6KQ5l-ag==.flv',
type: 'flv',
isLive: true,
hasAudio: false,
enableStashBuffer: true, //
enableWorker: true,
autoCleanupSourceBuffer: true, //自动清除缓存
url: this.options.videoUrl
})
flvPlayer.attachMediaElement(videoElement)
flvPlayer.load()
flvPlayer.play()
} else {
console.error('FLV.js is not supported in this browser.')
}
const corners = this.computeFrustumCorners(
this.frustum,
this.position,
this.hpr
)
// 创建 PolygonGeometry 并应用视频作为纹理
const polygonHierarchy = new Cesium.PolygonHierarchy([
corners.bottomLeft,
corners.bottomRight,
corners.topRight,
corners.topLeft
])
this.videoEntity = this.viewer.entities.add(
new Cesium.Entity({
id: '22222222',
show: true,
polygon: {
hierarchy: polygonHierarchy
}
})
)
videoElement.addEventListener('loadeddata', () => {
this.videoEntity.polygon.material = videoElement // 确保视频纹理加载后再设置
})
}
// 渲染视频
async addVideoToFrustumTop2() {
// 创建视频元素
const videoElement = document.createElement('video')
videoElement.width = 640
videoElement.height = 360
videoElement.autoplay = true
videoElement.loop = true
videoElement.muted = true
// videoElement.style.display = 'none'; // 隐藏视频元素
document.body.appendChild(videoElement)
await this.startPlay(videoElement, this.options.videoUrl)
const corners = this.computeFrustumCorners(
this.frustum,
this.position,
this.hpr
)
// 创建 PolygonGeometry 并应用视频作为纹理
const polygonHierarchy = new Cesium.PolygonHierarchy([
corners.bottomLeft,
corners.bottomRight,
corners.topRight,
corners.topLeft
])
this.videoEntity = this.viewer.entities.add(
new Cesium.Entity({
id: '22222222',
show: true,
polygon: {
hierarchy: polygonHierarchy
}
})
)
videoElement.addEventListener('loadeddata', () => {
this.videoEntity.polygon.material = videoElement // 确保视频纹理加载后再设置
})
}
async startPlay(element, url) {
// Close existing SDK instance if any
if (this.webrtc) {
this.webrtc.close()
}
// Initialize a new SDK instance
this.webrtc = new SrsRtcWhipWhepAsync()
// Bind the video player to the SDK stream
element.srcObject = this.webrtc.stream
try {
const session = await this.webrtc.play(url)
console.log(session)
// this.sessionId = session.sessionid
// this.simulatorUrl = `${session.simulator}?drop=1&username=${session.sessionid}`
} catch (error) {
// console.error('Error playing stream:', error)
this.webrtc.close()
// this.playerVisible = false
}
}
// 计算视锥体远裁剪面(大面)的四个角点
computeFrustumCorners(frustum, position, hpr) {
const tanFov = Math.tan(frustum.fov * 0.5)
const farHeight = frustum.far * tanFov
const farWidth = farHeight * frustum.aspectRatio
const topLeft = new Cesium.Cartesian3(-farWidth, farHeight, -frustum.far)
const topRight = new Cesium.Cartesian3(farWidth, farHeight, -frustum.far)
const bottomLeft = new Cesium.Cartesian3(
-farWidth,
-farHeight,
-frustum.far
)
const bottomRight = new Cesium.Cartesian3(
farWidth,
-farHeight,
-frustum.far
)
const transform = Cesium.Transforms.headingPitchRollToFixedFrame(
position,
hpr
)
// console.log('transform111111111111111111111111', transform)
return {
topLeft: Cesium.Matrix4.multiplyByPoint(
transform,
topLeft,
new Cesium.Cartesian3()
),
topRight: Cesium.Matrix4.multiplyByPoint(
transform,
topRight,
new Cesium.Cartesian3()
),
bottomLeft: Cesium.Matrix4.multiplyByPoint(
transform,
bottomLeft,
new Cesium.Cartesian3()
),
bottomRight: Cesium.Matrix4.multiplyByPoint(
transform,
bottomRight,
new Cesium.Cartesian3()
)
}
}
// 封装的函数:更新 Polygon 面的位置
updatePolygonPosition() {
const corners = this.computeFrustumCorners(
this.frustum,
this.position,
this.hpr
)
this.videoEntity.polygon.hierarchy = new Cesium.CallbackProperty(e => {
return new Cesium.PolygonHierarchy([
corners.bottomLeft,
corners.bottomRight,
corners.topRight,
corners.topLeft
])
})
}
// 更新锥体底部为正方形的方法
updateFrustumSquareBase(value) {
// 将输入值范围从 56 到 1 映射到面积范围 10000 到 100
const minArea = 100 // 最小面积
const maxArea = 10000 // 最大面积
// 映射公式(反转映射)
const newArea = ((56 - value) / (56 - 1)) * (maxArea - minArea) + minArea
// 确保aspectRatio保持为1正方形
this.frustum.aspectRatio = 1
// 根据面积计算正方形边长
const sideLength = Math.sqrt(newArea)
// 远平面距离
const far = this.frustum.far
// 计算新的fov
const fov = 2 * Math.atan(sideLength / (2 * far))
// 更新视锥体的fov
this.frustum.fov = fov
// 重新绘制视锥体轮廓和填充
this.drawFrustumOutline()
this.drawFrustumFilled()
this.syncHpr()
}
updateFrustumHeight(deltaHeight) {
const cartographic = Cesium.Cartographic.fromCartesian(this.position)
cartographic.height += deltaHeight // 更新高度
this.position = Cesium.Cartesian3.fromDegrees(
Cesium.Math.toDegrees(cartographic.longitude),
Cesium.Math.toDegrees(cartographic.latitude),
cartographic.height
)
this.options.position.alt = cartographic.height
// this.options.arr[
// this.options.index
// ] = this.viewer.scene.globe.ellipsoid.cartographicToCartesian(cartographic)
this.syncHpr()
this.drawFrustumOutline() // 重新绘制视锥体轮廓
this.drawFrustumFilled()
}
// 更新position变化后的视锥体属性
updatePositionHeight(p) {
this.options.position = this.cartesian3Towgs84(p)
this.syncHpr()
this.drawFrustumOutline() // 重新绘制视锥体轮廓
this.drawFrustumFilled()
}
cartesian3Towgs84(cartesian) {
var ellipsoid = this.viewer.scene.globe.ellipsoid
var cartesian3 = new Cesium.Cartesian3(
cartesian.x,
cartesian.y,
cartesian.z
)
var cartographic = ellipsoid.cartesianToCartographic(cartesian3)
var lat = Cesium.Math.toDegrees(cartographic.latitude)
var lng = Cesium.Math.toDegrees(cartographic.longitude)
var alt = cartographic.height < 0 ? 0 : cartographic.height
return {
lng: lng,
lat: lat,
alt: alt
}
}
setIntervalhpr(num) {
this.stopFrustumRotation() // 先停止当前的定时器
this.setInterval1 = setInterval(() => {
this.head += num
this.updateFrustumHPR(Cesium.Math.toRadians(this.head), this.pitch)
}, 10)
}
setIntervalhprr(num) {
this.stopFrustumRotation() // 先停止当前的定时器
this.setInterval1 = setInterval(() => {
// 限制 pitch 在 [60, 180] 范围内
this.pitch = Math.max(60, Math.min(180, this.pitch + num))
this.updateFrustumHPR(this.head, Cesium.Math.toRadians(this.pitch))
}, 10)
}
// 停止视锥体旋转
stopFrustumRotation() {
if (this.setInterval1) {
clearInterval(this.setInterval1)
this.setInterval1 = null
}
}
// 新增:绘制填充的视锥体
drawFrustumFilled() {
let that = this
// console.log('that.options.show', that.options.show)
const transform = Cesium.Transforms.headingPitchRollToFixedFrame(
this.position,
this.hpr
)
const frustumGeometry = new Cesium.FrustumGeometry({
frustum: this.frustum,
origin: Cesium.Matrix4.getTranslation(transform, new Cesium.Cartesian3()),
orientation: Cesium.Quaternion.fromRotationMatrix(
Cesium.Matrix4.getRotation(transform, new Cesium.Matrix3())
)
})
if (this.currentFrustumFilled) {
this.viewer.scene.primitives.remove(this.currentFrustumFilled)
}
this.currentFrustumFilled = new Cesium.Primitive({
geometryInstances: new Cesium.GeometryInstance({
geometry: frustumGeometry,
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
Cesium.Color.fromAlpha(Cesium.Color.YELLOW, 0.4) // 半透明黄色填充
)
}
}),
appearance: new Cesium.MaterialAppearance({
material: Cesium.Material.fromType('Color', {
color: Cesium.Color.fromAlpha(Cesium.Color.YELLOW, 0.4) // 填充颜色
}),
translucent: true
}),
asynchronous: false,
// show: false
show: that.options.show
})
this.viewer.scene.primitives.add(this.currentFrustumFilled)
}
// 绘制视锥体轮廓
drawFrustumOutline() {
let that = this
// console.log('that.options.show', that.options.show)
const transform = Cesium.Transforms.headingPitchRollToFixedFrame(
this.position,
this.hpr
)
const frustumOutlineGeometry = new Cesium.FrustumOutlineGeometry({
frustum: this.frustum,
origin: Cesium.Matrix4.getTranslation(transform, new Cesium.Cartesian3()),
orientation: Cesium.Quaternion.fromRotationMatrix(
Cesium.Matrix4.getRotation(transform, new Cesium.Matrix3())
)
})
if (this.currentFrustumOutline) {
this.viewer.scene.primitives.remove(this.currentFrustumOutline)
}
this.currentFrustumOutline = new Cesium.Primitive({
geometryInstances: new Cesium.GeometryInstance({
geometry: frustumOutlineGeometry,
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
Cesium.Color.YELLOW
)
}
}),
appearance: new Cesium.PolylineColorAppearance({
translucent: false
}),
asynchronous: false,
show: that.options.show
// show: false
})
this.viewer.scene.primitives.add(this.currentFrustumOutline)
}
// 更新视锥体位置
updateFrustumPosition(type = 'move', p, deg = 90, flag = true) {
if (type === 'move') {
// eslint-disable-next-line no-undef
const point = turf.point([
this.options.position.lng,
this.options.position.lat
])
const degreesValue = Cesium.Math.toDegrees(this.hpr.heading)
const bearing = degreesValue + deg
const options = { units: 'degrees' }
// eslint-disable-next-line no-undef
const destination = turf.destination(point, p, bearing, options).geometry
.coordinates
this.position = Cesium.Cartesian3.fromDegrees(
destination[0],
destination[1],
this.options.position.alt + this.options.normalHeight
)
this.options.position.lng = destination[0]
this.options.position.lat = destination[1]
this.viewer.camera.setView({
destination: Cesium.Cartesian3.fromDegrees(
destination[0],
destination[1],
this.viewer.camera.positionCartographic.height
)
})
}
if (type === 'update') {
this.position = p
this.options.videoUrl && this.updatePolygonPosition()
}
if (flag) {
this.syncHpr()
this.updateFrustumAttributes()
}
}
// 同步视角
syncHpr() {
// console.log('this.viewer1', this.viewer1);
if (this.viewer1) {
const { lng, lat, alt } = this.options.position
let pitch = -this.hpr.pitch - Cesium.Math.toRadians(-90.0)
this.viewer1.camera.setView({
destination: Cesium.Cartesian3.fromDegrees(
lng,
lat,
alt + this.options.normalHeight
),
orientation: {
heading: this.hpr.heading + Cesium.Math.toRadians(-90.0),
pitch,
roll: this.hpr.roll
}
})
}
}
// 更新视锥体的 HeadingPitchRoll
updateFrustumHPR(
h = this.head,
p = this.pitch,
r = 0,
flag = true,
type = ''
) {
function degreesToRadians(degrees) {
return (degrees * Math.PI) / 180.0
}
if (type == 'alone') {
this.hpr.heading = degreesToRadians(h)
this.hpr.pitch = degreesToRadians(p)
this.hpr.roll = degreesToRadians(r)
} else {
this.hpr.heading = Cesium.Math.negativePiToPi(h)
this.hpr.pitch = Cesium.Math.negativePiToPi(p)
this.hpr.roll = Cesium.Math.negativePiToPi(r)
}
if (flag) {
this.syncHpr()
this.updateFrustumAttributes()
}
}
// 用于更新
updateFrustumAttributes() {
let that = this
// 检查 position 和 hpr 是否已初始化
if (!this.position || !this.hpr) {
// eslint-disable-next-line no-console
console.error('Position or HPR is not defined:', this.position, this.hpr)
return
}
// 生成变换矩阵
const transform = Cesium.Transforms.headingPitchRollToFixedFrame(
this.position,
this.hpr
)
if (!transform) {
// eslint-disable-next-line no-console
console.error('Transform generation failed.')
return
}
try {
// 准备轮廓几何体和外观
const outlineGeometry = new Cesium.FrustumOutlineGeometry({
frustum: this.frustum,
origin: Cesium.Matrix4.getTranslation(
transform,
new Cesium.Cartesian3()
),
orientation: Cesium.Quaternion.fromRotationMatrix(
Cesium.Matrix4.getRotation(transform, new Cesium.Matrix3())
)
})
const outlineAppearance = new Cesium.PolylineColorAppearance({
translucent: false
})
const outlineColor = Cesium.ColorGeometryInstanceAttribute.fromColor(
Cesium.Color.YELLOW
)
// 准备填充几何体和外观
const filledGeometry = new Cesium.FrustumGeometry({
frustum: this.frustum,
origin: Cesium.Matrix4.getTranslation(
transform,
new Cesium.Cartesian3()
),
orientation: Cesium.Quaternion.fromRotationMatrix(
Cesium.Matrix4.getRotation(transform, new Cesium.Matrix3())
)
})
const filledAppearance = new Cesium.MaterialAppearance({
material: Cesium.Material.fromType('Color', {
color: Cesium.Color.YELLOW.withAlpha(0.5)
}),
translucent: true
})
const filledColor = Cesium.ColorGeometryInstanceAttribute.fromColor(
Cesium.Color.RED.withAlpha(0.5)
)
// 删除旧的 Primitive
if (this.currentFrustumOutline) {
this.viewer.scene.primitives.remove(this.currentFrustumOutline)
}
if (this.currentFrustumFilled) {
this.viewer.scene.primitives.remove(this.currentFrustumFilled)
}
// 创建并添加新的轮廓 Primitive
this.currentFrustumOutline = new Cesium.Primitive({
geometryInstances: new Cesium.GeometryInstance({
geometry: outlineGeometry,
attributes: { color: outlineColor }
}),
appearance: outlineAppearance,
asynchronous: false,
show: that.options.show
})
this.viewer.scene.primitives.add(this.currentFrustumOutline)
// 创建并添加新的填充 Primitive
this.currentFrustumFilled = new Cesium.Primitive({
geometryInstances: new Cesium.GeometryInstance({
geometry: filledGeometry,
attributes: { color: filledColor }
}),
appearance: filledAppearance,
asynchronous: false,
show: that.options.show
})
this.viewer.scene.primitives.add(this.currentFrustumFilled)
} catch (error) {
// eslint-disable-next-line no-console
console.error('Error in drawFrustum:', error)
}
}
// 调整视锥体的 near 和 far 平面
updateFrustumNearFar(newNear, newFar) {
this.frustum.near = newNear
this.frustum.far = newFar
this.drawFrustumOutline()
this.drawFrustumFilled()
}
// 调整视锥体的 fov
updateFrustumFov(newFov) {
this.frustum.fov = Cesium.Math.toRadians(newFov)
this.drawFrustumOutline()
this.drawFrustumFilled()
}
get show() {
return this.options.show
}
set show(bool) {
if (typeof bool === 'boolean') {
this.options.show = bool
this.currentFrustumOutline.show = bool
this.currentFrustumFilled.show = bool
}
}
remove() {
document.removeEventListener('keydown', this.keydownHandler)
document.removeEventListener('keyup', this.keyupHandler)
if (this.currentFrustumFilled) {
this.viewer.scene.primitives.remove(this.currentFrustumFilled)
}
if (this.currentFrustumOutline) {
this.viewer.scene.primitives.remove(this.currentFrustumOutline)
}
if (this.videoEntity) {
this.viewer.entities.remove(this.videoEntity)
}
}
}

257
src/Obj/AirLine/frustum2.js Normal file
View File

@ -0,0 +1,257 @@
export default class FRUSTUN {
constructor(options, viewer, viewer1) {
this.options = { ...options }
this.viewer = viewer
this.viewer1 = viewer1
this.head = 0
this.po = 0.00001
this.position = null
this.hpr = null
this.currentFrustumOutline = null
this.frustum = null
this.setInterval = null
FRUSTUN.setDefaultValue(this)
this.create()
}
static setDefaultValue(that) {
that.options.position = that.options.position || {}
that.options.fov = that.options.fov || 20
that.options.aspectRatio = that.options.aspectRatio || 1
that.options.near = that.options.near || 1
that.options.far = that.options.far || 100
that.options.heading = that.options.heading || 0
that.options.pitch = that.options.pitch || 90
that.options.roll = that.options.roll || 0
that.options.show = that.options.show || true
}
// 初始化视锥体
create() {
this.frustum = new Cesium.PerspectiveFrustum()
this.frustum.fov = Cesium.Math.toRadians(this.options.fov)
this.frustum.aspectRatio = 1.0 // 保持 aspectRatio 不变
this.frustum.near = 1.0
this.frustum.far = 50.0
// 设置初始视锥体位置和方向
let { lng, lat, alt } = this.options.position
let { heading, pitch, roll } = this.options
this.position = Cesium.Cartesian3.fromDegrees(lng, lat, alt + 100)
this.hpr = new Cesium.HeadingPitchRoll(
Cesium.Math.toRadians(heading),
Cesium.Math.toRadians(pitch),
Cesium.Math.toRadians(roll)
)
console.log(heading)
this.drawFrustumOutline()
this.monitorKeyboard()
}
setIntervalhpr(num) {
if (!this.setInterval1) {
this.setInterval1 = setInterval(() => {
this.head += num
this.updateFrustumHPR(Cesium.Math.toRadians(this.head))
}, 10)
}
}
// 监听 键盘事件
// monitorKeyboard() {
// let that = this;
// document.addEventListener("keydown", function (event) {
// switch (event.code) {
// case "KeyQ":
// that.setIntervalhpr(-0.45);
// break;
// case "KeyE":
// that.setIntervalhpr(0.45);
// break;
// case "KeyW":
// that.updateFrustumPosition("move", -0.00001);
// break;
// case "KeyS":
// that.updateFrustumPosition("move", 0.00001);
// break;
// case "KeyA":
// that.updateFrustumPosition("move", -0.00001, 0);
// break;
// case "KeyD":
// that.updateFrustumPosition("move", 0.00001, 0);
// break;
// default:
// break;
// }
// });
// document.addEventListener("keyup", function (event) {
// clearInterval(that.setInterval1);
// that.setInterval1 = null; // 重置 interval
// });
// }
// 监听键盘事件
monitorKeyboard() {
const keyActions = {
KeyQ: () => this.setIntervalhpr(-0.45),
KeyE: () => this.setIntervalhpr(0.45),
KeyW: () => this.updateFrustumPosition('move', -0.00001),
KeyS: () => this.updateFrustumPosition('move', 0.00001),
KeyA: () => this.updateFrustumPosition('move', -0.00001, 0),
KeyD: () => this.updateFrustumPosition('move', 0.00001, 0),
KeyC: () => this.updateFrustumHeight(1), // 增加高度
KeyZ: () => this.updateFrustumHeight(-1) // 降低高度
}
document.addEventListener('keydown', event => {
if (keyActions[event.code]) keyActions[event.code]()
})
document.addEventListener('keyup', () => this.stopFrustumRotation())
}
// 停止视锥体旋转
stopFrustumRotation() {
clearInterval(this.setInterval1)
this.setInterval1 = null
}
// 使用 HeadingPitchRoll 创建视锥体轮廓
drawFrustumOutline() {
const transform = Cesium.Transforms.headingPitchRollToFixedFrame(
this.position,
this.hpr
)
const frustumOutlineGeometry = new Cesium.FrustumOutlineGeometry({
frustum: this.frustum,
origin: Cesium.Matrix4.getTranslation(transform, new Cesium.Cartesian3()),
orientation: Cesium.Quaternion.fromRotationMatrix(
Cesium.Matrix4.getRotation(transform, new Cesium.Matrix3())
)
})
if (this.currentFrustumOutline) {
this.viewer.scene.primitives.remove(this.currentFrustumOutline)
}
this.currentFrustumOutline = new Cesium.Primitive({
geometryInstances: new Cesium.GeometryInstance({
geometry: frustumOutlineGeometry,
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
Cesium.Color.YELLOW
)
}
}),
appearance: new Cesium.PolylineColorAppearance({
translucent: false
}),
asynchronous: false
})
this.viewer.scene.primitives.add(this.currentFrustumOutline)
}
// 更新视锥体位置
updateFrustumPosition(type = 'move', p, deg = 90) {
if (type == 'move') {
var point = turf.point([
this.options.position.lng,
this.options.position.lat
])
const degreesValue = Cesium.Math.toDegrees(this.hpr.heading)
var distance = p
var bearing = degreesValue + deg
var options = { units: 'degrees' }
var destination = turf.destination(point, distance, bearing, options)
.geometry.coordinates
this.position = Cesium.Cartesian3.fromDegrees(
destination[0],
destination[1],
this.options.position.alt + 100
)
this.options.position.lng = destination[0]
this.options.position.lat = destination[1]
this.viewer.camera.setView({
destination: Cesium.Cartesian3.fromDegrees(
destination[0],
destination[1],
this.viewer.camera.positionCartographic.height
),
orientation: {
heading: this.viewer.camera.heading,
pitch: this.viewer.camera.pitch,
roll: this.viewer.camera.roll
}
})
}
if (type == 'update') {
this.position = p
}
// this.tongbuHpr();
this.drawFrustumOutline()
}
// 同步视角
tongbuHpr() {
const { lng, lat, alt } = this.options.position
this.viewer1.camera.setView({
destination: new Cesium.Cartesian3.fromDegrees(lng, lat, alt + 100),
orientation: {
heading: this.hpr.heading + Cesium.Math.toRadians(-90.0),
pitch: this.hpr.pitch + Cesium.Math.toRadians(-90.0),
roll: this.hpr.roll
}
})
}
updateFrustumHeight(deltaHeight) {
const cartographic = Cesium.Cartographic.fromCartesian(this.position)
cartographic.height += deltaHeight // 更新高度
this.position = Cesium.Cartesian3.fromDegrees(
Cesium.Math.toDegrees(cartographic.longitude),
Cesium.Math.toDegrees(cartographic.latitude),
cartographic.height
)
this.options.position.alt = cartographic.height
// this.tongbuHpr();
this.drawFrustumOutline() // 重新绘制视锥体轮廓
}
// 更新视锥体的 HeadingPitchRoll
updateFrustumHPR(h = 0, p = Cesium.Math.toRadians(90), r = 0) {
this.hpr.heading = Cesium.Math.negativePiToPi(h)
this.hpr.pitch = Cesium.Math.negativePiToPi(p)
this.hpr.roll = Cesium.Math.negativePiToPi(r)
// this.tongbuHpr();
this.drawFrustumOutline()
}
// 封装的函数:调整视锥体的 near 和 far 平面
updateFrustumNearFar(newNear, newFar) {
this.frustum.near = newNear
this.frustum.far = newFar
this.drawFrustumOutline()
}
// 封装的函数:调整视锥体的 fov远裁剪面的大小
updateFrustumFov(newFov) {
this.frustum.fov = Cesium.Math.toRadians(newFov)
this.drawFrustumOutline()
this.viewer.scene.requestRender() // 强制重新渲染场景
}
// 封装的函数:调整视锥体的高度
updateFrustumHeight(deltaHeight) {
const cartographic = Cesium.Cartographic.fromCartesian(this.position)
cartographic.height += deltaHeight
this.position = Cesium.Cartesian3.fromDegrees(
Cesium.Math.toDegrees(cartographic.longitude),
Cesium.Math.toDegrees(cartographic.latitude),
cartographic.height
)
this.drawFrustumOutline()
this.viewer.scene.requestRender() // 强制重新渲染场景
}
get show() {
return this.options.show
}
set show(bool) {
if (typeof bool == 'boolean') {
this.currentFrustumOutline.show = bool
}
}
remove() {
if (this.currentFrustumOutline) {
this.viewer.scene.primitives.remove(this.currentFrustumOutline)
}
}
}

290
src/Obj/AirLine/index.js Normal file
View File

@ -0,0 +1,290 @@
import { closeRotateAround, closeViewFollow} from '../../Global/global'
export default class AirLine {
constructor(options, earth) {
this.earth = earth
this.positions = null
this.options = { ...options }
this.Model = null
this.pointCollection = null
this.entity = null
this.dataSouce = new Cesium.CustomDataSource('airLineSource' + options.id)
AirLine.setDefaultValue(this)
AirLine.add(this)
}
static setDefaultValue(that) {
that.options.id = that.options.id || Cesium.createGuid()
that.options.positions = that.options.positions || []
that.options.width = that.options.width || 5
that.options.show = that.options.show || true
that.options.color = that.options.color || '#00FFFF'
that.options.height = that.options.height || 20
that.options.url = that.options.url || ''
that.options.modelShow = that.options.modelShow || false
that.options.flag = that.options.flag || true
that.options.speed = that.options.speed || 1
that.options.billboard.show = that.options.billboard.show || true
that.options.billboard.image = that.options.billboard.image || ''
that.options.billboard.scale = that.options.billboard.scale || 1
that.options.billboard.width = that.options.billboard.width || 64
that.options.billboard.height = that.options.billboard.height || 64
that.options.billboard.near = that.options.billboard.near ?? 1000
that.options.billboard.far = that.options.billboard.far ?? 10000
}
static add(that) {
if (that.options.positions.length < 3) {
// eslint-disable-next-line no-console
console.warn('坐标数量至少需要3个')
return
}
that.pointCollection = that.earth.viewer.scene.primitives.add(
new Cesium.PointPrimitiveCollection()
)
for (let i = 0; i < that.options.positions.length - 1; i++) {
let entity = that.createLine([
that.options.positions[i],
that.options.positions[i + 1]
])
that.dataSouce.entities.add(entity)
}
that.earth.viewer.dataSources.add(that.dataSouce).then(r => {})
that.createPoint()
that.createModel()
}
// 创建线条
createLine(positions) {
let entity = new Cesium.Entity({
id: Cesium.createGuid(),
polyline: {
positions: positions,
clampToGround: false,
width: this.options.width,
material: new Cesium.PolylineArrowMaterialProperty(
Cesium.Color.fromCssColorString(this.options.color)
),
zIndex: 99999999
},
show: true,
})
return entity
}
// 生成点
createPoint() {
this.options.positions.forEach((item, index) => {
this.pointCollection.add({
show: true,
position: item,
pixelSize: 10.0,
color: Cesium.Color.GREENYELLOW,
id: index
})
})
}
get show() {
return this.entity.show
}
set show(status) {
if (typeof status == 'boolean') this.entity.show = status
}
get modelShow() {
return this.Model.show
}
set modelShow(status) {
if (typeof status == 'boolean') this.Model.show = status
}
// 添加一个模型
createModel() {
let scaleByDistance = new Cesium.NearFarScalar(
this.options.billboard.near,
1,
this.options.billboard.far,
0
)
const position = this.options.positions[0]
const heading = Cesium.Math.toRadians(0)
const pitch = 0
const roll = 0
const hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll)
const orientation = Cesium.Transforms.headingPitchRollQuaternion(
position,
hpr
)
this.Model = this.earth.viewer.entities.add({
name: this.options.billboard.image,
position,
// orientation,
billboard: {
show: this.options.billboard.show,
image: this.options.billboard.image,
scale: this.options.billboard.scale,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
width: this.options.billboard.width,
height: this.options.billboard.height,
disableDepthTestDistance: Number.POSITIVE_INFINITY,
scaleByDistance,
pixelOffsetScaleByDistance: scaleByDistance
},
// model: {
// uri: this.options.url,
// minimumPixelSize: 128,
// maximumScale: 20000
// },
show: this.options.modelShow
})
}
// 开始飞行
start() {
if (!this.options.positions) {
// eslint-disable-next-line no-console
console.warn('请先绘制并且生成航线')
return
}
let i
let that = this
this.timer = setInterval(function() {
if (this.index) {
i = this.index
} else {
i = 0
}
i++
this.index = i
if (i > that.options.positions.length) {
clearInterval(this.timer)
} else {
let position = that.options.positions[i]
if (position) {
that.Model.position = new Cesium.CallbackProperty(e => {
return position
})
that.Model.orientation = that.direction(
that.options.positions[i - 1],
that.options.positions[i]
).orientation
}
}
}, 100)
}
// 停止飞行
stop() {
if (this.timer) {
clearInterval(this.timer)
}
}
// 飞入
flyTo() {
closeRotateAround(this.earth)
closeViewFollow(this.earth)
let positionArray = []
for (let i = 0; i < this.options.positions.length; i++) {
let item = this.options.positions[i]
positionArray.push(item.x, item.y, item.z)
}
// console.log('cartesian',cartesian);
// let position = Cesium.Cartographic.fromCartesian(cartesian)
// console.log('position',position);
let BoundingSphere = Cesium.BoundingSphere.fromVertices(positionArray)
this.earth.viewer.camera.flyToBoundingSphere(BoundingSphere, {
offset: {
heading: Cesium.Math.toRadians(0.0),
pitch: Cesium.Math.toRadians(-90.0),
roll: Cesium.Math.toRadians(0.0)
}
})
}
// 计算一个到另一个点的方向
direction(pointA, pointB) {
//向量AB
const vector2 = Cesium.Cartesian3.subtract(
pointB,
pointA,
new Cesium.Cartesian3()
)
//归一化
const normal = Cesium.Cartesian3.normalize(vector2, new Cesium.Cartesian3())
//旋转矩阵 rotationMatrixFromPositionVelocity源码中有并未出现在cesiumAPI中
const rotationMatrix3 = Cesium.Transforms.rotationMatrixFromPositionVelocity(
pointA,
normal,
Cesium.Ellipsoid.WGS84
)
const modelMatrix4 = Cesium.Matrix4.fromRotationTranslation(
rotationMatrix3,
pointA
)
// 获取getHeadingPitchRoll
let m1 = Cesium.Transforms.eastNorthUpToFixedFrame(
Cesium.Matrix4.getTranslation(modelMatrix4, new Cesium.Cartesian3()),
Cesium.Ellipsoid.WGS84,
new Cesium.Matrix4()
)
// 矩阵相除
let m3 = Cesium.Matrix4.multiply(
Cesium.Matrix4.inverse(m1, new Cesium.Matrix4()),
modelMatrix4,
new Cesium.Matrix4()
)
// 得到旋转矩阵
let mat3 = Cesium.Matrix4.getMatrix3(m3, new Cesium.Matrix3())
// 计算四元数
let q = Cesium.Quaternion.fromRotationMatrix(mat3)
// 计算旋转角(弧度)
let hpr = Cesium.HeadingPitchRoll.fromQuaternion(q)
// hpr.pitch = hpr.pitch + 3.14 / 2 + 3.14;
hpr.pitch = 0
let orientation = Cesium.Transforms.headingPitchRollQuaternion(pointA, hpr)
return { hpr, orientation }
}
// 删除
remove() {
this.earth.viewer.entities.remove(this.entity)
this.dataSouce.entities.removeAll()
this.pointCollection && this.pointCollection.destroy()
this.Model && this.earth.viewer.entities.remove(this.Model)
this.timer && clearInterval(this.timer)
this.timer = null
}
// 返回照片数量 航点数
getInfo() {
return {
length: this.countLength(),
time: this.countTime(),
waypoint: this.options.positions.length,
photos: this.options.positions.length
}
}
//计算航线得长度
countLength() {
let totalDistance = 0
for (let i = 0; i < this.options.positions.length - 1; i++) {
const start = this.options.positions[i]
const end = this.options.positions[i + 1]
const distance = Cesium.Cartesian3.distance(start, end)
totalDistance += distance
}
return totalDistance.toFixed(2) // 返回保留两位小数的距离
}
//计算航线时间
countTime() {
let time = Math.floor(Number(this.countLength())) / this.options.speed
let s = Math.floor(time % 60)
let m = Math.floor(time / 60)
let str = m + '分' + s + '秒'
return str
}
//显示隐藏
isShow(status) {
if (typeof status === 'boolean') {
this.modelShow = status
this.dataSouce.show = status
let len = this.pointCollection.length
for (let i = 0; i < len; ++i) {
let p = this.pointCollection.get(i)
p.show = status
}
} else {
// eslint-disable-next-line no-console
console.error('参数须为Boolean类型')
}
}
}

View File

@ -0,0 +1,359 @@
import FRUSTUN from './frustum.js'
import BillordPointLine from './billord_point_line'
export default class PointRoute {
constructor(options = {}, viewer, viewer1) {
this.options = { ...options }
this.viewer = viewer
this.viewer1 = viewer1
this.entity = null
this.frustum = null
this.billordPointLineMaps = []
this.index = 0
this.positions = []
PointRoute.setDefaultValue(this)
this.create()
}
static setDefaultValue(that) {
that.options.positions = that.options.positions || []
that.options.show = that.options.show || true
that.options.color = that.options.color || '#00d590'
that.options.height = that.options.height || 500
that.options.speed = that.options.speed || 1
that.options.frustumShow = that.options.frustumShow ?? true
that.options.saveFun = that.options.saveFun || null
that.options.selectFun = that.options.selectFun || null
that.options.keyboard = that.options.keyboard ?? true
that.options.normalHeight = that.options.normalHeight || 100
that.options.airHeight = that.options.airHeight || 100
}
create() {
if (this.options.positions.length < 2) {
return
}
let that = this
let { frustumShow } = that.options
this.entity = this.viewer.entities.add({
show: this.options.show,
polyline: {
positions: new Cesium.CallbackProperty(() => {
let positions = []
for (let i = 0; i < this.billordPointLineMaps.length; i++) {
const element = this.billordPointLineMaps[i]
positions.push(element.billboardEntity.position.getValue())
}
return positions
}, false),
width: 3,
material: Cesium.Color.fromCssColorString(this.options.color)
}
})
// 创建点、线、billbord
for (let i = 0; i < this.options.positions.length; i++) {
const element = this.options.positions[i]
// console.log("elementelementelement", element);
if (frustumShow && i == this.index) {
this.frustum = new FRUSTUN(
{
position: element,
show: false,
arr: this.options.positions,
index: i,
normalHeight: this.options.normalHeight
},
this.viewer,
this.viewer1
)
}
let op = new BillordPointLine(
{
positions: element,
index: i + 1,
saveFun: that.options.saveFun,
selectFun: that.options.selectFun,
keyboard: that.options.keyboard,
updateFrustumFun: that.updateFrustumPosition,
normalHeight: that.options.normalHeight,
frustum: that.frustum,
airHeight: that.options.airHeight
},
this.viewer
)
this.billordPointLineMaps.push(op)
}
this.onKey()
}
get show() {
return this.options.show
}
set show(bool) {
if (typeof bool === 'boolean') {
this.frustum.currentFrustumOutline.show = bool
this.billordPointLineMaps.forEach(item => {
item.show = bool
})
this.entity.show = bool
}
}
// 监听键盘事件
onKey() {
let that = this
document.addEventListener('keydown', function(event) {
switch (event.key) {
case 'ArrowUp':
that.index += 1
that.updateFrustum(true)
break
case 'ArrowDown':
that.index -= 1
that.updateFrustum(false)
break
}
})
}
// 更新frustum
updateFrustum(flag) {
console.log(this.index)
let obj
if (this.index > this.options.positions.length - 1 || this.index < 0) {
let str = this.index > 0 ? '已选中最后一个航点' : '已选中第一个航点'
alert(str)
return
}
for (let i = 0; i < this.billordPointLineMaps.length; i++) {
const element = this.billordPointLineMaps[i]
const hpr = null
if (i == this.index) {
let position = element.billboardEntity.position.getValue()
if (this.index !== 0) {
obj = this.direction(
this.billordPointLineMaps[
i - 1
].billboardEntity.position.getValue(),
element.billboardEntity.position.getValue()
)
hpr = obj.hpr
}
if (this.index == 0) {
obj = this.direction(
this.billordPointLineMaps[0].billboardEntity.position.getValue(),
this.billordPointLineMaps[1].billboardEntity.position.getValue()
)
hpr = obj.hpr
}
if (hpr) {
this.frustum.updateFrustumHPR(
hpr.heading,
this.frustum.pitch,
hpr.roll
)
}
if (position) {
this.frustum.updateFrustumPosition('update', position)
}
}
}
}
cartesian3Towgs84(cartesian) {
var ellipsoid = this.viewer.scene.globe.ellipsoid
var cartesian3 = new Cesium.Cartesian3(
cartesian.x,
cartesian.y,
cartesian.z
)
var cartographic = ellipsoid.cartesianToCartographic(cartesian3)
var lat = Cesium.Math.toDegrees(cartographic.latitude)
var lng = Cesium.Math.toDegrees(cartographic.longitude)
var alt = cartographic.height < 0 ? 0 : cartographic.height
return {
lng: lng,
lat: lat,
alt: alt
}
}
// 计算一个到另一个点的方向
direction(pointA, pointB) {
//向量AB
const vector2 = Cesium.Cartesian3.subtract(
pointA,
pointB,
new Cesium.Cartesian3()
)
//归一化
const normal = Cesium.Cartesian3.normalize(vector2, new Cesium.Cartesian3())
//旋转矩阵 rotationMatrixFromPositionVelocity源码中有并未出现在cesiumAPI中
const rotationMatrix3 = Cesium.Transforms.rotationMatrixFromPositionVelocity(
pointA,
normal,
Cesium.Ellipsoid.WGS84
)
const modelMatrix4 = Cesium.Matrix4.fromRotationTranslation(
rotationMatrix3,
pointA
)
// 获取getHeadingPitchRoll
let m1 = Cesium.Transforms.eastNorthUpToFixedFrame(
Cesium.Matrix4.getTranslation(modelMatrix4, new Cesium.Cartesian3()),
Cesium.Ellipsoid.WGS84,
new Cesium.Matrix4()
)
// 矩阵相除
let m3 = Cesium.Matrix4.multiply(
Cesium.Matrix4.inverse(m1, new Cesium.Matrix4()),
modelMatrix4,
new Cesium.Matrix4()
)
// 得到旋转矩阵
let mat3 = Cesium.Matrix4.getMatrix3(m3, new Cesium.Matrix3())
// 计算四元数
let q = Cesium.Quaternion.fromRotationMatrix(mat3)
// 计算旋转角(弧度)
let hpr = Cesium.HeadingPitchRoll.fromQuaternion(q)
// hpr.pitch = hpr.pitch + 3.14 / 2 + 3.14;
hpr.pitch = 90
let orientation = Cesium.Transforms.headingPitchRollQuaternion(pointA, hpr)
return { hpr, orientation }
}
/**
*
* @param {index} 索引
*/
// 删除航点
delPosition(index) {
this.options.positions.splice(index, 1)
// this.options.positions = this.options.positions.filter((item, index) => index !== i);
this.remove()
this.create()
}
// 获取最新的positions
getNewPositions() {
let positions = []
for (let i = 0; i < this.billordPointLineMaps.length; i++) {
const element = this.billordPointLineMaps[i]
let position = this.cartesian3Towgs84(
element.billboardEntity.position.getValue()
)
positions.push(position)
}
return positions
}
// 删除
remove() {
this.billordPointLineMaps.forEach((item, i) => {
item.remove()
})
if (this.frustum) {
this.frustum.remove()
}
this.viewer.entities.remove(this.entity)
this.billordPointLineMaps = []
}
/**
*
* @param {String} type
* @param {Number} index
* @param {Array} position
*/
// 新增航点 beforeafterend
addPoint(positions) {
this.options.positions = positions
this.remove()
this.create()
}
// 根据选中的点更新视锥的位置
updateFrustumPosition(index) {
if (!this.billordPointLineMaps || this.billordPointLineMaps.length === 0)
return
if (this.frustum) {
this.frustum.show = true
}
let current = this.billordPointLineMaps[
index
].billboardEntity.position.getValue()
if (index !== 0) {
let obj
let after =
index === this.billordPointLineMaps.length - 1
? this.billordPointLineMaps[
index - 1
].billboardEntity.position.getValue() // 获取前一个位置
: this.billordPointLineMaps[
index + 1
].billboardEntity.position.getValue() // 获取下一个位置
obj = this.direction(
index === this.billordPointLineMaps.length - 1 ? after : current,
index === this.billordPointLineMaps.length - 1 ? current : after
)
let { hpr } = obj
this.frustum.updateFrustumHPR(
hpr.heading,
Cesium.Math.toRadians(this.frustum.pitch),
hpr.roll
)
} else {
let obj
let after = this.billordPointLineMaps[1].billboardEntity.position.getValue()
obj = this.direction(current, after)
let { hpr } = obj
this.frustum.updateFrustumHPR(
hpr.heading,
Cesium.Math.toRadians(this.frustum.pitch),
hpr.roll
)
}
if (current) {
this.frustum.updateFrustumPosition('update', current)
}
let position = this.cartesian3Towgs84(current)
this.billordPointLineMaps.forEach(item => {
item.billboardEntity.label.show = false // 先将所有元素的 label.show 设置为 false
})
const targetItem = this.billordPointLineMaps.find(
item => item.billboardEntity.index == index + 1
)
if (targetItem) {
targetItem.billboardEntity.label.show = true // 然后找到匹配的 index 设置为 true
}
return position
}
flyTo() {
let positionArray = []
for (let i = 0; i < this.options.positions.length; i++) {
let a = Cesium.Cartesian3.fromDegrees(
this.options.positions[i].lng,
this.options.positions[i].lat,
this.options.positions[i].alt + this.options.height
)
positionArray.push(a.x, a.y, a.z)
}
let BoundingSphere = Cesium.BoundingSphere.fromVertices(positionArray)
this.viewer.camera.flyToBoundingSphere(BoundingSphere, {
offset: {
heading: Cesium.Math.toRadians(0.0),
pitch: Cesium.Math.toRadians(-80.0),
roll: Cesium.Math.toRadians(0.0)
}
})
}
//计算航线的长度
countLength() {
if (this.options.positions.length < 2) {
return 0
} else {
let lineString = []
this.options.positions.forEach(item => {
lineString.push([item.lng, item.lat])
})
var line = turf.lineString(lineString)
return (turf.length(line) * 1000).toFixed(2)
}
}
//计算航线时间
countTime() {
let time = Math.floor(Number(this.countLength())) / this.options.speed
let s = Math.floor(time % 60)
let m = Math.floor(time / 60)
let str = m + '分' + s + '秒'
return str
}
}

View File

@ -0,0 +1,25 @@
function html() {
return `
<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-1">
<input class="input" type="number" title="" min="0" max="999999" step="0.1" @model="viewPointHeight">
<span class="unit">m</span>
<span class="arrow"></span>
</div>
</div>
</div>
<div class="row">
<div class="col">
<span class="label">采样精度</span>
<input class="input" type="number" title="" min="1" max="100" step="1" @model="precision">
</div>
</div>
</div>
`
}
export { html }

View File

@ -0,0 +1,512 @@
/*
* @Author: Wang jianLei
* @Date: 2022-05-17 21:49:28
* @Last Modified by: Wang JianLei
* @Last Modified time: 2022-05-19 22:08:14
*/
let ViewShed = function (sdk, canvasEleId) {
if (!sdk.viewer) throw new Error("no viewer object!");
alert(canvasEleId)
let canvasEle = document.getElementById(canvasEleId);
if (!canvasEle) throw new Error("the canvas element is not exist");
this.canvasEle = canvasEle;
this.viewer = sdk.viewer;
this.handler = undefined;
this.lightCamera;
this.pyramid;
this.frustumPrimitive;
this.viewershedPolygon;
};
ViewShed.prototype = {
/**
* 初始化handler
*/
initHandler() {
if (this.handler) {
this.handler.destroy();
this.handler = undefined;
}
},
/**
* 开始执行视域分析
* @param {number} precision 精度值越大创建耗时越长建议在10~20之间
*/
createViewshed: function (precision) {
let $this = this;
let scene = $this.viewer.scene;
$this.initHandler();
$this.clearAll();
$this.handler = new Cesium.ScreenSpaceEventHandler($this.viewer.canvas);
$this.handler.setInputAction((event) => {
// 禁止地球旋转和缩放,地球的旋转会对鼠标移动监听有影响,所以需要禁止
scene.screenSpaceCameraController.enableRotate = false;
scene.screenSpaceCameraController.enableZoom = false;
scene.globe.depthTestAgainstTerrain = true;
let earthPosition = scene.pickPosition(event.position);
let pos = $this.cartesian3ToDegree(earthPosition);
$this.handler.setInputAction(function (event) {
let newPosition = scene.pickPosition(event.endPosition);
if (Cesium.defined(newPosition)) {
let pos1 = $this.cartesian3ToDegree(newPosition);
let distance = Cesium.Cartesian3.distance(newPosition, earthPosition);
let angle = $this.getAngle(pos[0], pos[1], pos1[0], pos1[1]);
let pitch = $this.getPitch(earthPosition, newPosition);
$this.ViewShedOptions = {
viewPosition: earthPosition, //观测点 笛卡尔坐标
endPosition: newPosition, //目标点 笛卡尔坐标
direction: angle, //观测方位角 默认为`0`,范围`0~360`
pitch: pitch, //俯仰角,radius,默认为`0`
horizontalViewAngle: 90, //可视域水平夹角,默认为 `90`,范围`0~360`
verticalViewAngle: 60, //可视域垂直夹角,默认为`60`,范围`0~180`
visibleAreaColor: Cesium.Color.GREEN, //可视区域颜色,默认为`green`
invisibleAreaColor: Cesium.Color.RED, //不可见区域颜色,默认为`red`
visualRange: distance, //距离,单位`米`
};
$this.updateViewShed();
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
}, Cesium.ScreenSpaceEventType.LEFT_DOWN);
$this.handler.setInputAction(() => {
$this.initHandler();
// 开启地球旋转和缩放
scene.screenSpaceCameraController.enableRotate = true;
scene.screenSpaceCameraController.enableZoom = true;
$this.drawViewershed(precision);
}, Cesium.ScreenSpaceEventType.LEFT_UP);
},
ReturnDistance(pos0, pos1) {
let distance = 0;
let point1cartographic = Cesium.Cartographic.fromCartesian(pos0);
let point2cartographic = Cesium.Cartographic.fromCartesian(pos1);
/**根据经纬度计算出距离**/
let geodesic = new Cesium.EllipsoidGeodesic();
geodesic.setEndPoints(point1cartographic, point2cartographic);
let s = geodesic.surfaceDistance;
return s;
},
getHeight(x, y, objectsToExclude) {
let endCartographic = Cesium.Cartographic.fromDegrees(x, y);
let endHeight = this.viewer.scene.sampleHeight(
endCartographic,
objectsToExclude
);
return endHeight;
},
cartesian3ToDegree: function (Cartesian3) {
let _ellipsoid = this.viewer.scene.globe.ellipsoid;
let _cartographic = _ellipsoid.cartesianToCartographic(Cartesian3);
let _lat = Cesium.Math.toDegrees(_cartographic.latitude);
let _lng = Cesium.Math.toDegrees(_cartographic.longitude);
let _alt = _cartographic.height;
return [_lng, _lat, _alt];
},
getAngle: function (lng1, lat1, lng2, lat2) {
let dRotateAngle = Math.atan2(Math.abs(lng1 - lng2), Math.abs(lat1 - lat2));
if (lng2 >= lng1) {
dRotateAngle = lat2 < lat1 ? Math.PI - dRotateAngle : dRotateAngle;
} else {
dRotateAngle =
lat2 >= lat1 ? 2 * Math.PI - dRotateAngle : Math.PI + dRotateAngle;
}
dRotateAngle = (dRotateAngle * 180) / Math.PI;
return dRotateAngle;
},
getPitch(pointA, pointB) {
let transfrom = Cesium.Transforms.eastNorthUpToFixedFrame(pointA);
const vector = Cesium.Cartesian3.subtract(
pointB,
pointA,
new Cesium.Cartesian3()
);
let direction = Cesium.Matrix4.multiplyByPointAsVector(
Cesium.Matrix4.inverse(transfrom, transfrom),
vector,
vector
);
Cesium.Cartesian3.normalize(direction, direction);
return Cesium.Math.PI_OVER_TWO - Cesium.Math.acosClamped(direction.z);
},
updateViewShed: function () {
this.clear();
this.setLightCamera();
this.addVisualPyramid();
this.createFrustum();
},
clear: function () {
if (this.pyramid) {
this.viewer.entities.removeById(this.pyramid.id);
this.pyramid = undefined;
}
if (this.frustumPrimitive) {
this.viewer.scene.primitives.remove(this.frustumPrimitive);
this.frustumPrimitive = undefined;
}
if (this.debugModelMatrixPrimitive) {
this.viewer.scene.primitives.remove(this.debugModelMatrixPrimitive);
this.debugModelMatrixPrimitive = undefined;
}
},
clearAll: function () {
this.clear();
if (this.viewershedPolygon) {
this.viewer.scene.primitives.remove(this.viewershedPolygon);
this.viewershedPolygon = undefined;
}
},
addVisualPyramid: function () {
let options = this.ViewShedOptions;
let position = options.viewPosition;
let visualRange = Number(options.visualRange);
let transform = Cesium.Transforms.eastNorthUpToFixedFrame(position);
this.debugModelMatrixPrimitive = this.viewer.scene.primitives.add(
new Cesium.DebugModelMatrixPrimitive({
modelMatrix: transform,
length: 5.0,
})
);
const halfClock = options.horizontalViewAngle / 2;
const halfCone = options.verticalViewAngle / 2;
const pitch = Cesium.Math.toDegrees(options.pitch);
const ellipsoid = new Cesium.EllipsoidGraphics({
radii: new Cesium.Cartesian3(visualRange, visualRange, visualRange),
minimumClock: Cesium.Math.toRadians(90 - options.direction - halfClock),
maximumClock: Cesium.Math.toRadians(90 - options.direction + halfClock),
minimumCone: Cesium.Math.toRadians(90 - pitch - halfCone),
maximumCone: Cesium.Math.toRadians(90 - pitch + halfCone),
fill: false,
outline: true,
subdivisions: 256,
stackPartitions: 64,
slicePartitions: 64,
outlineColor: Cesium.Color.YELLOWGREEN.withAlpha(0.5),
});
const pyramidEntity = new Cesium.Entity({
position: position,
ellipsoid,
});
this.pyramid = this.viewer.entities.add(pyramidEntity);
},
setLightCamera: function () {
if (!this.lightCamera) {
this.lightCamera = new Cesium.Camera(this.viewer.scene);
}
let options = this.ViewShedOptions;
let visualRange = Number(options.visualRange);
this.lightCamera.position = options.viewPosition;
this.lightCamera.frustum.near = 0.1;
this.lightCamera.frustum.far = visualRange;
const hr = Cesium.Math.toRadians(options.horizontalViewAngle);
const vr = Cesium.Math.toRadians(options.verticalViewAngle);
this.lightCamera.frustum.aspectRatio =
(visualRange * Math.tan(hr / 2) * 2) /
(visualRange * Math.tan(vr / 2) * 2);
this.lightCamera.frustum.fov = hr > vr ? hr : vr;
this.lightCamera.setView({
destination: options.viewPosition,
orientation: {
heading: Cesium.Math.toRadians(options.direction || 0),
pitch: options.pitch || 0,
roll: 0,
},
});
},
createFrustum: function () {
const scratchRight = new Cesium.Cartesian3();
const scratchRotation = new Cesium.Matrix3();
const scratchOrientation = new Cesium.Quaternion();
const direction = this.lightCamera.directionWC;
const up = this.lightCamera.upWC;
let right = this.lightCamera.rightWC;
right = Cesium.Cartesian3.negate(right, scratchRight);
let rotation = scratchRotation;
Cesium.Matrix3.setColumn(rotation, 0, right, rotation);
Cesium.Matrix3.setColumn(rotation, 1, up, rotation);
Cesium.Matrix3.setColumn(rotation, 2, direction, rotation);
let orientation = Cesium.Quaternion.fromRotationMatrix(
rotation,
scratchOrientation
);
let instanceOutline = new Cesium.GeometryInstance({
geometry: new Cesium.FrustumOutlineGeometry({
frustum: this.lightCamera.frustum,
origin: this.ViewShedOptions.viewPosition,
orientation: orientation,
}),
id: "视椎体轮廓线" + Math.random().toString(36).substr(2),
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
new Cesium.Color(0.0, 1.0, 0.0, 1.0)
),
show: new Cesium.ShowGeometryInstanceAttribute(true),
},
});
this.frustumPrimitive = this.viewer.scene.primitives.add(
new Cesium.Primitive({
geometryInstances: instanceOutline,
appearance: new Cesium.PerInstanceColorAppearance({
flat: true,
translucent: false,
closed: true,
}),
})
);
},
createPoint: function (firstPos, secondPos) {
let entity4FirstPos = new Cesium.Entity({
name: "firstPos",
show: true,
position: firstPos,
point: {
show: true,
pixelSize: 20,
color: Cesium.Color.RED,
outlineColor: Cesium.Color.YELLOW,
outlineWidth: 5,
},
description: `
<p>这是绘制的视椎体起点</p>`,
});
this.viewer.entities.add(entity4FirstPos);
let entity4SecondPos = new Cesium.Entity({
name: "secondPos",
show: true,
position: secondPos,
point: {
show: true,
pixelSize: 30,
color: Cesium.Color.YELLOW,
outlineColor: Cesium.Color.RED,
outlineWidth: 8,
},
description: `
<p>这是绘制的视椎体视角终点</p>`,
});
this.viewer.entities.add(entity4SecondPos);
},
//绘制可视域
add(positionArr) {
let polygon = new Cesium.PolygonGeometry({
polygonHierarchy: new Cesium.PolygonHierarchy(
Cesium.Cartesian3.fromDegreesArray(positionArr)
),
height: 0.0,
extrudedHeight: 0.0,
vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT,
stRotation: 0.0, // 纹理的旋转坐标(以弧度为单位),正旋转是逆时针方向
ellipsoid: Cesium.Ellipsoid.WGS84,
granularity: Cesium.Math.RADIANS_PER_DEGREE, // 每个纬度和经度之间的距离(以弧度为单位),确定缓冲区中的位置数
perPositionHeight: false, // 每个位置点使用的高度
closeTop: true,
closeBottom: true,
// NONE 与椭圆表面不符的直线;GEODESIC 遵循测地路径;RHUMB 遵循大黄蜂或恶魔般的道路。
arcType: Cesium.ArcType.GEODESIC, // 多边形边缘线型
});
let polygonInstance = new Cesium.GeometryInstance({
geometry: polygon,
name: "ViewershedPolygon",
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
Cesium.Color.BLUE.withAlpha(0.6)
),
show: new Cesium.ShowGeometryInstanceAttribute(true), //显示或者隐藏
},
});
this.viewershedPolygon = this.viewer.scene.primitives.add(
new Cesium.GroundPrimitive({
geometryInstances: polygonInstance,
appearance: new Cesium.EllipsoidSurfaceAppearance({
aboveGround: true,
material: new Cesium.Material({
fabric: {
type: "Image",
uniforms: {
image: this.returnImgae(),
},
},
}),
}),
})
);
},
drawViewershed(precision) {
const pos = this.cartesian3ToDegree(this.ViewShedOptions.viewPosition);
const radius = this.ViewShedOptions.visualRange;
const direction = this.ViewShedOptions.direction;
let boundary = this.computeBoundaryOptions(pos, radius, direction);
const bbox = boundary.bbox;
let mask = turf.polygon([boundary.boundaryPoints]);
const dis = this.ViewShedOptions.visualRange / (precision * 1000);
let gridPoints = turf.pointGrid(bbox, dis, { mask: mask });
let pointsResult = this.createTargetPoints(gridPoints, dis, pos);
let variogram = kriging.train(
pointsResult.values,
pointsResult.lngs,
pointsResult.lats,
"exponential",
0,
100
);
let grid = kriging.grid([boundary.boundaryPoints], variogram, dis / 1000);
const colors = [
"#ff000080",
"#ff000080",
"#ff000080",
"#ff000080",
"#ff000080",
"#ff000080",
"#00ff0080",
"#00ff0080",
"#00ff0080",
"#00ff0080",
"#00ff0080",
"#00ff0080",
];
this.canvasEle.width = 3840;
this.canvasEle.height = 2160;
kriging.plot(
this.canvasEle,
grid,
[bbox[0], bbox[2]],
[bbox[1], bbox[3]],
colors
);
this.add(boundary.positionArr);
},
computeBoundaryOptions(pos, radius, angle) {
let Ea = 6378137; // 赤道半径
let Eb = 6356725; // 极半径
const lng = pos[0],
lat = pos[1];
const bbox = [lng, lat, lng, lat]; //[minX, minY, maxX, maxY]
let positionArr = [];
let boundaryPoints = [];
positionArr.push(lng, lat);
boundaryPoints.push([lng, lat]);
//正北是0°
let start = angle + 45 > 360 ? angle - 45 - 360 : angle - 45;
let end = start + 90;
for (let i = start; i <= end; i++) {
let dx = radius * Math.sin((i * Math.PI) / 180.0);
let dy = radius * Math.cos((i * Math.PI) / 180.0);
let ec = Eb + ((Ea - Eb) * (90.0 - lat)) / 90.0;
let ed = ec * Math.cos((lat * Math.PI) / 180);
let BJD = lng + ((dx / ed) * 180.0) / Math.PI;
let BWD = lat + ((dy / ec) * 180.0) / Math.PI;
positionArr.push(BJD, BWD);
boundaryPoints.push([BJD, BWD]);
this.refreshBBox(bbox, BJD, BWD);
}
boundaryPoints.push([lng, lat]);
return {
positionArr,
boundaryPoints,
bbox,
};
},
/**
* 更新外围矩形 Bbox
* @param {Array} result 外围矩形Bbox-[minX, minY, maxX, maxY]
* @param {Number} x 经度
* @param {Number} y 纬度
*/
refreshBBox(result, x, y) {
result[0] = x < result[0] ? x : result[0];
result[1] = y < result[1] ? y : result[1];
result[2] = x > result[2] ? x : result[2];
result[3] = y > result[3] ? y : result[3];
},
/**
* 插值点用射线判断通视性
* @param {*} gridPoints 网格点
* @param {*} step 步长,可以理解成是精度
* @param {*} sourcePos 视域分析起点
* @returns kriging插值所需的参数对象{ values:[], lngs:[], lats:[]}
*/
createTargetPoints(gridPoints, step, sourcePos) {
let positionArr = [];
let objectsToExclude = [
this.frustumPrimitive,
this.pyramid,
this.debugModelMatrixPrimitive,
];
let values = [],
lngs = [],
lats = [];
let height = this.getHeight(sourcePos[0], sourcePos[1], objectsToExclude);
positionArr.push({
x: sourcePos[0],
y: sourcePos[1],
z: height,
});
let viewPoint = this.ViewShedOptions.viewPosition;
for (let index = 0; index < gridPoints.features.length; index++) {
const feature = gridPoints.features[index];
const coords = feature.geometry.coordinates;
const x = coords[0],
y = coords[1];
let h = this.getHeight(x, y, objectsToExclude);
let endPoint = Cesium.Cartesian3.fromDegrees(x, y, h);
let direction = Cesium.Cartesian3.normalize(
Cesium.Cartesian3.subtract(
endPoint,
viewPoint,
new Cesium.Cartesian3()
),
new Cesium.Cartesian3()
);
// 建立射线
let ray = new Cesium.Ray(viewPoint, direction);
let result = this.viewer.scene.pickFromRay(ray, objectsToExclude); // 计算交互点,返回第一个
if (result) {
let buffer = this.ReturnDistance(endPoint, result.position);
// let M_color = Cesium.Color.GREEN;
if (buffer > step) {
// M_color = Cesium.Color.RED;
values.push(0);
} else {
values.push(1);
}
lngs.push(x);
lats.push(y);
// this.viewer.entities.add(
// new Cesium.Entity({
// name: "插值点哦",
// show: true,
// position: endPoint,
// point: {
// show: true,
// pixelSize: 10,
// color: M_color,
// outlineWidth: 2,
// outlineColor: Cesium.Color.YELLOW,
// },
// })
// );
}
}
return {
values,
lngs,
lats,
};
},
/**
* canvas转image图片
* @returns base64图片
*/
returnImgae() {
return this.canvasEle.toDataURL("image/png");
},
};
export default ViewShed;

View File

@ -0,0 +1,131 @@
export default `
#define USE_CUBE_MAP_SHADOW true
uniform sampler2D colorTexture;
uniform sampler2D depthTexture;
varying vec2 v_textureCoordinates;
uniform mat4 camera_projection_matrix;
uniform mat4 camera_view_matrix;
uniform samplerCube shadowMap_textureCube;
uniform mat4 shadowMap_matrix;
uniform vec4 shadowMap_lightPositionEC;
uniform vec4 shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness;
uniform vec4 shadowMap_texelSizeDepthBiasAndNormalShadingSmooth;
uniform float helsing_viewDistance;
uniform vec4 helsing_visibleAreaColor;
uniform vec4 helsing_invisibleAreaColor;
struct zx_shadowParameters
{
vec3 texCoords;
float depthBias;
float depth;
float nDotL;
vec2 texelStepSize;
float normalShadingSmooth;
float darkness;
};
float czm_shadowVisibility(samplerCube shadowMap, zx_shadowParameters shadowParameters)
{
float depthBias = shadowParameters.depthBias;
float depth = shadowParameters.depth;
float nDotL = shadowParameters.nDotL;
float normalShadingSmooth = shadowParameters.normalShadingSmooth;
float darkness = shadowParameters.darkness;
vec3 uvw = shadowParameters.texCoords;
depth -= depthBias;
float visibility = czm_shadowDepthCompare(shadowMap, uvw, depth);
return czm_private_shadowVisibility(visibility, nDotL, normalShadingSmooth, darkness);
}
vec4 getPositionEC(){
return czm_windowToEyeCoordinates(gl_FragCoord);
}
vec3 getNormalEC(){
return vec3(1.);
}
vec4 toEye(in vec2 uv,in float depth){
vec2 xy=vec2((uv.x*2.-1.),(uv.y*2.-1.));
vec4 posInCamera=czm_inverseProjection*vec4(xy,depth,1.);
posInCamera=posInCamera/posInCamera.w;
return posInCamera;
}
vec3 pointProjectOnPlane(in vec3 planeNormal,in vec3 planeOrigin,in vec3 point){
vec3 v01=point-planeOrigin;
float d=dot(planeNormal,v01);
return(point-planeNormal*d);
}
float getDepth(in vec4 depth){
float z_window=czm_unpackDepth(depth);
z_window=czm_reverseLogDepth(z_window);
float n_range=czm_depthRange.near;
float f_range=czm_depthRange.far;
return(2.*z_window-n_range-f_range)/(f_range-n_range);
}
float shadow(in vec4 positionEC){
vec3 normalEC=getNormalEC();
zx_shadowParameters shadowParameters;
shadowParameters.texelStepSize=shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.xy;
shadowParameters.depthBias=shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.z;
shadowParameters.normalShadingSmooth=shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.w;
shadowParameters.darkness=shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness.w;
vec3 directionEC=positionEC.xyz-shadowMap_lightPositionEC.xyz;
float distance=length(directionEC);
directionEC=normalize(directionEC);
float radius=shadowMap_lightPositionEC.w;
if(distance>radius)
{
return 2.0;
}
vec3 directionWC=czm_inverseViewRotation*directionEC;
shadowParameters.depth=distance/radius-0.0003;
shadowParameters.nDotL=clamp(dot(normalEC,-directionEC),0.,1.);
shadowParameters.texCoords=directionWC;
float visibility=czm_shadowVisibility(shadowMap_textureCube,shadowParameters);
return visibility;
}
bool visible(in vec4 result)
{
result.x/=result.w;
result.y/=result.w;
result.z/=result.w;
return result.x>=-1.&&result.x<=1.
&&result.y>=-1.&&result.y<=1.
&&result.z>=-1.&&result.z<=1.;
}
void main(){
// 釉色 = 结构二维(颜色纹理, 纹理坐标)
gl_FragColor = texture2D(colorTexture, v_textureCoordinates);
// 深度 = 获取深度(结构二维(深度纹理, 纹理坐标))
float depth = getDepth(texture2D(depthTexture, v_textureCoordinates));
// 视角 = (纹理坐标, 深度)
vec4 viewPos = toEye(v_textureCoordinates, depth);
// 世界坐标
vec4 wordPos = czm_inverseView * viewPos;
// 虚拟相机中坐标
vec4 vcPos = camera_view_matrix * wordPos;
float near = .001 * helsing_viewDistance;
float dis = length(vcPos.xyz);
if(dis > near && dis < helsing_viewDistance){
// 透视投影
vec4 posInEye = camera_projection_matrix * vcPos;
// 可视区颜色
// vec4 helsing_visibleAreaColor=vec4(0.,1.,0.,.5);
// vec4 helsing_invisibleAreaColor=vec4(1.,0.,0.,.5);
if(visible(posInEye)){
float vis = shadow(viewPos);
if(vis > 0.3){
// gl_FragColor = mix(gl_FragColor,helsing_visibleAreaColor,.5);
} else {
gl_FragColor = mix(gl_FragColor,helsing_invisibleAreaColor,.5);
}
}
}
}`;

View File

@ -0,0 +1,380 @@
// ViewShed.js
import Event from '../../../Event'
import MouseTip from '../../../MouseTip'
import Tools from '../../../Tools'
import EventBinding from '../../Element/Dialog/eventBinding'
import Dialog from '../../../BaseDialog'
import { html } from './_element'
/**
* @constructor
* @description 可视域分析
* @param sdk
* @param {Object} options 选项。
* @param {Number} options.viewPointHeight=1.8 视点高度(m)。
* @param {Number} options.precision=20 精度。
* @param {String} options.visibleAreaColor=#008000 可视区域颜色。
* @param {String} options.invisibleAreaColor=#FF0000 不可视区域颜色。
*/
class CircleViewShed extends Tools {
#intervalEvents = new Map()
constructor(sdk, options = {}, _Dialog = {}) {
super(sdk, options)
this.viewer = sdk.viewer
this.options = {}
this.options.visibleAreaColor = options.visibleAreaColor || '#008000'
this.options.invisibleAreaColor = options.invisibleAreaColor || '#FF0000'
this.ids = []
this.primitives = []
this.viewpointPrimitive = null
this._elms = {}
this.precision = options.precision
this.viewPointHeight = options.viewPointHeight
this.Dialog = _Dialog
this._EventBinding = new EventBinding()
this.html = null
YJ.Analysis.Analyses.push(this)
CircleViewShed.edit(this)
// CircleViewShed.create(this)
}
get viewPointHeight() {
return this.options.viewPointHeight
}
set viewPointHeight(v) {
let viewPointHeight = Math.floor(Number(v) * 10) / 10
if (isNaN(viewPointHeight)) {
viewPointHeight = 1.8
}
if (viewPointHeight < 0) {
viewPointHeight = 0
}
this.options.viewPointHeight = viewPointHeight
this._elms.viewPointHeight &&
this._elms.viewPointHeight.forEach(item => {
item.value = viewPointHeight
})
}
get precision() {
return this.options.precision
}
set precision(v) {
let precision = Math.floor(Number(v))
if (isNaN(precision)) {
precision = 20
} else if (precision < 1) {
precision = 1
}
this.options.precision = precision
this._elms.precision &&
this._elms.precision.forEach(item => {
item.value = precision
})
}
static create(that) {
let count = 0
if (!YJ.Measure.GetMeasureStatus()) {
if (that._DialogObject && that._DialogObject.close) {
that._DialogObject.close()
that._DialogObject = null
}
let Draw = new YJ.Draw.DrawCircle(that.sdk)
Draw.start(async (a, options) => {
// that.center = options.center
if(!options) {
return
}
that.radius = options.radius
let positions = await Cesium.sampleTerrainMostDetailed(
that.sdk.viewer.terrainProvider,
[Cesium.Cartographic.fromDegrees(options.center.lng, options.center.lat)]
);
that.center = {
lng: options.center.lng,
lat: options.center.lat,
alt: positions[0].height
}
await that.analyse()
})
} else {
console.log('上一次测量未结束')
}
}
static async edit(that) {
if (that._DialogObject && that._DialogObject.close) {
that._DialogObject.close()
that._DialogObject = null
}
that._DialogObject = await new Dialog(that.sdk.viewer._container, {
title: '圆形视域分析',
left: '180px',
top: '100px',
closeCallBack: () => {
that.Dialog.closeCallBack && that.Dialog.closeCallBack()
YJ.Measure.SetMeasureStatus(false)
}
})
await that._DialogObject.init()
that._DialogObject._element.body.className =
that._DialogObject._element.body.className + ' circle-view-shed'
let contentElm = document.createElement('div')
contentElm.innerHTML = html()
that._DialogObject.contentAppChild(contentElm)
let drawElm = document.createElement('button')
drawElm.innerHTML = '绘制'
drawElm.addEventListener('click', () => {
let terrainAvailability = that.viewer.terrainProvider.availability;
if (!terrainAvailability) {
window.ELEMENT && window.ELEMENT.Message({
message: '未加载地形数据!',
type: 'warning',
duration: 1500
});
return
}
CircleViewShed.create(that)
})
that._DialogObject.footAppChild(drawElm)
let all_elm = contentElm.getElementsByTagName('*')
that._EventBinding.on(that, all_elm)
that._elms = that._EventBinding.element
}
analyse() {
// this.destroy()
let center = [this.center.lng, this.center.lat]
let radius = this.radius / 1000
let circle = turf.circle(center, radius, {
steps: 180,
units: 'kilometers',
properties: { foo: 'bar' }
})
if (!this.viewpointPrimitive) {
this.viewpointPrimitive = this.viewer.scene.primitives.add(
new Cesium.PointPrimitiveCollection()
)
}
if (!this.viewBillboardPrimitive) {
this.viewBillboardPrimitive = this.viewer.scene.primitives.add(
new Cesium.BillboardCollection()
)
}
let array = []
let distance = radius / this.precision
for (let i = 1; i < circle.geometry.coordinates[0].length; i++) {
let line = turf.lineString([center, circle.geometry.coordinates[0][i]])
let array2 = []
for (let j = 1; j <= this.precision; j++) {
let sliced = turf.lineSliceAlong(line, 0, distance * j, {
units: 'kilometers'
})
array2.push([
sliced.geometry.coordinates[1][0],
sliced.geometry.coordinates[1][1]
])
}
array.push(array2)
}
let viewPoint = Cesium.Cartesian3.fromDegrees(
this.center.lng,
this.center.lat,
this.center.alt + this.viewPointHeight
)
let instances = []
CircleViewShed.getcanvas(this).then(canvas =>
this.viewBillboardPrimitive.add({
position: viewPoint,
image: canvas,
width: 200,
height: 140,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
disableDepthTestDistance: Number.POSITIVE_INFINITY
})
)
this.viewpointPrimitive.add({
position: viewPoint,
color: Cesium.Color.AQUA.withAlpha(1),
pixelSize: 6
})
let m = 0
let _this = this
let key = this.randomString()
let intervalEvent = setInterval(() => {
if (m >= array.length) {
let item = this.#intervalEvents.get(key)
item && clearInterval(item.event)
return
}
InBatches(m)
m += 1
}, 0)
this.#intervalEvents.set(key, { event: intervalEvent })
function InBatches(k) {
let instances = []
let i = k
for (let j = 0; j < array[i].length; j++) {
let pt1 = array[i][j]
let pt2
let pt3
let pt4 = array[i][j - 1]
if (i == array.length - 1) {
pt2 = array[0][j]
pt3 = array[0][j - 1]
} else {
pt2 = array[i + 1][j]
pt3 = array[i + 1][j - 1]
}
if (j == 0) {
pt3 = [...center]
pt4 = []
}
let cpt = [(pt1[0] + pt3[0]) / 2, (pt1[1] + pt3[1]) / 2]
let cartographic = Cesium.Cartographic.fromDegrees(cpt[0], cpt[1])
let height = _this.viewer.scene.globe.getHeight(cartographic)
let targetPoint = Cesium.Cartesian3.fromDegrees(cpt[0], cpt[1], height)
let direction = Cesium.Cartesian3.normalize(
Cesium.Cartesian3.subtract(
targetPoint,
viewPoint,
new Cesium.Cartesian3()
),
new Cesium.Cartesian3()
)
let ray = new Cesium.Ray(viewPoint, direction)
let pickedObjects = _this.viewer.scene.drillPickFromRay(
ray,
_this.primitives
)
let result
for (let i = 0; i < pickedObjects.length; i++) {
if (pickedObjects[i].position) {
result = pickedObjects[i]
break
}
}
let color = Cesium.Color.LIME
if (
result &&
Math.abs(result.position.x - targetPoint.x) > 0.01 &&
Math.abs(result.position.y - targetPoint.y) > 0.01 &&
Math.abs(result.position.z - targetPoint.z) > 0.01
) {
color = Cesium.Color.RED
}
let polyline = new Cesium.GroundPolylineGeometry({
positions: Cesium.Cartesian3.fromDegreesArray([
...pt1,
...pt2,
...pt3,
...pt4,
...pt1
]),
width: 2
})
let polygonInstance = new Cesium.GeometryInstance({
geometry: polyline,
name: 'ViewershedPolygon',
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(color),
show: new Cesium.ShowGeometryInstanceAttribute(true) //显示或者隐藏
}
})
instances.push(polygonInstance)
}
_this.primitives.push(
_this.viewer.scene.primitives.add(
new Cesium.GroundPolylinePrimitive({
geometryInstances: instances,
appearance: new Cesium.PolylineColorAppearance()
})
)
)
}
}
static getcanvas(that) {
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
canvas.width = 220
canvas.height = 140
canvas.style.background = '#000000'
let img = new Image()
const data = [
{
images: that.getSourceRootPath() + '/img/bubble/lng.png',
text: '经度:' + parseFloat(that.center.lng.toFixed(10)) + '°'
},
{
images: that.getSourceRootPath() + '/img/bubble/lat.png',
text: '纬度:' + parseFloat(that.center.lat.toFixed(10)) + '°'
},
{
images: that.getSourceRootPath() + '/img/bubble/h.png',
text: '视高:' + that.viewPointHeight + ' m'
},
{
images: that.getSourceRootPath() + '/img/bubble/radius.png',
text: '半径:' + that.radius + ' m'
}
]
img.src = that.getSourceRootPath() + '/img/bubble/bubble.png'
let imagesLoaded = 0
return new Promise(async (resolve, reject) => {
img.onload = () => {
ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
data.forEach((item, index) => {
const img = new Image()
img.src = item.images
img.onload = () => {
ctx.drawImage(img, 12, 12 + index * 26)
ctx.fillStyle = '#fff'
ctx.font = '12px Arial'
ctx.fillText(item.text, 44, 28 + index * 26)
imagesLoaded++
if (imagesLoaded === data.length) {
resolve(canvas)
}
}
})
}
})
}
destroy() {
for (const [key, value] of this.#intervalEvents) {
clearInterval(value.event)
}
this.#intervalEvents = new Map()
for (let i = 0; i < this.primitives.length; i++) {
this.viewer.scene.primitives.remove(this.primitives[i])
}
this.primitives = []
if (this.viewpointPrimitive) {
this.viewer.scene.primitives.remove(this.viewpointPrimitive)
this.viewpointPrimitive = null
}
if (this.viewBillboardPrimitive) {
this.viewer.scene.primitives.remove(this.viewBillboardPrimitive)
this.viewBillboardPrimitive = null
}
YJ.Measure.SetMeasureStatus(false)
}
}
export default CircleViewShed

View File

@ -0,0 +1,208 @@
import Tools from '../../../Tools';
class ContourAnalysis {
/**
* @constructor 等高线分析
* @param sdk
* **/
constructor(sdk, options = {}) {
this.viewer = sdk.viewer
let terrainAvailability = this.viewer.terrainProvider.availability;
if (!terrainAvailability) {
this.error = '未加载地形数据!'
window.ELEMENT && window.ELEMENT.Message({
message: '未加载地形数据!',
type: 'warning',
duration: 1500
});
console.warn(this.error)
return
}
this.positions = options.positions
this.interfaceNum = options.interfaceNum || 25 //内插时均分的数量即沿着边界长或宽均分成n分进行插点默认值25
this.colorFill = options.colorFill || [
"#8CEA00",
"#B7FF4A",
"#FFFF37",
"#FFE66F",
"#FFD1A4",
"#FFCBB3",
"#FFBD9D",
"#FFAD86",
"#FF9D6F",
"#FF8F59",
"#FF8040",
"#FF5809",
"#F75000",
"#D94600",
"#BB3D00",
"#A23400",
"#842B00",
"#642100",
"#4D0000",
"#2F0000",
]; //等高线赋值颜色内含default值
this.countorLineList = Cesium.defaultValue(options.countorLineList, []);
YJ.Analysis.Analyses.push(this)
this.createNewLine();
}
createNewLine() {
ContourAnalysis.interpolatePoint(this);
}
//利用turf在box内进行插点
static interpolatePoint(that) {
let curPoints = that.positions
let features = [];
const boundaryCoord = {
minX: 360,
maxX: -360,
minY: 180,
maxY: -180,
}; //绘制几何图形的外围矩形box
for (let index = 0; index < curPoints.length; index++) {
const element = Cesium.Cartesian3.fromDegrees(curPoints[index].lng, curPoints[index].lat, curPoints[index].alt);
let ellipsoid = that.viewer.scene.globe.ellipsoid;
let cartographic = ellipsoid.cartesianToCartographic(element);
let lat = Cesium.Math.toDegrees(cartographic.latitude);
let lng = Cesium.Math.toDegrees(cartographic.longitude);
boundaryCoord.maxY = Math.max(lat, boundaryCoord.maxY);
boundaryCoord.minY = Math.min(lat, boundaryCoord.minY);
boundaryCoord.maxX = Math.max(lng, boundaryCoord.maxX);
boundaryCoord.minX = Math.min(lng, boundaryCoord.minX);
let curFeature = {
type: "Feature",
properties: {},
geometry: {
type: "Point",
coordinates: [lng, lat],
},
};
features.push(curFeature);
}
let boundaryJson = {
type: "FeatureCollection",
features: features,
};
turf.featureEach(boundaryJson, function (point) {
point.properties.height = 0;
});
let options = {
gridType: "points",
property: "height",
units: "kilometers",
};
let from = turf.point([boundaryCoord.minX, boundaryCoord.minY]);
let to = turf.point([boundaryCoord.maxX, boundaryCoord.maxY]);
let diagonalDistance = turf.rhumbDistance(from, to, {
units: "kilometers",
});
let grid = turf.interpolate(
boundaryJson,
diagonalDistance / that.interfaceNum,
options
);
let minHeight = 10000000; //最低点高程值
let maxHeight = -100000000; //最高点高程值
turf.featureEach(grid, function (point) {
let pos = point.geometry.coordinates;
let cartographic = Cesium.Cartographic.fromDegrees(pos[0], pos[1]);
let height = that.viewer.scene.globe.getHeight(cartographic);
maxHeight = Math.max(height, maxHeight);
minHeight = Math.min(height, minHeight);
point.properties.height = height;
});
let breaks = [];
let stepCount = that.colorFill.length - 1;
let step = (maxHeight - minHeight) / stepCount;
for (let index = 0; index < stepCount + 1; index++) {
breaks.push(Math.ceil(minHeight + step * index));
}
// console.log('grid', grid)
let linesJson = turf.isolines(grid, breaks, { zProperty: "height" });
let _countorLine = Cesium.GeoJsonDataSource.load(linesJson, {
clampToGround: true,
});
// console.log(linesJson)
_countorLine.then(function (dataSource) {
console.log(dataSource)
that.countorLine = dataSource; //最终计算生成的等高线对象GeoJsonDataSource
that.countorLineList.push(dataSource); //等高线数组
that.viewer.dataSources.add(dataSource);
let entities = dataSource.entities.values;
for (let index = 0; index < entities.length; index++) {
const element = entities[index];
let center = getPolylineCenter(element.polyline);
element.position = center;
// dataSource.entities.add(new Cesium.Entity({
// position: center,
// label: {
// text: element.properties.height._value + '',
// font: '20px Microsoft YaHei',
// fillColor: Cesium.Color.fromCssColorString('#f1d20c'),
// style: Cesium.LabelStyle.FILL_AND_OUTLINE,
// disableDepthTestDistance: Number.POSITIVE_INFINITY,
// heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
// },
// }))
// element.label = new Cesium.LabelGraphics({
// })
let cur_index = that.getObjectIndex(
breaks,
element.properties.height._value
);
if (cur_index) {
element.polyline.material = Cesium.Color.fromCssColorString(
that.colorFill[cur_index - 1]
);
}
}
});
function getPolylineCenter(polyline) {
let tools = new Tools()
let positions = polyline.positions;
let length = positions._value.length;
let array = []
for (let i = 0; i < length; i++) {
let pos = tools.cartesian3Towgs84(positions._value[i], that.viewer)
array.push([pos.lng, pos.lat])
}
let line = turf.lineString(array);
let distance = turf.length(line, { units: "kilometers" });
let along = turf.along(line, distance/2, { units: "kilometers" });
return Cesium.Cartesian3.fromDegrees(along.geometry.coordinates[0], along.geometry.coordinates[1], 0);
}
}
/**
* 返回随机插入的数在数组中的位置
* @param {*} arr 元数组
* @param {*} num 随机数
* @returns 序号
* @example getObjectIndex([0,218,325,333,444],354)=>4;
*/
getObjectIndex(arr, num) {
for (let i = 0; i < arr.length; i++) {
if (arr[i] > num) {
return i;
}
}
}
clear(countorLine) {
if (countorLine) {
this.viewer.dataSources.remove(countorLine);
let index = this.countorLineList.indexOf(countorLine);
this.countorLineList.splice(index, 1);
}
}
destroy() {
this.countorLineList.forEach((element) => {
this.viewer.dataSources.remove(element);
});
this.countorLineList = [];
}
}
export default ContourAnalysis;

View File

@ -0,0 +1,125 @@
class CreatePolygon {
constructor(viewer) {
if (!viewer) throw new Error("no viewer object!");
this.activePoints = [];
this.viewer = viewer;
this.handler = undefined;
this.init();
}
init() {
this.activeShapePoints = [];
this.floatingPoint = undefined;
this.activeShape = undefined;
this.activePoints.forEach((element) => {
this.viewer.entities.remove(element);
});
this.activePoints = [];
this.initHandler();
}
start(callback) {
const $this = this;
$this.keyDownStatus(true);
$this.init();
$this.handler = new Cesium.ScreenSpaceEventHandler($this.viewer.canvas);
$this.handler.setInputAction(function (event) {
let earthPosition = $this.viewer.scene.pickPosition(event.position);
if (Cesium.defined(earthPosition)) {
if ($this.activeShapePoints.length === 0) {
$this.floatingPoint = $this.createPoint(earthPosition);
$this.activeShapePoints.push(earthPosition);
let dynamicPositions = new Cesium.CallbackProperty(function () {
return new Cesium.PolygonHierarchy($this.activeShapePoints);
}, false);
$this.activeShape = $this.drawShape(dynamicPositions); //绘制动态图
}
$this.activeShapePoints.push(earthPosition);
$this.createPoint(earthPosition);
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
$this.handler.setInputAction(function (event) {
if (Cesium.defined($this.floatingPoint)) {
let newPosition = $this.viewer.scene.pickPosition(event.endPosition);
if (Cesium.defined(newPosition)) {
$this.floatingPoint.position.setValue(newPosition);
$this.activeShapePoints.pop();
$this.activeShapePoints.push(newPosition);
}
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
$this.handler.setInputAction(function () {
$this.activeShapePoints.pop(); //去除最后一个动态点
if ($this.activeShapePoints.length) {
$this.polygon = $this.drawShape($this.activeShapePoints); //绘制最终图
}
$this.viewer.entities.remove($this.floatingPoint); //去除动态点图形(当前鼠标点)
$this.viewer.entities.remove($this.activeShape); //去除动态图形
$this.activePoints.forEach((element) => {
$this.viewer.entities.remove(element);
});
$this.handler.destroy();
setTimeout(() => {
if (typeof callback == "function") callback();
}, 1000);
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
}
initHandler() {
if (this.handler) {
this.handler.destroy();
this.handler = undefined;
}
}
createPoint(worldPosition) {
let point = this.viewer.entities.add({
position: worldPosition,
point: {
color: Cesium.Color.SKYBLUE,
pixelSize: 5,
},
});
this.activePoints.push(point);
return point;
}
drawShape(positionData) {
let shape = this.viewer.entities.add({
polygon: {
hierarchy: positionData,
material: new Cesium.ColorMaterialProperty(
Cesium.Color.BLUE.withAlpha(0.4)
),
zIndex: 99999999
},
});
return shape;
}
//快捷键//Ctrl + Z
keyDownStatus(bool) {
const $this = this;
document.onkeydown = function (event) {
if (event.ctrlKey && window.event.keyCode == 90) {
if (!bool) {
return false;
}
$this.activeShapePoints.pop();
$this.viewer.entities.remove(
$this.activePoints[$this.activePoints.length - 1]
);
$this.activePoints.pop();
}
};
}
/**
* Cesium中世界坐标系笛卡尔转经纬度
* @param {*} cartesian3
* @returns 经纬度
*/
Cartesian3ToDgrees(cartesian3) {
let cartographic =
window.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian3);
let lat = Cesium.Math.toDegrees(cartographic.latitude);
let lng = Cesium.Math.toDegrees(cartographic.longitude);
let alt = cartographic.height;
return { lng: lng, lat: lat, alt: alt };
}
}
export default CreatePolygon;

View File

@ -0,0 +1,75 @@
function html() {
return `
<span class="custom-divider"></span>
<div class="div-item">
<div class="row">
<div class="col">
<span class="label" style="flex: 0 0 70px;">绘制分析区域</span>
<button class="draw-btn"><svg class="icon-edit"><use xlink:href="#yj-icon-edit"></use></svg>开始绘制</button>
</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-1">
<input class="input" type="number" title="" min="-999999" max="999999" name="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">
<input class="input" type="number" title="" min="1" max="1250" name="precision">
<span class="arrow"></span>
</div>
</div>
</div>
</div>
<span class="custom-divider"></span>
<div class="div-item">
<div class="row">
<div class="col">
<span class="label" style="flex: 0 0 74px;">总分析面积:</span>
<span class="text-number" name="allArea">0</span>
<span class="unit text-number">m²</span>
</div>
<div class="col">
<span class="label" style="flex: 0 0 90px;">无须填挖面积:</span>
<span class="text-number" name="noArea">0</span>
<span class="unit text-number">m²</span>
</div>
</div>
<div class="row">
<div class="col">
<span class="label" style="flex: 0 0 74px;">填方面积:</span>
<span class="text-number" name="fillArea">0</span>
<span class="unit text-number">m²</span>
</div>
<div class="col">
<span class="label" style="flex: 0 0 90px;">挖方面积:</span>
<span class="text-number" name="cutArea">0</span>
<span class="unit text-number">m²</span>
</div>
</div>
<div class="row">
<div class="col">
<span class="label" style="flex: 0 0 74px;">填方体积:</span>
<span class="text-number" name="fillVolume">0</span>
<span class="unit text-number">m³</span>
</div>
<div class="col">
<span class="label" style="flex: 0 0 90px;">挖方体积:</span>
<span class="text-number" name="cutVolume">0</span>
<span class="unit text-number">m³</span>
</div>
</div>
</div>
<span class="custom-divider"></span>
`
}
export { html }

View File

@ -0,0 +1,354 @@
import Dialog from '../../../BaseDialog';
import { html } from "./_element";
// import CreatePolygon from "./CreatePolygon";
import DrawPolygon from "../../../Draw/drawPolygon"
class CutFillAnalysis {
/**
* @constructor 填挖方分析
* @param sdk
* **/
constructor(sdk, options = {}, _Dialog = {}) {
this.sdk = sdk;
this.viewer = sdk.viewer;
// if (!positions) throw new Error("no positions object!");
// this.positions = positions;
this.height = options.height || 70
this.maxHeigh = -1000000;
this.precision = options.precision || 125
this.Dialog = _Dialog
this.result = {
allArea: "",
cutArea: "",
cutVolume: "",
fillArea: "",
fillVolume: "",
noArea: "",
}
this.entities = []
this.Draw = new DrawPolygon(this.sdk)
YJ.Analysis.Analyses.push(this)
CutFillAnalysis.EditBox(this)
}
create() {
this.clean()
this.Draw.start((a, positions) => {
if(!positions || positions.length<3) {
let _error = '最少需要三个坐标!'
console.warn(_error)
window.ELEMENT && window.ELEMENT.Message({
message: _error,
type: 'warning',
duration: 1500
});
return
}
let fromDegreesArray = []
for (let i = 0; i < positions.length; i++) {
fromDegreesArray.push(positions[i].lng, positions[i].lat, positions[i].alt)
}
this.positions = Cesium.Cartesian3.fromDegreesArrayHeights(fromDegreesArray)
this.createPolygonGeo(this.positions);
this.result = this.VolumeAnalysis();
this.viewer.scene.screenSpaceCameraController.enableCollisionDetection = false; //允许相机进入地下
})
// const $this = this;
// if (!this.cp) {
// this.cp = new CreatePolygon(this.viewer)
// }
// this.cp.start(function () {
// console.log($this.cp.activeShapePoints)
// $this.positions = $this.cp.activeShapePoints;
// $this.createPolygonGeo($this.positions);
// $this.result = $this.VolumeAnalysis();
// $this.viewer.entities.remove($this.cp.polygon);
// $this.viewer.scene.screenSpaceCameraController.enableCollisionDetection = false; //允许相机进入地下
// });
}
createPolygonGeo(points) {
//计算网格粒度-精度
let granularity = Math.PI / Math.pow(2, 11);
granularity = granularity / this.precision;
let polygonGeometry = new Cesium.PolygonGeometry.fromPositions({
positions: points,
vertexFormat: Cesium.PerInstanceColorAppearance.FLAT_VERTEX_FORMAT,
granularity: granularity,
});
//创建自定义平面几何体
this.geom = new Cesium.PolygonGeometry.createGeometry(polygonGeometry);
}
VolumeAnalysis() {
let cutArea = 0,
cutVolume = 0,
fillArea = 0,
fillVolume = 0,
noArea = 0;
const indices = this.geom.indices; //获取顶点索引数据
if (!this.geom || !this.geom.attributes || !this.geom.attributes.position) {
return;
}
const positions = this.geom.attributes.position.values;
for (let index = 0; index < indices.length; index += 3) {
const pos0 = this.returnPosition(positions, indices[index]);
const pos1 = this.returnPosition(positions, indices[index + 1]);
const pos2 = this.returnPosition(positions, indices[index + 2]);
let entity = this.viewer.entities.add({
name: "三角面",
polygon: {
hierarchy: [pos0.heightPos, pos1.heightPos, pos2.heightPos],
perPositionHeight: true,
material: Cesium.Color.fromRandom(),
extrudedHeight: this.height,
outline: true,
outlineColor: Cesium.Color.BLACK,
},
});
this.entities.push(entity)
//水平状态下三角形面积
const area = this.computeArea4Triangle(
pos0.noHeightPos,
pos1.noHeightPos,
pos2.noHeightPos
);
//计算三个点的均高
const height = (pos0.height + pos1.height + pos2.height) / 3;
if (height < this.height) {
// 需要填方的部分
fillArea += area;
const volume = area * (this.height - height);
fillVolume += volume;
} else if (height == this.height) {
noArea += area;
} else {
// 需要挖方的部分
cutArea += area;
const volume = area * (height - this.height);
cutVolume += volume;
}
}
const allArea = cutArea + fillArea + noArea;
// this.result = {
// allArea,
// cutArea,
// cutVolume,
// fillArea,
// fillVolume,
// noArea,
// };
this.result.allArea = allArea
this.result.cutArea = cutArea
this.result.cutVolume = cutVolume
this.result.fillArea = fillArea
this.result.fillVolume = fillVolume
this.result.noArea = noArea
return this.result;
}
computeCentroid4Polygon(positions) {
let x = [],
y = [];
let allX = 0,
allY = 0;
for (let i = 0; i < positions.length; i++) {
let cartographic = Cesium.Cartographic.fromCartesian(positions[i]);
allX += cartographic.longitude;
allY += cartographic.latitude;
x.push(cartographic.longitude);
y.push(cartographic.latitude);
}
let centroidx = allX / positions.length;
let centroidy = allY / positions.length;
const Cartographic = new Cesium.Cartographic(centroidx, centroidy);
return Cesium.Cartesian3.fromRadians(
Cartographic.longitude,
Cartographic.latitude,
this.maxHeigh + 30
);
}
/**
* 海伦公式求取三角形面积
* @param {*} pos1
* @param {*} pos2
* @param {*} pos3
* @returns 三角形面积㎡
*/
computeArea4Triangle(pos1, pos2, pos3) {
let a = Cesium.Cartesian3.distance(pos1, pos2);
let b = Cesium.Cartesian3.distance(pos2, pos3);
let c = Cesium.Cartesian3.distance(pos3, pos1);
let S = (a + b + c) / 2;
return Math.sqrt(S * (S - a) * (S - b) * (S - c));
}
returnPosition(positions, index) {
let cartesian = new Cesium.Cartesian3(
positions[index * 3],
positions[index * 3 + 1],
positions[index * 3 + 2]
);
let cartographic = Cesium.Cartographic.fromCartesian(cartesian);
let height = this.viewer.scene.sampleHeightSupported
? this.viewer.scene.sampleHeight(cartographic)
: this.viewer.scene.globe.getHeight(cartographic);
if (height > this.maxHeigh) {
this.maxHeigh = height;
}
return {
heightPos: Cesium.Cartesian3.fromRadians(
cartographic.longitude,
cartographic.latitude,
height
),
noHeightPos: Cesium.Cartesian3.fromRadians(
cartographic.longitude,
cartographic.latitude,
0
),
height: height,
};
}
static async EditBox(that) {
if (that._DialogObject && that._DialogObject.close) {
that._DialogObject.close()
that._DialogObject = null
}
that._DialogObject = await new Dialog(that.sdk.viewer._container, {
title: '土方分析', left: '180px', top: '100px',
closeCallBack: () => {
that.clean()
that.Dialog.closeCallBack && that.Dialog.closeCallBack()
},
})
await that._DialogObject.init()
let contentElm = document.createElement('div');
contentElm.innerHTML = html()
that._DialogObject.contentAppChild(contentElm)
that._DialogObject._element.body.className = that._DialogObject._element.body.className + ' cut-fill'
// 高度值
let e_height = contentElm.querySelector("input[name='height']")
e_height.value = that.height
e_height.addEventListener('blur', (e) => {
let value = e.target.value
if (e.data != '.' && (e.data != '-' || e.target.value)) {
value = Number(value)
if ((e.target.max) && value > Number(e.target.max)) {
value = Number(e.target.max)
}
if ((e.target.min) && value < Number(e.target.min)) {
value = Number(e.target.min)
}
e_height.value = value
that.height = e_height.value;
}
});
// 精度值
let e_precision = contentElm.querySelector("input[name='precision']")
e_precision.value = that.precision
e_precision.addEventListener('blur', (e) => {
let value = Number(e.target.value)
if ((e.target.max) && value > Number(e.target.max)) {
value = Number(e.target.max)
}
if ((e.target.min) && value < Number(e.target.min)) {
value = Number(e.target.min)
}
e_precision.value = value
that.precision = e_precision.value;
});
// 总分析面积
let e_allArea = contentElm.querySelector("span[name='allArea']")
e_allArea.innerHTML = that.result.allArea || 0
Object.defineProperty(that.result, 'allArea', {
get() {
return e_allArea.innerHTML
},
set(value) {
e_allArea.innerHTML = Number(value.toFixed(4))
}
})
// 填方面积
let e_fillArea = contentElm.querySelector("span[name='fillArea']")
e_fillArea.innerHTML = that.result.fillArea || 0
Object.defineProperty(that.result, 'fillArea', {
get() {
return e_fillArea.innerHTML
},
set(value) {
e_fillArea.innerHTML = Number(value.toFixed(4))
}
})
// 填方体积
let e_fillVolume = contentElm.querySelector("span[name='fillVolume']")
e_fillVolume.innerHTML = that.result.fillVolume || 0
Object.defineProperty(that.result, 'fillVolume', {
get() {
return e_fillVolume.innerHTML
},
set(value) {
e_fillVolume.innerHTML = Number(value.toFixed(4))
}
})
// 挖方面积
let e_cutArea = contentElm.querySelector("span[name='cutArea']")
e_cutArea.innerHTML = that.result.cutArea || 0
Object.defineProperty(that.result, 'cutArea', {
get() {
return e_cutArea.innerHTML
},
set(value) {
e_cutArea.innerHTML = Number(value.toFixed(4))
}
})
// 挖方体积
let e_cutVolume = contentElm.querySelector("span[name='cutVolume']")
e_cutVolume.innerHTML = that.result.cutVolume || 0
Object.defineProperty(that.result, 'cutVolume', {
get() {
return e_cutVolume.innerHTML
},
set(value) {
e_cutVolume.innerHTML = Number(value.toFixed(4))
}
})
// 无须填挖面积
let e_noArea = contentElm.querySelector("span[name='noArea']")
e_noArea.innerHTML = that.result.noArea || 0
Object.defineProperty(that.result, 'noArea', {
get() {
return e_noArea.innerHTML
},
set(value) {
e_noArea.innerHTML = Number(value.toFixed(4))
}
})
let newDivBtn = contentElm.getElementsByClassName('draw-btn')[0];
newDivBtn.addEventListener('click', () => {
that.create()
});
}
clean() {
this.Draw && this.Draw.end()
for (let i = 0; i < this.entities.length; i++) {
this.viewer.entities.remove(this.entities[i])
}
}
destroy() {
this.clean()
if (this._DialogObject && this._DialogObject.close) {
this._DialogObject.close()
this._DialogObject = null
}
}
}
export default CutFillAnalysis;

View File

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

View File

@ -0,0 +1,227 @@
import Tools from "../../../Tools";
class Flat extends Tools {
/**
* @constructor
* @description 模型压平
* @param sdk
* @param {Cesium.Cesium3DTileset} tileset 三维模型
* @param {Object} options
* @param {string} attr.id id
* @param {Number} options.height 压平高度
* @param {Cesium.Cartesian3[]} attr.positions 压平面坐标
*/
constructor(sdk, tileset, options = {}) {
super(sdk)
if (!tileset) return;
this.options = { ...options }
this.options.id = options.id || this.randomString()
this.options.positions = options.positions || []
this.tileset = tileset;
this.height = options.height;
this.center = tileset.boundingSphere.center.clone();
this.matrix = Cesium.Transforms.eastNorthUpToFixedFrame(this.center.clone());
this.localMatrix = Cesium.Matrix4.inverse(this.matrix, new Cesium.Matrix4());
// 多面的坐标数组
this.regionList = [];
// 多个面坐标转为局部模型坐标
this.localPositionsArr = [];
this.addRegion()
}
/**
* 添加压平面
* @param {Object} attr 参数
* @param {Cesium.Cartesian3[]} attr.positions 压平面坐标
* @param {Number} attr.height 压平深度,当前不支持单独设置
* @param {Number} attr.id 唯一标识
*/
addRegion(attr) {
// let { positions, height, id } = attr || {};
// // this.flatHeight = height;
// if (!id) id = (new Date()).getTime() + "" + Number(Math.random() * 1000).toFixed(0);
// this.regionList.push(attr);
// for (let i = 0; i < this.regionList.length; i++) {
// let item = this.regionList[i];
// const positions = item.positions;
// let localCoor = this.cartesiansToLocal(positions);
// this.localPositionsArr.push(localCoor);
// }
let positions = this.options.positions
let fromDegreesArray = []
for (let i = 0; i < positions.length; i++) {
fromDegreesArray.push(positions[i].lng, positions[i].lat)
}
let localCoor = this.cartesiansToLocal(Cesium.Cartesian3.fromDegreesArray(fromDegreesArray));
this.localPositionsArr.push(localCoor);
const funstr = this.getIsinPolygonFun(this.localPositionsArr);
let str = ``;
for (let i = 0; i < this.localPositionsArr.length; i++) {
const coors = this.localPositionsArr[i];
const n = coors.length;
let instr = ``;
coors.forEach((coordinate, index) => {
instr += `points_${n}[${index}] = vec2(${coordinate[0]}, ${coordinate[1]});\n`;
})
str += `
${instr}
if(isPointInPolygon_${n}(position2D)){
vec4 tileset_local_position_transformed = vec4(tileset_local_position.x, tileset_local_position.y, ground_z, 1.0);
vec4 model_local_position_transformed = czm_inverseModel * u_tileset_localToWorldMatrix * tileset_local_position_transformed;
vsOutput.positionMC.xy = model_local_position_transformed.xy;
vsOutput.positionMC.z = model_local_position_transformed.z+ modelMC.z*0.002;
return;
}`;
}
this.updateShader(funstr, str);
}
/**
* 根据id删除压平的面
* @param {String} id 唯一标识
*/
removeRegionById(id) {
if (!id) return;
this.regionList = this.regionList.filter((attr) => {
return attr.id != id;
})
this.localPositionsArr = [];
for (let i = 0; i < this.regionList.length; i++) {
let item = this.regionList[i];
const positions = item.positions;
let localCoor = this.cartesiansToLocal(positions);
this.localPositionsArr.push(localCoor);
}
const funstr = this.getIsinPolygonFun(this.localPositionsArr);
let str = ``;
for (let i = 0; i < this.localPositionsArr.length; i++) {
const coors = this.localPositionsArr[i];
const n = coors.length;
let instr = ``;
coors.forEach((coordinate, index) => {
instr += `points_${n}[${index}] = vec2(${coordinate[0]}, ${coordinate[1]});\n`;
})
str += `
${instr}
if(isPointInPolygon_${n}(position2D)){
vec4 tileset_local_position_transformed = vec4(tileset_local_position.x, tileset_local_position.y, ground_z, 1.0);
vec4 model_local_position_transformed = czm_inverseModel * u_tileset_localToWorldMatrix * tileset_local_position_transformed;
vsOutput.positionMC.xy = model_local_position_transformed.xy;
vsOutput.positionMC.z = model_local_position_transformed.z+ modelMC.z*0.002;
return;
}`;
}
this.updateShader(funstr, str);
}
/**
* 销毁
*/
destroy() {
this.tileset.customShader = undefined;
}
/**
* 根据数组长度,构建 判断点是否在面内 的压平函数
*/
getIsinPolygonFun(polygons) {
let pmap = polygons.map((polygon) => polygon.length);
let uniqueArray = this.getUniqueArray(pmap);
let str = ``;
uniqueArray.forEach(length => {
str += `
vec2 points_${length}[${length}];
bool isPointInPolygon_${length}(vec2 point){
int nCross = 0; // 交点数
const int n = ${length};
for(int i = 0; i < n; i++){
vec2 p1 = points_${length}[i];
vec2 p2 = points_${length}[int(mod(float(i+1),float(n)))];
if(p1[1] == p2[1]){
continue;
}
if(point[1] < min(p1[1], p2[1])){
continue;
}
if(point[1] >= max(p1[1], p2[1])){
continue;
}
float x = p1[0] + ((point[1] - p1[1]) * (p2[0] - p1[0])) / (p2[1] - p1[1]);
if(x > point[0]){
nCross++;
}
}
return int(mod(float(nCross), float(2))) == 1;
}
`
})
return str
}
updateShader(vtx1, vtx2) {
let flatCustomShader = new Cesium.CustomShader({
uniforms: {
u_tileset_localToWorldMatrix: {
type: Cesium.UniformType.MAT4,
value: this.matrix,
},
u_tileset_worldToLocalMatrix: {
type: Cesium.UniformType.MAT4,
value: this.localMatrix,
},
u_flatHeight: {
type: Cesium.UniformType.FLOAT,
value: this.height,
},
},
vertexShaderText: `
// 所有isPointInPolygon函数
${vtx1}
void vertexMain(VertexInput vsInput, inout czm_modelVertexOutput vsOutput){
vec3 modelMC = vsInput.attributes.positionMC;
vec4 model_local_position = vec4(modelMC.x, modelMC.y, modelMC.z, 1.0);
vec4 tileset_local_position = u_tileset_worldToLocalMatrix * czm_model * model_local_position;
vec2 position2D = vec2(tileset_local_position.x,tileset_local_position.y);
float ground_z = 0.0 + u_flatHeight;
// 多个多边形区域
${vtx2}
}`,
});
this.tileset.customShader = flatCustomShader;
this.sdk.viewer.scene.requestRender();
}
// 数组去重,不能处理嵌套的数组
getUniqueArray = (arr) => {
return arr.filter(function (item, index, arr) {
//当前元素,在原始数组中的第一个索引==当前索引值,否则返回当前元素
return arr.indexOf(item, 0) === index;
});
}
// 世界坐标转数组局部坐标
cartesiansToLocal(positions) {
let arr = [];
for (let i = 0; i < positions.length; i++) {
let position = positions[i];
let localp = Cesium.Matrix4.multiplyByPoint(
this.localMatrix,
position.clone(),
new Cesium.Cartesian3()
)
arr.push([localp.x, localp.y]);
}
return arr;
}
}
export default Flat;

View File

@ -0,0 +1,8 @@
function html() {
return `
<span class="custom-divider"></span>
<div class="profile-echarts"></div>
`
}
export { html }

View File

@ -0,0 +1,637 @@
import Draw from "../../../Draw/draw";
import MouseEvent from "../../../Event";
import MouseTip from "../../../MouseTip";
import Dialog from '../../../BaseDialog';
import { html } from "./_element";
class Profile extends Draw {
/**
* @constructor 剖面分析
* @param sdk
**/
constructor(sdk, _Dialog = {}) {
window.addEventListener("resize", () => {
this.echartsObject && this.echartsObject.resize();
});
super(sdk)
this.viewer = sdk.viewer;
this.Dialog = _Dialog
YJ.Analysis.Analyses.push(this)
Profile.create(this)
}
static create(that) {
this._currentId = Cesium.createGuid()
let id = this._currentId
that.clean()
if (YJ.Measure.GetMeasureStatus()) {
console.warn('上一次测量未结束')
} else {
YJ.Measure.SetMeasureStatus(true)
that.tip = new MouseTip('左键确定,右键取消', that.sdk)
that.event = new MouseEvent(that.sdk)
that.positions = []
that.points_ids = [] //存放左键点击时临时添加的point的id
let cache_positions = []
let car = undefined
that.event.mouse_left(async (movement, cartesian) => {
try {
if (!that.entityHasCreated) {
Profile.create_polyline(that)
}
cache_positions.push(cartesian)
that.points_ids.push(that.create_point(cartesian,))
if (cache_positions.length == 2) {
that.end()
let positions = []
cache_positions.forEach((item) => {
positions.push(that.cartesian3Towgs84(item, that.viewer))
})
Profile.interPoints(that).then((points) => {
if (this._currentId && this._currentId === id) {
that._DialogObject ? Profile.initEcharts(that, points) : Profile.edit(that, points)
}
})
}
} catch (error) {
console.log(error)
}
})
that.event.mouse_right((movement, cartesian) => {
let positions = []
cache_positions = []
that.clean()
})
that.event.mouse_move((movement, cartesian) => {
that.positions = cache_positions.concat(cartesian)
that.tip.setPosition(
cartesian,
movement.endPosition.x,
movement.endPosition.y
)
})
that.event.gesture_pinck_start((movement, cartesian) => {
let startTime = new Date()
that.event.gesture_pinck_end(() => {
let endTime = new Date()
if (endTime - startTime >= 500) {
let positions = []
cache_positions = []
that.end()
}
})
})
}
}
static create_polyline(that) {
that.entityHasCreated = true
let id = that.randomString()
that.polyline = that.viewer.entities.add(
new Cesium.Entity({
id: id,
polyline: {
positions: new Cesium.CallbackProperty(() => {
return that.positions
}, false),
width: 5,
material: Cesium.Color.fromCssColorString(that.color),
clampToGround: true,
zIndex: 99999999
},
})
)
return id
}
/**
* 线段插值点
*/
static async interPoints(that) {
let viewer = that.viewer
let positions = that.positions
let positionsCartographic = []
let positions84 = [];
for (let index = 0; index < positions.length; index++) {
const element = positions[index];
let cartographic = viewer.scene.globe.ellipsoid.cartesianToCartographic(element);
positionsCartographic.push(cartographic);
let pos84 = that.cartesian3Towgs84(element, viewer)
positions84.push(pos84);
}
let positions_Inter = [];
let height = await that.getClampToHeight({ lng: positions84[0].lng, lat: positions84[0].lat });
positions_Inter.push({
position: { lng: positions84[0].lng, lat: positions84[0].lat, height: height },
distance: 0,
});
for (let i = 0; i < positionsCartographic.length - 1; i++) {
let line = turf.lineString([[positions84[i].lng, positions84[i].lat], [positions84[i + 1].lng, positions84[i + 1].lat]]);
let totalDistance = turf.length(line, { units: 'kilometers' });
const m_Cartographic0 = positionsCartographic[i];
const m_Cartographic1 = positionsCartographic[i + 1];
let a =
Math.abs(m_Cartographic0.longitude - m_Cartographic1.longitude) *
10000000;
let b =
Math.abs(m_Cartographic0.latitude - m_Cartographic1.latitude) *
10000000;
//等距采样
if (a > b) b = a;
let length = parseInt(b / 2);
if (length > 150) length = 150;
if (length < 2) length = 2;
let distance = totalDistance / (length - 1)
for (let j = 0; j < length - 1; j++) {
let start = j * distance
let stop = (j + 1) * distance
let sliced = await turf.lineSliceAlong(line, start, stop, { units: 'kilometers' });
let lng = sliced.geometry.coordinates[sliced.geometry.coordinates.length - 1][0]
let lat = sliced.geometry.coordinates[sliced.geometry.coordinates.length - 1][1]
let height = await that.getClampToHeight({ lng: lng, lat: lat });
positions_Inter.push({
position: { lng: lng, lat: lat, height: height },
distance: stop * 1000,
});
}
}
return positions_Inter
}
static async edit(that, points) {
if (that._DialogObject && that._DialogObject.close) {
that._DialogObject.close()
that._DialogObject = null
}
that._DialogObject = await new Dialog(that.sdk.viewer._container, {
title: '剖面分析', left: '180px', top: '100px',
closeCallBack: () => {
that.clean()
that.Dialog.closeCallBack && that.Dialog.closeCallBack()
},
})
await that._DialogObject.init()
that._DialogObject._element.body.className = that._DialogObject._element.body.className + ' profile'
let contentElm = document.createElement('div');
contentElm.innerHTML = html()
that._DialogObject.contentAppChild(contentElm)
let resetBtn = document.createElement('button');
resetBtn.innerHTML = '<svg class="icon-edit"><use xlink:href="#yj-icon-edit"></use></svg>重新绘制'
resetBtn.style.width = 'auto'
resetBtn.addEventListener('click', () => {
Profile.create(that)
Profile.initEcharts(that)
})
that._DialogObject.footAppChild(resetBtn)
Profile.initEcharts(that, points)
}
static initEcharts(that, points) {
let datas = [],
coords = [];
const pointsData = points;
let option
if (pointsData) {
const maxDistance = pointsData[pointsData.length - 1].distance;
let xAixMax = Math.ceil(maxDistance);
for (let index = 0; index < pointsData.length; index++) {
const element = pointsData[index];
if (element.position.height === void 0) {
continue
}
const curData = [
element.distance.toFixed(2),
element.position.height.toFixed(2),
];
datas.push(curData);
const curCoords = [element.position.lng, element.position.lat];
coords.push(curCoords);
}
const pointOption = {
show: true,
pixelSize: 10,
color: Cesium.Color.GREEN,
outlineColor: Cesium.Color.SKYBLUE,
outlineWidth: 3,
disableDepthTestDistance: Number.POSITIVE_INFINITY
};
const ele = that._DialogObject._element.content.getElementsByClassName("profile-echarts")[0];
that.echartsObject = echarts.init(ele);
option = {
tooltip: {
trigger: "axis",
textStyle: {
align: "left",
},
formatter(params) {
const xy = coords[params[0].dataIndex];
const tipData = params[0]["data"];
if (!that.tipEntity) {
that.tipEntity = that.sdk.viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(
xy[0],
xy[1],
Number(tipData[1])
),
point: pointOption,
});
} else {
that.tipEntity.position = Cesium.Cartesian3.fromDegrees(
xy[0],
xy[1],
Number(tipData[1])
);
}
return (
"距离:" +
tipData[0] +
"m<br>" +
"高度:" +
tipData[1] +
"m<br>" +
"坐标:" +
xy[0].toFixed(5) +
"" +
xy[1].toFixed(5)
);
},
},
grid: {
top: 40,
bottom: 20,
left: 55,
right: 30
},
calculable: true,
xAxis: [
{
type: "value",
max: xAixMax,
scale: true,
axisLabel: {
color: '#ffffff'
},
axisLine: {
lineStyle: {
color: "#ffffff"
}
}
},
],
yAxis: [
{
type: "value",
scale: true,
axisLabel: {
color: '#ffffff'
},
axisLine: {
lineStyle: {
color: "#ffffff"
}
}
},
],
series: [
{
name: "ProfileLine",
type: "line",
data: datas,
smooth: true,
itemStyle: {
normal: {
color: "#39FDA1",
},
},
lineStyle: {
normal: {
width: 3,
color: {
type: "linear",
x: 0,
y: 0,
x2: 1,
y2: 0,
colorStops: [
{
offset: 0,
color: "rgba(85,254,139,1)", // 0% 处的颜色
},
{
offset: 0.5,
color: "rgba(7,252,202,1)", // 100% 处的颜色
},
{
offset: 1,
color: "rgba(14,245,210,1)", // 100% 处的颜色
},
],
globalCoord: false, // 缺省为 false
},
},
},
areaStyle: {
normal: {
color: new echarts.graphic.LinearGradient(
0,
0,
0,
1,
[
{
offset: 0,
color: "rgba(102,153,255,1)",
},
{
offset: 0.8,
color: "rgba(102,153,255,0.08)",
},
{
offset: 1,
color: "rgba(9,173,208,0.15)",
},
],
false
),
shadowColor: "rgba(14,245,210,1)", //阴影颜色
shadowBlur: 20,
},
},
markPoint: {
data: [
{
type: "max",
name: "最高点",
label: {
color: '#ffffff',
}
},
{
type: "min",
name: "最低点",
label: {
color: '#ffffff',
}
},
],
},
},
],
};
}
else {
const ele = that._DialogObject._element.content.getElementsByClassName("profile-echarts")[0];
that.echartsObject = echarts.init(ele);
option = {
tooltip: {
trigger: "axis",
textStyle: {
align: "left",
}
},
grid: {
top: 40,
bottom: 20,
left: 55,
right: 30
},
calculable: true,
xAxis: [
{
type: "value",
scale: true,
axisLabel: {
color: '#ffffff'
},
axisLine: {
lineStyle: {
color: "#ffffff"
}
}
},
],
yAxis: [
{
type: "value",
scale: true,
axisLabel: {
color: '#ffffff'
},
axisLine: {
lineStyle: {
color: "#ffffff"
}
}
},
],
series: [
{
name: "ProfileLine",
type: "line",
data: [],
smooth: true,
itemStyle: {
normal: {
color: "#39FDA1",
},
},
lineStyle: {
normal: {
width: 3,
color: {
type: "linear",
x: 0,
y: 0,
x2: 1,
y2: 0,
colorStops: [
{
offset: 0,
color: "rgba(85,254,139,1)", // 0% 处的颜色
},
{
offset: 0.5,
color: "rgba(7,252,202,1)", // 100% 处的颜色
},
{
offset: 1,
color: "rgba(14,245,210,1)", // 100% 处的颜色
},
],
globalCoord: false, // 缺省为 false
},
},
},
areaStyle: {
normal: {
color: new echarts.graphic.LinearGradient(
0,
0,
0,
1,
[
{
offset: 0,
color: "rgba(102,153,255,1)",
},
{
offset: 0.8,
color: "rgba(102,153,255,0.08)",
},
{
offset: 1,
color: "rgba(9,173,208,0.15)",
},
],
false
),
shadowColor: "rgba(14,245,210,1)", //阴影颜色
shadowBlur: 20,
},
},
markPoint: {
data: [
{
type: "max",
name: "最高点",
label: {
color: '#ffffff',
}
},
{
type: "min",
name: "最低点",
label: {
color: '#ffffff',
}
},
],
},
},
],
};
}
that.echartsObject.setOption(option);
}
clean() {
this.end()
this._currentId = null
this.entityHasCreated = false
this.polyline && this.viewer.entities.remove(this.polyline)
this.tipEntity && this.viewer.entities.remove(this.tipEntity)
this.polyline = null
this.tipEntity = null
}
destroy() {
this.clean()
if (this._DialogObject && this._DialogObject.close) {
this._DialogObject.close()
this._DialogObject = null
}
}
}
// const Profile = function (viewer, callback) {
// if (!viewer) throw new Error("no viewer object!");
// if (window.profileEntities && window.profileEntities.length > 0) {
// window.profileEntities.forEach((element) => {
// window.viewer.entities.remove(element);
// });
// }
// window.profileEntities = [];
// CreatePolyline(
// viewer,
// window.profileEntities,
// { color: Cesium.Color.RED, width: 2 },
// function (e) {
// e.polyline.clampToGround = true;
// console.log(e.pottingPoint);
// let points = interPoints(viewer, e.pottingPoint, [e]);
// console.log(points);
// if (typeof callback == "function") callback(points);
// }
// );
// };
// /**
// * 线段插值点
// * @param {*} viewer
// * @param {*} positions 线段节点集合
// * @param {*} objectsToExclude 高度采集时排除的对象集合
// * @returns 经纬度点集合,包含距离值
// */
// function interPoints(viewer, positions, objectsToExclude) {
// let positionsCartographic = [];
// let terrainSamplePositions = [];
// for (let index = 0; index < positions.length; index++) {
// const element = positions[index];
// let ellipsoid = viewer.scene.globe.ellipsoid;
// let cartographic = ellipsoid.cartesianToCartographic(element);
// positionsCartographic.push(cartographic);
// }
// for (let i = 0; i < positionsCartographic.length; i++) {
// const m_Cartographic0 = positionsCartographic[i];
// const m_Cartographic1 = positionsCartographic[i + 1];
// if (m_Cartographic1) {
// let a =
// Math.abs(m_Cartographic0.longitude - m_Cartographic1.longitude) *
// 10000000;
// let b =
// Math.abs(m_Cartographic0.latitude - m_Cartographic1.latitude) *
// 10000000;
// //等距采样
// if (a > b) b = a;
// let length = parseInt(b / 2);
// if (length > 1000) length = 1000;
// if (length < 2) length = 2;
// for (let j = 0; j < length; j++) {
// terrainSamplePositions.push(
// new Cesium.Cartographic(
// Cesium.Math.lerp(
// m_Cartographic0.longitude,
// m_Cartographic1.longitude,
// j / (length - 1)
// ),
// Cesium.Math.lerp(
// m_Cartographic0.latitude,
// m_Cartographic1.latitude,
// j / (length - 1)
// )
// )
// );
// }
// terrainSamplePositions.pop();
// } else {
// terrainSamplePositions.push(m_Cartographic0);
// }
// }
// let positions_Inter = [];
// let distance = 0;
// for (let n = 0; n < terrainSamplePositions.length; n++) {
// //地理坐标(弧度)转经纬度坐标
// let curCartographic = terrainSamplePositions[n];
// let height = viewer.scene.sampleHeight(curCartographic, objectsToExclude);
// const lon = (curCartographic.longitude / Math.PI) * 180;
// const lat = (curCartographic.latitude / Math.PI) * 180;
// let point = Cesium.Cartesian3.fromDegrees(lon, lat, height);
// let preCartographic = terrainSamplePositions[n - 1];
// if (preCartographic) {
// const lon1 = (preCartographic.longitude / Math.PI) * 180;
// const lat1 = (preCartographic.latitude / Math.PI) * 180;
// let point1 = Cesium.Cartesian3.fromDegrees(lon1, lat1, height);
// let curDis = Cesium.Cartesian3.distance(point1, point);
// distance += curDis;
// }
// positions_Inter.push({
// position: { lon: lon, lat: lat, height: height },
// distance: distance,
// });
// }
// return positions_Inter;
// }
export default Profile;

View File

@ -0,0 +1,145 @@
import Tools from "../../../Tools";
class Section extends Tools {
/**
* @constructor 剖切
* @param sdk
* @param tiles3d {object} 3dtiles对象
* @param {Array.<object>} options.positions 经纬度[{lon,lat,alt},...]
* @param options.regionsType=false 裁剪类型 false:裁剪内部true:裁剪外部
* **/
constructor(sdk, tiles3d, options = {}) {
super(sdk, options)
this.viewer = sdk.viewer
this.tiles3d = tiles3d
this.options = { ...options }
this.options.regionsType = this.options.regionsType || false
// YJ.Analysis.Analyses.push(this)
this.Planes = []
Section.start(this)
}
get regionsType() {
return this.options.regionsType
}
set regionsType(v) {
this.options.regionsType = v
if (this.Planes.length > 0) {
this.Planes = []
Section.planeCollection(this)
}
}
static start(that) {
let positions = that.options.positions || []
if(!that.isConvex(positions)) {
window.ELEMENT && window.ELEMENT.Message({
message: '不支持凹多边形',
type: 'warning',
duration: 1500
});
console.log('不支持凹多边形')
return
}
that.inverseTransform = getInverseTransform(that.tiles3d)
that.Planes = []
let array = []
if (positions.length > 0) {
for (let i = 0; i < positions.length; i++) {
array.push([positions[i].lng, positions[i].lat])
}
array.push([positions[0].lng, positions[0].lat])
that.isClockwise = turf.booleanClockwise(turf.lineString(array));
}
Section.planeCollection(that)
function getInverseTransform(tileSet) {
let transform
const tmp = tileSet.root.transform
if ((tmp && tmp.equals(Cesium.Matrix4.IDENTITY)) || !tmp) {
transform = Cesium.Transforms.eastNorthUpToFixedFrame(tileSet.boundingSphere.center)
} else {
transform = Cesium.Matrix4.fromArray(tileSet.root.transform)
}
return Cesium.Matrix4.inverseTransformation(transform, new Cesium.Matrix4())
}
}
static planeCollection(that) {
let positions = that.options.positions || []
if (that.regionsType == that.isClockwise) {
for (let i = 0; i < positions.length; i++) {
if (i === (positions.length - 1)) {
that.Planes.push(createPlane(positions[i], positions[0], that.inverseTransform))
} else {
that.Planes.push(createPlane(positions[i], positions[i + 1], that.inverseTransform))
}
}
}
else {
for (let i = positions.length - 1; i >= 0; i--) {
if (i === 0) {
that.Planes.push(createPlane(positions[i], positions[positions.length - 1], that.inverseTransform))
} else {
that.Planes.push(createPlane(positions[i], positions[i - 1], that.inverseTransform))
}
}
}
if(that.tiles3d.clippingPlanes) {
that.tiles3d.clippingPlanes.removeAll()
for(let i=0;i<that.Planes.length;i++) {
that.tiles3d.clippingPlanes.add(that.Planes[i])
}
that.tiles3d.clippingPlanes.enabled = true
}
else {
const PlaneCollection = new Cesium.ClippingPlaneCollection({
planes: that.Planes,
enabled: true,
unionClippingRegions: that.regionsType,
edgeColor: Cesium.Color.WHITE,
edgeWidth: 1,
})
that.tiles3d.clippingPlanes = PlaneCollection
}
function createPlane(p1, p2, inverseTransform) {
// 将仅包含经纬度信息的p1,p2转换为相应坐标系的cartesian3对象
const p1C3 = getOriginCoordinateSystemPoint(p1, inverseTransform)
const p2C3 = getOriginCoordinateSystemPoint(p2, inverseTransform)
// 定义一个垂直向上的向量up
const up = new Cesium.Cartesian3(0, 0, 10)
// right 实际上就是由p1指向p2的向量
const right = Cesium.Cartesian3.subtract(p2C3, p1C3, new Cesium.Cartesian3())
// 计算normal right叉乘up得到平面法向量这个法向量指向right的右侧
let normal = Cesium.Cartesian3.cross(right, up, new Cesium.Cartesian3())
normal = Cesium.Cartesian3.normalize(normal, normal)
// 由于已经获得了法向量和过平面的一点因此可以直接构造Plane,并进一步构造ClippingPlane
const planeTmp = Cesium.Plane.fromPointNormal(p1C3, normal)
return Cesium.ClippingPlane.fromPlane(planeTmp)
}
function getOriginCoordinateSystemPoint(point, inverseTransform) {
const val = Cesium.Cartesian3.fromDegrees(point.lng, point.lat)
return Cesium.Matrix4.multiplyByPoint(
inverseTransform, val, new Cesium.Cartesian3(0, 0, 0))
}
}
destroy() {
this.Planes = []
// this.tiles3d.clippingPlanes = new Cesium.ClippingPlaneCollection()
if(this.tiles3d.clippingPlanes) {
this.tiles3d.clippingPlanes.enabled = false
this.tiles3d.clippingPlanes.removeAll()
}
}
}
export default Section;

View File

@ -0,0 +1,517 @@
import Tools from "../../../Tools";
import DrawPolygon from "../../../Draw/drawPolygon"
import MouseEvent from '../../../Event/index'
class SlopeAspect extends Tools {
/**
* @constructor 坡度坡向分析
* @param sdk
* **/
constructor(sdk) {
super(sdk)
this.viewer = sdk.viewer;
let terrainAvailability = this.viewer.terrainProvider.availability;
if (!terrainAvailability) {
this.error = '未加载地形数据!'
window.ELEMENT && window.ELEMENT.Message({
message: '未加载地形数据!',
type: 'warning',
duration: 1500
});
return
}
this.event
this.result = []; //存储创建的坡度分析结果primitive集合
this.handler = undefined;
this.toolTip = "";
YJ.Analysis.Analyses.push(this)
this.Draw = new DrawPolygon(this.sdk)
// this.createNew4Distance()
this.createNew4Num(50)
}
//等距离切分网格
createNew4Distance(distance) {
distance = distance || 0.1; //默认0.1km精度
let width = distance * 200 > 35 ? 35 : distance * 200;
this.arrowWidth = width < 15 ? 15 : width;
const $this = this;
const viewer = this.viewer;
this.Draw.start((e, positions) => {
if (!positions || positions.length <= 2) {
window.ELEMENT && window.ELEMENT.Message({
message: '至少拥有三个坐标位置!',
type: 'warning',
duration: 1500
});
return
}
let boundary = [];
let minX = 10000,
minY = 10000,
maxX = -10000,
maxY = -1000;
for (let index = 0; index < positions.length; index++) {
const element = positions[index];
const x = element.lng;
const y = element.lat;
boundary.push([x, y]);
minX = x < minX ? x : minX;
minY = y < minY ? y : minY;
maxX = x > maxX ? x : maxX;
maxY = y > maxY ? y : maxY;
}
boundary.push(boundary[0]);
let bbox = [minX, minY, maxX, maxY];
let mask = turf.polygon([boundary]);
let gridSquare = turf.squareGrid(bbox, distance, { mask: mask });
this.createEllipse(gridSquare);
})
}
// 等分切分网格切分成一个num*num的网格
createNew4Num(n) {
let num = n
this.Draw.start((e, positions) => {
if (!positions || positions.length <= 2) {
console.warn('至少拥有三个坐标位置!')
return
}
let boundary = [];
let minX = 10000,
minY = 10000,
maxX = -10000,
maxY = -1000;
for (let index = 0; index < positions.length; index++) {
const element = positions[index];
const x = element.lng;
const y = element.lat;
boundary.push([x, y]);
minX = x < minX ? x : minX;
minY = y < minY ? y : minY;
maxX = x > maxX ? x : maxX;
maxY = y > maxY ? y : maxY;
}
boundary.push(boundary[0]);
let bbox = [minX, minY, maxX, maxY];
let a = maxX - minX;
let b = maxY - minY;
b = b > a ? b : a;
// 根据面积修改网格数
let mask = turf.polygon([boundary]);
let area = turf.area(mask);
if (area > 5000000000000) {
num = num - 25;
}
else if (area > 1000000000000) {
num = num - 20;
}
else if (area > 500000000000) {
num = num - 15;
}
else if (area > 100000000000) {
num = num - 10;
}
else if (area > 60000000000) {
num = num - 5;
}
const step = b / num;
let width = step * 2000 > 35 ? 35 : step * 2000;
this.arrowWidth = width < 15 ? 15 : width;
let gridSquare = turf.squareGrid(bbox, step, {
units: "degrees",
mask: mask,
});
this.createEllipse(gridSquare);
})
// CreatePolygonOnGround(
// viewer,
// [],
// {
// color: Cesium.Color.RED.withAlpha(0.1),
// outlineColor: Cesium.Color.YELLOW,
// outlineWidth: 2,
// },
// function (polygon) {
// let degrees = $this.Cartesian3ListToWGS84(polygon.pottingPoint);
// viewer.entities.remove(polygon);
// let boundary = [];
// let minX = 10000,
// minY = 10000,
// maxX = -10000,
// maxY = -1000;
// for (let index = 0; index < degrees.length; index++) {
// const element = degrees[index];
// const x = element.lng;
// const y = element.lat;
// boundary.push([x, y]);
// minX = x < minX ? x : minX;
// minY = y < minY ? y : minY;
// maxX = x > maxX ? x : maxX;
// maxY = y > maxY ? y : maxY;
// }
// boundary.push(boundary[0]);
// let bbox = [minX, minY, maxX, maxY];
// let a = maxX - minX;
// let b = maxY - minY;
// b = b > a ? b : a;
// const step = b / num;
// let width = step * 2000 > 35 ? 35 : step * 2000;
// this.arrowWidth = width < 15 ? 15 : width;
// let mask = turf.polygon([boundary]);
// let gridSquare = turf.squareGrid(bbox, step, {
// units: "degrees",
// mask: mask,
// });
// this.createEllipse(gridSquare);
// }
// );
}
createEllipse(gridSquare) {
let boxResults = [];
for (let index = 0; index < gridSquare.features.length; index++) {
const feature = gridSquare.features[index];
const coordinates = feature.geometry.coordinates[0];
const centerdegree = [
(coordinates[0][0] + coordinates[2][0]) / 2,
(coordinates[0][1] + coordinates[2][1]) / 2,
];
let centerCartographic = Cesium.Cartographic.fromDegrees(
centerdegree[0],
centerdegree[1]
);
boxResults.push(centerCartographic);
for (let i = 0; i < coordinates.length; i++) {
const coord = coordinates[i];
let cartographic = Cesium.Cartographic.fromDegrees(coord[0], coord[1]);
boxResults.push(cartographic);
const coord1 = coordinates[i + 1];
if (coord1) {
let newCoord = [
(coord[0] + coord1[0]) / 2,
(coord[1] + coord1[1]) / 2,
];
let newCartographic = Cesium.Cartographic.fromDegrees(
newCoord[0],
newCoord[1]
);
boxResults.push(newCartographic);
}
}
}
let _this = this
// 点位过多,分为三份计算
let num = (Math.floor(boxResults.length / 3) + '')
num = Number(num.substring(0, num.length - 1))*10
let i=0
let points = boxResults.slice(i * num, (i + 1) * num)
if (points.length > 0) {
sampleTerrainMostDetailed(points)
}
function sampleTerrainMostDetailed(ps) {
Cesium.sampleTerrainMostDetailed(
_this.viewer.scene.terrainProvider,
ps
).then((updatePositions) => {
i++
let points = boxResults.slice(i * num, (i + 1) * num)
if (points.length > 0) {
sampleTerrainMostDetailed(points)
}
let arrr = [];
let ellipseResults = updatePositions.reduce(function (
pre,
item,
index,
updatePositions
) {
var begin = index * 10;
var end = begin + 10;
var res = updatePositions.slice(begin, end);
if (res.length != 0) {
arrr[index] = res;
}
return arrr;
},
[]);
_this.calculateSlope(ellipseResults);
});
}
}
createPolygonInsrance(points, color, curSlope) {
let positions = [];
for (let index = 1; index < points.length - 1; index++) {
const element = points[index];
positions.push(Cesium.Cartographic.toCartesian(element));
}
let polygon = new Cesium.PolygonGeometry({
polygonHierarchy: new Cesium.PolygonHierarchy(positions),
});
let polygonInstance = new Cesium.GeometryInstance({
id: {
type: "SlopeAspect",
value: curSlope
},
geometry: polygon,
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
Cesium.Color.fromCssColorString(color)
),
show: new Cesium.ShowGeometryInstanceAttribute(true), //显示或者隐藏
},
});
return polygonInstance;
}
createArrowInstance(
targetPoint,
center,
diagonalPoint,
heightDifference,
curSlope
) {
let cartographic_0 = new Cesium.Cartographic(
(targetPoint.longitude + center.longitude) / 2,
(targetPoint.latitude + center.latitude) / 2,
(targetPoint.height + center.height) / 2
);
let cartographic_1 = new Cesium.Cartographic(
(diagonalPoint.longitude + center.longitude) / 2,
(diagonalPoint.latitude + center.latitude) / 2,
(diagonalPoint.height + center.height) / 2
);
//偏移的
let positions1 =
heightDifference > 0
? [
Cesium.Cartographic.toCartesian(cartographic_0),
Cesium.Cartographic.toCartesian(cartographic_1),
]
: [
Cesium.Cartographic.toCartesian(cartographic_1),
Cesium.Cartographic.toCartesian(cartographic_0),
];
//箭头线
const instance = new Cesium.GeometryInstance({
id: {
type: "SlopeAspect",
value: curSlope,
},
geometry: new Cesium.GroundPolylineGeometry({
positions: positions1,
width: this.arrowWidth,
}),
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
Cesium.Color.BLUE.withAlpha(0.6)
),
show: new Cesium.ShowGeometryInstanceAttribute(true), //显示或者隐藏
},
});
return instance;
}
calculateSlope(ellipseResults) {
let instances = [];
let polygonInstance = [];
for (let index = 0; index < ellipseResults.length; index++) {
const ellipse = ellipseResults[index];
const center = ellipse[0];
let heightDifference = 0;
let maxIndex = 0;
for (let i = 1; i < ellipse.length - 1; i++) {
const point = ellipse[i];
let curHD = point.height - center.height;
if (Math.abs(curHD) > heightDifference) {
heightDifference = curHD;
maxIndex = i;
}
}
let pos0 = new Cesium.Cartographic(center.longitude, center.latitude, 0);
let pos1 = new Cesium.Cartographic(
ellipse[maxIndex].longitude,
ellipse[maxIndex].latitude,
0
);
let distance = Cesium.Cartesian3.distance(
Cesium.Cartographic.toCartesian(pos0),
Cesium.Cartographic.toCartesian(pos1)
);
let curSlope = Math.abs(heightDifference / distance); //坡度的tan值
let curColor = this.calculateSlopeColor(curSlope, 0.4);
const curPolygonInstance = this.createPolygonInsrance(ellipse, curColor, curSlope);
polygonInstance.push(curPolygonInstance);
let diagonalPoint =
maxIndex > 4 ? ellipse[maxIndex - 4] : ellipse[maxIndex + 4]; //对角点
let targetPoint = ellipse[maxIndex];
const arrowInstance = this.createArrowInstance(
targetPoint,
center,
diagonalPoint,
heightDifference,
curSlope
);
instances.push(arrowInstance);
}
const mapPrimitive = this.viewer.scene.primitives.add(
new Cesium.GroundPrimitive({
geometryInstances: polygonInstance,
appearance: new Cesium.PerInstanceColorAppearance({
translucent: true, //false时透明度无效
closed: false,
}),
})
);
const arrowPrimitive = this.viewer.scene.primitives.add(
new Cesium.GroundPolylinePrimitive({
geometryInstances: instances,
appearance: new Cesium.PolylineMaterialAppearance({
material: new Cesium.Material({
fabric: {
type: "PolylineArrow",
uniforms: {
color: new Cesium.Color(1.0, 1.0, 0.0, 0.8),
},
},
}),
}),
})
);
this.result.push(arrowPrimitive, mapPrimitive);
this.event = new MouseEvent(this.sdk)
let mouseEvent = (movement, cartesian) => {
// console.log(movement, cartesian)
let infoBox = document.getElementById('SlopeAspect-box')
if (!infoBox) {
infoBox = document.createElement('div')
infoBox.id = 'SlopeAspect-box'
infoBox.style.pointerEvents = 'none'
infoBox.style.display = 'none'
infoBox.style.position = 'absolute'
infoBox.style.background = '#333333'
infoBox.style.color = '#fff'
infoBox.style.color = '#fff'
infoBox.style.padding = '5px'
infoBox.style.fontSize = '12px'
infoBox.style.borderRadius = '5px'
infoBox.style.transform = 'translate(-50%, -10px)'
infoBox.innerHTML = `
<div class="value">坡度:</div>
<span style="
position: absolute;
border: 4px solid;
border-color: #fff0 #fff0 #333333 #333333;
transform: rotate(-45deg);
left: calc(50% - 5px);
"></span>
`
document.body.appendChild(infoBox)
}
let vlaElm = infoBox.getElementsByClassName('value')[0]
let position = { ...movement.position }
let pickedObject = this.sdk.viewer.scene.pick(position);
if (pickedObject && pickedObject.id && pickedObject.id.type && pickedObject.id.type === "SlopeAspect") {
let top = 0
let left = 0
if (this.sdk.viewer && this.sdk.viewer._element) {
let element = this.sdk.viewer._element.getElementsByClassName('cesium-widget')[0].getElementsByTagName('canvas')[0]
top = element.getBoundingClientRect().top + window.scrollY
left = element.getBoundingClientRect().left + window.scrollX
}
infoBox.style.display = 'block'
infoBox.style.left = position.x + 2 + left + 'px'
infoBox.style.top = position.y - 20 + top + 'px'
vlaElm.innerHTML = '坡度:' + Number(Cesium.Math.toDegrees(pickedObject.id.value || 0).toFixed(2)) + '°'
}
else {
infoBox.style.display = 'none'
}
}
this.event.mouse_move((movement, cartesian) => {
let newMovement = {
position: { ...movement.endPosition }
}
mouseEvent(newMovement, cartesian)
})
this.event.mouse_left(mouseEvent)
this._camera = {
position: this.sdk.viewer.camera.position,
heading: this.sdk.viewer.camera.heading,
pitch: this.sdk.viewer.camera.pitch,
roll: this.sdk.viewer.camera.roll
}
this.sdk.viewer.scene.preRender.addEventListener(this._watchEvent, this)
// this.sdk.viewer.clock.onTick.addEventListener(() => {
// console.log(111111)
// let infoBox = document.getElementById('SlopeAspect-box')
// if(infoBox) {
// infoBox.style.display = 'none'
// }
// })
}
_watchEvent() {
if (
this._camera.position.x.toFixed(8) !== this.sdk.viewer.camera.position.x.toFixed(8) ||
this._camera.position.y.toFixed(8) !== this.sdk.viewer.camera.position.y.toFixed(8) ||
this._camera.position.z.toFixed(8) !== this.sdk.viewer.camera.position.z.toFixed(8) ||
this._camera.heading.toFixed(8) !== this.sdk.viewer.camera.heading.toFixed(8) ||
this._camera.pitch.toFixed(8) !== this.sdk.viewer.camera.pitch.toFixed(8) ||
this._camera.roll.toFixed(8) !== this.sdk.viewer.camera.roll.toFixed(8)
) {
let infoBox = document.getElementById('SlopeAspect-box')
if (infoBox) {
infoBox.style.display = 'none'
}
}
this._camera = {
position: this.sdk.viewer.camera.position,
heading: this.sdk.viewer.camera.heading,
pitch: this.sdk.viewer.camera.pitch,
roll: this.sdk.viewer.camera.roll
}
}
//根据坡度值赋值颜色
calculateSlopeColor(value, alpha) {
// 0°0.5°为平原0.00872686779075879,rgb(85,182,43)
// 0.5°2°为微斜坡0.03492076949174773,rgb(135,211,43)
// 2°5°为缓斜坡0.08748866352592401,rgb(204,244,44)
// 5°15°为斜坡0.2679491924311227,rgb(245,233,44)
// 15°35°为陡坡0.7002075382097097,rgb(255,138,43)
// 35°55°为峭坡1.4281480067421144,rgb(255,84,43)
// 55°90°为垂直壁,rgb(255,32,43)
if (value < 0.00872686779075879) {
return "rgba(85,182,43," + alpha + ")";
} else if (value < 0.03492076949174773) {
return "rgba(135,211,43," + alpha + ")";
} else if (value < 0.08748866352592401) {
return "rgba(204,244,44," + alpha + ")";
} else if (value < 0.2679491924311227) {
return "rgba(245,233,44," + alpha + ")";
} else if (value < 0.7002075382097097) {
return "rgba(255,138,43," + alpha + ")";
} else if (value < 1.4281480067421144) {
return "rgba(255,84,43," + alpha + ")";
} else {
return "rgba(255,32,43," + alpha + ")";
}
}
destroy() {
this.result && this.result.forEach((element) => {
this.viewer.scene.primitives.remove(element);
});
this.result = [];
this.sdk.viewer.scene.preRender.removeEventListener(this._watchEvent, this)
}
}
export default SlopeAspect;

View File

@ -0,0 +1,92 @@
function html() {
return `
<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="" name="waterVolume">
<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="" name="minWaterLevel">
<span class="unit">m</span>
<span class="arrow"></span>
</div>
</div>
</div>
<div class="row">
<div class="col">
<span class="label">水面面积</span>
<div class="input-number input-number-unit-3">
<input class="input area" type="number" readonly="readonly" type="text">
<span class="unit">㎡</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="" name="maxWaterLevel">
<span class="unit">m</span>
<span class="arrow"></span>
</div>
</div>
</div>
</div>
<span class="custom-divider"></span>
<div class="div-item">
<div class="row subtitle-box">
<span class="subtitle">上升速度</span>
</div>
<div class="row">
<div class="col">
<input type="range" max="50" min="0" step="0.01" name="risingSpeed">
<div class="input-number input-number-unit-3" style="flex: 0 0 110px;margin-left: 10px;">
<input class="input" type="number" title="" name="risingSpeed">
<span class="unit">m/s</span>
<span class="arrow"></span>
</div>
</div>
</div>
</div>
<span class="custom-divider"></span>
<div class="div-item">
<div class="row">
<div class="col operate-btn-box">
<button class="draw"><svg class="icon-draw"><use xlink:href="#yj-icon-draw"></use></svg>绘制范围</button>
<button class="flyto"><svg class="icon-positions"><use xlink:href="#yj-icon-positions"></use></svg>定位</button>
<button class="reset"><svg class="icon-reset"><use xlink:href="#yj-icon-reset"></use></svg>重置</button>
<button class="analog"><svg class="icon-play"><use xlink:href="#yj-icon-play"></use></svg>开始模拟</button>
<button class="pause" style="margin-right: 0px;"><svg class="icon-pause"><use xlink:href="#yj-icon-pause"></use></svg>暂停</button>
<button class="start" style="display: none;margin-right: 0px;"><svg class="icon-play"><use xlink:href="#yj-icon-play"></use></svg>播放</button>
</div>
</div>
</div>
<div class="table">
<div class="table-head">
<div class="tr">
<div class="th">序号</div>
<div class="th">经度</div>
<div class="th">纬度</div>
<div class="th">高程</div>
</div>
</div>
<div class="table-body">
</div>
<div class="table-empty">
<div class="empty-img"></div>
<p>暂无数据</p>
</div>
</div>
<span class="custom-divider" style="margin-top: 20px;"></span>
`
}
export { html }

View File

@ -0,0 +1,484 @@
import Dialog from '../../../BaseDialog';
import { html } from "./_element";
import DrawPolygon from "../../../Draw/drawPolygon"
import Tools from "../../../Tools";
import { closeRotateAround, closeViewFollow} from '../../../Global/global'
class Submerge extends Tools {
/**
* @constructor
* @param sdk
* @description 淹没效果
* */
constructor(sdk, options = {}, _Dialog = {}) {
super(sdk, options);
this.sdk = sdk
this.options = {}
this.options.name = options.name
this.options.risingSpeed = 1
this.options.minWaterLevel = 0
this.options.maxWaterLevel = 0
this.options.waterVolume = 0
this.currentWaterLaver
this.color = '#00d9ff66'
this.Dialog = _Dialog
this.Draw = new DrawPolygon(this.sdk)
this.positions
this.status = true
this.area = 0
this._elms = {};
YJ.Analysis.Analyses.push(this)
Submerge.EditBox(this)
// Submerge.create(this)
}
static create(that) {
that.Draw.start((a, positions) => {
if (!positions || positions.length < 3) {
let _error = '至少需要三个坐标!'
console.warn(_error)
window.ELEMENT &&
window.ELEMENT.Message({
message: _error,
type: 'warning',
duration: 1500
})
return
}
that.destroy()
if (!positions || positions.length == 0) {
that.positions = []
that._positions = []
that.options.minWaterLevel = 0
that.options.maxWaterLevel = 0
that.options.waterVolume = 0
that.area = 0
return
}
let fromDegreesArray = []
that.positions = positions
that._positions = positions
that.options.minWaterLevel = positions[0].alt
for (let i = 0; i < positions.length; i++) {
if (that.options.minWaterLevel > positions[i].alt) {
that.options.minWaterLevel = positions[i].alt
}
fromDegreesArray.push(positions[i].lng, positions[i].lat)
}
// for (let i = 0; i < positions.length; i++) {
// fromDegreesArray.push(positions[i].lng, positions[i].lat, that.options.minWaterLevel)
// }
let pos = Cesium.Cartesian3.fromDegreesArray(fromDegreesArray)
that.currentWaterLaver = that.options.minWaterLevel
that.entity = that.sdk.viewer.entities.add({
polygon: {
hierarchy: new Cesium.PolygonHierarchy(pos),
height: new Cesium.CallbackProperty(function () {
return that.options.minWaterLevel
}, false),
extrudedHeight: new Cesium.CallbackProperty(function () {
return that.currentWaterLaver
}, false),
material: Cesium.Color.fromCssColorString(that.color),
},
})
that.area = that.computeArea(positions)
if (that.TweenAnimate) {
TWEEN.remove(that.TweenAnimate)
that.TweenAnimate = null
}
let contentElm = that._DialogObject._element.body
let pauseBtn = contentElm.getElementsByClassName('pause')[0];
let startBtn = contentElm.getElementsByClassName('start')[0];
startBtn.style.display = 'flex'
pauseBtn.style.display = 'none'
// that.move()
// Submerge.EditBox(that)
})
}
static async EditBox(that) {
if (that._DialogObject && that._DialogObject.close) {
that._DialogObject.close()
that._DialogObject = null
}
that._DialogObject = await new Dialog(that.sdk.viewer._container, {
title: '淹没分析', left: '180px', top: '100px',
closeCallBack: () => {
that.destroy()
that.Dialog.closeCallBack && that.Dialog.closeCallBack()
},
})
await that._DialogObject.init()
that._DialogObject._element.body.className = that._DialogObject._element.body.className + ' submerge'
let contentElm = document.createElement('div');
contentElm.innerHTML = html()
that._DialogObject.contentAppChild(contentElm)
let stopBtn = document.createElement('button');
stopBtn.className = 'el-button'
stopBtn.innerHTML = '暂停'
stopBtn.style.width = '80px'
let drawBtn = contentElm.getElementsByClassName('draw')[0]
drawBtn.addEventListener('click', () => {
Submerge.create(that)
})
let analogBtn = contentElm.getElementsByClassName('analog')[0];
analogBtn.addEventListener('click', () => {
that.move()
})
let flytoBtn = contentElm.getElementsByClassName('flyto')[0];
flytoBtn.addEventListener('click', () => {
that.flyTo()
})
let resetBtn = contentElm.getElementsByClassName('reset')[0];
resetBtn.addEventListener('click', () => {
that.restart()
})
let pauseBtn = contentElm.getElementsByClassName('pause')[0];
let startBtn = contentElm.getElementsByClassName('start')[0];
pauseBtn.addEventListener('click', () => {
that.pause()
pauseBtn.style.display = 'none'
startBtn.style.display = 'flex'
})
startBtn.addEventListener('click', () => {
that.start()
startBtn.style.display = 'none'
pauseBtn.style.display = 'flex'
})
// that._DialogObject.footAppChild(stopBtn)
// that._DialogObject.footAppChild(resetBtn)
// that._DialogObject.footAppChild(flytoBtn)
// that._DialogObject.footAppChild(analogBtn)
// that._DialogObject.footAppChild(drawBtn)
// 速度
let e_risingSpeed = contentElm.querySelectorAll("input[name='risingSpeed']")
e_risingSpeed[0].value = that.options.risingSpeed
e_risingSpeed[1].value = that.options.risingSpeed
e_risingSpeed[0].addEventListener('input', e => {
that.options.risingSpeed = Number(e.target.value);
});
e_risingSpeed[1].addEventListener('input', e => {
if (e.data != '.') {
let value = Number(e.target.value)
let max = Number(e_risingSpeed[0].max)
let min = Number(e_risingSpeed[0].min)
if (value > max) {
that.options.risingSpeed = max;
}
else if (value < min) {
that.options.risingSpeed = min;
}
else {
that.options.risingSpeed = Math.floor(value * 100) / 100;
}
}
});
Object.defineProperty(that.options, 'risingSpeed', {
get() {
return e_risingSpeed[0].value
},
set(value) {
e_risingSpeed[0].value = value
e_risingSpeed[1].value = value
}
})
that.waterLevel = that.options.maxWaterLevel - that.options.minWaterLevel
// 最低水位
let e_minWaterLevel = contentElm.querySelector("input[name='minWaterLevel']")
e_minWaterLevel.value = that.options.minWaterLevel
e_minWaterLevel.addEventListener('input', e => {
if (e.data != '.') {
let value = Number(e.target.value)
if (value > 999999999) {
value = 999999999
}
if (value < 0) {
value = 0
}
that.options.minWaterLevel = Math.floor(value * 10000) / 10000;
that.options.maxWaterLevel = that.options.minWaterLevel + that.waterLevel;
}
});
Object.defineProperty(that.options, 'minWaterLevel', {
get() {
return Number(e_minWaterLevel.value)
},
set(value) {
e_minWaterLevel.value = Math.floor(Number(value) * 10000) / 10000;
}
})
// 最高水位
let e_maxWaterLevel = contentElm.querySelector("input[name='maxWaterLevel']")
e_maxWaterLevel.value = that.options.maxWaterLevel
e_maxWaterLevel.addEventListener('input', e => {
if (e.data != '.') {
let value = Number(e.target.value)
if (value > 999999999) {
value = 999999999
}
if (value < 0) {
value = 0
}
if (value < that.options.minWaterLevel) {
that.options.maxWaterLevel = that.options.minWaterLevel;
}
else {
that.options.maxWaterLevel = Math.floor(value * 10000) / 10000;
}
that.waterLevel = that.options.maxWaterLevel - that.options.minWaterLevel
that.options.waterVolume = Number((that.waterLevel * that.area).toFixed(4))
}
});
Object.defineProperty(that.options, 'maxWaterLevel', {
get() {
return Number(e_maxWaterLevel.value)
},
set(value) {
if (isNaN(value)) {
value = 0
}
e_maxWaterLevel.value = Math.floor(Number(value) * 10000) / 10000;
}
})
// 水量
let e_waterVolume = contentElm.querySelector("input[name='waterVolume']")
e_waterVolume.value = that.options.waterVolume
e_waterVolume.addEventListener('input', e => {
if (e.data != '.') {
let value = Number(e.target.value)
if (value > 99999999999999) {
value = 99999999999999
}
if (value < 0) {
value = 0
}
that.options.waterVolume = Math.floor(value * 10000) / 10000;
if (that.area) {
that.waterLevel = Number((that.options.waterVolume / that.area).toFixed(4))
that.options.maxWaterLevel = that.options.minWaterLevel + that.waterLevel
}
}
});
Object.defineProperty(that.options, 'waterVolume', {
get() {
return Number(e_waterVolume.value)
},
set(value) {
e_waterVolume.value = value
}
})
// 面积
let e_area = contentElm.getElementsByClassName('area')[0]
e_area.value = that.area
Object.defineProperty(that, 'area', {
get() {
return Number(e_area.value)
},
set(value) {
e_area.value = value
that.waterLevel = Number((that.options.waterVolume / that.area).toFixed(4))
that.options.maxWaterLevel = that.options.minWaterLevel + that.waterLevel
}
})
// 表格
let e_tableBody = contentElm.getElementsByClassName('table-body')[0]
let e_tableEmpty = contentElm.getElementsByClassName('table-empty')[0]
Object.defineProperty(that, 'positions', {
get() {
return that._positions
},
set(value) {
if (value && value.length > 0) {
e_tableEmpty.style.display = 'none'
let tr = ''
for (let i = 0; i < value.length; i++) {
tr = tr + `<div class="tr">
<div class="td">${i + 1}</div>
<div class="td">${Number(value[i].lng.toFixed(10))}</div>
<div class="td">${Number(value[i].lat.toFixed(10))}</div>
<div class="td">${Number(value[i].alt.toFixed(4))}</div>
</div>`
}
e_tableBody.innerHTML = tr
}
else {
e_tableBody.innerHTML = ''
e_tableEmpty.style.display = 'flex'
}
}
})
}
move() {
if (this.TweenAnimate) {
TWEEN.remove(this.TweenAnimate)
}
let totalTime = ((this.options.maxWaterLevel - this.options.minWaterLevel) / this.options.risingSpeed) * 1000
this.TweenAnimate = new TWEEN.Tween({ waterLevel: this.options.minWaterLevel }).to({ waterLevel: this.options.maxWaterLevel }, totalTime).delay(this.delay).easing(TWEEN.Easing.Linear.None).onUpdate(async (r, a) => {
this.currentWaterLaver = r.waterLevel
}).start()
let contentElm = this._DialogObject._element.body
let pauseBtn = contentElm.getElementsByClassName('pause')[0];
let startBtn = contentElm.getElementsByClassName('start')[0];
startBtn.style.display = 'none'
pauseBtn.style.display = 'flex'
}
restart() {
this.currentWaterLaver = this.options.minWaterLevel
let isPaused = false
if (this.TweenAnimate) {
isPaused = this.TweenAnimate._isPaused
TWEEN.remove(this.TweenAnimate)
}
let totalTime = ((this.options.maxWaterLevel - this.options.minWaterLevel) / this.options.risingSpeed) * 1000
this.TweenAnimate = new TWEEN.Tween({ waterLevel: this.options.minWaterLevel }).to({ waterLevel: this.options.maxWaterLevel }, totalTime).delay(this.delay).easing(TWEEN.Easing.Linear.None).onUpdate(async (r, a) => {
this.currentWaterLaver = r.waterLevel
}).start()
if (isPaused) {
this.pause()
}
}
start() {
if (this.TweenAnimate) {
this.TweenAnimate.resume()
}
}
pause() {
if (this.TweenAnimate) {
this.TweenAnimate.pause()
}
}
calculateVolumeHeight() {
that.options.maxWaterLevel
}
/**
* 飞到
*/
flyTo() {
if (!this.positions || this.positions.length === 0) {
return
}
closeRotateAround(this.sdk)
closeViewFollow(this.sdk)
let positionArray = []
for (let i = 0; i < this.positions.length; i++) {
let fromDegrees = Cesium.Cartesian3.fromDegrees(this.positions[i].lng, this.positions[i].lat, this.options.maxWaterLevel)
positionArray.push(fromDegrees.x, fromDegrees.y, fromDegrees.z)
}
let BoundingSphere = Cesium.BoundingSphere.fromVertices(positionArray)
this.sdk.viewer.camera.flyToBoundingSphere(BoundingSphere, {
offset: {
heading: Cesium.Math.toRadians(0.0),
pitch: Cesium.Math.toRadians(-90.0),
roll: Cesium.Math.toRadians(0.0)
}
})
}
destroy() {
if (this.TweenAnimate) {
TWEEN.remove(this.TweenAnimate)
}
this.Draw.end()
this.sdk.viewer.entities.remove(this.entity)
this.entity = null
}
static EventBinding(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]
}
}
if (that._elms[m.value]) {
that._elms[m.value].push(elements[i])
}
else {
that._elms[m.value] = [elements[i]]
}
removeName.push(m.name)
break;
}
case '@click': {
elements[i].addEventListener('click', (e) => {
if (typeof (that[m.value]) === 'function') {
that[m.value](e)
}
});
removeName.push(m.name)
// elements[i].attributes.removeNamedItem(m.name)
break;
}
case '@change': {
isEvent = true
Event.push((e) => {
let value = e.target.value
if (e.target.type == 'number' && value != '') {
value = Number(value)
e.target.value = value
}
if (typeof (that[m.value]) === 'function') {
that[m.value](e, value)
}
})
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)
}
});
}
}
}
}
export default Submerge

View File

@ -0,0 +1,32 @@
function html() {
return `
<span class="custom-divider"></span>
<div class="div-item">
<div class="row">
<div class="col">
<span class="label" style="flex: 0 0 70px;">挖掘高度</span>
<div class="input-number input-number-unit-1">
<input class="input" type="number" title="" min="0" max="5000000" name="height">
<span class="unit">m</span>
<span class="arrow"></span>
</div>
</div>
</div>
</div>
<span class="custom-divider"></span>
<div class="div-item">
<div class="row">
<div class="col">
<span class="label">绘制开挖区域</span>
<button class="start-excavation"><svg class="icon-edit"><use xlink:href="#yj-icon-edit"></use></svg>绘制</button>
</div>
<div class="col">
<span class="label">清除开挖区域</span>
<button class="clean-excavation"><svg class="icon-close"><use xlink:href="#yj-icon-close"></use></svg>清除</button>
</div>
</div>
</div>
`
}
export { html }

View File

@ -0,0 +1,459 @@
import Tools from "../../../Tools";
import DrawPolygon from "../../../Draw/drawPolygon"
import Dialog from '../../../BaseDialog';
import { html } from "./_element";
let ExcavationFaces = []
class TerrainExcavation extends Tools {
/**
* @constructor
* @description 地形开挖
* @param sdk
* */
constructor(sdk, options = {}) {
super(sdk)
this.viewer = sdk.viewer
this.options = options || {};
this.options.height = (this.options.height || this.options.height === 0) ? this.options.height : 10;
this.options.show = (this.options.show || this.options.show === false) ? this.options.show : true;
this.bottomImg = this.getSourceRootPath() + '/img/excavationregion_top.jpg';
this.wallImg = this.getSourceRootPath() + '/img/excavationregion_side.jpg';
this.splitNum = Cesium.defaultValue(options.splitNum, 50);
this.Draw = new DrawPolygon(this.sdk)
this.bottomMaterial = Cesium.Material.fromType('Color', {
color: Cesium.Color.fromAlpha(Cesium.Color.fromCssColorString('#735d4f'))
})
this.wallMaterial = Cesium.Material.fromType('Color', {
color: Cesium.Color.fromAlpha(Cesium.Color.fromCssColorString('#976b4e'))
})
let imageBottom = new Image();
let wallBottom = new Image();
imageBottom.src = this.bottomImg;
wallBottom.src = this.wallImg;
imageBottom.crossOrigin = "Anonymous";
wallBottom.crossOrigin = "Anonymous";
imageBottom.onload = () => {
const canvas = document.createElement('canvas');
canvas.width = imageBottom.width;
canvas.height = imageBottom.height;
const context = canvas.getContext('2d');
context.drawImage(imageBottom, 0, 0, imageBottom.width, imageBottom.height);
const base64 = canvas.toDataURL('image/jpg');
this.bottomMaterial = new Cesium.Material({
fabric: {
type: "Image",
uniforms: {
image: base64,
},
},
});
if (this.bottomSurface) {
this.bottomSurface.appearance.material = this.bottomMaterial;
}
}
wallBottom.onload = () => {
const canvas = document.createElement('canvas');
canvas.width = wallBottom.width;
canvas.height = wallBottom.height;
const context = canvas.getContext('2d');
context.drawImage(wallBottom, 0, 0, wallBottom.width, wallBottom.height);
const base64 = canvas.toDataURL('image/jpg');
this.wallMaterial = new Cesium.Material({
fabric: {
type: "Image",
uniforms: {
image: base64,
},
},
});
if (this.wellWall) {
this.wellWall.appearance.material = this.wallMaterial;
}
}
this.init();
}
get show() {
return this.options.show
}
set show(v) {
this.options.show = v;
this.switchExcavate(v);
}
get height() {
return this.options.height
}
set height(v) {
this.options.height = v;
// this.updateExcavateDepth(v);
}
init() {
TerrainExcavation.edit(this, true)
}
static async edit(that, state) {
if (that._DialogObject && that._DialogObject.close) {
that._DialogObject.close()
that._DialogObject = null
}
if (state) {
that._DialogObject = await new Dialog(that.sdk.viewer._container, {
title: '地形开挖',
closeCallBack: () => {
},
})
await that._DialogObject.init()
that._DialogObject._element.body.className = that._DialogObject._element.body.className + ' terrain-excavation'
let contentElm = document.createElement('div');
contentElm.innerHTML = html()
that._DialogObject.contentAppChild(contentElm)
// 开始
let e_start = contentElm.getElementsByClassName('start-excavation')[0]
e_start.addEventListener('click', () => {
that.startCreate()
});
// 清除
let e_clean = contentElm.getElementsByClassName('clean-excavation')[0]
e_clean.addEventListener('click', () => {
that.clear()
});
// 高度值
let e_height = contentElm.querySelector("input[name='height']")
e_height.value = that.height
e_height.addEventListener('change', (e) => {
let value = e.target.value
value = Number(value)
if (value < 0.01) {
value = 0.01
e.target.value = value
that.height = value;
}
})
e_height.addEventListener('blur', (e) => {
let value = e.target.value
value = Number(value)
if ((e.target.max) && value > Number(e.target.max)) {
value = Number(e.target.max)
}
if (value < 0.01) {
value = 0.01
}
e.target.value = value
that.height = value;
});
} else {
if (that._DialogObject && that._DialogObject.close) {
that._DialogObject.close()
that._DialogObject = null
}
}
}
startCreate() {
this.Draw.start((e, positions) => {
if (!positions || positions.length <= 2) {
window.ELEMENT && window.ELEMENT.Message({
message: '至少拥有三个坐标位置!',
type: 'warning',
duration: 1500
});
return
}
if(!this.isConvex(positions)) {
window.ELEMENT && window.ELEMENT.Message({
message: '不支持凹多边形',
type: 'warning',
duration: 1500
});
console.log('不支持凹多边形')
return
}
this.updateData(positions)
})
}
updateData(activePoints) {
let viewer = this.viewer;
this.clear();
let clippingPlanesList = [];
let array = []
for (let i = 0; i < activePoints.length; i++) {
array.push([activePoints[i].lng, activePoints[i].lat])
}
array.push([activePoints[0].lng, activePoints[0].lat])
let clockwiseRing = turf.lineString(array);
// 是否顺时针
let boolDiff = turf.booleanClockwise(clockwiseRing);
this.excavateMinHeight = 9999;
for (let index = 0; index < activePoints.length; ++index) {
let s = (index + 1) % activePoints.length;
let position1 = Cesium.Cartesian3.fromDegrees(activePoints[index].lng, activePoints[index].lat, activePoints[index].alt)
let position2 = Cesium.Cartesian3.fromDegrees(activePoints[s].lng, activePoints[s].lat, activePoints[s].alt)
let curMidPoint = Cesium.Cartesian3.midpoint(
position1,
position2,
new Cesium.Cartesian3()
);
let cartographic = Cesium.Cartographic.fromCartesian(position1);
let curHeight =
viewer.scene.globe.getHeight(cartographic) || cartographic.height;
if (curHeight < this.excavateMinHeight) {
this.excavateMinHeight = curHeight;
}
let curMidPointNormal = Cesium.Cartesian3.normalize(
curMidPoint,
new Cesium.Cartesian3()
);
let curMidPointDifference = boolDiff
? Cesium.Cartesian3.subtract(
position1,
curMidPoint,
new Cesium.Cartesian3()
)
: Cesium.Cartesian3.subtract(
position2,
curMidPoint,
new Cesium.Cartesian3()
);
curMidPointDifference = Cesium.Cartesian3.normalize(
curMidPointDifference,
curMidPointDifference
);
let curMidPointCross = Cesium.Cartesian3.cross(
curMidPointDifference,
curMidPointNormal,
new Cesium.Cartesian3()
);
curMidPointCross = Cesium.Cartesian3.normalize(
curMidPointCross,
curMidPointCross
);
let plane = new Cesium.Plane(curMidPointCross, 0);
let distance = Cesium.Plane.getPointDistance(plane, curMidPoint);
clippingPlanesList.push(
new Cesium.ClippingPlane(curMidPointCross, distance)
);
}
this.viewer.scene.globe.clippingPlanes = new Cesium.ClippingPlaneCollection(
{
planes: clippingPlanesList,
edgeWidth: 1,
edgeColor: Cesium.Color.WHITE,
enabled: true,
}
);
this.prepareWell(activePoints);
this.createWell(this.wellData);
// this.viewer.entities.remove(this.drawGeomtry);
}
clear() {
if (this.viewer.scene.globe.clippingPlanes) {
this.viewer.scene.globe.clippingPlanes.removeAll();
this.viewer.scene.primitives.remove(this.bottomSurface);
this.viewer.scene.primitives.remove(this.wellWall);
this.viewer.scene.render();
}
for (let i = ExcavationFaces.length - 1; i >= 0; i--) {
this.viewer.scene.primitives.remove(ExcavationFaces[i]);
}
ExcavationFaces = []
this.Draw && this.Draw.end()
}
destroy() {
this.clear()
}
//计算并更新wellData
prepareWell(activePoints) {
let pointLength = activePoints.length;
let heightDiff = this.excavateMinHeight - this.height;
let no_height_top = [],
bottom_pos = [],
lerp_pos = [];
for (let l = 0; l < pointLength; l++) {
let u = l == pointLength - 1 ? 0 : l + 1;
let point0 = [
Cesium.Cartographic.fromDegrees(activePoints[l].lng, activePoints[l].lat, activePoints[l].alt).longitude,
Cesium.Cartographic.fromDegrees(activePoints[l].lng, activePoints[l].lat, activePoints[l].alt).latitude,
];
let point1 = [
Cesium.Cartographic.fromDegrees(activePoints[u].lng, activePoints[u].lat, activePoints[u].alt).longitude,
Cesium.Cartographic.fromDegrees(activePoints[u].lng, activePoints[u].lat, activePoints[u].alt).latitude,
];
if (0 == l) {
lerp_pos.push(new Cesium.Cartographic(point0[0], point0[1]));
bottom_pos.push(
Cesium.Cartesian3.fromRadians(point0[0], point0[1], heightDiff)
);
no_height_top.push(
Cesium.Cartesian3.fromRadians(point0[0], point0[1], 0)
);
}
for (let p = 1; p <= this.splitNum; p++) {
let m = Cesium.Math.lerp(point0[0], point1[0], p / this.splitNum);
let g = Cesium.Math.lerp(point0[1], point1[1], p / this.splitNum);
(l == pointLength - 1 && p == this.splitNum) ||
(lerp_pos.push(new Cesium.Cartographic(m, g)),
bottom_pos.push(Cesium.Cartesian3.fromRadians(m, g, heightDiff)),
no_height_top.push(Cesium.Cartesian3.fromRadians(m, g, 0)));
}
}
this.wellData = {
lerp_pos: lerp_pos,
bottom_pos: bottom_pos,
no_height_top: no_height_top,
};
}
//开始创建底面和侧面
createWell(wallData) {
let $this = this;
if (this.viewer.terrainProvider._layers) {
this.createBottomSurface(wallData.bottom_pos);
let positions = Cesium.sampleTerrainMostDetailed(
this.viewer.terrainProvider,
wallData.lerp_pos
);
positions.then((pos) => {
let positionList = [];
for (let index = 0; index < pos.length; index++) {
const element = pos[index];
let curPos = Cesium.Cartesian3.fromRadians(
element.longitude,
element.latitude,
element.height
);
positionList.push(curPos);
}
$this.createWellWall(wallData.bottom_pos, positionList);
});
} else {
this.createBottomSurface(wallData.bottom_pos);
this.createWellWall(wallData.bottom_pos, wallData.no_height_top);
}
}
//坐标转换,转出经纬度格式
ellipsoidToDegree(pos) {
let cartesian3 = new Cesium.Cartesian3(pos.x, pos.y, pos.z);
let cartographic =
this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian3);
return {
longitude: Cesium.Math.toDegrees(cartographic.longitude),
latitude: Cesium.Math.toDegrees(cartographic.latitude),
altitude: cartographic.height,
};
}
//创建地形开挖的底面对象
createBottomSurface(points) {
if (points.length) {
let minHeight = this.getMinHeight(points);
let positions = [];
for (let i = 0; i < points.length; i++) {
let curPoint = this.ellipsoidToDegree(points[i]);
positions.push(curPoint.longitude, curPoint.latitude, minHeight);
}
let polygon = new Cesium.PolygonGeometry({
polygonHierarchy: new Cesium.PolygonHierarchy(
Cesium.Cartesian3.fromDegreesArrayHeights(positions)
),
perPositionHeight: true,
});
let appearance = new Cesium.MaterialAppearance({
translucent: false,
flat: true,
material: this.bottomMaterial,
});
this.bottomSurface = new Cesium.Primitive({
geometryInstances: new Cesium.GeometryInstance({
geometry: Cesium.PolygonGeometry.createGeometry(polygon),
}),
appearance: appearance,
asynchronous: false,
});
ExcavationFaces.push(this.bottomSurface);
this.viewer.scene.primitives.add(this.bottomSurface);
}
}
// 创建地形开挖的侧面墙对象
createWellWall(bottomPos, positionList) {
let minHeight = this.getMinHeight(bottomPos);
let maxHeights = [],
minHeights = [];
for (let i = 0; i < positionList.length; i++) {
maxHeights.push(this.ellipsoidToDegree(positionList[i]).altitude);
minHeights.push(minHeight);
}
let wall = new Cesium.WallGeometry({
positions: positionList,
maximumHeights: maxHeights,
minimumHeights: minHeights,
});
let geometry = Cesium.WallGeometry.createGeometry(wall);
let appearance = new Cesium.MaterialAppearance({
translucent: false,
flat: true,
material: this.wallMaterial,
});
this.wellWall = new Cesium.Primitive({
geometryInstances: new Cesium.GeometryInstance({
geometry: geometry,
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
Cesium.Color.GREY
),
},
id: "PitWall",
}),
appearance: appearance,
asynchronous: false,
});
ExcavationFaces.push(this.wellWall);
this.viewer.scene.primitives.add(this.wellWall);
}
//获取地形开挖最低点高程值
getMinHeight(points) {
let minHeight = 5000000;
let minPoint = null;
for (let i = 0; i < points.length; i++) {
let height = points[i]["z"];
if (height < minHeight) {
minHeight = height;
minPoint = this.ellipsoidToDegree(points[i]);
}
}
return minPoint.altitude;
}
switchExcavate(show) {
if (show) {
this.viewer.scene.globe.material = null;
this.wellWall.show = true;
this.bottomSurface.show = true;
} else {
this.viewer.scene.globe.material = null;
this.wellWall.show = false;
this.bottomSurface.show = false;
}
}
updateExcavateDepth(height) {
this.viewer.scene.primitives.remove(this.bottomSurface);
this.viewer.scene.primitives.remove(this.wellWall);
if (!this.wellData) {
return
}
let lerp_pos = this.wellData.lerp_pos;
let posList = [];
for (let n = 0; n < lerp_pos.length; n++) {
posList.push(
Cesium.Cartesian3.fromRadians(
lerp_pos[n].longitude,
lerp_pos[n].latitude,
this.excavateMinHeight - height
)
);
}
this.wellData.bottom_pos = posList;
this.createWell(this.wellData);
}
}
export default TerrainExcavation;

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>
<button class="edit"><svg class="icon-edit"><use xlink:href="#yj-icon-edit"></use></svg>拾取</button>
</div>
</div>
</div>
<span class="custom-divider"></span>
<div class="div-item">
<div class="row" style="margin-bottom: 25px;">
<div class="col">
<span class="label">视点高度</span>
<div class="input-number input-number-unit-1">
<input class="input" type="number" title="" min="0" max="999999" step="0.1" @model="viewPointHeight">
<span class="unit">m</span>
<span class="arrow"></span>
</div>
</div>
<div class="col">
</div>
</div>
<div class="row subtitle-box">
<span class="subtitle">视域夹角</span>
</div>
<div class="row">
<div class="col">
<div class="range-box">
<div class="range-bg">
<div class="range-process-box">
<div class="range-process"></div>
</div>
</div>
<div class="range-node-box">
<span class="range-node-text">0°</span>
<span class="range-node-text">45°</span>
<span class="range-node-text">90°</span>
<span class="range-node-text">135°</span>
<span class="range-node-text">180°</span>
<div class="range-node-active"><span class="range-node-active-text">0°</span></div>
</div>
<input type="range" max="180" min="0" step="1" name="horizontalViewAngle">
</div>
</div>
</div>
</div>
<span class="custom-divider"></span>
`
}
export { html }

View File

@ -0,0 +1,511 @@
/*
* @Author: Wang jianLei
* @Date: 2022-05-17 21:49:28
* @Last Modified by: Wang JianLei
* @Last Modified time: 2022-05-19 22:08:14
*/
let ViewShed = function (sdk, canvasEleId) {
if (!sdk.viewer) throw new Error("no viewer object!");
let canvasEle = document.getElementById(canvasEleId);
if (!canvasEle) throw new Error("the canvas element is not exist");
this.canvasEle = canvasEle;
this.viewer = sdk.viewer;
this.handler = undefined;
this.lightCamera;
this.pyramid;
this.frustumPrimitive;
this.viewershedPolygon;
};
ViewShed.prototype = {
/**
* 初始化handler
*/
initHandler() {
if (this.handler) {
this.handler.destroy();
this.handler = undefined;
}
},
/**
* 开始执行视域分析
* @param {number} precision 精度值越大创建耗时越长建议在10~20之间
*/
createViewshed: function (precision) {
let $this = this;
let scene = $this.viewer.scene;
$this.initHandler();
$this.clearAll();
$this.handler = new Cesium.ScreenSpaceEventHandler($this.viewer.canvas);
$this.handler.setInputAction((event) => {
// 禁止地球旋转和缩放,地球的旋转会对鼠标移动监听有影响,所以需要禁止
scene.screenSpaceCameraController.enableRotate = false;
scene.screenSpaceCameraController.enableZoom = false;
scene.globe.depthTestAgainstTerrain = true;
let earthPosition = scene.pickPosition(event.position);
let pos = $this.cartesian3ToDegree(earthPosition);
$this.handler.setInputAction(function (event) {
let newPosition = scene.pickPosition(event.endPosition);
if (Cesium.defined(newPosition)) {
let pos1 = $this.cartesian3ToDegree(newPosition);
let distance = Cesium.Cartesian3.distance(newPosition, earthPosition);
let angle = $this.getAngle(pos[0], pos[1], pos1[0], pos1[1]);
let pitch = $this.getPitch(earthPosition, newPosition);
$this.ViewShedOptions = {
viewPosition: earthPosition, //观测点 笛卡尔坐标
endPosition: newPosition, //目标点 笛卡尔坐标
direction: angle, //观测方位角 默认为`0`,范围`0~360`
pitch: pitch, //俯仰角,radius,默认为`0`
horizontalViewAngle: 90, //可视域水平夹角,默认为 `90`,范围`0~360`
verticalViewAngle: 60, //可视域垂直夹角,默认为`60`,范围`0~180`
visibleAreaColor: Cesium.Color.GREEN, //可视区域颜色,默认为`green`
invisibleAreaColor: Cesium.Color.RED, //不可见区域颜色,默认为`red`
visualRange: distance, //距离,单位`米`
};
$this.updateViewShed();
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
}, Cesium.ScreenSpaceEventType.LEFT_DOWN);
$this.handler.setInputAction(() => {
$this.initHandler();
// 开启地球旋转和缩放
scene.screenSpaceCameraController.enableRotate = true;
scene.screenSpaceCameraController.enableZoom = true;
$this.drawViewershed(precision);
}, Cesium.ScreenSpaceEventType.LEFT_UP);
},
ReturnDistance(pos0, pos1) {
let distance = 0;
let point1cartographic = Cesium.Cartographic.fromCartesian(pos0);
let point2cartographic = Cesium.Cartographic.fromCartesian(pos1);
/**根据经纬度计算出距离**/
let geodesic = new Cesium.EllipsoidGeodesic();
geodesic.setEndPoints(point1cartographic, point2cartographic);
let s = geodesic.surfaceDistance;
return s;
},
getHeight(x, y, objectsToExclude) {
let endCartographic = Cesium.Cartographic.fromDegrees(x, y);
let endHeight = this.viewer.scene.sampleHeight(
endCartographic,
objectsToExclude
);
return endHeight;
},
cartesian3ToDegree: function (Cartesian3) {
let _ellipsoid = this.viewer.scene.globe.ellipsoid;
let _cartographic = _ellipsoid.cartesianToCartographic(Cartesian3);
let _lat = Cesium.Math.toDegrees(_cartographic.latitude);
let _lng = Cesium.Math.toDegrees(_cartographic.longitude);
let _alt = _cartographic.height;
return [_lng, _lat, _alt];
},
getAngle: function (lng1, lat1, lng2, lat2) {
let dRotateAngle = Math.atan2(Math.abs(lng1 - lng2), Math.abs(lat1 - lat2));
if (lng2 >= lng1) {
dRotateAngle = lat2 < lat1 ? Math.PI - dRotateAngle : dRotateAngle;
} else {
dRotateAngle =
lat2 >= lat1 ? 2 * Math.PI - dRotateAngle : Math.PI + dRotateAngle;
}
dRotateAngle = (dRotateAngle * 180) / Math.PI;
return dRotateAngle;
},
getPitch(pointA, pointB) {
let transfrom = Cesium.Transforms.eastNorthUpToFixedFrame(pointA);
const vector = Cesium.Cartesian3.subtract(
pointB,
pointA,
new Cesium.Cartesian3()
);
let direction = Cesium.Matrix4.multiplyByPointAsVector(
Cesium.Matrix4.inverse(transfrom, transfrom),
vector,
vector
);
Cesium.Cartesian3.normalize(direction, direction);
return Cesium.Math.PI_OVER_TWO - Cesium.Math.acosClamped(direction.z);
},
updateViewShed: function () {
this.clear();
this.setLightCamera();
this.addVisualPyramid();
this.createFrustum();
},
clear: function () {
if (this.pyramid) {
this.viewer.entities.removeById(this.pyramid.id);
this.pyramid = undefined;
}
if (this.frustumPrimitive) {
this.viewer.scene.primitives.remove(this.frustumPrimitive);
this.frustumPrimitive = undefined;
}
if (this.debugModelMatrixPrimitive) {
this.viewer.scene.primitives.remove(this.debugModelMatrixPrimitive);
this.debugModelMatrixPrimitive = undefined;
}
},
clearAll: function () {
this.clear();
if (this.viewershedPolygon) {
this.viewer.scene.primitives.remove(this.viewershedPolygon);
this.viewershedPolygon = undefined;
}
},
addVisualPyramid: function () {
let options = this.ViewShedOptions;
let position = options.viewPosition;
let visualRange = Number(options.visualRange);
let transform = Cesium.Transforms.eastNorthUpToFixedFrame(position);
this.debugModelMatrixPrimitive = this.viewer.scene.primitives.add(
new Cesium.DebugModelMatrixPrimitive({
modelMatrix: transform,
length: 5.0,
})
);
const halfClock = options.horizontalViewAngle / 2;
const halfCone = options.verticalViewAngle / 2;
const pitch = Cesium.Math.toDegrees(options.pitch);
const ellipsoid = new Cesium.EllipsoidGraphics({
radii: new Cesium.Cartesian3(visualRange, visualRange, visualRange),
minimumClock: Cesium.Math.toRadians(90 - options.direction - halfClock),
maximumClock: Cesium.Math.toRadians(90 - options.direction + halfClock),
minimumCone: Cesium.Math.toRadians(90 - pitch - halfCone),
maximumCone: Cesium.Math.toRadians(90 - pitch + halfCone),
fill: false,
outline: true,
subdivisions: 256,
stackPartitions: 64,
slicePartitions: 64,
outlineColor: Cesium.Color.YELLOWGREEN.withAlpha(0.5),
});
const pyramidEntity = new Cesium.Entity({
position: position,
ellipsoid,
});
this.pyramid = this.viewer.entities.add(pyramidEntity);
},
setLightCamera: function () {
if (!this.lightCamera) {
this.lightCamera = new Cesium.Camera(this.viewer.scene);
}
let options = this.ViewShedOptions;
let visualRange = Number(options.visualRange);
this.lightCamera.position = options.viewPosition;
this.lightCamera.frustum.near = 0.1;
this.lightCamera.frustum.far = visualRange;
const hr = Cesium.Math.toRadians(options.horizontalViewAngle);
const vr = Cesium.Math.toRadians(options.verticalViewAngle);
this.lightCamera.frustum.aspectRatio =
(visualRange * Math.tan(hr / 2) * 2) /
(visualRange * Math.tan(vr / 2) * 2);
this.lightCamera.frustum.fov = hr > vr ? hr : vr;
this.lightCamera.setView({
destination: options.viewPosition,
orientation: {
heading: Cesium.Math.toRadians(options.direction || 0),
pitch: options.pitch || 0,
roll: 0,
},
});
},
createFrustum: function () {
const scratchRight = new Cesium.Cartesian3();
const scratchRotation = new Cesium.Matrix3();
const scratchOrientation = new Cesium.Quaternion();
const direction = this.lightCamera.directionWC;
const up = this.lightCamera.upWC;
let right = this.lightCamera.rightWC;
right = Cesium.Cartesian3.negate(right, scratchRight);
let rotation = scratchRotation;
Cesium.Matrix3.setColumn(rotation, 0, right, rotation);
Cesium.Matrix3.setColumn(rotation, 1, up, rotation);
Cesium.Matrix3.setColumn(rotation, 2, direction, rotation);
let orientation = Cesium.Quaternion.fromRotationMatrix(
rotation,
scratchOrientation
);
let instanceOutline = new Cesium.GeometryInstance({
geometry: new Cesium.FrustumOutlineGeometry({
frustum: this.lightCamera.frustum,
origin: this.ViewShedOptions.viewPosition,
orientation: orientation,
}),
id: "视椎体轮廓线" + Math.random().toString(36).substr(2),
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
new Cesium.Color(0.0, 1.0, 0.0, 1.0)
),
show: new Cesium.ShowGeometryInstanceAttribute(true),
},
});
this.frustumPrimitive = this.viewer.scene.primitives.add(
new Cesium.Primitive({
geometryInstances: instanceOutline,
appearance: new Cesium.PerInstanceColorAppearance({
flat: true,
translucent: false,
closed: true,
}),
})
);
},
createPoint: function (firstPos, secondPos) {
let entity4FirstPos = new Cesium.Entity({
name: "firstPos",
show: true,
position: firstPos,
point: {
show: true,
pixelSize: 20,
color: Cesium.Color.RED,
outlineColor: Cesium.Color.YELLOW,
outlineWidth: 5,
},
description: `
<p>这是绘制的视椎体起点</p>`,
});
this.viewer.entities.add(entity4FirstPos);
let entity4SecondPos = new Cesium.Entity({
name: "secondPos",
show: true,
position: secondPos,
point: {
show: true,
pixelSize: 30,
color: Cesium.Color.YELLOW,
outlineColor: Cesium.Color.RED,
outlineWidth: 8,
},
description: `
<p>这是绘制的视椎体视角终点</p>`,
});
this.viewer.entities.add(entity4SecondPos);
},
//绘制可视域
add(positionArr) {
let polygon = new Cesium.PolygonGeometry({
polygonHierarchy: new Cesium.PolygonHierarchy(
Cesium.Cartesian3.fromDegreesArray(positionArr)
),
height: 0.0,
extrudedHeight: 0.0,
vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT,
stRotation: 0.0, // 纹理的旋转坐标(以弧度为单位),正旋转是逆时针方向
ellipsoid: Cesium.Ellipsoid.WGS84,
granularity: Cesium.Math.RADIANS_PER_DEGREE, // 每个纬度和经度之间的距离(以弧度为单位),确定缓冲区中的位置数
perPositionHeight: false, // 每个位置点使用的高度
closeTop: true,
closeBottom: true,
// NONE 与椭圆表面不符的直线;GEODESIC 遵循测地路径;RHUMB 遵循大黄蜂或恶魔般的道路。
arcType: Cesium.ArcType.GEODESIC, // 多边形边缘线型
});
let polygonInstance = new Cesium.GeometryInstance({
geometry: polygon,
name: "ViewershedPolygon",
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
Cesium.Color.BLUE.withAlpha(0.6)
),
show: new Cesium.ShowGeometryInstanceAttribute(true), //显示或者隐藏
},
});
this.viewershedPolygon = this.viewer.scene.primitives.add(
new Cesium.GroundPrimitive({
geometryInstances: polygonInstance,
appearance: new Cesium.EllipsoidSurfaceAppearance({
aboveGround: true,
material: new Cesium.Material({
fabric: {
type: "Image",
uniforms: {
image: this.returnImgae(),
},
},
}),
}),
})
);
},
drawViewershed(precision) {
const pos = this.cartesian3ToDegree(this.ViewShedOptions.viewPosition);
const radius = this.ViewShedOptions.visualRange;
const direction = this.ViewShedOptions.direction;
let boundary = this.computeBoundaryOptions(pos, radius, direction);
const bbox = boundary.bbox;
let mask = turf.polygon([boundary.boundaryPoints]);
const dis = this.ViewShedOptions.visualRange / (precision * 1000);
let gridPoints = turf.pointGrid(bbox, dis, { mask: mask });
let pointsResult = this.createTargetPoints(gridPoints, dis, pos);
let variogram = kriging.train(
pointsResult.values,
pointsResult.lngs,
pointsResult.lats,
"exponential",
0,
100
);
let grid = kriging.grid([boundary.boundaryPoints], variogram, dis / 1000);
const colors = [
"#ff000080",
"#ff000080",
"#ff000080",
"#ff000080",
"#ff000080",
"#ff000080",
"#00ff0080",
"#00ff0080",
"#00ff0080",
"#00ff0080",
"#00ff0080",
"#00ff0080",
];
this.canvasEle.width = 3840;
this.canvasEle.height = 2160;
kriging.plot(
this.canvasEle,
grid,
[bbox[0], bbox[2]],
[bbox[1], bbox[3]],
colors
);
this.add(boundary.positionArr);
},
computeBoundaryOptions(pos, radius, angle) {
let Ea = 6378137; // 赤道半径
let Eb = 6356725; // 极半径
const lng = pos[0],
lat = pos[1];
const bbox = [lng, lat, lng, lat]; //[minX, minY, maxX, maxY]
let positionArr = [];
let boundaryPoints = [];
positionArr.push(lng, lat);
boundaryPoints.push([lng, lat]);
//正北是0°
let start = angle + 45 > 360 ? angle - 45 - 360 : angle - 45;
let end = start + 90;
for (let i = start; i <= end; i++) {
let dx = radius * Math.sin((i * Math.PI) / 180.0);
let dy = radius * Math.cos((i * Math.PI) / 180.0);
let ec = Eb + ((Ea - Eb) * (90.0 - lat)) / 90.0;
let ed = ec * Math.cos((lat * Math.PI) / 180);
let BJD = lng + ((dx / ed) * 180.0) / Math.PI;
let BWD = lat + ((dy / ec) * 180.0) / Math.PI;
positionArr.push(BJD, BWD);
boundaryPoints.push([BJD, BWD]);
this.refreshBBox(bbox, BJD, BWD);
}
boundaryPoints.push([lng, lat]);
return {
positionArr,
boundaryPoints,
bbox,
};
},
/**
* 更新外围矩形 Bbox
* @param {Array} result 外围矩形Bbox-[minX, minY, maxX, maxY]
* @param {Number} x 经度
* @param {Number} y 纬度
*/
refreshBBox(result, x, y) {
result[0] = x < result[0] ? x : result[0];
result[1] = y < result[1] ? y : result[1];
result[2] = x > result[2] ? x : result[2];
result[3] = y > result[3] ? y : result[3];
},
/**
* 插值点用射线判断通视性
* @param {*} gridPoints 网格点
* @param {*} step 步长,可以理解成是精度
* @param {*} sourcePos 视域分析起点
* @returns kriging插值所需的参数对象{ values:[], lngs:[], lats:[]}
*/
createTargetPoints(gridPoints, step, sourcePos) {
let positionArr = [];
let objectsToExclude = [
this.frustumPrimitive,
this.pyramid,
this.debugModelMatrixPrimitive,
];
let values = [],
lngs = [],
lats = [];
let height = this.getHeight(sourcePos[0], sourcePos[1], objectsToExclude);
positionArr.push({
x: sourcePos[0],
y: sourcePos[1],
z: height,
});
let viewPoint = this.ViewShedOptions.viewPosition;
for (let index = 0; index < gridPoints.features.length; index++) {
const feature = gridPoints.features[index];
const coords = feature.geometry.coordinates;
const x = coords[0],
y = coords[1];
let h = this.getHeight(x, y, objectsToExclude);
let endPoint = Cesium.Cartesian3.fromDegrees(x, y, h);
let direction = Cesium.Cartesian3.normalize(
Cesium.Cartesian3.subtract(
endPoint,
viewPoint,
new Cesium.Cartesian3()
),
new Cesium.Cartesian3()
);
// 建立射线
let ray = new Cesium.Ray(viewPoint, direction);
let result = this.viewer.scene.pickFromRay(ray, objectsToExclude); // 计算交互点,返回第一个
if (result) {
let buffer = this.ReturnDistance(endPoint, result.position);
// let M_color = Cesium.Color.GREEN;
if (buffer > step) {
// M_color = Cesium.Color.RED;
values.push(0);
} else {
values.push(1);
}
lngs.push(x);
lats.push(y);
// this.viewer.entities.add(
// new Cesium.Entity({
// name: "插值点哦",
// show: true,
// position: endPoint,
// point: {
// show: true,
// pixelSize: 10,
// color: M_color,
// outlineWidth: 2,
// outlineColor: Cesium.Color.YELLOW,
// },
// })
// );
}
}
return {
values,
lngs,
lats,
};
},
/**
* canvas转image图片
* @returns base64图片
*/
returnImgae() {
return this.canvasEle.toDataURL("image/png");
},
};
export default ViewShed;

View File

@ -0,0 +1,131 @@
export default `
#define USE_CUBE_MAP_SHADOW true
uniform sampler2D colorTexture;
uniform sampler2D depthTexture;
varying vec2 v_textureCoordinates;
uniform mat4 camera_projection_matrix;
uniform mat4 camera_view_matrix;
uniform samplerCube shadowMap_textureCube;
uniform mat4 shadowMap_matrix;
uniform vec4 shadowMap_lightPositionEC;
uniform vec4 shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness;
uniform vec4 shadowMap_texelSizeDepthBiasAndNormalShadingSmooth;
uniform float helsing_viewDistance;
uniform vec4 helsing_visibleAreaColor;
uniform vec4 helsing_invisibleAreaColor;
struct zx_shadowParameters
{
vec3 texCoords;
float depthBias;
float depth;
float nDotL;
vec2 texelStepSize;
float normalShadingSmooth;
float darkness;
};
float czm_shadowVisibility(samplerCube shadowMap, zx_shadowParameters shadowParameters)
{
float depthBias = shadowParameters.depthBias;
float depth = shadowParameters.depth;
float nDotL = shadowParameters.nDotL;
float normalShadingSmooth = shadowParameters.normalShadingSmooth;
float darkness = shadowParameters.darkness;
vec3 uvw = shadowParameters.texCoords;
depth -= depthBias;
float visibility = czm_shadowDepthCompare(shadowMap, uvw, depth);
return czm_private_shadowVisibility(visibility, nDotL, normalShadingSmooth, darkness);
}
vec4 getPositionEC(){
return czm_windowToEyeCoordinates(gl_FragCoord);
}
vec3 getNormalEC(){
return vec3(1.);
}
vec4 toEye(in vec2 uv,in float depth){
vec2 xy=vec2((uv.x*2.-1.),(uv.y*2.-1.));
vec4 posInCamera=czm_inverseProjection*vec4(xy,depth,1.);
posInCamera=posInCamera/posInCamera.w;
return posInCamera;
}
vec3 pointProjectOnPlane(in vec3 planeNormal,in vec3 planeOrigin,in vec3 point){
vec3 v01=point-planeOrigin;
float d=dot(planeNormal,v01);
return(point-planeNormal*d);
}
float getDepth(in vec4 depth){
float z_window=czm_unpackDepth(depth);
z_window=czm_reverseLogDepth(z_window);
float n_range=czm_depthRange.near;
float f_range=czm_depthRange.far;
return(2.*z_window-n_range-f_range)/(f_range-n_range);
}
float shadow(in vec4 positionEC){
vec3 normalEC=getNormalEC();
zx_shadowParameters shadowParameters;
shadowParameters.texelStepSize=shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.xy;
shadowParameters.depthBias=shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.z;
shadowParameters.normalShadingSmooth=shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.w;
shadowParameters.darkness=shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness.w;
vec3 directionEC=positionEC.xyz-shadowMap_lightPositionEC.xyz;
float distance=length(directionEC);
directionEC=normalize(directionEC);
float radius=shadowMap_lightPositionEC.w;
if(distance>radius)
{
return 2.0;
}
vec3 directionWC=czm_inverseViewRotation*directionEC;
shadowParameters.depth=distance/radius-0.0003;
shadowParameters.nDotL=clamp(dot(normalEC,-directionEC),0.,1.);
shadowParameters.texCoords=directionWC;
float visibility=czm_shadowVisibility(shadowMap_textureCube,shadowParameters);
return visibility;
}
bool visible(in vec4 result)
{
result.x/=result.w;
result.y/=result.w;
result.z/=result.w;
return result.x>=-1.&&result.x<=1.
&&result.y>=-1.&&result.y<=1.
&&result.z>=-1.&&result.z<=1.;
}
void main(){
// 釉色 = 结构二维(颜色纹理, 纹理坐标)
gl_FragColor = texture2D(colorTexture, v_textureCoordinates);
// 深度 = 获取深度(结构二维(深度纹理, 纹理坐标))
float depth = getDepth(texture2D(depthTexture, v_textureCoordinates));
// 视角 = (纹理坐标, 深度)
vec4 viewPos = toEye(v_textureCoordinates, depth);
// 世界坐标
vec4 wordPos = czm_inverseView * viewPos;
// 虚拟相机中坐标
vec4 vcPos = camera_view_matrix * wordPos;
float near = .001 * helsing_viewDistance;
float dis = length(vcPos.xyz);
if(dis > near && dis < helsing_viewDistance){
// 透视投影
vec4 posInEye = camera_projection_matrix * vcPos;
// 可视区颜色
// vec4 helsing_visibleAreaColor=vec4(0.,1.,0.,.5);
// vec4 helsing_invisibleAreaColor=vec4(1.,0.,0.,.5);
if(visible(posInEye)){
float vis = shadow(viewPos);
if(vis > 0.3){
gl_FragColor = mix(gl_FragColor,helsing_visibleAreaColor,.5);
} else{
gl_FragColor = mix(gl_FragColor,helsing_invisibleAreaColor,.5);
}
}
}
}`;

View File

@ -0,0 +1,131 @@
export default `
#define USE_CUBE_MAP_SHADOW true
uniform sampler2D colorTexture;
uniform sampler2D depthTexture;
in vec2 v_textureCoordinates;
uniform mat4 camera_projection_matrix;
uniform mat4 camera_view_matrix;
uniform samplerCube shadowMap_textureCube;
uniform mat4 shadowMap_matrix;
uniform vec4 shadowMap_lightPositionEC;
uniform vec4 shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness;
uniform vec4 shadowMap_texelSizeDepthBiasAndNormalShadingSmooth;
uniform float helsing_viewDistance;
uniform vec4 helsing_visibleAreaColor;
uniform vec4 helsing_invisibleAreaColor;
struct zx_shadowParameters
{
vec3 texCoords;
float depthBias;
float depth;
float nDotL;
vec2 texelStepSize;
float normalShadingSmooth;
float darkness;
};
float czm_shadowVisibility(samplerCube shadowMap, zx_shadowParameters shadowParameters)
{
float depthBias = shadowParameters.depthBias;
float depth = shadowParameters.depth;
float nDotL = shadowParameters.nDotL;
float normalShadingSmooth = shadowParameters.normalShadingSmooth;
float darkness = shadowParameters.darkness;
vec3 uvw = shadowParameters.texCoords;
depth -= depthBias;
float visibility = czm_shadowDepthCompare(shadowMap, uvw, depth);
return czm_private_shadowVisibility(visibility, nDotL, normalShadingSmooth, darkness);
}
vec4 getPositionEC(){
return czm_windowToEyeCoordinates(gl_FragCoord);
}
vec3 getNormalEC(){
return vec3(1.);
}
vec4 toEye(in vec2 uv,in float depth){
vec2 xy=vec2((uv.x*2.-1.),(uv.y*2.-1.));
vec4 posInCamera=czm_inverseProjection*vec4(xy,depth,1.);
posInCamera=posInCamera/posInCamera.w;
return posInCamera;
}
vec3 pointProjectOnPlane(in vec3 planeNormal,in vec3 planeOrigin,in vec3 point){
vec3 v01=point-planeOrigin;
float d=dot(planeNormal,v01);
return(point-planeNormal*d);
}
float getDepth(in vec4 depth){
float z_window=czm_unpackDepth(depth);
z_window=czm_reverseLogDepth(z_window);
float n_range=czm_depthRange.near;
float f_range=czm_depthRange.far;
return(2.*z_window-n_range-f_range)/(f_range-n_range);
}
float shadow(in vec4 positionEC){
vec3 normalEC=getNormalEC();
zx_shadowParameters shadowParameters;
shadowParameters.texelStepSize=shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.xy;
shadowParameters.depthBias=shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.z;
shadowParameters.normalShadingSmooth=shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.w;
shadowParameters.darkness=shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness.w;
vec3 directionEC=positionEC.xyz-shadowMap_lightPositionEC.xyz;
float distance=length(directionEC);
directionEC=normalize(directionEC);
float radius=shadowMap_lightPositionEC.w;
if(distance>radius)
{
return 2.0;
}
vec3 directionWC=czm_inverseViewRotation*directionEC;
shadowParameters.depth=distance/radius-0.0003;
shadowParameters.nDotL=clamp(dot(normalEC,-directionEC),0.,1.);
shadowParameters.texCoords=directionWC;
float visibility=czm_shadowVisibility(shadowMap_textureCube,shadowParameters);
return visibility;
}
bool visible(in vec4 result)
{
result.x/=result.w;
result.y/=result.w;
result.z/=result.w;
return result.x>=-1.&&result.x<=1.
&&result.y>=-1.&&result.y<=1.
&&result.z>=-1.&&result.z<=1.;
}
void main(){
// 釉色 = 结构二维(颜色纹理, 纹理坐标)
out_FragColor = texture(colorTexture, v_textureCoordinates);
// 深度 = 获取深度(结构二维(深度纹理, 纹理坐标))
float depth = getDepth(texture(depthTexture, v_textureCoordinates));
// 视角 = (纹理坐标, 深度)
vec4 viewPos = toEye(v_textureCoordinates, depth);
// 世界坐标
vec4 wordPos = czm_inverseView * viewPos;
// 虚拟相机中坐标
vec4 vcPos = camera_view_matrix * wordPos;
float near = .001 * helsing_viewDistance;
float dis = length(vcPos.xyz);
if(dis > near && dis < helsing_viewDistance){
// 透视投影
vec4 posInEye = camera_projection_matrix * vcPos;
// 可视区颜色
// vec4 helsing_visibleAreaColor=vec4(0.,1.,0.,.5);
// vec4 helsing_invisibleAreaColor=vec4(1.,0.,0.,.5);
if(visible(posInEye)){
float vis = shadow(viewPos);
if(vis > 0.3){
out_FragColor = mix(out_FragColor,helsing_visibleAreaColor,.5);
} else{
out_FragColor = mix(out_FragColor,helsing_invisibleAreaColor,.5);
}
}
}
}`;

View File

@ -0,0 +1,773 @@
// ViewShed.js
import glsl from './glsl'
import glsl2 from './glsl2'
import Event from "../../../Event";
import MouseTip from "../../../MouseTip";
import Tools from "../../../Tools";
import EventBinding from '../../Element/Dialog/eventBinding';
import Controller from "../../../Controller";
import Dialog from '../../../BaseDialog';
import { html } from "./_element";
/**
* @constructor
* @description 可视域分析
* @param sdk
* @param {Object} options 选项。
* @param {Cesium.Cartesian3} options.viewPosition 观测点位置。
* @param {Cesium.Cartesian3} options.viewPositionEnd 最远观测点位置(如果设置了观测距离,这个属性可以不设置)。
* @param {Number} options.viewPointHeight=1.8 视点高度(单位`米`)。
* @param {Number} options.viewDistance 观测距离(单位`米`)。
* @param {Number} options.viewHeading 航向角(单位`度`)。
* @param {Number} options.viewPitch 俯仰角(单位`度`)。
* @param {Number} options.horizontalViewAngle=90 可视域水平夹角(单位`度`)。
* @param {Number} options.verticalViewAngle=60 可视域垂直夹角(单位`度`)。
* @param {String} options.visibleAreaColor=#008000 可视区域颜色(默认值`绿色`)。
* @param {String} options.invisibleAreaColor=#FF0000 不可视区域颜色(默认值`红色`)。
*/
class ViewShedStage extends Tools {
constructor(sdk, options = {}, _Dialog = {}) {
super(sdk, options)
// if (Object.hasOwn(options.viewPosition, 'lng') && Object.hasOwn(options.viewPosition, 'lat') && Object.hasOwn(options.viewPosition, 'alt')) {
// this.error = '请提供观测点位置!'
// window.ELEMENT && window.ELEMENT.Message({
// message: '请提供观测点位置!',
// type: 'warning',
// duration: 1500
// });
// return
// }
this.viewer = sdk.viewer;
this.options = {}
this.options.viewPosition = options.viewPosition;
this.options.viewPositionEnd = options.viewPositionEnd;
this.options.horizontalViewAngle = (options.horizontalViewAngle || options.horizontalViewAngle === 0) ? options.horizontalViewAngle : 90.0;
this.options.verticalViewAngle = (options.verticalViewAngle || options.verticalViewAngle === 0) ? options.verticalViewAngle : 60.0;
this.options.visibleAreaColor = options.visibleAreaColor || '#008000';
this.options.invisibleAreaColor = options.invisibleAreaColor || '#FF0000';
this._elms = {};
this.viewPointHeight = options.viewPointHeight
// this.enabled = (typeof options.enabled === "boolean") ? options.enabled : true;
// this.softShadows = (typeof options.softShadows === "boolean") ? options.softShadows : true;
// this.size = options.size || 10240; // 2048
this.ids = []
this.Dialog = _Dialog
this._EventBinding = new EventBinding()
this.html = null
YJ.Analysis.Analyses.push(this)
ViewShedStage.edit(this)
// ViewShedStage.edit(this)
// this.update();
}
get viewPointHeight() {
return this.options.viewPointHeight
}
set viewPointHeight(v) {
let viewPointHeight = Math.floor(Number(v) * 10) / 10
if (isNaN(viewPointHeight)) {
viewPointHeight = 1.8
}
if (viewPointHeight < 0) {
viewPointHeight = 0
}
this.options.viewPointHeight = viewPointHeight
this._elms.viewPointHeight && this._elms.viewPointHeight.forEach((item) => {
item.value = viewPointHeight
})
}
get viewPosition() {
return this.options.viewPosition
}
set viewPosition(v) {
this.options.viewPosition = v
this.ids[0] && (this.viewer.entities.getById(this.ids[0]).position = new Cesium.Cartesian3.fromDegrees(v.lng, v.lat, v.alt))
this.update()
// let viewPosition3 = Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt)
}
get viewPositionEnd() {
return this.options.viewPositionEnd
}
set viewPositionEnd(v) {
this.options.viewPositionEnd = v
this.ids[1] && (this.viewer.entities.getById(this.ids[1]).position = new Cesium.Cartesian3.fromDegrees(v.lng, v.lat, v.alt))
this.update()
// let viewPositionEnd3 = Cesium.Cartesian3.fromDegrees(this.options.viewPositionEnd.lng, this.options.viewPositionEnd.lat, this.options.viewPositionEnd.alt)
// this.viewDistance = this.viewPositionEnd ? Cesium.Cartesian3.distance(this.viewPosition, this.viewPositionEnd) : (options.viewDistance || 100.0);
}
get horizontalViewAngle() {
return this.options.horizontalViewAngle
}
set horizontalViewAngle(v) {
this.options.horizontalViewAngle = v
if (this._DialogObject && this._DialogObject._element && this._DialogObject._element.content) {
let contentElm = this._DialogObject._element.content
let e_horizontalViewAngle = contentElm.querySelector("input[name='horizontalViewAngle']")
e_horizontalViewAngle.value = v
let rangeNodeActive = contentElm.getElementsByClassName('range-node-active')[0]
let rangeNodeActiveText = rangeNodeActive.getElementsByClassName('range-node-active-text')[0]
rangeNodeActiveText.innerHTML = v + '°';
let rangeProcess = contentElm.getElementsByClassName('range-process')[0]
rangeProcess.style.width = v / 180 * 100 + '%'
}
this.update()
}
get visibleAreaColor() {
return this.options.visibleAreaColor
}
set visibleAreaColor(v) {
this.options.visibleAreaColor = v
this.update()
}
get invisibleAreaColor() {
return this.options.invisibleAreaColor
}
set invisibleAreaColor(v) {
this.options.invisibleAreaColor = v
this.update()
}
get verticalViewAngle() {
return this.options.verticalViewAngle
}
set verticalViewAngle(v) {
this.options.verticalViewAngle = v
this.update()
}
get viewDistance() {
let viewPosition3 = Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt + this.viewPointHeight)
let viewPositionEnd3 = Cesium.Cartesian3.fromDegrees(this.options.viewPositionEnd.lng, this.options.viewPositionEnd.lat, this.options.viewPositionEnd.alt)
let distance = Cesium.Cartesian3.distance(viewPosition3, viewPositionEnd3)
return distance
}
get viewHeading() {
let viewPosition3 = Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt + this.viewPointHeight)
let viewPositionEnd3 = Cesium.Cartesian3.fromDegrees(this.options.viewPositionEnd.lng, this.options.viewPositionEnd.lat, this.options.viewPositionEnd.alt)
let heading = getHeading(viewPosition3, viewPositionEnd3)
return heading
}
get viewPitch() {
let viewPosition3 = Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt + this.viewPointHeight)
let viewPositionEnd3 = Cesium.Cartesian3.fromDegrees(this.options.viewPositionEnd.lng, this.options.viewPositionEnd.lat, this.options.viewPositionEnd.alt)
let pitch = getPitch(viewPosition3, viewPositionEnd3)
return pitch
}
static create(that) {
that.destroy()
let count = 0;
if (!YJ.Measure.GetMeasureStatus()) {
that.event = new Event(that.sdk)
that.tip = new MouseTip('左键选择观测点位置,右键取消', that.sdk)
YJ.Measure.SetMeasureStatus(true)
that.event.mouse_left((movement, cartesian) => {
if (!that.viewPosition) {
that.options.viewPosition = that.cartesian3Towgs84(cartesian, that.viewer)
that.ids.push(ViewShedStage.create_point(that, cartesian))
that.tip.set_text("左键选择最远观测点位置,右键取消")
}
count++
if (count === 2) {
that.options.viewPositionEnd = that.cartesian3Towgs84(cartesian, that.viewer)
that.ids.push(ViewShedStage.create_point(that, cartesian))
end()
that.update()
}
})
that.event.mouse_move((movement, cartesian) => {
that.tip.setPosition(cartesian, movement.endPosition.x, movement.endPosition.y)
})
that.event.mouse_right((movement, cartesian) => {
that.ids.forEach(id => {
that.viewer.entities.removeById(id)
})
that.ids = []
end()
})
that.event.gesture_pinck_start((movement, cartesian) => {
let startTime = new Date()
that.event.gesture_pinck_end(() => {
let endTime = new Date()
if (endTime - startTime >= 500) {
that.ids.forEach(id => {
that.viewer.entities.removeById(id)
})
that.ids = []
end()
}
})
})
}
else {
console.log('上一次测量未结束')
}
function end() {
that.ids.forEach(id => {
let entity = that.viewer.entities.getById(id)
entity.show = false
})
YJ.Measure.SetMeasureStatus(false)
that.tip.destroy()
that.event.destroy()
that.tip = null
that.event = null
}
}
static create_point(that, cartesian) {
let id = that.randomString()
let p = that.cartesian3Towgs84(cartesian, that.viewer)
let params = {
id: id,
position: Cesium.Cartesian3.fromDegrees(p.lng, p.lat, p.alt),
billboard: {
image: that.getSourceRootPath() + '/img/point.png',
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
disableDepthTestDistance: Number.POSITIVE_INFINITY,
color: Cesium.Color.WHITE.withAlpha(0.99)
}
}
that.viewer.entities.add(
new Cesium.Entity(params)
)
return id
}
add() {
this.createLightCamera();
this.createShadowMap();
this.createPostStage();
// this.drawFrustumOutline();
this.drawSketch();
ViewShedStage.getcanvas(this)
}
update() {
this.clear();
this.add();
}
static async edit(that) {
if (that._DialogObject && that._DialogObject.close) {
that._DialogObject.close()
that._DialogObject = null
}
that._DialogObject = await new Dialog(that.sdk.viewer._container, {
title: '可视域分析', left: '180px', top: '100px',
closeCallBack: () => {
that.Dialog.closeCallBack && that.Dialog.closeCallBack()
YJ.Measure.SetMeasureStatus(false)
that.editevent && that.editevent.destroy()
that.ControllerObject && that.ControllerObject.destroy()
that.ids.forEach(id => {
that.viewer.entities.removeById(id)
})
},
})
await that._DialogObject.init()
that._DialogObject._element.body.className = that._DialogObject._element.body.className + ' view-shed'
let contentElm = document.createElement('div');
contentElm.innerHTML = html()
that._DialogObject.contentAppChild(contentElm)
let resetBtn = that._DialogObject._element.body.getElementsByClassName('edit')[0];
resetBtn.addEventListener('click', () => {
that.nodeEdit()
})
let drawElm = document.createElement('button')
drawElm.innerHTML = '绘制'
drawElm.addEventListener('click', () => {
ViewShedStage.create(that)
})
that._DialogObject.footAppChild(drawElm)
that.html = contentElm
let all_elm = contentElm.getElementsByTagName("*")
that._EventBinding.on(that, all_elm)
that._elms = that._EventBinding.element
// //经度值
// let e_lng = contentElm.querySelector("span[name='lng']")
// e_lng.innerHTML = Number(that.options.viewPosition.lng.toFixed(8))
// //纬度值
// let e_lat = contentElm.querySelector("span[name='lat']")
// e_lat.innerHTML = Number(that.options.viewPosition.lat.toFixed(8))
// //高度值
// let e_alt = contentElm.querySelector("span[name='alt']")
// e_alt.innerHTML = Number(that.options.viewPosition.alt.toFixed(8))
// //偏航角
// let e_viewHeading = contentElm.querySelector("span[name='viewHeading']")
// e_viewHeading.innerHTML = Number(that.viewHeading.toFixed(8))
// //俯仰角
// let e_viewPitch = contentElm.querySelector("span[name='viewPitch']")
// e_viewPitch.innerHTML = Number(that.viewPitch.toFixed(8))
//视域夹角
let e_horizontalViewAngle = contentElm.querySelector("input[name='horizontalViewAngle']")
e_horizontalViewAngle.value = that.options.horizontalViewAngle
let rangeNodeActive = contentElm.getElementsByClassName('range-node-active')[0]
let rangeNodeActiveText = rangeNodeActive.getElementsByClassName('range-node-active-text')[0]
let rangeProcess = contentElm.getElementsByClassName('range-process')[0]
let percentage = that.horizontalViewAngle / 180 * 100
rangeNodeActive.style.left = percentage + '%';
rangeProcess.style.width = percentage + '%'
rangeNodeActiveText.innerHTML = that.horizontalViewAngle + '°';
let timeout
e_horizontalViewAngle.addEventListener('input', () => {
let percentage = e_horizontalViewAngle.value / 180 * 100
rangeNodeActive.style.left = percentage + '%';
rangeProcess.style.width = percentage + '%';
rangeNodeActiveText.innerHTML = e_horizontalViewAngle.value + '°';
})
e_horizontalViewAngle.addEventListener('change', () => {
clearTimeout(timeout)
timeout = setTimeout(() => {
that.horizontalViewAngle = e_horizontalViewAngle.value;
}, 300);
});
}
static getcanvas(that) {
if (!that.viewPosition) {
return
}
if (that.viewBillboardPrimitive) {
that.viewer.scene.primitives.remove(that.viewBillboardPrimitive)
that.viewBillboardPrimitive = null
}
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d')
canvas.width = 220
canvas.height = 180
canvas.style.background = "#000000"
let img = new Image();
const data = [
{
images: that.getSourceRootPath() + '/img/bubble/lng.png',
text: '经度:' + parseFloat(that.viewPosition.lng.toFixed(10)) + '°'
},
{
images: that.getSourceRootPath() + '/img/bubble/lat.png',
text: '纬度:' + parseFloat(that.viewPosition.lat.toFixed(10)) + '°'
},
{
images: that.getSourceRootPath() + '/img/bubble/h.png',
text: '高度:' + Number(((parseFloat(that.viewPosition.alt.toFixed(2)) + Number(that.viewPointHeight))).toFixed(2)) + ' m'
},
{
images: that.getSourceRootPath() + '/img/bubble/heading.png',
text: '偏航角:' + parseFloat(that.viewHeading.toFixed(10)) + '°'
},
{
images: that.getSourceRootPath() + '/img/bubble/pitch.png',
text: '俯仰角:' + parseFloat(that.viewPitch.toFixed(10)) + '°'
}
]
img.src = that.getSourceRootPath() + '/img/bubble/bubble.png';
let imagesLoaded = 0
img.onload = () => {
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
data.forEach((item, index) => {
const img = new Image();
img.src = item.images;
img.onload = () => {
ctx.drawImage(img, 12, 12 + (index * 26));
ctx.fillStyle = "#fff";
ctx.font = "12px Arial";
ctx.fillText(item.text, 44, 28 + (index * 26));
imagesLoaded++;
if (imagesLoaded === data.length) {
that.viewBillboardPrimitive = that.viewer.scene.primitives.add(new Cesium.BillboardCollection())
that.viewBillboardPrimitive.add({
position: Cesium.Cartesian3.fromDegrees(that.viewPosition.lng, that.viewPosition.lat, that.viewPosition.alt + that.viewPointHeight),
image: canvas,
width: 200,
height: 180,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
disableDepthTestDistance: Number.POSITIVE_INFINITY,
})
}
};
})
};
}
clear() {
YJ.Measure.SetMeasureStatus(false)
this.tip && this.tip.destroy()
this.event && this.event.destroy()
this.tip = null
this.event = null
if (this.sketch) {
this.viewer.entities.removeById(this.sketch.id);
this.sketch = null;
}
if (this.frustumOutline) {
// this.frustumOutline.destroy();
this.viewer.entities.removeById(this.frustumOutline.id);
this.frustumOutline = null;
}
if (this.postStage) {
this.viewer.scene.postProcessStages.remove(this.postStage);
this.postStage = null;
}
}
destroy() {
this.clear()
this.editevent && this.editevent.destroy()
this.ControllerObject && this.ControllerObject.destroy()
this.ids.forEach(id => {
this.viewer.entities.removeById(id)
})
this.ids = []
if (this.viewBillboardPrimitive) {
this.viewer.scene.primitives.remove(this.viewBillboardPrimitive)
}
this.viewBillboardPrimitive = null
this.options.viewPosition = null
this.options.viewPositionEnd = null
YJ.Measure.SetMeasureStatus(false)
if (this._originalShadowMap) {
this.viewer.scene.shadowMap = this._originalShadowMap
this._originalShadowMap = null
}
this.viewer.shadows = this.viewer._shadows
}
nodeEdit() {
if (YJ.Measure.GetMeasureStatus()) {
console.log('上一次测量未结束')
}
else {
this.editevent && this.editevent.destroy()
this.ids.forEach(id => {
let entity = this.viewer.entities.getById(id)
entity.show = true
})
let selectPoint
YJ.Measure.SetMeasureStatus(true)
// this.tip = new MouseTip('左键选择要操作的观测点,右键取消', this.sdk)
this.editevent = new Event(this.sdk)
this.editevent.mouse_left((movement, cartesian) => {
let pick = this.viewer.scene.pick(movement.position);
if (pick && pick.id && pick.id.id && this.ids.indexOf(pick.id.id) != -1 && (!selectPoint || selectPoint.id != pick.id.id)) {
selectPoint = pick.id
// this.event.destroy()
// this.tip.destroy()
this.viewer.entities.getById(this.ids[0]).position = new Cesium.Cartesian3.fromDegrees(this.viewPosition.lng, this.viewPosition.lat, this.viewPosition.alt)
this.viewer.entities.getById(this.ids[1]).position = new Cesium.Cartesian3.fromDegrees(this.viewPositionEnd.lng, this.viewPositionEnd.lat, this.viewPositionEnd.alt)
this.ControllerObject && this.ControllerObject.destroy()
this.ControllerObject = new Controller(this.sdk, { position: { ...this.cartesian3Towgs84(selectPoint.position._value, this.sdk.viewer) } })
this.ControllerObject.controllerCallBack = (params, status) => {
if (params.position.alt < 0) {
params.position.alt = 0
}
selectPoint.position = new Cesium.Cartesian3.fromDegrees(params.position.lng, params.position.lat, params.position.alt)
if (status) {
if (this.ids.indexOf(pick.id.id) == 0) {
this.viewPosition = params.position
}
else {
this.viewPositionEnd = params.position
}
YJ.Measure.SetMeasureStatus(true)
}
}
this.ControllerObject.editTranslational()
}
})
this.editevent.mouse_right((movement, cartesian) => {
YJ.Measure.SetMeasureStatus(false)
this.editevent && this.editevent.destroy()
this.ControllerObject && this.ControllerObject.destroy()
this.ids.forEach(id => {
let entity = this.viewer.entities.getById(id)
entity.show = false
})
selectPoint = null
})
this.editevent.mouse_move((movement, cartesian) => {
// this.tip.setPosition(
// cartesian,
// movement.endPosition.x,
// movement.endPosition.y
// )
})
this.editevent.gesture_pinck_start((movement, cartesian) => {
let startTime = new Date()
this.editevent.gesture_pinck_end(() => {
let endTime = new Date()
if (endTime - startTime >= 500) {
YJ.Measure.SetMeasureStatus(false)
this.editevent && this.editevent.destroy()
this.ControllerObject && this.ControllerObject.destroy()
this.ids.forEach(id => {
let entity = this.viewer.entities.getById(id)
entity.show = false
})
selectPoint = null
}
})
})
}
}
createLightCamera() {
if (!this.options.viewPosition) {
return
}
let _this = this
this.lightCamera = new Cesium.Camera(this.viewer.scene);
this.lightCamera.position = Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt + this.viewPointHeight);
// if (this.viewPositionEnd) {
// let direction = Cesium.Cartesian3.normalize(Cesium.Cartesian3.subtract(this.viewPositionEnd, this.viewPosition, new Cesium.Cartesian3()), new Cesium.Cartesian3());
// this.lightCamera.direction = direction; // direction是相机面向的方向
// }
this.lightCamera.frustum.near = this.viewDistance * 0.001;
this.lightCamera.frustum.far = this.viewDistance;
const hr = Cesium.Math.toRadians(this.horizontalViewAngle);
const vr = Cesium.Math.toRadians(this.verticalViewAngle);
const aspectRatio =
(this.viewDistance * Math.tan(hr / 2) * 2) /
(this.viewDistance * Math.tan(vr / 2) * 2);
this.lightCamera.frustum.aspectRatio = aspectRatio;
if (hr > vr) {
this.lightCamera.frustum.fov = hr;
} else {
this.lightCamera.frustum.fov = vr;
}
this.lightCamera.setView({
destination: Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt + this.viewPointHeight),
orientation: {
heading: Cesium.Math.toRadians(this.viewHeading || 0),
pitch: Cesium.Math.toRadians(this.viewPitch || 0),
roll: 0
}
});
}
createShadowMap() {
this.shadowMap = new Cesium.ShadowMap({
context: (this.viewer.scene).context,
lightCamera: this.lightCamera,
enabled: true,
isPointLight: true,
pointLightRadius: this.viewDistance,
cascadesEnabled: false,
size: 2048, // 2048
softShadows: true,
normalOffset: false,
fromLightSource: false
});
if (!this._originalShadowMap) {
this._originalShadowMap = this.viewer.scene.shadowMap
}
this.viewer.scene.shadowMap = this.shadowMap;
// setTimeout(() => {
// this.viewer.shadows = this.viewer._shadows
// }, 0);
}
createPostStage() {
const fs = glsl
if (Number(Cesium.VERSION.split('.')[1]) >= 102) {
fs = glsl2
}
const postStage = new Cesium.PostProcessStage({
fragmentShader: fs,
uniforms: {
shadowMap_textureCube: () => {
this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState"));
return Reflect.get(this.shadowMap, "_shadowMapTexture");
},
shadowMap_matrix: () => {
this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState"));
return Reflect.get(this.shadowMap, "_shadowMapMatrix");
},
shadowMap_lightPositionEC: () => {
this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState"));
return Reflect.get(this.shadowMap, "_lightPositionEC");
},
shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness: () => {
this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState"));
const bias = this.shadowMap._pointBias;
return Cesium.Cartesian4.fromElements(
bias.normalOffsetScale,
this.shadowMap._distance,
this.shadowMap.maximumDistance,
0.0,
new Cesium.Cartesian4()
);
},
shadowMap_texelSizeDepthBiasAndNormalShadingSmooth: () => {
this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState"));
const bias = this.shadowMap._pointBias;
const scratchTexelStepSize = new Cesium.Cartesian2();
const texelStepSize = scratchTexelStepSize;
texelStepSize.x = 1.0 / this.shadowMap._textureSize.x;
texelStepSize.y = 1.0 / this.shadowMap._textureSize.y;
return Cesium.Cartesian4.fromElements(
texelStepSize.x,
texelStepSize.y,
bias.depthBias,
bias.normalShadingSmooth,
new Cesium.Cartesian4()
);
},
camera_projection_matrix: this.lightCamera.frustum.projectionMatrix,
camera_view_matrix: this.lightCamera.viewMatrix,
helsing_viewDistance: () => {
return this.viewDistance;
},
helsing_visibleAreaColor: Cesium.Color.fromCssColorString(this.visibleAreaColor),
helsing_invisibleAreaColor: Cesium.Color.fromCssColorString(this.invisibleAreaColor),
}
});
this.postStage = this.viewer.scene.postProcessStages.add(postStage);
}
drawFrustumOutline() {
const scratchRight = new Cesium.Cartesian3();
const scratchRotation = new Cesium.Matrix3();
const scratchOrientation = new Cesium.Quaternion();
const position = this.lightCamera.positionWC;
const direction = this.lightCamera.directionWC;
const up = this.lightCamera.upWC;
let right = this.lightCamera.rightWC;
right = Cesium.Cartesian3.negate(right, scratchRight);
let rotation = scratchRotation;
Cesium.Matrix3.setColumn(rotation, 0, right, rotation);
Cesium.Matrix3.setColumn(rotation, 1, up, rotation);
Cesium.Matrix3.setColumn(rotation, 2, direction, rotation);
let orientation = Cesium.Quaternion.fromRotationMatrix(rotation, scratchOrientation);
let instance = new Cesium.GeometryInstance({
geometry: new Cesium.FrustumOutlineGeometry({
frustum: this.lightCamera.frustum,
origin: Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt + this.viewPointHeight),
orientation: orientation
}),
id: Math.random().toString(36).substr(2),
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
Cesium.Color.YELLOWGREEN//new Cesium.Color(0.0, 1.0, 0.0, 1.0)
),
show: new Cesium.ShowGeometryInstanceAttribute(true)
}
});
this.frustumOutline = this.viewer.scene.primitives.add(
new Cesium.Primitive({
geometryInstances: [instance],
appearance: new Cesium.PerInstanceColorAppearance({
flat: true,
translucent: false
})
})
);
}
drawSketch() {
this.sketch = this.viewer.entities.add({
name: 'sketch',
position: Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt + this.viewPointHeight),
orientation: Cesium.Transforms.headingPitchRollQuaternion(
Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt + this.viewPointHeight),
Cesium.HeadingPitchRoll.fromDegrees(this.viewHeading - 90, this.viewPitch, 0.0)
),
ellipsoid: {
radii: new Cesium.Cartesian3(
this.viewDistance,
this.viewDistance,
this.viewDistance
),
// innerRadii: new Cesium.Cartesian3(2.0, 2.0, 2.0),
minimumClock: Cesium.Math.toRadians(-this.horizontalViewAngle / 2),
maximumClock: Cesium.Math.toRadians(this.horizontalViewAngle / 2),
minimumCone: Cesium.Math.toRadians(90 - (this.verticalViewAngle / 2)),
maximumCone: Cesium.Math.toRadians(90 + (this.verticalViewAngle / 2)),
fill: false,
outline: true,
subdivisions: 256,
stackPartitions: 64,
slicePartitions: 64,
outlineColor: Cesium.Color.YELLOWGREEN
}
});
this.frustumOutline = this.viewer.entities.add({
name: 'sketch',
position: Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt + this.viewPointHeight),
orientation: Cesium.Transforms.headingPitchRollQuaternion(
Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt + this.viewPointHeight),
Cesium.HeadingPitchRoll.fromDegrees(this.viewHeading - 90, this.viewPitch, 0.0)
),
ellipsoid: {
radii: new Cesium.Cartesian3(
this.viewDistance,
this.viewDistance,
this.viewDistance
),
innerRadii: new Cesium.Cartesian3(0.0001, 0.0001, 0.0001),
minimumClock: Cesium.Math.toRadians(-this.horizontalViewAngle / 2),
maximumClock: Cesium.Math.toRadians(this.horizontalViewAngle / 2),
minimumCone: Cesium.Math.toRadians(90 - (this.verticalViewAngle / 2)),
maximumCone: Cesium.Math.toRadians(90 + (this.verticalViewAngle / 2)),
fill: false,
outline: true,
subdivisions: 256,
stackPartitions: 1,
slicePartitions: 1,
outlineColor: Cesium.Color.YELLOWGREEN
}
});
}
}
function getHeading(fromPosition, toPosition) {
let finalPosition = new Cesium.Cartesian3();
let matrix4 = Cesium.Transforms.eastNorthUpToFixedFrame(fromPosition);
Cesium.Matrix4.inverse(matrix4, matrix4);
Cesium.Matrix4.multiplyByPoint(matrix4, toPosition, finalPosition);
Cesium.Cartesian3.normalize(finalPosition, finalPosition);
return Cesium.Math.toDegrees(Math.atan2(finalPosition.x, finalPosition.y));
}
function getPitch(fromPosition, toPosition) {
let finalPosition = new Cesium.Cartesian3();
let matrix4 = Cesium.Transforms.eastNorthUpToFixedFrame(fromPosition);
Cesium.Matrix4.inverse(matrix4, matrix4);
Cesium.Matrix4.multiplyByPoint(matrix4, toPosition, finalPosition);
Cesium.Cartesian3.normalize(finalPosition, finalPosition);
return Cesium.Math.toDegrees(Math.asin(finalPosition.z));
}
export default ViewShedStage;

View File

@ -0,0 +1,74 @@
function html() {
return `
<span class="custom-divider"></span>
<div class="div-item">
<div class="row">
<div class="col">
<span class="label">位置拾取(起点、终点)</span>
<button class="edit"><svg class="icon-edit"><use xlink:href="#yj-icon-edit"></use></svg>拾取</button>
</div>
</div>
</div>
<span class="custom-divider"></span>
<div class="div-item">
<div class="row subtitle-box">
<span class="subtitle">视域夹角</span>
</div>
<div class="row">
<div class="col">
<div class="range-box">
<div class="range-bg">
<div class="range-process-box">
<div class="range-process"></div>
</div>
</div>
<div class="range-node-box">
<span class="range-node-text">0°</span>
<span class="range-node-text">45°</span>
<span class="range-node-text">90°</span>
<span class="range-node-text">135°</span>
<span class="range-node-text">180°</span>
<div class="range-node-active"><span class="range-node-active-text">0°</span></div>
</div>
<input type="range" max="180" min="0" step="1" name="horizontalViewAngle">
</div>
</div>
</div>
</div>
<span class="custom-divider"></span>
<div class="div-item">
<div class="row">
<div class="col">
<span class="label">经度:</span>
<span class="text-number" name="lng"></span>
</div>
<div class="col">
<span class="label">偏航角:</span>
<span class="text-number" name="viewHeading"></span>
<span class="unit">°</span>
</div>
</div>
<div class="row">
<div class="col">
<span class="label">纬度:</span>
<span class="text-number" name="lat"></span>
</div>
<div class="col">
<span class="label">俯仰角:</span>
<span class="text-number" name="viewPitch"></span>
<span class="unit">°</span>
</div>
</div>
<div class="row">
<div class="col">
<span class="label">高度:</span>
<span class="text-number" name="alt"></span>
<span class="unit text-number" style="margin-left: 5px;">m</span>
</div>
</div>
</div>
<span class="custom-divider"></span>
`
}
export { html }

View File

@ -0,0 +1,512 @@
/*
* @Author: Wang jianLei
* @Date: 2022-05-17 21:49:28
* @Last Modified by: Wang JianLei
* @Last Modified time: 2022-05-19 22:08:14
*/
let ViewShed = function (sdk, canvasEleId) {
if (!sdk.viewer) throw new Error("no viewer object!");
alert(canvasEleId)
let canvasEle = document.getElementById(canvasEleId);
if (!canvasEle) throw new Error("the canvas element is not exist");
this.canvasEle = canvasEle;
this.viewer = sdk.viewer;
this.handler = undefined;
this.lightCamera;
this.pyramid;
this.frustumPrimitive;
this.viewershedPolygon;
};
ViewShed.prototype = {
/**
* 初始化handler
*/
initHandler() {
if (this.handler) {
this.handler.destroy();
this.handler = undefined;
}
},
/**
* 开始执行视域分析
* @param {number} precision 精度值越大创建耗时越长建议在10~20之间
*/
createViewshed: function (precision) {
let $this = this;
let scene = $this.viewer.scene;
$this.initHandler();
$this.clearAll();
$this.handler = new Cesium.ScreenSpaceEventHandler($this.viewer.canvas);
$this.handler.setInputAction((event) => {
// 禁止地球旋转和缩放,地球的旋转会对鼠标移动监听有影响,所以需要禁止
scene.screenSpaceCameraController.enableRotate = false;
scene.screenSpaceCameraController.enableZoom = false;
scene.globe.depthTestAgainstTerrain = true;
let earthPosition = scene.pickPosition(event.position);
let pos = $this.cartesian3ToDegree(earthPosition);
$this.handler.setInputAction(function (event) {
let newPosition = scene.pickPosition(event.endPosition);
if (Cesium.defined(newPosition)) {
let pos1 = $this.cartesian3ToDegree(newPosition);
let distance = Cesium.Cartesian3.distance(newPosition, earthPosition);
let angle = $this.getAngle(pos[0], pos[1], pos1[0], pos1[1]);
let pitch = $this.getPitch(earthPosition, newPosition);
$this.ViewShedOptions = {
viewPosition: earthPosition, //观测点 笛卡尔坐标
endPosition: newPosition, //目标点 笛卡尔坐标
direction: angle, //观测方位角 默认为`0`,范围`0~360`
pitch: pitch, //俯仰角,radius,默认为`0`
horizontalViewAngle: 90, //可视域水平夹角,默认为 `90`,范围`0~360`
verticalViewAngle: 60, //可视域垂直夹角,默认为`60`,范围`0~180`
visibleAreaColor: Cesium.Color.GREEN, //可视区域颜色,默认为`green`
invisibleAreaColor: Cesium.Color.RED, //不可见区域颜色,默认为`red`
visualRange: distance, //距离,单位`米`
};
$this.updateViewShed();
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
}, Cesium.ScreenSpaceEventType.LEFT_DOWN);
$this.handler.setInputAction(() => {
$this.initHandler();
// 开启地球旋转和缩放
scene.screenSpaceCameraController.enableRotate = true;
scene.screenSpaceCameraController.enableZoom = true;
$this.drawViewershed(precision);
}, Cesium.ScreenSpaceEventType.LEFT_UP);
},
ReturnDistance(pos0, pos1) {
let distance = 0;
let point1cartographic = Cesium.Cartographic.fromCartesian(pos0);
let point2cartographic = Cesium.Cartographic.fromCartesian(pos1);
/**根据经纬度计算出距离**/
let geodesic = new Cesium.EllipsoidGeodesic();
geodesic.setEndPoints(point1cartographic, point2cartographic);
let s = geodesic.surfaceDistance;
return s;
},
getHeight(x, y, objectsToExclude) {
let endCartographic = Cesium.Cartographic.fromDegrees(x, y);
let endHeight = this.viewer.scene.sampleHeight(
endCartographic,
objectsToExclude
);
return endHeight;
},
cartesian3ToDegree: function (Cartesian3) {
let _ellipsoid = this.viewer.scene.globe.ellipsoid;
let _cartographic = _ellipsoid.cartesianToCartographic(Cartesian3);
let _lat = Cesium.Math.toDegrees(_cartographic.latitude);
let _lng = Cesium.Math.toDegrees(_cartographic.longitude);
let _alt = _cartographic.height;
return [_lng, _lat, _alt];
},
getAngle: function (lng1, lat1, lng2, lat2) {
let dRotateAngle = Math.atan2(Math.abs(lng1 - lng2), Math.abs(lat1 - lat2));
if (lng2 >= lng1) {
dRotateAngle = lat2 < lat1 ? Math.PI - dRotateAngle : dRotateAngle;
} else {
dRotateAngle =
lat2 >= lat1 ? 2 * Math.PI - dRotateAngle : Math.PI + dRotateAngle;
}
dRotateAngle = (dRotateAngle * 180) / Math.PI;
return dRotateAngle;
},
getPitch(pointA, pointB) {
let transfrom = Cesium.Transforms.eastNorthUpToFixedFrame(pointA);
const vector = Cesium.Cartesian3.subtract(
pointB,
pointA,
new Cesium.Cartesian3()
);
let direction = Cesium.Matrix4.multiplyByPointAsVector(
Cesium.Matrix4.inverse(transfrom, transfrom),
vector,
vector
);
Cesium.Cartesian3.normalize(direction, direction);
return Cesium.Math.PI_OVER_TWO - Cesium.Math.acosClamped(direction.z);
},
updateViewShed: function () {
this.clear();
this.setLightCamera();
this.addVisualPyramid();
this.createFrustum();
},
clear: function () {
if (this.pyramid) {
this.viewer.entities.removeById(this.pyramid.id);
this.pyramid = undefined;
}
if (this.frustumPrimitive) {
this.viewer.scene.primitives.remove(this.frustumPrimitive);
this.frustumPrimitive = undefined;
}
if (this.debugModelMatrixPrimitive) {
this.viewer.scene.primitives.remove(this.debugModelMatrixPrimitive);
this.debugModelMatrixPrimitive = undefined;
}
},
clearAll: function () {
this.clear();
if (this.viewershedPolygon) {
this.viewer.scene.primitives.remove(this.viewershedPolygon);
this.viewershedPolygon = undefined;
}
},
addVisualPyramid: function () {
let options = this.ViewShedOptions;
let position = options.viewPosition;
let visualRange = Number(options.visualRange);
let transform = Cesium.Transforms.eastNorthUpToFixedFrame(position);
this.debugModelMatrixPrimitive = this.viewer.scene.primitives.add(
new Cesium.DebugModelMatrixPrimitive({
modelMatrix: transform,
length: 5.0,
})
);
const halfClock = options.horizontalViewAngle / 2;
const halfCone = options.verticalViewAngle / 2;
const pitch = Cesium.Math.toDegrees(options.pitch);
const ellipsoid = new Cesium.EllipsoidGraphics({
radii: new Cesium.Cartesian3(visualRange, visualRange, visualRange),
minimumClock: Cesium.Math.toRadians(90 - options.direction - halfClock),
maximumClock: Cesium.Math.toRadians(90 - options.direction + halfClock),
minimumCone: Cesium.Math.toRadians(90 - pitch - halfCone),
maximumCone: Cesium.Math.toRadians(90 - pitch + halfCone),
fill: false,
outline: true,
subdivisions: 256,
stackPartitions: 64,
slicePartitions: 64,
outlineColor: Cesium.Color.YELLOWGREEN.withAlpha(0.5),
});
const pyramidEntity = new Cesium.Entity({
position: position,
ellipsoid,
});
this.pyramid = this.viewer.entities.add(pyramidEntity);
},
setLightCamera: function () {
if (!this.lightCamera) {
this.lightCamera = new Cesium.Camera(this.viewer.scene);
}
let options = this.ViewShedOptions;
let visualRange = Number(options.visualRange);
this.lightCamera.position = options.viewPosition;
this.lightCamera.frustum.near = 0.1;
this.lightCamera.frustum.far = visualRange;
const hr = Cesium.Math.toRadians(options.horizontalViewAngle);
const vr = Cesium.Math.toRadians(options.verticalViewAngle);
this.lightCamera.frustum.aspectRatio =
(visualRange * Math.tan(hr / 2) * 2) /
(visualRange * Math.tan(vr / 2) * 2);
this.lightCamera.frustum.fov = hr > vr ? hr : vr;
this.lightCamera.setView({
destination: options.viewPosition,
orientation: {
heading: Cesium.Math.toRadians(options.direction || 0),
pitch: options.pitch || 0,
roll: 0,
},
});
},
createFrustum: function () {
const scratchRight = new Cesium.Cartesian3();
const scratchRotation = new Cesium.Matrix3();
const scratchOrientation = new Cesium.Quaternion();
const direction = this.lightCamera.directionWC;
const up = this.lightCamera.upWC;
let right = this.lightCamera.rightWC;
right = Cesium.Cartesian3.negate(right, scratchRight);
let rotation = scratchRotation;
Cesium.Matrix3.setColumn(rotation, 0, right, rotation);
Cesium.Matrix3.setColumn(rotation, 1, up, rotation);
Cesium.Matrix3.setColumn(rotation, 2, direction, rotation);
let orientation = Cesium.Quaternion.fromRotationMatrix(
rotation,
scratchOrientation
);
let instanceOutline = new Cesium.GeometryInstance({
geometry: new Cesium.FrustumOutlineGeometry({
frustum: this.lightCamera.frustum,
origin: this.ViewShedOptions.viewPosition,
orientation: orientation,
}),
id: "视椎体轮廓线" + Math.random().toString(36).substr(2),
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
new Cesium.Color(0.0, 1.0, 0.0, 1.0)
),
show: new Cesium.ShowGeometryInstanceAttribute(true),
},
});
this.frustumPrimitive = this.viewer.scene.primitives.add(
new Cesium.Primitive({
geometryInstances: instanceOutline,
appearance: new Cesium.PerInstanceColorAppearance({
flat: true,
translucent: false,
closed: true,
}),
})
);
},
createPoint: function (firstPos, secondPos) {
let entity4FirstPos = new Cesium.Entity({
name: "firstPos",
show: true,
position: firstPos,
point: {
show: true,
pixelSize: 20,
color: Cesium.Color.RED,
outlineColor: Cesium.Color.YELLOW,
outlineWidth: 5,
},
description: `
<p>这是绘制的视椎体起点</p>`,
});
this.viewer.entities.add(entity4FirstPos);
let entity4SecondPos = new Cesium.Entity({
name: "secondPos",
show: true,
position: secondPos,
point: {
show: true,
pixelSize: 30,
color: Cesium.Color.YELLOW,
outlineColor: Cesium.Color.RED,
outlineWidth: 8,
},
description: `
<p>这是绘制的视椎体视角终点</p>`,
});
this.viewer.entities.add(entity4SecondPos);
},
//绘制可视域
add(positionArr) {
let polygon = new Cesium.PolygonGeometry({
polygonHierarchy: new Cesium.PolygonHierarchy(
Cesium.Cartesian3.fromDegreesArray(positionArr)
),
height: 0.0,
extrudedHeight: 0.0,
vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT,
stRotation: 0.0, // 纹理的旋转坐标(以弧度为单位),正旋转是逆时针方向
ellipsoid: Cesium.Ellipsoid.WGS84,
granularity: Cesium.Math.RADIANS_PER_DEGREE, // 每个纬度和经度之间的距离(以弧度为单位),确定缓冲区中的位置数
perPositionHeight: false, // 每个位置点使用的高度
closeTop: true,
closeBottom: true,
// NONE 与椭圆表面不符的直线;GEODESIC 遵循测地路径;RHUMB 遵循大黄蜂或恶魔般的道路。
arcType: Cesium.ArcType.GEODESIC, // 多边形边缘线型
});
let polygonInstance = new Cesium.GeometryInstance({
geometry: polygon,
name: "ViewershedPolygon",
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
Cesium.Color.BLUE.withAlpha(0.6)
),
show: new Cesium.ShowGeometryInstanceAttribute(true), //显示或者隐藏
},
});
this.viewershedPolygon = this.viewer.scene.primitives.add(
new Cesium.GroundPrimitive({
geometryInstances: polygonInstance,
appearance: new Cesium.EllipsoidSurfaceAppearance({
aboveGround: true,
material: new Cesium.Material({
fabric: {
type: "Image",
uniforms: {
image: this.returnImgae(),
},
},
}),
}),
})
);
},
drawViewershed(precision) {
const pos = this.cartesian3ToDegree(this.ViewShedOptions.viewPosition);
const radius = this.ViewShedOptions.visualRange;
const direction = this.ViewShedOptions.direction;
let boundary = this.computeBoundaryOptions(pos, radius, direction);
const bbox = boundary.bbox;
let mask = turf.polygon([boundary.boundaryPoints]);
const dis = this.ViewShedOptions.visualRange / (precision * 1000);
let gridPoints = turf.pointGrid(bbox, dis, { mask: mask });
let pointsResult = this.createTargetPoints(gridPoints, dis, pos);
let variogram = kriging.train(
pointsResult.values,
pointsResult.lngs,
pointsResult.lats,
"exponential",
0,
100
);
let grid = kriging.grid([boundary.boundaryPoints], variogram, dis / 1000);
const colors = [
"#ff000080",
"#ff000080",
"#ff000080",
"#ff000080",
"#ff000080",
"#ff000080",
"#00ff0080",
"#00ff0080",
"#00ff0080",
"#00ff0080",
"#00ff0080",
"#00ff0080",
];
this.canvasEle.width = 3840;
this.canvasEle.height = 2160;
kriging.plot(
this.canvasEle,
grid,
[bbox[0], bbox[2]],
[bbox[1], bbox[3]],
colors
);
this.add(boundary.positionArr);
},
computeBoundaryOptions(pos, radius, angle) {
let Ea = 6378137; // 赤道半径
let Eb = 6356725; // 极半径
const lng = pos[0],
lat = pos[1];
const bbox = [lng, lat, lng, lat]; //[minX, minY, maxX, maxY]
let positionArr = [];
let boundaryPoints = [];
positionArr.push(lng, lat);
boundaryPoints.push([lng, lat]);
//正北是0°
let start = angle + 45 > 360 ? angle - 45 - 360 : angle - 45;
let end = start + 90;
for (let i = start; i <= end; i++) {
let dx = radius * Math.sin((i * Math.PI) / 180.0);
let dy = radius * Math.cos((i * Math.PI) / 180.0);
let ec = Eb + ((Ea - Eb) * (90.0 - lat)) / 90.0;
let ed = ec * Math.cos((lat * Math.PI) / 180);
let BJD = lng + ((dx / ed) * 180.0) / Math.PI;
let BWD = lat + ((dy / ec) * 180.0) / Math.PI;
positionArr.push(BJD, BWD);
boundaryPoints.push([BJD, BWD]);
this.refreshBBox(bbox, BJD, BWD);
}
boundaryPoints.push([lng, lat]);
return {
positionArr,
boundaryPoints,
bbox,
};
},
/**
* 更新外围矩形 Bbox
* @param {Array} result 外围矩形Bbox-[minX, minY, maxX, maxY]
* @param {Number} x 经度
* @param {Number} y 纬度
*/
refreshBBox(result, x, y) {
result[0] = x < result[0] ? x : result[0];
result[1] = y < result[1] ? y : result[1];
result[2] = x > result[2] ? x : result[2];
result[3] = y > result[3] ? y : result[3];
},
/**
* 插值点用射线判断通视性
* @param {*} gridPoints 网格点
* @param {*} step 步长,可以理解成是精度
* @param {*} sourcePos 视域分析起点
* @returns kriging插值所需的参数对象{ values:[], lngs:[], lats:[]}
*/
createTargetPoints(gridPoints, step, sourcePos) {
let positionArr = [];
let objectsToExclude = [
this.frustumPrimitive,
this.pyramid,
this.debugModelMatrixPrimitive,
];
let values = [],
lngs = [],
lats = [];
let height = this.getHeight(sourcePos[0], sourcePos[1], objectsToExclude);
positionArr.push({
x: sourcePos[0],
y: sourcePos[1],
z: height,
});
let viewPoint = this.ViewShedOptions.viewPosition;
for (let index = 0; index < gridPoints.features.length; index++) {
const feature = gridPoints.features[index];
const coords = feature.geometry.coordinates;
const x = coords[0],
y = coords[1];
let h = this.getHeight(x, y, objectsToExclude);
let endPoint = Cesium.Cartesian3.fromDegrees(x, y, h);
let direction = Cesium.Cartesian3.normalize(
Cesium.Cartesian3.subtract(
endPoint,
viewPoint,
new Cesium.Cartesian3()
),
new Cesium.Cartesian3()
);
// 建立射线
let ray = new Cesium.Ray(viewPoint, direction);
let result = this.viewer.scene.pickFromRay(ray, objectsToExclude); // 计算交互点,返回第一个
if (result) {
let buffer = this.ReturnDistance(endPoint, result.position);
// let M_color = Cesium.Color.GREEN;
if (buffer > step) {
// M_color = Cesium.Color.RED;
values.push(0);
} else {
values.push(1);
}
lngs.push(x);
lats.push(y);
// this.viewer.entities.add(
// new Cesium.Entity({
// name: "插值点哦",
// show: true,
// position: endPoint,
// point: {
// show: true,
// pixelSize: 10,
// color: M_color,
// outlineWidth: 2,
// outlineColor: Cesium.Color.YELLOW,
// },
// })
// );
}
}
return {
values,
lngs,
lats,
};
},
/**
* canvas转image图片
* @returns base64图片
*/
returnImgae() {
return this.canvasEle.toDataURL("image/png");
},
};
export default ViewShed;

View File

@ -0,0 +1,131 @@
export default `
#define USE_CUBE_MAP_SHADOW true
uniform sampler2D colorTexture;
uniform sampler2D depthTexture;
varying vec2 v_textureCoordinates;
uniform mat4 camera_projection_matrix;
uniform mat4 camera_view_matrix;
uniform samplerCube shadowMap_textureCube;
uniform mat4 shadowMap_matrix;
uniform vec4 shadowMap_lightPositionEC;
uniform vec4 shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness;
uniform vec4 shadowMap_texelSizeDepthBiasAndNormalShadingSmooth;
uniform float helsing_viewDistance;
uniform vec4 helsing_visibleAreaColor;
uniform vec4 helsing_invisibleAreaColor;
struct zx_shadowParameters
{
vec3 texCoords;
float depthBias;
float depth;
float nDotL;
vec2 texelStepSize;
float normalShadingSmooth;
float darkness;
};
float czm_shadowVisibility(samplerCube shadowMap, zx_shadowParameters shadowParameters)
{
float depthBias = shadowParameters.depthBias;
float depth = shadowParameters.depth;
float nDotL = shadowParameters.nDotL;
float normalShadingSmooth = shadowParameters.normalShadingSmooth;
float darkness = shadowParameters.darkness;
vec3 uvw = shadowParameters.texCoords;
depth -= depthBias;
float visibility = czm_shadowDepthCompare(shadowMap, uvw, depth);
return czm_private_shadowVisibility(visibility, nDotL, normalShadingSmooth, darkness);
}
vec4 getPositionEC(){
return czm_windowToEyeCoordinates(gl_FragCoord);
}
vec3 getNormalEC(){
return vec3(1.);
}
vec4 toEye(in vec2 uv,in float depth){
vec2 xy=vec2((uv.x*2.-1.),(uv.y*2.-1.));
vec4 posInCamera=czm_inverseProjection*vec4(xy,depth,1.);
posInCamera=posInCamera/posInCamera.w;
return posInCamera;
}
vec3 pointProjectOnPlane(in vec3 planeNormal,in vec3 planeOrigin,in vec3 point){
vec3 v01=point-planeOrigin;
float d=dot(planeNormal,v01);
return(point-planeNormal*d);
}
float getDepth(in vec4 depth){
float z_window=czm_unpackDepth(depth);
z_window=czm_reverseLogDepth(z_window);
float n_range=czm_depthRange.near;
float f_range=czm_depthRange.far;
return(2.*z_window-n_range-f_range)/(f_range-n_range);
}
float shadow(in vec4 positionEC){
vec3 normalEC=getNormalEC();
zx_shadowParameters shadowParameters;
shadowParameters.texelStepSize=shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.xy;
shadowParameters.depthBias=shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.z;
shadowParameters.normalShadingSmooth=shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.w;
shadowParameters.darkness=shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness.w;
vec3 directionEC=positionEC.xyz-shadowMap_lightPositionEC.xyz;
float distance=length(directionEC);
directionEC=normalize(directionEC);
float radius=shadowMap_lightPositionEC.w;
if(distance>radius)
{
return 2.0;
}
vec3 directionWC=czm_inverseViewRotation*directionEC;
shadowParameters.depth=distance/radius-0.0003;
shadowParameters.nDotL=clamp(dot(normalEC,-directionEC),0.,1.);
shadowParameters.texCoords=directionWC;
float visibility=czm_shadowVisibility(shadowMap_textureCube,shadowParameters);
return visibility;
}
bool visible(in vec4 result)
{
result.x/=result.w;
result.y/=result.w;
result.z/=result.w;
return result.x>=-1.&&result.x<=1.
&&result.y>=-1.&&result.y<=1.
&&result.z>=-1.&&result.z<=1.;
}
void main(){
// 釉色 = 结构二维(颜色纹理, 纹理坐标)
gl_FragColor = texture2D(colorTexture, v_textureCoordinates);
// 深度 = 获取深度(结构二维(深度纹理, 纹理坐标))
float depth = getDepth(texture2D(depthTexture, v_textureCoordinates));
// 视角 = (纹理坐标, 深度)
vec4 viewPos = toEye(v_textureCoordinates, depth);
// 世界坐标
vec4 wordPos = czm_inverseView * viewPos;
// 虚拟相机中坐标
vec4 vcPos = camera_view_matrix * wordPos;
float near = .001 * helsing_viewDistance;
float dis = length(vcPos.xyz);
if(dis > near && dis < helsing_viewDistance){
// 透视投影
vec4 posInEye = camera_projection_matrix * vcPos;
// 可视区颜色
// vec4 helsing_visibleAreaColor=vec4(0.,1.,0.,.5);
// vec4 helsing_invisibleAreaColor=vec4(1.,0.,0.,.5);
if(visible(posInEye)){
float vis = shadow(viewPos);
if(vis > 0.3){
gl_FragColor = mix(gl_FragColor,helsing_visibleAreaColor,.5);
} else {
gl_FragColor = mix(gl_FragColor,helsing_invisibleAreaColor,.5);
}
}
}
}`;

View File

@ -0,0 +1,721 @@
// ViewShed.js
import glsl from './glsl'
import Event from "../../../Event";
import MouseTip from "../../../MouseTip";
import Tools from "../../../Tools";
import Controller from "../../../Controller";
import Dialog from '../../../BaseDialog';
import { html } from "./_element";
/**
* @constructor
* @description 可视域分析(测试中)
* @param sdk
* @param {Object} options 选项。
* @param {Cesium.Cartesian3} options.viewPosition 观测点位置。
* @param {Cesium.Cartesian3} options.viewPositionEnd 最远观测点位置(如果设置了观测距离,这个属性可以不设置)。
* @param {Number} options.viewDistance 观测距离(单位`米`)。
* @param {Number} options.viewHeading 航向角(单位`度`)。
* @param {Number} options.viewPitch 俯仰角(单位`度`)。
* @param {Number} options.horizontalViewAngle=90 可视域水平夹角(单位`度`)。
* @param {Number} options.verticalViewAngle=60 可视域垂直夹角(单位`度`)。
* @param {String} options.visibleAreaColor=#008000 可视区域颜色(默认值`绿色`)。
* @param {String} options.invisibleAreaColor=#FF0000 不可视区域颜色(默认值`红色`)。
*/
class ViewShedStage extends Tools {
constructor(sdk, options = {}, _Dialog = {}) {
super(sdk, options)
// if (Object.hasOwn(options.viewPosition, 'lng') && Object.hasOwn(options.viewPosition, 'lat') && Object.hasOwn(options.viewPosition, 'alt')) {
// this.error = '请提供观测点位置!'
// window.ELEMENT && window.ELEMENT.Message({
// message: '请提供观测点位置!',
// type: 'warning',
// duration: 1500
// });
// return
// }
this.viewer = sdk.viewer;
this.options = {}
this.options.viewPosition = options.viewPosition;
this.options.viewPositionEnd = options.viewPositionEnd;
this.options.horizontalViewAngle = (options.horizontalViewAngle || options.horizontalViewAngle === 0) ? options.horizontalViewAngle : 90.0;
this.options.verticalViewAngle = (options.verticalViewAngle || options.verticalViewAngle === 0) ? options.verticalViewAngle : 60.0;
this.options.visibleAreaColor = options.visibleAreaColor || '#008000';
this.options.invisibleAreaColor = options.invisibleAreaColor || '#FF0000';
// this.enabled = (typeof options.enabled === "boolean") ? options.enabled : true;
// this.softShadows = (typeof options.softShadows === "boolean") ? options.softShadows : true;
// this.size = options.size || 10240; // 2048
this.ids = []
this.Dialog = _Dialog
this.html = null
YJ.Analysis.Analyses.push(this)
ViewShedStage.create(this)
// ViewShedStage.edit(this)
// this.update();
}
get viewPosition() {
return this.options.viewPosition
}
set viewPosition(v) {
this.options.viewPosition = v
this.ids[0] && (this.viewer.entities.getById(this.ids[0]).position = new Cesium.Cartesian3.fromDegrees(v.lng, v.lat, v.alt))
this.update()
// let viewPosition3 = Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt)
}
get viewPositionEnd() {
return this.options.viewPositionEnd
}
set viewPositionEnd(v) {
this.options.viewPositionEnd = v
this.ids[1] && (this.viewer.entities.getById(this.ids[1]).position = new Cesium.Cartesian3.fromDegrees(v.lng, v.lat, v.alt))
this.update()
// let viewPositionEnd3 = Cesium.Cartesian3.fromDegrees(this.options.viewPositionEnd.lng, this.options.viewPositionEnd.lat, this.options.viewPositionEnd.alt)
// this.viewDistance = this.viewPositionEnd ? Cesium.Cartesian3.distance(this.viewPosition, this.viewPositionEnd) : (options.viewDistance || 100.0);
}
get horizontalViewAngle() {
return this.options.horizontalViewAngle
}
set horizontalViewAngle(v) {
this.options.horizontalViewAngle = v
if (this._DialogObject && this._DialogObject._element && this._DialogObject._element.content) {
let contentElm = this._DialogObject._element.content
let e_horizontalViewAngle = contentElm.querySelector("input[name='horizontalViewAngle']")
e_horizontalViewAngle.value = v
let rangeNodeActive = contentElm.getElementsByClassName('range-node-active')[0]
let rangeNodeActiveText = rangeNodeActive.getElementsByClassName('range-node-active-text')[0]
rangeNodeActiveText.innerHTML = v + '°';
let rangeProcess = contentElm.getElementsByClassName('range-process')[0]
rangeProcess.style.width = v / 180 * 100 + '%'
}
this.update()
}
get visibleAreaColor() {
return this.options.visibleAreaColor
}
set visibleAreaColor(v) {
this.options.visibleAreaColor = v
this.update()
}
get invisibleAreaColor() {
return this.options.invisibleAreaColor
}
set invisibleAreaColor(v) {
this.options.invisibleAreaColor = v
this.update()
}
get verticalViewAngle() {
return this.options.verticalViewAngle
}
set verticalViewAngle(v) {
this.options.verticalViewAngle = v
this.update()
}
get viewDistance() {
let viewPosition3 = Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt)
let viewPositionEnd3 = Cesium.Cartesian3.fromDegrees(this.options.viewPositionEnd.lng, this.options.viewPositionEnd.lat, this.options.viewPositionEnd.alt)
let distance = Cesium.Cartesian3.distance(viewPosition3, viewPositionEnd3)
return distance
}
get viewHeading() {
let viewPosition3 = Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt)
let viewPositionEnd3 = Cesium.Cartesian3.fromDegrees(this.options.viewPositionEnd.lng, this.options.viewPositionEnd.lat, this.options.viewPositionEnd.alt)
let heading = getHeading(viewPosition3, viewPositionEnd3)
if (this.html) {
let e_viewHeading = this.html.querySelector("span[name='viewHeading']")
e_viewHeading.innerHTML = Number(heading.toFixed(8))
}
return heading
}
get viewPitch() {
let viewPosition3 = Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt)
let viewPositionEnd3 = Cesium.Cartesian3.fromDegrees(this.options.viewPositionEnd.lng, this.options.viewPositionEnd.lat, this.options.viewPositionEnd.alt)
let pitch = getPitch(viewPosition3, viewPositionEnd3)
if (this.html) {
let e_viewPitch = this.html.querySelector("span[name='viewPitch']")
e_viewPitch.innerHTML = Number(pitch.toFixed(8))
}
return pitch
}
static create(that) {
let count = 0;
if (!YJ.Measure.GetMeasureStatus()) {
that.event = new Event(that.sdk)
that.tip = new MouseTip('左键选择观测点位置,右键取消', that.sdk)
YJ.Measure.SetMeasureStatus(true)
that.event.mouse_left((movement, cartesian) => {
if (!that.viewPosition) {
that.options.viewPosition = that.cartesian3Towgs84(cartesian, that.viewer)
that.ids.push(ViewShedStage.create_point(that, cartesian))
that.tip.set_text("左键选择最远观测点位置,右键取消")
}
count++
if (count === 2) {
that.options.viewPositionEnd = that.cartesian3Towgs84(cartesian, that.viewer)
that.ids.push(ViewShedStage.create_point(that, cartesian))
end()
that.update()
}
})
that.event.mouse_move((movement, cartesian) => {
that.tip.setPosition(cartesian, movement.endPosition.x, movement.endPosition.y)
})
that.event.mouse_right((movement, cartesian) => {
that.ids.forEach(id => {
that.viewer.entities.removeById(id)
})
that.ids = []
end()
})
that.event.gesture_pinck_start((movement, cartesian) => {
let startTime = new Date()
that.event.gesture_pinck_end(() => {
let endTime = new Date()
if (endTime - startTime >= 500) {
that.ids.forEach(id => {
that.viewer.entities.removeById(id)
})
that.ids = []
end()
}
})
})
}
else {
console.log('上一次测量未结束')
}
function end() {
that.ids.forEach(id => {
let entity = that.viewer.entities.getById(id)
entity.show = false
})
YJ.Measure.SetMeasureStatus(false)
that.tip.destroy()
that.event.destroy()
that.tip = null
that.event = null
if (count === 2) {
ViewShedStage.edit(that)
}
}
}
static create_point(that, cartesian) {
let id = that.randomString()
let p = that.cartesian3Towgs84(cartesian, that.viewer)
let params = {
id: id,
position: Cesium.Cartesian3.fromDegrees(p.lng, p.lat, p.alt),
billboard: {
image: that.getSourceRootPath() + '/img/point.png',
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
disableDepthTestDistance: Number.POSITIVE_INFINITY,
color: Cesium.Color.WHITE.withAlpha(0.99)
}
}
that.viewer.entities.add(
new Cesium.Entity(params)
)
return id
}
add() {
this.createLightCamera();
this.createShadowMap();
this.createPostStage();
this.drawFrustumOutline();
this.drawSketch();
}
update() {
this.clear();
this.add();
}
static async edit(that) {
if (that._DialogObject && that._DialogObject.close) {
that._DialogObject.close()
that._DialogObject = null
}
that._DialogObject = await new Dialog(that.sdk.viewer._container, {
title: '可视域分析', left: '180px', top: '100px',
closeCallBack: () => {
that.Dialog.closeCallBack && that.Dialog.closeCallBack()
YJ.Measure.SetMeasureStatus(false)
that.editevent && that.editevent.destroy()
that.ControllerObject && that.ControllerObject.destroy()
that.ids.forEach(id => {
that.viewer.entities.removeById(id)
})
},
})
await that._DialogObject.init()
that._DialogObject._element.body.className = that._DialogObject._element.body.className + ' view-shed'
let contentElm = document.createElement('div');
contentElm.innerHTML = html()
that._DialogObject.contentAppChild(contentElm)
let resetBtn = that._DialogObject._element.body.getElementsByClassName('edit')[0];
resetBtn.addEventListener('click', () => {
that.nodeEdit()
})
that.html = contentElm
//经度值
let e_lng = contentElm.querySelector("span[name='lng']")
e_lng.innerHTML = Number(that.options.viewPosition.lng.toFixed(8))
//纬度值
let e_lat = contentElm.querySelector("span[name='lat']")
e_lat.innerHTML = Number(that.options.viewPosition.lat.toFixed(8))
//高度值
let e_alt = contentElm.querySelector("span[name='alt']")
e_alt.innerHTML = Number(that.options.viewPosition.alt.toFixed(8))
//偏航角
let e_viewHeading = contentElm.querySelector("span[name='viewHeading']")
e_viewHeading.innerHTML = Number(that.viewHeading.toFixed(8))
//俯仰角
let e_viewPitch = contentElm.querySelector("span[name='viewPitch']")
e_viewPitch.innerHTML = Number(that.viewPitch.toFixed(8))
//视域夹角
let e_horizontalViewAngle = contentElm.querySelector("input[name='horizontalViewAngle']")
e_horizontalViewAngle.value = that.options.horizontalViewAngle
let rangeNodeActive = contentElm.getElementsByClassName('range-node-active')[0]
let rangeNodeActiveText = rangeNodeActive.getElementsByClassName('range-node-active-text')[0]
let rangeProcess = contentElm.getElementsByClassName('range-process')[0]
let percentage = that.horizontalViewAngle / 180 * 100
rangeNodeActive.style.left = percentage + '%';
rangeProcess.style.width = percentage + '%'
rangeNodeActiveText.innerHTML = that.horizontalViewAngle + '°';
let timeout
e_horizontalViewAngle.addEventListener('input', () => {
let percentage = e_horizontalViewAngle.value / 180 * 100
rangeNodeActive.style.left = percentage + '%';
rangeProcess.style.width = percentage + '%';
rangeNodeActiveText.innerHTML = e_horizontalViewAngle.value + '°';
})
e_horizontalViewAngle.addEventListener('change', () => {
clearTimeout(timeout)
timeout = setTimeout(() => {
that.horizontalViewAngle = e_horizontalViewAngle.value;
}, 300);
});
}
clear() {
YJ.Measure.SetMeasureStatus(false)
this.tip && this.tip.destroy()
this.event && this.event.destroy()
this.tip = null
this.event = null
if (this.sketch) {
this.viewer.entities.removeById(this.sketch.id);
this.sketch = null;
}
if (this.frustumOutline) {
this.frustumOutline.destroy();
this.frustumOutline = null;
}
if (this.FrustumBottomSurface) {
this.FrustumBottomSurface.destroy();
this.FrustumBottomSurface = null;
}
if (this.postStage) {
this.viewer.scene.postProcessStages.remove(this.postStage);
this.postStage = null;
}
}
destroy() {
this.clear()
this.editevent && this.editevent.destroy()
this.ControllerObject && this.ControllerObject.destroy()
this.ids.forEach(id => {
this.viewer.entities.removeById(id)
})
YJ.Measure.SetMeasureStatus(false)
}
nodeEdit() {
if (YJ.Measure.GetMeasureStatus()) {
console.log('上一次测量未结束')
}
else {
this.editevent && this.editevent.destroy()
this.ids.forEach(id => {
let entity = this.viewer.entities.getById(id)
entity.show = true
})
let selectPoint
YJ.Measure.SetMeasureStatus(true)
// this.tip = new MouseTip('左键选择要操作的观测点,右键取消', this.sdk)
this.editevent = new Event(this.sdk)
this.editevent.mouse_left((movement, cartesian) => {
let pick = this.viewer.scene.pick(movement.position);
if (pick && pick.id && pick.id.id && this.ids.indexOf(pick.id.id) != -1 && (!selectPoint || selectPoint.id != pick.id.id)) {
selectPoint = pick.id
// this.event.destroy()
// this.tip.destroy()
this.viewer.entities.getById(this.ids[0]).position = new Cesium.Cartesian3.fromDegrees(this.viewPosition.lng, this.viewPosition.lat, this.viewPosition.alt)
this.viewer.entities.getById(this.ids[1]).position = new Cesium.Cartesian3.fromDegrees(this.viewPositionEnd.lng, this.viewPositionEnd.lat, this.viewPositionEnd.alt)
this.viewPosition
this.ControllerObject && this.ControllerObject.destroy()
console.log(this.cartesian3Towgs84(selectPoint.position._value, this.sdk.viewer))
this.ControllerObject = new Controller(this.sdk, { position: { ...this.cartesian3Towgs84(selectPoint.position._value, this.sdk.viewer) } })
this.ControllerObject.controllerCallBack = (params, status) => {
if (params.position.alt < 0) {
params.position.alt = 0
}
selectPoint.position = new Cesium.Cartesian3.fromDegrees(params.position.lng, params.position.lat, params.position.alt)
if (status) {
if (this.ids.indexOf(pick.id.id) == 0) {
this.viewPosition = params.position
}
else {
this.viewPositionEnd = params.position
}
YJ.Measure.SetMeasureStatus(true)
}
}
this.ControllerObject.editTranslational()
}
})
this.editevent.mouse_right((movement, cartesian) => {
YJ.Measure.SetMeasureStatus(false)
this.editevent && this.editevent.destroy()
this.ControllerObject && this.ControllerObject.destroy()
this.ids.forEach(id => {
let entity = this.viewer.entities.getById(id)
entity.show = false
})
selectPoint = null
})
this.editevent.mouse_move((movement, cartesian) => {
// this.tip.setPosition(
// cartesian,
// movement.endPosition.x,
// movement.endPosition.y
// )
})
this.editevent.gesture_pinck_start((movement, cartesian) => {
let startTime = new Date()
this.editevent.gesture_pinck_end(() => {
let endTime = new Date()
if (endTime - startTime >= 500) {
YJ.Measure.SetMeasureStatus(false)
this.editevent && this.editevent.destroy()
this.ControllerObject && this.ControllerObject.destroy()
this.ids.forEach(id => {
let entity = this.viewer.entities.getById(id)
entity.show = false
})
selectPoint = null
}
})
})
}
}
createLightCamera() {
let _this = this
this.lightCamera = new Cesium.Camera(this.viewer.scene);
this.lightCamera.position = Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt);
// if (this.viewPositionEnd) {
// let direction = Cesium.Cartesian3.normalize(Cesium.Cartesian3.subtract(this.viewPositionEnd, this.viewPosition, new Cesium.Cartesian3()), new Cesium.Cartesian3());
// this.lightCamera.direction = direction; // direction是相机面向的方向
// }
this.lightCamera.frustum.near = this.viewDistance * 0.001;
this.lightCamera.frustum.far = this.viewDistance;
const hr = Cesium.Math.toRadians(this.horizontalViewAngle);
const vr = Cesium.Math.toRadians(this.verticalViewAngle);
const aspectRatio =
(this.viewDistance * Math.tan(hr / 2) * 2) /
(this.viewDistance * Math.tan(vr / 2) * 2);
this.lightCamera.frustum.aspectRatio = aspectRatio;
if (hr > vr) {
this.lightCamera.frustum.fov = hr;
} else {
this.lightCamera.frustum.fov = vr;
}
this.lightCamera.setView({
destination: Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt),
orientation: {
heading: Cesium.Math.toRadians(this.viewHeading || 0),
pitch: Cesium.Math.toRadians(this.viewPitch || 0),
roll: 0
}
});
}
createShadowMap() {
this.shadowMap = new Cesium.ShadowMap({
context: (this.viewer.scene).context,
lightCamera: this.lightCamera,
enabled: true,
isPointLight: true,
pointLightRadius: this.viewDistance,
cascadesEnabled: false,
size: 2048, // 2048
softShadows: true,
normalOffset: false,
fromLightSource: false
});
this.viewer.scene.shadowMap = this.shadowMap;
}
createPostStage() {
const fs = glsl
const postStage = new Cesium.PostProcessStage({
fragmentShader: fs,
uniforms: {
shadowMap_textureCube: () => {
this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState"));
return Reflect.get(this.shadowMap, "_shadowMapTexture");
},
shadowMap_matrix: () => {
this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState"));
return Reflect.get(this.shadowMap, "_shadowMapMatrix");
},
shadowMap_lightPositionEC: () => {
this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState"));
return Reflect.get(this.shadowMap, "_lightPositionEC");
},
shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness: () => {
this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState"));
const bias = this.shadowMap._pointBias;
return Cesium.Cartesian4.fromElements(
bias.normalOffsetScale,
this.shadowMap._distance,
this.shadowMap.maximumDistance,
0.0,
new Cesium.Cartesian4()
);
},
shadowMap_texelSizeDepthBiasAndNormalShadingSmooth: () => {
this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState"));
const bias = this.shadowMap._pointBias;
const scratchTexelStepSize = new Cesium.Cartesian2();
const texelStepSize = scratchTexelStepSize;
texelStepSize.x = 1.0 / this.shadowMap._textureSize.x;
texelStepSize.y = 1.0 / this.shadowMap._textureSize.y;
return Cesium.Cartesian4.fromElements(
texelStepSize.x,
texelStepSize.y,
bias.depthBias,
bias.normalShadingSmooth,
new Cesium.Cartesian4()
);
},
camera_projection_matrix: this.lightCamera.frustum.projectionMatrix,
camera_view_matrix: this.lightCamera.viewMatrix,
helsing_viewDistance: () => {
return this.viewDistance;
},
helsing_visibleAreaColor: Cesium.Color.fromCssColorString(this.visibleAreaColor),
helsing_invisibleAreaColor: Cesium.Color.fromCssColorString(this.invisibleAreaColor),
shadowMap: this.shadowMap,
far: () => {
return this.viewDistance;
},
}
});
this.postStage = this.viewer.scene.postProcessStages.add(postStage);
}
drawFrustumOutline() {
const scratchRight = new Cesium.Cartesian3();
const scratchRotation = new Cesium.Matrix3();
const scratchOrientation = new Cesium.Quaternion();
const position = this.lightCamera.positionWC;
const direction = this.lightCamera.directionWC;
const up = this.lightCamera.upWC;
let right = this.lightCamera.rightWC;
right = Cesium.Cartesian3.negate(right, scratchRight);
let rotation = scratchRotation;
Cesium.Matrix3.setColumn(rotation, 0, right, rotation);
Cesium.Matrix3.setColumn(rotation, 1, up, rotation);
Cesium.Matrix3.setColumn(rotation, 2, direction, rotation);
let orientation = Cesium.Quaternion.fromRotationMatrix(rotation, scratchOrientation);
let instance = new Cesium.GeometryInstance({
geometry: new Cesium.FrustumOutlineGeometry({
frustum: this.lightCamera.frustum,
origin: Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt),
orientation: orientation
}),
id: Math.random().toString(36).substr(2),
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
Cesium.Color.YELLOWGREEN//new Cesium.Color(0.0, 1.0, 0.0, 1.0)
),
show: new Cesium.ShowGeometryInstanceAttribute(true)
}
});
let frustum = this.lightCamera.frustum.clone()
frustum.near = frustum.far - 100
let instance2 = new Cesium.GeometryInstance({
geometry: new Cesium.FrustumGeometry({
frustum: frustum,
origin: Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt),
orientation: orientation,
vertexFormat: Cesium.VertexFormat.POSITION_ONLY,
}),
id: Math.random().toString(36).substr(2),
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
Cesium.Color.YELLOWGREEN//new Cesium.Color(0.0, 1.0, 0.0, 1.0)
),
show: new Cesium.ShowGeometryInstanceAttribute(true)
}
});
this.frustumOutline = this.viewer.scene.primitives.add(
new Cesium.Primitive({
geometryInstances: [instance],
appearance: new Cesium.PerInstanceColorAppearance({
flat: true,
translucent: false
})
})
);
const radius = this.viewDistance;
const angle = this.viewHeading;
let Ea = 6378137; // 赤道半径
let Eb = 6356725; // 极半径
const lng = this.options.viewPosition.lng,
lat = this.options.viewPosition.lat;
let positionArr = [];
let boundaryPoints = [];
positionArr.push(lng, lat);
boundaryPoints.push([lng, lat]);
//正北是0°
let start = angle + 45 > 360 ? angle - 45 - 360 : angle - 45;
let end = start + 90;
for (let i = start; i <= end; i++) {
let dx = radius * Math.sin((i * Math.PI) / 180.0);
let dy = radius * Math.cos((i * Math.PI) / 180.0);
let ec = Eb + ((Ea - Eb) * (90.0 - lat)) / 90.0;
let ed = ec * Math.cos((lat * Math.PI) / 180);
let BJD = lng + ((dx / ed) * 180.0) / Math.PI;
let BWD = lat + ((dy / ec) * 180.0) / Math.PI;
positionArr.push(BJD, BWD);
}
let polygon = new Cesium.PolygonGeometry({
polygonHierarchy: new Cesium.PolygonHierarchy(
Cesium.Cartesian3.fromDegreesArray(positionArr)
),
height: 0.0,
extrudedHeight: 0.0,
vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT,
stRotation: 0.0, // 纹理的旋转坐标(以弧度为单位),正旋转是逆时针方向
ellipsoid: Cesium.Ellipsoid.WGS84,
granularity: Cesium.Math.RADIANS_PER_DEGREE, // 每个纬度和经度之间的距离(以弧度为单位),确定缓冲区中的位置数
perPositionHeight: false, // 每个位置点使用的高度
closeTop: true,
closeBottom: true,
// NONE 与椭圆表面不符的直线;GEODESIC 遵循测地路径;RHUMB 遵循大黄蜂或恶魔般的道路。
arcType: Cesium.ArcType.GEODESIC, // 多边形边缘线型
});
let polygonInstance = new Cesium.GeometryInstance({
geometry: polygon,
name: "ViewershedPolygon",
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
Cesium.Color.BLUE
),
show: new Cesium.ShowGeometryInstanceAttribute(true), //显示或者隐藏
},
});
// this.FrustumBottomSurface = this.viewer.scene.primitives.add(
// new Cesium.GroundPrimitive({
// geometryInstances: polygonInstance,
// appearance: new Cesium.PerInstanceColorAppearance({
// translucent: true, //false时透明度无效
// closed: false,
// }),
// })
// );
}
drawSketch() {
this.sketch = this.viewer.entities.add({
name: 'sketch',
position: Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt),
orientation: Cesium.Transforms.headingPitchRollQuaternion(
Cesium.Cartesian3.fromDegrees(this.options.viewPosition.lng, this.options.viewPosition.lat, this.options.viewPosition.alt),
Cesium.HeadingPitchRoll.fromDegrees(this.viewHeading - 90, this.viewPitch, 0.0)
),
ellipsoid: {
radii: new Cesium.Cartesian3(
this.viewDistance,
this.viewDistance,
this.viewDistance
),
// innerRadii: new Cesium.Cartesian3(2.0, 2.0, 2.0),
minimumClock: Cesium.Math.toRadians(-this.horizontalViewAngle / 2),
maximumClock: Cesium.Math.toRadians(this.horizontalViewAngle / 2),
minimumCone: Cesium.Math.toRadians(this.verticalViewAngle + 7.75),
maximumCone: Cesium.Math.toRadians(180 - this.verticalViewAngle - 7.75),
fill: false,
outline: true,
subdivisions: 256,
stackPartitions: 64,
slicePartitions: 64,
outlineColor: Cesium.Color.YELLOWGREEN
}
});
}
}
function getHeading(fromPosition, toPosition) {
let finalPosition = new Cesium.Cartesian3();
let matrix4 = Cesium.Transforms.eastNorthUpToFixedFrame(fromPosition);
Cesium.Matrix4.inverse(matrix4, matrix4);
Cesium.Matrix4.multiplyByPoint(matrix4, toPosition, finalPosition);
Cesium.Cartesian3.normalize(finalPosition, finalPosition);
return Cesium.Math.toDegrees(Math.atan2(finalPosition.x, finalPosition.y));
}
function getPitch(fromPosition, toPosition) {
let finalPosition = new Cesium.Cartesian3();
let matrix4 = Cesium.Transforms.eastNorthUpToFixedFrame(fromPosition);
Cesium.Matrix4.inverse(matrix4, matrix4);
Cesium.Matrix4.multiplyByPoint(matrix4, toPosition, finalPosition);
Cesium.Cartesian3.normalize(finalPosition, finalPosition);
return Cesium.Math.toDegrees(Math.asin(finalPosition.z));
}
export default ViewShedStage;

View File

@ -0,0 +1,74 @@
function html() {
return `
<span class="custom-divider"></span>
<div class="div-item">
<div class="row">
<div class="col">
<span class="label">位置拾取(起点、终点)</span>
<button class="edit"><svg class="icon-edit"><use xlink:href="#yj-icon-edit"></use></svg>拾取</button>
</div>
</div>
</div>
<span class="custom-divider"></span>
<div class="div-item">
<div class="row subtitle-box">
<span class="subtitle">视域夹角</span>
</div>
<div class="row">
<div class="col">
<div class="range-box">
<div class="range-bg">
<div class="range-process-box">
<div class="range-process"></div>
</div>
</div>
<div class="range-node-box">
<span class="range-node-text">0°</span>
<span class="range-node-text">45°</span>
<span class="range-node-text">90°</span>
<span class="range-node-text">135°</span>
<span class="range-node-text">180°</span>
<div class="range-node-active"><span class="range-node-active-text">0°</span></div>
</div>
<input type="range" max="180" min="0" step="1" name="horizontalViewAngle">
</div>
</div>
</div>
</div>
<span class="custom-divider"></span>
<div class="div-item">
<div class="row">
<div class="col">
<span class="label">经度:</span>
<span class="text-number" name="lng"></span>
</div>
<div class="col">
<span class="label">偏航角:</span>
<span class="text-number" name="viewHeading"></span>
<span class="unit">°</span>
</div>
</div>
<div class="row">
<div class="col">
<span class="label">纬度:</span>
<span class="text-number" name="lat"></span>
</div>
<div class="col">
<span class="label">俯仰角:</span>
<span class="text-number" name="viewPitch"></span>
<span class="unit">°</span>
</div>
</div>
<div class="row">
<div class="col">
<span class="label">高度:</span>
<span class="text-number" name="alt"></span>
<span class="unit text-number" style="margin-left: 5px;">m</span>
</div>
</div>
</div>
<span class="custom-divider"></span>
`
}
export { html }

View File

@ -0,0 +1,512 @@
/*
* @Author: Wang jianLei
* @Date: 2022-05-17 21:49:28
* @Last Modified by: Wang JianLei
* @Last Modified time: 2022-05-19 22:08:14
*/
let ViewShed = function (sdk, canvasEleId) {
if (!sdk.viewer) throw new Error("no viewer object!");
alert(canvasEleId)
let canvasEle = document.getElementById(canvasEleId);
if (!canvasEle) throw new Error("the canvas element is not exist");
this.canvasEle = canvasEle;
this.viewer = sdk.viewer;
this.handler = undefined;
this.lightCamera;
this.pyramid;
this.frustumPrimitive;
this.viewershedPolygon;
};
ViewShed.prototype = {
/**
* 初始化handler
*/
initHandler() {
if (this.handler) {
this.handler.destroy();
this.handler = undefined;
}
},
/**
* 开始执行视域分析
* @param {number} precision 精度值越大创建耗时越长建议在10~20之间
*/
createViewshed: function (precision) {
let $this = this;
let scene = $this.viewer.scene;
$this.initHandler();
$this.clearAll();
$this.handler = new Cesium.ScreenSpaceEventHandler($this.viewer.canvas);
$this.handler.setInputAction((event) => {
// 禁止地球旋转和缩放,地球的旋转会对鼠标移动监听有影响,所以需要禁止
scene.screenSpaceCameraController.enableRotate = false;
scene.screenSpaceCameraController.enableZoom = false;
scene.globe.depthTestAgainstTerrain = true;
let earthPosition = scene.pickPosition(event.position);
let pos = $this.cartesian3ToDegree(earthPosition);
$this.handler.setInputAction(function (event) {
let newPosition = scene.pickPosition(event.endPosition);
if (Cesium.defined(newPosition)) {
let pos1 = $this.cartesian3ToDegree(newPosition);
let distance = Cesium.Cartesian3.distance(newPosition, earthPosition);
let angle = $this.getAngle(pos[0], pos[1], pos1[0], pos1[1]);
let pitch = $this.getPitch(earthPosition, newPosition);
$this.ViewShedOptions = {
viewPosition: earthPosition, //观测点 笛卡尔坐标
endPosition: newPosition, //目标点 笛卡尔坐标
direction: angle, //观测方位角 默认为`0`,范围`0~360`
pitch: pitch, //俯仰角,radius,默认为`0`
horizontalViewAngle: 90, //可视域水平夹角,默认为 `90`,范围`0~360`
verticalViewAngle: 60, //可视域垂直夹角,默认为`60`,范围`0~180`
visibleAreaColor: Cesium.Color.GREEN, //可视区域颜色,默认为`green`
invisibleAreaColor: Cesium.Color.RED, //不可见区域颜色,默认为`red`
visualRange: distance, //距离,单位`米`
};
$this.updateViewShed();
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
}, Cesium.ScreenSpaceEventType.LEFT_DOWN);
$this.handler.setInputAction(() => {
$this.initHandler();
// 开启地球旋转和缩放
scene.screenSpaceCameraController.enableRotate = true;
scene.screenSpaceCameraController.enableZoom = true;
$this.drawViewershed(precision);
}, Cesium.ScreenSpaceEventType.LEFT_UP);
},
ReturnDistance(pos0, pos1) {
let distance = 0;
let point1cartographic = Cesium.Cartographic.fromCartesian(pos0);
let point2cartographic = Cesium.Cartographic.fromCartesian(pos1);
/**根据经纬度计算出距离**/
let geodesic = new Cesium.EllipsoidGeodesic();
geodesic.setEndPoints(point1cartographic, point2cartographic);
let s = geodesic.surfaceDistance;
return s;
},
getHeight(x, y, objectsToExclude) {
let endCartographic = Cesium.Cartographic.fromDegrees(x, y);
let endHeight = this.viewer.scene.sampleHeight(
endCartographic,
objectsToExclude
);
return endHeight;
},
cartesian3ToDegree: function (Cartesian3) {
let _ellipsoid = this.viewer.scene.globe.ellipsoid;
let _cartographic = _ellipsoid.cartesianToCartographic(Cartesian3);
let _lat = Cesium.Math.toDegrees(_cartographic.latitude);
let _lng = Cesium.Math.toDegrees(_cartographic.longitude);
let _alt = _cartographic.height;
return [_lng, _lat, _alt];
},
getAngle: function (lng1, lat1, lng2, lat2) {
let dRotateAngle = Math.atan2(Math.abs(lng1 - lng2), Math.abs(lat1 - lat2));
if (lng2 >= lng1) {
dRotateAngle = lat2 < lat1 ? Math.PI - dRotateAngle : dRotateAngle;
} else {
dRotateAngle =
lat2 >= lat1 ? 2 * Math.PI - dRotateAngle : Math.PI + dRotateAngle;
}
dRotateAngle = (dRotateAngle * 180) / Math.PI;
return dRotateAngle;
},
getPitch(pointA, pointB) {
let transfrom = Cesium.Transforms.eastNorthUpToFixedFrame(pointA);
const vector = Cesium.Cartesian3.subtract(
pointB,
pointA,
new Cesium.Cartesian3()
);
let direction = Cesium.Matrix4.multiplyByPointAsVector(
Cesium.Matrix4.inverse(transfrom, transfrom),
vector,
vector
);
Cesium.Cartesian3.normalize(direction, direction);
return Cesium.Math.PI_OVER_TWO - Cesium.Math.acosClamped(direction.z);
},
updateViewShed: function () {
this.clear();
this.setLightCamera();
this.addVisualPyramid();
this.createFrustum();
},
clear: function () {
if (this.pyramid) {
this.viewer.entities.removeById(this.pyramid.id);
this.pyramid = undefined;
}
if (this.frustumPrimitive) {
this.viewer.scene.primitives.remove(this.frustumPrimitive);
this.frustumPrimitive = undefined;
}
if (this.debugModelMatrixPrimitive) {
this.viewer.scene.primitives.remove(this.debugModelMatrixPrimitive);
this.debugModelMatrixPrimitive = undefined;
}
},
clearAll: function () {
this.clear();
if (this.viewershedPolygon) {
this.viewer.scene.primitives.remove(this.viewershedPolygon);
this.viewershedPolygon = undefined;
}
},
addVisualPyramid: function () {
let options = this.ViewShedOptions;
let position = options.viewPosition;
let visualRange = Number(options.visualRange);
let transform = Cesium.Transforms.eastNorthUpToFixedFrame(position);
this.debugModelMatrixPrimitive = this.viewer.scene.primitives.add(
new Cesium.DebugModelMatrixPrimitive({
modelMatrix: transform,
length: 5.0,
})
);
const halfClock = options.horizontalViewAngle / 2;
const halfCone = options.verticalViewAngle / 2;
const pitch = Cesium.Math.toDegrees(options.pitch);
const ellipsoid = new Cesium.EllipsoidGraphics({
radii: new Cesium.Cartesian3(visualRange, visualRange, visualRange),
minimumClock: Cesium.Math.toRadians(90 - options.direction - halfClock),
maximumClock: Cesium.Math.toRadians(90 - options.direction + halfClock),
minimumCone: Cesium.Math.toRadians(90 - pitch - halfCone),
maximumCone: Cesium.Math.toRadians(90 - pitch + halfCone),
fill: false,
outline: true,
subdivisions: 256,
stackPartitions: 64,
slicePartitions: 64,
outlineColor: Cesium.Color.YELLOWGREEN.withAlpha(0.5),
});
const pyramidEntity = new Cesium.Entity({
position: position,
ellipsoid,
});
this.pyramid = this.viewer.entities.add(pyramidEntity);
},
setLightCamera: function () {
if (!this.lightCamera) {
this.lightCamera = new Cesium.Camera(this.viewer.scene);
}
let options = this.ViewShedOptions;
let visualRange = Number(options.visualRange);
this.lightCamera.position = options.viewPosition;
this.lightCamera.frustum.near = 0.1;
this.lightCamera.frustum.far = visualRange;
const hr = Cesium.Math.toRadians(options.horizontalViewAngle);
const vr = Cesium.Math.toRadians(options.verticalViewAngle);
this.lightCamera.frustum.aspectRatio =
(visualRange * Math.tan(hr / 2) * 2) /
(visualRange * Math.tan(vr / 2) * 2);
this.lightCamera.frustum.fov = hr > vr ? hr : vr;
this.lightCamera.setView({
destination: options.viewPosition,
orientation: {
heading: Cesium.Math.toRadians(options.direction || 0),
pitch: options.pitch || 0,
roll: 0,
},
});
},
createFrustum: function () {
const scratchRight = new Cesium.Cartesian3();
const scratchRotation = new Cesium.Matrix3();
const scratchOrientation = new Cesium.Quaternion();
const direction = this.lightCamera.directionWC;
const up = this.lightCamera.upWC;
let right = this.lightCamera.rightWC;
right = Cesium.Cartesian3.negate(right, scratchRight);
let rotation = scratchRotation;
Cesium.Matrix3.setColumn(rotation, 0, right, rotation);
Cesium.Matrix3.setColumn(rotation, 1, up, rotation);
Cesium.Matrix3.setColumn(rotation, 2, direction, rotation);
let orientation = Cesium.Quaternion.fromRotationMatrix(
rotation,
scratchOrientation
);
let instanceOutline = new Cesium.GeometryInstance({
geometry: new Cesium.FrustumOutlineGeometry({
frustum: this.lightCamera.frustum,
origin: this.ViewShedOptions.viewPosition,
orientation: orientation,
}),
id: "视椎体轮廓线" + Math.random().toString(36).substr(2),
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
new Cesium.Color(0.0, 1.0, 0.0, 1.0)
),
show: new Cesium.ShowGeometryInstanceAttribute(true),
},
});
this.frustumPrimitive = this.viewer.scene.primitives.add(
new Cesium.Primitive({
geometryInstances: instanceOutline,
appearance: new Cesium.PerInstanceColorAppearance({
flat: true,
translucent: false,
closed: true,
}),
})
);
},
createPoint: function (firstPos, secondPos) {
let entity4FirstPos = new Cesium.Entity({
name: "firstPos",
show: true,
position: firstPos,
point: {
show: true,
pixelSize: 20,
color: Cesium.Color.RED,
outlineColor: Cesium.Color.YELLOW,
outlineWidth: 5,
},
description: `
<p>这是绘制的视椎体起点</p>`,
});
this.viewer.entities.add(entity4FirstPos);
let entity4SecondPos = new Cesium.Entity({
name: "secondPos",
show: true,
position: secondPos,
point: {
show: true,
pixelSize: 30,
color: Cesium.Color.YELLOW,
outlineColor: Cesium.Color.RED,
outlineWidth: 8,
},
description: `
<p>这是绘制的视椎体视角终点</p>`,
});
this.viewer.entities.add(entity4SecondPos);
},
//绘制可视域
add(positionArr) {
let polygon = new Cesium.PolygonGeometry({
polygonHierarchy: new Cesium.PolygonHierarchy(
Cesium.Cartesian3.fromDegreesArray(positionArr)
),
height: 0.0,
extrudedHeight: 0.0,
vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT,
stRotation: 0.0, // 纹理的旋转坐标(以弧度为单位),正旋转是逆时针方向
ellipsoid: Cesium.Ellipsoid.WGS84,
granularity: Cesium.Math.RADIANS_PER_DEGREE, // 每个纬度和经度之间的距离(以弧度为单位),确定缓冲区中的位置数
perPositionHeight: false, // 每个位置点使用的高度
closeTop: true,
closeBottom: true,
// NONE 与椭圆表面不符的直线;GEODESIC 遵循测地路径;RHUMB 遵循大黄蜂或恶魔般的道路。
arcType: Cesium.ArcType.GEODESIC, // 多边形边缘线型
});
let polygonInstance = new Cesium.GeometryInstance({
geometry: polygon,
name: "ViewershedPolygon",
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
Cesium.Color.BLUE.withAlpha(0.6)
),
show: new Cesium.ShowGeometryInstanceAttribute(true), //显示或者隐藏
},
});
this.viewershedPolygon = this.viewer.scene.primitives.add(
new Cesium.GroundPrimitive({
geometryInstances: polygonInstance,
appearance: new Cesium.EllipsoidSurfaceAppearance({
aboveGround: true,
material: new Cesium.Material({
fabric: {
type: "Image",
uniforms: {
image: this.returnImgae(),
},
},
}),
}),
})
);
},
drawViewershed(precision) {
const pos = this.cartesian3ToDegree(this.ViewShedOptions.viewPosition);
const radius = this.ViewShedOptions.visualRange;
const direction = this.ViewShedOptions.direction;
let boundary = this.computeBoundaryOptions(pos, radius, direction);
const bbox = boundary.bbox;
let mask = turf.polygon([boundary.boundaryPoints]);
const dis = this.ViewShedOptions.visualRange / (precision * 1000);
let gridPoints = turf.pointGrid(bbox, dis, { mask: mask });
let pointsResult = this.createTargetPoints(gridPoints, dis, pos);
let variogram = kriging.train(
pointsResult.values,
pointsResult.lngs,
pointsResult.lats,
"exponential",
0,
100
);
let grid = kriging.grid([boundary.boundaryPoints], variogram, dis / 1000);
const colors = [
"#ff000080",
"#ff000080",
"#ff000080",
"#ff000080",
"#ff000080",
"#ff000080",
"#00ff0080",
"#00ff0080",
"#00ff0080",
"#00ff0080",
"#00ff0080",
"#00ff0080",
];
this.canvasEle.width = 3840;
this.canvasEle.height = 2160;
kriging.plot(
this.canvasEle,
grid,
[bbox[0], bbox[2]],
[bbox[1], bbox[3]],
colors
);
this.add(boundary.positionArr);
},
computeBoundaryOptions(pos, radius, angle) {
let Ea = 6378137; // 赤道半径
let Eb = 6356725; // 极半径
const lng = pos[0],
lat = pos[1];
const bbox = [lng, lat, lng, lat]; //[minX, minY, maxX, maxY]
let positionArr = [];
let boundaryPoints = [];
positionArr.push(lng, lat);
boundaryPoints.push([lng, lat]);
//正北是0°
let start = angle + 45 > 360 ? angle - 45 - 360 : angle - 45;
let end = start + 90;
for (let i = start; i <= end; i++) {
let dx = radius * Math.sin((i * Math.PI) / 180.0);
let dy = radius * Math.cos((i * Math.PI) / 180.0);
let ec = Eb + ((Ea - Eb) * (90.0 - lat)) / 90.0;
let ed = ec * Math.cos((lat * Math.PI) / 180);
let BJD = lng + ((dx / ed) * 180.0) / Math.PI;
let BWD = lat + ((dy / ec) * 180.0) / Math.PI;
positionArr.push(BJD, BWD);
boundaryPoints.push([BJD, BWD]);
this.refreshBBox(bbox, BJD, BWD);
}
boundaryPoints.push([lng, lat]);
return {
positionArr,
boundaryPoints,
bbox,
};
},
/**
* 更新外围矩形 Bbox
* @param {Array} result 外围矩形Bbox-[minX, minY, maxX, maxY]
* @param {Number} x 经度
* @param {Number} y 纬度
*/
refreshBBox(result, x, y) {
result[0] = x < result[0] ? x : result[0];
result[1] = y < result[1] ? y : result[1];
result[2] = x > result[2] ? x : result[2];
result[3] = y > result[3] ? y : result[3];
},
/**
* 插值点用射线判断通视性
* @param {*} gridPoints 网格点
* @param {*} step 步长,可以理解成是精度
* @param {*} sourcePos 视域分析起点
* @returns kriging插值所需的参数对象{ values:[], lngs:[], lats:[]}
*/
createTargetPoints(gridPoints, step, sourcePos) {
let positionArr = [];
let objectsToExclude = [
this.frustumPrimitive,
this.pyramid,
this.debugModelMatrixPrimitive,
];
let values = [],
lngs = [],
lats = [];
let height = this.getHeight(sourcePos[0], sourcePos[1], objectsToExclude);
positionArr.push({
x: sourcePos[0],
y: sourcePos[1],
z: height,
});
let viewPoint = this.ViewShedOptions.viewPosition;
for (let index = 0; index < gridPoints.features.length; index++) {
const feature = gridPoints.features[index];
const coords = feature.geometry.coordinates;
const x = coords[0],
y = coords[1];
let h = this.getHeight(x, y, objectsToExclude);
let endPoint = Cesium.Cartesian3.fromDegrees(x, y, h);
let direction = Cesium.Cartesian3.normalize(
Cesium.Cartesian3.subtract(
endPoint,
viewPoint,
new Cesium.Cartesian3()
),
new Cesium.Cartesian3()
);
// 建立射线
let ray = new Cesium.Ray(viewPoint, direction);
let result = this.viewer.scene.pickFromRay(ray, objectsToExclude); // 计算交互点,返回第一个
if (result) {
let buffer = this.ReturnDistance(endPoint, result.position);
// let M_color = Cesium.Color.GREEN;
if (buffer > step) {
// M_color = Cesium.Color.RED;
values.push(0);
} else {
values.push(1);
}
lngs.push(x);
lats.push(y);
// this.viewer.entities.add(
// new Cesium.Entity({
// name: "插值点哦",
// show: true,
// position: endPoint,
// point: {
// show: true,
// pixelSize: 10,
// color: M_color,
// outlineWidth: 2,
// outlineColor: Cesium.Color.YELLOW,
// },
// })
// );
}
}
return {
values,
lngs,
lats,
};
},
/**
* canvas转image图片
* @returns base64图片
*/
returnImgae() {
return this.canvasEle.toDataURL("image/png");
},
};
export default ViewShed;

View File

@ -0,0 +1,131 @@
export default `
#define USE_CUBE_MAP_SHADOW true
uniform sampler2D colorTexture;
uniform sampler2D depthTexture;
varying vec2 v_textureCoordinates;
uniform mat4 camera_projection_matrix;
uniform mat4 camera_view_matrix;
uniform samplerCube shadowMap_textureCube;
uniform mat4 shadowMap_matrix;
uniform vec4 shadowMap_lightPositionEC;
uniform vec4 shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness;
uniform vec4 shadowMap_texelSizeDepthBiasAndNormalShadingSmooth;
uniform float helsing_viewDistance;
uniform vec4 helsing_visibleAreaColor;
uniform vec4 helsing_invisibleAreaColor;
struct zx_shadowParameters
{
vec3 texCoords;
float depthBias;
float depth;
float nDotL;
vec2 texelStepSize;
float normalShadingSmooth;
float darkness;
};
float czm_shadowVisibility(samplerCube shadowMap, zx_shadowParameters shadowParameters)
{
float depthBias = shadowParameters.depthBias;
float depth = shadowParameters.depth;
float nDotL = shadowParameters.nDotL;
float normalShadingSmooth = shadowParameters.normalShadingSmooth;
float darkness = shadowParameters.darkness;
vec3 uvw = shadowParameters.texCoords;
depth -= depthBias;
float visibility = czm_shadowDepthCompare(shadowMap, uvw, depth);
return czm_private_shadowVisibility(visibility, nDotL, normalShadingSmooth, darkness);
}
vec4 getPositionEC(){
return czm_windowToEyeCoordinates(gl_FragCoord);
}
vec3 getNormalEC(){
return vec3(1.);
}
vec4 toEye(in vec2 uv,in float depth){
vec2 xy=vec2((uv.x*2.-1.),(uv.y*2.-1.));
vec4 posInCamera=czm_inverseProjection*vec4(xy,depth,1.);
posInCamera=posInCamera/posInCamera.w;
return posInCamera;
}
vec3 pointProjectOnPlane(in vec3 planeNormal,in vec3 planeOrigin,in vec3 point){
vec3 v01=point-planeOrigin;
float d=dot(planeNormal,v01);
return(point-planeNormal*d);
}
float getDepth(in vec4 depth){
float z_window=czm_unpackDepth(depth);
z_window=czm_reverseLogDepth(z_window);
float n_range=czm_depthRange.near;
float f_range=czm_depthRange.far;
return(2.*z_window-n_range-f_range)/(f_range-n_range);
}
float shadow(in vec4 positionEC){
vec3 normalEC=getNormalEC();
zx_shadowParameters shadowParameters;
shadowParameters.texelStepSize=shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.xy;
shadowParameters.depthBias=shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.z;
shadowParameters.normalShadingSmooth=shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.w;
shadowParameters.darkness=shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness.w;
vec3 directionEC=positionEC.xyz-shadowMap_lightPositionEC.xyz;
float distance=length(directionEC);
directionEC=normalize(directionEC);
float radius=shadowMap_lightPositionEC.w;
if(distance>radius)
{
return 2.0;
}
vec3 directionWC=czm_inverseViewRotation*directionEC;
shadowParameters.depth=distance/radius-0.0003;
shadowParameters.nDotL=clamp(dot(normalEC,-directionEC),0.,1.);
shadowParameters.texCoords=directionWC;
float visibility=czm_shadowVisibility(shadowMap_textureCube,shadowParameters);
return visibility;
}
bool visible(in vec4 result)
{
result.x/=result.w;
result.y/=result.w;
result.z/=result.w;
return result.x>=-1.&&result.x<=1.
&&result.y>=-1.&&result.y<=1.
&&result.z>=-1.&&result.z<=1.;
}
void main(){
// 釉色 = 结构二维(颜色纹理, 纹理坐标)
gl_FragColor = texture2D(colorTexture, v_textureCoordinates);
// 深度 = 获取深度(结构二维(深度纹理, 纹理坐标))
float depth = getDepth(texture2D(depthTexture, v_textureCoordinates));
// 视角 = (纹理坐标, 深度)
vec4 viewPos = toEye(v_textureCoordinates, depth);
// 世界坐标
vec4 wordPos = czm_inverseView * viewPos;
// 虚拟相机中坐标
vec4 vcPos = camera_view_matrix * wordPos;
float near = .001 * helsing_viewDistance;
float dis = length(vcPos.xyz);
if(dis > near && dis < helsing_viewDistance){
// 透视投影
vec4 posInEye = camera_projection_matrix * vcPos;
// 可视区颜色
// vec4 helsing_visibleAreaColor=vec4(0.,1.,0.,.5);
// vec4 helsing_invisibleAreaColor=vec4(1.,0.,0.,.5);
if(visible(posInEye)){
float vis = shadow(viewPos);
if(vis > 0.3){
// gl_FragColor = mix(gl_FragColor,helsing_visibleAreaColor,.5);
} else {
gl_FragColor = mix(gl_FragColor,helsing_invisibleAreaColor,.5);
}
}
}
}`;

View File

@ -0,0 +1,302 @@
// ViewShed.js
import glsl from './glsl'
import Event from "../../../Event";
import MouseTip from "../../../MouseTip";
import Tools from "../../../Tools";
import Controller from "../../../Controller";
import Dialog from '../../../BaseDialog';
import { html } from "./_element";
/**
* @constructor
* @description 圆形可视域分析(--方块)
* @param sdk
* @param {Object} options 选项。
* @param {String} options.visibleAreaColor=#008000 可视区域颜色(默认值`绿色`)。
* @param {String} options.invisibleAreaColor=#FF0000 不可视区域颜色(默认值`红色`)。
*/
class ViewShedStage extends Tools {
constructor(sdk, options = {}, _Dialog = {}) {
super(sdk, options)
this.viewer = sdk.viewer;
this.options = {}
let precision = Math.floor(options.precision)
if (isNaN(precision)) {
this.precision = 40
}
else if (precision < 10) {
this.precision = 10
}
else {
this.precision = precision
}
this.options.visibleAreaColor = options.visibleAreaColor || '#008000';
this.options.invisibleAreaColor = options.invisibleAreaColor || '#FF0000';
this.ids = []
this.primitives = []
this.viewpointPrimitive = null
this.Dialog = _Dialog
this.html = null
YJ.Analysis.Analyses.push(this)
ViewShedStage.create(this)
}
static create(that) {
let count = 0;
if (!YJ.Measure.GetMeasureStatus()) {
let Draw = new YJ.Draw.DrawCircle(that.sdk)
Draw.start((a, options) => {
that.center = options.center
that.radius = options.radius
that.analyse()
})
}
else {
console.log('上一次测量未结束')
}
}
static async edit(that) {
if (that._DialogObject && that._DialogObject.close) {
that._DialogObject.close()
that._DialogObject = null
}
that._DialogObject = await new Dialog(that.sdk.viewer._container, {
title: '可视域分析', left: '180px', top: '100px',
closeCallBack: () => {
that.Dialog.closeCallBack && that.Dialog.closeCallBack()
YJ.Measure.SetMeasureStatus(false)
},
})
await that._DialogObject.init()
that._DialogObject._element.body.className = that._DialogObject._element.body.className + ' view-shed'
let contentElm = document.createElement('div');
contentElm.innerHTML = html()
that._DialogObject.contentAppChild(contentElm)
}
analyse() {
this.destroy()
let center = [this.center.lng, this.center.lat];
let radius = this.radius / 1000;
let circle = turf.circle(center, radius, { steps: 180, units: 'kilometers', properties: { foo: 'bar' } });
let pointPrimitives = null;// 申明点渲染集合
this.viewpointPrimitive = this.viewer.scene.primitives.add(new Cesium.PointPrimitiveCollection());
console.log('circle', circle)
let bbox = turf.bbox(circle);
console.log(bbox)
let bboxPolygon = turf.bboxPolygon(bbox);
console.log(bboxPolygon)
let cellSide = radius / this.precision;
let grid = turf.pointGrid(bbox, cellSide, { units: 'kilometers' });
console.log(grid)
let ptsWithin = turf.pointsWithinPolygon(grid, circle);
console.log('ptsWithin', ptsWithin)
let viewPoint = Cesium.Cartesian3.fromDegrees(this.center.lng, this.center.lat, this.center.alt + 2);
this.viewpointPrimitive.add({
position: viewPoint,
color: Cesium.Color.AQUA.withAlpha(1),
pixelSize: 6
})
let instances = []
let xp = (bbox[2] - bbox[0]) / (this.precision * 4)
let yp = (bbox[3] - bbox[1]) / (this.precision * 4)
let _this = this
let item = 200
let m = 0
let total = ptsWithin.features.length
let intervalEvent = setInterval(() => {
if (m >= ptsWithin.features.length) {
clearInterval(intervalEvent)
return
}
else {
InBatches(m)
m += 200
}
}, 30);
function InBatches(k) {
let instances = []
let length = k + 200
if (length >= ptsWithin.features.length) {
length = ptsWithin.features.length
}
for (let i = k; i < length; i++) {
let positionArr = []
let pt = ptsWithin.features[i].geometry.coordinates;
let cartographic = Cesium.Cartographic.fromDegrees(pt[0], pt[1]);
let height = _this.viewer.scene.globe.getHeight(cartographic)
let pt3d = Cesium.Cartesian3.fromDegrees(pt[0], pt[1], height);
// let position = this.viewer.scene.clampToHeight(pt3d)
let targetPoint = pt3d;
let direction = Cesium.Cartesian3.normalize(
Cesium.Cartesian3.subtract(
targetPoint,
viewPoint,
new Cesium.Cartesian3()
),
new Cesium.Cartesian3()
);
let ray = new Cesium.Ray(viewPoint, direction);
let pickedObjects = _this.viewer.scene.drillPickFromRay(ray);
let result
for (let i = 0; i < pickedObjects.length; i++) {
if (pickedObjects[i].position) {
result = pickedObjects[i]
break
}
}
let color = Cesium.Color.LIME
if (result && Math.abs(result.position.x - pt3d.x) > 0.01 && Math.abs(result.position.y - pt3d.y) > 0.01 && Math.abs(result.position.z - pt3d.z) > 0.01) {
color = Cesium.Color.RED
}
positionArr.push(pt[0] - xp, pt[1] + yp, pt[0] + xp, pt[1] + yp, pt[0] + xp, pt[1] - yp, pt[0] - xp, pt[1] - yp)
let polygon = new Cesium.PolygonGeometry({
polygonHierarchy: new Cesium.PolygonHierarchy(
Cesium.Cartesian3.fromDegreesArray(positionArr)
),
height: 0.0,
extrudedHeight: 0.0,
vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT,
ellipsoid: Cesium.Ellipsoid.WGS84,
granularity: Cesium.Math.RADIANS_PER_DEGREE, // 每个纬度和经度之间的距离(以弧度为单位),确定缓冲区中的位置数
perPositionHeight: false, // 每个位置点使用的高度
closeTop: true,
closeBottom: true,
});
let polygonInstance = new Cesium.GeometryInstance({
geometry: polygon,
name: "ViewershedPolygon",
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
color.withAlpha(0.6)
),
show: new Cesium.ShowGeometryInstanceAttribute(true), //显示或者隐藏
},
});
instances.push(polygonInstance)
}
_this.primitives.push(_this.viewer.scene.primitives.add(
new Cesium.GroundPrimitive({
geometryInstances: instances,
appearance: new Cesium.PerInstanceColorAppearance({
translucent: true, //false时透明度无效
closed: false,
}),
})
));
}
// for (let i = 0; i < ptsWithin.features.length; i++) {
// let positionArr = []
// let pt = ptsWithin.features[i].geometry.coordinates;
// let cartographic = Cesium.Cartographic.fromDegrees(pt[0], pt[1]);
// let height = this.viewer.scene.globe.getHeight(cartographic)
// let pt3d = Cesium.Cartesian3.fromDegrees(pt[0], pt[1], height);
// // let position = this.viewer.scene.clampToHeight(pt3d)
// let targetPoint = pt3d;
// let direction = Cesium.Cartesian3.normalize(
// Cesium.Cartesian3.subtract(
// targetPoint,
// viewPoint,
// new Cesium.Cartesian3()
// ),
// new Cesium.Cartesian3()
// );
// let ray = new Cesium.Ray(viewPoint, direction);
// let pickedObjects = this.viewer.scene.drillPickFromRay(ray);
// let result
// for (let i = 0; i < pickedObjects.length; i++) {
// if (pickedObjects[i].position) {
// result = pickedObjects[i]
// break
// }
// }
// let color = Cesium.Color.LIME
// if (result && Math.abs(result.position.x - pt3d.x) > 1 && Math.abs(result.position.y - pt3d.y) > 1 && Math.abs(result.position.z - pt3d.z) > 1) {
// color = Cesium.Color.RED
// // this.viewer.entities.add({
// // polyline: {
// // positions: [viewPoint, result.position],
// // material: Cesium.Color.GREEN.withAlpha(0.1),
// // // clampToGround: true,
// // width: 1,
// // zIndex: 99999999
// // },
// // });
// // this.viewer.entities.add({
// // polyline: {
// // positions: [result.position, targetPoint],
// // material: Cesium.Color.RED.withAlpha(0.1),
// // // clampToGround: true,
// // width: 1,
// // zIndex: 99999999
// // },
// // });
// // pointPrimitives.add({
// // position: result.position,
// // color: Cesium.Color.AQUA.withAlpha(0.5),
// // pixelSize: 6
// // })
// }
// positionArr.push(pt[0] - xp, pt[1] + yp, pt[0] + xp, pt[1] + yp, pt[0] + xp, pt[1] - yp, pt[0] - xp, pt[1] - yp)
// let polygon = new Cesium.PolygonGeometry({
// polygonHierarchy: new Cesium.PolygonHierarchy(
// Cesium.Cartesian3.fromDegreesArray(positionArr)
// ),
// height: 0.0,
// extrudedHeight: 0.0,
// vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT,
// ellipsoid: Cesium.Ellipsoid.WGS84,
// granularity: Cesium.Math.RADIANS_PER_DEGREE, // 每个纬度和经度之间的距离(以弧度为单位),确定缓冲区中的位置数
// perPositionHeight: false, // 每个位置点使用的高度
// closeTop: true,
// closeBottom: true,
// });
// let polygonInstance = new Cesium.GeometryInstance({
// geometry: polygon,
// name: "ViewershedPolygon",
// attributes: {
// color: Cesium.ColorGeometryInstanceAttribute.fromColor(
// color.withAlpha(0.5)
// ),
// show: new Cesium.ShowGeometryInstanceAttribute(true), //显示或者隐藏
// },
// });
// instances.push(polygonInstance)
// }
// this.viewer.scene.primitives.add(
// new Cesium.GroundPrimitive({
// geometryInstances: instances,
// appearance: new Cesium.PerInstanceColorAppearance({
// translucent: true, //false时透明度无效
// closed: false,
// }),
// })
// );
}
destroy() {
for (let i = 0; i < this.primitives.length; i++) {
this.viewer.scene.primitives.remove(this.primitives[i])
}
this.primitives = []
this.viewpointPrimitive && this.viewer.scene.primitives.remove(this.viewpointPrimitive)
YJ.Measure.SetMeasureStatus(false)
}
}
export default ViewShedStage;

View File

@ -0,0 +1,19 @@
function html() {
return `
<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-1">
<input class="input" type="number" title="" min="0" max="999999" step="0.1" @model="viewPointHeight">
<span class="unit">m</span>
<span class="arrow"></span>
</div>
</div>
</div>
</div>
`
}
export { html }

View File

@ -0,0 +1,355 @@
/*
*通视分析
* @Author: Wang jianLei
* @Date: 2022-04-17 22:04:52
* @Last Modified by: Wang JianLei
* @Last Modified time: 2022-04-17 22:05:13
*/
import Tools from "../../../Tools";
import Event from "../../../Event";
import MouseTip from "../../../MouseTip";
import EventBinding from '../../Element/Dialog/eventBinding';
import Dialog from '../../../BaseDialog';
import { html } from "./_element";
class VisibilityAnalysis extends Tools {
constructor(sdk, options = {}, _Dialog = {}) {
super(sdk, options)
this.viewer = sdk.viewer;
this.resultObject = {
viewPoint: undefined, //通视分析起点
targetPoints: [], //通视分析目标点集合
targetPoint: undefined, //当前目标点
objectExclude: [], //射线排除集合
entities: [], //创建的Entity对象
};
this.options = {}
this._elms = {};
this.viewPointHeight = options.viewPointHeight
this.Dialog = _Dialog
this._EventBinding = new EventBinding()
YJ.Analysis.Analyses.push(this)
VisibilityAnalysis.edit(this)
}
get viewPointHeight() {
return this.options.viewPointHeight
}
set viewPointHeight(v) {
let viewPointHeight = Math.floor(Number(v) * 10) / 10
if (isNaN(viewPointHeight)) {
viewPointHeight = 1.8
}
if (viewPointHeight < 0) {
viewPointHeight = 0
}
this.options.viewPointHeight = viewPointHeight
this._elms.viewPointHeight && this._elms.viewPointHeight.forEach((item) => {
item.value = viewPointHeight
})
}
static create(that) {
if (!YJ.Measure.GetMeasureStatus()) {
if (that._DialogObject && that._DialogObject.close) {
that._DialogObject.close()
that._DialogObject = null
}
that.event = new Event(that.sdk)
that.tip = new MouseTip('左键点击创建视角起点', that.sdk)
YJ.Measure.SetMeasureStatus(true)
let count = 0;
that.event.mouse_left(async (movement, cartesian) => {
that.tip.set_text("左键创建视角终点,右键结束通视分析")
if (!that.resultObject.viewPoint) {
let pos84 = that.cartesian3Towgs84(cartesian, that.viewer)
let positions = await Cesium.sampleTerrainMostDetailed(
that.sdk.viewer.terrainProvider,
[Cesium.Cartographic.fromDegrees(pos84.lng, pos84.lat)]
);
if (positions[0].height > pos84.alt) {
pos84.alt = positions[0].height
}
pos84.alt = pos84.alt + that.viewPointHeight
let pos = Cesium.Cartesian3.fromDegrees(pos84.lng, pos84.lat, pos84.alt)
that.resultObject.viewPoint = pos;
let pointEntity = that.viewer.entities.add({
position: pos,
point: {
color: Cesium.Color.YELLOW,
pixelSize: 5,
},
});
that.resultObject.objectExclude.push(pointEntity);
that.resultObject.entities.push(pointEntity);
} else {
that.resultObject.targetPoint = cartesian;
let pointEntity = that.viewer.entities.add({
position: cartesian,
point: {
color: Cesium.Color.YELLOW,
pixelSize: 5,
},
});
that.resultObject.objectExclude.push(pointEntity);
that.resultObject.entities.push(pointEntity);
let direction = Cesium.Cartesian3.normalize(
Cesium.Cartesian3.subtract(
that.resultObject.targetPoint,
that.resultObject.viewPoint,
new Cesium.Cartesian3()
),
new Cesium.Cartesian3()
);
let ray = new Cesium.Ray(that.resultObject.viewPoint, direction);
let pickedObjects = that.viewer.scene.drillPickFromRay(ray);
let result = {}
for (let i = 0; i < pickedObjects.length; i++) {
if (pickedObjects[i].position) {
result = pickedObjects[i]
break
}
}
// let result = that.viewer.scene.pickFromRay(
// ray,
// that.resultObject.objectExclude
// ); // 计算交互点,返回第一个
if (result) {
let dis0 = VisibilityAnalysis.distance(
that.resultObject.viewPoint,
that.resultObject.targetPoint
);
let dis1 = VisibilityAnalysis.distance(
that.resultObject.viewPoint,
result.position || cartesian
);
let dis2 = VisibilityAnalysis.distance(
result.position || cartesian,
that.resultObject.targetPoint
);
if (dis0 > dis1) {
let _poly0 = that.viewer.entities.add({
polyline: {
positions: [that.resultObject.viewPoint, result.position],
material: Cesium.Color.GREEN,
width: 3,
zIndex: 99999999
},
});
that.resultObject.entities.push(_poly0);
let _poly1 = that.viewer.entities.add({
polyline: {
positions: [result.position, that.resultObject.targetPoint],
material: Cesium.Color.RED,
width: 3,
zIndex: 99999999
},
});
that.resultObject.entities.push(_poly1);
that.resultObject.targetPoints.push({
targetPoint: cartesian,
visual: false, //如果dis2足够小其实他是可视的
distance: [dis0, dis1, dis2], //[初始点和终点,初始点和交点,交点和终点]
});
} else {
let _poly2 = that.viewer.entities.add({
polyline: {
positions: [
that.resultObject.viewPoint,
that.resultObject.targetPoint,
],
material: Cesium.Color.GREEN,
width: 3,
zIndex: 99999999
},
});
that.resultObject.entities.push(_poly2);
that.resultObject.targetPoints.push({
targetPoint: cartesian,
visual: true, //如果dis2足够小其实他是可视的
distance: [dis0, dis1, dis2], //[初始点和终点,初始点和交点,交点和终点]
});
}
}
}
})
that.event.mouse_move((movement, cartesian) => {
that.tip.setPosition(cartesian, movement.endPosition.x, movement.endPosition.y)
})
that.event.mouse_right((movement, cartesian) => {
end()
})
that.event.gesture_pinck_start((movement, cartesian) => {
let startTime = new Date()
that.event.gesture_pinck_end(() => {
let endTime = new Date()
if (endTime - startTime >= 500) {
end()
}
})
})
}
else {
console.log('上一次测量未结束')
}
function end() {
YJ.Measure.SetMeasureStatus(false)
that.tip.destroy()
that.event.destroy()
that.tip = null
that.event = null
}
}
// static update(that) {
// if (!that.resultObject.viewPoint) {
// return
// }
// for (let i = that.resultObject.entities.length - 1; i >= 0; i--) {
// if (that.resultObject.entities[i].point) {
// that.viewer.entities.remove(that.resultObject.entities[i]);
// that.resultObject.entities.splice(i, 1)
// }
// }
// setTimeout(() => {
// for (let i = 0; i < that.resultObject.targetPoints.length; i++) {
// that.resultObject.targetPoint = that.resultObject.targetPoints[i].targetPoint;
// let direction = Cesium.Cartesian3.normalize(
// Cesium.Cartesian3.subtract(
// that.resultObject.targetPoint,
// that.resultObject.viewPoint,
// new Cesium.Cartesian3()
// ),
// new Cesium.Cartesian3()
// );
// let ray = new Cesium.Ray(that.resultObject.viewPoint, direction);
// let pickedObjects = that.viewer.scene.drillPickFromRay(ray);
// let result = {}
// for (let i = 0; i < pickedObjects.length; i++) {
// if (pickedObjects[i].position) {
// result = pickedObjects[i]
// break
// }
// }
// // let result = that.viewer.scene.pickFromRay(
// // ray,
// // that.resultObject.objectExclude
// // ); // 计算交互点,返回第一个
// if (result) {
// let dis0 = VisibilityAnalysis.distance(
// that.resultObject.viewPoint,
// that.resultObject.targetPoint
// );
// let dis1 = VisibilityAnalysis.distance(
// that.resultObject.viewPoint,
// result.position || cartesian
// );
// let dis2 = VisibilityAnalysis.distance(
// result.position || cartesian,
// that.resultObject.targetPoint
// );
// if (dis0 > dis1) {
// let _poly0 = that.viewer.entities.add({
// polyline: {
// positions: [that.resultObject.viewPoint, result.position],
// material: Cesium.Color.GREEN,
// width: 3,
// zIndex: 99999999
// },
// });
// that.resultObject.entities.push(_poly0);
// let _poly1 = that.viewer.entities.add({
// polyline: {
// positions: [result.position, that.resultObject.targetPoint],
// material: Cesium.Color.RED,
// width: 3,
// zIndex: 99999999
// },
// });
// that.resultObject.entities.push(_poly1);
// } else {
// let _poly2 = that.viewer.entities.add({
// polyline: {
// positions: [
// that.resultObject.viewPoint,
// that.resultObject.targetPoint,
// ],
// material: Cesium.Color.GREEN,
// width: 3,
// zIndex: 99999999
// },
// });
// that.resultObject.entities.push(_poly2);
// }
// }
// }
// }, 1000);
// }
static async edit(that) {
if (that._DialogObject && that._DialogObject.close) {
that._DialogObject.close()
that._DialogObject = null
}
that._DialogObject = await new Dialog(that.sdk.viewer._container, {
title: '多点视线分析', left: '180px', top: '100px',
closeCallBack: () => {
that.Dialog.closeCallBack && that.Dialog.closeCallBack()
YJ.Measure.SetMeasureStatus(false)
},
})
await that._DialogObject.init()
that._DialogObject._element.body.className = that._DialogObject._element.body.className + ' visibility'
let contentElm = document.createElement('div');
contentElm.innerHTML = html()
that._DialogObject.contentAppChild(contentElm)
let drawElm = document.createElement('button')
drawElm.innerHTML = '绘制'
drawElm.addEventListener('click', () => {
VisibilityAnalysis.create(that)
})
that._DialogObject.footAppChild(drawElm)
let all_elm = contentElm.getElementsByTagName("*")
that._EventBinding.on(that, all_elm)
that._elms = that._EventBinding.element
}
//空间两点间距离
static distance(point1, point2) {
let point1cartographic = Cesium.Cartographic.fromCartesian(point1);
let point2cartographic = Cesium.Cartographic.fromCartesian(point2);
/**根据经纬度计算出距离**/
let geodesic = new Cesium.EllipsoidGeodesic();
geodesic.setEndPoints(point1cartographic, point2cartographic);
let s = geodesic.surfaceDistance;
//返回两点之间的距离
s = Math.sqrt(
Math.pow(s, 2) +
Math.pow(point2cartographic.height - point1cartographic.height, 2)
);
return s;
}
destroy() {
this.resultObject.entities.forEach((element) => {
this.viewer.entities.remove(element);
});
this.resultObject = {
viewPoint: undefined, //通视分析起点
targetPoints: [], //通视分析目标点集合
targetPoint: undefined, //当前目标点
objectExclude: [], //射线排除集合
entities: [], //创建的Entity对象
};
this.tip && this.tip.destroy()
this.event && this.event.destroy()
this.tip = null
this.event = null
YJ.Measure.SetMeasureStatus(false)
}
}
export default VisibilityAnalysis;

View File

@ -0,0 +1,8 @@
function Clear() {
YJ.Analysis.Analyses.forEach(m => {
m.destroy()
})
// YJ.Analysis.Analyses = []
}
export {Clear}

Some files were not shown because too many files have changed in this diff Show More