引子
瞭解 WebGL 基礎之後,接著去看獲取解析風場資料的邏輯,又遇到問題。
安裝 ecCodes
在文章示例源庫的說明中,首先要安裝 ecCodes ,嘗試使用 HomeBrew 但不行。於是就按照 ecCodes 源庫的介紹本地進行編譯安裝。
在進行第 4 步的時候,碰到了問題:
No CMAKE_Fortran_COMPILER could be found.
查詢資料說是缺少 gfortran
,可以使用命令檢視是否已安裝:
which gfortran
解決這個問題後按照指導繼續,編譯安裝成功,版本是 2.23.0 。
執行指令碼
執行指令碼的時候,出現了錯誤提示:
grib_set: command not found grib_dump: command not found
但在前面安裝的資料夾的 bin
目錄下是找到了 grib_set 的執行檔案。推斷是沒有註冊到全域性路徑中。
檢視 ecCodes 安裝路徑是否註冊到全域性路徑中:
echo $PATH
這裡碰到的問題是沒有註冊到全域性路徑中,設定方式可參考這裡。
修改示例:
vim ./.bash_profile
進入到編輯模式後,新增下面的內容:
export ECCODE_HOME=/xx/xx/xx/xx/eccodesbuild/bin
export PATH=$PATH:$ECCODE_HOME
儲存後,使其生效
source ./.bash_profile
想知道是否生效了,試試指令 grib_set -h
,如果發現沒有效果,有可能跟使用的 shell 端有關,可參看這裡。
資料生成
指令碼可以正常執行了,但生成的資料不對:
undefined:1
{"u":,"v":}
檢視源庫的 issues ,裡面也有人提這個問題,試了裡面的一些方法,發現這個 pull 的修改可以正常的執行。於是就 fork 了一下把這個修改的內容弄過來了,改了些資料,見 XXHolic/webgl-wind 。
資料含義
在 download.sh
指令碼中,獲取資料解析後,生成可讀檔案 tmp.json
,來看看這個檔案中主要結構和部分資料:
{
"u":{
"messages" : [
[
{
"key" : "name",
"value" : "U component of wind"
},
{
"key" : "Ni",
"value" : 360
},
{
"key" : "Nj",
"value" : 181
},
{
"key" : "values",
"value" : [5.51964, 5.71964, ...]
},
{
"key" : "maximum",
"value" : 103.02
},
{
"key" : "minimum",
"value" : -36.0804
}
]
]
},
"v":{
"messages" : [
[
{
"key" : "name",
"value" : "V component of wind"
},
{
"key" : "getNumberOfValues",
"value" : 65160
},
{
"key" : "values",
"value" : [14.9446, 14.8446, ...]
},
{
"key" : "maximum",
"value" : 80.3446
},
{
"key" : "minimum",
"value" : -66.4554
}
]
]
}
}
看到這些可能會有些疑惑,大氣中的氣流既有速度也有方向,在數學上可以用一個向量表示。在氣象學中,如果知道風的方向和大小,就可以得到表示風的向量,u 分量和 v 分量:
// ws 風力大小 θ 風在數學上的方向描述
u = ws * cos(θ)
v = ws * sin(θ)
更加詳細的介紹見 Wind: u and v Components 。
接著在 prepare.js
中使用到風資料中的 key
有:
Ni
表示在一條緯線上有多少個點,簡單的說就是有多少列。Nj
表示在一條經線上有多少個點,簡單的說就是有多少行。values
存放分量所有的值。minimum
表示分量的最小值。maximum
表示分量的最大值。
其中 Ni
和 Nj
決定了生成圖片的寬和高,風速大小對映對應顏色主要邏輯如下:
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const i = (y * width + x) * 4;
const k = y * width + ((x + width / 2) % width);
png.data[i + 0] = Math.floor(
(255 * (u.values[k] - u.minimum)) / (u.maximum - u.minimum)
);
png.data[i + 1] = Math.floor(
(255 * (v.values[k] - v.minimum)) / (v.maximum - v.minimum)
);
png.data[i + 2] = 0;
png.data[i + 3] = 255;
}
}
i
: 使用了 pngjs 外掛,顏色使用 RGBA 模式,陣列中每連續的 4 個位置儲存的是一個點的顏色值,所以i
變數要是 4 的倍數。k
: 用於獲取風速大小的索引,先看看 y=0 時,k 的取值變化先從 180 -> 359 遞增,然後從 0 -> 179 遞增,這樣從中間開始取值,猜測是由於這個展示地圖是二維的世界地圖,返回的資料就是這樣的對應規則。- 對映方式: 以
maximum - minimum
作為基準,然後計算風速大小相對值values[k] - minimum
,兩個值的比例乘以顏色分量最大值 255 。