Protocol Buffers ベースのラスター標高タイル。
3段階ズーム LOD · GEBCO + ALOS 2ソース · Int16 デルタ + deflateRaw · Worker ゼロコピー
altpbf は Protocol Buffers ベースのバイナリ標高タイルフォーマットである。 GeoPBF がベクタージオメトリ(海岸線・道路・ポリゴン)を扱うのに対し、 altpbf はラスター標高グリッド、すなわち 地形レンダリング・影計算・3D 可視化に必要な数値標高モデル(DEM)と 海底地形データを扱う。
各タイルは Int16 標高値(メートル)の矩形グリッドを
デルタエンコードし deflateRaw で圧縮したものである。
3 種類のタイルサイズが異なる解像度で地球全体をカバーし、
ズームレベルに応じて適切なティアが自動選択される。
地球の標高範囲はおよそ −11,000 m(マリアナ海溝)から +8,849 m(エベレスト)。 符号付き 16 bit 整数は −32,768 〜 +32,767 m をカバーできる — 必要十分でビット無駄なし。 Float32 と比較してデータサイズが圧縮前から半分になる。
| ソース | カバレッジ | 解像度 | 用途 |
|---|---|---|---|
| GEBCO General Bathymetric Chart of the Oceans |
全球(陸・海底) | 約 450 m (15 arc-sec) | HGT90 · HGT10 |
| ALOS AW3D30 JAXA ALOS 全球 3D 地図 |
陸地のみ | 約 30 m (1 arc-sec) | HGT01 |
GEBCO は海底地形を含む全球データであり、すべてのズームレベルのベースラインとして機能する。 ALOS AW3D30 は JAXA が公開する高精度陸地 DEM であり、 30 m 解像度により近距離の地形レンダリングで視覚的に意味のある詳細を提供する。 ALOS タイルは陸地のみに存在するため、altpbf は利用可能タイルのインデックスを保持し、 海洋クエリに対しては GEBCO HGT10 へシームレスにフォールバックする。
altpbf は 3 種類のタイルサイズを定義し、それぞれが異なる角度範囲の地球をカバーする。
createGetHeight は現在のズームレベルに基づいてティアを切り替え、
デフォルトは level1 = 7、level2 = 12 である。
各ティアは厳格なフォールバックチェーンを形成する:HGT01 → HGT10 → HGT90。 高解像度タイルが存在しない(海洋、ALOS データなし)か標高値が得られない場合、 次のより粗いティアが透過的にクエリに答える。 呼び出し側は常に有効な標高値を受け取る。
タイル内では calcHeight(x, y, v) が最近傍 4 グリッドセルにわたる
バイリニア補間を実行するため、階段状のアーティファクトが生じない。
タイル内の正規化座標(0〜1)は生の lat/lng から計算され、
そのまま補間関数に渡される。
各 .altpbf タイルは deflateRaw 圧縮された Protocol Buffers メッセージである。
deflateRaw / inflateRaw地形の標高はなだらかに変化する — DEM の隣接セルが数十メートル以上異なることはまれである。 デルタエンコーディングはこの局所性を利用し、絶対値ではなく差分を格納することで 値を小さく保ち、Varint バイト数を削減する。
なだらかな地形タイルでは、デルタエンコード後のほとんどの値が 1 Varint バイトに収まる。 その上に deflateRaw を重ねることで、altpbf タイルは生 Int16 配列と比べて 典型的に 5〜15 倍 小さくなる。
altpbf2png は標高・水深ステップに応じたカラーで PNG としてタイルをレンダリングする:
各タイルは範囲・緯度・経度をコンパクトにエンコードした名前文字列で一意に識別される:
encodeName(lng, lat, range)
// range > 0 → "R{02d(range)}{緯度符号}{03d(|lat|)}{経度符号}{03d(|lng|)}"
// range = 0 → "{緯度符号}{03d(|lat|)}{経度符号}{03d(|lng|)}" (ALOS 1° タイル)
// 例:
encodeName(0, -90, 90) // → "R90S090E000" (HGT90 南西象限)
encodeName(130, 30, 10) // → "R10N030E130" (HGT10 日本周辺)
encodeName(135, 35, 0) // → "N035E135" (HGT01 ALOS、近畿地方)
ALOS AW3D30 タイルは陸地にしか存在しない。
HGT01 タイルをリクエストする前に、altpbf は JAXA タイルリストから
読み込んだインメモリインデックス(index_alos())を確認する。
海洋クエリはネットワークラウンドトリップなしで即座に HGT10 へフォールバックする。
// worker.js — Int16Array をゼロコピーでメインスレッドへ転送
import { load } from "./altpbf.js";
onmessage = async e => {
const { name, apiUrl } = e.data;
if (apiUrl) setApiUrl(apiUrl);
const obj = await load(name);
obj ? postMessage(obj, [obj.data.buffer]) // ← Transferable: ゼロコピー
: postMessage(null);
};
Worker はタイルの伸張・デコードをメインスレッド外で行い、
Int16Array バッファを Transferable インターフェースでゼロコピー返却する。
1 つの Worker がリクエストを直列処理するため、ロード中に来た追加クエリは同じ Promise を待つ。
デコード後はセッションをまたいで即時再利用できるよう IndexedDB に永続化される。
GEBCO の生ソースは 90° 象限ごとに 21,600 × 21,600 ピクセルのグローバル GeoTIFF
(全球で 43,200 × 21,600)。
GEBCO() 関数がこれをダウンロードして altpbf 形式にタイル化する:
// Step 1 — HGT90: 8× 平均プーリングダウンサンプル
// 21600 × 21600 → 2700 × 2700 (象限ごとに 1 つの 90° タイル)
// 出力 1 ピクセル = 8×8 ソースピクセルの平均
// Step 2 — HGT10: 象限ごとに 9×9 = 81 サブタイルを切り出し
// 極収縮(polar shrink)を適用してタイルが画面上で正方形に見えるよう調整
経線は極に向かうにつれ収束するため、高緯度では 10° の経度幅が表す実距離が赤道より大幅に短い。 GEBCO HGT10 タイル生成では、極域のタイルのピクセル幅を縮小することでこれを補正する:
赤道基準に対するタイルピクセル幅の比。極域タイルは細く、 1 経度あたりの実距離縮小と対応している。
// ── createGetHeight — メインエントリーポイント ─────────
const getHeight = await createGetHeight({
apiUrl: 'https://your-api.example.com', // nativeBucket ベース URL
level1: 7, // HGT90 → HGT10 切替ズーム閾値
level2: 12, // HGT10 → HGT01 切替ズーム閾値
onstart: name => console.log(`loading ${name}...`),
onend: name => console.log(`done ${name}`),
});
// 任意の (lng, lat, zoom) で標高クエリ
const h = await getHeight(139.77, 35.68, 14); // → 標高(メートル)
// zoom 省略 → 常に最高解像度(HGT01)を使用
const h = await getHeight(139.77, 35.68);
// ── altpbf2png — タイルを PNG としてレンダリング ────────
const blob = await altpbf2png(pbfBlob, {
size: 256, // 出力 PNG サイズ(正方形)
colorMap: h => [r, g, b] // カスタムカラー関数(省略可)
});
// ── 低レベル encode / decode ─────────────────────────────
const buf = await encode({ name, source, lng, lat, range, width, height, data });
const obj = await decode(blob); // → { name, source, lng, lat, range, width, height, data: Int16Array }
// ── GEBCO 一括タイル生成 ─────────────────────────────────
await GEBCO({ year: 2026, noIce: false, log: console });
// 約 12 GB ソースをダウンロード、HGT90 + HGT10 altpbf タイルを生成してバケットへアップロード
// ── ALOS タイルインデックス ───────────────────────────────
const index = await index_alos();
// → { "N035E135": "v2404", "N036E135": "v2404", ... }