代码迁移
This commit is contained in:
89
src/Obj/AirLine/DrawTakeOff.js
Normal file
89
src/Obj/AirLine/DrawTakeOff.js
Normal 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
|
||||
112
src/Obj/AirLine/GenerateRoute.js
Normal file
112
src/Obj/AirLine/GenerateRoute.js
Normal 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
|
||||
272
src/Obj/AirLine/billord_point_line.js
Normal file
272
src/Obj/AirLine/billord_point_line.js
Normal 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
673
src/Obj/AirLine/frustum.js
Normal 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
257
src/Obj/AirLine/frustum2.js
Normal 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
290
src/Obj/AirLine/index.js
Normal 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类型!')
|
||||
}
|
||||
}
|
||||
}
|
||||
359
src/Obj/AirLine/pointRoute.js
Normal file
359
src/Obj/AirLine/pointRoute.js
Normal 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
|
||||
*/
|
||||
// 新增航点 (before,after,end)
|
||||
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
|
||||
}
|
||||
}
|
||||
25
src/Obj/Analysis/CircleViewShed/_element.js
Normal file
25
src/Obj/Analysis/CircleViewShed/_element.js
Normal 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 }
|
||||
512
src/Obj/Analysis/CircleViewShed/_index.js
Normal file
512
src/Obj/Analysis/CircleViewShed/_index.js
Normal 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;
|
||||
131
src/Obj/Analysis/CircleViewShed/glsl.js
Normal file
131
src/Obj/Analysis/CircleViewShed/glsl.js
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}`;
|
||||
380
src/Obj/Analysis/CircleViewShed/index.js
Normal file
380
src/Obj/Analysis/CircleViewShed/index.js
Normal 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
|
||||
208
src/Obj/Analysis/Contour/index.js
Normal file
208
src/Obj/Analysis/Contour/index.js
Normal 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;
|
||||
125
src/Obj/Analysis/CutFill/CreatePolygon.js
Normal file
125
src/Obj/Analysis/CutFill/CreatePolygon.js
Normal 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;
|
||||
75
src/Obj/Analysis/CutFill/_element.js
Normal file
75
src/Obj/Analysis/CutFill/_element.js
Normal 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 }
|
||||
354
src/Obj/Analysis/CutFill/index.js
Normal file
354
src/Obj/Analysis/CutFill/index.js
Normal 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;
|
||||
483
src/Obj/Analysis/Flat/index.js
Normal file
483
src/Obj/Analysis/Flat/index.js
Normal 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;
|
||||
227
src/Obj/Analysis/Flat/index1.js
Normal file
227
src/Obj/Analysis/Flat/index1.js
Normal 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;
|
||||
8
src/Obj/Analysis/Profile/_element.js
Normal file
8
src/Obj/Analysis/Profile/_element.js
Normal file
@ -0,0 +1,8 @@
|
||||
function html() {
|
||||
return `
|
||||
<span class="custom-divider"></span>
|
||||
<div class="profile-echarts"></div>
|
||||
`
|
||||
}
|
||||
|
||||
export { html }
|
||||
637
src/Obj/Analysis/Profile/index.js
Normal file
637
src/Obj/Analysis/Profile/index.js
Normal 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;
|
||||
145
src/Obj/Analysis/Section/index.js
Normal file
145
src/Obj/Analysis/Section/index.js
Normal 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;
|
||||
517
src/Obj/Analysis/SlopeAspect/index.js
Normal file
517
src/Obj/Analysis/SlopeAspect/index.js
Normal 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;
|
||||
92
src/Obj/Analysis/Submerge/_element.js
Normal file
92
src/Obj/Analysis/Submerge/_element.js
Normal 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 }
|
||||
484
src/Obj/Analysis/Submerge/index.js
Normal file
484
src/Obj/Analysis/Submerge/index.js
Normal 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
|
||||
32
src/Obj/Analysis/TerrainExcavation/_element.js
Normal file
32
src/Obj/Analysis/TerrainExcavation/_element.js
Normal 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 }
|
||||
459
src/Obj/Analysis/TerrainExcavation/index.js
Normal file
459
src/Obj/Analysis/TerrainExcavation/index.js
Normal 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;
|
||||
54
src/Obj/Analysis/ViewShed/_element.js
Normal file
54
src/Obj/Analysis/ViewShed/_element.js
Normal 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 }
|
||||
511
src/Obj/Analysis/ViewShed/_index.js
Normal file
511
src/Obj/Analysis/ViewShed/_index.js
Normal 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;
|
||||
131
src/Obj/Analysis/ViewShed/glsl.js
Normal file
131
src/Obj/Analysis/ViewShed/glsl.js
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}`;
|
||||
131
src/Obj/Analysis/ViewShed/glsl2.js
Normal file
131
src/Obj/Analysis/ViewShed/glsl2.js
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}`;
|
||||
773
src/Obj/Analysis/ViewShed/index.js
Normal file
773
src/Obj/Analysis/ViewShed/index.js
Normal 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;
|
||||
74
src/Obj/Analysis/ViewShed2/_element.js
Normal file
74
src/Obj/Analysis/ViewShed2/_element.js
Normal 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 }
|
||||
512
src/Obj/Analysis/ViewShed2/_index.js
Normal file
512
src/Obj/Analysis/ViewShed2/_index.js
Normal 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;
|
||||
131
src/Obj/Analysis/ViewShed2/glsl.js
Normal file
131
src/Obj/Analysis/ViewShed2/glsl.js
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}`;
|
||||
721
src/Obj/Analysis/ViewShed2/index.js
Normal file
721
src/Obj/Analysis/ViewShed2/index.js
Normal 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;
|
||||
74
src/Obj/Analysis/ViewShed3/_element.js
Normal file
74
src/Obj/Analysis/ViewShed3/_element.js
Normal 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 }
|
||||
512
src/Obj/Analysis/ViewShed3/_index.js
Normal file
512
src/Obj/Analysis/ViewShed3/_index.js
Normal 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;
|
||||
131
src/Obj/Analysis/ViewShed3/glsl.js
Normal file
131
src/Obj/Analysis/ViewShed3/glsl.js
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}`;
|
||||
302
src/Obj/Analysis/ViewShed3/index.js
Normal file
302
src/Obj/Analysis/ViewShed3/index.js
Normal 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;
|
||||
19
src/Obj/Analysis/Visibility/_element.js
Normal file
19
src/Obj/Analysis/Visibility/_element.js
Normal 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 }
|
||||
355
src/Obj/Analysis/Visibility/index.js
Normal file
355
src/Obj/Analysis/Visibility/index.js
Normal 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;
|
||||
8
src/Obj/Analysis/clear.js
Normal file
8
src/Obj/Analysis/clear.js
Normal file
@ -0,0 +1,8 @@
|
||||
function Clear() {
|
||||
YJ.Analysis.Analyses.forEach(m => {
|
||||
m.destroy()
|
||||
})
|
||||
// YJ.Analysis.Analyses = []
|
||||
}
|
||||
|
||||
export {Clear}
|
||||
74
src/Obj/Analysis/test/_element.js
Normal file
74
src/Obj/Analysis/test/_element.js
Normal 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 }
|
||||
511
src/Obj/Analysis/test/_index.js
Normal file
511
src/Obj/Analysis/test/_index.js
Normal 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;
|
||||
72
src/Obj/Analysis/test/glsl.js
Normal file
72
src/Obj/Analysis/test/glsl.js
Normal file
@ -0,0 +1,72 @@
|
||||
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 vec4 helsing_visibleAreaColor;
|
||||
uniform vec4 helsing_invisibleAreaColor;
|
||||
uniform sampler2D helsing_texture;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 positionEC = toEye(v_textureCoordinates, depth);
|
||||
// 世界坐标
|
||||
vec4 wordPos = czm_inverseView * positionEC;
|
||||
// 虚拟相机中坐标
|
||||
vec4 vcPos = camera_view_matrix * wordPos;
|
||||
vec4 videoColor = texture2D(helsing_texture, v_textureCoordinates);
|
||||
float dis = length(vcPos.xyz);
|
||||
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)){
|
||||
vec4 out_FragColor = helsing_visibleAreaColor;
|
||||
gl_FragColor = mix(gl_FragColor,videoColor,1.0);
|
||||
}
|
||||
}`;
|
||||
787
src/Obj/Analysis/test/index.js
Normal file
787
src/Obj/Analysis/test/index.js
Normal file
@ -0,0 +1,787 @@
|
||||
// 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 Test 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)
|
||||
Test.create(this)
|
||||
// Test.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(Test.create_point(that, cartesian))
|
||||
that.tip.set_text("左键选择最远观测点位置,右键取消")
|
||||
}
|
||||
count++
|
||||
if (count === 2) {
|
||||
that.options.viewPositionEnd = that.cartesian3Towgs84(cartesian, that.viewer)
|
||||
that.ids.push(Test.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) {
|
||||
Test.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 video = document.getElementsByTagName('video')[0];
|
||||
const img = document.getElementById('img')[0];
|
||||
const that = this;
|
||||
if (video /*&& !video.paused*/) {
|
||||
this.activeVideoListener || (this.activeVideoListener = function () {
|
||||
that.texture && that.texture.destroy();
|
||||
that.texture = new Cesium.Texture({
|
||||
context: that.viewer.scene.context,
|
||||
source: video
|
||||
});
|
||||
});
|
||||
that.viewer.clock.onTick.addEventListener(this.activeVideoListener);
|
||||
}
|
||||
const fs = glsl
|
||||
const postStage = new Cesium.PostProcessStage({
|
||||
vertexShaderText: `
|
||||
attribute vec3 position3DHigh;
|
||||
attribute vec3 position3DLow;
|
||||
attribute vec3 normal;
|
||||
attribute vec2 st;
|
||||
attribute float batchId;
|
||||
|
||||
uniform mat3 rotation;
|
||||
uniform vec3 scale;
|
||||
uniform vec3 translation;
|
||||
uniform mat4 modelViewProjection;
|
||||
|
||||
varying vec2 v_st;
|
||||
|
||||
void main() {
|
||||
v_st = st;
|
||||
vec3 positionHigh = position3DHigh + normal * scale;
|
||||
vec3 positionLow = position3DLow + normal * scale;
|
||||
vec4 positionWC = vec4(positionHigh + (positionLow + translation) / 65536.0, 1.0);
|
||||
gl_Position = modelViewProjection * positionWC;
|
||||
}
|
||||
`,
|
||||
fragmentShader: `
|
||||
precision highp float;
|
||||
varying vec2 v_st;
|
||||
uniform sampler2D colorTexture;
|
||||
|
||||
void main() {
|
||||
vec2 stripeMultiplier = vec2(1.0, 1.0);
|
||||
// 水平贴合效果
|
||||
stripeMultiplier.y *= abs(fract(v_st.y * 100.0) - 0.5) * 2.0;
|
||||
gl_FragColor = texture2D(colorTexture, v_st * stripeMultiplier);
|
||||
}
|
||||
`
|
||||
,
|
||||
uniforms: {
|
||||
helsing_texture: function () {
|
||||
return that.texture;
|
||||
},
|
||||
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_texture: () => {
|
||||
this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState"));
|
||||
return Reflect.get(this.shadowMap, "_shadowMapTexture");
|
||||
},
|
||||
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_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),
|
||||
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)
|
||||
}
|
||||
});
|
||||
console.log('this.lightCamera.frustum', this.lightCamera.frustum)
|
||||
let frustum = this.lightCamera.frustum.clone()
|
||||
// frustum.near = frustum.far-1
|
||||
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.withAlpha(0.1)//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
|
||||
})
|
||||
})
|
||||
);
|
||||
this.FrustumBottomSurface = this.viewer.scene.primitives.add(
|
||||
new Cesium.Primitive({
|
||||
geometryInstances: [instance2],
|
||||
appearance: new Cesium.PerInstanceColorAppearance({
|
||||
flat: false,
|
||||
translucent: true
|
||||
})
|
||||
})
|
||||
);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
console.log('positionArr', 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.FrustumBottomSurface = this.viewer.scene.primitives.add(
|
||||
// new Cesium.GroundPrimitive({
|
||||
// geometryInstances: polygonInstance,
|
||||
// appearance: new Cesium.PerInstanceColorAppearance({
|
||||
// flat: false,
|
||||
// translucent: false
|
||||
// })
|
||||
// })
|
||||
// );
|
||||
// this.FrustumBottomSurface.shadows = 1
|
||||
// console.log(Cesium.GeometryPipeline.toWireframe(polygon))
|
||||
// var model = this.viewer.scene.primitives.add(new Cesium.Model({
|
||||
// // 通过GeometryPipeline.toWireframeGeometry将多边形转换为线框模型
|
||||
// geometry: Cesium.GeometryPipeline.toWireframe(polygon),
|
||||
// // 设置一个简单的材质
|
||||
// material: Cesium.Material.fromType('Color')
|
||||
// }));
|
||||
}
|
||||
|
||||
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 Test;
|
||||
117
src/Obj/Analysis/test2/TestMaterialProperty.js
Normal file
117
src/Obj/Analysis/test2/TestMaterialProperty.js
Normal file
@ -0,0 +1,117 @@
|
||||
/**
|
||||
* @description 测试
|
||||
*/
|
||||
import MaterialProperty from "../../Materail/MaterialProperty";
|
||||
|
||||
|
||||
|
||||
class TestMaterialProperty extends MaterialProperty {
|
||||
constructor(options = {}) {
|
||||
super(options);
|
||||
/**
|
||||
* 定义Cesium材质对象
|
||||
*/
|
||||
Cesium.Material.TestMaterialPropertyType = "TestMaterialProperty";
|
||||
Cesium.Material._materialCache.addMaterial(
|
||||
Cesium.Material.TestMaterialPropertyType,
|
||||
{
|
||||
fabric: {
|
||||
type: Cesium.Material.TestMaterialPropertyType,
|
||||
uniforms: {
|
||||
color: new Cesium.Color(1.0, 0.0, 0.0, 0.1),
|
||||
image: Cesium.Material.DefaultImageId,
|
||||
tmask: Cesium.Material.DefaultImageId,
|
||||
speed: 1,
|
||||
repeat: new Cesium.Cartesian2(1, 1),
|
||||
rotate: 0
|
||||
},
|
||||
source: `uniform sampler2D image;
|
||||
uniform float speed;
|
||||
uniform vec4 color;
|
||||
uniform vec2 repeat;
|
||||
|
||||
czm_material czm_getMaterial(czm_materialInput materialInput){
|
||||
czm_material material=czm_getDefaultMaterial(materialInput);
|
||||
mat2 rotationMatrix = mat2(cos(radians(-rotate)), sin(radians(-rotate)), -sin(radians(-rotate)), cos(radians(-rotate)));
|
||||
vec2 st=repeat*materialInput.st*rotationMatrix;
|
||||
float time=fract(czm_frameNumber);
|
||||
vec4 colorImage = texture2D(image,vec2(fract(st.s-time),st.t));
|
||||
vec4 maskImage = texture2D(tmask, vec2(st.s, st.t));
|
||||
material.alpha=colorImage.a*maskImage.r;
|
||||
material.diffuse=colorImage.rgb;
|
||||
return material;
|
||||
}`,
|
||||
},
|
||||
isTranslucent: function () {
|
||||
return true;
|
||||
},
|
||||
}
|
||||
);
|
||||
// Object.defineProperties(PolylineImageTrailMaterialProperty.prototype, {
|
||||
// color: Cesium.createPropertyDescriptor("color"),
|
||||
// speed: Cesium.createPropertyDescriptor("speed"),
|
||||
// image: Cesium.createPropertyDescriptor("image"),
|
||||
// repeat: Cesium.createPropertyDescriptor("repeat"),
|
||||
// });
|
||||
this._image = undefined;
|
||||
this._tmask = undefined;
|
||||
this._imageSubscription = undefined;
|
||||
this._repeat = undefined;
|
||||
this._repeatSubscription = undefined;
|
||||
this.image = options.image;
|
||||
this.tmask = options.tmask;
|
||||
this.repeat = new Cesium.Cartesian2(
|
||||
options.repeat?.x || 1,
|
||||
options.repeat?.y || 1
|
||||
);
|
||||
this.rotate = options.rotate
|
||||
let i=1
|
||||
// setInterval(() => {
|
||||
// this.repeat = new Cesium.Cartesian2(
|
||||
// i++,
|
||||
// options.repeat?.y || 1
|
||||
// );
|
||||
// console.log(this.repeat)
|
||||
// }, 1000);
|
||||
// setInterval(() => {
|
||||
// this.rotate ++
|
||||
// }, 100);
|
||||
}
|
||||
|
||||
getType() {
|
||||
return Cesium.Material.TestMaterialPropertyType;
|
||||
}
|
||||
|
||||
getValue(time, result) {
|
||||
if (!result) {
|
||||
result = {};
|
||||
}
|
||||
|
||||
|
||||
result.color = this.color;
|
||||
result.image = this.image;
|
||||
result.tmask = this.tmask;
|
||||
result.repeat = this.repeat;
|
||||
result.speed = this.speed;
|
||||
result.rotate = this.rotate
|
||||
// console.log(result.repeat)
|
||||
return result;
|
||||
}
|
||||
|
||||
equals(other) {
|
||||
return (
|
||||
this === other ||
|
||||
(other instanceof TestMaterialProperty &&
|
||||
Cesium.Property.equals(this.color, other._color) &&
|
||||
Cesium.Property.equals(this.image, other._image) &&
|
||||
Cesium.Property.equals(this.tmask, other._tmask) &&
|
||||
Cesium.Property.equals(this.repeat, other._repeat) &&
|
||||
Cesium.Property.equals(this.speed, other._speed) &&
|
||||
Cesium.Property.equals(this.rotate, other._rotate))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
export default TestMaterialProperty;
|
||||
78
src/Obj/Analysis/test2/_element.js
Normal file
78
src/Obj/Analysis/test2/_element.js
Normal file
@ -0,0 +1,78 @@
|
||||
import { attributeElm, labelStyleElm1, labelStyleElm2 } from '../../Element/elm_html'
|
||||
|
||||
function html(that) {
|
||||
return `
|
||||
<span class="custom-divider"></span>
|
||||
<div class="div-item">
|
||||
<div class="row" style="align-items: flex-start;">
|
||||
<div class="col">
|
||||
<span class="label">名称</span>
|
||||
<input class="input" maxlength="40" type="text" @model="name">
|
||||
</div>
|
||||
<div class="col" style="flex: 0 0 60%;">
|
||||
<div class="row">
|
||||
<div class="col input-select-unit-box">
|
||||
<span class="label" style="margin-right: 0px;">占地面积:</span>
|
||||
<input class="input input-text" readonly="readonly" type="text" @model="area">
|
||||
<div class="input-select-unit"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="div-item">
|
||||
<div class="row">
|
||||
<DIV-cy-tabs id="polygon-object-edit-tabs">
|
||||
<DIV-cy-tab-pane label="属性信息">
|
||||
${attributeElm(that)}
|
||||
</DIV-cy-tab-pane>
|
||||
<DIV-cy-tab-pane label="面风格">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">面颜色</span>
|
||||
<div class="color"></div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">描边颜色</span>
|
||||
<div class="lineColor"></div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">描边宽度</span>
|
||||
<div class="input-number input-number-unit-2">
|
||||
<input class="input" type="number" title="" min="0" max="99" @model="lineWidth">
|
||||
<span class="unit">px</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">面贴地</span>
|
||||
<input class="btn-switch" type="checkbox" @model="ground">
|
||||
</div>
|
||||
<div class="col" style="flex: 0 0 165px;">
|
||||
<span class="label">面高度</span>
|
||||
<div class="input-number input-number-unit-2">
|
||||
<input class="input height" type="number" title="" min="-999999" max="9999999" style="width: 120px;">
|
||||
<span class="unit">m</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
</div>
|
||||
</div>
|
||||
</DIV-cy-tab-pane>
|
||||
<DIV-cy-tab-pane label="标注风格">
|
||||
${labelStyleElm1()}
|
||||
</DIV-cy-tab-pane>
|
||||
<DIV-cy-tab-pane label="标签风格">
|
||||
${labelStyleElm2()}
|
||||
</DIV-cy-tab-pane>
|
||||
</DIV-cy-tabs>
|
||||
</div>
|
||||
</div>
|
||||
<span class="custom-divider"></span>
|
||||
`
|
||||
}
|
||||
|
||||
export { html }
|
||||
511
src/Obj/Analysis/test2/_index.js
Normal file
511
src/Obj/Analysis/test2/_index.js
Normal 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;
|
||||
72
src/Obj/Analysis/test2/glsl.js
Normal file
72
src/Obj/Analysis/test2/glsl.js
Normal file
@ -0,0 +1,72 @@
|
||||
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 vec4 helsing_visibleAreaColor;
|
||||
uniform vec4 helsing_invisibleAreaColor;
|
||||
uniform sampler2D helsing_texture;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 positionEC = toEye(v_textureCoordinates, depth);
|
||||
// 世界坐标
|
||||
vec4 wordPos = czm_inverseView * positionEC;
|
||||
// 虚拟相机中坐标
|
||||
vec4 vcPos = camera_view_matrix * wordPos;
|
||||
vec4 videoColor = texture2D(helsing_texture, v_textureCoordinates);
|
||||
float dis = length(vcPos.xyz);
|
||||
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)){
|
||||
vec4 out_FragColor = helsing_visibleAreaColor;
|
||||
gl_FragColor = mix(gl_FragColor,videoColor,1.0);
|
||||
}
|
||||
}`;
|
||||
2095
src/Obj/Analysis/test2/index.js
Normal file
2095
src/Obj/Analysis/test2/index.js
Normal file
File diff suppressed because one or more lines are too long
184
src/Obj/Analysis/test2/index2.js
Normal file
184
src/Obj/Analysis/test2/index2.js
Normal file
@ -0,0 +1,184 @@
|
||||
import Base from "../../Base/index";
|
||||
class PolygonObject extends Base {
|
||||
|
||||
constructor(sdk, options = {}, _Dialog = {}) {
|
||||
super(sdk, options);
|
||||
this.create()
|
||||
}
|
||||
|
||||
create() {
|
||||
let fragmentShaderSource = `
|
||||
varying vec3 v_normal;
|
||||
varying vec2 v_uv;
|
||||
uniform vec2 repeat;
|
||||
uniform sampler2D image;
|
||||
uniform vec4 color;
|
||||
uniform sampler2D colorTexture;
|
||||
czm_material czm_getMaterial(czm_materialInput materialInput)
|
||||
{
|
||||
czm_material material = czm_getDefaultMaterial(materialInput);
|
||||
material.diffuse = czm_gammaCorrect(texture2D(image, fract(repeat * materialInput.st)).rgb * color.rgb);
|
||||
material.alpha = texture2D(image, fract(repeat * materialInput.st)).a * color.a;
|
||||
return material;
|
||||
}
|
||||
|
||||
|
||||
varying vec3 v_positionMC;
|
||||
varying vec3 v_positionEC;
|
||||
varying vec2 v_st;
|
||||
void main()
|
||||
{
|
||||
czm_materialInput materialInput;
|
||||
vec3 normalEC = normalize(czm_normal3D * czm_geodeticSurfaceNormal(v_positionMC, vec3(0.0), vec3(1.0)));
|
||||
#ifdef FACE_FORWARD
|
||||
normalEC = faceforward(normalEC, vec3(0.0, 0.0, 1.0), -normalEC);
|
||||
#endif
|
||||
materialInput.s = v_st.s;
|
||||
materialInput.st = v_st;
|
||||
materialInput.str = vec3(v_st, 0.0);
|
||||
materialInput.normalEC = normalEC;
|
||||
materialInput.tangentToEyeMatrix = czm_eastNorthUpToEyeCoordinates(v_positionMC, materialInput.normalEC);
|
||||
vec3 positionToEyeEC = -v_positionEC;
|
||||
materialInput.positionToEyeEC = positionToEyeEC;
|
||||
czm_material material = czm_getMaterial(materialInput);
|
||||
#ifdef FLAT
|
||||
gl_FragColor = vec4(material.diffuse + material.emission, material.alpha);
|
||||
#else
|
||||
gl_FragColor = czm_phong(normalize(positionToEyeEC), material, czm_lightDirectionEC);
|
||||
#endif
|
||||
}
|
||||
|
||||
`
|
||||
|
||||
const vertexShaderSource = `
|
||||
// attribute vec3 position;
|
||||
// attribute vec3 normal;
|
||||
// varying vec3 v_normal;
|
||||
// attribute vec2 uv;
|
||||
// varying vec2 v_uv;
|
||||
// void main()
|
||||
// {
|
||||
// gl_Position = czm_modelViewProjection * vec4(position, 1.);
|
||||
// v_normal = normal;
|
||||
// v_uv = uv;
|
||||
// }
|
||||
attribute vec3 position3DHigh;
|
||||
attribute vec3 position3DLow;
|
||||
attribute vec2 st;
|
||||
attribute float batchId;
|
||||
varying vec3 v_positionMC;
|
||||
varying vec3 v_positionEC;
|
||||
varying vec2 v_st;
|
||||
attribute vec3 position;
|
||||
void main()
|
||||
{
|
||||
vec4 p = vec4(position, 1.);
|
||||
v_positionMC = position3DHigh + position3DLow;
|
||||
v_positionEC = (czm_modelViewRelativeToEye * p).xyz;
|
||||
v_st = st;
|
||||
gl_Position = czm_modelViewProjectionRelativeToEye * p;
|
||||
}
|
||||
|
||||
`
|
||||
|
||||
class ly_primitive {
|
||||
|
||||
constructor(options) {
|
||||
this.drawCommand = undefined
|
||||
|
||||
if (Cesium.defined(options)) {
|
||||
this.modelMatrix = options.modelMatrix
|
||||
this.geometry = options.geometry
|
||||
console.log('this.geometry', this.geometry)
|
||||
}
|
||||
}
|
||||
|
||||
createCommand(context) {
|
||||
let t = performance.now()
|
||||
if (!Cesium.defined(this.geometry)) return
|
||||
const geometry = Cesium.BoxGeometry.createGeometry(this.geometry)
|
||||
this.vertexarray = Cesium.VertexArray.fromGeometry({
|
||||
context: context,
|
||||
geometry: geometry
|
||||
})
|
||||
const renderstate = Cesium.RenderState.fromCache({
|
||||
depthTest: {
|
||||
enabled: true
|
||||
}
|
||||
// blending: {
|
||||
// enabled: true
|
||||
// }
|
||||
// cull: {
|
||||
// enabled: false,
|
||||
// }
|
||||
})
|
||||
const shaderProgram = Cesium.ShaderProgram.fromCache({
|
||||
context: context,
|
||||
vertexShaderSource: vertexShaderSource,
|
||||
fragmentShaderSource: fragmentShaderSource
|
||||
})
|
||||
const that = this
|
||||
const videoElm = document.getElementsByTagName('video')[0];
|
||||
let texture = new Cesium.Texture({
|
||||
context: context,
|
||||
source: videoElm
|
||||
})
|
||||
const uniformmap = {
|
||||
colorTexture: function() {
|
||||
texture.copyFrom({
|
||||
source: videoElm
|
||||
})
|
||||
return texture
|
||||
},
|
||||
iTime: function() {
|
||||
return (performance.now() - t) / 1000
|
||||
}
|
||||
}
|
||||
|
||||
this.drawCommand = new Cesium.DrawCommand({
|
||||
boundingVolume: this.geometry.boundingSphere,
|
||||
modelMatrix: this.modelMatrix,
|
||||
// pass: Cesium.Pass.OPAQUE,
|
||||
pass: Cesium.Pass.TRANSLUCENT,
|
||||
shaderProgram: shaderProgram,
|
||||
renderState: renderstate,
|
||||
vertexArray: this.vertexarray,
|
||||
uniformMap: uniformmap
|
||||
})
|
||||
}
|
||||
|
||||
update(frameState) {
|
||||
if (!this.drawCommand) {
|
||||
this.createCommand(frameState.context)
|
||||
}
|
||||
frameState.commandList.push(this.drawCommand)
|
||||
}
|
||||
}
|
||||
|
||||
let positions = this.options.positions
|
||||
let fromDegreesArray = []
|
||||
for (let i = 0; i < positions.length; i++) {
|
||||
fromDegreesArray.push(positions[i].lng, positions[i].lat)
|
||||
}
|
||||
|
||||
const video = document.getElementsByTagName('video')[0];
|
||||
|
||||
let polygon = new Cesium.PolygonGeometry({
|
||||
polygonHierarchy: new Cesium.PolygonHierarchy(
|
||||
Cesium.Cartesian3.fromDegreesArray(fromDegreesArray)
|
||||
),
|
||||
height: 100
|
||||
});
|
||||
|
||||
const options = {
|
||||
modelMatrix: Cesium.Matrix4.IDENTITY,
|
||||
geometry: Cesium.PolygonGeometry.createGeometry(polygon)
|
||||
}
|
||||
|
||||
this.sdk.viewer.scene.primitives.add(
|
||||
new ly_primitive(options)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default PolygonObject
|
||||
93
src/Obj/Base/AssembleObject/_element.js
Normal file
93
src/Obj/Base/AssembleObject/_element.js
Normal file
@ -0,0 +1,93 @@
|
||||
import { attributeElm, labelStyleElm1, labelStyleElm2 } from '../../Element/elm_html'
|
||||
|
||||
function html(that) {
|
||||
return `
|
||||
<span class="custom-divider"></span>
|
||||
<div class="div-item">
|
||||
<div class="row" style="align-items: flex-start;">
|
||||
<div class="col">
|
||||
<span class="label">名称</span>
|
||||
<input class="input" maxlength="40" type="text" @model="name">
|
||||
</div>
|
||||
<div class="col" style="flex: 0 0 60%;">
|
||||
<div class="row">
|
||||
<div class="col input-select-unit-box">
|
||||
<span class="label" style="margin-right: 0px;">投影面积:</span>
|
||||
<input class="input input-text" readonly="readonly" type="text" @model="area">
|
||||
<div class="input-select-unit"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="div-item">
|
||||
<div class="row">
|
||||
<DIV-cy-tabs id="assemble-object-edit-tabs">
|
||||
<DIV-cy-tab-pane label="属性信息">
|
||||
${attributeElm(that)}
|
||||
</DIV-cy-tab-pane>
|
||||
<DIV-cy-tab-pane label="空间信息">
|
||||
<div class="row">
|
||||
<div class="col height-mode-box">
|
||||
<span class="label" style="flex: 0 0 56px;">高度模式</span>
|
||||
<div class="height-mode"></div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">Z值统一增加</span>
|
||||
<div class="input-number input-number-unit-1 height-box">
|
||||
<input class="input height" type="number" title="" min="-9999999" max="999999999">
|
||||
<span class="unit">m</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
<button class="confirm height-confirm" style="margin-left: 5px;">确认</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="table spatial-info-table">
|
||||
<div class="table-head">
|
||||
<div class="tr">
|
||||
<div class="th"></div>
|
||||
<div class="th">经度(X)</div>
|
||||
<div class="th">纬度(Y)</div>
|
||||
<div class="th">高度(Z)</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-body">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DIV-cy-tab-pane>
|
||||
<DIV-cy-tab-pane label="面风格">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">面颜色</span>
|
||||
<div class="color"></div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">边线颜色</span>
|
||||
<div class="lineColor"></div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">边线宽度</span>
|
||||
<div class="input-number input-number-unit-2" style="width: 80px;">
|
||||
<input class="input" type="number" title="" min="0" max="99" @model="lineWidth">
|
||||
<span class="unit">px</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DIV-cy-tab-pane>
|
||||
<DIV-cy-tab-pane label="标注风格">
|
||||
${labelStyleElm1()}
|
||||
</DIV-cy-tab-pane>
|
||||
<DIV-cy-tab-pane label="标签风格">
|
||||
${labelStyleElm2()}
|
||||
</DIV-cy-tab-pane>
|
||||
</DIV-cy-tabs>
|
||||
</div>
|
||||
</div>
|
||||
<span class="custom-divider"></span>
|
||||
`
|
||||
}
|
||||
|
||||
export { html }
|
||||
2380
src/Obj/Base/AssembleObject/index.js
Normal file
2380
src/Obj/Base/AssembleObject/index.js
Normal file
File diff suppressed because it is too large
Load Diff
115
src/Obj/Base/AttackArrowObject/_element.js
Normal file
115
src/Obj/Base/AttackArrowObject/_element.js
Normal file
@ -0,0 +1,115 @@
|
||||
import { attributeElm, labelStyleElm1, labelStyleElm2 } from '../../Element/elm_html'
|
||||
|
||||
function html(that) {
|
||||
return `
|
||||
<span class="custom-divider"></span>
|
||||
<div class="div-item">
|
||||
<div class="row" style="align-items: flex-start;">
|
||||
<div class="col">
|
||||
<span class="label" style="flex: 0 0 56px;">名称</span>
|
||||
<input class="input" maxlength="40" type="text" @model="name">
|
||||
</div>
|
||||
<div class="col" style="flex: 0 0 60%;">
|
||||
<div class="row">
|
||||
<div class="col input-select-unit-box">
|
||||
<span class="label" style="margin-right: 0px;">投影面积:</span>
|
||||
<input class="input input-text" readonly="readonly" type="text" @model="area">
|
||||
<div class="input-select-unit"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">动画时长</span>
|
||||
<div class="input-number input-number-unit-3">
|
||||
<input class="input blur" type="number" title="" min="500" max="9999999" @model="spreadTime">
|
||||
<span class="unit">ms</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col" style="flex: 0 0 60%;">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">动画</span>
|
||||
<input class="btn-switch" type="checkbox" @model="spreadState">
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">动画重复</span>
|
||||
<input class="btn-switch" type="checkbox" @model="loop">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="div-item">
|
||||
<div class="row">
|
||||
<DIV-cy-tabs id="attack-arrow-object-edit-tabs">
|
||||
<DIV-cy-tab-pane label="属性信息">
|
||||
${attributeElm(that)}
|
||||
</DIV-cy-tab-pane>
|
||||
<DIV-cy-tab-pane label="空间信息">
|
||||
<div class="row">
|
||||
<div class="col height-mode-box">
|
||||
<span class="label" style="flex: 0 0 56px;">高度模式</span>
|
||||
<div class="height-mode"></div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">Z值统一增加</span>
|
||||
<div class="input-number input-number-unit-1 height-box">
|
||||
<input class="input height" type="number" title="" min="-9999999" max="999999999">
|
||||
<span class="unit">m</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
<button class="confirm height-confirm" style="margin-left: 5px;">确认</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="table spatial-info-table">
|
||||
<div class="table-head">
|
||||
<div class="tr">
|
||||
<div class="th"></div>
|
||||
<div class="th">经度(X)</div>
|
||||
<div class="th">纬度(Y)</div>
|
||||
<div class="th">高度(Z)</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-body">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DIV-cy-tab-pane>
|
||||
<DIV-cy-tab-pane label="面风格">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">面颜色</span>
|
||||
<div class="color"></div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">边线颜色</span>
|
||||
<div class="lineColor"></div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">边线宽度</span>
|
||||
<div class="input-number input-number-unit-2" style="width: 80px;">
|
||||
<input class="input" type="number" title="" min="0" max="99" @model="lineWidth">
|
||||
<span class="unit">px</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DIV-cy-tab-pane>
|
||||
<DIV-cy-tab-pane label="标注风格">
|
||||
${labelStyleElm1()}
|
||||
</DIV-cy-tab-pane>
|
||||
<DIV-cy-tab-pane label="标签风格">
|
||||
${labelStyleElm2()}
|
||||
</DIV-cy-tab-pane>
|
||||
</DIV-cy-tabs>
|
||||
</div>
|
||||
</div>
|
||||
<span class="custom-divider"></span>
|
||||
`
|
||||
}
|
||||
|
||||
export { html }
|
||||
2647
src/Obj/Base/AttackArrowObject/index.js
Normal file
2647
src/Obj/Base/AttackArrowObject/index.js
Normal file
File diff suppressed because it is too large
Load Diff
73
src/Obj/Base/BaseSource/BaseLayer/ArcgisImagery/index.js
Normal file
73
src/Obj/Base/BaseSource/BaseLayer/ArcgisImagery/index.js
Normal file
@ -0,0 +1,73 @@
|
||||
/**
|
||||
* @name: index
|
||||
* @author: Administrator
|
||||
* @date: 2023-11-20 19:00
|
||||
* @description:index
|
||||
* @update: 2023-11-20 19:00
|
||||
*/
|
||||
|
||||
import BaseLayer from "../index";
|
||||
import { setSplitDirection, setActiveId } from '../../../../../Global/SplitScreen'
|
||||
|
||||
class ArcgisLayer extends BaseLayer {
|
||||
constructor(sdk, options = {}) {
|
||||
super(sdk, options);
|
||||
}
|
||||
|
||||
get type() {
|
||||
return "layer"
|
||||
}
|
||||
|
||||
async createArcGis(url) {
|
||||
let imageryProvider
|
||||
if (Number(Cesium.VERSION.split('.')[1]) >= 107) {
|
||||
imageryProvider = await Cesium.ArcGisMapServerImageryProvider.fromUrl(url);
|
||||
}
|
||||
else {
|
||||
imageryProvider = new Cesium.ArcGisMapServerImageryProvider({
|
||||
url
|
||||
});
|
||||
}
|
||||
if (this.options.hasOwnProperty("layer_index")) {
|
||||
this.entity = this.sdk.viewer.imageryLayers.addImageryProvider(imageryProvider, this.options.layer_index)
|
||||
} else {
|
||||
this.entity = this.sdk.viewer.imageryLayers.addImageryProvider(imageryProvider,)
|
||||
}
|
||||
for (let i = 0; i < this.sdk.viewer.imageryLayers._layers.length; i++) {
|
||||
if (this.sdk.viewer.imageryLayers._layers[i]._imageryProvider && this.sdk.viewer.imageryLayers._layers[i]._imageryProvider._type && (this.sdk.viewer.imageryLayers._layers[i]._imageryProvider._type === 'flw' || this.sdk.viewer.imageryLayers._layers[i]._imageryProvider._type === 'jww')) {
|
||||
let layer = this.sdk.viewer.imageryLayers._layers[i]
|
||||
this.sdk.viewer.imageryLayers.raiseToTop(layer)
|
||||
}
|
||||
}
|
||||
this.show = this.options.show
|
||||
this.alpha = this.options.alpha
|
||||
this.brightness = this.options.brightness
|
||||
|
||||
if(this.options.show) {
|
||||
setSplitDirection(0, this.options.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ArcgisWXImagery extends ArcgisLayer {
|
||||
constructor(sdk, options) {
|
||||
super(sdk, options);
|
||||
this.createArcGis("https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer")
|
||||
}
|
||||
}
|
||||
|
||||
class ArcgisBLUEImagery extends ArcgisLayer {
|
||||
constructor(sdk, options) {
|
||||
super(sdk, options);
|
||||
this.createArcGis("https://map.geoq.cn/arcgis/rest/services/ChinaOnlineStreetPurplishBlue/MapServer")
|
||||
}
|
||||
}
|
||||
|
||||
class ArcgisLWImagery extends ArcgisLayer {
|
||||
constructor(sdk, options) {
|
||||
super(sdk, options);
|
||||
this.createArcGis("https://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer")
|
||||
}
|
||||
}
|
||||
|
||||
export {ArcgisWXImagery, ArcgisBLUEImagery, ArcgisLWImagery}
|
||||
71
src/Obj/Base/BaseSource/BaseLayer/GdImagery/index.js
Normal file
71
src/Obj/Base/BaseSource/BaseLayer/GdImagery/index.js
Normal file
@ -0,0 +1,71 @@
|
||||
import BaseLayer from "../index";
|
||||
import { setSplitDirection, setActiveId } from '../../../../../Global/SplitScreen'
|
||||
|
||||
/**
|
||||
* @name: index
|
||||
* @author: Administrator
|
||||
* @date: 2023-11-20 19:18
|
||||
* @description:index
|
||||
* @update: 2023-11-20 19:18
|
||||
*/
|
||||
class GdImagery extends BaseLayer {
|
||||
constructor(sdk, options = {}) {
|
||||
super(sdk, options);
|
||||
}
|
||||
|
||||
get type() {
|
||||
return "layer"
|
||||
}
|
||||
|
||||
createGD(url) {
|
||||
let gdLayer = new Cesium.UrlTemplateImageryProvider({
|
||||
url,
|
||||
minimumLevel: 3,
|
||||
maximumLevel: 18,
|
||||
tilingScheme: this.amapMercatorTilingScheme()
|
||||
})
|
||||
|
||||
if (this.options.hasOwnProperty("layer_index")) {
|
||||
this.entity = this.sdk.viewer.imageryLayers.addImageryProvider(gdLayer, this.options.layer_index)
|
||||
} else {
|
||||
this.entity = this.sdk.viewer.imageryLayers.addImageryProvider(gdLayer,)
|
||||
}
|
||||
for (let i = 0; i < this.sdk.viewer.imageryLayers._layers.length; i++) {
|
||||
if (this.sdk.viewer.imageryLayers._layers[i]._imageryProvider && this.sdk.viewer.imageryLayers._layers[i]._imageryProvider._type && (this.sdk.viewer.imageryLayers._layers[i]._imageryProvider._type === 'flw' || this.sdk.viewer.imageryLayers._layers[i]._imageryProvider._type === 'jww')) {
|
||||
let layer = this.sdk.viewer.imageryLayers._layers[i]
|
||||
this.sdk.viewer.imageryLayers.raiseToTop(layer)
|
||||
}
|
||||
}
|
||||
this.show = this.options.show
|
||||
this.alpha = this.options.alpha
|
||||
this.brightness = this.options.brightness
|
||||
|
||||
if(this.options.show) {
|
||||
|
||||
setSplitDirection(0, this.options.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class GDLWImagery extends GdImagery {
|
||||
constructor(earth, options = {}) {
|
||||
super(earth, options);
|
||||
this.createGD("https://webst02.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scale=1&style=8")
|
||||
}
|
||||
}
|
||||
|
||||
class GDWXImagery extends GdImagery {
|
||||
constructor(earth, options = {}) {
|
||||
super(earth, options);
|
||||
this.createGD("https://webst02.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}")
|
||||
}
|
||||
}
|
||||
|
||||
class GDSLImagery extends GdImagery {
|
||||
constructor(earth, options = {}) {
|
||||
super(earth, options);
|
||||
this.createGD("https://webrd02.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}")
|
||||
}
|
||||
}
|
||||
|
||||
export {GDLWImagery, GDWXImagery, GDSLImagery}
|
||||
146
src/Obj/Base/BaseSource/BaseLayer/Layer/index.js
Normal file
146
src/Obj/Base/BaseSource/BaseLayer/Layer/index.js
Normal file
@ -0,0 +1,146 @@
|
||||
/**
|
||||
* @name: index
|
||||
* @author: Administrator
|
||||
* @date: 2023-11-20 15:51
|
||||
* @description:index
|
||||
* @update: 2023-11-20 15:51
|
||||
*/
|
||||
import { getHost } from "../../../../../on";
|
||||
import { syncData } from '../../../../../Global/MultiViewportMode'
|
||||
import BaseLayer from "../index";
|
||||
import { setSplitDirection, setActiveId } from '../../../../../Global/SplitScreen'
|
||||
|
||||
|
||||
class Layer extends BaseLayer {
|
||||
constructor(sdk, options = {}) {
|
||||
super(sdk, options)
|
||||
this.object = {}
|
||||
this.options.host = this.options.host || getHost()
|
||||
|
||||
}
|
||||
|
||||
get type() {
|
||||
return "layer"
|
||||
}
|
||||
|
||||
on() {
|
||||
return this.add()
|
||||
}
|
||||
|
||||
|
||||
async add() {
|
||||
let res = await this.requestResource()
|
||||
let text = await res.text()
|
||||
text = JSON.parse(text)
|
||||
if ([0, 200].includes(text.code)) {
|
||||
return this.loadLayer(text.data)
|
||||
} else {
|
||||
return new Promise((res, reject) => {
|
||||
reject(text.msg || text.message)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async loadLayer(data) {
|
||||
this.object = { ...data }
|
||||
let url = ""
|
||||
if (this.object.url.startsWith("http"))
|
||||
url = this.object.url
|
||||
else {
|
||||
if (this.options.host) {
|
||||
let o = new URL(this.object.url, this.options.host)
|
||||
url = o.href
|
||||
} else
|
||||
url = this.object.url
|
||||
}
|
||||
let params = {
|
||||
url: url,
|
||||
mimmumLevel: this.object.minimumLevel,
|
||||
maximumLevel: this.object.maximumLevel,
|
||||
rectangle: new Cesium.Rectangle(
|
||||
Cesium.Math.toRadians(this.object.west),
|
||||
Cesium.Math.toRadians(this.object.south),
|
||||
Cesium.Math.toRadians(this.object.east),
|
||||
Cesium.Math.toRadians(this.object.north)
|
||||
),
|
||||
}
|
||||
// if (this.object.scheme_name === "GeographicTilingScheme") {
|
||||
// console.log("添加GeographicTilingScheme")
|
||||
// params.tilingScheme = new Cesium.GeographicTilingScheme()
|
||||
// }
|
||||
// if (this.object.scheme_name === "amapMercatorTilingScheme") {
|
||||
// console.log("添加amapMercatorTilingScheme")
|
||||
// params.tilingScheme = this.amapMercatorTilingScheme()
|
||||
// }
|
||||
|
||||
let layer
|
||||
// if (this.object.tiletrans === 'tms') {
|
||||
// params.url = params.url.substr(0, params.url.indexOf('{'))
|
||||
// tms = new Cesium.TileMapServiceImageryProvider(params)
|
||||
// } else {
|
||||
// tms = new Cesium.UrlTemplateImageryProvider(params)
|
||||
// }
|
||||
switch (this.object.scheme_name) {
|
||||
case "amapMercatorTilingScheme":
|
||||
params.tilingScheme = this.amapMercatorTilingScheme()
|
||||
break;
|
||||
case "":
|
||||
break;
|
||||
default:
|
||||
params.tilingScheme = new Cesium[this.object.scheme_name]()
|
||||
break;
|
||||
}
|
||||
switch (this.object.load_method) {
|
||||
case "tms":
|
||||
if(this.object.url.endsWith("tilemapresource.xml")){
|
||||
let arr = this.object.url.split("/")
|
||||
arr.pop()
|
||||
let url = arr.join("/")
|
||||
params.url = url
|
||||
}
|
||||
if (Number(Cesium.VERSION.split('.')[1]) >= 107) {
|
||||
layer = await Cesium.TileMapServiceImageryProvider.fromUrl(params.url, params);
|
||||
}
|
||||
else {
|
||||
layer = new Cesium.TileMapServiceImageryProvider(params)
|
||||
}
|
||||
break;
|
||||
case "xyz":
|
||||
layer = new Cesium.UrlTemplateImageryProvider(params)
|
||||
break;
|
||||
case "wmts":
|
||||
layer = new Cesium.WebMapTileServiceImageryProvider(params)
|
||||
break;
|
||||
default:
|
||||
layer = new Cesium.UrlTemplateImageryProvider(params)
|
||||
break;
|
||||
}
|
||||
|
||||
if(!this.sdk || !this.sdk.viewer) {
|
||||
return
|
||||
}
|
||||
if (this.options.hasOwnProperty("layer_index")) {
|
||||
this.entity =
|
||||
this.sdk.viewer.scene.imageryLayers.addImageryProvider(layer, this.options.layer_index)
|
||||
} else {
|
||||
this.entity =
|
||||
this.sdk.viewer.scene.imageryLayers.addImageryProvider(layer,)
|
||||
}
|
||||
for (let i = 0; i < this.sdk.viewer.imageryLayers._layers.length; i++) {
|
||||
if (this.sdk.viewer.imageryLayers._layers[i]._imageryProvider && this.sdk.viewer.imageryLayers._layers[i]._imageryProvider._type && (this.sdk.viewer.imageryLayers._layers[i]._imageryProvider._type === 'flw' || this.sdk.viewer.imageryLayers._layers[i]._imageryProvider._type === 'jww')) {
|
||||
let layer = this.sdk.viewer.imageryLayers._layers[i]
|
||||
this.sdk.viewer.imageryLayers.raiseToTop(layer)
|
||||
}
|
||||
}
|
||||
this.show = this.options.show
|
||||
this.alpha = this.options.alpha
|
||||
this.brightness = this.options.brightness
|
||||
|
||||
if(this.options.show) {
|
||||
setSplitDirection(0, this.options.id)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Layer
|
||||
57
src/Obj/Base/BaseSource/BaseLayer/Layer3rdparty/index.js
vendored
Normal file
57
src/Obj/Base/BaseSource/BaseLayer/Layer3rdparty/index.js
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
/**
|
||||
* @name: index
|
||||
* @author: Administrator
|
||||
* @date: 2023-11-20 15:51
|
||||
* @description:index
|
||||
* @update: 2023-11-20 15:51
|
||||
*/
|
||||
import BaseLayer from "../index";
|
||||
import { setSplitDirection, setActiveId } from '../../../../../Global/SplitScreen'
|
||||
|
||||
|
||||
class Layer3rdparty extends BaseLayer {
|
||||
constructor(sdk, options = {}) {
|
||||
super(sdk, options)
|
||||
this.loadLayer()
|
||||
}
|
||||
|
||||
get type() {
|
||||
return "layer"
|
||||
}
|
||||
|
||||
loadLayer(data) {
|
||||
let params = {
|
||||
url: this.options.url,
|
||||
mimmumLevel: this.options.minimumLevel || 0,
|
||||
maximumLevel: this.options.maximumLevel || 20,
|
||||
subdomains: ['0','1','2','3','4','5','6','7'],
|
||||
}
|
||||
|
||||
let layer
|
||||
|
||||
layer = new Cesium.UrlTemplateImageryProvider(params)
|
||||
if (this.options.hasOwnProperty("layer_index")) {
|
||||
this.entity =
|
||||
this.sdk.viewer.scene.imageryLayers.addImageryProvider(layer, this.options.layer_index)
|
||||
} else {
|
||||
this.entity =
|
||||
this.sdk.viewer.scene.imageryLayers.addImageryProvider(layer,)
|
||||
}
|
||||
for (let i = 0; i < this.sdk.viewer.imageryLayers._layers.length; i++) {
|
||||
if (this.sdk.viewer.imageryLayers._layers[i]._imageryProvider && this.sdk.viewer.imageryLayers._layers[i]._imageryProvider._type && (this.sdk.viewer.imageryLayers._layers[i]._imageryProvider._type === 'flw' || this.sdk.viewer.imageryLayers._layers[i]._imageryProvider._type === 'jww')) {
|
||||
let layer = this.sdk.viewer.imageryLayers._layers[i]
|
||||
this.sdk.viewer.imageryLayers.raiseToTop(layer)
|
||||
}
|
||||
}
|
||||
this.show = this.options.show
|
||||
this.alpha = this.options.alpha
|
||||
this.brightness = this.options.brightness
|
||||
|
||||
if(this.options.show) {
|
||||
setSplitDirection(0, this.options.id)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Layer3rdparty
|
||||
311
src/Obj/Base/BaseSource/BaseLayer/index.js
Normal file
311
src/Obj/Base/BaseSource/BaseLayer/index.js
Normal file
@ -0,0 +1,311 @@
|
||||
/**
|
||||
* @name: index
|
||||
* @author: Administrator
|
||||
* @date: 2023-11-20 18:06
|
||||
* @description:index
|
||||
* @update: 2023-11-20 18:06
|
||||
*/
|
||||
|
||||
import Dialog from '../../../Element/Dialog';
|
||||
import CoordTransform from "../../../../transform/CoordTransform";
|
||||
import BaseSource from "../index";
|
||||
import { syncData } from '../../../../Global/MultiViewportMode'
|
||||
import { setSplitDirection, syncSplitData } from '../../../../Global/SplitScreen'
|
||||
import { setActiveViewer, closeRotateAround, closeViewFollow } from '../../../../Global/global'
|
||||
|
||||
class BaseLayer extends BaseSource {
|
||||
constructor(sdk, options, _Dialog = {}) {
|
||||
super(sdk, options);
|
||||
this.options.name = options.name || '未命名对象'
|
||||
this.Dialog = _Dialog
|
||||
this._elms = {};
|
||||
}
|
||||
|
||||
setDefaultValue() {
|
||||
super.setDefaultValue();
|
||||
this.options.alpha = this.options.alpha ?? 1
|
||||
this.options.brightness = this.options.brightness ?? 1
|
||||
}
|
||||
|
||||
get layerIndex() {
|
||||
return this.entity._layerIndex
|
||||
}
|
||||
|
||||
get layer_index() {
|
||||
return this.entity._layerIndex
|
||||
}
|
||||
|
||||
get brightness() {
|
||||
return this.options.brightness
|
||||
}
|
||||
|
||||
set brightness(v) {
|
||||
this.options.brightness = v
|
||||
this.entity.brightness = v
|
||||
}
|
||||
|
||||
get alpha() {
|
||||
return this.options.alpha
|
||||
}
|
||||
|
||||
|
||||
set alpha(v) {
|
||||
if (Number(v) > 1) v = 1
|
||||
if (Number(v) < 0) v = 0
|
||||
this.entity.alpha = v
|
||||
this.options.alpha = v
|
||||
this._elms.alpha && this._elms.alpha.forEach((item) => {
|
||||
item.value = v
|
||||
})
|
||||
}
|
||||
|
||||
/**@description 提高图层的一层层级
|
||||
* @method layerRaise
|
||||
* @param id {string} 图层id
|
||||
*@memberOf Layer
|
||||
* */
|
||||
layerRaise(id) {
|
||||
this.sdk.viewer.imageryLayers.raise(this.entity)
|
||||
for (let i = 0; i < this.sdk.viewer.imageryLayers._layers.length; i++) {
|
||||
if (this.sdk.viewer.imageryLayers._layers[i]._imageryProvider && this.sdk.viewer.imageryLayers._layers[i]._imageryProvider._type && (this.sdk.viewer.imageryLayers._layers[i]._imageryProvider._type === 'flw' || this.sdk.viewer.imageryLayers._layers[i]._imageryProvider._type === 'jww')) {
|
||||
let layer = this.sdk.viewer.imageryLayers._layers[i]
|
||||
this.sdk.viewer.imageryLayers.raiseToTop(layer)
|
||||
}
|
||||
}
|
||||
this.options.layer_index = this.entity._layerIndex
|
||||
return this.entity._layerIndex
|
||||
}
|
||||
|
||||
/**@description 降低图层的一层层级
|
||||
* @method layerLower
|
||||
* @memberOf Layer
|
||||
|
||||
* */
|
||||
layerLower() {
|
||||
this.sdk.viewer.imageryLayers.lower(this.entity)
|
||||
this.options.layer_index = this.entity._layerIndex
|
||||
return this.entity._layerIndex
|
||||
}
|
||||
|
||||
/**@description 置顶
|
||||
* @method layerToTop
|
||||
* @memberOf Layer
|
||||
|
||||
* */
|
||||
layerToTop() {
|
||||
this.sdk.viewer.imageryLayers.raiseToTop(this.entity)
|
||||
for (let i = 0; i < this.sdk.viewer.imageryLayers._layers.length; i++) {
|
||||
if (this.sdk.viewer.imageryLayers._layers[i]._imageryProvider && this.sdk.viewer.imageryLayers._layers[i]._imageryProvider._type && (this.sdk.viewer.imageryLayers._layers[i]._imageryProvider._type === 'flw' || this.sdk.viewer.imageryLayers._layers[i]._imageryProvider._type === 'jww')) {
|
||||
let layer = this.sdk.viewer.imageryLayers._layers[i]
|
||||
this.sdk.viewer.imageryLayers.raiseToTop(layer)
|
||||
}
|
||||
}
|
||||
this.options.layer_index = this.entity._layerIndex
|
||||
return this.entity._layerIndex
|
||||
}
|
||||
|
||||
/**@description 置底
|
||||
* @method lowerToBottom
|
||||
* @memberOf Layer
|
||||
|
||||
* */
|
||||
layerToBottom() {
|
||||
this.sdk.viewer.imageryLayers.lowerToBottom(this.entity)
|
||||
this.options.layer_index = this.entity._layerIndex
|
||||
return this.entity._layerIndex
|
||||
}
|
||||
|
||||
remove() {
|
||||
super.remove()
|
||||
this.sdk.viewer.scene.imageryLayers.remove(this.entity)
|
||||
this.entity = null
|
||||
}
|
||||
|
||||
/**@description 定位
|
||||
* @method flyTo
|
||||
* @memberOf Layer
|
||||
|
||||
* */
|
||||
async flyTo(options = {}) {
|
||||
if (this._error) {
|
||||
return
|
||||
}
|
||||
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.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 {
|
||||
this.sdk.viewer.flyTo(this.entity)
|
||||
}
|
||||
}
|
||||
|
||||
/*高德的纠偏*/
|
||||
amapMercatorTilingScheme(options) {
|
||||
class AmapMercatorTilingScheme extends Cesium.WebMercatorTilingScheme {
|
||||
constructor(options) {
|
||||
super(options)
|
||||
let projection = new Cesium.WebMercatorProjection()
|
||||
this._projection.project = function (cartographic, result) {
|
||||
result = CoordTransform.WGS84ToGCJ02(
|
||||
Cesium.Math.toDegrees(cartographic.longitude),
|
||||
Cesium.Math.toDegrees(cartographic.latitude)
|
||||
)
|
||||
result = projection.project(
|
||||
new Cesium.Cartographic(
|
||||
Cesium.Math.toRadians(result[0]),
|
||||
Cesium.Math.toRadians(result[1])
|
||||
)
|
||||
)
|
||||
return new Cesium.Cartesian2(result.x, result.y)
|
||||
}
|
||||
this._projection.unproject = function (cartesian, result) {
|
||||
let cartographic = projection.unproject(cartesian)
|
||||
result = CoordTransform.GCJ02ToWGS84(
|
||||
Cesium.Math.toDegrees(cartographic.longitude),
|
||||
Cesium.Math.toDegrees(cartographic.latitude)
|
||||
)
|
||||
return new Cesium.Cartographic(
|
||||
Cesium.Math.toRadians(result[0]),
|
||||
Cesium.Math.toRadians(result[1])
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new AmapMercatorTilingScheme(options)
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 编辑框
|
||||
* @param state=false {boolean} 状态: true打开, false关闭
|
||||
*/
|
||||
async edit(state = false) {
|
||||
this.originalOptions = this.deepCopyObj(this.options)
|
||||
if (this._DialogObject && this._DialogObject.close) {
|
||||
this._DialogObject.close()
|
||||
this._DialogObject = null
|
||||
}
|
||||
this._DialogObject = await new Dialog(this.sdk, this.options, {
|
||||
title: '底图属性', left: '180px', top: '100px',
|
||||
confirmCallBack: (options) => {
|
||||
this.name = this.name.trim()
|
||||
if (!this.name) {
|
||||
this.name = '未命名对象'
|
||||
}
|
||||
this.originalOptions = this.deepCopyObj(this.options)
|
||||
this._DialogObject.close()
|
||||
this.Dialog.confirmCallBack && this.Dialog.confirmCallBack(this.originalOptions)
|
||||
syncData(this.sdk, this.options.id)
|
||||
syncSplitData(this.sdk, this.options.id)
|
||||
},
|
||||
closeCallBack: () => {
|
||||
this.reset()
|
||||
this.Dialog.closeCallBack && this.Dialog.closeCallBack()
|
||||
},
|
||||
// resetCallBack: () => {
|
||||
// this.name = this.originalOptions.name
|
||||
// this.alpha = this.originalOptions.alpha
|
||||
// this.Dialog.resetCallBack && this.Dialog.resetCallBack()
|
||||
// },
|
||||
removeCallBack: () => {
|
||||
this.Dialog.removeCallBack && this.Dialog.removeCallBack()
|
||||
},
|
||||
}, true)
|
||||
let contentElm = document.createElement('div')
|
||||
contentElm.style.width = '300px'
|
||||
let html = `
|
||||
<span class="custom-divider"></span>
|
||||
<div class="div-item">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label" style="flex: 0 0 60px;">名称:</span>
|
||||
<input class="input name" type="text">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label" style="flex: 0 0 60px;">透明度:</span>
|
||||
<input type="range" class="alpha" min="0" max="1" step="0.01">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
contentElm.innerHTML = html
|
||||
let nameElm = contentElm.getElementsByClassName('name')[0]
|
||||
let alphaElm = contentElm.getElementsByClassName('alpha')[0]
|
||||
nameElm.value = this.name
|
||||
alphaElm.value = this.alpha
|
||||
nameElm.addEventListener('input', () => {
|
||||
this.name = nameElm.value
|
||||
})
|
||||
alphaElm.addEventListener('input', () => {
|
||||
this.alpha = alphaElm.value
|
||||
})
|
||||
this._DialogObject.contentAppChild(contentElm)
|
||||
this._elms.name = [nameElm]
|
||||
this._elms.alpha = [alphaElm]
|
||||
}
|
||||
|
||||
reset() {
|
||||
if (!this.entity && !this._DialogObject) {
|
||||
return
|
||||
}
|
||||
this.options = this.deepCopyObj(this.originalOptions)
|
||||
this.name = this.options.name
|
||||
this.alpha = this.options.alpha
|
||||
this.brightness = this.options.brightness
|
||||
}
|
||||
|
||||
flicker() { }
|
||||
}
|
||||
|
||||
export default BaseLayer
|
||||
196
src/Obj/Base/BaseSource/BaseModel/Model/_element.js
Normal file
196
src/Obj/Base/BaseSource/BaseModel/Model/_element.js
Normal file
@ -0,0 +1,196 @@
|
||||
|
||||
import { attributeElm, labelStyleElm1, labelStyleElm2 } from '../../../../Element/elm_html'
|
||||
|
||||
function html(that) {
|
||||
return `
|
||||
<span class="custom-divider"></span>
|
||||
<div class="div-item">
|
||||
<div class="row" style="align-items: flex-start;">
|
||||
<div class="col">
|
||||
<span class="label">名称</span>
|
||||
<input class="input" maxlength="40" type="text" @model="name">
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label" style="flex: 0 0 60px;">颜色</span>
|
||||
<div class="color"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="custom-divider"></span>
|
||||
<div class="div-item">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">经度</span>
|
||||
<input class="input" type="number" title="" min="-180" max="180" @model="lng">
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label" style="flex: 0 0 60px;">最大比例</span>
|
||||
<div class="input-number input-number-unit-1">
|
||||
<input class="input" type="number" title="" min="0.1" max="99999" step="0.1" @model="maximumScale">
|
||||
<span class="unit">倍</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="-90" max="90" @model="lat">
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label" style="flex: 0 0 60px;">最小像素</span>
|
||||
<div class="input-number input-number-unit-1">
|
||||
<input class="input" type="number" title="" min="1" max="99999" @model="minimumPixelSize">
|
||||
<span class="unit">px</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-1">
|
||||
<input class="input" type="number" title="" min="-99999" max="9999999" @model="alt">
|
||||
<span class="unit">m</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">视野缩放</span>
|
||||
<input class="btn-switch" type="checkbox" @model="scaleByDistance">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="div-item">
|
||||
<div class="row">
|
||||
<DIV-cy-tabs id="model-edit-tabs">
|
||||
<DIV-cy-tab-pane label="属性信息">
|
||||
${attributeElm(that)}
|
||||
</DIV-cy-tab-pane>
|
||||
<DIV-cy-tab-pane label="方向信息">
|
||||
<div>
|
||||
<div class="row">
|
||||
<p class="lable-left-line">旋转</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">x 轴</span>
|
||||
<input style="flex: 1;margin-right: 15px;" type="range" max="360" min="0" step="0.01" @model="rotateX">
|
||||
<div class="input-number input-number-unit-1" style="width: auto;">
|
||||
<input style="width: 100px;" type="number" title="" min="0" max="360" @model="rotateX">
|
||||
<span class="unit">°</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">y 轴</span>
|
||||
<input style="flex: 1;margin-right: 15px;" type="range" max="360" min="0" step="0.01" @model="rotateY">
|
||||
<div class="input-number input-number-unit-1" style="width: auto;">
|
||||
<input style="width: 100px;" type="number" title="" min="0" max="360" @model="rotateY">
|
||||
<span class="unit">°</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">z 轴</span>
|
||||
<input style="flex: 1;margin-right: 15px;" type="range" max="360" min="0" step="0.01" @model="rotateZ">
|
||||
<div class="input-number input-number-unit-1" style="width: auto;">
|
||||
<input style="width: 100px;" type="number" title="" min="0" max="360" @model="rotateZ">
|
||||
<span class="unit">°</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="lable-left-line">
|
||||
<span>缩放</span>
|
||||
<div class="checkbox-box">
|
||||
<input type="checkbox">
|
||||
<span>是否等比例缩放</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row no-equal" style="display: none;">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">x 轴</span>
|
||||
<input style="flex: 1;margin-right: 15px;" type="range" max="99999" min="0" step="1" @model="scaleX">
|
||||
<div class="input-number input-number-unit-1" style="width: auto;">
|
||||
<input style="width: 100px;" type="number" title="" min="0" max="99999" @model="scaleX">
|
||||
<span class="unit">倍</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">y 轴</span>
|
||||
<input style="flex: 1;margin-right: 15px;" type="range" max="99999" min="0" step="1" @model="scaleY">
|
||||
<div class="input-number input-number-unit-1" style="width: auto;">
|
||||
<input style="width: 100px;" type="number" title="" min="0" max="99999" @model="scaleY">
|
||||
<span class="unit">倍</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">z 轴</span>
|
||||
<input style="flex: 1;margin-right: 15px;" type="range" max="99999" min="0" step="1" @model="scaleZ">
|
||||
<div class="input-number input-number-unit-1" style="width: auto;">
|
||||
<input style="width: 100px;" type="number" title="" min="0" max="99999" @model="scaleZ">
|
||||
<span class="unit">倍</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row equal" style="display: none;">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">等比例缩放</span>
|
||||
<input style="flex: 1;margin-right: 15px;" type="range" max="99999" min="0" step="1">
|
||||
<div class="input-number input-number-unit-1" style="width: auto;">
|
||||
<input style="width: 100px;" type="number" title="" min="0" max="99999" step="1">
|
||||
<span class="unit">倍</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p class="lable-left-line">高度</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">高度</span>
|
||||
<input style="flex: 1;margin-right: 15px;" type="range" max="999999" min="-99999" step="0.01" @model="alt">
|
||||
<div class="input-number input-number-unit-1" style="width: auto;">
|
||||
<input style="width: 100px;" type="number" title="" min="-99999" max="999999" @model="alt">
|
||||
<span class="unit">m</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</DIV-cy-tab-pane>
|
||||
<DIV-cy-tab-pane label="标注风格">
|
||||
${labelStyleElm1()}
|
||||
</DIV-cy-tab-pane>
|
||||
<DIV-cy-tab-pane label="标签风格">
|
||||
${labelStyleElm2()}
|
||||
</DIV-cy-tab-pane>
|
||||
</DIV-cy-tabs>
|
||||
</div>
|
||||
</div>
|
||||
<span class="custom-divider"></span>
|
||||
`
|
||||
}
|
||||
|
||||
export { html }
|
||||
1689
src/Obj/Base/BaseSource/BaseModel/Model/index.js
Normal file
1689
src/Obj/Base/BaseSource/BaseModel/Model/index.js
Normal file
File diff suppressed because it is too large
Load Diff
123
src/Obj/Base/BaseSource/BaseModel/Model2/_element.js
Normal file
123
src/Obj/Base/BaseSource/BaseModel/Model2/_element.js
Normal file
@ -0,0 +1,123 @@
|
||||
|
||||
import { attributeElm, labelStyleElm1, labelStyleElm2 } from '../../../../Element/elm_html'
|
||||
|
||||
function html(that) {
|
||||
return `
|
||||
<div class="row" style="align-items: flex-start;">
|
||||
<div class="col">
|
||||
<span class="label">名称</span>
|
||||
<input class="input" maxlength="40" type="text" @model="name">
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">颜色</span>
|
||||
<div class="color"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">经度</span>
|
||||
<input class="input" type="number" title="" min="-180" max="180" @model="lng">
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">最大比例</span>
|
||||
<input class="input" type="number" title="" min="0.1" max="99999" step="0.1" @model="maximumScale">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">纬度</span>
|
||||
<input class="input" type="number" title="" min="-90" max="90" @model="lat">
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">最小像素</span>
|
||||
<input class="input" type="number" title="" min="1" max="99999" @model="minimumPixelSize">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">高度</span>
|
||||
<input class="input" type="number" title="" min="-9999999" max="999999999" @model="alt">
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">视野缩放</span>
|
||||
<input class="btn-switch" type="checkbox" @model="scaleByDistance">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<DIV-cy-tabs id="model-edit-tabs">
|
||||
<DIV-cy-tab-pane label="属性信息">
|
||||
${attributeElm(that)}
|
||||
</DIV-cy-tab-pane>
|
||||
<DIV-cy-tab-pane label="方向信息">
|
||||
<div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">x轴</span>
|
||||
<input style="width: 332px;" type="range" max="360" min="0" step="0.01" @model="rotateX">
|
||||
<input style="font-size: 13px;width: 100px;" type="number" title="" min="0" max="360" @model="rotateX">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">y轴</span>
|
||||
<input style="width: 332px;" type="range" max="360" min="0" step="0.01" @model="rotateY">
|
||||
<input style="font-size: 13px;width: 100px;" type="number" title="" min="0" max="360" @model="rotateY">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">z轴</span>
|
||||
<input style="width: 332px;" type="range" max="360" min="0" step="0.01" @model="rotateZ">
|
||||
<input style="font-size: 13px;width: 100px;" type="number" title="" min="0" max="360" @model="rotateZ">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">高度</span>
|
||||
<input style="width: 332px;" type="range" max="999999" min="-99999" step="0.01" @model="alt">
|
||||
<input style="font-size: 13px;width: 100px;" type="number" title="" min="-99999" max="999999" @model="alt">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">缩放</span>
|
||||
<input style="width: 332px;" type="range" max="999" min="0" step="1" @model="scale">
|
||||
<input style="font-size: 13px;width: 100px;" type="number" title="" min="0" max="999" step="1" @model="scale">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DIV-cy-tab-pane>
|
||||
<DIV-cy-tab-pane label="标注风格">
|
||||
${labelStyleElm1()}
|
||||
</DIV-cy-tab-pane>
|
||||
<DIV-cy-tab-pane label="标签风格">
|
||||
${labelStyleElm2()}
|
||||
</DIV-cy-tab-pane>
|
||||
</DIV-cy-tabs>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
function css() {
|
||||
return `
|
||||
.YJ-custom-base-dialog>.content {
|
||||
width: 600px;
|
||||
}
|
||||
.YJ-custom-base-dialog>.content>div>.row .col {
|
||||
margin: 0 10px;
|
||||
}
|
||||
.YJ-custom-base-dialog>.content>div>.row .col:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
.YJ-custom-base-dialog>.content>div>.row .col:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
.YJ-custom-base-dialog>.content>div>.row .label {
|
||||
flex: 0 0 74px;
|
||||
}
|
||||
.YJ-custom-base-dialog>.content .DIV-cy-tab-content-pane .input-select {
|
||||
width: 100px;
|
||||
}
|
||||
`
|
||||
}
|
||||
|
||||
export { html, css }
|
||||
1349
src/Obj/Base/BaseSource/BaseModel/Model2/index.js
Normal file
1349
src/Obj/Base/BaseSource/BaseModel/Model2/index.js
Normal file
File diff suppressed because it is too large
Load Diff
74
src/Obj/Base/BaseSource/BaseModel/index.js
Normal file
74
src/Obj/Base/BaseSource/BaseModel/index.js
Normal file
@ -0,0 +1,74 @@
|
||||
import richText from "../../../Element/richText";
|
||||
import BaseSource from "../index";
|
||||
|
||||
class BaseModel extends BaseSource {
|
||||
constructor(sdk, options, _Dialog = {}) {
|
||||
super(sdk, options);
|
||||
}
|
||||
|
||||
async add() {
|
||||
if (this.options.url) {
|
||||
return this.loadModel(this.options.url)
|
||||
}
|
||||
}
|
||||
|
||||
_addLink() {
|
||||
// document.getElementsByClassName
|
||||
if (this._DialogObject._element.content.getElementsByClassName('link_add')[0].value) {
|
||||
this.options.attribute.link.content.push({
|
||||
name: this.getDateTimeString(),
|
||||
url: this._DialogObject._element.content.getElementsByClassName('link_add')[0].value
|
||||
})
|
||||
this._DialogObject._element.content.getElementsByClassName('link_add')[0].value = ''
|
||||
this.attributeLink = this.options.attribute.link.content
|
||||
}
|
||||
else {
|
||||
this.Dialog.clickAddLink && this.Dialog.clickAddLink()
|
||||
}
|
||||
}
|
||||
|
||||
addAttributeLink(link) {
|
||||
this.options.attribute.link.content.push({
|
||||
name: this.getDateTimeString(),
|
||||
url: link
|
||||
})
|
||||
this.attributeLink = this.options.attribute.link.content
|
||||
}
|
||||
|
||||
_addRr() {
|
||||
if (this._DialogObject._element.content.getElementsByClassName('vr_add')[0].value) {
|
||||
this.options.attribute.vr.content.push({
|
||||
name: '全景图' + (this.options.attribute.vr.content.length + 1),
|
||||
url: this._DialogObject._element.content.getElementsByClassName('vr_add')[0].value
|
||||
})
|
||||
this._DialogObject._element.content.getElementsByClassName('vr_add')[0].value = ''
|
||||
this.attributeVr = this.options.attribute.vr.content
|
||||
}
|
||||
else {
|
||||
this.Dialog.clickAddVr && this.Dialog.clickAddVr()
|
||||
}
|
||||
}
|
||||
|
||||
addAttributeRr(vr) {
|
||||
this.options.attribute.vr.content.push({
|
||||
name: '全景图' + (this.options.attribute.vr.content.length + 1),
|
||||
url: vr
|
||||
})
|
||||
this.attributeVr = this.options.attribute.vr.content
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开富文本框
|
||||
*/
|
||||
openRichTextEditor(e) {
|
||||
// var ue = UE.getEditor('app');
|
||||
richText.open(this.options.id, this.options.name, this.options.richTextContent)
|
||||
richText.primaryCallBack = (content) => {
|
||||
this.options.richTextContent = content
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default BaseModel
|
||||
|
||||
286
src/Obj/Base/BaseSource/BaseTerrain/index.js
Normal file
286
src/Obj/Base/BaseSource/BaseTerrain/index.js
Normal file
@ -0,0 +1,286 @@
|
||||
/**
|
||||
* @name: index
|
||||
* @author: Administrator
|
||||
* @date: 2023-11-20 17:54
|
||||
* @description:index
|
||||
* @update: 2023-11-20 17:54
|
||||
*/
|
||||
import Dialog from '../../../Element/Dialog';
|
||||
import { getHost } from "../../../../on";
|
||||
import BaseSource from "../index";
|
||||
import { setActiveViewer, closeRotateAround, closeViewFollow} from '../../../../Global/global'
|
||||
import { setSplitDirection, syncSplitData } from '../../../../Global/SplitScreen'
|
||||
|
||||
class BaseTerrain extends BaseSource {
|
||||
#updateModelTimeout;
|
||||
constructor(sdk, options = {}, object = {}, _Dialog = {}) {
|
||||
super(sdk, options);
|
||||
this.object = JSON.parse(JSON.stringify(object))
|
||||
this.object.west || (this.object.west = 40)
|
||||
this.object.south || (this.object.south = 30)
|
||||
this.object.east || (this.object.east = 160)
|
||||
this.object.north || (this.object.north = 50)
|
||||
this.show = this.options.show
|
||||
this._elms = {};
|
||||
this.Dialog = _Dialog
|
||||
}
|
||||
|
||||
get type() {
|
||||
return "terrain"
|
||||
}
|
||||
|
||||
get name() {
|
||||
return this.options.name
|
||||
}
|
||||
set name(v) {
|
||||
this.options.name = v
|
||||
this._elms.name && this._elms.name.forEach((item) => {
|
||||
item.value = v
|
||||
})
|
||||
}
|
||||
|
||||
get show() {
|
||||
return !(
|
||||
this.sdk.viewer.scene.terrainProvider instanceof
|
||||
Cesium.EllipsoidTerrainProvider
|
||||
)
|
||||
}
|
||||
|
||||
set show(status) {
|
||||
status ? this.open() : this.close()
|
||||
}
|
||||
|
||||
async open() {
|
||||
if (this.options.url) {
|
||||
return this.loadTerrain({
|
||||
url: this.options.url
|
||||
})
|
||||
} else {
|
||||
let res = await this.requestResource()
|
||||
let text = await res.text()
|
||||
text = JSON.parse(text)
|
||||
if ([0, 200].includes(text.code)) {
|
||||
if (text.data.url.length)
|
||||
return this.loadTerrain(text.data)
|
||||
else
|
||||
return new Promise((res, reject) => {
|
||||
reject('资源不存在')
|
||||
})
|
||||
} else {
|
||||
return new Promise((res, reject) => {
|
||||
reject(text.msg || text.message)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//关闭地形
|
||||
close() {
|
||||
this.sdk.viewer.scene.terrainProvider =
|
||||
new Cesium.EllipsoidTerrainProvider({})
|
||||
syncSplitData(this.sdk, this.options.id)
|
||||
|
||||
clearTimeout(this.#updateModelTimeout)
|
||||
this.#updateModelTimeout = setTimeout(() => {
|
||||
clearTimeout(this.#updateModelTimeout)
|
||||
for (let [key, entity] of this.sdk.entityMap) {
|
||||
if (entity.type === 'BillboardObject' && (entity.heightMode == 1 || entity.heightMode == 3)) {
|
||||
entity.updateHeight()
|
||||
}
|
||||
else {
|
||||
if (entity.label) {
|
||||
entity.label.show = entity.label.show
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
|
||||
async loadTerrain(options) {
|
||||
let object = { ...options }
|
||||
let url = ""
|
||||
if (object.url.startsWith("http"))
|
||||
url = object.url
|
||||
else {
|
||||
//说明是本地的json,在磁盘中存在的
|
||||
if (object.url.includes(":")) {
|
||||
url = object.url
|
||||
} else {
|
||||
if (this.options.host) {
|
||||
let o = new URL(object.url, this.options.host)
|
||||
url = o.href
|
||||
} else
|
||||
url = object.url
|
||||
}
|
||||
}
|
||||
if (Number(Cesium.VERSION.split('.')[1]) >= 107) {
|
||||
this.terrainProvider = await Cesium.CesiumTerrainProvider.fromUrl(url)
|
||||
}
|
||||
else {
|
||||
this.terrainProvider = new Cesium.CesiumTerrainProvider({
|
||||
url: url
|
||||
})
|
||||
}
|
||||
if (!this.sdk || !this.sdk.viewer) {
|
||||
return
|
||||
}
|
||||
this.sdk.viewer.terrainProvider = this.terrainProvider;
|
||||
clearTimeout(this.#updateModelTimeout)
|
||||
this.#updateModelTimeout = setTimeout(() => {
|
||||
clearTimeout(this.#updateModelTimeout)
|
||||
this.terrainProvider.readyPromise.then(() => {
|
||||
for (let [key, entity] of this.sdk.entityMap) {
|
||||
if (entity.type === 'BillboardObject' && (entity.heightMode == 1 || entity.heightMode == 3)) {
|
||||
entity.updateHeight()
|
||||
}
|
||||
else {
|
||||
if (entity.label) {
|
||||
entity.label.show = entity.label.show
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}, 1000);
|
||||
|
||||
|
||||
syncSplitData(this.sdk, this.options.id)
|
||||
}
|
||||
|
||||
remove() {
|
||||
this.close()
|
||||
}
|
||||
|
||||
async flyTo(duration = 3) {
|
||||
if (this._error) {
|
||||
return
|
||||
}
|
||||
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.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,
|
||||
duration
|
||||
})
|
||||
}
|
||||
else {
|
||||
let rectangle = new Cesium.Rectangle(
|
||||
Cesium.Math.toRadians(this.object.west),
|
||||
Cesium.Math.toRadians(this.object.south),
|
||||
Cesium.Math.toRadians(this.object.east),
|
||||
Cesium.Math.toRadians(this.object.north)
|
||||
)
|
||||
this.sdk.viewer.camera.flyTo({
|
||||
destination: rectangle,
|
||||
duration,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
setDefaultValue() {
|
||||
super.setDefaultValue()
|
||||
this.options.host = this.options.host || getHost()
|
||||
this.options.url = this.options.url || ""
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 编辑框
|
||||
* @param state=false {boolean} 状态: true打开, false关闭
|
||||
*/
|
||||
async edit(state = false) {
|
||||
this.originalOptions = this.deepCopyObj(this.options)
|
||||
if (this._DialogObject && this._DialogObject.close) {
|
||||
this._DialogObject.close()
|
||||
this._DialogObject = null
|
||||
}
|
||||
this._DialogObject = await new Dialog(this.sdk, this.options, {
|
||||
title: '地形属性', left: '180px', top: '100px',
|
||||
confirmCallBack: (options) => {
|
||||
this.name = this.name.trim()
|
||||
if (!this.name) {
|
||||
this.name = '未命名对象'
|
||||
}
|
||||
this.originalOptions = this.deepCopyObj(this.options)
|
||||
this._DialogObject.close()
|
||||
this.Dialog.confirmCallBack && this.Dialog.confirmCallBack(this.originalOptions)
|
||||
},
|
||||
// resetCallBack: () => {
|
||||
// this.name = this.originalOptions.name
|
||||
// this.Dialog.resetCallBack && this.Dialog.resetCallBack()
|
||||
// },
|
||||
removeCallBack: () => {
|
||||
this.Dialog.removeCallBack && this.Dialog.removeCallBack()
|
||||
},
|
||||
}, true)
|
||||
let contentElm = document.createElement('div')
|
||||
contentElm.style.width = '300px'
|
||||
let html = `
|
||||
<span class="custom-divider"></span>
|
||||
<div class="div-item">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">名称:</span>
|
||||
<input class="input name" type="text">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
contentElm.innerHTML = html
|
||||
let nameElm = contentElm.getElementsByClassName('name')[0]
|
||||
nameElm.value = this.name
|
||||
nameElm.addEventListener('input', () => {
|
||||
this.name = nameElm.value
|
||||
})
|
||||
this._DialogObject.contentAppChild(contentElm)
|
||||
this._elms.name = [nameElm]
|
||||
}
|
||||
|
||||
flicker() { }
|
||||
}
|
||||
|
||||
export default BaseTerrain
|
||||
93
src/Obj/Base/BaseSource/BaseTileset/BIM/_element.js
Normal file
93
src/Obj/Base/BaseSource/BaseTileset/BIM/_element.js
Normal file
@ -0,0 +1,93 @@
|
||||
|
||||
|
||||
function html() {
|
||||
return `
|
||||
<span class="custom-divider"></span>
|
||||
<div class="div-item">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">名称</span>
|
||||
<input class="input" @model="name">
|
||||
</div>
|
||||
<div class="col">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="custom-divider"></span>
|
||||
<div class="div-item">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">经度</span>
|
||||
<input class="input" type="number" title="" min="-180" max="180" @model="lng">
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">x轴</span>
|
||||
<input type="number" title="" min="-180" max="180" @model="roll">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">纬度</span>
|
||||
<input class="input" type="number" title="" min="-90" max="90" @model="lat">
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">y轴</span>
|
||||
<input type="number" title="" min="-180" max="180" @model="heading">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">高度</span>
|
||||
<div class="input-number input-number-unit-1">
|
||||
<input class="input" type="number" title="" min="-9999999" max="999999999" @model="height">
|
||||
<span class="unit">m</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">z轴</span>
|
||||
<input type="number" title="" min="-180" max="180" @model="pitch">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">大小</span>
|
||||
<input type="range" max="10" min="0.1" step="0.1" @model="scale">
|
||||
<div class="input-number" style="width: 100px;margin-left: 10px;">
|
||||
<input type="number" title="" min="0" max="10" step="0.1" @model="scale">
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="divide">
|
||||
<div class="line"></div>
|
||||
<p>BIM属性导出选项</p>
|
||||
<div class="line"></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div style="display: flex;">
|
||||
<div class="checkbox-box" @click="exportState">
|
||||
<input type="checkbox" value="3">
|
||||
<span>修建中</span>
|
||||
</div>
|
||||
<div class="checkbox-box" @click="exportState">
|
||||
<input type="checkbox" value="2">
|
||||
<span>未完成</span>
|
||||
</div>
|
||||
<div class="checkbox-box" @click="exportState">
|
||||
<input type="checkbox" value="1">
|
||||
<span>已完成</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<button @click="exportProperty">导 出</button>
|
||||
</div>
|
||||
</div>
|
||||
<span class="custom-divider"></span>
|
||||
`
|
||||
}
|
||||
|
||||
export { html }
|
||||
82
src/Obj/Base/BaseSource/BaseTileset/BIM/_element2.js
Normal file
82
src/Obj/Base/BaseSource/BaseTileset/BIM/_element2.js
Normal file
@ -0,0 +1,82 @@
|
||||
|
||||
|
||||
function html2() {
|
||||
return `
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">构件名称</span>
|
||||
<input class="input" name="name" disabled="disabled">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">选择状态</span>
|
||||
<select class="input input-select" name="state-select">
|
||||
<option value="0" style="color: #000;">重置</option>
|
||||
<option value="1" style="color: #f00;">已完成</option>
|
||||
<option value="2" style="color: #0f0;">未完成</option>
|
||||
<option value="3" style="color: #00f;">修建中</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="divide">
|
||||
<div class="line"></div>
|
||||
<p>自定义属性</p>
|
||||
<div class="line"></div>
|
||||
</div>
|
||||
<div class="property">
|
||||
</div>
|
||||
`
|
||||
}
|
||||
function css2() {
|
||||
return `
|
||||
.YJ-custom-base-dialog>.content {
|
||||
width: 440px;
|
||||
}
|
||||
.YJ-custom-base-dialog>.content .row .label {
|
||||
flex: 0 0 110px;
|
||||
}
|
||||
.col:first-child {
|
||||
margin-right: 10px;
|
||||
}
|
||||
.col:last-child {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.YJ-custom-base-dialog>.content .divide {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 20px 0;
|
||||
}
|
||||
.YJ-custom-base-dialog>.content .divide .line{
|
||||
height: 1px;
|
||||
background: #ddd;
|
||||
flex: 1;
|
||||
}
|
||||
.YJ-custom-base-dialog>.content .divide p{
|
||||
margin: 0 10px;
|
||||
}
|
||||
.YJ-custom-base-dialog>.content .property .property-item .btn{
|
||||
font-size: 24px;
|
||||
line-height: 20px;
|
||||
padding: 2px 0;
|
||||
}
|
||||
.YJ-custom-base-dialog>.content .property .property-item .input_lable {
|
||||
flex: 0 0 115px;
|
||||
border: none;
|
||||
margin-right: 15px;
|
||||
text-align: right;
|
||||
}
|
||||
.YJ-custom-base-dialog>.content .property .property-item:first-child .delete{
|
||||
display: none
|
||||
}
|
||||
.YJ-custom-base-dialog>.content .property .property-item .add{
|
||||
display: none;
|
||||
}
|
||||
.YJ-custom-base-dialog>.content .property .property-item:last-child .add{
|
||||
display: inline-block;
|
||||
}
|
||||
`
|
||||
}
|
||||
|
||||
export { html2, css2 }
|
||||
877
src/Obj/Base/BaseSource/BaseTileset/BIM/index.js
Normal file
877
src/Obj/Base/BaseSource/BaseTileset/BIM/index.js
Normal file
@ -0,0 +1,877 @@
|
||||
/**
|
||||
* @name: index
|
||||
* @author: Administrator
|
||||
* @date: 2023-11-20 16:05
|
||||
* @description:index
|
||||
* @update: 2023-11-20 16:05
|
||||
*/
|
||||
import BaseTileset from "../index";
|
||||
import { html } from "./_element";
|
||||
import { html2, css2 } from "./_element2";
|
||||
import Dialog from '../../../../Element/Dialog';
|
||||
import EventBinding from '../../../../Element/Dialog/eventBinding';
|
||||
import BaseDialog from '../../../../../BaseDialog'
|
||||
import { syncData } from '../../../../../Global/MultiViewportMode'
|
||||
import { syncSplitData } from '../../../../../Global/SplitScreen'
|
||||
import { setActiveViewer, closeRotateAround, closeViewFollow} from '../../../../../Global/global'
|
||||
|
||||
class BIM extends BaseTileset {
|
||||
#updateModelTimeout
|
||||
/**
|
||||
* @constructor
|
||||
* @description 加载BIM模型
|
||||
* @param sdk {object} sdk
|
||||
* @param options {object} 模型参数
|
||||
* @param options.id {string} 对象id
|
||||
* @param options.show=true {boolean} 模型显隐
|
||||
* @param options.name {string} 名称
|
||||
* @param options.url {string} 资源地址
|
||||
* @param options.position {object} 模型位置
|
||||
* @param options.position.lng {number} 经度
|
||||
* @param options.position.lat {number} 纬度
|
||||
* @param options.position.alt {number} 高度
|
||||
* */
|
||||
constructor(sdk, options = {}, _Dialog = {}) {
|
||||
super(sdk, options)
|
||||
this.picking = false
|
||||
this.features = options.features || []
|
||||
this.exportStateArray = []
|
||||
this.Dialog = _Dialog
|
||||
this._elms = {};
|
||||
this._EventBinding = new EventBinding()
|
||||
this.Dialog.exportState = (e) => {
|
||||
this.exportState(e)
|
||||
}
|
||||
this.Dialog.exportProperty = (e) => {
|
||||
this.exportProperty(this.exportStateArray)
|
||||
}
|
||||
this.features = new Map()
|
||||
}
|
||||
|
||||
get type() {
|
||||
return "bim"
|
||||
}
|
||||
|
||||
get name() {
|
||||
return this.newData.name
|
||||
}
|
||||
|
||||
set name(v) {
|
||||
this.newData.name = v
|
||||
this._elms.name && this._elms.name.forEach((item) => {
|
||||
item.value = v
|
||||
})
|
||||
}
|
||||
|
||||
get lng() {
|
||||
return this.newData.lng
|
||||
}
|
||||
|
||||
set lng(v) {
|
||||
this.newData.lng = v
|
||||
this.updateModel(this.newData.lng, this.newData.lat, this.newData.height, this.newData.roll, this.newData.heading, this.newData.pitch, this.newData.scale)
|
||||
this._elms.lng && this._elms.lng.forEach((item) => {
|
||||
item.value = v
|
||||
})
|
||||
}
|
||||
|
||||
get lat() {
|
||||
return this.newData.lat
|
||||
}
|
||||
|
||||
set lat(v) {
|
||||
this.newData.lat = v
|
||||
this.updateModel(this.newData.lng, this.newData.lat, this.newData.height, this.newData.roll, this.newData.heading, this.newData.pitch, this.newData.scale)
|
||||
this._elms.lat && this._elms.lat.forEach((item) => {
|
||||
item.value = v
|
||||
})
|
||||
}
|
||||
|
||||
get height() {
|
||||
return this.newData.height
|
||||
}
|
||||
|
||||
set height(v) {
|
||||
this.newData.height = v
|
||||
this.updateModel(this.newData.lng, this.newData.lat, this.newData.height, this.newData.roll, this.newData.heading, this.newData.pitch, this.newData.scale)
|
||||
this._elms.height && this._elms.height.forEach((item) => {
|
||||
item.value = v
|
||||
})
|
||||
}
|
||||
|
||||
get roll() {
|
||||
return this.newData.roll
|
||||
}
|
||||
|
||||
set roll(v) {
|
||||
this.newData.roll = v
|
||||
this.updateModel(this.newData.lng, this.newData.lat, this.newData.height, this.newData.roll, this.newData.heading, this.newData.pitch, this.newData.scale)
|
||||
this._elms.roll && this._elms.roll.forEach((item) => {
|
||||
item.value = v
|
||||
})
|
||||
}
|
||||
|
||||
get heading() {
|
||||
return this.newData.heading
|
||||
}
|
||||
|
||||
set heading(v) {
|
||||
this.newData.heading = v
|
||||
this.updateModel(this.newData.lng, this.newData.lat, this.newData.height, this.newData.roll, this.newData.heading, this.newData.pitch, this.newData.scale)
|
||||
this._elms.heading && this._elms.heading.forEach((item) => {
|
||||
item.value = v
|
||||
})
|
||||
}
|
||||
|
||||
get pitch() {
|
||||
return this.newData.pitch
|
||||
}
|
||||
|
||||
set pitch(v) {
|
||||
this.newData.pitch = v
|
||||
this.updateModel(this.newData.lng, this.newData.lat, this.newData.height, this.newData.roll, this.newData.heading, this.newData.pitch, this.newData.scale)
|
||||
this._elms.pitch && this._elms.pitch.forEach((item) => {
|
||||
item.value = v
|
||||
})
|
||||
}
|
||||
|
||||
get scale() {
|
||||
return this.newData.scale
|
||||
}
|
||||
|
||||
set scale(v) {
|
||||
this.newData.scale = v
|
||||
this.updateModel(this.newData.lng, this.newData.lat, this.newData.height, this.newData.roll, this.newData.heading, this.newData.pitch, this.newData.scale)
|
||||
this._elms.scale && this._elms.scale.forEach((item) => {
|
||||
item.value = v
|
||||
})
|
||||
}
|
||||
|
||||
// get transparency() {
|
||||
// return this.newData.transparency
|
||||
// }
|
||||
|
||||
// set transparency(v) {
|
||||
// this.newData.transparency = v
|
||||
// this.entity.style = new Cesium.Cesium3DTileStyle({
|
||||
// color: "color('rgba(255,255,255," + this.newData.transparency + ")')",
|
||||
// show: true,
|
||||
// });
|
||||
// this.entity.transparency = Number(this.newData.transparency)
|
||||
// this._elms.transparency && this._elms.transparency.forEach((item) => {
|
||||
// item.value = v
|
||||
// })
|
||||
// }
|
||||
|
||||
async loadSceneTree(url) {
|
||||
|
||||
// Cesium.ExperimentalFeatures.enableModelExperimental = true;
|
||||
let array = url.split('/')
|
||||
array[array.length - 1] = 'scenetree.json'
|
||||
|
||||
|
||||
await Cesium.Resource.fetchJson({
|
||||
url: array.join('/')
|
||||
}).then(res => {
|
||||
this.scenetree = res
|
||||
|
||||
const initData = (array) => {
|
||||
array.forEach(item => {
|
||||
if (this.features.has(item.id)) {
|
||||
this.features.get(item.id).sphere = item.sphere
|
||||
}
|
||||
else {
|
||||
this.features.set(item.id, { sphere: item.sphere })
|
||||
}
|
||||
if (item.children) {
|
||||
initData(item.children)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
initData(res.scenes[0].children)
|
||||
|
||||
// res.scenes[0].children.forEach(item => {
|
||||
// if (this.features.has(item.id)) {
|
||||
// this.features.get(item.id).sphere = item.sphere
|
||||
// }
|
||||
// else {
|
||||
// this.features.set(item.id, {sphere: item.sphere})
|
||||
// }
|
||||
// })
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
// 编辑框
|
||||
async edit(state) {
|
||||
let _this = this
|
||||
this.originalOptions = this.deepCopyObj(this.options)
|
||||
|
||||
if (this._DialogObject && this._DialogObject.close) {
|
||||
this._DialogObject.close()
|
||||
this._DialogObject = null
|
||||
}
|
||||
if (state) {
|
||||
|
||||
this._DialogObject = await new Dialog(this.sdk, this.newData, {
|
||||
title: 'BIM模型属性', left: '180px', top: '100px',
|
||||
resetCallBack: () => {
|
||||
this.reset()
|
||||
this.Dialog.resetCallBack && this.Dialog.resetCallBack()
|
||||
},
|
||||
confirmCallBack: (info) => {
|
||||
this.name = this.name.trim()
|
||||
if (!this.name) {
|
||||
this.name = '未命名对象'
|
||||
}
|
||||
this.oldData.name = this.newData.name
|
||||
this.oldData.height = this.newData.height
|
||||
this.oldData.lng = this.newData.lng
|
||||
this.oldData.lat = this.newData.lat
|
||||
// this.oldData.transparency = this.newData.transparency
|
||||
this.oldData.scale = this.newData.scale
|
||||
this.oldData.roll = this.newData.roll
|
||||
this.oldData.heading = this.newData.heading
|
||||
this.oldData.pitch = this.newData.pitch
|
||||
this._DialogObject.close()
|
||||
let features = new Map()
|
||||
this.features.forEach((item, key) => {
|
||||
let data = { ...item }
|
||||
delete data.features
|
||||
features.set(key, data)
|
||||
})
|
||||
this.Dialog.confirmCallBack && this.Dialog.confirmCallBack({ ...this.oldData, features: features, type: this.type })
|
||||
syncSplitData(this.sdk, this.oldData.id)
|
||||
},
|
||||
removeCallBack: () => {
|
||||
this.Dialog.removeCallBack && this.Dialog.removeCallBack()
|
||||
},
|
||||
closeCallBack: () => {
|
||||
this.reset()
|
||||
// this.newData.transparency = this.oldData.transparency
|
||||
// this.newData.name = this.oldData.name
|
||||
// this.newData.height = this.oldData.height
|
||||
// this.newData.lng = this.oldData.lng
|
||||
// this.newData.lat = this.oldData.lat
|
||||
// this.newData.scale = this.oldData.scale
|
||||
// this.entity.style = new Cesium.Cesium3DTileStyle({
|
||||
// color: "color('rgba(255,255,255," + this.newData.transparency + ")')",
|
||||
// show: true,
|
||||
// });
|
||||
this.editObj.destroy()
|
||||
this.Dialog.closeCallBack && this.Dialog.closeCallBack()
|
||||
},
|
||||
showCallBack: (show) => {
|
||||
this.newData.show = show
|
||||
this.entity && (this.entity.show = show)
|
||||
this.Dialog.showCallBack && this.Dialog.showCallBack()
|
||||
},
|
||||
rotateCallBack: () => {
|
||||
if (this.rotationEditing) {
|
||||
this.rotationEditing = false
|
||||
}
|
||||
else {
|
||||
this.rotationEditing = true
|
||||
}
|
||||
},
|
||||
translationalCallBack: () => {
|
||||
if (this.positionEditing) {
|
||||
this.positionEditing = false
|
||||
}
|
||||
else {
|
||||
this.positionEditing = true
|
||||
}
|
||||
}
|
||||
})
|
||||
this._DialogObject._element.body.className = this._DialogObject._element.body.className + ' tileset-bim'
|
||||
// 内容部分
|
||||
let contentElm = document.createElement('div');
|
||||
contentElm.innerHTML = html()
|
||||
this._DialogObject.contentAppChild(contentElm)
|
||||
|
||||
let all_elm = contentElm.getElementsByTagName("*")
|
||||
this._EventBinding.on(this, all_elm)
|
||||
this._elms = this._EventBinding.element
|
||||
|
||||
} else {
|
||||
if (this._DialogObject && this._DialogObject.close) {
|
||||
this._DialogObject.close()
|
||||
this._DialogObject = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async featureEdit(state, feature) {
|
||||
let _this = this
|
||||
this._element_style = null
|
||||
|
||||
if (this._DialogObject && this._DialogObject.close) {
|
||||
this._DialogObject.close()
|
||||
this._DialogObject = null
|
||||
}
|
||||
if (state) {
|
||||
// console.log(this.entity)
|
||||
// console.log(this.entity.root.children[0].content)
|
||||
// console.log(feature.getProperty('id'), feature.getProperty('name'), feature.getProperty('state'))
|
||||
let name = feature.getProperty('name')
|
||||
// console.log(feature.getProperty('descriptions'))
|
||||
let data = {
|
||||
id: feature.getProperty('id'),
|
||||
name: name,
|
||||
state: feature.getProperty('state') || 0,
|
||||
descriptions: feature.getProperty('descriptions') || [
|
||||
{
|
||||
id: this.randomString(),
|
||||
key: "点击此处可编辑",
|
||||
value: ""
|
||||
}
|
||||
]
|
||||
}
|
||||
switch (feature.getProperty('state')) {
|
||||
case '0': data.stateCH = ''
|
||||
break
|
||||
case '1': data.stateCH = '已完成'
|
||||
break
|
||||
case '2': data.stateCH = '未完成'
|
||||
break
|
||||
case '3': data.stateCH = '修建中'
|
||||
break
|
||||
}
|
||||
// let feature = this.entity.root.children[0].content.getFeature(0)
|
||||
// console.log(id,feature, this.entity)
|
||||
// return
|
||||
this._element_style = document.createElement('style');
|
||||
this._element_style.type = 'text/css';
|
||||
this._element_style.setAttribute('data-name', 'YJ_style_dialog');
|
||||
this._element_style.innerHTML = css2();
|
||||
|
||||
|
||||
this._DialogObject = await new BaseDialog(this.sdk.viewer._container, {
|
||||
title: this.oldData.name + '-----设置状态', left: 'calc(50% - 200px)', top: 'calc(50% - 200px)',
|
||||
closeCallBack: () => {
|
||||
this.Dialog.closeCallBack && this.Dialog.closeCallBack()
|
||||
}
|
||||
})
|
||||
await this._DialogObject.init()
|
||||
document.getElementsByTagName('head')[0].appendChild(this._element_style);
|
||||
// 内容部分
|
||||
let content = document.createElement('div');
|
||||
content.innerHTML = html2()
|
||||
// 名称
|
||||
let e_name = content.querySelector("input[name='name']")
|
||||
e_name.value = name
|
||||
//状态
|
||||
let e_state = content.querySelector("select[name='state-select']")
|
||||
e_state.value = data.state
|
||||
e_state.addEventListener('change', (e) => {
|
||||
data.state = e.target.value
|
||||
switch (data.state) {
|
||||
case '0': data.stateCH = ''
|
||||
break
|
||||
case '1': data.stateCH = '已完成'
|
||||
break
|
||||
case '2': data.stateCH = '未完成'
|
||||
break
|
||||
case '3': data.stateCH = '修建中'
|
||||
break
|
||||
}
|
||||
});
|
||||
//自定义属性
|
||||
let e_property = content.getElementsByClassName('property')[0]
|
||||
for (let i = 0; i < data.descriptions.length; i++) {
|
||||
createPropertyItem(data.descriptions[i], i)
|
||||
}
|
||||
function createPropertyItem(item) {
|
||||
let html = `<div class="row property-item">
|
||||
<div class="col">
|
||||
<input class="input_lable" name="key" value="${item.key}">
|
||||
<input class="input" name="value" value="${item.value}">
|
||||
<button class="btn add">+</button>
|
||||
<button class="btn delete">-</button>
|
||||
</div>
|
||||
</div>`
|
||||
// document.createRange().createContextualFragment(html)
|
||||
let newElement = document.createElement("div");
|
||||
newElement.innerHTML = html
|
||||
let itemElm = newElement.getElementsByClassName('property-item')[0]
|
||||
let e_key = itemElm.querySelector("input[name='key']")
|
||||
let e_value = itemElm.querySelector("input[name='value']")
|
||||
let e_add = itemElm.getElementsByClassName('add')[0]
|
||||
let e_delete = itemElm.getElementsByClassName('delete')[0]
|
||||
e_key.addEventListener('input', (e) => {
|
||||
item.key = e.target.value
|
||||
})
|
||||
e_value.addEventListener('input', (e) => {
|
||||
item.value = e.target.value
|
||||
})
|
||||
e_add.addEventListener('click', () => {
|
||||
let newItem = {
|
||||
id: _this.randomString(),
|
||||
key: "点击此处可编辑",
|
||||
value: ""
|
||||
}
|
||||
data.descriptions.push(newItem)
|
||||
createPropertyItem(newItem)
|
||||
})
|
||||
e_delete.addEventListener('click', (e) => {
|
||||
for (let i = 0; i < data.descriptions.length; i++) {
|
||||
if (data.descriptions[i].id === item.id) {
|
||||
data.descriptions.splice(i, 1)
|
||||
break
|
||||
}
|
||||
}
|
||||
e_property.removeChild(itemElm)
|
||||
// let item = {
|
||||
// key: "点击此处可编辑",
|
||||
// value: ""
|
||||
// }
|
||||
// createPropertyItem(item)
|
||||
})
|
||||
e_property.appendChild(itemElm)
|
||||
}
|
||||
let target = this._DialogObject._element.foot.getElementsByClassName('translational')[0]
|
||||
this._DialogObject.contentAppChild(content)
|
||||
// foot部分
|
||||
let confirmBtn = document.createElement('button');
|
||||
confirmBtn.className = 'confirm';
|
||||
confirmBtn.innerHTML = '确认'
|
||||
this._DialogObject.footAppChild(confirmBtn, target)
|
||||
confirmBtn.addEventListener('click', () => {
|
||||
let flag = false
|
||||
for (let i = 0; i < this.features.length; i++) {
|
||||
if (this.features[i].id == data.id) {
|
||||
this.features[i] = data
|
||||
flag = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!flag) {
|
||||
this.features.push(data)
|
||||
}
|
||||
feature.setProperty('state', data.state)
|
||||
feature.setProperty('descriptions', data.descriptions)
|
||||
let color = '#fff'
|
||||
switch (data.state) {
|
||||
case '0':
|
||||
color = '#fff'
|
||||
break;
|
||||
case '1':
|
||||
color = '#f00'
|
||||
break;
|
||||
case '2':
|
||||
color = '#0f0'
|
||||
break;
|
||||
case '3':
|
||||
color = '#00f'
|
||||
break;
|
||||
default:
|
||||
}
|
||||
feature.color = Cesium.Color.fromCssColorString(color)
|
||||
this._DialogObject.close()
|
||||
this.Dialog.confirmCallBack && this.Dialog.confirmCallBack({ ...this.newData, features: this.features })
|
||||
});
|
||||
} else {
|
||||
if (this._element_style) {
|
||||
document.getElementsByTagName('head')[0].removeChild(this._element_style)
|
||||
this._element_style = null
|
||||
}
|
||||
if (this._DialogObject && this._DialogObject.close) {
|
||||
this._DialogObject.close()
|
||||
this._DialogObject = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reset() {
|
||||
if (!this.entity) {
|
||||
return
|
||||
}
|
||||
// this.transparency = this.oldData.transparency
|
||||
this.name = this.oldData.name
|
||||
this.height = this.oldData.height
|
||||
this.lng = this.oldData.lng
|
||||
this.lat = this.oldData.lat
|
||||
this.roll = this.oldData.roll
|
||||
this.heading = this.oldData.heading
|
||||
this.pitch = this.oldData.pitch
|
||||
this.scale = this.oldData.scale
|
||||
}
|
||||
|
||||
//更新模型位置
|
||||
updateModel(_tx, _ty, _tz, _rx = 0, _ry = 0, _rz = 0, s = 1) {
|
||||
if (!this.tileset.root.transform) {
|
||||
if (window.ELEMENT) {
|
||||
window.ELEMENT.Message.closeAll();
|
||||
window.ELEMENT.Message({
|
||||
message: '该模型不支持移动和旋转!',
|
||||
type: 'warning',
|
||||
duration: 1500
|
||||
});
|
||||
}
|
||||
console.warn('该模型不支持移动和旋转!')
|
||||
return
|
||||
}
|
||||
if ((!_tx && _tx!==0) || (!_ty && _ty!==0) || (!_tz && _tz!==0)) {
|
||||
return
|
||||
}
|
||||
let mx = Cesium.Matrix3.fromRotationX(
|
||||
Cesium.Math.toRadians(_rx)
|
||||
)
|
||||
let my = Cesium.Matrix3.fromRotationY(
|
||||
Cesium.Math.toRadians(_ry)
|
||||
)
|
||||
let mz = Cesium.Matrix3.fromRotationZ(
|
||||
Cesium.Math.toRadians(_rz)
|
||||
)
|
||||
// 平移
|
||||
let m = Cesium.Transforms.eastNorthUpToFixedFrame(new Cesium.Cartesian3.fromDegrees(_tx, _ty, _tz))
|
||||
// 旋转
|
||||
let rotationX = Cesium.Matrix4.fromRotationTranslation(mx)
|
||||
let rotationY = Cesium.Matrix4.fromRotationTranslation(my)
|
||||
let rotationZ = Cesium.Matrix4.fromRotationTranslation(mz)
|
||||
let originalMatrix = new Cesium.Matrix4()
|
||||
Cesium.Matrix4.multiply(m, rotationX, originalMatrix)
|
||||
Cesium.Matrix4.multiply(originalMatrix, rotationY, originalMatrix)
|
||||
Cesium.Matrix4.multiply(originalMatrix, rotationZ, originalMatrix)
|
||||
const scale = Cesium.Matrix4.fromUniformScale(s);
|
||||
Cesium.Matrix4.multiply(originalMatrix, scale, this.entity._root.transform)
|
||||
if (!this.editObj.activeAxis) {
|
||||
this.editObj.position = { lng: _tx, lat: _ty, alt: _tz }
|
||||
}
|
||||
if (!this.editObj.activeCircle) {
|
||||
this.editObj.rotate = { x: _rx, y: _ry, z: _rz }
|
||||
}
|
||||
this.editObj && this.editObj.update()
|
||||
|
||||
clearTimeout(this.#updateModelTimeout)
|
||||
this.#updateModelTimeout = setTimeout(() => {
|
||||
clearTimeout(this.#updateModelTimeout)
|
||||
let center = this.cartesian3Towgs84(this.entity.boundingSphere.center, this.sdk.viewer)
|
||||
let circle = turf.circle([center.lng, center.lat], this.entity.boundingSphere.radius / 1000, { steps: 360, units: 'kilometers' });
|
||||
for (let [key, entity] of this.sdk.entityMap) {
|
||||
if (entity.type === 'BillboardObject' && entity.heightMode == 3) {
|
||||
let pt = turf.point([entity.lng, entity.lat]);
|
||||
if (turf.booleanPointInPolygon(pt, circle)) {
|
||||
entity.updateHeight()
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(entity.label) {
|
||||
entity.label.show = entity.label.show
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
|
||||
|
||||
// exportProperty(states) {
|
||||
// console.log(this.features)
|
||||
// let fieldKeys = ['name', '', '', '', '', '', '', '', '', '', '', '', 'stateCH', 'descriptions']
|
||||
// let fieldLabels = ['构件名称', '体积', '墩全高H', '墩身高h', '底部高程', '承台宽', '承台长', '承台高', '族', '桩径', '桩长', '结构材质', '完成情况', '自定义属性']
|
||||
|
||||
// let dataStr = fieldLabels.toString() + '\r\n';
|
||||
// for (let i = 0; i < this.features.length; i++) {
|
||||
// for (let j = 0; j < states.length; j++) {
|
||||
// if (this.features[i].state == states[j]) {
|
||||
// fieldKeys.forEach(key => {
|
||||
// if (Array.isArray(this.features[i][key])) {
|
||||
// let str = ''
|
||||
// for (let k in this.features[i][key]) {
|
||||
// str += `${this.features[i][key][k].key + ':' + this.features[i][key][k].value}\n`
|
||||
// }
|
||||
// dataStr += `"${str}"\t`
|
||||
// }
|
||||
// else {
|
||||
// // 加引号是为了使换行符在单元格内正常显示
|
||||
// dataStr += `"${this.features[i][key] ? this.features[i][key] : ''}"\t,`;
|
||||
// }
|
||||
// });
|
||||
// dataStr += '\r\n';
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// // encodeURIComponent 解决中文乱码
|
||||
// const url = "data:text/xls;charset=utf-8,\ufeff" + encodeURIComponent(dataStr);
|
||||
// console.log(url)
|
||||
// // const link = document.createElement("a");
|
||||
// // link.href = url;
|
||||
// // link.download = this.oldData.name + "--构件属性.xls";
|
||||
// // link.style.display = 'none';
|
||||
// // document.body.appendChild(link);
|
||||
// // link.click();
|
||||
// // document.body.removeChild(link); //释放标签
|
||||
// }
|
||||
|
||||
getScenetree() {
|
||||
return this.scenetree
|
||||
}
|
||||
|
||||
// 设置feature颜色
|
||||
featureColor(id, color) {
|
||||
if (this.features.has(id)) {
|
||||
let features = this.features.get(id).features
|
||||
for (let key in features) {
|
||||
if (features[key].content._model) {
|
||||
features[key].color = Cesium.Color.fromCssColorString(color)
|
||||
}
|
||||
features[key].customColor = Cesium.Color.fromCssColorString(color)
|
||||
}
|
||||
this.features.get(id).customColor = Cesium.Color.fromCssColorString(color)
|
||||
}
|
||||
}
|
||||
|
||||
getFeatureColor(id) {
|
||||
if (this.features.has(id)) {
|
||||
if (this.features.get(id).customColor) {
|
||||
return this.features.get(id).customColor
|
||||
}
|
||||
let features = this.features.get(id).features
|
||||
for (let key in features) {
|
||||
if (features[key].content._model) {
|
||||
return features[key].customColor || features[key].color
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 设置feature显隐
|
||||
featureShow(id, show) {
|
||||
if (this.features.has(id)) {
|
||||
let features = this.features.get(id).features
|
||||
for (let key in features) {
|
||||
if (features[key].content._model) {
|
||||
features[key].show = show
|
||||
}
|
||||
features[key].customShow = show
|
||||
}
|
||||
this.features.get(id).customShow = show
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//飞到feature位置
|
||||
async featureFlyto(id) {
|
||||
if (this.features.has(id)) {
|
||||
let sphere = this.features.get(id).sphere
|
||||
let center = new Cesium.Cartesian3(
|
||||
sphere[0],
|
||||
sphere[1],
|
||||
sphere[2]
|
||||
)
|
||||
let srcMatInv = this.entity._root.originalTransform
|
||||
srcMatInv = Cesium.Matrix4.inverse(srcMatInv, new Cesium.Matrix4())
|
||||
let curMat = this.entity._root.transform
|
||||
let mat = Cesium.Matrix4.multiply(curMat, srcMatInv, new Cesium.Matrix4())
|
||||
let center2 = Cesium.Matrix4.multiplyByPoint(
|
||||
mat,
|
||||
center,
|
||||
new Cesium.Cartesian3()
|
||||
)
|
||||
let wgs84 = this.cartesian3Towgs84(center2, this.sdk.viewer)
|
||||
let cartesian3 = Cesium.Cartesian3.fromDegrees(
|
||||
wgs84.lng,
|
||||
wgs84.lat,
|
||||
wgs84.alt + sphere[3]
|
||||
)
|
||||
setActiveViewer(0)
|
||||
closeRotateAround(this.sdk)
|
||||
closeViewFollow(this.sdk)
|
||||
|
||||
this.sdk.viewer.camera.flyTo({
|
||||
destination: cartesian3
|
||||
})
|
||||
// this.entity.style = await new Cesium.Cesium3DTileStyle({
|
||||
// color: "color('rgba(255,255,255,0.2)')"
|
||||
// });
|
||||
this.features.forEach((item, key) => {
|
||||
if (key === id) {
|
||||
let color = this.getFeatureColor(id)
|
||||
if (this.features.has(id) && color) {
|
||||
let features = this.features.get(id).features
|
||||
for (let k in features) {
|
||||
if (features[k].content._model) {
|
||||
features[k].color = color
|
||||
}
|
||||
features[k].customAlpha = 1
|
||||
}
|
||||
this.features.get(id).customAlpha = 1
|
||||
}
|
||||
// this.featureColor(id, `rgba(${Cesium.Color.floatToByte(color.red)},${Cesium.Color.floatToByte(color.green)},${Cesium.Color.floatToByte(color.blue)},${color.alpha})`)
|
||||
}
|
||||
else {
|
||||
let color = this.getFeatureColor(key)
|
||||
if (this.features.has(key) && color) {
|
||||
let features = this.features.get(key).features
|
||||
for (let k in features) {
|
||||
if (features[k].content._model) {
|
||||
features[k].color = Cesium.Color.fromCssColorString(`rgba(${Cesium.Color.floatToByte(color.red)},${Cesium.Color.floatToByte(color.green)},${Cesium.Color.floatToByte(color.blue)},${color.alpha * 0.2})`)
|
||||
}
|
||||
features[k].customAlpha = color.alpha * 0.2
|
||||
}
|
||||
this.features.get(key).customAlpha = color.alpha * 0.2
|
||||
}
|
||||
// this.featureColor(key, `rgba(${Cesium.Color.floatToByte(color.red)},${Cesium.Color.floatToByte(color.green)},${Cesium.Color.floatToByte(color.blue)},${color.alpha * 0.2})`)
|
||||
}
|
||||
})
|
||||
// this.entity.readyPromise.then(()=>{
|
||||
// this.featureColor(id, '#ffffff')
|
||||
// })
|
||||
}
|
||||
else {
|
||||
this.features.forEach((item, key) => {
|
||||
let features = this.features.get(key).features
|
||||
let color = this.getFeatureColor(key)
|
||||
if (color) {
|
||||
for (let k in features) {
|
||||
if (features[k].content._model) {
|
||||
features[k].color = color
|
||||
}
|
||||
features[k].customAlpha = 1
|
||||
}
|
||||
this.features.get(key).customAlpha = color.alpha * 0.2
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 导出属性
|
||||
exportProperty(states) {
|
||||
if (this.exportStateArray.length === 0) {
|
||||
window.ELEMENT && window.ELEMENT.Message({
|
||||
message: '未选择属性导出选项!',
|
||||
type: 'warning',
|
||||
duration: 1500
|
||||
});
|
||||
return
|
||||
}
|
||||
let fieldKeys = ['name', '', '', '', '', '', '', '', '', '', '', '', 'stateCH', 'descriptions']
|
||||
let fieldLabels = ['构件名称', '体积', '墩全高H', '墩身高h', '底部高程', '承台宽', '承台长', '承台高', '族', '桩径', '桩长', '结构材质', '完成情况', '自定义属性']
|
||||
var url = 'data:application/vnd.ms-excel;base64,',
|
||||
tmplWorkbookXML = '<?xml version="1.0"?><?mso-application progid="Excel.Sheet"?><Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">'
|
||||
+ '<DocumentProperties xmlns="urn:schemas-microsoft-com:office:office"><Author>Axel Richter</Author><Created>{created}</Created></DocumentProperties>'
|
||||
+ '<Styles>'
|
||||
+ '<Style ss:ID="Currency"><NumberFormat ss:Format="Currency"></NumberFormat></Style>'
|
||||
+ '<Style ss:ID="Date"><NumberFormat ss:Format="Medium Date"></NumberFormat></Style>'
|
||||
+ '</Styles>'
|
||||
+ '{worksheets}</Workbook>'
|
||||
, tmplWorksheetXML = '<Worksheet ss:Name="{nameWS}"><Table><ss:Column ss:Width="120"/><ss:Column ss:Width="120"/><ss:Column ss:Width="120"/><ss:Column ss:Width="120"/><ss:Column ss:Width="120"/><ss:Column ss:Width="120"/><ss:Column ss:Width="120"/><ss:Column ss:Width="120"/><ss:Column ss:Width="120"/><ss:Column ss:Width="120"/><ss:Column ss:Width="120"/><ss:Column ss:Width="120"/><ss:Column ss:Width="120"/><ss:Column ss:Width="240"/>{rows}</Table></Worksheet>'
|
||||
, tmplCellXML = '<Cell><Data ss:Type="{nameType}">{data}</Data></Cell>'
|
||||
, base64 = function (s) {
|
||||
return window.btoa(unescape(encodeURIComponent(s)))
|
||||
}
|
||||
, format = function (s, c) {
|
||||
return s.replace(/{(\w+)}/g, function (m, p) {
|
||||
return c[p];
|
||||
})
|
||||
}
|
||||
|
||||
var ctx = "";
|
||||
var workbookXML = "";
|
||||
var worksheetsXML = "";
|
||||
var rowsXML = "";
|
||||
|
||||
var pil = 0;
|
||||
for (var i = 0; i < this.features.length; i++) {
|
||||
for (let j = 0; j < states.length; j++) {
|
||||
if (this.features[i].state == states[j]) {
|
||||
if (i == 0) {
|
||||
rowsXML += '<Row>' +
|
||||
'<Cell><Data ss:Type="String">构件名称</Data></Cell>' +
|
||||
'<Cell><Data ss:Type="String">体积</Data></Cell>' +
|
||||
'<Cell><Data ss:Type="String">墩全高H</Data></Cell>' +
|
||||
'<Cell><Data ss:Type="String">墩身高h</Data></Cell>' +
|
||||
'<Cell><Data ss:Type="String">底部高程</Data></Cell>' +
|
||||
'<Cell><Data ss:Type="String">承台宽</Data></Cell>' +
|
||||
'<Cell><Data ss:Type="String">承台长</Data></Cell>' +
|
||||
'<Cell><Data ss:Type="String">承台高</Data></Cell>' +
|
||||
'<Cell><Data ss:Type="String">族</Data></Cell>' +
|
||||
'<Cell><Data ss:Type="String">桩径</Data></Cell>' +
|
||||
'<Cell><Data ss:Type="String">桩长</Data></Cell>' +
|
||||
'<Cell><Data ss:Type="String">结构材质</Data></Cell>' +
|
||||
'<Cell><Data ss:Type="String">完成情况</Data></Cell>' +
|
||||
'<Cell><Data ss:Type="String">自定义属性</Data></Cell>' +
|
||||
'</Row>';
|
||||
}
|
||||
rowsXML += '<Row>';
|
||||
for (var key in fieldKeys) {
|
||||
if (Array.isArray(this.features[i][fieldKeys[key]])) {
|
||||
let str = ''
|
||||
for (let k in this.features[i][fieldKeys[key]]) {
|
||||
str += `${this.features[i][fieldKeys[key]][k].key + ':' + this.features[i][fieldKeys[key]][k].value} `
|
||||
}
|
||||
ctx = {
|
||||
nameType: 'String',
|
||||
data: str
|
||||
};
|
||||
}
|
||||
else {
|
||||
ctx = {
|
||||
nameType: 'String',
|
||||
data: this.features[i][fieldKeys[key]] || "0"
|
||||
};
|
||||
}
|
||||
rowsXML += format(tmplCellXML, ctx);
|
||||
}
|
||||
rowsXML += '</Row>';
|
||||
if (i > 0 && (i / 60000) % 1 === 0) {
|
||||
pil++;
|
||||
ctx = { rows: rowsXML, nameWS: 'Sheet' + i };
|
||||
worksheetsXML += format(tmplWorksheetXML, ctx);
|
||||
rowsXML = "";
|
||||
rowsXML += '<Row>' +
|
||||
'<Cell><Data ss:Type="String">构件名称</Data></Cell>' +
|
||||
'<Cell><Data ss:Type="String">体积</Data></Cell>' +
|
||||
'<Cell><Data ss:Type="String">墩全高H</Data></Cell>' +
|
||||
'<Cell><Data ss:Type="String">墩身高h</Data></Cell>' +
|
||||
'<Cell><Data ss:Type="String">底部高程</Data></Cell>' +
|
||||
'<Cell><Data ss:Type="String">承台宽</Data></Cell>' +
|
||||
'<Cell><Data ss:Type="String">承台长</Data></Cell>' +
|
||||
'<Cell><Data ss:Type="String">承台高</Data></Cell>' +
|
||||
'<Cell><Data ss:Type="String">族</Data></Cell>' +
|
||||
'<Cell><Data ss:Type="String">桩径</Data></Cell>' +
|
||||
'<Cell><Data ss:Type="String">桩长</Data></Cell>' +
|
||||
'<Cell><Data ss:Type="String">结构材质</Data></Cell>' +
|
||||
'<Cell><Data ss:Type="String">完成情况</Data></Cell>' +
|
||||
'<Cell><Data ss:Type="String">自定义属性</Data></Cell>' +
|
||||
'</Row>';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx = { rows: rowsXML, nameWS: 'Sheet' };
|
||||
worksheetsXML += format(tmplWorksheetXML, ctx);
|
||||
rowsXML = "";
|
||||
ctx = { created: (new Date()).getTime(), worksheets: worksheetsXML };
|
||||
workbookXML = format(tmplWorkbookXML, ctx);
|
||||
var link = document.createElement("A");
|
||||
link.href = url + base64(workbookXML);
|
||||
link.download = this.oldData.name + "--构件属性.xls"
|
||||
link.target = '_blank';
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
}
|
||||
|
||||
exportState(e) {
|
||||
let checkbox = e.target.getElementsByTagName('input')[0]
|
||||
checkbox.checked = !checkbox.checked
|
||||
if (checkbox.checked) {
|
||||
this.exportStateArray.push(checkbox.value)
|
||||
this.exportStateArray = Array.from(new Set(this.exportStateArray))
|
||||
}
|
||||
else {
|
||||
for (let i = 0; i < this.exportStateArray.length; i++) {
|
||||
if (this.exportStateArray[i] == checkbox.value) {
|
||||
this.exportStateArray.splice(i, 1)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default BIM
|
||||
54
src/Obj/Base/BaseSource/BaseTileset/Tileset/_element.js
Normal file
54
src/Obj/Base/BaseSource/BaseTileset/Tileset/_element.js
Normal file
@ -0,0 +1,54 @@
|
||||
|
||||
|
||||
function html() {
|
||||
return `
|
||||
<span class="custom-divider"></span>
|
||||
<div class="div-item">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">名称</span>
|
||||
<input class="input" @model="name">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="custom-divider"></span>
|
||||
<div class="div-item">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">高度</span>
|
||||
<div class="input-number input-number-unit-3">
|
||||
<input class="input" type="number" title="" @model="height">
|
||||
<span class="unit">m</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">精度</span>
|
||||
<div class="input-number input-number-unit-3">
|
||||
<input class="input" type="number" title="" min="0.1" max="10" step="0.1" @model="accuracy">
|
||||
<span class="unit">倍</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">透视</span>
|
||||
<input type="range" min="0" max="1" step="0.01" @model="transparency">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
function css() {
|
||||
return `
|
||||
.YJ-custom-base-dialog>.content {
|
||||
width: 420px;
|
||||
}
|
||||
.YJ-custom-base-dialog>.content .row .label {
|
||||
flex: 0 0 45px;
|
||||
}
|
||||
`
|
||||
}
|
||||
|
||||
export { html, css }
|
||||
87
src/Obj/Base/BaseSource/BaseTileset/Tileset/eventBinding.js
Normal file
87
src/Obj/Base/BaseSource/BaseTileset/Tileset/eventBinding.js
Normal file
@ -0,0 +1,87 @@
|
||||
class eventBinding {
|
||||
constructor() {
|
||||
this.element = {}
|
||||
}
|
||||
static event = {}
|
||||
|
||||
getEvent(name) {
|
||||
return eventBinding.event[name]
|
||||
}
|
||||
|
||||
getEventAll() {
|
||||
return eventBinding.event
|
||||
}
|
||||
|
||||
setEvent(name, event) {
|
||||
eventBinding.event[name] = event
|
||||
}
|
||||
|
||||
on(that, elements) {
|
||||
for (let i = 0; i < elements.length; i++) {
|
||||
let Event = []
|
||||
let isEvent = false
|
||||
let removeName = []
|
||||
if (!elements[i] || !elements[i].attributes) {
|
||||
continue;
|
||||
}
|
||||
for (let m of elements[i].attributes) {
|
||||
switch (m.name) {
|
||||
case '@model': {
|
||||
isEvent = true
|
||||
if (elements[i].type == 'checkbox') {
|
||||
Event.push((e) => { that[m.value] = e.target.checked })
|
||||
elements[i].checked = that[m.value]
|
||||
}
|
||||
else {
|
||||
Event.push((e) => {
|
||||
let value = e.target.value
|
||||
if(e.target.type == 'number') {
|
||||
value = Number(value)
|
||||
}
|
||||
that[m.value] = value
|
||||
})
|
||||
if(elements[i].nodeName=='IMG') {
|
||||
elements[i].src = that[m.value]
|
||||
}
|
||||
else {
|
||||
elements[i].value = that[m.value]
|
||||
}
|
||||
}
|
||||
this.element[m.value] = elements[i]
|
||||
removeName.push(m.name)
|
||||
break;
|
||||
}
|
||||
case '@click': {
|
||||
elements[i].addEventListener('click', (e) => {
|
||||
if (typeof (that.Dialog[m.value]) === 'function') {
|
||||
that.Dialog[m.value](e)
|
||||
}
|
||||
});
|
||||
removeName.push(m.name)
|
||||
// elements[i].attributes.removeNamedItem(m.name)
|
||||
break;
|
||||
}
|
||||
}
|
||||
// elements[i].attributes[m] = undefined
|
||||
}
|
||||
for(let n=0;n<removeName.length;n++) {
|
||||
elements[i].attributes.removeNamedItem(removeName[n])
|
||||
}
|
||||
|
||||
if (isEvent) {
|
||||
let ventType = 'input'
|
||||
if (elements[i].tagName != 'INPUT' || elements[i].type == 'checkbox') {
|
||||
ventType = 'change'
|
||||
}
|
||||
elements[i].addEventListener(ventType, (e) => {
|
||||
for (let t = 0; t < Event.length; t++) {
|
||||
Event[t](e)
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const EventBinding = new eventBinding();
|
||||
export default EventBinding;
|
||||
373
src/Obj/Base/BaseSource/BaseTileset/Tileset/index.js
Normal file
373
src/Obj/Base/BaseSource/BaseTileset/Tileset/index.js
Normal file
@ -0,0 +1,373 @@
|
||||
/**
|
||||
* @name: index
|
||||
* @author: Administrator
|
||||
* @date: 2023-11-20 16:05
|
||||
* @description:index
|
||||
* @update: 2023-11-20 16:05
|
||||
*/
|
||||
import BaseTileset from "../index";
|
||||
import cy_slider from "../../../../Element/cy_html_slider";
|
||||
import { html, css } from "./_element";
|
||||
import EventBinding from '../../../../Element/Dialog/eventBinding';
|
||||
import { syncSplitData } from '../../../../../Global/SplitScreen'
|
||||
import Dialog from '../../../../Element/Dialog';
|
||||
|
||||
class Tileset extends BaseTileset {
|
||||
#updateModelTimeout;
|
||||
/**
|
||||
* @constructor
|
||||
* @description 加载Tileset模型
|
||||
* @param sdk {object} sdk
|
||||
* @param options {object} 模型参数
|
||||
* @param options.id {string} 对象id
|
||||
* @param options.show=true {boolean} 模型显隐
|
||||
* @param options.name {string} 名称
|
||||
* @param options.url {string} 资源地址
|
||||
* @param options.accuracy=1 {number} 精度(倍)
|
||||
* @param options.position {object} 模型位置
|
||||
* @param options.position.lng {number} 经度
|
||||
* @param options.position.lat {number} 纬度
|
||||
* @param options.position.alt {number} 高度
|
||||
* */
|
||||
constructor(earth, options = {}, _Dialog = {}) {
|
||||
super(earth, options)
|
||||
this.picking = false
|
||||
this.Dialog = _Dialog
|
||||
this._elms = {};
|
||||
this._EventBinding = new EventBinding()
|
||||
}
|
||||
|
||||
get type() {
|
||||
return "tileset"
|
||||
}
|
||||
|
||||
on() {
|
||||
return this.add()
|
||||
}
|
||||
|
||||
get name() {
|
||||
return this.newData.name
|
||||
}
|
||||
|
||||
set name(v) {
|
||||
this.newData.name = v
|
||||
this._elms.name && this._elms.name.forEach((item) => {
|
||||
item.value = v
|
||||
})
|
||||
}
|
||||
|
||||
get height() {
|
||||
return this.newData.height
|
||||
}
|
||||
|
||||
set height(v) {
|
||||
this.newData.height = v
|
||||
this.options.position.alt = v
|
||||
this._elms.height && this._elms.height.forEach((item) => {
|
||||
item.value = v
|
||||
})
|
||||
this.updateModel(this.newData.lng, this.newData.lat, this.newData.height, this.newData.roll, this.newData.heading, this.newData.pitch)
|
||||
}
|
||||
|
||||
get accuracy() {
|
||||
return this.newData.accuracy
|
||||
}
|
||||
|
||||
set accuracy(v) {
|
||||
this.newData.accuracy = Number(v.toFixed(1))
|
||||
if(this.newData.accuracy<0.1) {
|
||||
this.newData.accuracy = 0.1
|
||||
}
|
||||
if(this.entity) {
|
||||
this.entity.maximumScreenSpaceError = 32/this.newData.accuracy
|
||||
}
|
||||
this._elms.accuracy && this._elms.accuracy.forEach((item) => {
|
||||
item.value = this.newData.accuracy
|
||||
})
|
||||
}
|
||||
|
||||
get lng() {
|
||||
return this.newData.lng
|
||||
}
|
||||
set lng(v) {
|
||||
this.newData.lng = v
|
||||
this.options.position.lng = v
|
||||
this.updateModel(this.newData.lng, this.newData.lat, this.newData.height, this.newData.roll, this.newData.heading, this.newData.pitch)
|
||||
}
|
||||
|
||||
get lat() {
|
||||
return this.newData.lat
|
||||
}
|
||||
set lat(v) {
|
||||
this.newData.lat = v
|
||||
this.options.position.lat = v
|
||||
this.updateModel(this.newData.lng, this.newData.lat, this.newData.height, this.newData.roll, this.newData.heading, this.newData.pitch)
|
||||
}
|
||||
|
||||
get roll() {
|
||||
return this.newData.roll
|
||||
}
|
||||
|
||||
set roll(v) {
|
||||
this.newData.roll = v
|
||||
this.updateModel(this.newData.lng, this.newData.lat, this.newData.height, this.newData.roll, this.newData.heading, this.newData.pitch, this.newData.scale)
|
||||
}
|
||||
|
||||
get heading() {
|
||||
return this.newData.heading
|
||||
}
|
||||
|
||||
set heading(v) {
|
||||
this.newData.heading = v
|
||||
this.updateModel(this.newData.lng, this.newData.lat, this.newData.height, this.newData.roll, this.newData.heading, this.newData.pitch, this.newData.scale)
|
||||
}
|
||||
|
||||
get pitch() {
|
||||
return this.newData.pitch
|
||||
}
|
||||
|
||||
set pitch(v) {
|
||||
this.newData.pitch = v
|
||||
this.updateModel(this.newData.lng, this.newData.lat, this.newData.height, this.newData.roll, this.newData.heading, this.newData.pitch, this.newData.scale)
|
||||
}
|
||||
|
||||
get transparency() {
|
||||
return this.newData.transparency
|
||||
}
|
||||
|
||||
set transparency(v) {
|
||||
if (!this.newData) {
|
||||
return
|
||||
}
|
||||
this.newData.transparency = Number(v)
|
||||
this._elms.transparency && this._elms.transparency.forEach((item) => {
|
||||
item.value = v
|
||||
})
|
||||
let transparency = this.newData.transparency
|
||||
// if (transparency == 1) {
|
||||
// transparency = 0.99
|
||||
// }
|
||||
this.entity.style = new Cesium.Cesium3DTileStyle({
|
||||
color: {
|
||||
"conditions": [
|
||||
//有size属性表示为点云,需要与点颜色融合
|
||||
["Boolean(${SIZE})", "${COLOR} * color('rgba(255,255,255)', " + transparency + ")"],
|
||||
["true", "color('rgba(255,255,255," + transparency + ")')"]
|
||||
]
|
||||
},
|
||||
show: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 编辑框
|
||||
* @param state=false {boolean} 状态: true打开, false关闭
|
||||
*/
|
||||
async edit(state = false) {
|
||||
let _this = this
|
||||
this._element_style = null
|
||||
|
||||
// let elms = this.sdk.viewer._container.getElementsByClassName('YJ-custom-base-dialog')
|
||||
// for (let i = elms.length - 1; i >= 0; i--) {
|
||||
// this.sdk.viewer._container.removeChild(elms[i])
|
||||
// }
|
||||
|
||||
if (this._DialogObject && this._DialogObject.close) {
|
||||
this._DialogObject.close()
|
||||
this._DialogObject = null
|
||||
}
|
||||
|
||||
if (state) {
|
||||
this._element_style = document.createElement('style');
|
||||
this._element_style.type = 'text/css';
|
||||
this._element_style.setAttribute('data-name', 'YJ_style_dialog');
|
||||
this._element_style.innerHTML = css();
|
||||
|
||||
this._DialogObject = await new Dialog(this.sdk, this.newData, {
|
||||
title: '倾斜模型属性', left: '180px', top: '100px',
|
||||
confirmCallBack: (options) => {
|
||||
this.oldData.name = this.newData.name
|
||||
this.oldData.height = this.newData.height
|
||||
this.oldData.lng = this.newData.lng
|
||||
this.oldData.lat = this.newData.lat
|
||||
this.oldData.transparency = this.newData.transparency
|
||||
this.oldData.scale = this.newData.scale
|
||||
this.oldData.roll = this.newData.roll
|
||||
this.oldData.heading = this.newData.heading
|
||||
this.oldData.pitch = this.newData.pitch
|
||||
this.oldData.type = this.type
|
||||
this.oldData.accuracy = this.newData.accuracy
|
||||
this._DialogObject.close()
|
||||
this.Dialog.confirmCallBack && this.Dialog.confirmCallBack({ ...this.oldData, type: this.type })
|
||||
syncSplitData(this.sdk, this.oldData.id)
|
||||
},
|
||||
resetCallBack: () => {
|
||||
this.reset()
|
||||
this.Dialog.resetCallBack && this.Dialog.resetCallBack()
|
||||
},
|
||||
removeCallBack: () => {
|
||||
this.Dialog.removeCallBack && this.Dialog.removeCallBack()
|
||||
},
|
||||
closeCallBack: () => {
|
||||
this.reset()
|
||||
if (this.positionEditing) {
|
||||
this.positionEditing = false
|
||||
}
|
||||
if (this.rotationEditing) {
|
||||
this.rotationEditing = false
|
||||
}
|
||||
this.Dialog.closeCallBack && this.Dialog.closeCallBack()
|
||||
},
|
||||
showCallBack: (show) => {
|
||||
this.newData.show = show
|
||||
this.entity && (this.entity.show = show)
|
||||
this.Dialog.showCallBack && this.Dialog.showCallBack()
|
||||
},
|
||||
rotateCallBack: () => {
|
||||
if (this.rotationEditing) {
|
||||
this.rotationEditing = false
|
||||
}
|
||||
else {
|
||||
this.rotationEditing = true
|
||||
}
|
||||
},
|
||||
translationalCallBack: () => {
|
||||
if (this.positionEditing) {
|
||||
this.positionEditing = false
|
||||
}
|
||||
else {
|
||||
this.positionEditing = true
|
||||
}
|
||||
}
|
||||
}, true)
|
||||
document.getElementsByTagName('head')[0].appendChild(this._element_style);
|
||||
let contentElm = document.createElement('div');
|
||||
contentElm.innerHTML = html()
|
||||
this._DialogObject.contentAppChild(contentElm)
|
||||
|
||||
let all_elm = contentElm.getElementsByTagName("*")
|
||||
this._EventBinding.on(this, all_elm)
|
||||
this._elms = this._EventBinding.element
|
||||
} else {
|
||||
// if (this._element_style) {
|
||||
// document.getElementsByTagName('head')[0].removeChild(this._element_style)
|
||||
// this._element_style = null
|
||||
// }
|
||||
// if (this._DialogObject && this._DialogObject.remove) {
|
||||
// this._DialogObject.remove()
|
||||
// this._DialogObject = null
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
//更新模型位置
|
||||
updateModel(_tx, _ty, _tz, _rx = 0, _ry = 0, _rz = 0, s = 1) {
|
||||
if (!this.tileset.root.transform) {
|
||||
if (window.ELEMENT) {
|
||||
window.ELEMENT.Message.closeAll();
|
||||
window.ELEMENT.Message({
|
||||
message: '该模型不支持移动和旋转!',
|
||||
type: 'warning',
|
||||
duration: 1500
|
||||
});
|
||||
}
|
||||
console.warn('该模型不支持移动和旋转!')
|
||||
return
|
||||
}
|
||||
if ((!_tx && _tx!==0) || (!_ty && _ty!==0) || (!_tz && _tz!==0)) {
|
||||
return
|
||||
}
|
||||
let mx = Cesium.Matrix3.fromRotationX(
|
||||
Cesium.Math.toRadians(_rx)
|
||||
)
|
||||
let my = Cesium.Matrix3.fromRotationY(
|
||||
Cesium.Math.toRadians(_ry)
|
||||
)
|
||||
let mz = Cesium.Matrix3.fromRotationZ(
|
||||
Cesium.Math.toRadians(_rz)
|
||||
)
|
||||
// 平移
|
||||
let m = Cesium.Transforms.eastNorthUpToFixedFrame(new Cesium.Cartesian3.fromDegrees(_tx, _ty, _tz))
|
||||
// 旋转
|
||||
let rotationX = Cesium.Matrix4.fromRotationTranslation(mx)
|
||||
let rotationY = Cesium.Matrix4.fromRotationTranslation(my)
|
||||
let rotationZ = Cesium.Matrix4.fromRotationTranslation(mz)
|
||||
let originalMatrix = new Cesium.Matrix4()
|
||||
Cesium.Matrix4.multiply(m, rotationX, originalMatrix)
|
||||
Cesium.Matrix4.multiply(originalMatrix, rotationY, originalMatrix)
|
||||
Cesium.Matrix4.multiply(originalMatrix, rotationZ, originalMatrix)
|
||||
const scale = Cesium.Matrix4.fromUniformScale(s);
|
||||
Cesium.Matrix4.multiply(originalMatrix, scale, this.entity._root.transform)
|
||||
// console.log(_tx, _ty, _tz)
|
||||
if (!this.editObj.activeAxis) {
|
||||
this.editObj.position = { lng: _tx, lat: _ty, alt: _tz }
|
||||
}
|
||||
if (!this.editObj.activeCircle) {
|
||||
this.editObj.rotate = { x: _rx, y: _ry, z: _rz }
|
||||
}
|
||||
this.editObj && this.editObj.update()
|
||||
|
||||
clearTimeout(this.#updateModelTimeout)
|
||||
this.#updateModelTimeout = setTimeout(() => {
|
||||
clearTimeout(this.#updateModelTimeout)
|
||||
let center = this.cartesian3Towgs84(this.entity.boundingSphere.center, this.sdk.viewer)
|
||||
let circle = turf.circle([center.lng, center.lat], this.entity.boundingSphere.radius / 1000, { steps: 360, units: 'kilometers' });
|
||||
for (let [key, entity] of this.sdk.entityMap) {
|
||||
if (entity.type === 'BillboardObject' && entity.heightMode == 3) {
|
||||
let pt = turf.point([entity.lng, entity.lat]);
|
||||
if (turf.booleanPointInPolygon(pt, circle)) {
|
||||
entity.updateHeight()
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (entity.label) {
|
||||
entity.label.show = entity.label.show
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
|
||||
// flyTo() {
|
||||
// this.entity.readyPromise.then(() => {
|
||||
// console.log(this.entity)
|
||||
// let boundingSphere
|
||||
// if(!this.lng || !this.lat) {
|
||||
// boundingSphere = new Cesium.BoundingSphere(this.entity.boundingSphere)
|
||||
// }
|
||||
// else {
|
||||
// boundingSphere = new Cesium.BoundingSphere(Cesium.Cartesian3.fromDegrees(this.lng, this.lat, this.height), this.entity.boundingSphere.radius)
|
||||
// }
|
||||
// this.sdk.viewer.camera.flyToBoundingSphere(boundingSphere)
|
||||
// })
|
||||
// }
|
||||
|
||||
reset() {
|
||||
this.editObj.destroy()
|
||||
if (!this.entity) {
|
||||
return
|
||||
}
|
||||
this.transparency = this.oldData.transparency
|
||||
this.name = this.oldData.name
|
||||
this.height = this.oldData.height
|
||||
this.lng = this.oldData.lng
|
||||
this.lat = this.oldData.lat
|
||||
this.roll = this.oldData.roll
|
||||
this.heading = this.oldData.heading
|
||||
this.pitch = this.oldData.pitch
|
||||
this.scale = this.oldData.scale
|
||||
this.accuracy = this.oldData.accuracy
|
||||
|
||||
this.entity.style = new Cesium.Cesium3DTileStyle({
|
||||
color: {
|
||||
"conditions": [
|
||||
["Boolean(${SIZE})", "${COLOR} * color('rgba(255,255,255)', " + this.transparency + ")"],
|
||||
["true", "color('rgba(255,255,255," + this.transparency + ")')"]
|
||||
]
|
||||
},
|
||||
show: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default Tileset
|
||||
650
src/Obj/Base/BaseSource/BaseTileset/index.js
Normal file
650
src/Obj/Base/BaseSource/BaseTileset/index.js
Normal file
@ -0,0 +1,650 @@
|
||||
/**
|
||||
* @name: index
|
||||
* @author: Administrator
|
||||
* @date: 2023-11-20 17:54
|
||||
* @description:index
|
||||
* @update: 2023-11-20 17:54
|
||||
*/
|
||||
import { getHost } from "../../../../on";
|
||||
import BaseSource from "../index";
|
||||
import { regLeftClickCallback, regRightClickCallback, regMoveCallback } from "../../../../Global/ClickCallback";
|
||||
import Controller from "../../../../Controller/index";
|
||||
import { syncData } from '../../../../Global/MultiViewportMode'
|
||||
import { setSplitDirection, syncSplitData, setActiveId } from '../../../../Global/SplitScreen'
|
||||
|
||||
class BaseTileset extends BaseSource {
|
||||
#updateModelTimeout;
|
||||
/**
|
||||
* @constructor
|
||||
* @param sdk
|
||||
* @description 模型
|
||||
* @param options {object}
|
||||
* @param options.id{string} id
|
||||
* @param options.name{string} 名称
|
||||
* @param options.url{string} 模型地址
|
||||
* @param options.lng{number} 经度
|
||||
* @param options.lat{number} 纬度
|
||||
* @param options.height=0{number} 高度
|
||||
* @param options.scale=1{number} 模型比例
|
||||
* @param options.roll=0{number} 模型x旋转
|
||||
* @param options.heading=0{number} 模型z轴旋转角度
|
||||
* @param options.pitch=0{number} 模型y轴旋转角度
|
||||
* */
|
||||
constructor(sdk, options) {
|
||||
super(sdk, options);
|
||||
this.setDefaultValue()
|
||||
this.watchs = []
|
||||
this.positionCallBack = null
|
||||
this.rotationCallback = null
|
||||
this.onClickCallback = null
|
||||
this._DialogObject = null
|
||||
this._element_style = null
|
||||
this.options.accuracy = options.accuracy ? Number(options.accuracy.toFixed(1)) : 1
|
||||
this.options.position = this.options.position || {}
|
||||
this.oldData = {
|
||||
id: this.options.id,
|
||||
transparency: (this.options.transparency || this.options.transparency === 0) ? this.options.transparency : 1,
|
||||
name: this.options.name,
|
||||
accuracy: this.options.accuracy,
|
||||
url: this.options.url,
|
||||
height: this.options.position.alt || 0,
|
||||
lng: this.options.position.lng,
|
||||
lat: this.options.position.lat,
|
||||
scale: (this.options.scale || this.options.scale === 0) ? this.options.scale : 1,
|
||||
roll: this.options.roll || 0,
|
||||
heading: this.options.heading || 0,
|
||||
pitch: this.options.pitch || 0
|
||||
}
|
||||
this.newData = {
|
||||
id: this.options.id,
|
||||
transparency: (this.options.transparency || this.options.transparency === 0) ? this.options.transparency : 1,
|
||||
name: this.options.name,
|
||||
accuracy: this.options.accuracy,
|
||||
url: this.options.url,
|
||||
height: this.options.position.alt || 0,
|
||||
lng: this.options.position.lng,
|
||||
lat: this.options.position.lat,
|
||||
scale: (this.options.scale || this.options.scale === 0) ? this.options.scale : 1,
|
||||
roll: this.options.roll || 0,
|
||||
heading: this.options.heading || 0,
|
||||
pitch: this.options.pitch || 0
|
||||
}
|
||||
this.tileset = undefined
|
||||
this.editObj = new Controller(this.sdk)
|
||||
this.editObj.controllerCallBack = this.rotationEditingCallBack
|
||||
}
|
||||
|
||||
async add() {
|
||||
if (this.options.url) {
|
||||
return this.loadTileset({
|
||||
url: this.options.url
|
||||
})
|
||||
} else {
|
||||
let res = await this.requestResource()
|
||||
let text = await res.text()
|
||||
text = JSON.parse(text)
|
||||
if ([0, 200].includes(text.code)) {
|
||||
if (text.data.url.length)
|
||||
return this.loadTileset(text.data)
|
||||
else
|
||||
return new Promise((res, reject) => {
|
||||
reject('资源不存在')
|
||||
})
|
||||
} else {
|
||||
return new Promise((res, reject) => {
|
||||
reject(text.msg || text.message)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
loadSceneTree() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
async loadTileset(options) {
|
||||
let object = { ...options }
|
||||
let url = ""
|
||||
if (object.url.startsWith("http"))
|
||||
url = object.url
|
||||
else {
|
||||
//说明是本地的json,在磁盘中存在的
|
||||
if (object.url.includes(":")) {
|
||||
url = object.url
|
||||
} else {
|
||||
if (this.options.host) {
|
||||
let o = new URL(object.url, this.options.host)
|
||||
url = o.href
|
||||
} else
|
||||
url = object.url
|
||||
}
|
||||
}
|
||||
|
||||
let response = await fetch(url, {
|
||||
method: 'get',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
}
|
||||
})
|
||||
if (response.status === 200) {
|
||||
this.tileset = await response.json()
|
||||
}
|
||||
let params = {
|
||||
show: this.options.show,
|
||||
skipLevelOfDetail: true,
|
||||
baseScreenSpaceError: 1024,
|
||||
maximumScreenSpaceError: 32, // 数值加大,能让最终成像变模糊
|
||||
skipScreenSpaceErrorFactor: 16,
|
||||
skipLevels: 1,
|
||||
immediatelyLoadDesiredLevelOfDetail: false,
|
||||
loadSiblings: true, // 如果为true则不会在已加载完概况房屋后,自动从中心开始超清化房屋
|
||||
cullWithChildrenBounds: true,
|
||||
cullRequestsWhileMoving: true,
|
||||
cullRequestsWhileMovingMultiplier: 10, // 值越小能够更快的剔除
|
||||
preloadWhenHidden: false,
|
||||
preferLeaves: true,
|
||||
maximumCacheOverflowBytes: 128, // 内存分配变小有利于倾斜摄影数据回收,提升性能体验
|
||||
progressiveResolutionHeightFraction: 0.5, // 数值偏于0能够让初始加载变得模糊
|
||||
dynamicScreenSpaceErrorDensity: 0.1, // 数值加大,能让周边加载变快
|
||||
dynamicScreenSpaceErrorFactor: 1,
|
||||
dynamicScreenSpaceError: true // 有了这个后,会在真正的全屏加载完之后才清晰化房屋
|
||||
}
|
||||
let tileset
|
||||
if (Number(Cesium.VERSION.split('.')[1]) >= 107) {
|
||||
tileset = await Cesium.Cesium3DTileset.fromUrl(url, params);
|
||||
this.entity = tileset
|
||||
this.entity.imageBasedLighting.luminanceAtZenith = 0.1
|
||||
}
|
||||
else {
|
||||
params.url = url
|
||||
tileset = new Cesium.Cesium3DTileset(params);
|
||||
this.entity = await tileset.readyPromise
|
||||
this.entity.imageBasedLighting.luminanceAtZenith = 0.1
|
||||
}
|
||||
|
||||
// syncData(this.sdk, this.options.id)
|
||||
|
||||
|
||||
await this.loadSceneTree(url)
|
||||
const initData = (tile) => {
|
||||
if (tile._contents) {
|
||||
for (let i = 0; i < tile._contents.length; i++) {
|
||||
initData(tile._contents[i])
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (let i = 0; i < tile.featuresLength; i++) {
|
||||
let feature = tile.getFeature(i)
|
||||
let file = feature.content.url
|
||||
let id = feature.getProperty('id')
|
||||
if (this.features.has(id)) {
|
||||
if (this.features.get(id).features) {
|
||||
if (this.features.get(id).features[file]) {
|
||||
// feature = this.features.get(id).features[feature.featureId]
|
||||
if (this.features.get(id).features[file].customColor) {
|
||||
feature.color = this.features.get(id).features[file].customColor
|
||||
feature.customColor = this.features.get(id).features[file].customColor
|
||||
}
|
||||
if (this.features.get(id).features[file].customAlpha) {
|
||||
let color = feature.color
|
||||
feature.color = Cesium.Color.fromCssColorString(`rgba(${Cesium.Color.floatToByte(color.red)},${Cesium.Color.floatToByte(color.green)},${Cesium.Color.floatToByte(color.blue)},${this.features.get(id).features[file].customAlpha})`)
|
||||
feature.customAlpha = this.features.get(id).features[file].customAlpha
|
||||
}
|
||||
if (this.features.get(id).features[file].customShow) {
|
||||
feature.show = this.features.get(id).features[file].customShow
|
||||
feature.customShow = this.features.get(id).features[file].customShow
|
||||
}
|
||||
}
|
||||
this.features.get(id).features[file] = feature
|
||||
}
|
||||
else {
|
||||
let object = {}
|
||||
if (this.features.get(id).customColor) {
|
||||
feature.color = this.features.get(id).customColor
|
||||
feature.customColor = this.features.get(id).customColor
|
||||
}
|
||||
if (this.features.get(id).customAlpha) {
|
||||
let color = feature.color
|
||||
feature.color = Cesium.Color.fromCssColorString(`rgba(${Cesium.Color.floatToByte(color.red)},${Cesium.Color.floatToByte(color.green)},${Cesium.Color.floatToByte(color.blue)},${this.features.get(id).customAlpha})`)
|
||||
feature.customAlpha = this.features.get(id).customAlpha
|
||||
}
|
||||
if (this.features.get(id).customShow) {
|
||||
feature.show = this.features.get(id).customShow
|
||||
feature.customShow = this.features.get(id).customShow
|
||||
}
|
||||
object[file] = feature
|
||||
this.features.get(id).features = object
|
||||
}
|
||||
}
|
||||
else {
|
||||
let object = {}
|
||||
object[file] = feature
|
||||
this.features.set(id, { features: object })
|
||||
}
|
||||
if (!feature.customColor) {
|
||||
feature.customColor = Cesium.Color.fromCssColorString('#ffffff')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// for (let i = 0; i < tile._content.featuresLength; i++) {
|
||||
// let feature = tile._content.getFeature(i)
|
||||
// feature.show = false
|
||||
// }
|
||||
// if (tile._content._contents) {
|
||||
// for (let i = 0; i < tile._content._contents.length; i++) {
|
||||
// for (let m = 0; m < tile._content._contents[i].featuresLength; m++) {
|
||||
// let feature = tile._content._contents[i].getFeature(m)
|
||||
// feature.show = false
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
if (!this.sdk || !this.sdk.viewer || !this.sdk.viewer.scene) {
|
||||
return
|
||||
}
|
||||
tileset.tileLoad.addEventListener(tile => {
|
||||
// this.test()
|
||||
initData(tile._content)
|
||||
|
||||
clearTimeout(this.#updateModelTimeout)
|
||||
this.#updateModelTimeout = setTimeout(() => {
|
||||
clearTimeout(this.#updateModelTimeout)
|
||||
let center = this.cartesian3Towgs84(tileset.boundingSphere.center, this.sdk.viewer)
|
||||
let circle = turf.circle([center.lng, center.lat], tileset.boundingSphere.radius / 1000, { steps: 360, units: 'kilometers' });
|
||||
for (let [key, entity] of this.sdk.entityMap) {
|
||||
if (entity.type === 'BillboardObject' && entity.heightMode == 3) {
|
||||
let pt = turf.point([entity.lng, entity.lat]);
|
||||
if (turf.booleanPointInPolygon(pt, circle)) {
|
||||
entity.updateHeight()
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (entity.label) {
|
||||
entity.label.show = entity.label.show
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 500);
|
||||
|
||||
// if (tile._content._contents) {
|
||||
// for (let i = 0; i < tile._content._contents.length; i++) {
|
||||
// for (let m = 0; m < tile._content._contents[i].featuresLength; m++) {
|
||||
// let feature = tile._content._contents[i].getFeature(m)
|
||||
// console.log(feature)
|
||||
// feature.show = false
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// for (let i = 0; i < tile._content.featuresLength; i++) {
|
||||
// let feature = tile._content.getFeature(i)
|
||||
// let file = feature.content.url
|
||||
// let id = feature.getProperty('id')
|
||||
// if (this.features.has(id)) {
|
||||
// if (this.features.get(id).features) {
|
||||
// if (this.features.get(id).features[file]) {
|
||||
// // feature = this.features.get(id).features[feature.featureId]
|
||||
// if (this.features.get(id).features[file].customColor) {
|
||||
// feature.color = this.features.get(id).features[file].customColor
|
||||
// feature.customColor = this.features.get(id).features[file].customColor
|
||||
// }
|
||||
// if (this.features.get(id).features[file].customAlpha) {
|
||||
// let color = feature.color
|
||||
// feature.color = Cesium.Color.fromCssColorString(`rgba(${Cesium.Color.floatToByte(color.red)},${Cesium.Color.floatToByte(color.green)},${Cesium.Color.floatToByte(color.blue)},${this.features.get(id).features[file].customAlpha})`)
|
||||
// feature.customAlpha = this.features.get(id).features[file].customAlpha
|
||||
// }
|
||||
// if (this.features.get(id).features[file].customShow) {
|
||||
// feature.show = this.features.get(id).features[file].customShow
|
||||
// feature.customShow = this.features.get(id).features[file].customShow
|
||||
// }
|
||||
|
||||
|
||||
// }
|
||||
// this.features.get(id).features[file] = feature
|
||||
// }
|
||||
// else {
|
||||
// let object = {}
|
||||
// object[file] = feature
|
||||
// this.features.get(id).features = object
|
||||
// }
|
||||
// }
|
||||
// else {
|
||||
// let object = {}
|
||||
// object[file] = feature
|
||||
// this.features.set(id, { features: object })
|
||||
// }
|
||||
// if (!feature.customColor) {
|
||||
// feature.customColor = Cesium.Color.fromCssColorString('#ffffff')
|
||||
// }
|
||||
// }
|
||||
})
|
||||
// // console.log(tileset)
|
||||
// if (this.type === 'bim') {
|
||||
// const setTilesetStyle = (f) => {
|
||||
// if (tileset.style) {
|
||||
// // tileset.style = new Cesium.Cesium3DTileStyle({
|
||||
// // color: {
|
||||
// // conditions: [
|
||||
// // ['${name} ==="对象074" ', 'color("red")'], //符合条件项
|
||||
// // ['true', 'rgba(255,255,255,1)'] //其他项
|
||||
// // ]
|
||||
// // }
|
||||
// // })
|
||||
// // tileset.tileLoad.removeEventListener(setTilesetStyle)
|
||||
// }
|
||||
// console.log(f)
|
||||
// }
|
||||
// tileset.tileLoad.addEventListener(setTilesetStyle)
|
||||
// }
|
||||
|
||||
this.entity._root.originalTransform = { ...this.entity._root.transform }
|
||||
this.entity.id = this.options.id || this.randomString()
|
||||
this.entity.type = this.type
|
||||
// this.editObj = new EditB3DM(this.sdk, this.entity)
|
||||
|
||||
this.sdk.viewer.scene.primitives.add(tileset);
|
||||
if (this.options.position && JSON.stringify(this.options.position) != "{}"
|
||||
&& (this.options.position.lng || this.options.position.lng === 0) && (this.options.position.lat || this.options.position.lat === 0)) {
|
||||
this.options.position.alt == this.options.position.alt || 0
|
||||
let cartographic = Cesium.Cartographic.fromCartesian(this.entity.boundingSphere.center);
|
||||
if (this.tileset.root.transform) {
|
||||
cartographic = Cesium.Cartographic.fromCartesian({ x: this.tileset.root.transform[12], y: this.tileset.root.transform[13], z: this.tileset.root.transform[14] })
|
||||
}
|
||||
this.entity.original = {
|
||||
lng: Cesium.Math.toDegrees(cartographic.longitude), // 经度
|
||||
lat: Cesium.Math.toDegrees(cartographic.latitude), // 纬度
|
||||
height: cartographic.height
|
||||
}
|
||||
let m = Cesium.Transforms.eastNorthUpToFixedFrame(new Cesium.Cartesian3.fromDegrees(this.options.position.lng, this.options.position.lat, this.options.position.alt))
|
||||
const scale = Cesium.Matrix4.fromUniformScale(this.oldData.scale);
|
||||
if (this.tileset.root.transform) {
|
||||
Cesium.Matrix4.multiply(m, scale, this.entity._root.transform)
|
||||
}
|
||||
this.lng = this.oldData.lng
|
||||
this.lat = this.oldData.lat
|
||||
this.height = this.oldData.height
|
||||
}
|
||||
else {
|
||||
this.options.position = {}
|
||||
let cartographic = Cesium.Cartographic.fromCartesian(this.entity.boundingSphere.center);
|
||||
if (this.tileset.root.transform) {
|
||||
cartographic = Cesium.Cartographic.fromCartesian({ x: this.tileset.root.transform[12], y: this.tileset.root.transform[13], z: this.tileset.root.transform[14] })
|
||||
}
|
||||
this.entity.original = {
|
||||
lng: Cesium.Math.toDegrees(cartographic.longitude),
|
||||
lat: this.oldData.lat = Cesium.Math.toDegrees(cartographic.latitude),
|
||||
height: cartographic.height,
|
||||
}
|
||||
this.lng = this.oldData.lng = Cesium.Math.toDegrees(cartographic.longitude); // 经度
|
||||
this.lat = this.oldData.lat = Cesium.Math.toDegrees(cartographic.latitude); // 纬度
|
||||
this.height = this.oldData.height = cartographic.height; // 高度
|
||||
|
||||
}
|
||||
|
||||
this.scale = this.oldData.scale
|
||||
this.roll = this.oldData.roll
|
||||
this.heading = this.oldData.heading
|
||||
this.pitch = this.oldData.pitch
|
||||
this.transparency = this.oldData.transparency
|
||||
|
||||
syncSplitData(this.sdk, this.options.id)
|
||||
|
||||
regMoveCallback(this.entity.id, this.mouseMoveCB, this)
|
||||
|
||||
|
||||
// this.entity = this.sdk.viewer.scene.primitives.add(tileset);
|
||||
// if (this.options.position && JSON.stringify(this.options.position) != "{}") {
|
||||
// let m = Cesium.Transforms.eastNorthUpToFixedFrame(new Cesium.Cartesian3.fromDegrees(this.options.position.lng, this.options.position.lat, this.options.position.alt))
|
||||
// const scale = Cesium.Matrix4.fromUniformScale(this.oldData.scale);
|
||||
// Cesium.Matrix4.multiply(m, scale, this.entity._root.transform)
|
||||
// }
|
||||
// else {
|
||||
// this.options.position = {}
|
||||
// }
|
||||
// this.lng = this.oldData.lng
|
||||
// this.lat = this.oldData.lat
|
||||
// this.height = this.oldData.height
|
||||
// this.scale = this.oldData.scale
|
||||
// this.roll = this.oldData.roll
|
||||
// this.heading = this.oldData.heading
|
||||
// this.pitch = this.oldData.pitch
|
||||
// this.transparency = this.oldData.transparency
|
||||
|
||||
// regMoveCallback(this.entity.id, this.mouseMoveCB, this)
|
||||
|
||||
// this.editObj = new EditB3DM(this.sdk, this.entity)
|
||||
// this.editObj.transformCallBack = this.rotationEditingCallBack
|
||||
// tileset.readyPromise.then(() => {
|
||||
// this.entity = this.sdk.viewer.scene.primitives.add(tileset);
|
||||
|
||||
// })
|
||||
// let x = this.sdk.viewer.scene.primitives.add(new Cesium.Cesium3DTileset({
|
||||
// url: url
|
||||
// }));
|
||||
// setTimeout(() => {
|
||||
// console.log(x)
|
||||
// this.sdk.viewer.flyTo(this.entity)
|
||||
// }, 3000);
|
||||
}
|
||||
|
||||
// test() {
|
||||
// let heightstyle = new Cesium.Cesium3DTileStyle({
|
||||
// color: {
|
||||
// conditions: [
|
||||
// ["Number(${height})>=300", "rgba(45,0,75,0.5)"],
|
||||
// ["Number(${height})>=200", "rgb(102,71,151)"],
|
||||
// ["Number(${height})>=100", "rgb(170,162,204)"],
|
||||
// ["Number(${height})>=50", "rgb(224,226,238)"],
|
||||
// ["Number(${height})>=25", "rgb(252,230, 200)"],
|
||||
// ["Number(${height})>=10", "rgb(248,176,87)"],
|
||||
// ["Number(${height})>=5", "rgb(198, 106,11)"],
|
||||
// ["isNaN(Number(${height}))", "rgb(255, 255, 255)"],
|
||||
// ["true", "rgb(127,59,8)"]
|
||||
// ]
|
||||
// }
|
||||
// });
|
||||
// this.entity.style = heightstyle;
|
||||
// }
|
||||
|
||||
|
||||
remove() {
|
||||
super.remove()
|
||||
this.editObj.destroy()
|
||||
this.sdk.viewer.scene.primitives.remove(this.entity);
|
||||
this.entity = null
|
||||
if (this._DialogObject) {
|
||||
this._DialogObject.close()
|
||||
this._DialogObject = null
|
||||
}
|
||||
}
|
||||
|
||||
flyTo() {
|
||||
super.flyTo()
|
||||
}
|
||||
|
||||
|
||||
on() {
|
||||
return this.add()
|
||||
}
|
||||
|
||||
setDefaultValue() {
|
||||
super.setDefaultValue()
|
||||
this.options.host = this.options.host || getHost()
|
||||
this.options.url = this.options.url || ""
|
||||
}
|
||||
|
||||
get position() {
|
||||
let cartographic = Cesium.Cartographic.fromCartesian(this.entity.boundingSphere.center);
|
||||
if (this.tileset.root.transform) {
|
||||
cartographic = Cesium.Cartographic.fromCartesian({ x: this.tileset.root.transform[12], y: this.tileset.root.transform[13], z: this.tileset.root.transform[14] })
|
||||
}
|
||||
let lng = Cesium.Math.toDegrees(cartographic.longitude + 0.00000000663814);
|
||||
let lat = Cesium.Math.toDegrees(cartographic.latitude + 0.00000025137835);
|
||||
if (this.newData.lng && this.newData.lat && this.newData.height) {
|
||||
return { lng: this.newData.lng, lat: this.newData.lat, height: this.newData.height }
|
||||
}
|
||||
else {
|
||||
return { lng: lng, lat: lat, height: cartographic.height - 2.19104611043234 }
|
||||
}
|
||||
}
|
||||
|
||||
set position(p) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @desc 打开模型旋转功能
|
||||
* @param status {boolean}
|
||||
* @methodOf Source
|
||||
* */
|
||||
set rotationEditing(status) {
|
||||
if (!this.tileset.root.transform) {
|
||||
if (window.ELEMENT) {
|
||||
window.ELEMENT.Message.closeAll();
|
||||
window.ELEMENT.Message({
|
||||
message: '该模型不支持移动和旋转!',
|
||||
type: 'warning',
|
||||
duration: 1500
|
||||
});
|
||||
}
|
||||
console.warn('该模型不支持移动和旋转!')
|
||||
return
|
||||
}
|
||||
if (status) {
|
||||
this.editObj.position = { lng: this.newData.lng, lat: this.newData.lat, alt: this.newData.height }
|
||||
this.editObj.update()
|
||||
this.editObj.editRtation()
|
||||
}
|
||||
else {
|
||||
this.editObj.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @desc 获取模型旋转状态
|
||||
* @method rotationEditing
|
||||
* @return boolean
|
||||
* @methodOf Source
|
||||
|
||||
* */
|
||||
get rotationEditing() {
|
||||
if (this.editObj.getActiveState() === 'rtation') {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**@desc 打开平移模型功能
|
||||
*
|
||||
* @memberOf Source
|
||||
*@param status {boolean}
|
||||
*
|
||||
* */
|
||||
set positionEditing(status) {
|
||||
if (!this.sdk || !this.sdk.viewer || !this.entity) {
|
||||
return
|
||||
}
|
||||
if (!this.tileset.root.transform) {
|
||||
if (window.ELEMENT) {
|
||||
window.ELEMENT.Message.closeAll();
|
||||
window.ELEMENT.Message({
|
||||
message: '该模型不支持移动和旋转!',
|
||||
type: 'warning',
|
||||
duration: 1500
|
||||
});
|
||||
}
|
||||
console.warn('该模型不支持移动和旋转!')
|
||||
return
|
||||
}
|
||||
if (status) {
|
||||
this.editObj.position = { lng: this.newData.lng, lat: this.newData.lat, alt: this.newData.height }
|
||||
this.editObj.update()
|
||||
this.editObj.editTranslational()
|
||||
}
|
||||
else {
|
||||
this.editObj.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
get positionEditing() {
|
||||
if (this.editObj.getActiveState() === 'translational') {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
//平移时,坐标信息变化的回调
|
||||
set positionEditingCallBack(callback) {
|
||||
return
|
||||
}
|
||||
|
||||
get positionEditingCallBack() {
|
||||
}
|
||||
|
||||
//旋转时,坐标信息变化的回调
|
||||
set rotationEditingCallBack(callback) {
|
||||
this._rotationEditingCallBack = callback
|
||||
}
|
||||
|
||||
get rotationEditingCallBack() {
|
||||
return (params, state) => {
|
||||
this.lng = params.position.lng
|
||||
this.lat = params.position.lat
|
||||
this.height = params.position.alt
|
||||
this.roll = params.rotate.x
|
||||
this.heading = params.rotate.y
|
||||
this.pitch = params.rotate.z
|
||||
// this._rotationEditingCallBack && this._rotationEditingCallBack(this.editObj._params)
|
||||
}
|
||||
}
|
||||
|
||||
flicker() { }
|
||||
|
||||
// 编辑框
|
||||
async edit(state) { }
|
||||
|
||||
get show() {
|
||||
return this.options.show
|
||||
}
|
||||
|
||||
set show(v) {
|
||||
if (typeof v === "boolean") {
|
||||
this.options.show = v
|
||||
this.entity && (this.entity.show = v)
|
||||
if (this._DialogObject && this._DialogObject.showBtn) {
|
||||
this._DialogObject.showBtn.checked = v
|
||||
}
|
||||
if (this.options.label && this.options.label.show && this.label) {
|
||||
this.label.show = v
|
||||
}
|
||||
setTimeout(() => {
|
||||
let center = this.cartesian3Towgs84(this.entity.boundingSphere.center, this.sdk.viewer)
|
||||
let circle = turf.circle([center.lng, center.lat], this.entity.boundingSphere.radius / 1000, { steps: 360, units: 'kilometers' });
|
||||
for (let [key, entity] of this.sdk.entityMap) {
|
||||
if (entity.type === 'BillboardObject' && entity.heightMode == 3) {
|
||||
let pt = turf.point([entity.lng, entity.lat]);
|
||||
if (turf.booleanPointInPolygon(pt, circle)) {
|
||||
entity.updateHeight()
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (entity.label) {
|
||||
entity.label.show = entity.label.show
|
||||
}
|
||||
}
|
||||
}
|
||||
syncData(this.sdk, this.options.id)
|
||||
syncSplitData(this.sdk, this.options.id)
|
||||
}, 300);
|
||||
} else {
|
||||
console.error("参数必须为boolean")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default BaseTileset
|
||||
45
src/Obj/Base/BaseSource/index.js
Normal file
45
src/Obj/Base/BaseSource/index.js
Normal file
@ -0,0 +1,45 @@
|
||||
/**
|
||||
* @name: index
|
||||
* @author: Administrator
|
||||
* @date: 2023-11-20 18:31
|
||||
* @description:index
|
||||
* @update: 2023-11-20 18:31
|
||||
*/
|
||||
import Base from "../index";
|
||||
import {getHost, getToken} from "../../../on";
|
||||
import { setSplitDirection } from "../../../Global/SplitScreen";
|
||||
|
||||
class BaseSource extends Base {
|
||||
constructor(sdk, options) {
|
||||
super(sdk, options);
|
||||
this.sdk.addIncetance(this.options.id, this)
|
||||
if (this.options.show) {
|
||||
setSplitDirection(0, this.options.id)
|
||||
}
|
||||
}
|
||||
|
||||
setDefaultValue() {
|
||||
super.setDefaultValue();
|
||||
this.options.host = this.options.host || getHost()
|
||||
}
|
||||
|
||||
requestResource() {
|
||||
let url = ""
|
||||
if (this.options.host.endsWith("yjearth4.0"))
|
||||
url = this.options.host + '/data/service/load-compact-service'
|
||||
else
|
||||
url = this.options.host + '/yjearth4.0/data/service/load-compact-service'
|
||||
return fetch(url, {
|
||||
method: 'post',
|
||||
body: JSON.stringify({source_id: this.options.id}),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
"token": getToken(),
|
||||
"Authorization": "Bearer " + getToken(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default BaseSource
|
||||
335
src/Obj/Base/BillboardObject/_element.js
Normal file
335
src/Obj/Base/BillboardObject/_element.js
Normal file
@ -0,0 +1,335 @@
|
||||
import { attributeElm } from '../../Element/elm_html'
|
||||
|
||||
function html(that) {
|
||||
return `
|
||||
<span class="custom-divider"></span>
|
||||
<div class="div-item">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label" style="flex: unset;">名称</span>
|
||||
<input class="input" type="text" @model="labelText">
|
||||
</div>
|
||||
<div class="col">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="custom-divider"></span>
|
||||
<div class="div-item">
|
||||
<div class="row">
|
||||
<div style="width: 46%;">
|
||||
<div class="row">
|
||||
<p class="lable-left-line">WGS84坐标</p>
|
||||
</div>
|
||||
<div class="row" style="margin-bottom: 5px;">
|
||||
<div class="col">
|
||||
<span class="label">经度</span>
|
||||
<input class="input" type="number" title="" min="-180" max="180" @model="lng">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" style="margin-bottom: 5px;">
|
||||
<div class="col">
|
||||
<span class="label">纬度</span>
|
||||
<input class="input" type="number" title="" min="-90" max="90" @model="lat">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">海拔高度</span>
|
||||
<div class="input-number input-number-unit-1 alt-box">
|
||||
<input class="input" type="number" title="" min="-9999999" max="999999999" @model="alt">
|
||||
<span class="unit">m</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="width: 50%;">
|
||||
<div class="row coordinate-select-box">
|
||||
<div class="lable-left-line">转换坐标选择
|
||||
<div class="input input-select coordinate-select" style="margin-left: 20px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" style="margin-bottom: 5px;">
|
||||
<div class="col">
|
||||
<span class="label">X轴:</span>
|
||||
<input style="border: none;background: none;" class="input convert-x" readonly="readonly">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" style="margin-bottom: 5px;">
|
||||
<div class="col">
|
||||
<span class="label">Y轴:</span>
|
||||
<input style="border: none;background: none;" class="input convert-y" readonly="readonly">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">Z轴:</span>
|
||||
<input style="border: none;background: none;" class="input convert-z" readonly="readonly">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="custom-divider"></span>
|
||||
<div class="div-item">
|
||||
<div class="row">
|
||||
<div class="col" style="flex: 0 0 120px;">
|
||||
<span class="label">视野缩放</span>
|
||||
<input class="btn-switch" type="checkbox" @model="scaleByDistance">
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">最近距离</span>
|
||||
<div class="input-number input-number-unit-1">
|
||||
<input class="input" type="number" title="" min="1" max="99999999" @model="near">
|
||||
<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-1">
|
||||
<input class="input" type="number" title="" min="1" max="99999999" @model="far">
|
||||
<span class="unit">m</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<DIV-cy-tabs id="point-object-edit-tabs">
|
||||
<DIV-cy-tab-pane label="属性信息">
|
||||
${attributeElm(that)}
|
||||
</DIV-cy-tab-pane>
|
||||
<DIV-cy-tab-pane label="空间信息">
|
||||
<div class="row">
|
||||
<div class="col height-mode-box">
|
||||
<span class="label" style="flex: 0 0 56px;">高度模式</span>
|
||||
<div class="height-mode"></div>
|
||||
</div>
|
||||
<div class="col height-box">
|
||||
<span class="label" style="flex: 0 0 56px;">高度</span>
|
||||
<div class="input-number input-number-unit-1">
|
||||
<input class="input height" type="number" title="" min="-9999999" max="999999999">
|
||||
<span class="unit">m</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="YJ-custom-checkbox-box" style="display: flex;align-items: center;cursor: pointer;">
|
||||
<input type="checkbox" class="YJ-custom-checkbox">
|
||||
<span style="margin-left: 10px; margin-bottom: 1px;user-select: none;">小数格式</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="YJ-custom-checkbox-box" style="display: flex;align-items: center;cursor: pointer;">
|
||||
<input type="checkbox" class="YJ-custom-checkbox">
|
||||
<span style="margin-left: 10px; margin-bottom: 1px;user-select: none;">度分格式</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="YJ-custom-checkbox-box" style="display: flex;align-items: center;cursor: pointer;">
|
||||
<input type="checkbox" class="YJ-custom-checkbox">
|
||||
<span style="margin-left: 10px; margin-bottom: 1px;user-select: none;">度分秒格式</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div style="flex: 1;">
|
||||
<div class="proj-input-box">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span style="flex: 0 0 40px;">经度</span>
|
||||
<input class="input lng" readonly="readonly">
|
||||
</div>
|
||||
<div class="col">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span style="flex: 0 0 40px;">纬度</span>
|
||||
<input class="input lat" readonly="readonly">
|
||||
</div>
|
||||
<div class="col">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="proj-input-box" style="width: 56%;">
|
||||
<div class="row">
|
||||
<div class="col" style="flex-direction: column;">
|
||||
<div class="row" style="margin-bottom: 15px;">
|
||||
<span style="flex: 0 0 40px;">经度</span>
|
||||
<input class="input lng-dm-d" style="flex: 1;" readonly="readonly">
|
||||
<span class="label" style="flex: 0 0 14px;margin: 0 10px;">度</span>
|
||||
<input class="input lng-dm-m" style="flex: 1;" readonly="readonly">
|
||||
<span class="label" style="flex: 0 0 14px;margin: 0 10px;">分</span>
|
||||
<span class="top-line"></span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span style="flex: 0 0 40px;">纬度</span>
|
||||
<input class="input lat-dm-d" style="flex: 1;" readonly="readonly">
|
||||
<span class="label" style="flex: 0 0 14px;margin: 0 10px;">度</span>
|
||||
<input class="input lat-dm-m" style="flex: 1;" readonly="readonly">
|
||||
<span class="label" style="flex: 0 0 14px;margin: 0 10px;">分</span>
|
||||
<span class="bottom-line"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="proj-input-box" style="width: 70%;">
|
||||
<div class="row">
|
||||
<div class="col" style="flex-direction: column;">
|
||||
<div class="row" style="margin-bottom: 15px;">
|
||||
<span style="flex: 0 0 40px;">经度</span>
|
||||
<input class="input lng-dms-d" style="flex: 1;" readonly="readonly">
|
||||
<span class="label" style="flex: 0 0 14px;margin: 0 10px;">度</span>
|
||||
<input class="input lng-dms-m" style="flex: 1;" readonly="readonly">
|
||||
<span class="label" style="flex: 0 0 14px;margin: 0 10px;">分</span>
|
||||
<input class="input lng-dms-s" style="flex: 1;" readonly="readonly">
|
||||
<span class="label" style="flex: 0 0 14px;margin: 0 10px;">秒</span>
|
||||
<span class="top-line"></span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span style="flex: 0 0 40px;">纬度</span>
|
||||
<input class="input lat-dms-d" style="flex: 1;" readonly="readonly">
|
||||
<span class="label" style="flex: 0 0 14px;margin: 0 10px;">度</span>
|
||||
<input class="input lat-dms-m" style="flex: 1;" readonly="readonly">
|
||||
<span class="label" style="flex: 0 0 14px;margin: 0 10px;">分</span>
|
||||
<input class="input lat-dms-s" style="flex: 1;" readonly="readonly">
|
||||
<span class="label" style="flex: 0 0 14px;margin: 0 10px;">秒</span>
|
||||
<span class="bottom-line"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DIV-cy-tab-pane>
|
||||
<DIV-cy-tab-pane label="标注风格">
|
||||
<div>
|
||||
<h4>图标设置</h4>
|
||||
<div class="row" style="margin-bottom: 10px;">
|
||||
<div class="col" style="flex: 0 0 80px;">
|
||||
<span class="label" style="flex: none;">显隐</span>
|
||||
<input class="btn-switch" type="checkbox" @model="billboardShow">
|
||||
</div>
|
||||
<div class="col" style="flex: 0 0 90px;">
|
||||
<span class="label" style="flex: none;">图标</span>
|
||||
<div class="image-box" @click="clickChangeImage">
|
||||
<img class="image" src="" alt="" @model="billboardImage">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col" style="flex: 0 0 90px;">
|
||||
<span class="label" style="flex: none;">默认图标</span>
|
||||
<div class="image-box" @click="clickChangeDefaultImage">
|
||||
<img class="image" src="" alt="" @model="billboardDefaultImage">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">图标倍数</span>
|
||||
<div class="input-number input-number-unit-2">
|
||||
<input class="input" type="number" title="" min="0.1" max="99" @model="billboardScale">
|
||||
<span class="unit">倍</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4>文字设置</h4>
|
||||
<div class="row">
|
||||
<div class="col" style="flex: 0 0 80px;">
|
||||
<span class="label" style="flex: none;">显隐</span>
|
||||
<input class="btn-switch" type="checkbox" @model="labelShow">
|
||||
</div>
|
||||
<div class="col font-select-box">
|
||||
<span class="label" style="flex: none;">字体选择</span>
|
||||
<div class="input input-select font-select"></div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">文字大小</span>
|
||||
<div class="input-number input-number-unit-2">
|
||||
<input class="input" type="number" title="" min="1" max="99" @model="labelFontSize" style="width: 70px;">
|
||||
<span class="unit">px</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">文字颜色</span>
|
||||
<div class="labelColor"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DIV-cy-tab-pane>
|
||||
<!-- <DIV-cy-tab-pane label="效果">
|
||||
<div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">扩散</span>
|
||||
<input class="btn-switch" type="checkbox" @model="diffuseShow">
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">半径</span>
|
||||
<input class="input" type="number" title="" min="0" max="9999999" @model="diffuseRadius">
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">时间</span>
|
||||
<input class="input" type="number" title="" min="100" max="99999" @model="diffuseDuration">
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">颜色</span>
|
||||
<div class="diffuseColor"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">雷达</span>
|
||||
<input class="btn-switch" type="checkbox" @model="scanShow">
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">半径</span>
|
||||
<input class="input" type="number" title="" min="0" max="9999999" @model="scanRadius">
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">时间</span>
|
||||
<input class="input" type="number" title="" min="100" max="99999" @model="scanDuration">
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">颜色</span>
|
||||
<div class="scanColor"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DIV-cy-tab-pane>-->
|
||||
<!-- <DIV-cy-tab-pane label="灯光控制">-->
|
||||
<!-- <div>-->
|
||||
<!-- <div class="row">-->
|
||||
<!-- <div class="col">-->
|
||||
<!-- <span class="label">指令</span>-->
|
||||
<!-- <input class="input" type="text" @model="instruct">-->
|
||||
<!-- <button class="primary" @click="instructSubmit">提交</button>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </DIV-cy-tab-pane>-->
|
||||
<!-- <DIV-cy-tab-pane label="设置操作点">-->
|
||||
<!-- <div>-->
|
||||
<!-- <div class="row">-->
|
||||
<!-- <div class="col">-->
|
||||
<!-- <span class="label">设置操作点</span>-->
|
||||
<!-- <input class="input" type="text" @model="operatingPoint">-->
|
||||
<!-- <button class="primary" @click="operatingPointSubmit">提交</button>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </DIV-cy-tab-pane>-->
|
||||
</DIV-cy-tabs>
|
||||
</div>
|
||||
<span class="custom-divider"></span>
|
||||
`
|
||||
}
|
||||
|
||||
export { html }
|
||||
2619
src/Obj/Base/BillboardObject/index.js
Normal file
2619
src/Obj/Base/BillboardObject/index.js
Normal file
File diff suppressed because it is too large
Load Diff
85
src/Obj/Base/CircleDiffuse/_element.js
Normal file
85
src/Obj/Base/CircleDiffuse/_element.js
Normal file
@ -0,0 +1,85 @@
|
||||
import { attributeElm, labelStyleElm1, labelStyleElm2 } from '../../Element/elm_html'
|
||||
|
||||
function html(that) {
|
||||
return `
|
||||
<span class="custom-divider"></span>
|
||||
<div class="div-item">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">名称</span>
|
||||
<input class="input" maxlength="40" type="text" @model="name">
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">透明度</span>
|
||||
<input type="range" min="0" max="1" step="0.01" @model="transparency">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="custom-divider"></span>
|
||||
<div class="div-item">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">经度</span>
|
||||
<input class="input" type="number" title="" min="-180" max="180" @model="lng">
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">波纹层数</span>
|
||||
<div class="input-number input-number-unit">
|
||||
<input class="input" type="number" title="" min="1" max="10" @model="count">
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">纬度</span>
|
||||
<input class="input" type="number" title="" min="-180" max="180" @model="lat">
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">扩散速度</span>
|
||||
<div class="input-number input-number-unit">
|
||||
<input class="input" type="number" title="" min="0" max="20" @model="speed">
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="custom-divider"></span>
|
||||
<div class="div-item">
|
||||
<div class="row">
|
||||
<div class="col input-radius-unit-box" style="margin: 0;">
|
||||
<span class="label">半径单位</span>
|
||||
<div class="input-radius-unit"></div>
|
||||
</div>
|
||||
<div class="col" style="margin: 0;">
|
||||
</div>
|
||||
<div class="col" style="margin: 0;">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row circle-content-box">
|
||||
<div class="col">
|
||||
<span class="label"></span>
|
||||
<input class="input" type="number" title="" min="-180" max="180" @model="lat">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="div-item">
|
||||
<div class="row">
|
||||
<DIV-cy-tabs id="circle-diffuse-edit-tabs">
|
||||
<DIV-cy-tab-pane label="属性信息">
|
||||
${attributeElm(that)}
|
||||
</DIV-cy-tab-pane>
|
||||
<DIV-cy-tab-pane label="标注风格">
|
||||
${labelStyleElm1()}
|
||||
</DIV-cy-tab-pane>
|
||||
<DIV-cy-tab-pane label="标签风格">
|
||||
${labelStyleElm2()}
|
||||
</DIV-cy-tab-pane>
|
||||
</DIV-cy-tabs>
|
||||
</div>
|
||||
</div>
|
||||
<span class="custom-divider"></span>
|
||||
`
|
||||
}
|
||||
|
||||
export { html }
|
||||
1576
src/Obj/Base/CircleDiffuse/index.js
Normal file
1576
src/Obj/Base/CircleDiffuse/index.js
Normal file
File diff suppressed because it is too large
Load Diff
87
src/Obj/Base/CircleObject/_element.js
Normal file
87
src/Obj/Base/CircleObject/_element.js
Normal file
@ -0,0 +1,87 @@
|
||||
import { attributeElm, labelStyleElm1, labelStyleElm2 } from '../../Element/elm_html'
|
||||
|
||||
function html(that) {
|
||||
return `
|
||||
<div class="row" style="align-items: flex-start;">
|
||||
<div class="col">
|
||||
<span class="label">名称</span>
|
||||
<input class="input" maxlength="40" type="text" @model="name">
|
||||
</div>
|
||||
<div class="col" style="flex: 0 0 60%;">
|
||||
<div class="row">
|
||||
<div class="col input-select-unit-box">
|
||||
<span class="label" style="margin-right: 0px;">投影面积:</span>
|
||||
<input class="input input-text" readonly="readonly" type="text" @model="area">
|
||||
<div class="input-select-unit"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<DIV-cy-tabs id="circle-object-edit-tabs">
|
||||
<DIV-cy-tab-pane label="属性信息">
|
||||
${attributeElm(that)}
|
||||
</DIV-cy-tab-pane>
|
||||
<DIV-cy-tab-pane label="空间信息">
|
||||
<div class="row">
|
||||
<div class="col height-mode-box">
|
||||
<span class="label" style="flex: 0 0 56px;">高度模式</span>
|
||||
<div class="height-mode"></div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">Z值统一增加</span>
|
||||
<div class="input-number input-number-unit-1 height-box">
|
||||
<input class="input height" type="number" title="" min="-9999999" max="999999999">
|
||||
<span class="unit">m</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
<button class="confirm height-confirm" style="margin-left: 5px;">确认</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="table spatial-info-table">
|
||||
<div class="table-head">
|
||||
<div class="tr">
|
||||
<div class="th"></div>
|
||||
<div class="th">经度(X)</div>
|
||||
<div class="th">纬度(Y)</div>
|
||||
<div class="th">高度(Z)</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-body">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DIV-cy-tab-pane>
|
||||
<DIV-cy-tab-pane label="面风格">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">面颜色</span>
|
||||
<div class="color"></div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">边线颜色</span>
|
||||
<div class="lineColor"></div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">边线宽度</span>
|
||||
<div class="input-number input-number-unit-2" style="width: 80px;">
|
||||
<input class="input" type="number" title="" min="0" max="99" @model="lineWidth">
|
||||
<span class="unit">px</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DIV-cy-tab-pane>
|
||||
<DIV-cy-tab-pane label="标注风格">
|
||||
${labelStyleElm1()}
|
||||
</DIV-cy-tab-pane>
|
||||
<DIV-cy-tab-pane label="标签风格">
|
||||
${labelStyleElm2()}
|
||||
</DIV-cy-tab-pane>
|
||||
</DIV-cy-tabs>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
|
||||
export { html }
|
||||
2173
src/Obj/Base/CircleObject/index.js
Normal file
2173
src/Obj/Base/CircleObject/index.js
Normal file
File diff suppressed because it is too large
Load Diff
64
src/Obj/Base/Corridor/index.js
Normal file
64
src/Obj/Base/Corridor/index.js
Normal file
@ -0,0 +1,64 @@
|
||||
// /**
|
||||
// * 走廊
|
||||
// */
|
||||
// import Base from "../index";
|
||||
|
||||
// class Corridor extends Base {
|
||||
// /**
|
||||
// * @constructor
|
||||
// * @param sdk
|
||||
// * @param options {object} 线属性
|
||||
// * @param options.name{string} 名称
|
||||
// * @param options.image{string | HTMLImageElement | HTMLCanvasElement | HTMLVideoElement} 指定 Image、URL、Canvas 或 Video 的属性
|
||||
// * @param options.width=10{number} 宽度
|
||||
// * @param options.height=0{number} 高度
|
||||
// * */
|
||||
// constructor(sdk, options = {}) {
|
||||
// super(sdk, options);
|
||||
// this.options.name = options.name || ''
|
||||
// this.options.image = options.image
|
||||
// this.options.width = options.width || 10
|
||||
// this.options.height = options.height || 0
|
||||
// }
|
||||
|
||||
// create(positions) {
|
||||
// let fromDegreesArray = []
|
||||
// for (let i = 0; i < positions.length; i++) {
|
||||
// fromDegreesArray.push(positions[i].lng, positions[i].lat)
|
||||
// }
|
||||
// this.entity = this.sdk.viewer.scene.primitives.add(new Cesium.Primitive({//GroundPrimitive贴地
|
||||
// geometryInstances: new Cesium.GeometryInstance({
|
||||
// geometry: new Cesium.CorridorGeometry({
|
||||
// positions: Cesium.Cartesian3.fromDegreesArray(fromDegreesArray),
|
||||
// width: this.options.width,
|
||||
// height: this.options.height,
|
||||
// cornerType: Cesium.CornerType.MITERED,
|
||||
// vertexFormat: Cesium.MaterialAppearance.MaterialSupport.ALL.vertexFormat
|
||||
// }),
|
||||
// attributes: {
|
||||
// color: Cesium.ColorGeometryInstanceAttribute.fromColor(new Cesium.Color(1.0, 1.0, 1.0, 0.5))
|
||||
// }
|
||||
// }),
|
||||
// appearance: new Cesium.MaterialAppearance({
|
||||
// material: Cesium.Material.fromType('Image', {
|
||||
// image: this.options.image,
|
||||
// repeat: new Cesium.Cartesian2(100, 1.0)
|
||||
// }),
|
||||
// faceForward: true,
|
||||
// renderState: {
|
||||
// blending: Cesium.BlendingState.ALPHA_BLEND
|
||||
// }
|
||||
// })
|
||||
// }));
|
||||
// }
|
||||
|
||||
// // 编辑框
|
||||
// async edit(state) { }
|
||||
|
||||
// remove() {
|
||||
// this.sdk.viewer.scene.primitives.remove(this.entity)
|
||||
// this.entity = null
|
||||
// }
|
||||
// }
|
||||
|
||||
// export default Corridor
|
||||
152
src/Obj/Base/CurvelineObject/_element.js
Normal file
152
src/Obj/Base/CurvelineObject/_element.js
Normal file
@ -0,0 +1,152 @@
|
||||
import { attributeElm, labelStyleElm1, labelStyleElm2 } from '../../Element/elm_html'
|
||||
|
||||
function html(that) {
|
||||
return `
|
||||
<span class="custom-divider"></span>
|
||||
<div class="div-item">
|
||||
<div class="row" style="align-items: flex-start;">
|
||||
<div class="col">
|
||||
<span class="label">名称</span>
|
||||
<input class="input" maxlength="40" type="text" @model="name">
|
||||
</div>
|
||||
<div class="col" style="flex: 0 0 54%;">
|
||||
<div>
|
||||
<div class="row">
|
||||
<div class="col input-select-unit-box">
|
||||
<span class="label">原始长度:</span>
|
||||
<input class="input input-text" readonly="readonly" type="text" style="flex: 0 0 130px;" @model="length">
|
||||
<div class="input-select-unit"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col input-select-fit-unit-box">
|
||||
<span class="label">拟合长度:</span>
|
||||
<input class="input input-text" readonly="readonly" type="text" style="flex: 0 0 130px;" @model="fitLength">
|
||||
<div class="input-select-fit-unit"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="div-item">
|
||||
<div class="row">
|
||||
<DIV-cy-tabs id="polyline-object-edit-tabs">
|
||||
<DIV-cy-tab-pane label="属性信息">
|
||||
${attributeElm(that)}
|
||||
</DIV-cy-tab-pane>
|
||||
<DIV-cy-tab-pane label="空间信息">
|
||||
<div class="row">
|
||||
<div class="col height-mode-box">
|
||||
<span class="label" style="flex: 0 0 56px;">高度模式</span>
|
||||
<div class="height-mode"></div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">Z值统一增加</span>
|
||||
<div class="input-number input-number-unit-1 height-box">
|
||||
<input class="input height" type="number" title="" min="-9999999" max="999999999">
|
||||
<span class="unit">m</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
<button class="confirm height-confirm" style="margin-left: 5px;">确认</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="table spatial-info-table">
|
||||
<div class="table-head">
|
||||
<div class="tr">
|
||||
<div class="th"></div>
|
||||
<div class="th">经度(X)</div>
|
||||
<div class="th">纬度(Y)</div>
|
||||
<div class="th">高度(Z)</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-body">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DIV-cy-tab-pane>
|
||||
<DIV-cy-tab-pane label="线条风格">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">线条颜色</span>
|
||||
<div class="color"></div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">线条宽度</span>
|
||||
<div class="input-number input-number-unit-1" style="width: 80px;">
|
||||
<input class="input" type="number" title="" min="1" max="999" @model="lineWidth">
|
||||
<span class="unit">px</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col input-select-line-type-box">
|
||||
<span class="label">线条形式</span>
|
||||
<div class="input-select-line-type"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">线段缓冲</span>
|
||||
<input class="btn-switch" type="checkbox" @model="extend">
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">缓冲宽度</span>
|
||||
<div class="input-number input-number-unit-1" style="width: 80px;">
|
||||
<input class="input" type="number" title="" min="0" data-min="0.01" max="999999" @model="extendWidth">
|
||||
<span class="unit">m</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">缓冲颜色</span>
|
||||
<div class="extendColor"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">首尾相连</span>
|
||||
<input class="btn-switch" type="checkbox" @model="noseToTail">
|
||||
</div>
|
||||
<div class="col">
|
||||
</div>
|
||||
<div class="col">
|
||||
</div>
|
||||
</div>
|
||||
</DIV-cy-tab-pane>
|
||||
<DIV-cy-tab-pane label="标注风格">
|
||||
${labelStyleElm1()}
|
||||
</DIV-cy-tab-pane>
|
||||
<DIV-cy-tab-pane label="标签风格">
|
||||
${labelStyleElm2()}
|
||||
</DIV-cy-tab-pane>
|
||||
<!-- <DIV-cy-tab-pane label="灯光控制">-->
|
||||
<!-- <div>-->
|
||||
<!-- <div class="row">-->
|
||||
<!-- <div class="col">-->
|
||||
<!-- <span class="label">指令</span>-->
|
||||
<!-- <input class="input" type="text" @model="instruct">-->
|
||||
<!-- <button class="primary" @click="instructSubmit">提交</button>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </DIV-cy-tab-pane>-->
|
||||
<!-- <DIV-cy-tab-pane label="设置操作点">-->
|
||||
<!-- <div>-->
|
||||
<!-- <div class="row">-->
|
||||
<!-- <div class="col">-->
|
||||
<!-- <span class="label">设置操作点</span>-->
|
||||
<!-- <input class="input" type="text" @model="operatingPoint">-->
|
||||
<!-- <button class="primary" @click="operatingPointSubmit">提交</button>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </DIV-cy-tab-pane>-->
|
||||
</DIV-cy-tabs>
|
||||
</div>
|
||||
</div>
|
||||
<span class="custom-divider"></span>
|
||||
`
|
||||
}
|
||||
|
||||
export { html }
|
||||
120
src/Obj/Base/CurvelineObject/eventBinding.js
Normal file
120
src/Obj/Base/CurvelineObject/eventBinding.js
Normal file
@ -0,0 +1,120 @@
|
||||
class eventBinding {
|
||||
constructor() {
|
||||
this.element = {}
|
||||
}
|
||||
static event = {}
|
||||
|
||||
getEvent(name) {
|
||||
return eventBinding.event[name]
|
||||
}
|
||||
|
||||
getEventAll() {
|
||||
return eventBinding.event
|
||||
}
|
||||
|
||||
setEvent(name, event) {
|
||||
eventBinding.event[name] = event
|
||||
}
|
||||
|
||||
on(that, elements) {
|
||||
for (let i = 0; i < elements.length; i++) {
|
||||
let Event = []
|
||||
let isEvent = false
|
||||
let removeName = []
|
||||
if (!elements[i] ||!elements[i].attributes) {
|
||||
continue
|
||||
}
|
||||
for (let m of elements[i].attributes) {
|
||||
switch (m.name) {
|
||||
case '@model': {
|
||||
isEvent = true
|
||||
if (elements[i].type == 'checkbox') {
|
||||
Event.push((e) => { that[m.value] = e.target.checked })
|
||||
elements[i].checked = that[m.value]
|
||||
}
|
||||
else {
|
||||
Event.push((e) => {
|
||||
let value = e.target.value
|
||||
if (e.target.type == 'number') {
|
||||
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)
|
||||
}
|
||||
if((e.target.dataset.min) && value<Number(e.target.dataset.min)) {
|
||||
value = Number(e.target.dataset.min)
|
||||
}
|
||||
that[m.value] = value
|
||||
}
|
||||
}
|
||||
else {
|
||||
that[m.value] = value
|
||||
}
|
||||
})
|
||||
if(elements[i].nodeName=='IMG') {
|
||||
elements[i].src = that[m.value]
|
||||
}
|
||||
else {
|
||||
elements[i].value = that[m.value]
|
||||
}
|
||||
}
|
||||
if(this.element[m.value]) {
|
||||
this.element[m.value].push(elements[i])
|
||||
}
|
||||
else {
|
||||
this.element[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)
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const EventBinding = new eventBinding();
|
||||
export default EventBinding;
|
||||
2753
src/Obj/Base/CurvelineObject/index.js
Normal file
2753
src/Obj/Base/CurvelineObject/index.js
Normal file
File diff suppressed because it is too large
Load Diff
87
src/Obj/Base/EllipseObject/_element.js
Normal file
87
src/Obj/Base/EllipseObject/_element.js
Normal file
@ -0,0 +1,87 @@
|
||||
import { attributeElm, labelStyleElm1, labelStyleElm2 } from '../../Element/elm_html'
|
||||
|
||||
function html(that) {
|
||||
return `
|
||||
<div class="row" style="align-items: flex-start;">
|
||||
<div class="col">
|
||||
<span class="label">名称</span>
|
||||
<input class="input" maxlength="40" type="text" @model="name">
|
||||
</div>
|
||||
<div class="col" style="flex: 0 0 60%;">
|
||||
<div class="row">
|
||||
<div class="col input-select-unit-box">
|
||||
<span class="label" style="margin-right: 0px;">投影面积:</span>
|
||||
<input class="input input-text" readonly="readonly" type="text" @model="area">
|
||||
<div class="input-select-unit"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<DIV-cy-tabs id="circle-object-edit-tabs">
|
||||
<DIV-cy-tab-pane label="属性信息">
|
||||
${attributeElm(that)}
|
||||
</DIV-cy-tab-pane>
|
||||
<DIV-cy-tab-pane label="空间信息">
|
||||
<div class="row">
|
||||
<div class="col height-mode-box">
|
||||
<span class="label" style="flex: 0 0 56px;">高度模式</span>
|
||||
<div class="height-mode"></div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">Z值统一增加</span>
|
||||
<div class="input-number input-number-unit-1 height-box">
|
||||
<input class="input height" type="number" title="" min="-9999999" max="999999999">
|
||||
<span class="unit">m</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
<button class="confirm height-confirm" style="margin-left: 5px;">确认</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="table spatial-info-table">
|
||||
<div class="table-head">
|
||||
<div class="tr">
|
||||
<div class="th"></div>
|
||||
<div class="th">经度(X)</div>
|
||||
<div class="th">纬度(Y)</div>
|
||||
<div class="th">高度(Z)</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-body">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DIV-cy-tab-pane>
|
||||
<DIV-cy-tab-pane label="面风格">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">面颜色</span>
|
||||
<div class="color"></div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">边线颜色</span>
|
||||
<div class="lineColor"></div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">边线宽度</span>
|
||||
<div class="input-number input-number-unit-2" style="width: 80px;">
|
||||
<input class="input" type="number" title="" min="0" max="99" @model="lineWidth">
|
||||
<span class="unit">px</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DIV-cy-tab-pane>
|
||||
<DIV-cy-tab-pane label="标注风格">
|
||||
${labelStyleElm1()}
|
||||
</DIV-cy-tab-pane>
|
||||
<DIV-cy-tab-pane label="标签风格">
|
||||
${labelStyleElm2()}
|
||||
</DIV-cy-tab-pane>
|
||||
</DIV-cy-tabs>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
|
||||
export { html }
|
||||
2171
src/Obj/Base/EllipseObject/index.js
Normal file
2171
src/Obj/Base/EllipseObject/index.js
Normal file
File diff suppressed because it is too large
Load Diff
51
src/Obj/Base/Explosion/_element.js
Normal file
51
src/Obj/Base/Explosion/_element.js
Normal file
@ -0,0 +1,51 @@
|
||||
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" maxlength="40" type="text" @model="name">
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">随地图缩放</span>
|
||||
<input class="btn-switch" type="checkbox" @model="scaleByDistance">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="custom-divider"></span>
|
||||
<div class="div-item">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">经度</span>
|
||||
<input class="input" type="number" title="" title="" min="-180" max="180" @model="lng">
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">爆炸范围</span>
|
||||
<div class="input-number input-number-unit-1">
|
||||
<input class="input" type="number" title="" min="1" max="999999" @model="size">
|
||||
<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="-90" max="90" @model="lat">
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">高度</span>
|
||||
<div class="input-number input-number-unit-1">
|
||||
<input class="input" type="number" title="" min="-9999999" max="999999999" @model="alt">
|
||||
<span class="unit">m</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="custom-divider"></span>
|
||||
`
|
||||
}
|
||||
|
||||
export { html }
|
||||
382
src/Obj/Base/Explosion/index.js
Normal file
382
src/Obj/Base/Explosion/index.js
Normal file
@ -0,0 +1,382 @@
|
||||
import Base from "../index";
|
||||
import Dialog from '../../Element/Dialog';
|
||||
import EventBinding from '../../Element/Dialog/eventBinding';
|
||||
import { html } from "./_element";
|
||||
import MouseEvent from '../../../Event/index'
|
||||
import { syncData } from '../../../Global/MultiViewportMode'
|
||||
import MouseTip from '../../../MouseTip'
|
||||
import { setSplitDirection, syncSplitData, setActiveId } from '../../../Global/SplitScreen'
|
||||
import { setActiveViewer, closeRotateAround, closeViewFollow, getGroundCover} from '../../../Global/global'
|
||||
class Explosion extends Base {
|
||||
/**
|
||||
* @constructor
|
||||
* @description 爆炸
|
||||
* @param sdk
|
||||
* @param options {object} 爆炸属性
|
||||
* */
|
||||
constructor(sdk, options = {}, _Dialog = {}) {
|
||||
super(sdk, options);
|
||||
this.viewer = sdk.viewer
|
||||
this.options.show = (options.show || options.show === false) ? options.show : true
|
||||
this.options.name = this.options.name || '未命名对象'
|
||||
this.options.size = (this.options.size || this.options.size === 0) ? this.options.size : 80
|
||||
this.options.scaleByDistance = (options.scaleByDistance || options.scaleByDistance === false) ? options.scaleByDistance : true
|
||||
this.event = new MouseEvent(this.sdk)
|
||||
this.Dialog = _Dialog
|
||||
this.operate = {}
|
||||
this._elms = {};
|
||||
this._EventBinding = new EventBinding()
|
||||
this.sdk.addIncetance(this.options.id, this)
|
||||
Explosion.create(this)
|
||||
}
|
||||
|
||||
get type() {
|
||||
return 'Explosion'
|
||||
}
|
||||
|
||||
// 创建
|
||||
static create(that) {
|
||||
let img_bz = []
|
||||
for (let i = 10001; i <= 10120; i++) {
|
||||
let src = that.getSourceRootPath() + `/img/frameAnimation/explosion/b${i}.png`
|
||||
img_bz.push(src)
|
||||
}
|
||||
let i = 0
|
||||
let flyEntity = new Cesium.Entity({
|
||||
id: that.options.id,
|
||||
show: that.options.show,
|
||||
position: new Cesium.CallbackProperty(() => {
|
||||
return Cesium.Cartesian3.fromDegrees(that.options.position.lng, that.options.position.lat, that.options.position.alt)
|
||||
}, false),
|
||||
billboard: {
|
||||
image: new Cesium.CallbackProperty(() => {
|
||||
let img = img_bz[flyEntity.imgIndex]
|
||||
flyEntity.imgIndex++
|
||||
if (flyEntity.imgIndex >= img_bz.length) {
|
||||
flyEntity.imgIndex = 0
|
||||
}
|
||||
return img
|
||||
}, false),
|
||||
// scale: that.options.size,
|
||||
disableDepthTestDistance: new Cesium.CallbackProperty(function () {
|
||||
return getGroundCover() ? undefined : Number.POSITIVE_INFINITY
|
||||
}, false),
|
||||
width: that.options.size,
|
||||
height: that.options.size,
|
||||
sizeInMeters: that.options.scaleByDistance,
|
||||
pixelOffset: { x: 0, y: -20 }
|
||||
},
|
||||
});
|
||||
flyEntity.imgIndex = 0
|
||||
that.entity = that.viewer.entities.add(flyEntity)
|
||||
syncData(that.sdk, that.options.id)
|
||||
if(that.options.show) {
|
||||
setSplitDirection(0, that.options.id)
|
||||
}
|
||||
}
|
||||
|
||||
// 编辑框
|
||||
async edit(state) {
|
||||
let _this = this
|
||||
this.originalOptions = this.deepCopyObj(this.options)
|
||||
|
||||
if (this._DialogObject && this._DialogObject.close) {
|
||||
this._DialogObject.close()
|
||||
this._DialogObject = null
|
||||
}
|
||||
if (state) {
|
||||
this._DialogObject = await new Dialog(this.sdk, this.options, {
|
||||
title: '爆炸属性', left: '180px', top: '100px',
|
||||
confirmCallBack: (options) => {
|
||||
this.name = this.name.trim()
|
||||
if(!this.name) {
|
||||
this.name = '未命名对象'
|
||||
}
|
||||
this.originalOptions = this.deepCopyObj(this.options)
|
||||
this._DialogObject.close()
|
||||
this.Dialog.confirmCallBack && this.Dialog.confirmCallBack(this.originalOptions)
|
||||
syncData(this.sdk, this.options.id)
|
||||
syncSplitData(this.sdk, this.options.id)
|
||||
},
|
||||
resetCallBack: () => {
|
||||
this.reset()
|
||||
this.Dialog.resetCallBack && this.Dialog.resetCallBack()
|
||||
},
|
||||
removeCallBack: () => {
|
||||
this.Dialog.removeCallBack && this.Dialog.removeCallBack()
|
||||
},
|
||||
closeCallBack: () => {
|
||||
this.reset()
|
||||
this.positionEditing = false
|
||||
this.Dialog.closeCallBack && this.Dialog.closeCallBack()
|
||||
},
|
||||
showCallBack: (show) => {
|
||||
this.options.show = show
|
||||
this.originalOptions.show = show
|
||||
this.show = show
|
||||
this.Dialog.showCallBack && this.Dialog.showCallBack()
|
||||
},
|
||||
translationalCallBack: () => {
|
||||
this.positionEditing = !this.positionEditing
|
||||
},
|
||||
})
|
||||
this._DialogObject._element.body.className = this._DialogObject._element.body.className + ' explosion'
|
||||
let contentElm = document.createElement('div');
|
||||
contentElm.innerHTML = html()
|
||||
this._DialogObject.contentAppChild(contentElm)
|
||||
|
||||
let all_elm = contentElm.getElementsByTagName("*")
|
||||
this._EventBinding.on(this, all_elm)
|
||||
this._elms = this._EventBinding.element
|
||||
this.scaleByDistance = this.options.scaleByDistance
|
||||
}
|
||||
}
|
||||
|
||||
async flyTo(options = {}) {
|
||||
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.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 {
|
||||
this.sdk.viewer.camera.flyTo({
|
||||
destination: Cesium.Cartesian3.fromDegrees(this.options.position.lng, this.options.position.lat, this.options.position.alt + (this.options.size * 8)),
|
||||
orientation: options.orientation || {
|
||||
heading: Cesium.Math.toRadians(0.0),
|
||||
pitch: Cesium.Math.toRadians(-85.0),
|
||||
roll: Cesium.Math.toRadians(0.0)
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
reset() {
|
||||
if (!this.entity) {
|
||||
return
|
||||
}
|
||||
this.previous = null
|
||||
this.options = this.deepCopyObj(this.originalOptions)
|
||||
this.name = this.originalOptions.name
|
||||
this.size = this.originalOptions.size
|
||||
this.scaleByDistance = this.originalOptions.scaleByDistance
|
||||
this.lng = this.options.position.lng
|
||||
this.lat = this.options.position.lat
|
||||
}
|
||||
|
||||
get scaleByDistance() {
|
||||
return this.options.scaleByDistance
|
||||
}
|
||||
set scaleByDistance(v) {
|
||||
this.options.scaleByDistance = v
|
||||
this.entity.billboard.sizeInMeters = v
|
||||
this._elms.scaleByDistance && this._elms.scaleByDistance.forEach((item) => {
|
||||
item.checked = v
|
||||
})
|
||||
}
|
||||
|
||||
get lng() {
|
||||
return this.options.position.lng
|
||||
}
|
||||
|
||||
set lng(v) {
|
||||
this.options.position.lng = v
|
||||
this._elms.lng && this._elms.lng.forEach((item) => {
|
||||
item.value = v
|
||||
})
|
||||
}
|
||||
|
||||
get lat() {
|
||||
return this.options.position.lat
|
||||
}
|
||||
|
||||
set lat(v) {
|
||||
this.options.position.lat = v
|
||||
this._elms.lat && this._elms.lat.forEach((item) => {
|
||||
item.value = v
|
||||
})
|
||||
}
|
||||
|
||||
get alt() {
|
||||
return this.options.position.alt
|
||||
}
|
||||
|
||||
set alt(v) {
|
||||
this.options.position.alt = v
|
||||
this._elms.alt && this._elms.alt.forEach((item) => {
|
||||
item.value = v
|
||||
})
|
||||
}
|
||||
|
||||
get size() {
|
||||
return this.options.size
|
||||
}
|
||||
set size(v) {
|
||||
this.options.size = v
|
||||
this.entity.billboard.width = this.options.size
|
||||
this.entity.billboard.height = this.options.size
|
||||
this._elms.size && this._elms.size.forEach((item) => {
|
||||
item.value = v
|
||||
})
|
||||
}
|
||||
|
||||
/**@desc 打开平移功能
|
||||
*
|
||||
* @memberOf Source
|
||||
* @param status {boolean}
|
||||
*
|
||||
* */
|
||||
set positionEditing(status) {
|
||||
if (YJ.Measure.GetMeasureStatus() || !this.sdk || !this.sdk.viewer || !this.entity) {
|
||||
return
|
||||
}
|
||||
this.operate.positionEditing = status
|
||||
if (status === true) {
|
||||
this.tip && this.tip.destroy()
|
||||
this.tip = new MouseTip('点击鼠标左键确认,右键取消', this.sdk)
|
||||
this.previous = {
|
||||
position: { ...this.options.position }
|
||||
}
|
||||
this.event.mouse_move((movement, cartesian) => {
|
||||
let positions = this.cartesian3Towgs84(cartesian, this.sdk.viewer)
|
||||
this.lng = positions.lng
|
||||
this.lat = positions.lat
|
||||
this.alt = positions.alt
|
||||
this.tip.setPosition(
|
||||
cartesian,
|
||||
movement.endPosition.x,
|
||||
movement.endPosition.y
|
||||
)
|
||||
})
|
||||
this.event.mouse_left((movement, cartesian) => {
|
||||
let positions = this.cartesian3Towgs84(cartesian, this.sdk.viewer)
|
||||
this.lng = positions.lng
|
||||
this.lat = positions.lat
|
||||
this.alt = positions.alt
|
||||
this.previous = {
|
||||
position: { ...this.options.position }
|
||||
}
|
||||
this.event.mouse_move(() => { })
|
||||
this.event.mouse_left(() => { })
|
||||
this.event.mouse_right(() => { })
|
||||
this.event.gesture_pinck_start(() => { })
|
||||
this.event.gesture_pinck_end(() => { })
|
||||
this.positionEditing = false
|
||||
})
|
||||
this.event.mouse_right((movement, cartesian) => {
|
||||
this.positionEditing = false
|
||||
})
|
||||
|
||||
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.positionEditing = false
|
||||
}
|
||||
else {
|
||||
let positions = this.cartesian3Towgs84(cartesian, this.sdk.viewer)
|
||||
this.lng = positions.lng
|
||||
this.lat = positions.lat
|
||||
this.alt = positions.alt
|
||||
this.previous = {
|
||||
position: { ...this.options.position }
|
||||
}
|
||||
this.event.mouse_move(() => { })
|
||||
this.event.mouse_left(() => { })
|
||||
this.event.mouse_right(() => { })
|
||||
this.event.gesture_pinck_start(() => { })
|
||||
this.event.gesture_pinck_end(() => { })
|
||||
this.positionEditing = false
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
else {
|
||||
if (this.event) {
|
||||
this.event.mouse_move(() => { })
|
||||
this.event.mouse_left(() => { })
|
||||
this.event.mouse_right(() => { })
|
||||
this.event.gesture_pinck_start(() => { })
|
||||
this.event.gesture_pinck_end(() => { })
|
||||
}
|
||||
this.tip && this.tip.destroy()
|
||||
if (this.previous) {
|
||||
this.lng = this.previous.position.lng
|
||||
this.lat = this.previous.position.lat
|
||||
this.alt = this.previous.position.alt
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get positionEditing() {
|
||||
return this.operate.positionEditing
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除
|
||||
*/
|
||||
async remove() {
|
||||
this.viewer.entities.remove(this.entity)
|
||||
this.entity = null
|
||||
if (this._DialogObject && !this._DialogObject.isDestroy) {
|
||||
this._DialogObject.close()
|
||||
this._DialogObject = null
|
||||
}
|
||||
this.tip && this.tip.destroy()
|
||||
this.event && this.event.destroy()
|
||||
await this.sdk.removeIncetance(this.options.id)
|
||||
await syncData(this.sdk, this.options.id)
|
||||
}
|
||||
|
||||
flicker() {}
|
||||
}
|
||||
|
||||
export default Explosion
|
||||
67
src/Obj/Base/FlyRoam/_element.js
Normal file
67
src/Obj/Base/FlyRoam/_element.js
Normal 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 }
|
||||
418
src/Obj/Base/FlyRoam/index.js
Normal file
418
src/Obj/Base/FlyRoam/index.js
Normal file
@ -0,0 +1,418 @@
|
||||
|
||||
/**
|
||||
* @description 飞行漫游
|
||||
*/
|
||||
import Dialog from '../../../BaseDialog';
|
||||
import { html } from "./_element";
|
||||
import Base from "../index";
|
||||
import { setActiveViewer, closeRotateAround, closeViewFollow} from '../../../Global/global'
|
||||
|
||||
class FlyRoam extends Base {
|
||||
#clickHandler = undefined
|
||||
constructor(sdk, options = {}, _Dialog = {}) {
|
||||
super(sdk, options)
|
||||
this.options.id = options.id || this.randomString()
|
||||
this.options.name = options.name || '漫游路径'
|
||||
this.options.points = options.points || []
|
||||
if(this.options.repeat) {
|
||||
this.options.repeat = Number(this.options.repeat)
|
||||
}
|
||||
this.Dialog = _Dialog
|
||||
}
|
||||
|
||||
get repeat() {
|
||||
return this.options.repeat
|
||||
}
|
||||
|
||||
/**设置循环次数 (Infinity: 无限循环)*/
|
||||
set repeat(v) {
|
||||
if (this.options.repeat != Number(v)) {
|
||||
this.options.repeat = Number(v)
|
||||
if (this._DialogObject && this._DialogObject._element && this._DialogObject._element.content) {
|
||||
let repeatElm = this._DialogObject._element.content.querySelector("input[name='repeat']")
|
||||
if (v === Infinity) {
|
||||
repeatElm.checked = true
|
||||
}
|
||||
else {
|
||||
repeatElm.checked = false
|
||||
}
|
||||
this.Dialog.changeRepeatStateCallBack && this.Dialog.changeRepeatStateCallBack(repeatElm.checked)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async edit(state) {
|
||||
let _this = this
|
||||
let viewer = this.sdk.viewer
|
||||
let active = 0
|
||||
|
||||
if (this._DialogObject && this._DialogObject.close) {
|
||||
this._DialogObject.close()
|
||||
this._DialogObject = null
|
||||
}
|
||||
if (state) {
|
||||
this._DialogObject = await new Dialog(viewer._container, {
|
||||
title: '飞行漫游', left: '180px', top: '100px',
|
||||
closeCallBack: () => {
|
||||
this.cease()
|
||||
},
|
||||
})
|
||||
await this._DialogObject.init()
|
||||
let contentElm = document.createElement('div');
|
||||
contentElm.className = 'fly-roam'
|
||||
contentElm.innerHTML = html()
|
||||
this._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 < this.options.points.length; i++) {
|
||||
points.push(this.options.points[i])
|
||||
addTrElm(this.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 = this.name
|
||||
nameElm.addEventListener('input', () => {
|
||||
this.name = nameElm.value
|
||||
})
|
||||
|
||||
let addListBtn = document.createElement('button');
|
||||
addListBtn.innerHTML = '保存'
|
||||
addListBtn.addEventListener('click', () => {
|
||||
if (!this.name) {
|
||||
this.name = '漫游路径'
|
||||
nameElm.value = this.name
|
||||
}
|
||||
let newPoints = []
|
||||
points.map((item) => {
|
||||
newPoints.push(item)
|
||||
})
|
||||
this._DialogObject.close()
|
||||
this.Dialog.confirmCallBack && this.Dialog.confirmCallBack(
|
||||
{
|
||||
id: this.options.id,
|
||||
name: this.name,
|
||||
points: newPoints,
|
||||
repeat: this.repeat+''
|
||||
}
|
||||
)
|
||||
})
|
||||
this._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) {
|
||||
this.flyTo(0)
|
||||
}
|
||||
})
|
||||
|
||||
let addBtn = contentElm.getElementsByClassName('add-point')[0]
|
||||
addBtn.addEventListener('click', () => {
|
||||
let position = this.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)
|
||||
this.options.points.splice(active, 0, data)
|
||||
addTrElm(data)
|
||||
i++
|
||||
})
|
||||
let modifyBtn = contentElm.getElementsByClassName('modify-point')[0]
|
||||
modifyBtn.addEventListener('click', () => {
|
||||
if (!active) {
|
||||
return
|
||||
}
|
||||
let position = this.cartesian3Towgs84(viewer.camera.position, viewer)
|
||||
this.options.points[active - 1].position = points[active - 1].position = position
|
||||
this.options.points[active - 1].orientation = 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
|
||||
this.options.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
|
||||
this.options.points[i].duration = time
|
||||
trList[i].querySelector("input[name='time']").value = time
|
||||
}
|
||||
trList[trList.length - 1].querySelector("input[name='time']").value = 0
|
||||
}
|
||||
})
|
||||
repeatElm.checked = (this.repeat === Infinity ? true : false)
|
||||
repeatElm.addEventListener('change', () => {
|
||||
if (repeatElm.checked) {
|
||||
this.repeat = Infinity
|
||||
}
|
||||
else {
|
||||
this.repeat = 0
|
||||
}
|
||||
})
|
||||
|
||||
// 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) {
|
||||
_this.flyTo(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].duration = 0
|
||||
_this.options.points.splice(m, 1)
|
||||
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'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flyTo(i = 0) {
|
||||
setActiveViewer(0)
|
||||
let _this = this
|
||||
let points = this.options.points
|
||||
let currentRepeat = this.repeat
|
||||
|
||||
closeRotateAround(_this.sdk)
|
||||
const executeFlyTo = (index = 0, noStart) => {
|
||||
if (this.#clickHandler) {
|
||||
this.#clickHandler.destroy()
|
||||
}
|
||||
let _this = this
|
||||
this.#clickHandler = new Cesium.ScreenSpaceEventHandler(_this.sdk.viewer.canvas)
|
||||
this.#clickHandler.setInputAction((movement) => {
|
||||
this.cease()
|
||||
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
|
||||
let viewer = _this.sdk.viewer
|
||||
setActiveViewer(0)
|
||||
viewer.camera.cancelFlight()
|
||||
// function pauseExecution(seconds) {
|
||||
// return new Promise(resolve => setTimeout(resolve, seconds * 1000));
|
||||
// }
|
||||
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 (this.repeat === Infinity) {
|
||||
currentRepeat = Infinity
|
||||
}
|
||||
else if (currentRepeat === Infinity) {
|
||||
currentRepeat = this.repeat
|
||||
}
|
||||
if (index <= points.length - 1) {
|
||||
executeFlyTo(index, true)
|
||||
}
|
||||
else if (currentRepeat) {
|
||||
currentRepeat--
|
||||
executeFlyTo(0)
|
||||
}
|
||||
else {
|
||||
if (this.#clickHandler) {
|
||||
this.#clickHandler.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
easingFunction: noStart ? Cesium.EasingFunction.LINEAR_NONE : Cesium.EasingFunction.EXPONENTIAL_OUT
|
||||
})
|
||||
}
|
||||
|
||||
executeFlyTo(i)
|
||||
|
||||
}
|
||||
|
||||
/** 停止 */
|
||||
cease() {
|
||||
this.sdk && this.sdk.viewer && this.sdk.viewer.camera.cancelFlight()
|
||||
if (this.#clickHandler) {
|
||||
this.#clickHandler.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
remove() {
|
||||
if (this._DialogObject && this._DialogObject.close) {
|
||||
this._DialogObject.close()
|
||||
this._DialogObject = null
|
||||
}
|
||||
else {
|
||||
this.cease()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
export default FlyRoam
|
||||
191
src/Obj/Base/GeoJson/index.js
Normal file
191
src/Obj/Base/GeoJson/index.js
Normal file
@ -0,0 +1,191 @@
|
||||
/**
|
||||
* @name: index
|
||||
* @author: Administrator
|
||||
* @date: 2023-03-04 10:39
|
||||
* @description:index
|
||||
* @update: 2023-03-04 10:39
|
||||
*/
|
||||
import { getHost, getToken } from "../../../on";
|
||||
import Base from '../index'
|
||||
import Tools from '../../../Tools'
|
||||
import { setActiveViewer, closeRotateAround, closeViewFollow} from '../../../Global/global'
|
||||
|
||||
class GeoJson extends Base {
|
||||
/**
|
||||
* @constructor
|
||||
* @param sdk
|
||||
* @param options {object} 参数
|
||||
* @param options.id {string} id
|
||||
* @param options.url {string} geojson地址
|
||||
* @param [options.color=#ef0606] {string} 线条颜色
|
||||
* @param [options.width=1] {number} 线条宽度
|
||||
* @example new YJ.Obj.GeoJson(earth,{id:"123",url:""})
|
||||
* */
|
||||
constructor(sdk, options = {}) {
|
||||
super(sdk, options)
|
||||
|
||||
this.primitive = undefined
|
||||
this.positions = []
|
||||
|
||||
this.loading = true
|
||||
}
|
||||
|
||||
setDefaultValue() {
|
||||
super.setDefaultValue()
|
||||
this.options.host = this.options.host || getHost()
|
||||
// let url = this.options.url
|
||||
// if (this.options.host) {
|
||||
// let o = new URL(this.options.url, this.options.host)
|
||||
// url = o.href
|
||||
// }
|
||||
|
||||
// this.options.url = url
|
||||
this.options.color = this.options.color || 'rgb(239, 6, 6, 1)'
|
||||
this.options.width = this.options.width || 1
|
||||
}
|
||||
|
||||
get show() {
|
||||
return this.options.show
|
||||
}
|
||||
|
||||
set show(status) {
|
||||
this.options.show = status
|
||||
if (this.entity) {
|
||||
for (let i = 0; i < this.entity.entities.values.length; i++) {
|
||||
this.entity.entities.values[i].show = status
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async on() {
|
||||
let url = ""
|
||||
if (this.options.host.endsWith("yjearth4.0"))
|
||||
url = this.options.host + '/data/service/getFile'
|
||||
else
|
||||
url = this.options.host + '/yjearth4.0/data/service/getFile'
|
||||
url = url + '?path=' + encodeURIComponent(this.options.url)
|
||||
let rsp = await fetch(url, {
|
||||
method: 'get',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
"token": getToken(),
|
||||
"Authorization": "Bearer " + getToken(),
|
||||
}
|
||||
})
|
||||
let json = await rsp.json()
|
||||
this.geojson = json
|
||||
return GeoJson.addDataToGlobe(this, json.features)
|
||||
}
|
||||
|
||||
/*geojosn暂时只用线的形式*/
|
||||
static addDataToGlobe(that) {
|
||||
const geoJsonDataSource = new Cesium.GeoJsonDataSource();
|
||||
let geojson = that.deepCopyObj(that.geojson)
|
||||
for (let i = 0; i < geojson.features.length; i++) {
|
||||
if (!geojson.features[i].id) {
|
||||
geojson.features[i].id = that.options.id + '_' + i
|
||||
}
|
||||
}
|
||||
// console.log(geojson)
|
||||
let promise = geoJsonDataSource.load(geojson, {
|
||||
clampToGround: true,
|
||||
});
|
||||
return promise.then(datasource => {
|
||||
that.entity = datasource
|
||||
datasource.entities.values.forEach(enetity => {
|
||||
// console.log(enetity)
|
||||
let color = Cesium.Color.fromCssColorString(that.options.color)
|
||||
let colorPolygon = color.withAlpha(0.2)
|
||||
enetity.show = that.options.show
|
||||
that.sdk.viewer.entities.add(enetity)
|
||||
if (enetity.billboard) {
|
||||
enetity.billboard.heightReference = Cesium.HeightReference.CLAMP_TO_GROUND
|
||||
enetity.point = new Cesium.PointGraphics({
|
||||
show: true,
|
||||
color: color, // 点的颜色
|
||||
pixelSize: 10, // 点的大小
|
||||
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
|
||||
disableDepthTestDistance: Number.POSITIVE_INFINITY // 不应用深度测试
|
||||
})
|
||||
}
|
||||
|
||||
if (enetity.polyline) {
|
||||
enetity.polyline.material = color
|
||||
enetity.polyline.zIndex = that.sdk._entityZIndex
|
||||
that.sdk._entityZIndex++
|
||||
}
|
||||
|
||||
if (enetity.polygon) {
|
||||
enetity.polygon.perPositionHeight = false
|
||||
enetity.polygon.material = colorPolygon
|
||||
enetity.polygon.zIndex = that.sdk._entityZIndex
|
||||
|
||||
enetity.polyline = new Cesium.PolylineGraphics({
|
||||
positions: enetity.polygon.hierarchy._value.positions,
|
||||
width: 1,
|
||||
clampToGround: true,
|
||||
material: color,
|
||||
zIndex: that.sdk._entityZIndex
|
||||
})
|
||||
that.sdk._entityZIndex++
|
||||
}
|
||||
})
|
||||
that.loading = false
|
||||
})
|
||||
}
|
||||
|
||||
remove() {
|
||||
if (this.entity) {
|
||||
this.entity.entities.values.forEach(enetity => {
|
||||
this.sdk.viewer.entities.remove(enetity)
|
||||
})
|
||||
this.entity = null
|
||||
this.geojson = {}
|
||||
}
|
||||
}
|
||||
|
||||
async flyTo() {
|
||||
if (!this.loading) {
|
||||
if (this.geojson) {
|
||||
setActiveViewer(0)
|
||||
closeRotateAround(this.sdk)
|
||||
closeViewFollow(this.sdk)
|
||||
|
||||
let range = turf.bbox(this.geojson);
|
||||
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: range[0], lat: range[1] }
|
||||
// 如果没有高度值,则获取紧贴高度计算
|
||||
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 {
|
||||
this.viewer.camera.flyTo({
|
||||
destination: Cesium.Rectangle.fromDegrees(...range)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flicker() { }
|
||||
}
|
||||
|
||||
export default GeoJson
|
||||
145
src/Obj/Base/GeoJson/index2.js
Normal file
145
src/Obj/Base/GeoJson/index2.js
Normal file
@ -0,0 +1,145 @@
|
||||
/**
|
||||
* @name: index
|
||||
* @author: Administrator
|
||||
* @date: 2023-03-04 10:39
|
||||
* @description:index
|
||||
* @update: 2023-03-04 10:39
|
||||
*/
|
||||
import { getHost } from "../../../on";
|
||||
import Base from '../index'
|
||||
import Tools from '../../../Tools'
|
||||
|
||||
class GeoJson extends Base {
|
||||
/**
|
||||
* @constructor
|
||||
* @param sdk
|
||||
* @param options {object} 参数
|
||||
* @param options.id {string} id
|
||||
* @param options.url {string} geojson地址
|
||||
* @param [options.color=#ef0606] {string} 线条颜色
|
||||
* @param [options.width=1] {number} 线条宽度
|
||||
* @example new YJ.Obj.GeoJson(earth,{id:"123",url:""})
|
||||
* */
|
||||
constructor(sdk, options = {}) {
|
||||
super(sdk, options)
|
||||
|
||||
this.primitive = undefined
|
||||
this.positions = []
|
||||
|
||||
this.loading = true
|
||||
}
|
||||
|
||||
setDefaultValue() {
|
||||
super.setDefaultValue()
|
||||
this.options.host = this.options.host || getHost()
|
||||
let url = this.options.url
|
||||
if(this.options.host) {
|
||||
let o = new URL(this.options.url, this.options.host)
|
||||
url = o.href
|
||||
}
|
||||
|
||||
this.options.url = url
|
||||
this.options.color = this.options.color || '#ef0606'
|
||||
this.options.width = this.options.width || 1
|
||||
}
|
||||
|
||||
get show() {
|
||||
if (this.primitive) return this.primitive.show
|
||||
return undefined
|
||||
}
|
||||
|
||||
set show(status) {
|
||||
if (this.primitive) {
|
||||
this.primitive.show = status
|
||||
}
|
||||
}
|
||||
|
||||
async on() {
|
||||
let rsp = await fetch(this.options.url)
|
||||
let json = await rsp.json()
|
||||
return GeoJson.addDataToGlobe(this, json.features)
|
||||
}
|
||||
|
||||
/*geojosn暂时只用线的形式*/
|
||||
static addDataToGlobe(that, features) {
|
||||
const instances = []
|
||||
for (let i = 0; i < features.length; i++) {
|
||||
let positions = []
|
||||
if ('LineString' === features[i].geometry.type) {
|
||||
features[i].geometry.coordinates.forEach(c => {
|
||||
that.positions.push({ lng: c[0], lat: c[1] })
|
||||
positions.push(c[0], c[1])
|
||||
})
|
||||
}
|
||||
if ('Polygon' === features[i].geometry.type) {
|
||||
features[i].geometry.coordinates.forEach(polygon => {
|
||||
polygon.forEach(c => {
|
||||
that.positions.push({ lng: c[0], lat: c[1] })
|
||||
positions.push(c[0], c[1])
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const polyline = new Cesium.GroundPolylineGeometry({
|
||||
positions: Cesium.Cartesian3.fromDegreesArray(positions),
|
||||
width: that.options.width //线宽
|
||||
// vertexFormat: Cesium.PolylineColorAppearance.VERTEX_FORMAT
|
||||
})
|
||||
// let geometry = Cesium.PolylineGeometry.createGeometry(polyline)
|
||||
instances.push(
|
||||
new Cesium.GeometryInstance({
|
||||
geometry: polyline
|
||||
// attributes: {
|
||||
// color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.BLUE),
|
||||
// },
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
that.primitive = new Cesium.GroundPolylinePrimitive({
|
||||
geometryInstances: instances,
|
||||
// appearance: new Cesium.PerInstanceColorAppearance({ // 为每个instance着色
|
||||
// translucent: true,
|
||||
// closed: false
|
||||
// }),
|
||||
appearance: new Cesium.PolylineMaterialAppearance({
|
||||
material: Cesium.Material.fromType('Color', {
|
||||
color: Cesium.Color.fromCssColorString(that.options.color)
|
||||
})
|
||||
}),
|
||||
asynchronous: false, // 确定基元是异步创建还是阻塞直到准备就绪
|
||||
show: that.options.show ?? true
|
||||
})
|
||||
that.viewer.scene.primitives.add(that.primitive)
|
||||
that.loading = false
|
||||
}
|
||||
|
||||
remove() {
|
||||
if (this.primitive) {
|
||||
super.remove()
|
||||
this.viewer.scene.primitives.remove(this.primitive)
|
||||
this.primitive = null
|
||||
}
|
||||
}
|
||||
|
||||
flyTo() {
|
||||
if (!this.loading) {
|
||||
if (this.positions) {
|
||||
let arr = new Tools().cal_envelope(this.positions)
|
||||
var rectangle = new Cesium.Rectangle.fromDegrees(
|
||||
arr[0][0],
|
||||
arr[0][1],
|
||||
arr[2][0],
|
||||
arr[2][1]
|
||||
)
|
||||
this.viewer.camera.flyTo({
|
||||
destination: rectangle
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flicker() {}
|
||||
}
|
||||
|
||||
export default GeoJson
|
||||
185
src/Obj/Base/GeoJson/index3.js
Normal file
185
src/Obj/Base/GeoJson/index3.js
Normal file
@ -0,0 +1,185 @@
|
||||
/**
|
||||
* @name: index
|
||||
* @author: Administrator
|
||||
* @date: 2023-03-04 10:39
|
||||
* @description:index
|
||||
* @update: 2023-03-04 10:39
|
||||
*/
|
||||
import { getHost } from "../../../on";
|
||||
import Base from '../index'
|
||||
import Tools from '../../../Tools'
|
||||
|
||||
class GeoJson extends Base {
|
||||
/**
|
||||
* @constructor
|
||||
* @param sdk
|
||||
* @param options {object} 参数
|
||||
* @param options.id {string} id
|
||||
* @param options.url {string} geojson地址
|
||||
* @param [options.color=#ef0606] {string} 线条颜色
|
||||
* @param [options.width=1] {number} 线条宽度
|
||||
* @example new YJ.Obj.GeoJson(earth,{id:"123",url:""})
|
||||
* */
|
||||
constructor(sdk, options = {}) {
|
||||
super(sdk, options)
|
||||
|
||||
this.primitive = undefined
|
||||
this.positions = []
|
||||
|
||||
this.loading = true
|
||||
}
|
||||
|
||||
setDefaultValue() {
|
||||
super.setDefaultValue()
|
||||
this.options.host = this.options.host || getHost()
|
||||
let url = this.options.url
|
||||
if (this.options.host) {
|
||||
let o = new URL(this.options.url, this.options.host)
|
||||
url = o.href
|
||||
}
|
||||
|
||||
this.options.url = url
|
||||
this.options.color = this.options.color || 'rgb(239, 6, 6, 0.2)'
|
||||
this.options.width = this.options.width || 1
|
||||
}
|
||||
|
||||
get show() {
|
||||
if (this.primitive) return this.primitive.show
|
||||
return undefined
|
||||
}
|
||||
|
||||
set show(status) {
|
||||
if (this.primitive) {
|
||||
this.primitive.show = status
|
||||
}
|
||||
}
|
||||
|
||||
async on() {
|
||||
let rsp = await fetch(this.options.url)
|
||||
let json = await rsp.json()
|
||||
this.geojson = json
|
||||
return GeoJson.addDataToGlobe(this, json.features)
|
||||
}
|
||||
|
||||
/*geojosn暂时只用线的形式*/
|
||||
static addDataToGlobe(that, features) {
|
||||
const instancesList = []
|
||||
const instancesPolygon = []
|
||||
for (let i = 0; i < features.length; i++) {
|
||||
let color = Cesium.Color.fromRandom().withAlpha(0.2)
|
||||
if(features[i].geometry.type === 'LineString' || features[i].geometry.type === 'MultiLineString') {
|
||||
let coordinates = features[i].geometry.coordinates
|
||||
if(features[i].geometry.type === 'LineString') {
|
||||
coordinates = [features[i].geometry.coordinates]
|
||||
}
|
||||
for (let m = 0; m < coordinates.length; m++) {
|
||||
let item = coordinates[i]
|
||||
let positions = []
|
||||
item.forEach(c => {
|
||||
positions.push(c[0], c[1])
|
||||
})
|
||||
const polyline = new Cesium.GroundPolylineGeometry({
|
||||
positions: Cesium.Cartesian3.fromDegreesArray(positions),
|
||||
width: that.options.width //线宽
|
||||
})
|
||||
instancesList.push(
|
||||
new Cesium.GeometryInstance({
|
||||
geometry: polyline
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if(features[i].geometry.type === 'Polygon' || features[i].geometry.type === 'MultiPolygon') {
|
||||
let coordinates = features[i].geometry.coordinates
|
||||
if(features[i].geometry.type === 'Polygon') {
|
||||
coordinates = [features[i].geometry.coordinates]
|
||||
}
|
||||
for (let m = 0; m < coordinates.length; m++) {
|
||||
let item = coordinates[m]
|
||||
item.forEach(p => {
|
||||
let positions = []
|
||||
p.forEach(c => {
|
||||
positions.push(c[0], c[1])
|
||||
})
|
||||
let polygon = new Cesium.PolygonGeometry({
|
||||
polygonHierarchy: new Cesium.PolygonHierarchy(Cesium.Cartesian3.fromDegreesArray(positions)),
|
||||
});
|
||||
instancesPolygon.push(
|
||||
new Cesium.GeometryInstance({
|
||||
geometry: polygon,
|
||||
attributes: {
|
||||
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
|
||||
Cesium.Color.fromRandom().withAlpha(0.2)
|
||||
),
|
||||
show: new Cesium.ShowGeometryInstanceAttribute(that.options.show ?? true), //显示或者隐藏
|
||||
},
|
||||
})
|
||||
)
|
||||
|
||||
const polyline = new Cesium.GroundPolylineGeometry({
|
||||
positions: Cesium.Cartesian3.fromDegreesArray(positions),
|
||||
width: 2
|
||||
})
|
||||
instancesList.push(
|
||||
new Cesium.GeometryInstance({
|
||||
geometry: polyline
|
||||
})
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (instancesList.length > 0) {
|
||||
that.primitive = new Cesium.GroundPolylinePrimitive({
|
||||
geometryInstances: instancesList,
|
||||
appearance: new Cesium.PolylineMaterialAppearance({
|
||||
material: Cesium.Material.fromType('Color', {
|
||||
color: Cesium.Color.fromCssColorString(that.options.color)
|
||||
})
|
||||
}),
|
||||
asynchronous: false, // 确定基元是异步创建还是阻塞直到准备就绪
|
||||
show: that.options.show ?? true
|
||||
})
|
||||
that.viewer.scene.primitives.add(that.primitive)
|
||||
}
|
||||
if (instancesPolygon.length > 0) {
|
||||
that.primitive = new Cesium.GroundPrimitive({
|
||||
geometryInstances: instancesPolygon,
|
||||
appearance: new Cesium.PerInstanceColorAppearance({
|
||||
translucent: true, //false时透明度无效
|
||||
closed: false,
|
||||
}),
|
||||
asynchronous: false, // 确定基元是异步创建还是阻塞直到准备就绪
|
||||
show: that.options.show ?? true
|
||||
})
|
||||
that.viewer.scene.primitives.add(that.primitive)
|
||||
}
|
||||
|
||||
that.loading = false
|
||||
}
|
||||
|
||||
remove() {
|
||||
if (this.primitive) {
|
||||
super.remove()
|
||||
this.viewer.scene.primitives.remove(this.primitive)
|
||||
this.primitive = null
|
||||
}
|
||||
}
|
||||
|
||||
flyTo() {
|
||||
if (!this.loading) {
|
||||
if(this.geojson) {
|
||||
let range = turf.bbox(this.geojson);
|
||||
this.viewer.camera.flyTo({
|
||||
destination: Cesium.Rectangle.fromDegrees(...range)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flicker() { }
|
||||
}
|
||||
|
||||
export default GeoJson
|
||||
22
src/Obj/Base/Graffiti/_element.js
Normal file
22
src/Obj/Base/Graffiti/_element.js
Normal file
@ -0,0 +1,22 @@
|
||||
function html() {
|
||||
return `
|
||||
<span class="custom-divider"></span>
|
||||
<div class="div-item">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">涂鸦颜色</span>
|
||||
<div class="color"></div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">线条宽度</span>
|
||||
<div class="input-number input-number-unit-2" style="width: 80px;">
|
||||
<input class="input" type="number" title="" min="1" max="99" step="1" @model="width">
|
||||
<span class="unit">px</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
export { html }
|
||||
227
src/Obj/Base/Graffiti/index.js
Normal file
227
src/Obj/Base/Graffiti/index.js
Normal file
@ -0,0 +1,227 @@
|
||||
/**
|
||||
* 涂鸦
|
||||
*/
|
||||
import Draw from '../../../Draw/draw'
|
||||
import MouseTip from '../../../MouseTip'
|
||||
import MouseEvent from '../../../Event'
|
||||
import Dialog from '../../../BaseDialog';
|
||||
import EventBinding from '../../Element/Dialog/eventBinding';
|
||||
import { html } from "./_element";
|
||||
import { CameraController } from '../../../Global/global'
|
||||
|
||||
class Graffiti extends Draw {
|
||||
/**
|
||||
* @constructor
|
||||
* @param sdk
|
||||
* @description 涂鸦
|
||||
* @param options {object} 线属性
|
||||
* @param options.width=10{number} 宽度
|
||||
* @param options.color=#ff0000{string} 宽度
|
||||
* */
|
||||
constructor(sdk, options = {}) {
|
||||
super(sdk, options);
|
||||
this.options.width = options.width || 1
|
||||
this.options.color = options.color || '#ff0000'
|
||||
this._elms = {};
|
||||
this._EventBinding = new EventBinding()
|
||||
Graffiti.edit(this, true)
|
||||
}
|
||||
|
||||
get color() {
|
||||
return this.options.color
|
||||
}
|
||||
set color(v) {
|
||||
if(!this.options.color) {
|
||||
return
|
||||
}
|
||||
this.options.color = v
|
||||
if (this._elms.color) {
|
||||
this._elms.color.forEach((item, i) => {
|
||||
let colorPicker = new ewPlugins('colorpicker', {
|
||||
el: item.el,
|
||||
size: 'mini',//颜色box类型
|
||||
alpha: true,//是否开启透明度
|
||||
defaultColor: v,
|
||||
disabled: false,//是否禁止打开颜色选择器
|
||||
openPickerAni: 'opacity',//打开颜色选择器动画
|
||||
sure: (c) => {
|
||||
this.color = c
|
||||
},//点击确认按钮事件回调
|
||||
clear: () => {
|
||||
this.color = 'rgba(255,255,255,1)'
|
||||
},//点击清空按钮事件回调
|
||||
})
|
||||
this._elms.color[i] = colorPicker
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
get width() {
|
||||
return this.options.width
|
||||
}
|
||||
set width(v) {
|
||||
this.options.width = v
|
||||
this._elms.width && this._elms.width.forEach((item) => {
|
||||
item.value = v
|
||||
})
|
||||
}
|
||||
|
||||
// 编辑框
|
||||
static async edit(that, state) {
|
||||
if (state) {
|
||||
that._DialogObject = await new Dialog(that.sdk.viewer._container, {
|
||||
title: '涂鸦参数',
|
||||
})
|
||||
await that._DialogObject.init()
|
||||
let contentElm = document.createElement('div');
|
||||
contentElm.innerHTML = html()
|
||||
that._DialogObject.contentAppChild(contentElm)
|
||||
// 颜色组件
|
||||
let colorPicker = new ewPlugins('colorpicker', {
|
||||
el: contentElm.getElementsByClassName("color")[0],
|
||||
size: 'mini',//颜色box类型
|
||||
alpha: true,//是否开启透明度
|
||||
defaultColor: that.color,
|
||||
disabled: false,//是否禁止打开颜色选择器
|
||||
openPickerAni: 'opacity',//打开颜色选择器动画
|
||||
sure: (color) => {
|
||||
that.color = color
|
||||
},//点击确认按钮事件回调
|
||||
clear: () => {
|
||||
that.color = 'rgba(255,255,255,1)'
|
||||
},//点击清空按钮事件回调
|
||||
})
|
||||
that._DialogObject._element.body.className = that._DialogObject._element.body.className + ' graffiti'
|
||||
let all_elm = contentElm.getElementsByTagName("*")
|
||||
that._EventBinding.on(that, all_elm)
|
||||
that._elms = that._EventBinding.element
|
||||
that._elms.color = [colorPicker]
|
||||
|
||||
let confirmBtn = document.createElement('button');
|
||||
confirmBtn.className = 'confirm';
|
||||
confirmBtn.innerHTML = '确认'
|
||||
that._DialogObject.footAppChild(confirmBtn)
|
||||
confirmBtn.addEventListener('click', () => {
|
||||
that.start()
|
||||
Graffiti.edit(that, false)
|
||||
});
|
||||
}
|
||||
else {
|
||||
if (that._DialogObject && that._DialogObject.close) {
|
||||
that._DialogObject.close()
|
||||
that._DialogObject = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @desc 开始动态获绘制线
|
||||
* @method start
|
||||
* })
|
||||
* */
|
||||
start() {
|
||||
let _this = this
|
||||
if (YJ.Measure.GetMeasureStatus()) {
|
||||
console.log('上一次测量未结束')
|
||||
} else {
|
||||
let viewer = this.sdk.viewer
|
||||
CameraController(this.sdk, false)
|
||||
super.start()
|
||||
YJ.Measure.SetMeasureStatus(true)
|
||||
this.tip = new MouseTip('长按左键,拖动鼠标进行涂鸦,右键结束涂鸦', this.sdk)
|
||||
this.event = new MouseEvent(this.sdk)
|
||||
this.positions = []
|
||||
this.points_ids = [] //存放左键点击时临时添加的point的id
|
||||
let polylineArray = []
|
||||
let positions = []
|
||||
|
||||
this.event.mouse_left_down((movement, cartesian) => {
|
||||
positions = []
|
||||
let line = this.sdk.viewer.entities.add({
|
||||
name: '涂鸦',
|
||||
polyline: {
|
||||
positions: new Cesium.CallbackProperty(function () {
|
||||
return positions
|
||||
}, false),
|
||||
width: this.width,
|
||||
clampToGround: true,
|
||||
material: Cesium.Color.fromCssColorString(this.color),
|
||||
zIndex: 99999999
|
||||
}
|
||||
})
|
||||
polylineArray.push(line)
|
||||
this.event.mouse_move((movement, cartesian) => {
|
||||
this.tip.setPosition(
|
||||
cartesian,
|
||||
movement.endPosition.x,
|
||||
movement.endPosition.y
|
||||
)
|
||||
positions.push(cartesian)
|
||||
})
|
||||
})
|
||||
this.event.mouse_left_up((movement, cartesian) => {
|
||||
polylineArray[polylineArray.length-1].polyline.positions = positions
|
||||
this.event.mouse_move((movement, cartesian) => {
|
||||
this.tip.setPosition(
|
||||
cartesian,
|
||||
movement.endPosition.x,
|
||||
movement.endPosition.y
|
||||
)
|
||||
})
|
||||
})
|
||||
this.event.mouse_move((movement, cartesian) => {
|
||||
this.tip.setPosition(
|
||||
cartesian,
|
||||
movement.endPosition.x,
|
||||
movement.endPosition.y
|
||||
)
|
||||
})
|
||||
this.event.mouse_right((movement, cartesian) => {
|
||||
this.end()
|
||||
})
|
||||
|
||||
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()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @desc 结束制线
|
||||
* @method end
|
||||
* })
|
||||
* */
|
||||
end() {
|
||||
YJ.Measure.SetMeasureStatus(false)
|
||||
this.event && this.event.destroy()
|
||||
this.event = undefined
|
||||
this.tip && this.tip.destroy()
|
||||
this.tip = undefined
|
||||
CameraController(this.sdk, true)
|
||||
}
|
||||
|
||||
remove() {
|
||||
this.end()
|
||||
if (this._DialogObject && this._DialogObject.close) {
|
||||
this._DialogObject.close()
|
||||
this._DialogObject = null
|
||||
}
|
||||
let entities = this.sdk.viewer.entities.values
|
||||
for (let i = entities.length - 1; i >= 0; i--) {
|
||||
if (entities[i].name === '涂鸦') {
|
||||
this.sdk.viewer.entities.remove(entities[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flicker() {}
|
||||
}
|
||||
|
||||
export default Graffiti
|
||||
42
src/Obj/Base/GroundImage/_element.js
Normal file
42
src/Obj/Base/GroundImage/_element.js
Normal file
@ -0,0 +1,42 @@
|
||||
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" maxlength="40" type="text" @model="name">
|
||||
</div>
|
||||
<div class="col">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="custom-divider"></span>
|
||||
<div class="div-item">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">旋转角度</span>
|
||||
<input type="range" max="360" min="0" step="0.1" @model="angle">
|
||||
<div class="input-number input-number-unit" style="width: 100px;flex: 0 0 100px;margin-left: 10px;">
|
||||
<input class="input" type="number" title="" min="0" max="360" step="0.1" @model="angle">
|
||||
<span class="unit">°</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">调整大小</span>
|
||||
<input type="range" max="99999" min="0" step="0.1" @model="scale">
|
||||
<div class="input-number input-number-unit-1" style="width: 100px;flex: 0 0 100px;margin-left: 10px;">
|
||||
<input class="input" type="number" title="" min="0" max="99999" step="0.1" @model="scale">
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="custom-divider"></span>
|
||||
`
|
||||
}
|
||||
|
||||
export { html }
|
||||
558
src/Obj/Base/GroundImage/index.js
Normal file
558
src/Obj/Base/GroundImage/index.js
Normal file
@ -0,0 +1,558 @@
|
||||
import Dialog from '../../Element/Dialog';
|
||||
import cy_slider from "../../Element/cy_html_slider";
|
||||
import { html } from "./_element";
|
||||
import EventBinding from '../../Element/Dialog/eventBinding';
|
||||
import Base from "../index";
|
||||
import MouseEvent from '../../../Event/index'
|
||||
import { syncData } from '../../../Global/MultiViewportMode'
|
||||
import MouseTip from '../../../MouseTip'
|
||||
import { setSplitDirection, syncSplitData, setActiveId } from '../../../Global/SplitScreen'
|
||||
import { setActiveViewer, closeRotateAround, closeViewFollow} from '../../../Global/global'
|
||||
|
||||
class GroundImage extends Base {
|
||||
/**
|
||||
* @constructor
|
||||
* @param sdk
|
||||
* @description 贴地图片
|
||||
* @param options {object} 属性
|
||||
* @param options.id {string} 唯一标识
|
||||
* @param options.show=true {boolean} 显示/隐藏
|
||||
* @param options.name {string} 名称
|
||||
* @param options.angle=0 {number} 旋转角度
|
||||
* @param options.scale=1 {number} 比例
|
||||
* @param options.flipe {object} 翻转
|
||||
* @param options.flipe.x=false {boolean} 绕X轴翻转
|
||||
* @param options.flipe.y=false {boolean} 绕Y轴翻转
|
||||
* @param options.url {string} 图片地址
|
||||
* @param {Array.<object>} options.positions 经纬度和高度的列表,值交替 [{lon,lat,alt},...]
|
||||
* @param _Dialog {object} 弹框事件
|
||||
* @param _Dialog.confirmCallBack {function} 弹框确认时的回调
|
||||
* */
|
||||
constructor(sdk, options = {}, _Dialog = {}) {
|
||||
super(sdk, options);
|
||||
this.options.name = options.name || '未命名对象'
|
||||
this.options.show = (options.show || options.show === false) ? options.show : true
|
||||
this.options.url = options.url
|
||||
this.options.angle = options.angle || 0
|
||||
this.options.scale = (options.scale || options.scale === 0) ? options.scale : 1
|
||||
this.options.positions = options.positions
|
||||
|
||||
this.options.flipe = options.flipe || {}
|
||||
this.options.flipe.x = this.options.flipe.x || false
|
||||
this.options.flipe.y = this.options.flipe.y || false
|
||||
|
||||
this.entity = {
|
||||
id: this.options.id
|
||||
}
|
||||
this._positionEditing = false
|
||||
this.Dialog = _Dialog
|
||||
this._elms = {};
|
||||
this.previous = {
|
||||
positions: { ...this.options.positions }
|
||||
}
|
||||
this._EventBinding = new EventBinding()
|
||||
this.event = new MouseEvent(this.sdk)
|
||||
this.sdk.addIncetance(this.options.id, this)
|
||||
this.create()
|
||||
}
|
||||
|
||||
get angle() {
|
||||
return this.options.angle
|
||||
}
|
||||
|
||||
set angle(v) {
|
||||
this.options.angle = v
|
||||
this._elms.angle && this._elms.angle.forEach((item) => {
|
||||
item.value = v
|
||||
})
|
||||
}
|
||||
|
||||
get scale() {
|
||||
return this.options.scale
|
||||
}
|
||||
|
||||
set scale(v) {
|
||||
this.options.scale = v
|
||||
this._elms.scale && this._elms.scale.forEach((item) => {
|
||||
item.value = v
|
||||
})
|
||||
}
|
||||
|
||||
get flipeY() {
|
||||
return this.options.flipe.y
|
||||
}
|
||||
set flipeY(v) {
|
||||
if (typeof v === "boolean") {
|
||||
this.options.flipe.y = v
|
||||
if (!this.entity) {
|
||||
return
|
||||
}
|
||||
const img = new Image();
|
||||
img.src = this.options.url;
|
||||
img.onload = () => {
|
||||
const canvas = document.createElement('canvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
// 设置画布大小
|
||||
canvas.width = img.width;
|
||||
canvas.height = img.height;
|
||||
|
||||
// 绘制图像
|
||||
if (this.flipeX) {
|
||||
ctx.scale(1, -1);
|
||||
ctx.translate(0, -canvas.height)
|
||||
}
|
||||
if (this.flipeY) {
|
||||
ctx.scale(-1, 1);
|
||||
ctx.translate(-canvas.width, 0);
|
||||
}
|
||||
ctx.drawImage(img, 0, 0);
|
||||
this.entity && (this.entity.rectangle.material = new Cesium.ImageMaterialProperty({
|
||||
image: canvas,
|
||||
transparent: true
|
||||
}))
|
||||
}
|
||||
} else {
|
||||
console.error("参数必须为boolean")
|
||||
}
|
||||
}
|
||||
get flipeX() {
|
||||
return this.options.flipe.x
|
||||
}
|
||||
set flipeX(v) {
|
||||
if (typeof v === "boolean") {
|
||||
this.options.flipe.x = v
|
||||
if (!this.entity) {
|
||||
return
|
||||
}
|
||||
const img = new Image();
|
||||
img.src = this.options.url;
|
||||
img.onload = () => {
|
||||
const canvas = document.createElement('canvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
// 设置画布大小
|
||||
canvas.width = img.width;
|
||||
canvas.height = img.height;
|
||||
|
||||
// 绘制图像
|
||||
if (this.flipeX) {
|
||||
ctx.scale(1, -1);
|
||||
ctx.translate(0, -canvas.height)
|
||||
}
|
||||
if (this.flipeY) {
|
||||
ctx.scale(-1, 1);
|
||||
ctx.translate(-canvas.width, 0);
|
||||
}
|
||||
ctx.drawImage(img, 0, 0);
|
||||
this.entity.rectangle.material = new Cesium.ImageMaterialProperty({
|
||||
image: canvas,
|
||||
transparent: true
|
||||
})
|
||||
}
|
||||
} else {
|
||||
console.error("参数必须为boolean")
|
||||
}
|
||||
}
|
||||
|
||||
async create() {
|
||||
// let gap = Math.abs(Math.cos(Math.PI/180 * this.options.positions.lat)) * (0.0001*this.options.scale)
|
||||
// let fromDegreesArray = [
|
||||
// this.options.positions.lng - 0.05, this.options.positions.lat - 0.05,
|
||||
// this.options.positions.lng + 0.05, this.options.positions.lat - 0.05,
|
||||
// this.options.positions.lng + 0.05, this.options.positions.lat + 0.05,
|
||||
// this.options.positions.lng - 0.05, this.options.positions.lat + 0.05,
|
||||
// ]
|
||||
let response = await fetch(this.options.url, {
|
||||
method: 'get',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
}
|
||||
})
|
||||
if (response.ok) {
|
||||
// let data = await response.blob()
|
||||
// let arrayBuffer = await data.arrayBuffer()
|
||||
// const str = String.fromCharCode(...new Uint8Array(arrayBuffer));
|
||||
const img = new Image();
|
||||
img.src = this.options.url;
|
||||
img.onload = () => {
|
||||
const canvas = document.createElement('canvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
// 设置画布大小
|
||||
canvas.width = img.width;
|
||||
canvas.height = img.height;
|
||||
// 绘制图像
|
||||
if (this.flipeX) {
|
||||
ctx.scale(1, -1);
|
||||
ctx.translate(0, -canvas.height)
|
||||
}
|
||||
if (this.flipeY) {
|
||||
ctx.scale(-1, 1);
|
||||
ctx.translate(-canvas.width, 0);
|
||||
}
|
||||
ctx.drawImage(img, 0, 0);
|
||||
|
||||
this.entity = this.sdk.viewer.entities.add({
|
||||
id: this.options.id,
|
||||
show: this.options.show,
|
||||
rectangle: {
|
||||
coordinates: new Cesium.CallbackProperty(() => {
|
||||
let gap = Math.abs(Math.cos(Math.PI / 180 * this.options.positions.lat)) * (0.0001 * this.options.scale)
|
||||
let fromDegreesArray = [
|
||||
this.options.positions.lng - (0.0001 * this.options.scale), this.options.positions.lat - gap,
|
||||
// this.options.positions.lng + 0.05, this.options.positions.lat - 0.05,
|
||||
this.options.positions.lng + (0.0001 * this.options.scale), this.options.positions.lat + gap,
|
||||
// this.options.positions.lng - 0.05, this.options.positions.lat + 0.05,
|
||||
]
|
||||
|
||||
return Cesium.Rectangle.fromDegrees(...fromDegreesArray)
|
||||
}, false),
|
||||
material: new Cesium.ImageMaterialProperty({
|
||||
image: canvas,
|
||||
transparent: true
|
||||
}),
|
||||
rotation: new Cesium.CallbackProperty(() => {
|
||||
return Cesium.Math.toRadians(this.options.angle)
|
||||
}, false),
|
||||
stRotation: new Cesium.CallbackProperty(() => {
|
||||
return Cesium.Math.toRadians(this.options.angle)
|
||||
}, false)
|
||||
},
|
||||
})
|
||||
if (this.sdk.viewer._element.className === 'cesium-viewer 2d') {
|
||||
this.entity.rectangle.height = 0
|
||||
}
|
||||
syncData(this.sdk, this.options.id)
|
||||
if(this.options.show) {
|
||||
|
||||
setSplitDirection(0, this.options.id)
|
||||
}
|
||||
}
|
||||
|
||||
// if (data.code === 200 || data.code === 0) {
|
||||
// this.$message({
|
||||
// message: '添加成功!',
|
||||
// type: 'success',
|
||||
// duration: 1500
|
||||
// });
|
||||
// this.close()
|
||||
// // this.$emit('getBuildingList')
|
||||
// // this.$emit('onSubmitCallBack')
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 编辑框
|
||||
async edit(state) {
|
||||
let _this = this
|
||||
this.originalOptions = { ...this.options }
|
||||
if (this._DialogObject && this._DialogObject.close) {
|
||||
this._DialogObject.close()
|
||||
this._DialogObject = null
|
||||
}
|
||||
if (state) {
|
||||
this._DialogObject = await new Dialog(this.sdk, this.originalOptions, {
|
||||
title: '军标属性', left: '180px', top: '100px',
|
||||
confirmCallBack: (options) => {
|
||||
this.name = this.name.trim()
|
||||
if (!this.name) {
|
||||
this.name = '未命名对象'
|
||||
}
|
||||
this.originalOptions = this.deepCopyObj(this.options)
|
||||
this._DialogObject.close()
|
||||
this.Dialog.confirmCallBack && this.Dialog.confirmCallBack(this.originalOptions)
|
||||
syncData(this.sdk, this.options.id)
|
||||
syncSplitData(this.sdk, this.options.id)
|
||||
},
|
||||
resetCallBack: () => {
|
||||
this.reset()
|
||||
this.Dialog.resetCallBack && this.Dialog.resetCallBack()
|
||||
},
|
||||
removeCallBack: () => {
|
||||
this.Dialog.removeCallBack && this.Dialog.removeCallBack()
|
||||
},
|
||||
closeCallBack: () => {
|
||||
this.reset()
|
||||
// this.entity.style = new Cesium.Cesium3DTileStyle({
|
||||
// color: "color('rgba(255,255,255," + this.newData.transparency + ")')",
|
||||
// show: true,
|
||||
// });
|
||||
this.positionEditing = false
|
||||
this.Dialog.closeCallBack && this.Dialog.closeCallBack()
|
||||
},
|
||||
showCallBack: (show) => {
|
||||
this.show = show
|
||||
this.Dialog.showCallBack && this.Dialog.showCallBack()
|
||||
},
|
||||
translationalCallBack: () => {
|
||||
this.positionEditing = !this.positionEditing
|
||||
},
|
||||
addFootElm: [
|
||||
{
|
||||
tagName: 'button',
|
||||
className: 'flipe-over-y',
|
||||
innerHTML: 'Y轴翻转',
|
||||
event: [
|
||||
'click',
|
||||
() => {
|
||||
this.flipeY = !this.flipeY
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
tagName: 'button',
|
||||
className: 'flipe-over-x',
|
||||
innerHTML: 'X轴翻转',
|
||||
event: [
|
||||
'click',
|
||||
() => {
|
||||
this.flipeX = !this.flipeX
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}, true)
|
||||
this._DialogObject._element.body.className = this._DialogObject._element.body.className + ' ground-image'
|
||||
let contentElm = document.createElement('div');
|
||||
contentElm.innerHTML = html()
|
||||
this._DialogObject.contentAppChild(contentElm)
|
||||
let all_elm = contentElm.getElementsByTagName("*")
|
||||
this._EventBinding.on(this, all_elm)
|
||||
this._elms = this._EventBinding.element
|
||||
|
||||
} else {
|
||||
if (this._DialogObject && this._DialogObject.remove) {
|
||||
this._DialogObject.remove()
|
||||
this._DialogObject = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**@desc 打开平移功能
|
||||
*
|
||||
* @memberOf Source
|
||||
* @param status {boolean}
|
||||
*
|
||||
* */
|
||||
set positionEditing(status) {
|
||||
if (!this.sdk || !this.sdk.viewer || !this.entity) {
|
||||
return
|
||||
}
|
||||
this._positionEditing = status
|
||||
this.previous = {
|
||||
positions: { ...this.options.positions }
|
||||
}
|
||||
if (status === true) {
|
||||
this.tip && this.tip.destroy()
|
||||
this.tip = new MouseTip('点击鼠标左键确认,右键取消', this.sdk)
|
||||
this.event.mouse_move((movement, cartesian) => {
|
||||
let positions = this.cartesian3Towgs84(cartesian, this.sdk.viewer)
|
||||
this.options.positions.lng = positions.lng
|
||||
this.options.positions.lat = positions.lat
|
||||
this.options.positions.alt = positions.alt
|
||||
this.tip.setPosition(
|
||||
cartesian,
|
||||
movement.endPosition.x,
|
||||
movement.endPosition.y
|
||||
)
|
||||
})
|
||||
this.event.mouse_left((movement, cartesian) => {
|
||||
let positions = this.cartesian3Towgs84(cartesian, this.sdk.viewer)
|
||||
this.options.positions.lng = positions.lng
|
||||
this.options.positions.lat = positions.lat
|
||||
this.options.positions.alt = positions.alt
|
||||
this.event.mouse_move(() => { })
|
||||
this.event.mouse_left(() => { })
|
||||
this.event.mouse_right(() => { })
|
||||
this.event.gesture_pinck_start(() => { })
|
||||
this.event.gesture_pinck_end(() => { })
|
||||
this.positionEditing = false
|
||||
})
|
||||
this.event.mouse_right((movement, cartesian) => {
|
||||
this.options.positions.lng = this.previous.positions.lng
|
||||
this.options.positions.lat = this.previous.positions.lat
|
||||
this.options.positions.alt = this.previous.positions.alt
|
||||
this.positionEditing = false
|
||||
})
|
||||
|
||||
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.options.positions.lng = this.previous.positions.lng
|
||||
this.options.positions.lat = this.previous.positions.lat
|
||||
this.options.positions.alt = this.previous.positions.alt
|
||||
this.positionEditing = false
|
||||
}
|
||||
else {
|
||||
let positions = this.cartesian3Towgs84(cartesian, this.sdk.viewer)
|
||||
this.options.positions.lng = positions.lng
|
||||
this.options.positions.lat = positions.lat
|
||||
this.options.positions.alt = positions.alt
|
||||
this.event.mouse_move(() => { })
|
||||
this.event.mouse_left(() => { })
|
||||
this.event.mouse_right(() => { })
|
||||
this.event.gesture_pinck_start(() => { })
|
||||
this.event.gesture_pinck_end(() => { })
|
||||
this.positionEditing = false
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
else {
|
||||
if (this.event) {
|
||||
this.event.mouse_move(() => { })
|
||||
this.event.mouse_left(() => { })
|
||||
this.event.mouse_right(() => { })
|
||||
this.event.gesture_pinck_start(() => { })
|
||||
this.event.gesture_pinck_end(() => { })
|
||||
}
|
||||
this.tip && this.tip.destroy()
|
||||
this.options.positions.lng = this.previous.positions.lng
|
||||
this.options.positions.lat = this.previous.positions.lat
|
||||
this.options.positions.alt = this.previous.positions.alt
|
||||
}
|
||||
}
|
||||
|
||||
get positionEditing() {
|
||||
return this._positionEditing
|
||||
}
|
||||
|
||||
/**
|
||||
* 飞到
|
||||
*/
|
||||
async flyTo(options = {}) {
|
||||
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.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 gap = Math.abs(Math.cos(Math.PI / 180 * this.options.positions.lat)) * (0.0001 * this.options.scale)
|
||||
let fromDegreesArray = [
|
||||
[this.options.positions.lng - (0.0001 * this.options.scale), this.options.positions.lat - gap],
|
||||
[this.options.positions.lng + (0.0001 * this.options.scale), this.options.positions.lat + gap],
|
||||
]
|
||||
let positionArray = []
|
||||
let height = 0
|
||||
let position = this.options.positions
|
||||
let point1 = Cesium.Cartesian3.fromDegrees(position.lng, position.lat, 0);
|
||||
let point2 = Cesium.Cartesian3.fromDegrees(position.lng, position.lat, 10000000);
|
||||
let direction = Cesium.Cartesian3.subtract(point2, point1, new Cesium.Cartesian3());
|
||||
let c = Cesium.Cartesian3.normalize(direction, direction);
|
||||
let ray = new Cesium.Ray(point1, c);
|
||||
let r = {}
|
||||
let pickedObjects = this.sdk.viewer.scene.drillPickFromRay(ray);
|
||||
for (let i = 0; i < pickedObjects.length; i++) {
|
||||
if (pickedObjects[i].position) {
|
||||
r = pickedObjects[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
if (r && r.position) {
|
||||
height = this.cartesian3Towgs84(r.position, this.sdk.viewer).alt
|
||||
}
|
||||
else {
|
||||
try {
|
||||
var promise = await Cesium.sampleTerrainMostDetailed(this.sdk.viewer.terrainProvider, [Cesium.Cartographic.fromDegrees(position.lng, position.lat)]);
|
||||
height = promise[0].height
|
||||
} catch (error) {
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < fromDegreesArray.length; i++) {
|
||||
let a = Cesium.Cartesian3.fromDegrees(...fromDegreesArray[i], height)
|
||||
positionArray.push(a.x, a.y, a.z)
|
||||
}
|
||||
let BoundingSphere = Cesium.BoundingSphere.fromVertices(positionArray)
|
||||
this.sdk.viewer.camera.flyToBoundingSphere(BoundingSphere, {
|
||||
offset: options.orientation || {
|
||||
heading: Cesium.Math.toRadians(0.0),
|
||||
pitch: Cesium.Math.toRadians(-90.0),
|
||||
roll: Cesium.Math.toRadians(0.0)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
reset() {
|
||||
if (!this.entity) {
|
||||
return
|
||||
}
|
||||
this.name = this.originalOptions.name
|
||||
this.angle = this.originalOptions.angle
|
||||
this.scale = this.originalOptions.scale
|
||||
}
|
||||
|
||||
async remove() {
|
||||
this.event && this.event.destroy()
|
||||
this.tip && this.tip.destroy()
|
||||
this.sdk.viewer.entities.remove(this.entity)
|
||||
this.entity = null
|
||||
if (this._DialogObject && !this._DialogObject.isDestroy) {
|
||||
this._DialogObject.close()
|
||||
this._DialogObject = null
|
||||
}
|
||||
await this.sdk.removeIncetance(this.options.id)
|
||||
await syncData(this.sdk, this.options.id)
|
||||
}
|
||||
|
||||
setPosition(v) {
|
||||
this.options.positions.lng = v.position.lng
|
||||
this.options.positions.lat = v.position.lat
|
||||
this.options.positions.alt = v.position.alt
|
||||
}
|
||||
}
|
||||
|
||||
export default GroundImage
|
||||
113
src/Obj/Base/GroundSvg/_element.js
Normal file
113
src/Obj/Base/GroundSvg/_element.js
Normal file
@ -0,0 +1,113 @@
|
||||
import { attributeElm } from '../../Element/elm_html'
|
||||
|
||||
function html(that) {
|
||||
return `
|
||||
<span class="custom-divider"></span>
|
||||
<div class="div-item">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">名称</span>
|
||||
<input class="input" maxlength="40" type="text" @model="name">
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">颜色</span>
|
||||
<div class="color"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="custom-divider"></span>
|
||||
<div class="div-item">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">旋转角度</span>
|
||||
<input type="range" max="360" min="0" step="0.1" @model="angle">
|
||||
<div class="input-number input-number-unit" style="width: 100px;flex: 0 0 100px;margin-left: 10px;">
|
||||
<input class="input" type="number" title="" min="0" max="360" step="0.1" @model="angle">
|
||||
<span class="unit">°</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col x-scale">
|
||||
<span class="label">X 轴大小</span>
|
||||
<input type="range" max="200" min="0.001" step="0.001">
|
||||
<div class="input-number" style="width: 100px;flex: 0 0 100px;margin-left: 10px;">
|
||||
<input class="input" type="number" title="" min="0.001" max="200" step="0.001">
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col y-scale">
|
||||
<span class="label">Y 轴大小</span>
|
||||
<input type="range" max="200" min="0.001" step="0.001">
|
||||
<div class="input-number" style="width: 100px;flex: 0 0 100px;margin-left: 10px;">
|
||||
<input class="input" type="number" title="" min="0.001" max="200" step="0.001">
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="custom-divider"></span>
|
||||
<div class="div-item">
|
||||
<div class="row">
|
||||
<div class="col" style="flex: 5;">
|
||||
<span class="label">文字内容</span>
|
||||
<input class="input" type="text" @model="textValue">
|
||||
</div>
|
||||
<div class="col">
|
||||
<button class="btn" @click="textPosPick">设置位置</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">文字开关</span>
|
||||
<input class="btn-switch" type="checkbox" @model="textShow">
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">字体颜色</span>
|
||||
<div class="textColor"></div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">字体大小</span>
|
||||
<div class="input-number input-number-unit-2">
|
||||
<input class="input" type="number" title="" min="1" max="99" @model="textFontSize">
|
||||
<span class="unit">px</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span class="label">视野缩放</span>
|
||||
<input class="btn-switch" type="checkbox" @model="textScaleByDistance">
|
||||
</div>
|
||||
<div class="col">
|
||||
<span class="label">最近距离</span>
|
||||
<div class="input-number input-number-unit-1">
|
||||
<input class="input" type="number" title="" min="1" max="99999999" @model="textNear">
|
||||
<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-1">
|
||||
<input class="input" type="number" title="" min="1" max="99999999" @model="textFar">
|
||||
<span class="unit">m</span>
|
||||
<span class="arrow"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="custom-divider"></span>
|
||||
<div class="div-item attribute-info">
|
||||
<div class="row">
|
||||
${attributeElm(that)}
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
|
||||
export { html }
|
||||
792
src/Obj/Base/GroundSvg/index-2.js
Normal file
792
src/Obj/Base/GroundSvg/index-2.js
Normal file
@ -0,0 +1,792 @@
|
||||
import Base from "../index";
|
||||
import * as THREE from '../../../../static/3rdparty/three/three.module.min.js';
|
||||
import { SVGLoader } from '../../../../static/3rdparty/three/jsm/loaders/SVGLoader.js';
|
||||
|
||||
// 合并图形,统一颜色
|
||||
class GroundSvg extends Base {
|
||||
#loadEvent=void 0
|
||||
constructor(sdk, options = {}) {
|
||||
super(sdk, options);
|
||||
this.options.angle = this.options.angle || 0
|
||||
this.options.color = this.options.color || '#ff0000'
|
||||
|
||||
this.loaded = false;
|
||||
|
||||
if (this.options.position.lat > 83.5) {
|
||||
this.options.position.lat = 83.5
|
||||
}
|
||||
if (this.options.position.lat < -83.5) {
|
||||
this.options.position.lat = -83.5
|
||||
}
|
||||
|
||||
this.hierarchys = []
|
||||
|
||||
this.options.scale = options.scale || {}
|
||||
this.options.scale.x = (this.options.scale.x || this.options.scale.x === 0) ? this.options.scale.x : 1
|
||||
this.options.scale.y = (this.options.scale.y || this.options.scale.y === 0) ? this.options.scale.y : 1
|
||||
|
||||
this.init()
|
||||
}
|
||||
|
||||
get position() {
|
||||
return this.options.position
|
||||
}
|
||||
|
||||
set position(v) {
|
||||
this.options.position = v
|
||||
if (this.options.position.lat > 83.5) {
|
||||
this.options.position.lat = 83.5
|
||||
}
|
||||
if (this.options.position.lat < -83.5) {
|
||||
this.options.position.lat = -83.5
|
||||
}
|
||||
this.update()
|
||||
}
|
||||
|
||||
get color() {
|
||||
return this.options.color
|
||||
}
|
||||
|
||||
set color(v) {
|
||||
this.options.color = v
|
||||
for (let i = 0; i < this.entity.values.length; i++) {
|
||||
this.entity.values[i].polygon.material = Cesium.Color.fromCssColorString(this.options.color || '#ff0000')
|
||||
}
|
||||
}
|
||||
|
||||
get angle() {
|
||||
return this.options.angle
|
||||
}
|
||||
|
||||
set angle(v) {
|
||||
this.options.angle = v
|
||||
this.update()
|
||||
}
|
||||
|
||||
get scale() {
|
||||
return this.options.scale
|
||||
}
|
||||
|
||||
set scale(scale) {
|
||||
this.options.scale.x = scale.x
|
||||
this.options.scale.y = scale.y
|
||||
this.update()
|
||||
}
|
||||
|
||||
init() {
|
||||
this.hierarchys = []
|
||||
let geometryArray = []
|
||||
const loader = new SVGLoader();
|
||||
loader.load(this.options.url, (data) => {
|
||||
data.xml.style.width = '0'
|
||||
data.xml.style.height = '0'
|
||||
document.body.appendChild(data.xml)
|
||||
for (const path of data.paths) {
|
||||
const fillColor = path.userData.style.fill;
|
||||
let style = window.getComputedStyle(path.userData.node)
|
||||
if (style.strokeWidth) {
|
||||
path.userData.style.strokeWidth = Number(style.strokeWidth.replace(/[a-zA-Z]/g, ''))
|
||||
}
|
||||
if (fillColor !== undefined && fillColor !== 'none') {
|
||||
const shapes = SVGLoader.createShapes(path);
|
||||
for (const shape of shapes) {
|
||||
const geometry = new THREE.ShapeGeometry(shape);
|
||||
const mesh = new THREE.Mesh(geometry);
|
||||
geometryArray.push(mesh.geometry)
|
||||
}
|
||||
}
|
||||
const strokeColor = path.userData.style.stroke;
|
||||
if (strokeColor !== undefined && strokeColor !== 'none') {
|
||||
for (const subPath of path.subPaths) {
|
||||
const geometry = SVGLoader.pointsToStroke(subPath.getPoints(), path.userData.style);
|
||||
if (geometry) {
|
||||
const mesh = new THREE.Mesh(geometry);
|
||||
geometryArray.push(mesh.geometry)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
document.body.removeChild(data.xml)
|
||||
|
||||
let min = 0
|
||||
let max = 0
|
||||
let geojson
|
||||
for (let key = 0; key < geometryArray.length; key++) {
|
||||
let geometry = geometryArray[key];
|
||||
let array = geometry.attributes.position.array
|
||||
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
if (min > array[i]) {
|
||||
min = array[i]
|
||||
}
|
||||
if (max < array[i]) {
|
||||
max = array[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
min = Math.abs(min)
|
||||
max = Math.abs(max)
|
||||
|
||||
if (min > max) {
|
||||
max = min
|
||||
}
|
||||
let max2 = max
|
||||
max = max * (10 / 3) * 100
|
||||
let scale = (4000 / max) / 5
|
||||
max2 = max2 * scale
|
||||
for (let key = 0; key < geometryArray.length; key++) {
|
||||
let positions = []
|
||||
let position = []
|
||||
geometryArray[key].scale(scale, scale, 1)
|
||||
|
||||
geometryArray[key].rotateX(THREE.MathUtils.degToRad(180))
|
||||
let geometry = geometryArray[key];
|
||||
let array = geometry.attributes.position.array
|
||||
|
||||
for (let i = 0; i < array.length; i += 3) {
|
||||
let x = array[i] - (max2 / 2)
|
||||
let y = array[i + 1] + (max2 / 2)
|
||||
position.push([x, y, array[i + 1]])
|
||||
}
|
||||
if (geometry.index && geometry.index.array) {
|
||||
let index = geometry.index.array
|
||||
for (let i = 0; i < index.length; i += 3) {
|
||||
positions.push([position[index[i]], position[index[i + 1]], position[index[i + 2]]])
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (let i = 0; i < position.length; i += 3) {
|
||||
positions.push([position[i], position[i + 1], position[i + 2]])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let polygons = []
|
||||
// 组合多边形
|
||||
for (let i = 0; i < positions.length; i++) {
|
||||
let polygon = turf.polygon([[
|
||||
...positions[i],
|
||||
positions[i][0]
|
||||
]]);
|
||||
polygons.push(polygon)
|
||||
|
||||
if (geojson) {
|
||||
geojson = turf.union(geojson, polygon);
|
||||
}
|
||||
else {
|
||||
geojson = polygon
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.geojson = JSON.parse(JSON.stringify(geojson))
|
||||
|
||||
// 计算边界框
|
||||
let bbox = turf.bbox(geojson);
|
||||
let width = Math.abs(bbox[2] - bbox[0])
|
||||
let height = Math.abs(bbox[3] - bbox[1])
|
||||
|
||||
// 获取最小正方形
|
||||
let square = turf.square(bbox);
|
||||
// 控制点界限
|
||||
square[0] = square[0] + this.options.position.lng - (width / 5)
|
||||
square[1] = square[1] + this.options.position.lat - (height / 5)
|
||||
square[2] = square[2] + this.options.position.lng + (width / 5)
|
||||
square[3] = square[3] + this.options.position.lat + (height / 5)
|
||||
|
||||
this.bbox = square
|
||||
|
||||
|
||||
|
||||
geojson = JSON.parse(JSON.stringify(this.geojson))
|
||||
|
||||
geojson.properties.directionDistance = []
|
||||
|
||||
|
||||
if (geojson.geometry.type === 'MultiPolygon') {
|
||||
for (let i = 0; i < geojson.geometry.coordinates.length; i++) {
|
||||
let array = []
|
||||
for (let m = 0; m < geojson.geometry.coordinates[i].length; m++) {
|
||||
let array2 = []
|
||||
for (let n = 0; n < geojson.geometry.coordinates[i][m].length; n++) {
|
||||
let point1 = turf.point([0, geojson.geometry.coordinates[i][m][n][1]])
|
||||
let point2 = turf.point([...geojson.geometry.coordinates[i][m][n]])
|
||||
let distance = turf.distance(point1, point2, { units: 'kilometers' });
|
||||
let angle = turf.rhumbBearing(point1, point2);
|
||||
array2.push(
|
||||
{
|
||||
origin: geojson.geometry.coordinates[i][m][n],
|
||||
distance: distance,
|
||||
angle: angle
|
||||
}
|
||||
)
|
||||
}
|
||||
array.push(array2)
|
||||
}
|
||||
geojson.properties.directionDistance.push(array)
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (let i = 0; i < geojson.geometry.coordinates.length; i++) {
|
||||
let array = []
|
||||
for (let m = 0; m < geojson.geometry.coordinates[i].length; m++) {
|
||||
let point1 = turf.point([0, geojson.geometry.coordinates[i][m][1]])
|
||||
let point2 = turf.point([...geojson.geometry.coordinates[i][m]])
|
||||
let distance = turf.distance(point1, point2, { units: 'kilometers' });
|
||||
let angle = turf.rhumbBearing(point1, point2);
|
||||
array.push(
|
||||
{
|
||||
origin: geojson.geometry.coordinates[i][m],
|
||||
distance: distance,
|
||||
angle: angle
|
||||
}
|
||||
)
|
||||
}
|
||||
geojson.properties.directionDistance.push(array)
|
||||
}
|
||||
}
|
||||
|
||||
if (geojson.geometry.type === 'MultiPolygon') {
|
||||
for (let i = 0; i < geojson.geometry.coordinates.length; i++) {
|
||||
let hierarchy = this.getHierarchyPolygon(geojson, i)
|
||||
this.hierarchys.push(hierarchy)
|
||||
}
|
||||
}
|
||||
else {
|
||||
let hierarchy = this.getHierarchyPolygon(geojson)
|
||||
this.hierarchys.push(hierarchy)
|
||||
}
|
||||
this.entity = new Cesium.EntityCollection()
|
||||
for (let i = 0; i < this.hierarchys.length; i++) {
|
||||
this.entity.add(this.sdk.viewer.entities.add({
|
||||
polygon: {
|
||||
hierarchy: new Cesium.CallbackProperty(() => {
|
||||
let hierarchy = this.hierarchys[i]
|
||||
let holes = []
|
||||
for (let m = 0; m < hierarchy.holes.length; m++) {
|
||||
holes.push({
|
||||
positions: hierarchy.holes[m]
|
||||
})
|
||||
}
|
||||
return {
|
||||
positions: hierarchy.positions,
|
||||
holes: holes
|
||||
}
|
||||
}, false),
|
||||
material: Cesium.Color.fromCssColorString(this.color),
|
||||
zIndex: 1
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
this.scale = this.scale
|
||||
|
||||
this.loaded = true
|
||||
if (this.#loadEvent) {
|
||||
this.#loadEvent()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
drag() {
|
||||
this.createControlPoints()
|
||||
this.update()
|
||||
}
|
||||
|
||||
getHierarchyPolygon(geojson, key) {
|
||||
let hierarchy = {}
|
||||
let holes = []
|
||||
let directionDistance = geojson.properties.directionDistance
|
||||
if (key !== undefined) {
|
||||
directionDistance = geojson.properties.directionDistance[key]
|
||||
}
|
||||
|
||||
for (let i = 0; i < directionDistance.length; i++) {
|
||||
let positions = []
|
||||
for (let m = 0; m < directionDistance[i].length; m++) {
|
||||
let lng = this.options.position.lng
|
||||
let lat = directionDistance[i][m].origin[1] + this.options.position.lat
|
||||
if (lat > 90) {
|
||||
lng += 180
|
||||
}
|
||||
let origin = [lng, lat]
|
||||
let pt = turf.point(origin);
|
||||
let destination = turf.rhumbDestination(pt, directionDistance[i][m].distance, directionDistance[i][m].angle, { units: 'kilometers' });
|
||||
positions.push(Cesium.Cartesian3.fromDegrees(...destination.geometry.coordinates))
|
||||
}
|
||||
if (i === 0) {
|
||||
|
||||
hierarchy.positions = positions
|
||||
}
|
||||
else {
|
||||
holes.push(positions)
|
||||
}
|
||||
}
|
||||
hierarchy.holes = holes
|
||||
return hierarchy
|
||||
}
|
||||
|
||||
createControlPoints() {
|
||||
if (this.ScreenSpaceEventHandler) {
|
||||
this.ScreenSpaceEventHandler.destroy()
|
||||
this.ScreenSpaceEventHandler = null
|
||||
}
|
||||
this.ScreenSpaceEventHandler = new Cesium.ScreenSpaceEventHandler(
|
||||
sdk.viewer.canvas
|
||||
)
|
||||
let width = Math.abs(this.bbox[0] - this.bbox[2])
|
||||
let height = Math.abs(this.bbox[1] - this.bbox[3])
|
||||
this.ScreenSpaceEventHandler.setInputAction(async (movement) => {
|
||||
if (this.pickPoint) {
|
||||
let sCartesian = this.pickPoint.position.getValue()
|
||||
let eCartesian = sdk.viewer.scene.pickPosition(movement.endPosition)
|
||||
if (!eCartesian) {
|
||||
const ray = sdk.viewer.camera.getPickRay(movement.endPosition);
|
||||
eCartesian = sdk.viewer.scene.globe.pick(ray, sdk.viewer.scene);
|
||||
}
|
||||
if (!sCartesian || !eCartesian) {
|
||||
return
|
||||
}
|
||||
let position1 = this.cartesian3Towgs84(sCartesian, sdk.viewer)
|
||||
let position2 = this.cartesian3Towgs84(eCartesian, sdk.viewer)
|
||||
let x = 0
|
||||
let y = 0
|
||||
|
||||
let radians, radiansW, radiansH
|
||||
|
||||
let w = 3.5 * this.scale.x
|
||||
let h = 3.5 * this.scale.y
|
||||
let wh = Math.sqrt(((w / 2) ** 2) + ((h / 2) ** 2))
|
||||
let angle = Math.atan((w / 2) / (h / 2)) * (180 / Math.PI)
|
||||
let angleW, angleH;
|
||||
|
||||
let point = turf.point([this.position.lng, this.position.lat]);
|
||||
let options = { units: 'kilometers' };
|
||||
let controlPoints = []
|
||||
controlPoints[0] = turf.destination(point, h / 2 * 1.5, 0 + this.options.angle, options).geometry.coordinates
|
||||
controlPoints[1] = turf.destination(point, wh, 180 + angle + this.options.angle, options).geometry.coordinates
|
||||
controlPoints[2] = turf.destination(point, h / 2, 180 + this.options.angle, options).geometry.coordinates
|
||||
controlPoints[3] = turf.destination(point, wh, 180 - angle + this.options.angle, options).geometry.coordinates
|
||||
controlPoints[4] = turf.destination(point, w / 2, 270 + this.options.angle, options).geometry.coordinates
|
||||
controlPoints[5] = [this.position.lng, this.position.lat]
|
||||
controlPoints[6] = turf.destination(point, w / 2, 90 + this.options.angle, options).geometry.coordinates
|
||||
controlPoints[7] = turf.destination(point, wh, 360 - angle + this.options.angle, options).geometry.coordinates
|
||||
controlPoints[8] = turf.destination(point, h / 2, 0 + this.options.angle, options).geometry.coordinates
|
||||
controlPoints[9] = turf.destination(point, wh, 0 + angle + this.options.angle, options).geometry.coordinates
|
||||
|
||||
let point1 = turf.point([position1.lng, position1.lat]);
|
||||
let point2 = turf.point([position2.lng, position2.lat]);
|
||||
let pointC = turf.point([this.position.lng, this.position.lat]);
|
||||
let bearing1 = turf.rhumbBearing(pointC, point1);
|
||||
let bearing2_0 = turf.rhumbBearing(pointC, point2);
|
||||
let bearing2 = (((bearing2_0 + 360) - this.angle) % 360)
|
||||
let bearingH
|
||||
let bearingW
|
||||
// 中心点到鼠标的距离
|
||||
let distance = turf.rhumbDistance(pointC, point2, options);
|
||||
|
||||
switch (this.pickPoint.id) {
|
||||
case 'svg-control-points_0':
|
||||
angle = bearing2_0 - bearing1
|
||||
this.angle += angle
|
||||
break
|
||||
case 'svg-control-points_1':
|
||||
case 'svg-control-points_7':
|
||||
bearingW = (((turf.rhumbBearing(pointC, turf.point(controlPoints[4])) + 360) - this.angle) % 360)
|
||||
bearingH = (((turf.rhumbBearing(pointC, turf.point(controlPoints[2])) + 360) - this.angle) % 360)
|
||||
angleW = bearing2 - bearingW
|
||||
angleH = bearing2 - bearingH
|
||||
|
||||
if ((angleW > -360 && angleW < -90) || (angleW < 360 && angleW > 90)) {
|
||||
angleW = angleW + 180
|
||||
}
|
||||
if ((angleH > -360 && angleH < -90) || (angleH < 360 && angleH > 90)) {
|
||||
angleH = angleH + 180
|
||||
}
|
||||
|
||||
radiansW = (Math.PI / 180) * angleW
|
||||
radiansH = (Math.PI / 180) * angleH
|
||||
// 矩形高度
|
||||
w = (Math.cos(radiansW) * distance) * 2
|
||||
h = (Math.cos(radiansH) * distance) * 2
|
||||
// scaleY值
|
||||
this.scale.x = w / 3.5
|
||||
this.scale.y = h / 3.5
|
||||
break
|
||||
case 'svg-control-points_2':
|
||||
case 'svg-control-points_8':
|
||||
bearingH = (((turf.rhumbBearing(pointC, turf.point(controlPoints[2])) + 360) - this.angle) % 360)
|
||||
angleH = bearing2 - bearingH
|
||||
|
||||
if ((angleH > -360 && angleH < -90) || (angleH < 360 && angleH > 90)) {
|
||||
angleH = angleH + 180
|
||||
}
|
||||
|
||||
radiansH = (Math.PI / 180) * angleH
|
||||
// 矩形高度
|
||||
h = (Math.cos(radiansH) * distance) * 2
|
||||
// scaleY值
|
||||
this.scale.y = h / 3.5
|
||||
break
|
||||
case 'svg-control-points_3':
|
||||
case 'svg-control-points_9':
|
||||
bearingW = (((turf.rhumbBearing(pointC, turf.point(controlPoints[6])) + 360) - this.angle) % 360)
|
||||
bearingH = (((turf.rhumbBearing(pointC, turf.point(controlPoints[2])) + 360) - this.angle) % 360)
|
||||
angleW = bearing2 - bearingW
|
||||
angleH = bearing2 - bearingH
|
||||
|
||||
if ((angleW > -360 && angleW < -90) || (angleW < 360 && angleW > 90)) {
|
||||
angleW = angleW + 180
|
||||
}
|
||||
if ((angleH > -360 && angleH < -90) || (angleH < 360 && angleH > 90)) {
|
||||
angleH = angleH + 180
|
||||
}
|
||||
|
||||
radiansW = (Math.PI / 180) * angleW
|
||||
radiansH = (Math.PI / 180) * angleH
|
||||
// 矩形高度
|
||||
w = (Math.cos(radiansW) * distance) * 2
|
||||
h = (Math.cos(radiansH) * distance) * 2
|
||||
// scaleY值
|
||||
this.scale.x = w / 3.5
|
||||
this.scale.y = h / 3.5
|
||||
break
|
||||
case 'svg-control-points_4':
|
||||
bearingW = (((turf.rhumbBearing(pointC, turf.point(controlPoints[4])) + 360) - this.angle) % 360)
|
||||
angleW = bearing2 - bearingW
|
||||
|
||||
if ((angleW > -360 && angleW < -90) || (angleW < 360 && angleW > 90)) {
|
||||
angleW = angleW + 180
|
||||
}
|
||||
|
||||
radiansW = (Math.PI / 180) * angleW
|
||||
// 矩形宽度
|
||||
w = (Math.cos(radiansW) * distance) * 2
|
||||
// scaleY值
|
||||
this.scale.x = w / 3.5
|
||||
|
||||
break
|
||||
case 'svg-control-points_5':
|
||||
if (position2.lat > 83.5) {
|
||||
position2.lat = 83.5
|
||||
}
|
||||
if (position2.lat < -83.5) {
|
||||
position2.lat = -83.5
|
||||
}
|
||||
this.position = {lng: position2.lng, lat: position2.lat}
|
||||
let cx = position2.lng - position1.lng
|
||||
let cy = position2.lat - position1.lat
|
||||
this.bbox[0] = this.bbox[0] + cx
|
||||
this.bbox[1] = this.bbox[1] + cy
|
||||
this.bbox[2] = this.bbox[2] + cx
|
||||
this.bbox[3] = this.bbox[3] + cy
|
||||
break
|
||||
case 'svg-control-points_6':
|
||||
bearingW = (((turf.rhumbBearing(pointC, turf.point(controlPoints[6])) + 360) - this.angle) % 360)
|
||||
angleW = bearing2 - bearingW
|
||||
|
||||
if ((angleW > -360 && angleW < -90) || (angleW < 360 && angleW > 90)) {
|
||||
angleW = angleW + 180
|
||||
}
|
||||
|
||||
radiansW = (Math.PI / 180) * angleW
|
||||
// 矩形高度
|
||||
w = (Math.cos(radiansW) * distance) * 2
|
||||
this.scale.x = w / 3.5
|
||||
|
||||
break
|
||||
default:
|
||||
}
|
||||
|
||||
// let radians = (Math.PI / 180) * this.options.angle
|
||||
// x = x*Math.cos(radians)
|
||||
// y = y*Math.cos(radians)
|
||||
|
||||
|
||||
// let bbox = turf.bbox(geojson);
|
||||
// let square = turf.square(bbox);
|
||||
|
||||
x = x / (width / 2) * 100
|
||||
y = y / (height / 2) * 100
|
||||
|
||||
let scale = { ...this.scale }
|
||||
scale.x = scale.x + x
|
||||
scale.y = scale.y - y
|
||||
|
||||
// let pt = turf.point(this.center);
|
||||
// let destination1 = turf.rhumbDestination(pt, 220, 45, { units: 'kilometers' });
|
||||
// let destination2 = turf.rhumbDestination(pt, 220, 225, { units: 'kilometers' });
|
||||
|
||||
// width = Math.abs(destination2.geometry.coordinates[0] - destination1.geometry.coordinates[0])
|
||||
// height = Math.abs(destination2.geometry.coordinates[1] - destination1.geometry.coordinates[1])
|
||||
|
||||
if (scale.y > 200) {
|
||||
scale.y = 200
|
||||
}
|
||||
if (scale.y < 0) {
|
||||
scale.y = 0
|
||||
}
|
||||
|
||||
if (scale.x > 200) {
|
||||
scale.x = 200
|
||||
}
|
||||
if (scale.x < 0) {
|
||||
scale.x = 0
|
||||
}
|
||||
|
||||
this.scale = { ...scale }
|
||||
|
||||
}
|
||||
else {
|
||||
let pickedObjectArray = sdk.viewer.scene.drillPick(movement.endPosition);
|
||||
let pickPoint
|
||||
for (let i = 0; i < pickedObjectArray.length; i++) {
|
||||
let pickedObject = pickedObjectArray[i]
|
||||
if (pickedObject && pickedObject.primitive && pickedObject.primitive._id &&
|
||||
(pickedObject.primitive._id.id && pickedObject.primitive._id.id.indexOf('svg-control-points_') !== -1)
|
||||
) {
|
||||
pickPoint = pickedObject.primitive._id
|
||||
break
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < this.pointEntityCollection.values.length; i++) {
|
||||
if (pickPoint && this.pointEntityCollection.values[i].id === pickPoint.id) {
|
||||
pickPoint.point.color = Cesium.Color.fromCssColorString('#ffff00')
|
||||
}
|
||||
else {
|
||||
switch (this.pointEntityCollection.values[i].id) {
|
||||
case 'svg-control-points_5':
|
||||
this.pointEntityCollection.values[i].point.color = Cesium.Color.fromCssColorString('#ffff00')
|
||||
break
|
||||
case 'svg-control-points_0':
|
||||
this.pointEntityCollection.values[i].point.color = Cesium.Color.fromCssColorString('#ff0000')
|
||||
break
|
||||
default:
|
||||
this.pointEntityCollection.values[i].point.color = Cesium.Color.fromCssColorString('#00ff0a')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
|
||||
this.ScreenSpaceEventHandler.setInputAction((movement) => {
|
||||
let pickedObjectArray = sdk.viewer.scene.drillPick(movement.position);
|
||||
for (let i = 0; i < pickedObjectArray.length; i++) {
|
||||
let pickedObject = pickedObjectArray[i]
|
||||
if (pickedObject && pickedObject.primitive && pickedObject.primitive._id && pickedObject.primitive._id.objectId === this.options.id &&
|
||||
(pickedObject.primitive._id.id && pickedObject.primitive._id.id.indexOf('svg-control-points_') !== -1)
|
||||
) {
|
||||
YJ.Global.CameraController(sdk, false)
|
||||
this.pickPoint = pickedObject.primitive._id
|
||||
this.pickPoint.point.color = Cesium.Color.fromCssColorString('#ff0000')
|
||||
break
|
||||
}
|
||||
}
|
||||
}, Cesium.ScreenSpaceEventType.LEFT_DOWN)
|
||||
this.ScreenSpaceEventHandler.setInputAction((movement) => {
|
||||
if (this.pickPoint) {
|
||||
YJ.Global.CameraController(sdk, true)
|
||||
switch (this.pickPoint.id) {
|
||||
case 'svg-control-points_4':
|
||||
this.pickPoint.point.color = Cesium.Color.fromCssColorString('#ffff00')
|
||||
break
|
||||
case 'svg-control-points_9':
|
||||
this.pickPoint.point.color = Cesium.Color.fromCssColorString('#ff0000')
|
||||
break
|
||||
default:
|
||||
this.pickPoint.point.color = Cesium.Color.fromCssColorString('#00ff0a')
|
||||
}
|
||||
this.pickPoint = null
|
||||
}
|
||||
}, Cesium.ScreenSpaceEventType.LEFT_UP)
|
||||
|
||||
|
||||
|
||||
|
||||
this.pointEntityCollection = new Cesium.EntityCollection()
|
||||
let w = 3.5 * this.scale.x
|
||||
let h = 3.5 * this.scale.y
|
||||
let wh = Math.sqrt(((w / 2) ** 2) + ((h / 2) ** 2))
|
||||
let angle = Math.atan((w / 2) / (h / 2)) * (180 / Math.PI)
|
||||
|
||||
let point = turf.point([this.position.lng, this.position.lat]);
|
||||
let options = { units: 'kilometers' };
|
||||
let controlPoints = []
|
||||
controlPoints[0] = turf.destination(point, h / 2 * 1.5, 0, options).geometry.coordinates
|
||||
controlPoints[1] = turf.destination(point, wh, 180 + angle, options).geometry.coordinates
|
||||
controlPoints[2] = turf.destination(point, h / 2, 180, options).geometry.coordinates
|
||||
controlPoints[3] = turf.destination(point, wh, 180 - angle, options).geometry.coordinates
|
||||
controlPoints[4] = turf.destination(point, w / 2, 270, options).geometry.coordinates
|
||||
controlPoints[5] = [this.position.lng, this.position.lat]
|
||||
controlPoints[6] = turf.destination(point, w / 2, 90, options).geometry.coordinates
|
||||
controlPoints[7] = turf.destination(point, wh, 360 - angle, options).geometry.coordinates
|
||||
controlPoints[8] = turf.destination(point, h / 2, 0, options).geometry.coordinates
|
||||
controlPoints[9] = turf.destination(point, wh, 0 + angle, options).geometry.coordinates
|
||||
|
||||
this.controlPoints = controlPoints
|
||||
for (let i = 0; i < this.controlPoints.length; i++) {
|
||||
let color = '#00ff0a'
|
||||
if (i === 5) {
|
||||
color = '#ffff00'
|
||||
}
|
||||
if (i === 0) {
|
||||
color = '#ff0000'
|
||||
}
|
||||
let entity = sdk.viewer.entities.getOrCreateEntity('svg-control-points_' + i)
|
||||
entity.objectId = this.options.id
|
||||
entity.position = new Cesium.CallbackProperty(() => {
|
||||
return Cesium.Cartesian3.fromDegrees(...this.controlPoints[i])
|
||||
})
|
||||
entity.point = new Cesium.PointGraphics({
|
||||
color: Cesium.Color.fromCssColorString(color), // 点的颜色
|
||||
pixelSize: 10, // 点的大小
|
||||
disableDepthTestDistance: Number.POSITIVE_INFINITY // 不应用深度测试
|
||||
})
|
||||
this.pointEntityCollection.add(entity)
|
||||
}
|
||||
}
|
||||
|
||||
_updateGeojson(data, x, y) {
|
||||
let width = Math.abs(this.bbox[0] - this.bbox[2])
|
||||
let height = Math.abs(this.bbox[1] - this.bbox[3])
|
||||
if (typeof data[0] === 'object') {
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
this._updateGeojson(data[i], x, y)
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (let i = 0; i < data.length; i += 2) {
|
||||
data[i] = data[i] + ((data[i] / (width / 2)) * x)
|
||||
}
|
||||
for (let i = 1; i < data.length; i += 2) {
|
||||
data[i] = data[i] - ((data[i] / (height / 2)) * y)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update() {
|
||||
let point = turf.point([this.position.lng, this.position.lat]);
|
||||
let options = { units: 'kilometers' };
|
||||
|
||||
let hierarchys = []
|
||||
let interimBbox = [...this.bbox]
|
||||
let width = Math.abs(interimBbox[2] - interimBbox[0])
|
||||
let height = Math.abs(interimBbox[3] - interimBbox[1])
|
||||
let x = ((width / 2) * this.options.scale.x) / 100 - (width / 2)
|
||||
let y = (height / 2) * (-(this.options.scale.y)) / 100 + (height / 2)
|
||||
|
||||
interimBbox[0] = interimBbox[0] - x
|
||||
interimBbox[1] = interimBbox[1] + y
|
||||
interimBbox[2] = interimBbox[2] + x
|
||||
interimBbox[3] = interimBbox[3] - y
|
||||
|
||||
let interim
|
||||
|
||||
if (interimBbox[0] > interimBbox[2]) {
|
||||
interim = interimBbox[0]
|
||||
interimBbox[0] = interimBbox[2]
|
||||
interimBbox[2] = interim
|
||||
}
|
||||
if (interimBbox[1] > interimBbox[3]) {
|
||||
interim = interimBbox[1]
|
||||
interimBbox[1] = interimBbox[3]
|
||||
interimBbox[3] = interim
|
||||
}
|
||||
|
||||
let geojson = JSON.parse(JSON.stringify(this.geojson))
|
||||
this._updateGeojson(geojson.geometry.coordinates, x, y)
|
||||
geojson = turf.transformRotate(geojson, this.angle, { pivot: [0, 0] });
|
||||
let directionDistance = []
|
||||
if (geojson.geometry.type === 'MultiPolygon') {
|
||||
for (let i = 0; i < geojson.geometry.coordinates.length; i++) {
|
||||
let array = []
|
||||
for (let m = 0; m < geojson.geometry.coordinates[i].length; m++) {
|
||||
let array2 = []
|
||||
for (let n = 0; n < geojson.geometry.coordinates[i][m].length; n++) {
|
||||
let point1 = turf.point([0, geojson.geometry.coordinates[i][m][n][1]])
|
||||
let point2 = turf.point([...geojson.geometry.coordinates[i][m][n]])
|
||||
let distance = turf.distance(point1, point2, { units: 'kilometers' });
|
||||
let angle2 = turf.rhumbBearing(point1, point2);
|
||||
array2.push(
|
||||
{
|
||||
origin: geojson.geometry.coordinates[i][m][n],
|
||||
distance: distance,
|
||||
angle: angle2
|
||||
}
|
||||
)
|
||||
}
|
||||
array.push(array2)
|
||||
}
|
||||
directionDistance.push(array)
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (let i = 0; i < geojson.geometry.coordinates.length; i++) {
|
||||
let array = []
|
||||
for (let m = 0; m < geojson.geometry.coordinates[i].length; m++) {
|
||||
let array2 = []
|
||||
let point1 = turf.point([0, geojson.geometry.coordinates[i][m][1]])
|
||||
let point2 = turf.point([...geojson.geometry.coordinates[i][m]])
|
||||
let distance = turf.distance(point1, point2, { units: 'kilometers' });
|
||||
let angle2 = turf.rhumbBearing(point1, point2);
|
||||
array.push({
|
||||
origin: geojson.geometry.coordinates[i][m],
|
||||
distance: distance,
|
||||
angle: angle2
|
||||
})
|
||||
}
|
||||
directionDistance.push(array)
|
||||
}
|
||||
}
|
||||
|
||||
geojson.properties.directionDistance = directionDistance
|
||||
|
||||
// this.bbox = [...interimBbox]
|
||||
|
||||
|
||||
let w = 3.5 * this.scale.x
|
||||
let h = 3.5 * this.scale.y
|
||||
let wh = Math.sqrt(((w / 2) ** 2) + ((h / 2) ** 2))
|
||||
let angle = Math.atan((w / 2) / (h / 2)) * (180 / Math.PI)
|
||||
let controlPoints = []
|
||||
controlPoints[0] = turf.destination(point, h / 2 * 1.5, 0 + this.options.angle, options).geometry.coordinates
|
||||
controlPoints[1] = turf.destination(point, wh, 180 + angle + this.options.angle, options).geometry.coordinates
|
||||
controlPoints[2] = turf.destination(point, h / 2, 180 + this.options.angle, options).geometry.coordinates
|
||||
controlPoints[3] = turf.destination(point, wh, 180 - angle + this.options.angle, options).geometry.coordinates
|
||||
controlPoints[4] = turf.destination(point, w / 2, 270 + this.options.angle, options).geometry.coordinates
|
||||
controlPoints[5] = [this.position.lng, this.position.lat]
|
||||
controlPoints[6] = turf.destination(point, w / 2, 90 + this.options.angle, options).geometry.coordinates
|
||||
controlPoints[7] = turf.destination(point, wh, 360 - angle + this.options.angle, options).geometry.coordinates
|
||||
controlPoints[8] = turf.destination(point, h / 2, 0 + this.options.angle, options).geometry.coordinates
|
||||
controlPoints[9] = turf.destination(point, wh, 0 + angle + this.options.angle, options).geometry.coordinates
|
||||
|
||||
let points = turf.points(controlPoints);
|
||||
controlPoints = []
|
||||
for (let i = 0; i < points.features.length; i++) {
|
||||
controlPoints.push(points.features[i].geometry.coordinates)
|
||||
}
|
||||
this.controlPoints = controlPoints
|
||||
|
||||
if (geojson.geometry.type === 'MultiPolygon') {
|
||||
for (let i = 0; i < geojson.geometry.coordinates.length; i++) {
|
||||
let hierarchy = this.getHierarchyPolygon(geojson, i)
|
||||
hierarchys.push(hierarchy)
|
||||
}
|
||||
}
|
||||
else {
|
||||
let hierarchy = this.getHierarchyPolygon(geojson)
|
||||
hierarchys.push(hierarchy)
|
||||
}
|
||||
this.hierarchys = hierarchys
|
||||
}
|
||||
|
||||
load(callback) {
|
||||
if(this.loaded) {
|
||||
callback();
|
||||
}
|
||||
else {
|
||||
this.#loadEvent = callback
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default GroundSvg
|
||||
1723
src/Obj/Base/GroundSvg/index-3.js
Normal file
1723
src/Obj/Base/GroundSvg/index-3.js
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user