geotiff.jsでbounding boxで範囲を指定して取得する方法

# bounding boxで範囲を指定して取得する方法
```js
const filepath = "{somegeotiff.tif}"
const tiff = await GeoTIFF.fromUrl(filepath);
const image = await tiff.readRasters({
    bbox: [139.5, 35.5, 140, 36],
    resX: 0.001,
    resY: 0.001
})
console.log(image);
```
<img width="558" alt="スクリーンショット 2020-05-09 19.46.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203034/e9b1d3b3-fc69-78b0-aa01-f66c16b9b18f.png">

基本的なGeoTIFFとgeotiff.jsの使い方はこちらを読んでください。
[Cloud Optimized GeoTIFFの触り方](https://qiita.com/yonda_gliese/items/19aae7024c4c670982b4)


# ダメな例

```js
const filepath = "{somegeotiff.tif}"
const tiff = await GeoTIFF.fromUrl(filepath); //GeoTIFFBase
const image = await tiff.getImage(0); //GeoTIFFImage
console.log(`Bounding box: ${image.getBoundingBox()}`);
console.log(`Resolution: ${image.getResolution()}`);
console.log(image);
console.log(await image.readRasters({
    bbox: [139.5, 35.5, 140, 36],
    resX: 0.001,
    resY: 0.001
}));
```
<img width="553" alt="スクリーンショット 2020-05-09 19.53.26.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203034/11c3e372-8e79-97aa-7d51-4d80931559a7.png">


[README](https://github.com/geotiffjs/geotiff.js#automatic-image-selection-experimental) を読めばわかることですが、`bbox`を引数で指定できるのは`GeoTIFFBase`のインスタンスの`readRasters`のみです。
`GeoTIFFImage`のインスタンスの`readRasters`で指定しても無視されます（画像全体が取得されます）。
ここに気づかずハマりました。

`GeoTIFFBase.readRasters({bbox,resX,resY})`は指定した分解能に合わせて内部で[いい感じ](https://github.com/geotiffjs/geotiff.js/blob/700763fa9080058b57f864f6f993030899e33bac/src/geotiff.js#L238)にCOGの画像ピラミッドの階層を選択してくれます。`window`はどっちも対応してるのに`bbox`は`GeoTIFFImage`でのみ対応なのはこれが理由）

# 取得例
## 緯度経度
```html
<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>GeoTiff sample</title>
    <style>
        body {
            margin: 0;
            padding: 20px;
            width: 100%;
        }

        #info {
            font-size: 14px;
            margin-bottom: 10px;
        }

        #images>* {
            font-size: 14px;
            margin-bottom: 10px;
        }
    </style>
</head>

<body>
    <div id="info"></div>
    <div id="images"></div>

    <script src="https://cdn.jsdelivr.net/npm/geotiff"></script>
    </script>
    <script>
        (async function () {
            const filepath = "{ASTGTMV003_N35E139_dem.tif}"
            const tiff = await GeoTIFF.fromUrl(filepath);

            const showImage = (tiff, bbox, resX, resY) => {
                tiff.readRasters({
                    bbox,
                    resX,
                    resY
                }).then((image) => {
                    const {
                        width,
                        height
                    } = image;

                    let arr = [];
                    if (image[0].length === width * height) {
                        for (let i = 0; i < image[0].length; i++) {
                            arr[i * 4] = image[0][i];
                            arr[i * 4 + 1] = image[0][i];
                            arr[i * 4 + 2] = image[0][i];
                            arr[i * 4 + 3] = 255;
                        }
                    } else {
                        arr = image[0];
                    }

                    const data = new ImageData(new Uint8ClampedArray(arr), width, height)
                    const canvas = document.createElement("canvas");
                    const ctx = canvas.getContext("2d");
                    canvas.width = width;
                    canvas.height = height;
                    ctx.putImageData(data, 0, 0);

                    const div = document.createElement("div");
                    div.innerHTML =
                        `Bounding box: ${bbox}<br>resX: ${resX}, resY: ${resY}<br>width: ${width}px, height: ${height}px<br>`
                    div.appendChild(canvas);
                    document.getElementById("images").appendChild(div);
                });
            }
            const image = await tiff.getImage(0);
            document.getElementById("info").innerHTML =
                `all<br>Bounding box: ${image.getBoundingBox()}<br>Resolution: ${image.getResolution()}`
            showImage(tiff, [139.5, 35.5, 140, 36], 0.01, 0.01)
            showImage(tiff, [139.5, 35.5, 140, 36], 0.001, 0.001)

        })()
    </script>
</body>

</html>
```
<img width="545" alt="スクリーンショット 2020-05-09 21.26.21.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203034/ce59dab5-3b4c-e4cb-5abf-f7a63b9778df.png">

[ASTER GDEM](https://ssl.jspacesystems.or.jp/ersdac/GDEM/J/) という標高のGeoTIFFの取得例です。
緯度経度座標系で投影されています。COGの状態で配布されています。

サンプルで利用しているファイルは、範囲が[139, 35, 140, 36]、１ピクセルの分解能は0.000277777777777778 (=1/3600) です。

```js
Bounding box: 138.999861111111,34.99986111111112,140.00013888888876,36.0001388888889
Resolution: 0.000277777777777778,-0.000277777777777778,0
```

画像として２枚表示していますが、どちらもbboxで[139.5, 35.5, 140, 36]の範囲を指定して取得しました。
左が分解能0.01, 右が分解能0.001です。
分解能は取得する画像ピラミッドの階層を決めているだけで、widthが (bbox[2] - bbox[0])/resX となるわけではないので注意してください。



## ユニバーサル横メルカトル(UTM)直交座標系

```js
filepath = "https://s3-us-west-2.amazonaws.com/planet-disaster-data/hurricane-harvey/SkySat_Freeport_s03_20170831T162740Z3.tif"
// 中略
showImage(tiff, [265000, 3210000, 270000, 3215000], 100, 100)
showImage(tiff, [265000, 3210000, 270000, 3215000], 20, 20)
```

<img width="397" alt="スクリーンショット 2020-05-09 21.37.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203034/301443ea-22b3-c97b-9ee4-346091fe76eb.png">

だいたいの衛星画像はUTMで座標が与えられているのでこちらの指定の方法にお世話になることが多いかも。