はじめに
2023 年 5 月に Cesium と Esri の ArcGIS が正式に連携をサポートするニュースがありました。CesiumJS で ArcGIS のロケーションサービスを使用する機能を Esri と Cesium が正式にサポートされるようになりました。Cesium と Esri では、以下のアナウンスがありました。
今回は、ArcGIS と連携した CesiumJS で具体的にどのような機能が使用できるようになったのか、 主に連携した内容にフォーカスして説明していきたいと思います。
Cesium とは
Cesium は、オープンソースの 3D 地理空間可視化プラットフォームで、3D の地物や地形のデータを読み込んで、ブラウザだけで GIS を実現することができます。2012 年に初期リリースされており、3D 情報を表示する仕組みとして 3DTiles を導入しています。3D 関連のサービスや製品としては、以下の 3D 関連の製品群があります。
- 3D 関連の製品群
CesiumJS(ArcGIS との連携)
ArcGIS との連携を可能にしているのは、Web アプリ開発用 API である CesiumJS になります。CesiumJS には、連携用のクラスを提供しています。
連携用のクラス | 内容 |
---|---|
Cesium.I3SDataProvider | OGC I3S (Esri の 3D データ仕様) を表示 |
ArcGisMapServerImageryProvider | 2D イメージ タイルを表示 |
ArcGISTiledElevationTerrainProvider | Esri の標高レイヤーを標高ソースに使用 |
Esri 側には、CesiumJS と連携するための ArcGIS REST JS を使用した連携のコードを提供しています。これにより、ArcGIS のロケーションサービスを使用することができるようになります。
具体的には、以下のレイヤーや機能が使用できます。
- レイヤー
- フィーチャ レイヤー (GeoJSON)
- 3D オブジェクト シーン レイヤー
- 3D メッシュ シーン レイヤー
- 2D イメージ タイル レイヤー
- 標高レイヤー
- 機能
- フィーチャのクエリ
- データの可視化
- 住所検索
- ルート検索等...
代表的なサービスや機能の詳細を以下に説明します。
サービス | 機能 | 内容 |
---|---|---|
シーン | 背景地図 | 衛星画像や陰影を含むイメージ タイル サービス、標高サービスを表示します。 |
データサービス | フィーチャ サービス | フィーチャは、ジオメトリと属性情報を含んだ地理データです。フィーチャ サービスからクエリして GeoJSON 形式でフィーチャを返して表示します。 |
3D オブジェクト | 3D オブジェクトを表示します。3D オブジェクトは、建物などのエンティティのモデリングに使用される I3S データの一種です。I3S は、OGC の Community Standard として承認されています。 | |
3D メッシュ | 3D メッシュを表示します。3D メッシュは、エリア全体をモデル化するために使用されるI3Sデータの一種です。通常、航空画像によって作成される統合メッシュは、ある範囲内のすべてを含む単一の連続サーフェスで構成されます。I3S は、OGC の Community Standard として承認されています。 | |
イメージ タイルサービス | イメージ タイルは、イメージ タイルサービスに保存されるタイルデータの一種です。通常、航空写真などの画像を表示しますが、他のデータを表示するために使用することもできます。イメージ タイル サービスは、ArcGIS でホストされているフィーチャ サービスをパブリッシュすることで作成できます。 | |
ジオコーディングサービス | 住所検索 | 検索ボックスから場所や住所を検索します。 |
リバースジオコーディング | 緯度/経度から場所や住所を検索します。 | |
場所の検索 | コーヒーショップ、ガソリンスタンド、レストランなどの場所を検索します。 | |
ルート検索 | ルート検索とルート案内 | 出発地から目的地までのルートとルート案内を検索します。 |
到達圏(サービスエリア)の検索 | ある場所から特定の運転時間で到達できるエリアを検索します。 | |
POI (Point of Interest)の検索 | 近くの場所と詳細の検索 | キーワード検索で場所周辺の場所を見つけ、詳細な場所情報を取得します。 |
矩形範囲の場所を検索 | テキストベースの検索を実行して、バウンディングボックス内の場所を検索します。 |
CesiumJS での使用方法については、サンプルコードも合わせてチュートリアルにございますのでご確認ください。
CesiumJS で 3Dオブジェクトを表示
日本のデータを使用して表示してみたいと思います。今回は、データサービスとして 3D オブジェクトを表示しました。3D オブジェクトのデータとして、 Living Atlas に公開されている「Project PLATEAU」の東京都23区・八王子市南大沢 3D都市モデル(Project PLATEAU)を使用しました。このデータは無料で利用することができます。ただし、ご利用にあたっては、国土交通省ホームページ PLATEAU Policy に定められた利用条件を必ず遵守する必要があります。
3D オブジェクトの表示は、以下のチュートリアルを参考としました。ほぼ、同じコードで実装できます。
実装したサンプルのソースです。
<html> <head> <meta charset="utf-8" /> <title>CesiumJS: Display a 3D object layer popup</title> <!-- Include the CesiumJS JavaScript and CSS files --> <script src="https://cesium.com/downloads/cesiumjs/releases/1.110/Build/Cesium/Cesium.js"></script> <link href="https://cesium.com/downloads/cesiumjs/releases/1.110/Build/Cesium/Widgets/widgets.css" rel="stylesheet"> <style> html, body { margin: 0px; padding: 0px; height: 100%; } #cesiumContainer { height: 100%; } </style> </head> <body> <div id="cesiumContainer"></div> <script type="module"> const apiKey = ""; Cesium.ArcGisMapService.defaultAccessToken = apiKey; const cesiumAccessToken = ''; Cesium.Ion.defaultAccessToken = cesiumAccessToken; const arcGisImagery = Cesium.ArcGisMapServerImageryProvider.fromBasemapType(Cesium.ArcGisBaseMapType.SATELLITE, { enablePickFeatures:false }); const viewer = new Cesium.Viewer("cesiumContainer", { baseLayer: Cesium.ImageryLayer.fromProviderAsync(arcGisImagery), terrain: Cesium.Terrain.fromWorldTerrain(), timeline: false, animation: false, geocoder:false }); viewer.camera.setView({ destination: Cesium.Cartesian3.fromDegrees(139.767125,35.671236,400), orientation: { heading: Cesium.Math.toRadians(60), pitch: Cesium.Math.toRadians(-15.0), } }); const geoidService = await Cesium.ArcGISTiledElevationTerrainProvider.fromUrl("https://tiles.arcgis.com/tiles/z2tnIkrLQ2BRzr6P/arcgis/rest/services/EGM2008/ImageServer"); const i3sLayer = "https://tiles.arcgis.com/tiles/wlVTGRSYTzAbjjiC/arcgis/rest/services/13100_13201_Tokyo-23ku_Minamiosawa_Building/SceneServer"; const i3sProvider = await Cesium.I3SDataProvider.fromUrl(i3sLayer, { geoidTiledTerrainProvider: geoidService, token: apiKey }) viewer.scene.primitives.add(i3sProvider); // An entity object which will hold info about the currently selected feature for infobox display const selectedEntity = new Cesium.Entity(); // Show metadata in the InfoBox. viewer.screenSpaceEventHandler.setInputAction(function onLeftClick(movement) { // Pick a new feature const pickedFeature = viewer.scene.pick(movement.position); if (!Cesium.defined(pickedFeature)) { return; } const pickedPosition = viewer.scene.pickPosition(movement.position); if ( Cesium.defined(pickedFeature.content) && Cesium.defined(pickedFeature.content.tile.i3sNode) ) { const i3sNode = pickedFeature.content.tile.i3sNode; i3sNode.loadFields().then(function () { const geometry = i3sNode.geometryData[0]; if (pickedPosition) { const location = geometry.getClosestPointIndexOnTriangle( pickedPosition.x, pickedPosition.y, pickedPosition.z ); let description = "No attributes"; let name; if (location.index !== -1 && geometry.customAttributes.featureIndex) { const featureIndex = geometry.customAttributes.featureIndex[location.index]; if (Object.keys(i3sNode.fields).length > 0) { description = '<table class="cesium-infoBox-defaultTable"><tbody>'; for (const fieldName in i3sNode.fields) { if (i3sNode.fields.hasOwnProperty(fieldName)) { const field = i3sNode.fields[fieldName]; description += `<tr><th>${field.name}</th><td>`; description += `${field.values[featureIndex]}</td></tr>`; console.log( `${field.name}: ${field.values[featureIndex]}` ); if ( !Cesium.defined(name) && isNameProperty(field.name) ) { name = field.values[featureIndex]; } } } description += `</tbody></table>`; } } if (!Cesium.defined(name)) { name = "unknown"; } selectedEntity.name = name; selectedEntity.description = description; viewer.selectedEntity = selectedEntity; } }); } }, Cesium.ScreenSpaceEventType.LEFT_CLICK); function isNameProperty(propertyName) { const name = propertyName.toLowerCase(); if ( name.localeCompare("name") === 0 || name.localeCompare("objname") === 0 ) { return true; } return false; } </script> </body> </html>
実装した3Dオブジェクトを表示した Cesium アプリやソースコードは、GitHub でも公開していますので、興味のある方は触ってみてください。
最後に
Cesium が ArcGIS のサービスをサポートしたことで、Cesium で実現できる幅がかなり広がったと思われます。まだ、I3S のサービスを完全にサポートはされていませんが、今後に期待したいところです。また、新しい機能がサポートされたら本ブログでも紹介していきたいと思います。