この記事は、 FOSS4G Advent Calendar 2023 の4日目の内容になります。(が、遅れてしまって申し訳ありません...)
はじめに
先週の2023/11/29(水)にFOSS4G Asia 2023で、今年の夏頃から取り組んでいるGEOS-WASMの話をオンラインで発表してきましたので、スライドの概要と補足説明、イベントの感想などを記載しようと思います。
スライドの概要
アジェンダ
冒頭の以下の項目が、プレゼンで最低限紹介したかった箇所、
- What is GEOS ?
- What is GEOS-WASM ?
- GEOS-WASM using library/app
続く以下の項目が、背景、経緯と特徴、
- Background
- How the project started
- Characteristics of GEOS-WASM
最後の以下の項目が、最近の話題とWebAssemblyの将来の可能性、謝辞となります。
- Recent related topics
- Future possibilities of WebAssembly
- Ackowledgements
GEOSって何?
FOSS4G界隈の方はご存知だと思いますが、初見の方もいるかもしれなかったので、GEOSの簡単な説明をしました。
- Webサイト: https://libgeos.org/
- 計算幾何学のためのC/C++ライブラリ
- OGCのシンプルフィーチャのジオメトリモデルと空間関数を実装
- PostGIS、QGIS、GDAL、Shapelyなどのバックエンドで利用されている
GEOS-WASMって何?
このプレゼンのメインテーマ、GEOS-WASM の紹介になります。
- Webサイト: https://chrispahm.github.io/geos-wasm/
- GEOSライブラリのWebAssemblyビルドで、ブラウザやNode.js環境で利用可能
- GEOSの低水準のC-APIを、抽象化なしでそのままJavaScriptに公開
- 高レベルのライブラリのビルディングブロックや、特定のユースケースでの利用を意図
Webサイトで左側メニューの Examples から Buffer を選択すると、実際に動作するサンプルが見れます。
インストールは簡単で、Node.jsなら
npm install geos-wasm
ブラウザなら
<script type="module">
import initGeosJs from 'https://cdn.skypack.dev/geos-wasm';
</script>
ただし、利用の際には、初期化されたGEOSオブジェクトを取得後、GEOSのC-APIと同様な呼び出しが必要になります。
import initGeosJs from 'geos-wasm'
// initGeosJsはGEOSオブジェクトへのPromiseを返す
const geos = await initGeosJs()
// GEOSオブジェクトを利用してGEOS関数を呼び出す
// 例: ポリゴンの面積を取得する
// WKTリーダを作成
const reader = geos.GEOSWKTReader_create()
const wkt = 'POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))'
// WKT文字列を読み込んでGEOSジオメトリのポインタを取得
const geomPtr = geos.GEOSWKTReader_read(reader, wkt)
// 面積が書き込まれるポインター領域を作成
const areaPtr = geos.Module._malloc(8)
// ジオメトリの面積を計算
geos.GEOSArea(geomPtr, areaPtr)
// 面積をポインタからJavaScriptの数値に変換
const area = geos.Module.getValue(areaPtr, 'double')
console.log(area) // area = 1
// WKTリーダ、ジオメトリ、ポインタを解放
geos.GEOSWKTReader_destroy(reader)
geos.GEOSGeom_destroy(geomPtr)
geos.GEOSFree(areaPtr)
GEOS-WASMを使ったライブラリ・アプリ
GEOS-WASMを使ったライブラリ・アプリの1つ目は @neocarto さん開発の geotoolbox
になります。
- GitHub: neocarto/geotoolbox
- デモサイト: https://observablehq.com/@neocartocnrs/hello-geotoolbox
- 様々な動作可能なサンプルが含まれている
- GEOS-WASMはv2.0からいくつかの関数(
Buffer
,Clip
,Densify
とUnion
)で利用されている
GEOS-WASMを使ったライブラリ・アプリの2つ目は拙作の GEOS WASM Tester
になります。
- GitHub: sanak/geos-wasm-tester
- デモサイト: https://sanak.github.io/geos-wasm-tester/
- デスクトップ環境で動作する JTS Test Builder を参考に
- GEOS-WASMはgit submoduleとして利用
どちらもデモサイトから動作を確認できます。
背景 - 2次元の地理空間解析ライブラリ
背景の1つ目として、2次元の地理空間解析ライブラリを開発開始年順とバインディング、利用アプリ・ライブラリ・DBと合わせて記載しています。
GEOSはJTS Topology Suiteのバインディングですが、最も利用されているライブラリと言えると思います。
また、2010年頃までは、Java・C++などの枯れた言語による実装が主でしたが、2010年以降は、JavaScriptやRustなどの新しい言語での実装・バインディングが進んでいるように思います。
太字の箇所は以降のスライドで名前が出てきます。
背景 - WebAssembly
WebAssemblyの概要と経緯について簡単に記載しています。
全般に、一つ前のスライドの2次元の地理空間解析ライブラリが出揃った後(2015年以降)にWebAssemblyが登場したイメージです。
FOSS4GイベントでのWebAssembly関連の発表をまとめています。
最初のPirminさんの発表と、最後のMichaelさんの発表(太字箇所)は、スライド資料へのリンクになってますので、WebAssemblyに興味のある方は是非一読頂けると良いと思います。
Geo系でWebAssemblyに対応したオープンソースをリストアップしています。
既にEmscripten (C/C++)、Rustを利用した様々なプロジェクトがありますが、Emscripten (C/C++)ベースのプロジェクトは既存ライブラリをWebAssemblyにポーティングしたもの、Rustベースのプロジェクトは新しい実装になると思います。
太字の箇所は以降のスライドで名前が出てきます。
プロジェクトが始まった経緯
プロジェクトのアイデア自体は@tmcwさんのブレインダンプ(https://github.com/tmcw/geos-wasm) から始まりました。
- TurfはWeb開発で最も快適
- ただし、ロバストネス(堅牢性)には、JTSからのポートであるJSTSのような、他の安定した実装が必要
- GEOSと同じ機能・バグが得られることが望ましい
- GEOS/WASMのアイデアを提起
@chrispahmさんがリポジトリを見つけ、概念実証(PoC)バージョンをGEOSとEmscriptenを用いて実装し、Issue(geos-wasm - Is it worth the effort? · Issue #2 · tmcw/geos-wasm) を起票
- 完全に動作する
buffer
デモと極めて詳細なドキュメント - コンパイルプロセスは bugra9/gdal3.js を参考
- シリアライゼーションパフォーマンスの問題について記載
@kylebarronさんがブログ(Thoughts on GEOS in WebAssembly)を投稿し、以下に言及
- Apache Parquetバインディングとの類似性
- WebAssemblyのパフォーマンスの概念の詳細
- シリアライゼーションパフォーマンスの問題の詳細
- GeoRustの将来の可能性
- 後に geoarrow/geoarrow-rs プロジェクトを開始し、
- Observableで記事(Prototyping GeoRust + GeoArrow in WebAssembly / Kyle Barron | Observable)を投稿
私はX(Twitter)経由で @kylebarron さんのブログ記事を見つけ、このプロジェクトに興奮を覚えました。なぜなら、
- 過去、Windows+IE (ActiveX)環境向けに GEOS COM Wrapper の開発経験があったが、動作可能な環境を広げたいと思っていた。
- 最近になって node-geos へのコントリビューション(貢献)を試みたが、Node (v8)のC++APIが私には難しかったのと、NodeはサポートできてもWebブラウザはサポートできないので諦めていた。
- 上記から、このプロジェクトへのコントリビューションを開始
最初の課題はシリアライゼーションパフォーマンス問題の解消でした。
Preferred data transfer between JS and WASM context → shouldn't it be WKB? · Issue #4 · chrispahm/geos-wasm
- JavaScriptとGEOS-WASM間でジオメトリを渡す時に、テキストベースのフォーマット(WKTや文字列化されたGeoJSON)だと遅い問題
- WKBフォーマットを @syncpoint/wkx パッケージと合わせて利用することで、パフォーマンスを改善
- (後に、PR(プルリクエスト)#19で別のヘルパーメソッドも追加されています。)
2つ目の課題はAPI設計でした。
API preferences? · Issue #5 · chrispahm/geos-wasm
- 元々は、Turf.jsと互換性のある
buffer
のような高水準の関数と組み合わせる設計となっていた。 - 個人的には、ShapelyのようなAPIが好ましいと思っていたが、JavaScriptのガベージコレクションでのメモリ解放が難しそうだった...
- 議論の結果、低水準のGEOS C-API関数のみ提供する形に。
GEOS-WASMの特徴
- GEOSのバインディングの中では、EmscriptenによりC/C++コードをコンパイルする点がユニーク
- GEOS C/C++ライブラリへのダイナミックリンクを利用する、他のShapelyなどのGEOSバインディングとは異なる
- JTSのバインディング(JSTS、dart_jts、NTSなど)は、Javaのコードを各言語にポートしているので、GEOS-WASMはそちらに少し似ている。
- GEOSのパッチバージョンアップ時は、WebAssemblyへのフルコンパイルが必要
- ライセンスはGEOSと同様、LGPL 2.1
- フルコンパイルのため、npmパッケージサイズはTurf.jsより大きく、JSTSと同じレベル
- geos-wasm: 2.98 MB
- jsts: 3.42 MB
- @turf/turf: 658 kB
最近の関連トピック
- The State of WebAssembly 2023
-
WebAssembly Garbage Collection (WasmGC) enabled by default in Chrome
- 関連したFlutterのニュース: Support for WebAssembly (Wasm) | Flutter
FOSS4GでのWebAssembly関連では
-
qgis/qgis-js (Demo)
- QGIS(のコア機能)がEmscriptenビルドでWebブラウザ上で動作するというもの
- SotM EU 2023 ワークショップ: Ungap the Map: designing moonshot cycling networks by Dustin Carlino
- カスタムのコスト関数を定義可能なクライアント側の経路探索 (リンク)
WebAssemblyの将来の可能性
- オープンな3D建物データとクライアン側経路探索による日陰を通る経路探索など
- Rustの既存のリソース (dabreegster/route_snapper) を利用
- もしくは、 pgRouting のコアの C/C++ 箇所をEmscriptenでWebAssemblyにエクスポートするなど?
- 言語間の相互運用性の向上
- Michael SchmukiさんのFOSS4G 2022のWebAssembly4G: Where we are, and where we're headingのスライドの p.20 p.37 で言及されていた Component Model
謝辞
- GEOS-WASMの著者とコントリビュータ(貢献者)へ
- 彼らのアウトプット・努力がなければ、プロジェクトは始まらなかったので
- GEOSコミュニティへ
- 20年を超える堅牢なジオメトリ演算機能の提供・維持を感謝して
- そしてスライド内で言及した他の全てのプロジェクトと方々に
イベントの感想
事前準備
Call for Presentationが8月末に終わって、イベントまで時間は十分あったはずなのに、スライドを書き始めたのが発表の1週間前で、かつ、アジェンダ部分がなかなか整理できずに焦りばかりつのってしまう状況でした。
会社で希望者が利用できる英語のレッスン(基本は週1で30分)を再開し、イベントまで集中的に予約して、アジェンダの部分もアドバイス頂いたことで、何とかスライド作成・発表までこぎつけました...
当日発表
オンライントークは日本からは私だけで、Zoomで司会をされていた方は中国科学院大学のSongさんという方でした。
前後がコミュニティ・学術系の発表で、少し気後れ・緊張しましたが、所々英語発音をかみながらも、何とか無事済ませられました。
20分の発表で18分ほどで終わってしまい、少し時間が余ったので司会のSongさんから、「Extensionのように動作するのか?」との質問があったんですが、想定環境が良く分からずでうまく回答できず、しどろもどろになってしまいました...
他にも、スライド資料でリンクを多用していたこともあって、ZoomのQAでリンクが分からないという質問がありましたので、発表終了後に一旦Googleスライドのリンクを共有しましたが、今後発表の際は、スライド資料自体のURLをQRコードなどで提供するようにします...。
ZoomのQAでは、プロジェクト参加の動機に関する質問もあり、「GEOSがWebブラウザ上で動作すること自体が面白いと思ったから」のように回答したと思います。
オンライン視聴
1日目(11/29)はプレゼン発表の後、力尽きてしまったので、2日目(11/30)の午後からYouTubeでライブ配信のメインホールの動画を視聴していました。
https://www.youtube.com/watch?v=WCV90Fpt4Mg&t=14440s
3日目(12/1)のクロージングセレモニーも印象的でしたので、頭出ししたリンクを上げておきます。
https://www.youtube.com/watch?v=V1EKvxzhSbI&t=21029s
おわりに
以上、少し冗長・単調になったかもしれませんが、GEOS-WASMのスライドの概要とイベントの感想を記載しました。
個人的な反省点としては、普段からアウトプットをしていないと、いざという時に言葉が出てこないことがあるように思いましたので、今後は色々とアウトプットを心がけていきたいと思います。
最後に、今年も残りわずかとなりましたが、今後とも、よろしくお願いいたします!