CODE HOUSE


Hello, I'm a freelance software engineer.


[WORK]標高エリアjsonデータを読み込む

標高エリアjsonデータを読み込む

先日の記事で作成した、不思議な文字列のjsonデータを読み込むクラスを作成してみる。読み込みの手順は下記の通りになる。

  1. require()でjsonを読み込む。
  2. 読み込んだ文字列を4文字ごとに区切る。
  3. 4文字に区切ったうち、末尾の’=‘を削る。
  4. 残りの文字列をbase64と似たアルゴリズムでデコードする。すると、24bitのデータが抽出される。
  5. 上位7bitが緯度、次の8ビット経度、残り9bitが3x3グリッドのデータ有無を表す。
  6. 緯度経度を16進数変換して4文字の文字列にする。これをkeyとする。グリッドの値はそのままvalueとする。
  7. 結果として下記の様なObjectになる。
area Object
 1area = {
 2  "NE": {
 3    "000a": 511, // 北緯0度、東経10度の3x3グリッドには全てのグリッドにデータがあることを示す。
 4    "0100": 511,
 5    :
 6  },
 7  "NW": {
 8    "0a0a": 511,
 9    "0a0b": 511,
10    :
11  },
12  "SE": {
13    "0a01": 511,
14    "0a02": 511
15    :
16  },
17  "SW": {
18    "0a29": 8,  // 南緯10度、西経41度の3x3グリッドには、y=1, x=0のグリッドにのみデータがあることを示す。
19    "0d26": 384
20  }
21};

上記処理のコード部分を抜粋して下記に置いておきます。

AltitudeService.js(一部抜粋)
 1class AltitudeService {
 2  _prepareArea() {
 3    let areaJson = require('./altfilter.json');
 4    let area = {
 5      "NE": {},
 6      "NW": {},
 7      "SE": {},
 8      "SW": {}
 9    };
10
11    Object.keys(areaJson).map((areaName) => {
12      let coordinateList = areaJson[areaName].match(/.{1,4}/g);
13      coordinateList.forEach((coordinateBase64) => {
14        let coordinateKeyValue = this._decodeBase64(coordinateBase64);
15        area[areaName][coordinateKeyValue.key] = coordinateKeyValue.value;
16      })
17    });
18
19    return area;
20  }
21
22  _decodeBase64(base64) {
23    base64 = base64.replace("=", "");
24
25    let shift = 0;
26    let decodeValue = 0;
27    while(base64 !== ""){
28      let c = base64.substr(0, 1);
29      let code = c.charCodeAt(0) - 0x3f;
30      decodeValue += code<<shift;
31      shift += 6;
32      base64 = base64.substr(1);
33    }
34
35    let lat = (decodeValue >> 17) & 0x7f;
36    let lng = (decodeValue >> 9) & 0xff;
37    let grid = decodeValue & 0x1ff;
38
39    return {
40      key: this._lngLatToHex(lng, lat),
41      value: grid
42    };
43  }
44}