vue+cesium实现风场
一、风场类编写
/***
* 风场类
* date:2022-03-14
* author:zdh
* @type {CanvasWindy}
*/
import {Cartesian3,EllipsoidalOccluder,SceneTransforms,Ellipsoid,Cartesian2,Math as CMath} from 'cesium/Cesium'
export let CanvasWindy = function (json,params) {
//风场json数据
this.windData = json;
//可配置参数
this.viewer = params.viewer;
this.canvas = params.canvas;
this.extent = params.extent || [];//风场绘制时的地图范围,范围不应该大于风场数据的范围,顺序:west/east/south/north,有正负区分,如:[110,120,30,36]
this.canvasContext = params.canvas.getContext("2d");//canvas上下文
this.canvasWidth = params.canvasWidth || 300;//画板宽度
this.canvasHeight = params.canvasHeight || 180;//画板高度
this.speedRate = params.speedRate || 100;//风前进速率,意思是将当前风场横向纵向分成100份,再乘以风速就能得到移动位置,无论地图缩放到哪一级别都是一样的速度,可以用该数值控制线流动的快慢,值越大,越慢,
this.particlesNumber = params.particlesNumber || 20000;//初始粒子总数,根据实际需要进行调节
this.maxAge = params.maxAge || 120;//每个粒子的最大生存周期
this.frameTime = 1000/(params.frameRate || 10);//每秒刷新次数,因为requestAnimationFrame固定每秒60次的渲染,所以如果不想这么快,就把该数值调小一些
this.color = params.color || '#ffffff';//线颜色,提供几个示例颜色['#14208e','#3ac32b','#e0761a']
this.lineWidth = params.lineWidth || 1;//线宽度
//内置参数
this.initExtent = [];//风场初始范围
this.calc_speedRate = [0,0];//根据speedRate参数计算经纬度步进长度
this.windField = null;
this.particles = [];
this.animateFrame = null;//requestAnimationFrame事件句柄,用来清除操作
this.isdistory = false;//是否销毁,进行删除操作
this._init();
};
CanvasWindy.prototype = {
constructor: CanvasWindy,
_init: function () {
let self = this;
// 创建风场网格
this.windField = this.createField();
this.initExtent = [this.windField.west,this.windField.east,this.windField.south,this.windField.north];
//如果风场创建时,传入的参数有extent,就根据给定的extent,让随机生成的粒子落在extent范围内
if(this.extent.length!=0){
this.extent = [
Math.max(this.initExtent[0],this.extent[0]),
Math.min(this.initExtent[1],this.extent[1]),
Math.max(this.initExtent[2],this.extent[2]),
Math.min(this.initExtent[3],this.extent[3])
];
}
// console.log(this.extent);
this._calcStep();
// 创建风场粒子
for (let i = 0; i < this.particlesNumber; i++) {
this.particles.push(this.randomParticle(new CanvasParticle()));
}
this.canvasContext.fillStyle = "rgba(0, 0, 0, 0.97)";
this.canvasContext.globalAlpha = 0.6;
this.animate();
let then = Date.now();
(function frame() {
if(!self.isdistory){
self.animateFrame = requestAnimationFrame(frame);
let now = Date.now();
let delta = now - then;
if (delta > self.frameTime) {
then = now - delta % self.frameTime;
self.animate();
}
}else{
self.removeLines();
}
})();
},
//计算经纬度步进长度
_calcStep:function(){
let isextent = (this.extent.length!=0);
let calcExtent = isextent?this.extent:this.initExtent;
let calcSpeed = this.speedRate;
this.calc_speedRate = [(calcExtent[1]-calcExtent[0])/calcSpeed,(calcExtent[3]-calcExtent[2])/calcSpeed];
},
//根据现有参数重新生成风场
redraw:function(){
window.cancelAnimationFrame(this.animateFrame);
this.particles = [];
this._init();
},
createField: function () {
let data = this._parseWindJson();
return new CanvasWindField(data);
},
animate: function () {
let self = this,
field = self.windField;
let nextLng = null,
nextLat = null,
uv = null;
self.particles.forEach(function (particle) {
if (particle.age == null || particle.age <= 0) {
self.randomParticle(particle);
}
if (particle.age > 0) {
let x = particle.x,
y = particle.y,
tlng = particle.tlng,
tlat = particle.tlat;
let gridpos = self._togrid(tlng,tlat);
let tx = gridpos[0];
let ty = gridpos[1];
if (!self.isInExtent(tlng,tlat)) {
particle.age = 0;
} else {
uv = field.getIn(tx, ty);
nextLng = tlng + self.calc_speedRate[0] * uv[0];
nextLat = tlat + self.calc_speedRate[1] * uv[1];
particle.lng = tlng;
particle.lat = tlat;
particle.x = tx;
particle.y = ty;
particle.tlng = nextLng;
particle.tlat = nextLat;
particle.age--;
}
}
});
if (self.particles.length <= 0) this.removeLines();
self._drawLines();
},
//粒子是否在地图范围内
isInExtent:function(lng,lat){
let calcExtent = this.initExtent;
if((lng>=calcExtent[0] && lng<=calcExtent[1]) && (lat>=calcExtent[2] && lat<=calcExtent[3])) return true;
return false;
},
_resize:function(width,height){
this.canvasWidth = width;
this.canvasHeight = height;
},
_parseWindJson: function () {
let uComponent = null,
vComponent = null,
header = null;
this.windData.forEach(function (record) {
let type = record.header.parameterCategory + "," + record.header.parameterNumber;
switch (type) {
case "2,2":
uComponent = record['data'];
header = record['header'];
break;
case "2,3":
vComponent = record['data'];
break;
default:
break;
}
});
return {
header: header,
uComponent: uComponent,
vComponent: vComponent
};
},
removeLines: function () {
window.cancelAnimationFrame(this.animateFrame);
this.isdistory = true;
this.canvas.width = 1;
document.getElementById('content').removeChild(this.canvas);
},
//根据粒子当前所处的位置(棋盘网格位置),计算经纬度,在根据经纬度返回屏幕坐标
_tomap: function (lng,lat,particle) {
let ct3 = Cartesian3.fromDegrees(lng,lat,0);
// 判断当前点是否在地球可见端
let isVisible = new EllipsoidalOccluder(Ellipsoid.WGS84, this.viewer.camera.position).isPointVisible(ct3);
let pos = SceneTransforms.wgs84ToWindowCoordinates(this.viewer.scene, ct3);
if(!isVisible){
particle.age = 0;
}
// console.log(pos);
return pos?[pos.x,pos.y]:null;
},
//根据经纬度,算出棋盘格位置
_togrid: function (lng,lat) {
let field = this.windField;
let x = (lng-this.initExtent[0])/(this.initExtent[1]-this.initExtent[0])*(field.cols-1);
let y = (this.initExtent[3]-lat)/(this.initExtent[3]-this.initExtent[2])*(field.rows-1);
return [x,y];
},
_drawLines: function () {
let self = this;
let particles = this.particles;
this.canvasContext.lineWidth = self.lineWidth;
//后绘制的图形和前绘制的图形如果发生遮挡的话,只显示后绘制的图形跟前一个绘制的图形重合的前绘制的图形部分,示例:https://www.w3school.com.cn/tiy/t.asp?f=html5_canvas_globalcompop_all
this.canvasContext.globalCompositeOperation = "destination-in";
this.canvasContext.fillRect(0,0,this.canvasWidth,this.canvasHeight);
this.canvasContext.globalCompositeOperation = "lighter";//重叠部分的颜色会被重新计算
this.canvasContext.globalAlpha = 0.9;
this.canvasContext.beginPath();
this.canvasContext.strokeStyle = this.color;
particles.forEach(function (particle) {
let movetopos = self._tomap(particle.lng, particle.lat,particle);
let linetopos = self._tomap(particle.tlng, particle.tlat,particle);
// console.log(movetopos,linetopos);
if(movetopos!=null && linetopos!=null){
self.canvasContext.moveTo(movetopos[0],movetopos[1]);
self.canvasContext.lineTo(linetopos[0],linetopos[1]);
}
});
this.canvasContext.stroke();
},
//随机数生成器(小数)
fRandomByfloat:function(under, over){
return under+Math.random()*(over-under);
},
//随机数生成器(整数)
fRandomBy:function(under, over){
switch(arguments.length){
case 1: return parseInt(Math.random()*under+1);
case 2: return parseInt(Math.random()*(over-under+1) + under);
default: return 0;
}
},
//根据当前风场extent随机生成粒子
randomParticle: function (particle) {
let safe = 30,x=-1, y=-1,lng=null,lat=null;
let hasextent = this.extent.length!=0;
let calc_extent = hasextent?this.extent:this.initExtent;
try{
do {
try{
if(hasextent){
let pos_x = this.fRandomBy(0,this.canvasWidth);
let pos_y = this.fRandomBy(0,this.canvasHeight);
let cartesian = this.viewer.camera.pickEllipsoid(new Cartesian2(pos_x, pos_y), this.viewer.scene.globe.ellipsoid);
let cartographic = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian);
if(cartographic){
//将弧度转为度的十进制度表示
lng = CMath.toDegrees(cartographic.longitude);
lat = CMath.toDegrees(cartographic.latitude);
}
}else{
lng = this.fRandomByfloat(calc_extent[0],calc_extent[1]);
lat = this.fRandomByfloat(calc_extent[2],calc_extent[3]);
}
}catch(e){
}
if(lng){
let gridpos = this._togrid(lng,lat);
x = gridpos[0];
y = gridpos[1];
}
} while (this.windField.getIn(x, y)[2] <= 0 && safe++ < 30);
}catch (e) {
}
try{
let field = this.windField;
let uv = field.getIn(x, y);
particle.speed = uv[2];
particle.lng = lng;
particle.lat = lat;
particle.x = x;
particle.y = y;
let nextLng = lng + this.calc_speedRate[0] * uv[0];
let nextLat = lat + this.calc_speedRate[1] * uv[1];
particle.tlng = nextLng;
particle.tlat = nextLat;
particle.age = Math.round(Math.random() * this.maxAge);//每一次生成都不一样
}
catch (e) {
}
return particle;
}
};
/****
*棋盘类
*根据风场数据生产风场棋盘网格
****/
let CanvasWindField = function (obj) {
this.west = null;
this.east = null;
this.south = null;
this.north = null;
this.rows = null;
this.cols = null;
this.dx = null;
this.dy = null;
this.unit = null;
this.date = null;
this.grid = null;
this._init(obj);
};
CanvasWindField.prototype = {
constructor: CanvasWindField,
_init: function (obj) {
let header = obj.header,
uComponent = obj['uComponent'],
vComponent = obj['vComponent'];
this.west = +header['lo1'];
this.east = +header['lo2'];
this.south = +header['la2'];
this.north = +header['la1'];
this.rows = +header['ny'];
this.cols = +header['nx'];
this.dx = +header['dx'];
this.dy = +header['dy'];
this.unit = header['parameterUnit'];
this.date = header['refTime'];
this.grid = [];
let k = 0,
rows = null,
uv = null;
for (let j = 0; j < this.rows; j++) {
rows = [];
for (let i = 0; i < this.cols; i++, k++) {
uv = this._calcUV(uComponent[k], vComponent[k]);
rows.push(uv);
}
this.grid.push(rows);
}
},
_calcUV: function (u, v) {
return [+u, +v, Math.sqrt(u * u + v * v)];
},
//二分差值算法计算给定节点的速度
_bilinearInterpolation: function (x, y, g00, g10, g01, g11) {
let rx = (1 - x);
let ry = (1 - y);
let a = rx * ry, b = x * ry, c = rx * y, d = x * y;
let u = g00[0] * a + g10[0] * b + g01[0] * c + g11[0] * d;
let v = g00[1] * a + g10[1] * b + g01[1] * c + g11[1] * d;
return this._calcUV(u, v);
},
getIn: function (x, y) {
if(x<0 || x>=359 || y>=180){
return [0,0,0];
}
let x0 = Math.floor(x),
y0 = Math.floor(y),
x1, y1;
if (x0 === x && y0 === y) return this.grid[y][x];
x1 = x0 + 1;
y1 = y0 + 1;
let g00 = this.getIn(x0, y0),
g10 = this.getIn(x1, y0),
g01 = this.getIn(x0, y1),
g11 = this.getIn(x1, y1);
let result = null;
try{
result = this._bilinearInterpolation(x - x0, y - y0, g00, g10, g01, g11);
}catch(e){
// console.log(x,y);
}
return result;
},
isInBound: function (x, y) {
if ((x >= 0 && x < this.cols-1) && (y >= 0 && y < this.rows-1)) return true;
return false;
}
};
/****
*粒子对象
****/
let CanvasParticle = function () {
this.lng = null;//粒子初始经度
this.lat = null;//粒子初始纬度
this.x = null;//粒子初始x位置(相对于棋盘网格,比如x方向有360个格,x取值就是0-360,这个是初始化时随机生成的)
this.y = null;//粒子初始y位置(同上)
this.tlng = null;//粒子下一步将要移动的经度,这个需要计算得来
this.tlat = null;//粒子下一步将要移动的y纬度,这个需要计算得来
this.age = null;//粒子生命周期计时器,每次-1
this.speed = null;//粒子移动速度,可以根据速度渲染不同颜色
};
二、风场工具类编写
/***
* 风场通用工具
* date:2022-03-14
* author:zdh
* @type {windyUtil}
*/
import $ from 'jquery'
import {CanvasWindy} from "./CanvasWindy";
import {Cartesian2,ScreenSpaceEventType,ScreenSpaceEventHandler} from 'cesium/Cesium'
// export let wa={}
let windyUtil = (function () {
function windyUtil (zdhCesium,layerId) {
this.zdhCesium = zdhCesium
this.globalExtent = []
this.canvasId = layerId
this.postRender = null
this.handler = null
this.allgrid = null
this.windData = null
this.windy = null
this.windycanvas = null
this.WindInformation = {
block_show:false, //模块化显示
Wind_speed:0, //风速
wind_direction:"无", //风向
wind_field:[] //差值后的向量
}
this.windyVisible = true
}
windyUtil.prototype.showWindy = function(){
this.windyVisible = true
$('#' + this.canvasId).show()
this.windy.extent = this.globalExtent;
this.windy.redraw();
}
windyUtil.prototype.hideWindy = function(){
this.windyVisible = false
$('#' + this.canvasId).hide()
}
windyUtil.prototype.getCesiumExtent = function(){
let canvaswidth = window.innerWidth,
canvasheight = window.innerHeight*0.5-50;
let left_top_pt = new Cartesian2(0,0)
let left_bottom_pt = new Cartesian2(0,canvasheight)
let right_top_pt = new Cartesian2(canvaswidth,0)
let right_bottom_pt = new Cartesian2(canvaswidth,canvasheight)
let pick1= this.zdhCesium.viewer.scene.globe.pick(this.zdhCesium.viewer.camera.getPickRay(left_top_pt), this.zdhCesium.viewer.scene)
let pick2= this.zdhCesium.viewer.scene.globe.pick(this.zdhCesium.viewer.camera.getPickRay(left_bottom_pt), this.zdhCesium.viewer.scene)
let pick3= this.zdhCesium.viewer.scene.globe.pick(this.zdhCesium.viewer.camera.getPickRay(right_top_pt), this.zdhCesium.viewer.scene)
let pick4= this.zdhCesium.viewer.scene.globe.pick(this.zdhCesium.viewer.camera.getPickRay(right_bottom_pt), this.zdhCesium.viewer.scene)
if(pick1 && pick2 && pick3 && pick4){
//将三维坐标转成地理坐标---只需计算左下右上的坐标即可
let geoPt1= this.zdhCesium.viewer.scene.globe.ellipsoid.cartesianToCartographic(pick2)
let geoPt2= this.zdhCesium.viewer.scene.globe.ellipsoid.cartesianToCartographic(pick3)
//地理坐标转换为经纬度坐标
let point1=[geoPt1.longitude / Math.PI * 180,geoPt1.latitude / Math.PI * 180]
let point2=[geoPt2.longitude / Math.PI * 180,geoPt2.latitude / Math.PI * 180]
// console.log(point1,point2);
//此时说明extent需要分为东西半球
if(point1[0]>point2[0]){
this.globalExtent = [point1[0],180,point1[1],point2[1],-180,point2[0],point1[1],point2[1]];
}else{
this.globalExtent = [point1[0],point2[0],point1[1],point2[1]];
}
}else{
this.globalExtent = []
}
}
windyUtil.prototype.resizeCanvas = function(){
if(this.windycanvas==null){
return;
}
this.windycanvas.width=window.innerWidth;
this.windycanvas.height=window.innerHeight;
// console.log(windycanvas.width,windycanvas.height);
if(this.windy){
this.windy._resize(this.windycanvas.width,this.windycanvas.height);
}
}
windyUtil.prototype.createWindLayer = function (windData) {
if (this.windycanvas != null){
return
}
let _this = this
// 开启监听器--无论对当前地球做的任何操作都会监听到
this.postRender = this.zdhCesium.viewer.scene.postRender.addEventListener(() => {
_this.getCesiumExtent();
});
this.addWindHandle()
if (this.windycanvas == null){
this.windycanvas = document.createElement('canvas');
this.windycanvas.setAttribute("id", this.canvasId);
this.windycanvas.style.position='absolute'
this.windycanvas.style["pointer-events"]="none";
this.windycanvas.style["z-index"]=10;
this.windycanvas.style["top"]=0;
this.windycanvas.style["right"]=0;
document.getElementById('cesiumContainer1').appendChild(this.windycanvas);
}
this.resizeCanvas();
window.οnresize=this.resizeCanvas;
//风场的参数配置,除了canvas/viewer是必传项,其他可以不传,参数含义见windy.js
let params = {
viewer:this.zdhCesium.viewer,
canvas:this.windycanvas,
canvasWidth:window.innerWidth,
canvasHeight:window.innerHeight,
speedRate:5000,
particlesNumber:5000,
maxAge:120,
frameRate:10,
color:'#ffffff',
lineWidth:1,
};
this.windData = windData
this.analysisWindyData(this.windData)
this.windy = new CanvasWindy(this.windData, params);
}
windyUtil.prototype.addWindHandle = function () {
let _this = this
let refreshTimer = -1;
let mouse_down = false;
let mouse_move = false;
this.handler = new ScreenSpaceEventHandler(this.zdhCesium.viewer.scene.canvas);
//鼠标滚动、旋转后是否需要重新生成风场---如果需要,打开以下注释--旋转或者移动到北半球的时候计算会有问题
this.handler.setInputAction(function(e) {
if(_this.windyVisible === true){
clearTimeout(refreshTimer);
$('#' + _this.canvasId).hide()
// _this.hideWindy();
setTimeout(function(){
_this.windy.extent = _this.globalExtent;
_this.windy.redraw();
$('#' + _this.canvasId).show()
// _this.showWindy();
},200);
}
},ScreenSpaceEventType.WHEEL);
//鼠标左键、右键按下
this.handler.setInputAction(function(e) {
mouse_down = true;
},ScreenSpaceEventType.LEFT_DOWN);
this.handler.setInputAction(function(e) {
mouse_down = true;
},ScreenSpaceEventType.RIGHT_DOWN);
//鼠标移动
this.handler.setInputAction(function(e) {
if(_this.windyVisible === true){
if(mouse_down){
$('#' + _this.canvasId).hide()
// _this.hideWindy();
mouse_move = true;
}
}
},ScreenSpaceEventType.MOUSE_MOVE);
//鼠标左键、右键抬起
this.handler.setInputAction(function(e) {
if(_this.windyVisible === true){
if(mouse_down && mouse_move){
_this.windy.extent = _this.globalExtent;
_this.windy.redraw();
}
$('#' + _this.canvasId).show()
// _this.showWindy();
mouse_down = false;
mouse_move = false;
}
},ScreenSpaceEventType.LEFT_UP);
this.handler.setInputAction(function(e) {
if(_this.windyVisible === true){
if(mouse_down && mouse_move){
_this.windy.extent = _this.globalExtent;
_this.windy.redraw();
}
$('#' + _this.canvasId).show()
// _this.showWindy();
mouse_down = false;
mouse_move = false;
}
},ScreenSpaceEventType.RIGHT_UP);
}
//根据光标推算风场数据函数
windyUtil.prototype.GetWindInformation = function (x, y, width, height) {
let Wind_speed = 0
let wind_direction = "无"
let mycolumns = this.WindInformation.wind_field
if (mycolumns.length !== 0) {
let columns_x = mycolumns.length
let columns_y = mycolumns[0].length
// console.log(x+","+y+"")
let i = Math.floor(x / (width / columns_x))
let j = Math.floor(y / (height / columns_y))
let myfield = mycolumns[i][j]
if (myfield.length == 3) {
Wind_speed = myfield[2].toFixed(2)
} else if (myfield.length == 2) {
Wind_speed = Math.sqrt(myfield[0] * myfield[0] + myfield[1] * myfield[1]).toFixed(2)
}
wind_direction = direction_calculation(myfield[0], myfield[1])
this.WindInformation.Wind_speed = Wind_speed
this.WindInformation.wind_direction = wind_direction
} else {
this.WindInformation.Wind_speed = 0
this.WindInformation.wind_direction = "无"
}
function direction_calculation(u, v) {
let fx = 0
// let v = v2 * (-1)
let text = "无"
if (u == 0) {
if (v > 0) {
text = "南风"
} else if (v < 0) {
text = "北风"
}
} else if (v == 0) {
if (u > 0) {
text = "西风"
} else if (u < 0) {
text = "东风"
}
} else {
if (u > 0 & v > 0) {//第一象限
// fx = Math.atan(v / u) * 180 / Math.PI
fx = 270 - Math.atan(v / u) * 180 / Math.PI
if (fx <= 191.25) {
text = "南风"
} else if (fx > 191.25 && fx < 258.76) {
text = "西南风"
} else {
text = "西风"
}
// if (fx <= 11.25) {
// text = "南风"
// } else if (fx > 11.25 && fx < 78.76) {
// text = "西南风"
// } else {
// text = "西风"
// }
}
else if (u > 0 & v < 0) {//第二象限
// fx = 180 + Math.atan(v / u) * 180 / Math.PI
fx = 270 - Math.atan(v / u) * 180 / Math.PI
if (fx <= 281.25) {
text = "西风"
} else if (fx > 281.25 && fx < 348.76) {
text = "西北风"
} else {
text = "北风"
}
// if (fx <= 101.25) {
// text = "西风"
// } else if (fx > 101.25 && fx < 168.76) {
// text = "西北风"
// } else {
// text = "北风"
// }
}
else if (u < 0 & v < 0) {//第三象限
// fx = 180 + Math.atan(v / u) * 180 / Math.PI
fx = 90 - Math.atan(v / u) * 180 / Math.PI
if (fx <= 11.25) {
text = "北风"
} else if (fx > 11.25 && fx < 78.76) {
text = "东北风"
} else {
text = "东风"
}
// if (fx <= 191.25) {
// text = "东风"
// } else if (fx > 191.25 && fx < 258.76) {
// text = "东北风"
// } else {
// text = "北风"
// }
}
else if (u < 0 & v > 0) {//第四象限
// fx = 360 + Math.atan(v / u) * 180 / Math.PI
fx = 90 - Math.atan(v / u) * 180 / Math.PI
if (fx <= 101.25) {
text = "东风"
} else if (fx > 101.25 && fx < 168.76) {
text = "东南风"
} else {
text = "南风"
}
}
}
return text
}
}
windyUtil.prototype.analysisWindyData = function(windydata) {
this.allgrid = []
let p = 0
let east, north
if (windydata[0].header.parameterNumberName == "eastward_wind") {
east = windydata[0]
north = windydata[1]
} else {
east = windydata[1]
north = windydata[0]
}
for (let j = 0; j < north.header.ny; j++) {
let row = []
for (let i = 0; i < north.header.nx; i++, p++) {
row[i] = [east.data[p], north.data[p]]
}
this.allgrid[j] = row
}
}
windyUtil.prototype.getWindyDetail = function(coord) {
let lng = coord[0]
let lat = coord[1]
// 与格网序列的数据转换
// if (lng >= 0) {
// lng = Math.floor(lng)
// } else {
// lng = 360 + Math.floor(lng)
// }
// lat = 90 - Math.floor(lat)
// 获取对应的格网序列(此示例为中国区域0.25度规格)
let xlength = Math.floor((coord[0]-70) / 0.25)
let ylength = Math.floor((55-coord[1]) / 0.25)
let xdata, ydata
xdata = parseFloat(this.allgrid[Math.abs(ylength)][Math.abs(xlength)][0])
ydata = parseFloat(this.allgrid[Math.abs(ylength)][Math.abs(xlength)][1])
debugger
let feng=this.direction_calculation(xdata,ydata)
if (typeof xdata != "number" || typeof ydata != "number") {
console.error("暂无该区域风向数据!")
return
}
let v = Math.sqrt(Math.pow(xdata, 2) + Math.pow(ydata, 2))
let angle = this.getWindyAngle(xdata, ydata)
let result = {
"direction": feng,
"level": this.getWindyLevel(v),
"speed": v.toFixed(2)
}
return result
}
windyUtil.prototype.direction_calculation = function (u, v) {
let fx = 0
// let v = v2 * (-1)
let text = "无"
if (u == 0) {
if (v > 0) {
text = "南风"
} else if (v < 0) {
text = "北风"
}
} else if (v == 0) {
if (u > 0) {
text = "西风"
} else if (u < 0) {
text = "东风"
}
} else {
if (u > 0 & v > 0) {//第一象限
// fx = Math.atan(v / u) * 180 / Math.PI
fx = 270 - Math.atan(v / u) * 180 / Math.PI
if (fx <= 191.25) {
text = "南风"
} else if (fx > 191.25 && fx < 258.76) {
text = "西南风"
} else {
text = "西风"
}
// if (fx <= 11.25) {
// text = "南风"
// } else if (fx > 11.25 && fx < 78.76) {
// text = "西南风"
// } else {
// text = "西风"
// }
}
else if (u > 0 & v < 0) {//第二象限
// fx = 180 + Math.atan(v / u) * 180 / Math.PI
fx = 270 - Math.atan(v / u) * 180 / Math.PI
if (fx <= 281.25) {
text = "西风"
} else if (fx > 281.25 && fx < 348.76) {
text = "西北风"
} else {
text = "北风"
}
// if (fx <= 101.25) {
// text = "西风"
// } else if (fx > 101.25 && fx < 168.76) {
// text = "西北风"
// } else {
// text = "北风"
// }
}
else if (u < 0 & v < 0) {//第三象限
// fx = 180 + Math.atan(v / u) * 180 / Math.PI
fx = 90 - Math.atan(v / u) * 180 / Math.PI
if (fx <= 11.25) {
text = "北风"
} else if (fx > 11.25 && fx < 78.76) {
text = "东北风"
} else {
text = "东风"
}
// if (fx <= 191.25) {
// text = "东风"
// } else if (fx > 191.25 && fx < 258.76) {
// text = "东北风"
// } else {
// text = "北风"
// }
}
else if (u < 0 & v > 0) {//第四象限
// fx = 360 + Math.atan(v / u) * 180 / Math.PI
fx = 90 - Math.atan(v / u) * 180 / Math.PI
if (fx <= 101.25) {
text = "东风"
} else if (fx > 101.25 && fx < 168.76) {
text = "东南风"
} else {
text = "南风"
}
}
}
return text
}
windyUtil.prototype.getWindyDirection = function(angle) {
if ((angle >= 0 && angle <= 22.5) || (angle <= 360 && angle > 337.5)) {
return "东风"
}
if (angle <= 337.5 && angle > 292.5) {
return "西北风"
}
if (angle <= 292.5 && angle > 247.5) {
return "北风"
}
if (angle <= 247.5 && angle > 202.5) {
return "西南风"
}
if (angle <= 202.5 && angle > 157.5) {
return "东风"
}
if (angle <= 157.5 && angle > 112.5) {
return "东南风"
}
if (angle <= 112.5 && angle > 67.5) {
return "南风"
}
if (angle <= 67.5 && angle > 22.5) {
return "西南风"
}
}
windyUtil.prototype.getWindyAngle = function(u, v) {
let fx = 0
if (u > 0 & v > 0) {
fx = 90 - Math.atan(v / u) * 180 / Math.PI
} else if (u < 0 & v > 0) {
fx = 90 - Math.atan(v / u) * 180 / Math.PI
} else if (u < 0 & v < 0) {
fx = 270 - Math.atan(v / u) * 180 / Math.PI
} else if (u > 0 & v < 0) {
fx = 270 - Math.atan(v / u) * 180 / Math.PI
} else if (u == 0 & v > 0) {
fx = 180
} else if (u == 0 & v < 0) {
fx = 0
} else if (u > 0 & v == 0) {
fx = 270
} else if (u < 0 & v == 0) {
fx = 90
} else if (u == 0 & v == 0) {
fx = 999.9
}
return fx
}
windyUtil.prototype.getWindyLevel = function(v) {
if (v < 0.3) {
return 0
}
if (v >= 0.3 && v < 1.6) {
return 1
}
if (v >= 1.6 && v < 3.4) {
return 2
}
if (v >= 3.4 && v < 5.5) {
return 3
}
if (v >= 5.5 && v < 8.0) {
return 4
}
if (v >= 8.0 && v < 10.8) {
return 5
}
if (v >= 10.8 && v < 13.9) {
return 6
}
if (v >= 13.9 && v < 17.2) {
return 7
}
if (v >= 17.2 && v < 20.8) {
return 8
}
if (v >= 20.8 && v < 24.5) {
return 9
}
if (v >= 24.5 && v < 28.5) {
return 10
}
if (v >= 28.5 && v < 32.7) {
return 11
}
if (v >= 32.7 && v < 37.0) {
return 12
}
if (v >= 37.0 && v < 41.5) {
return 13
}
if (v >= 41.5 && v < 46.2) {
return 14
}
if (v >= 46.2 && v < 51.0) {
return 15
}
if (v >= 51.0 && v < 56.1) {
return 16
}
if (v >= 56.1 && v < 61.2) {
return 17
}
if (v >= 61.2) {
return 18
}
}
return windyUtil
}())
export {windyUtil}
三、调用代码编写
let windyUtil1 = new windyUtil(zdhCesium,layerId)
windyUtil1.createWindLayer(res)
if(layersInfo[layerId].options.isShow == false){
windyUtil1.hideWindy()
}
layersInfo[layerId].entities.push(windyUtil1)
四、成果展示
————————————————
版权声明:本文为CSDN博主「兴诚」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_42496466/article/details/123501757