【Node.js】ウェブ上の地図にPLATEAUの建物を反映させてみた


国土交通省の３D都市モデルPLATEAUを使ったウェブアプリケーションを作るため、JavascriptのライブラリCesiumJSを使ってみました。


## 環境
- Node.js
- 使用エディタ： VSCode  
- 動作確認OS ： Windows10


## PLATEAU
広島県呉市のデータを例にします。
ここからダウンロード
https://www.geospatial.jp/ckan/dataset/plateau-34202-kure-shi-2020

この中から 3D Tiles, GeoJson, MVT, Shape 
＞　詳細　＞　ダウロード
[![Image from Gyazo](https://i.gyazo.com/a41a29c5ebd49fa57417edbebc441024.png)](https://gyazo.com/a41a29c5ebd49fa57417edbebc441024)

ダウンロードデータを解凍すると
[![Image from Gyazo](https://i.gyazo.com/f02fd7eaf3e6ce7b9c21034eba5dac56.png)](https://gyazo.com/f02fd7eaf3e6ce7b9c21034eba5dac56)

この中から
01_building > 34202_kure-shi_2020_bldg_notexture

[![Image from Gyazo](https://i.gyazo.com/c0115fa088d4e553da215332f83116c6.png)](https://gyazo.com/c0115fa088d4e553da215332f83116c6)

これをどこかサーバーに保存します。


## AWS S3 の場合

サーバーに保存するといった時点で、多くの人が脱落しそうなので、ここでは、AWSのS3に保存するケースを説明します。

### バケットの作成
AWS コンソールにアクセス
AWS S3 > バケットを作成

バケット名入力、
リージョン選択

このバケットのブロックパブリックアクセス設定
「パブリックアクセスをすべて ブロック」のチェックを外し、
「パブリックアクセスのブロックをすべてオフにすると・・・」のチェックを入れる。

[![Image from Gyazo](https://i.gyazo.com/7880ebe5882877ee797f7ba0d3e2bc08.png)](https://gyazo.com/7880ebe5882877ee797f7ba0d3e2bc08)

「パケットを作成」をクリック


バケットができる。

### バケットポリシーの編集

アクセス許可　＞　バケットポリシー　を編集

ポリシーを以下のように設定する

```
{
   "Version":"2012-10-17",
   "Statement":[{
    "Sid":"PublicReadForGetBucketObjects",
         "Effect":"Allow",
      "Principal": "*",
       "Action":["s3:GetObject"],
       "Resource":["arn:aws:s3:::[バケット名]/*"
       ]
     }
   ]
 }
```

### CORS設定

アクセス許可　＞　Cross-Origin Resource Sharing (CORS) 

```
[
    {
        "AllowedHeaders": [
            "Authorization"
        ],
        "AllowedMethods": [
            "GET",
            "HEAD",
            "POST"
        ],
        "AllowedOrigins": [
            "オリジンを指定" （例）http://XXX.0.0.1:5500
        ],
        "ExposeHeaders": [
            "Access-Control-Allow-Origin"
        ]
    }
]
```
<br>

そして、先ほどのPLATEAU のファイル（dataフォルダ、tileset.json）をアップロードします。
[![Image from Gyazo](https://i.gyazo.com/c0115fa088d4e553da215332f83116c6.png)](https://gyazo.com/c0115fa088d4e553da215332f83116c6)

<br>



## 作成

Node.js で環境を構築し、CesiumJS というライブラリを使用します。

このあたりのところは、ほぼこちらの記事そのままです。先人の知恵ありがとうございます。
[Cesium js の始め方：インストールから解説します！](https://qiita.com/keijipoon/items/615ebaf7561a27d744f5)

<br>
まずは、最初の設定

```
$ mkdir cesium-project
$ cd cesium-project
$ npm init -y
```
<br>
CesiumJS　をインストール

```
$ npm install cesium --save
```

### コード

以下の3つのファイルを作成。

``` index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>cesium</title>
    <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no">
    <link rel="stylesheet" href="node_modules/cesium/Build/Cesium/Widgets/widgets.css">
    <link rel="stylesheet" href="stylesheet.css">
  </head>
  <body>
    <div id="cesium" class="cesium"></div>
    <script src="node_modules/cesium/Build/Cesium/Cesium.js"></script>
    <script src="main.js"></script>
  </body>
</html>
```


``` stylesheet.css
body {
  margin: 0;
}

.cesium {
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
}

```

``` main.js
(function() {
    "use strict";
  
    var viewer = new Cesium.Viewer("cesium");
  
      //初期の視点（カメラ）の位置 日本の中国地方の上空にカメラが来るように設定。
    viewer.camera.setView({
     destination: Cesium.Cartesian3.fromDegrees( 132 , 34, 500000), //経度・緯度、高さ
     orientation: {
       heading: 0, // 水平方向の回転度（ラジアン）
       pitch: -1.6, // 垂直方向の回転度（ラジアン） 上を見上げたり下を見下ろしたり
       roll: 0
    }
  });

 
  viewer.scene.primitives.add(new Cesium.Cesium3DTileset({
    url:"https://XXX.com/tileset.json"   //tilesetを保存したURL
  }));

  
}());
```

<br>

## 実行

ローカルサーバーを立てます。
私は、　VS Codeの拡張機能LineServerを使っています。
LineServerではVSCode下方の 「Go Live」をクリックするだけでローカルサーバーが立ち上がるので楽ちんです。
[![Image from Gyazo](https://i.gyazo.com/e92bec17d2d634ad8df138f70f947e45.png)](https://gyazo.com/e92bec17d2d634ad8df138f70f947e45)

「Go Live」をクリックすると、サーバーが起動し、こんな画面になります。
[![Image from Gyazo](https://i.gyazo.com/4adfb22ee4af85d88982f1bf2b922cdd.jpg)](https://gyazo.com/4adfb22ee4af85d88982f1bf2b922cdd)

地図を拡大して呉市。
ちゃんとPLATEAUの建物が反映されてました。
[![Image from Gyazo](https://i.gyazo.com/46e9c76abbf01933232b5667a291c169.jpg)](https://gyazo.com/46e9c76abbf01933232b5667a291c169)


<br>
しかし、

地面が平面のままなので、拡大すると、建物が浮かんでいますね。

[![Image from Gyazo](https://i.gyazo.com/462f1e362aace7ef403ec27014072695.jpg)](https://gyazo.com/462f1e362aace7ef403ec27014072695)

ウェブのUI　「Cesium World Terrain」 で地形を反映させます。
[![Image from Gyazo](https://i.gyazo.com/ca634afcdf241163a8017113aacea156.jpg)](https://gyazo.com/ca634afcdf241163a8017113aacea156)


地形が反映されました。
[![Image from Gyazo](https://i.gyazo.com/1778df769d5963d640e914c57b0ebe5a.jpg)](https://gyazo.com/1778df769d5963d640e914c57b0ebe5a)

[![Image from Gyazo](https://i.gyazo.com/1ba9ae453d22e76c4c25d34ccbfe60fb.jpg)](https://gyazo.com/1ba9ae453d22e76c4c25d34ccbfe60fb)

<br>

[Cesium World TerrainのWebサイト](https://cesium.com/platform/cesium-ion/content/cesium-world-terrain/)を見ると
Cesium ion　にサインアップして数行コードを入力すれば、UIからでなくてプログラムから地形を３Dに反映することができそう。
（今後の宿題にします）

<br><br>

以上、やっと、PLATEAU のデータを使ったウェブアプリケーション開発の初めの一歩に到達できました。

<br>