フリーダムの日記

GIS(地理情報システム)を中心に技術的なことを書いています。

ArcGIS と deck.gl の連携

はじめに

本エントリーは deck.gl Advent Calendar 2021 19日目の記事です。

qiita.com

ArcGIS と deck.gl の連携について紹介したいと思います。

Esri が提供している ArcGIS API for JavaScript からカスタムレイヤーとして deck.gl が提供している機能を使用することができるようになっています。
developers.arcgis.com

過去に以下の記事で紹介しています。
freedom-tech.hatenablog.com

また、deck.gl からは ArcGIS の 3D データモデルを表示することができるようになっています。 ArcGIS の 3D データモデルは、オープンスタンダートの Open Geospatial Consortium(OGC) にも準拠しており、3D GIS データを扱うための各種フォーマットをシーン サービスと呼ばれる I3S 形式で提供しています。

deck.gl

こちらも過去に以下の記事で紹介しています。 freedom-tech.hatenablog.com

今回は前回紹介したときから deck.gl と ArcGIS API for JavaScript のバージョンをアップしていますので、改めて新しい情報を含めて紹介したいと思います。

deck.gl とは

世界最大の配車アプリを開発・運営する Uber 社 がオープンソースとして公開しているデータビジュアライゼーションフレームワークです。現在は、Uber 社から離れてオープンなプロジェクト vis.gl Technical Steering Committee(TSC) として運用されているようです。

deck.gl

ArcGIS API for JavaScript で deck.gl のレイヤーを表示

ArcGIS API for JavaScript の現在の最新バージョンは、4.22 ですが、deck.gl のレイヤーも呼び出して使用することができるようになっています。ArcGIS API for JavaScript から deck.gl を利用する方法については、それぞれ以下のガイドから確認することができます。

deck.gl

developers.arcgis.com

deck.gl と ArcGIS API for JavaScript のレイヤーを使用したサンプルアプリです。

作成したアプリのサンプルソースは以下になります。GeoJSON は、ArcGIS API for JavaScript と deck.gl でも扱うことができるようになっていますが、今回は、ArcGIS API for JavaScriptGeoJSON レイヤークラスを使用しました。

<html>
  <head>
    <!-- deck.gl standalone bundle -->
    <script src="https://unpkg.com/deck.gl@latest/dist.min.js"></script>
    <script src="https://unpkg.com/@deck.gl/arcgis@latest/dist.min.js"></script>

    <!-- ArcGIS dependencies -->
    <link rel="stylesheet" href="https://js.arcgis.com/4.22/esri/themes/light/main.css"/>
    <script src="https://js.arcgis.com/4.22/"></script>

    <style type="text/css">
      body {margin: 0; padding: 0;}
      #container {width: 100vw; height: 100vh;}
    </style>
  </head>

  <body>
    <div id="container"></div>
  </body>

  <script type="text/javascript">

const {loadArcGISModules} = deck;

// source: Natural Earth http://www.naturalearthdata.com/ via geojson.xyz
const COUNTRIES =
  'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_50m_admin_0_scale_rank.geojson'; //eslint-disable-line
const AIR_PORTS =
  'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_10m_airports.geojson';

loadArcGISModules(['esri/Map', 'esri/views/MapView', "esri/layers/GeoJSONLayer"]).then(({DeckLayer, modules}) => {
  const [ArcGISMap, MapView, GeoJSONLayer] = modules;
  const layer = new DeckLayer({
    'deck.layers': [
      new deck.GeoJsonLayer({
        id: 'airports',
        data: AIR_PORTS,
        // Styles
        filled: true,
        pointRadiusMinPixels: 2,
        pointRadiusScale: 2000,
        getPointRadius: f => (11 - f.properties.scalerank),
        getFillColor: [200, 0, 80, 180],
        // Interactive props
        pickable: true,
        autoHighlight: true,
        onClick: info => info.object && alert(`${info.object.properties.name} (${info.object.properties.abbrev})`)
      }),
      new deck.ArcLayer({
        id: 'arcs',
        data: AIR_PORTS,
        dataTransform: d => d.features.filter(f => f.properties.scalerank < 4),
        // Styles
        getSourcePosition: f => [-0.4531566,51.4709959], // London
        getTargetPosition: f => f.geometry.coordinates,
        getSourceColor: [0, 128, 200],
        getTargetColor: [200, 0, 80],
        getWidth: 1
    })
    ]
  });

  const geojsonLayer = new GeoJSONLayer({
    url: COUNTRIES,
    opacity: 0.3,
    copyright: "COUNTRIES"
  });

  // In the ArcGIS API for JavaScript the MapView is responsible
  // for displaying a Map, which usually contains at least a basemap.
  // eslint-disable-next-line
  const mapView = new MapView({
    container: 'container',
    map: new ArcGISMap({
      basemap: 'dark-gray-vector',
      layers: [layer, geojsonLayer]
    }),
    center: [0.119167, 52.205276],
    zoom: 5
  });
});
  </script>
</html>

使用したサンプルアプリは以下の GitHub にも公開しています。 github.com

deck.gl で i3S の 3D データを表示

ArcGIS

次に deck.gl から ArcGIS の 3D データモデルを表示する場合に loaders.gl というライブラリを使用します。

loaders.gl

loaders.gl

現在の最新バージョンが、バージョン 3.1 でいくつか更新されていますが、ArcGIS に関係しそうなところですと、@loaders.gl/i3s が、KTX2-Basis のテクスチャに対応したそうです。
さっそく、テクスチャに対応した i3S の 3D モデルのデータを deck.gl で表示したいと思います。今回は東京都の千代田区の 3D モデルを使用します。以下のサイトから千代田区の 3D Tiles のデータをダウンロードします。

www.geospatial.jp

ダウンロードした 3DTiles のデータを i3S へと変換するために Tile Converter を使用します。
loaders.gl

Tile Converter を最初にインストールします。

$npm i @loaders.gl/tile-converter
$npx tile-converter --install-dependencies

そして、ダウンロードした 3D Tiles を i3S へと変換するために以下のコマンドを実行します。

$npx tile-converter --input-type 3DTILES --tileset ./13101_chiyoda-ku/tileset.json --name 13101_chiyoda-ku --output ./13101_chiyoda-ku_output --slpk

変換に成功すると 13101_chiyoda-ku.slpk という SLPK 形式のファイルが作成されますので、それを ArcGIS のプラットフォームに登録します。

developers.arcgis.com

ArcGIS に 13101_chiyoda-ku.slpk を登録することで、シーンサービスとして作成されます。 以下に ArcGIS に登録した 13101_chiyoda-ku.slpk をシーンビューワーでご覧いただけます。
www.arcgis.com

最後に作成されたシーンサービスを deck.gl から表示してみます。以下の URL が REST のエンドポイントとして、作成されますので、この URL を指定します。 https://tiles.arcgis.com/tiles/HzGpeRqGvs5TMkVr/arcgis/rest/services/13101_chiyoda_ku/SceneServer/layers/0

千代田区の 3D モデルを表示したサンプルアプリです。

千代田区の 3D モデル サンプルアプリ

作成したアプリのサンプルソースは以下になります。

import {loadArcGISModules} from '@deck.gl/arcgis';
import {Tile3DLayer} from '@deck.gl/geo-layers';
import {I3SLoader} from '@loaders.gl/i3s';

// Tileset entry point: Indexed 3D layer file url
const TILESET_URL = 'https://tiles.arcgis.com/tiles/HzGpeRqGvs5TMkVr/arcgis/rest/services/13101_chiyoda_ku/SceneServer/layers/0'

export async function renderToDOM(container) {
  const {DeckRenderer, modules} = await loadArcGISModules([
    'esri/Map',
    'esri/views/SceneView',
    'esri/views/3d/externalRenderers'
  ]);
  const [ArcGISMap, SceneView, externalRenderers] = modules;

  const sceneView = new SceneView({
    container,
    qualityProfile: 'high',
    map: new ArcGISMap({
      basemap: 'dark-gray-vector'
    }),
    environment: {
      atmosphereEnabled: false
    },
    camera: {
      position: {x: 139.7673068, y: 35.6809591, z: 3000},
      heading: 0,
      tilt: 25
    },
    viewingMode: 'local'
  });

  const renderer = new DeckRenderer(sceneView, {});
  externalRenderers.add(sceneView, renderer);

  sceneView.on('layerview-create', () => {
    renderer.deck.layers = [
      new Tile3DLayer({
        id: 'tile-3d-layer',
        data: TILESET_URL,
        loader: I3SLoader
      })
    ];
  });

  return {
    remove: () => {
      sceneView.destroy();
      renderer.dispose();
    }
  };
}

作成したサンプルアプリ一式は以下の GitHub にも公開しています。 github.com

さいごに

deck.gl や loaders.gl はオープンソースなので、ArcGIS 製品を使用しなくても i3S のデータを扱うことができるのは大変便利ですね。前回紹介したときよりも i3S の対応が格段によくなっており、3DTiles や i3S が手軽に使用できる環境になっているのではないかと思いました。今後も deck.gl、loaders.gl ともにバージョンアップもされていくので今後の機能拡張に期待できますね。