Cesium-Examples/examples/cesiumEx/ocean/layers/LayerWindField/windy/RenderDynamicWind.js
2025-03-11 17:51:04 +08:00

564 lines
17 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { windData } from './WindData.js'
function RenderDynamicWind(viewer, Cesium) {
this.particles = []
this.particleCount = []
this._height = undefined
this._field = undefined
this._scale = 1.0 //生成粒子的缩放因子
this._imageMask = undefined
this._particleNum = undefined
this._mapCenter = undefined
this._mapScale = undefined
this._windowWidth = undefined
this._windowHeight = undefined
this._bounds = {
x: 0,
y: 0,
xMax: 0,
yMax: 0,
width: 0,
height: 0
}
this._viewer = viewer
this._cancel = false
this._centerPnt = new Cesium.Cartographic()
this._timerOut = null
this.animationLoop
this.densityScale = window.densityScale || 0.8 //密度比例系数
this.velocityScale = window.velocityScale || 0.6 //速度比例系数
this.builder = null
}
RenderDynamicWind.prototype.parseData = function (data) {
this.uvData = data
}
RenderDynamicWind.prototype.Render = function () {
var scene = this._viewer.scene
var renderObject = this
renderObject.start = true
renderObject._height = scene.camera.positionCartographic.height
renderObject.velocityScale_o = renderObject.getVelocityScaleByHeight(
renderObject._height
)
renderObject._isRender = true
renderObject._scale = renderObject.getScaleByHeight(renderObject._height)
renderObject.reCreate(renderObject)
scene.camera.moveEnd.addEventListener(function () {
renderObject._scale = renderObject.getScaleByHeight(renderObject._height)
if (!renderObject.start) return
//获取当前相机高度
renderObject.start1 = true
//获取当前相机高度
renderObject._height = scene.camera.positionCartographic.height
var newCenter = scene.camera.positionCartographic
if (newCenter != renderObject._centerPnt) {
// 添加延迟计算,尝试提升移动地球的流畅度
if (renderObject._timerOut) {
clearTimeout(renderObject._timerOut)
renderObject._timerOut = null
}
renderObject._timerOut = setTimeout(() => {
renderObject.velocityScale_o = renderObject.getVelocityScaleByHeight(
renderObject._height
)
renderObject.reCreate(renderObject)
if (renderObject._height > 14125162)
renderObject._isRender = true
renderObject._scale = renderObject.getScaleByHeight(newCenter.height)
renderObject.particles = []
renderObject.particleCount = Math.round(
renderObject._windowHeight *
windData.PARTICLE_MULTIPLIER *
renderObject._windowWidth *
renderObject._scale
)
if (renderObject._field != null) {
for (var i = 0; i < renderObject.particleCount; i++) {
if (!renderObject.start1) {
i = renderObject.particleCount - 1
return
}
renderObject.particles.push(
renderObject._field.randomize({
age: windData.random(0, windData.MAX_PARTICLE_AGE)
})
)
}
}
}, 10)
}
})
scene.camera.moveStart.addEventListener(function () {
//获取当前相机高度
var newCenter = scene.camera.positionCartographic
if (newCenter != renderObject._centerPnt) {
if (renderObject._field != null) {
renderObject._field.release()
}
renderObject.start1 = false
renderObject._isRender = false
if (renderObject._imageG) {
renderObject._imageG.clearRect(
0,
0,
renderObject._windowWidth,
renderObject._windowHeight
)
renderObject._g.clearRect(
0,
0,
renderObject._windowWidth,
renderObject._windowHeight
)
}
}
})
var colorStyles = windData.windIntensityColorScale(
windData.INTENSITY_SCALE_STEP,
windData.maxIntensity
)
var buckets = colorStyles.map(function () {
return []
})
function evolve() {
buckets.forEach(function (bucket) {
bucket.length = 0
})
renderObject.particles.forEach(function (particle) {
if (particle.age > windData.MAX_PARTICLE_AGE) {
renderObject._field.randomize(particle).age = 0
}
var x = particle.x
var y = particle.y
var v = renderObject._field(x, y) // vector at current position
var m = v[2]
if (m === null) {
particle.age = windData.MAX_PARTICLE_AGE // particle has escaped the grid, never to return...
} else {
var xt = x + v[0] * windData.WindScale
var yt = y + v[1] * windData.WindScale
if (renderObject._field.isDefined(xt, yt)) {
// Path from (x,y) to (xt,yt) is visible, so add this particle to the appropriate draw bucket.
particle.xt = xt
particle.yt = yt
buckets[colorStyles.indexFor(m)].push(particle)
} else {
// Particle isn't visible, but it still moves through the field.
particle.x = xt
particle.y = yt
}
}
particle.age += 1
})
}
function draw() {
if (!renderObject.start) return
var g = renderObject._g
if (g == null || renderObject._imageMask == null) {
return
}
var bounds = renderObject._bounds
var prev = g.globalCompositeOperation
g.globalCompositeOperation = 'destination-in'
g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height)
//g.putImageData(renderObject._imageMask.imageData,0,0)
g.globalCompositeOperation = prev
g.lineWidth = renderObject.lineWidth || 1
// Draw new particle trails.
buckets.forEach(function (bucket, i) {
if (bucket.length > 0) {
g.beginPath()
g.strokeStyle = colorStyles[i]
bucket.forEach(function (particle) {
g.moveTo(particle.x, particle.y)
g.lineTo(particle.xt, particle.yt)
particle.x = particle.xt
particle.y = particle.yt
})
g.stroke()
}
})
}
;(function frame() {
evolve()
draw()
if (renderObject.start) {
renderObject.animationLoop = requestAnimationFrame(frame)
}
})()
}
RenderDynamicWind.prototype.zoom = function (renderObject) {
var width = renderObject._viewer.scene.canvas.clientWidth
var height = renderObject._viewer.scene.canvas.clientHeight
renderObject._windowWidth = width
renderObject._windowHeight = height
renderObject._bounds.xMax = width
renderObject._bounds.yMax = height
renderObject._bounds.width = width
renderObject._bounds.height = height
if (renderObject._field != null) {
renderObject._field.release()
}
}
RenderDynamicWind.prototype.reCreate = function (renderObject) {
this.zoom(renderObject)
var scene = this._viewer.scene
var canvas = scene.canvas
var camera = scene.camera
var params = {}
params.clientWidth = canvas.clientWidth
params.clientHeight = canvas.clientHeight
params.viewMatrix = camera.viewMatrix
params.projectionMatrix = camera.frustum.projectionMatrix
params.fovy = camera.frustum.fovy
params.aspectRatio = camera.frustum.aspectRatio
params.near = camera.frustum.near
params.positionWC = camera.positionWC
params.directionWC = camera.directionWC
params.rightWC = camera.rightWC
params.upWC = camera.upWC
params.center = renderObject._centerPnt
params.bounds = renderObject._bounds
params.uvData = this.uvData
params.velocityScale_o = renderObject.velocityScale_o
const data = renderObject.dealData(renderObject, params)
renderObject.setData(renderObject, data)
}
RenderDynamicWind.prototype.dealData = (renderObject, params) => {
const that = renderObject
if (!that.builder) {
let uvData = params.uvData
let [header, uData, vData] = uvData
that.builder = new windData.buildGrid({
header,
data: function (i) {
return [uData[i], vData[i]]
},
interpolate: windData.bilinearInterpolateVector
})
}
if (params.velocityScale_o) windData.velocityScale_o = params.velocityScale_o
let result = windData.reCreate(params, that.builder, true)
let data = {
params,
columns: result.columns,
pixels: result.mask.imageData
}
return data
}
RenderDynamicWind.prototype.setData = (renderObject, e) => {
const that = renderObject
var bounds = e.params.bounds
var columns = e.columns
var maskImageData = e.pixels
var mask = maskImageData
that._imageMask = mask
that._field = windData.createField(columns, bounds, false)
//lxl发现粒子在原位置时没生成移到此位置
that.particleCount = Math.round(
e.params.clientHeight *
e.params.clientWidth *
windData.PARTICLE_MULTIPLIER *
that._scale
)
if (that._field != null) {
for (var i = 0; i < that.particleCount; i++) {
that.particles.push(
that._field.randomize({
age: windData.random(0, windData.MAX_PARTICLE_AGE)
})
)
}
}
var canvas, canvasOverLay
if (document.getElementById('fullScreen')) {
canvas = document.getElementById('fullScreen')
canvasOverLay = document.getElementById('image-canvas')
} else {
canvasOverLay = document.createElement('CANVAS')
// document.body.appendChild(canvasOverLay);
that._viewer.container.appendChild(canvasOverLay)
canvasOverLay.id = 'image-canvas'
canvasOverLay.width = bounds.width
canvasOverLay.height = bounds.height
canvasOverLay.style.position = 'absolute'
canvasOverLay.style.top = 0
canvasOverLay.style.left = 0
canvasOverLay.style.zIndex = 100
canvasOverLay.style.pointerEvents = 'none'
canvas = document.createElement('CANVAS')
// document.body.appendChild(canvas);
that._viewer.container.appendChild(canvas)
canvas.id = 'fullScreen'
canvas.style.position = 'absolute'
canvas.style.top = 0
canvas.style.left = 0
canvas.style.zIndex = 100
canvas.style.pointerEvents = 'none'
canvas.width = bounds.width
canvas.height = bounds.height
}
var g = canvas.getContext('2d')
g.clearRect(0, 0, canvas.width, canvas.height)
that._lineCanvas = canvas
that._lineCanvas.style.display = 'block'
that._g = g
that._g.lineWidth = that.lineWidth || 1
that._g.fillStyle = windData.fadeFillStyle
var gOverlay = canvasOverLay.getContext('2d')
gOverlay.clearRect(0, 0, canvasOverLay.width, canvasOverLay.height)
that._imageCanvas = canvasOverLay
that._imageCanvas.style.display = 'block'
that._imageG = gOverlay
}
//根据分辨率、视野面积、高度获取例子流动速度
RenderDynamicWind.prototype.getVelocityScaleByHeight = function (height) {
let extent = this.getCurrentExtent()
let mapBounds = {
south: this.deg2rad(extent[1]),
north: this.deg2rad(extent[3]),
east: this.deg2rad(extent[2]),
west: this.deg2rad(extent[0])
}
let mapArea =
(mapBounds.south - mapBounds.north) * (mapBounds.west - mapBounds.east)
let scale = 0.0008 * this.velocityScale
if (height < 650000) scale = 0.00018 * this.velocityScale
let velocityScale_o =
scale *
(Math.pow(window.devicePixelRatio, 1 / 3) || 1) *
Math.pow(mapArea, 0.2)
return velocityScale_o
}
RenderDynamicWind.prototype.computeDistance = function (
newCenter,
oldCenter,
statues
) {
let w_newCenter
let w_oldCenter
let distance = 0
if (statues) {
w_newCenter = Cesium.Cartesian3.fromDegrees(
newCenter.longitude,
newCenter.latitude,
0
)
w_oldCenter = Cesium.Cartesian3.fromDegrees(
oldCenter.longitude,
oldCenter.latitude,
0
)
distance = Cesium.Cartesian3.distance(w_newCenter, w_oldCenter)
} else {
distance = Math.abs(Number(newCenter.height) - Number(oldCenter.height))
}
return distance
}
// 通过高度获取比例
RenderDynamicWind.prototype.getScaleByHeight = function (height) {
const baseMaxHeight = 14125162
if (height < 550000) this.densityScale = 0.25
let _scale
if (height > baseMaxHeight) {
_scale = 0.25 * this.densityScale
} else if (height > baseMaxHeight * 0.8) {
_scale = 0.25 * this.densityScale
} else if (height > baseMaxHeight * Math.pow(0.8, 2)) {
_scale = 0.225 * this.densityScale
} else if (height > baseMaxHeight * Math.pow(0.5, 3)) {
_scale = 0.2 * this.densityScale
} else if (height > baseMaxHeight * Math.pow(0.5, 4)) {
_scale = 0.09 * this.densityScale
} else if (height > baseMaxHeight * Math.pow(0.5, 5)) {
_scale = 0.07 * this.densityScale
} else if (height > baseMaxHeight * Math.pow(0.5, 6)) {
_scale = 0.065 * this.densityScale
} else if (height > baseMaxHeight * Math.pow(0.5, 7)) {
_scale = 0.04 * this.densityScale
} else if (height > baseMaxHeight * Math.pow(0.5, 8)) {
_scale = 0.03 * this.densityScale
} else if (height > baseMaxHeight * Math.pow(0.5, 9)) {
_scale = 0.02 * this.densityScale
} else if (height > baseMaxHeight * Math.pow(0.5, 10)) {
_scale = 0.015 * this.densityScale
} else if (height > baseMaxHeight * Math.pow(0.5, 11)) {
_scale = 0.01 * this.densityScale
} else if (height > baseMaxHeight * Math.pow(0.5, 12)) {
_scale = 0.005 * this.densityScale
} else if (height > baseMaxHeight * Math.pow(0.5, 13)) {
_scale = 0.0025 * this.densityScale
} else {
_scale = 0.00005 * this.densityScale
}
return _scale
}
RenderDynamicWind.prototype.getCurrentExtent = function () {
let _self = this
//获取当前三维地图范围
var Rectangle = _self._viewer.camera.computeViewRectangle()
//地理坐标(弧度)转经纬度坐标
var extent = [
(Rectangle.west / Math.PI) * 180,
(Rectangle.south / Math.PI) * 180,
(Rectangle.east / Math.PI) * 180,
(Rectangle.north / Math.PI) * 180
]
return extent
}
RenderDynamicWind.prototype.deg2rad = function (deg) {
return (deg / 180) * Math.PI
}
RenderDynamicWind.prototype.remove = function () {
if (this.animationLoop) {
cancelAnimationFrame(this.animationLoop)
this.animationLoop = null
}
var renderObject = this
if (
renderObject._lineCanvas != undefined &&
renderObject._lineCanvas.style != null
) {
renderObject._lineCanvas.style.display = 'none'
}
if (
renderObject._imageCanvas != undefined &&
renderObject._imageCanvas.style != null
) {
renderObject._imageCanvas.style.display = 'none'
}
renderObject.start = false
if (this._timerOut) {
clearTimeout(this._timerOut)
this._timerOut = null
}
if (document.getElementById('image-canvas'))
document.getElementById('image-canvas').remove()
if (document.getElementById('fullScreen'))
document.getElementById('fullScreen').remove()
this.particles = []
}
RenderDynamicWind.prototype.clone = function () {}
RenderDynamicWind.prototype.update = function () {
var RTOD = 180.0 / 3.1415926
var canvas = document.getElementById('animation')
var g = canvas.getContext('2d')
g.fillStyle = 'rgba(0, 0, 0, 0.97)'
g.lineWidth = 20
function draw() {
// Fade existing particle trails.
var prev = 'source-over'
g.globalCompositeOperation = 'destination-in'
g.fillRect(0, 0, 800, 600)
g.globalCompositeOperation = prev
g.beginPath()
g.strokeStyle = 0x111111
for (var i = 0; i < 100; i++) {
var x = Math.floor(Math.random() * 800)
var y = Math.floor(Math.random() * 600)
g.moveTo(x, y)
g.lineTo(x + 5, y + 5)
}
g.stroke()
}
;(function frame() {
try {
draw()
setTimeout(frame, 400)
} catch (e) {}
})()
}
RenderDynamicWind.prototype.updateO = function (options) {
const renderObject = this
var scene = renderObject._viewer.scene
renderObject.lineWidth = options.lineWidth || renderObject.lineWidth
renderObject.densityScale = options.densityScale || renderObject.densityScale
renderObject.velocityScale =
options.velocityScale || renderObject.velocityScale
//同比执行一次movestart 和moveend
if (renderObject._field != null) {
renderObject._field.release()
}
renderObject.start1 = false
renderObject._isRender = false
if (renderObject._imageG) {
renderObject._imageG.clearRect(
0,
0,
renderObject._windowWidth,
renderObject._windowHeight
)
renderObject._g.clearRect(
0,
0,
renderObject._windowWidth,
renderObject._windowHeight
)
}
if (!renderObject.start) return
//获取当前相机高度
renderObject.start1 = true
//获取当前相机高度
renderObject._height = scene.camera.positionCartographic.height
renderObject._scale = renderObject.getScaleByHeight(renderObject._height)
renderObject.velocityScale_o = renderObject.getVelocityScaleByHeight(
renderObject._height
)
renderObject.reCreate(renderObject)
renderObject._isRender = true
renderObject.particles = []
renderObject.particleCount = Math.round(
renderObject._windowHeight *
windData.PARTICLE_MULTIPLIER *
renderObject._windowWidth *
renderObject._scale
)
if (renderObject._field != null) {
for (var i = 0; i < renderObject.particleCount; i++) {
if (!renderObject.start1) {
i = renderObject.particleCount - 1
return
}
renderObject.particles.push(
renderObject._field.randomize({
age: windData.random(0, windData.MAX_PARTICLE_AGE)
})
)
}
}
}
export default RenderDynamicWind