GIS风场及其相关技术研究二

标签: Gis 分类: Gis 创建时间:2019-10-29 05:57:10 更新时间:2025-01-17 10:39:22

继成功改造了从:https://meteowise.com/windy/ 获取到的源码显示了全球的流动的风场之后,今天又继续奋战在风场可视化的技术研究路上。虽然代码已经有了,部分的原理也已经说明了,但是就我这小脑袋瓜子,愣是看不懂。特别是从图片中提取风场信息的readImgAttr函数( 原理 ),代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
VectorField.readImgArr = function(imageArr) {
var field = [];
var w = 720;
var h = 360;
var n = 2 * w * h;
var i = 0;

var total = 0;
var weight = 0;
for (var x = 0; x < w; x++) {
field[x] = [];
for (var y = 0; y < h; y++) {
var vx = (imageArr[(w*y+x)*4+0]-128)/1.6;
var vy = (imageArr[(w*y+x)*4+1]-128)/1.6;
var v = new Vector(vx, vy);
var ux = x / (w - 1);
var uy = y / (h - 1);
var lon = -179.5 * (1 - ux) + 179.5 * ux;
var lat = 89.5 * (1 - uy) + -89.5 * uy;
var m = Math.PI * lat / 180;
var length = v.length();
if (length) {
total += length * m;
weight += m;
}
v.x /= Math.cos(m);
v.setLength(length);
field[x].push(v);
}
}
var result = new VectorField(field, -179.5, 89.5, 179.5, -89.5);
// window.console.log('total = ' + total);
// window.console.log('weight = ' + weight);
if (total && weight) {

result.averageLength = total / weight;
}
return result;

};

其中的vx,vy为什么要除以1.6呢?搞不懂,带着这个问题,我又先后访问了以下几个代码库

esri风场效果 这是上面的一个效果图

参考文章:
1.leaflet-velocity 这是leaflet中的一个插件
2.Esri/wind-js esri关于风场的一个实现
3.grib气象格式插件 这是将grib气象格式转为json格式的一个插件

同时,我也找到了原始的气象数据格式:esri_gfs气象数据之风向数据json格式解析

这也是 VectorField.read 函数所要读取的气象数据格式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
VectorField.read = function(data) {
var field = [];
var w = data[0].header.nx;
var h = data[0].header.ny;
var n = 2 * w * h;
var i = 0;

var total = 0;
var weight = 0;
for (var x = 0; x < w; x++) {
field[x] = [];
for (var y = 0; y < h; y++) {
var vx = data[0].data[w*y+x];
var vy = data[1].data[w*y+x];
var v = new Vector(vx, vy);
var ux = x / (w - 1);
var uy = y / (h - 1);
var lon = data[0].header.lo1 * (1 - ux) + data[0].header.lo2 * ux;
var lat = data[0].header.la1 * (1 - uy) + data[0].header.la2 * uy;
var m = Math.PI * lat / 180;
var length = v.length();
if (length) {
total += length * m;
weight += m;
}
v.x /= Math.cos(m);
v.setLength(length);
field[x].push(v);
}
}
var result = new VectorField(field, data[0].header.lo1, data[0].header.la1, data[0].header.lo2, data[0].header.la2);
// window.console.log('total = ' + total);
// window.console.log('weight = ' + weight);
if (total && weight) {

result.averageLength = total / weight;
}
return result;
};

通过cambecc/earth,我又顺腾摸瓜,找到了:wind ,通过查看源码,发现,其实他的实现方式和函数,类命名方式,就是可视化风场那一篇中提到的基本一致。
另一个可视化的示例网站:可视化
通过esri提供的windy.js,我将其进行移植,但是出现了只能绘制一部分的情况,这个主要是canvas的大小问题。

主要代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
<!DOCTYPE html>
<html>
<head>
<title>风场测试</title>
<meta charset="utf-8"/>
<link rel="stylesheet" href="../lib/ol/ol.css" type="text/css">
<script src="../lib/ol/ol.js"></script>
<script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
<style>
body,html{
width:100%;
margin:0;
padding:0;
height: 100%;
position:absolute;
}
.map{
width:100%;
height:100%;
position:absolute;
}
.save{
position: absolute;
left: 200px;
z-index: 10;
}
</style>
</head>
<body>
<canvas id="canvas" style="position: absolute; z-index: 10; pointer-events: none;left: 0;top:0;bottom: 0;right: 0;"></canvas>
<div class="map" id="map"></div>
<script src="./js/windy.js"></script>
<script>
var asideVue={
projection: "EPSG:3857"
}
var DARK_BLUE = new ol.source.XYZ({
url: "http://map.geoq.cn/ArcGIS/rest/services/ChinaOnlineStreetPurplishBlue/MapServer/tile/{z}/{y}/{x}"
});

var basicMap = new ol.layer.Tile({source: DARK_BLUE});
var projection = "EPSG:3857"; // "EPSG:3857"; //"EPSG:10035";
var center = new ol.proj.fromLonLat([110, 24], projection);
var mapExtent = ol.proj.transformExtent([-180, -85, 180, 85],'EPSG:4326', projection);
var monitorMap = new ol.Map({
controls: ol.control.defaults({
attributionOptions:
({
collapsible: false
})
}),
layers:[basicMap],
target: 'map',
view: new ol.View({
projection: projection,
center: center,
extent: mapExtent,
zoom: 4,
maxZoom: 15,
minZoom: 3,
})
});
// var display = new MotionDisplay(document.getElementById('canvas'), new VectorField([[]], -179.5, 89.5, 179.5, -89.5));

$.ajax({
url:"./gfs.json",
success:function(data){
var canvas=monitorMap.getTargetElement().querySelector(".ol-unselectable");
//var windy = new Windy({ canvas:canvas, data: data });
var windy = new Windy({ canvas:document.getElementById('canvas'), data: data });

var mapSize = monitorMap.getSize();
var width = mapSize[0];
var height = mapSize[1];
var extent = monitorMap.getView().calculateExtent(mapSize);
extent = new ol.proj.transformExtent(extent,asideVue.projection, 'EPSG:4326' );
windy.start(
[[0,0],[width, height]],
width,
height,
[[extent[0], extent[1]],[extent[2], extent[3]]]
);
},
error:function(err){
console.log(err);
}
})
</script>
</body>
</html>

我这里的canvas用到的id为canvas的canvas,没有设置其大小,但是我使用ol地图的canvas,底图会出现被逐渐淡化的问题。

底图最终会成为了空白底图,暂时还没有找到解决问题的方法,继续探索吧。

参考文章:
1.数据可视化之风场分布图 这是一个公司的网站,包括了:数据解析,解析了美国气象局数据;数据编码;数据解码
2.这张气象数据——风场可视化地图是怎么做的? Mapbox 技术大牛倾囊相授 这里也提到了图片存储风场数据,但是整篇文章的思路,是使用的WEBGL进行风场的绘制,还是感觉有点懵。
3.气象可视化之windy方案的技术分析 这个对windy用到的技术有了一定的分析
小额赞助
本人提供免费与付费咨询服务,感谢您的支持!赞助请发邮件通知,方便公布您的善意!
**光 3.01 元
Sun 3.00 元
bibichuan 3.00 元
微信公众号
广告位
诚心邀请广大金主爸爸洽谈合作
每日一省
isNaN 和 Number.isNaN 函数的区别?

1.函数 isNaN 接收参数后,会尝试将这个参数转换为数值,任何不能被转换为数值的的值都会返回 true,因此非数字值传入也会返回 true ,会影响 NaN 的判断。

2.函数 Number.isNaN 会首先判断传入参数是否为数字,如果是数字再继续判断是否为 NaN ,不会进行数据类型的转换,这种方法对于 NaN 的判断更为准确。

每日二省
为什么0.1+0.2 ! == 0.3,如何让其相等?

一个直接的解决方法就是设置一个误差范围,通常称为“机器精度”。对JavaScript来说,这个值通常为2-52,在ES6中,提供了Number.EPSILON属性,而它的值就是2-52,只要判断0.1+0.2-0.3是否小于Number.EPSILON,如果小于,就可以判断为0.1+0.2 ===0.3。

每日三省
== 操作符的强制类型转换规则?

1.首先会判断两者类型是否**相同,**相同的话就比较两者的大小。

2.类型不相同的话,就会进行类型转换。

3.会先判断是否在对比 null 和 undefined,是的话就会返回 true。

4.判断两者类型是否为 string 和 number,是的话就会将字符串转换为 number。

5.判断其中一方是否为 boolean,是的话就会把 boolean 转为 number 再进行判断。

6.判断其中一方是否为 object 且另一方为 string、number 或者 symbol,是的话就会把 object 转为原始类型再进行判断。

每日英语
Happiness is time precipitation, smile is the lonely sad.
幸福是年华的沉淀,微笑是寂寞的悲伤。