代码迁移
This commit is contained in:
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
|
Reference in New Issue
Block a user