godai-kaihatsu / gondwana

https://gondwana.godai.co.jp/
2 stars 0 forks source link

GeoObject システムに GeoJSON をロードする API が欲しい / 実装ステップ1: Point へ対応 #23

Closed usagi closed 6 years ago

usagi commented 6 years ago

spec.: https://tools.ietf.org/html/rfc7946

usagi commented 6 years ago

GSI sample:

サンプルURLの場所は羊蹄山の山頂から北東側のタイル。

名称 key z sample-url
単写真 pp 14 https://cyberjapandata.gsi.go.jp/xyz/pp/14/14600/6029.geojson
基準点 cp [ 7 .. 12 ] https://cyberjapandata.gsi.go.jp/xyz/cp/12/3650/1507.geojson
指定緊急避難場所(洪水) skhb01 10 https://cyberjapandata.gsi.go.jp/xyz/skhb01/10/912/376.geojson
指定緊急避難場所(崖崩れ、土石流及び地滑り) skhb02 10 https://cyberjapandata.gsi.go.jp/xyz/skhb02/10/912/376.geojson
指定緊急避難場所(高潮) skhb03 10 https://cyberjapandata.gsi.go.jp/xyz/skhb03/10/912/376.geojson
指定緊急避難場所(地震) skhb04 10 https://cyberjapandata.gsi.go.jp/xyz/skhb04/10/912/376.geojson
指定緊急避難場所(津波) skhb05 10 https://cyberjapandata.gsi.go.jp/xyz/skhb05/10/912/376.geojson
指定緊急避難場所(大規模な火事) skhb06 10 https://cyberjapandata.gsi.go.jp/xyz/skhb06/10/912/376.geojson
指定緊急避難場所(内水氾濫) skhb07 10 https://cyberjapandata.gsi.go.jp/xyz/skhb07/10/912/376.geojson
指定緊急避難場所(火山現象) skhb08 10 https://cyberjapandata.gsi.go.jp/xyz/skhb08/10/912/376.geojson
usagi commented 6 years ago
  1. type -> FeatureCollection, Feature の再帰構造に対応
  2. geometry -> Point, LineString, Polygon, MultiPoint, MultiLineString, MultiPolygon, GeometryCollection に対応
    1. step-1 Point に対応
    2. step-2 LineString に対応
    3. step-3 Polygon に対応
    4. step-4 multi- 系に対応

G4 の GeoObject システムは Point には現在の実装で対応できるが、 LineString を表現する実装、 Polygon を三角形に分割する実装と内側に穴を開ける実装、複数の GeoObject をグループ化する実装(タグ機能でも実現は可能だが、異なる GeoObject からなる群ではなく、同じ GeoObject からなる群を扱うためにグループ機能を追加した方がスマート)、がそれぞれ無いので、この実装には少しコストがかかる。そこで、本チケットでは Point のみ対応し、他のジオメトリーデータは段階的に別チケットとして実装を進める。

usagi commented 6 years ago

Properties は G4 GeoObject の文字列-文字列プロパティーシステムへ入れる。

usagi commented 6 years ago

できるだけ低レベルの API を先ずは用意する方針のなか、 GeoJSON から GeoObject 群を生成する扱いの善い API 仕様を検討している。

現在の案:

/// @param geo_json GeoJSON 文字列
/// @return 生成された GeoObject の id 群
[ <number:id> ] GeoObject.NewObjectFromGeoJSON( string geo_json );

オプショナルなパラメーターとして [<string>] tags を入れるなどしようかとも検討したが、できるだけシンプルな方がユーザーが扱いやすかろうと考え、そうした必要があれば return から別途 AddTag などして貰うのが善いだろうと判断している。

usagi commented 6 years ago

標準で Local Address Mode で生成するか、標準で Global Address Mode で生成するか、選択肢をパラメーター化するか、 API メソッドレベルで分けて用意するか検討。結果、標準で Global Address Mode で生成する事にした。

理由

Point の場合は Local Address モードで生成し、任意のメッシュやビルボード化を行う用途が多いと考えたが、 LineString や Polygon の場合は Global Address で生成した方が素直であり、 Point とそれ以外で Local / Global が異なる状態で生成される事はユーザーに複雑な生成ルールを学ばせる事になりバグの原因にもなるだろうと考え、結果、望むならば Local / Global 変換 API を別途叩いて貰えばよい、あるいはユーザーニーズが多くあれば将来的に高レベル API で別途対応するのが善いと判断した。

usagi commented 6 years ago

GeoObject に DefaultRendering 機能を追加する事にした。この機能はメッシュとして有効な情報を設定されていないが、点、または接続した線分の集合としては有効な頂点群が与えられている場合に、簡易的な点または線の描画を行う機能で、ユーザーが GeoObject にメッシュやマテリアルを未設定の状態でも点と接続した線分の集合については簡易的に表示するお手軽機能である。

具体的には、 Global Address Mode かつ Indices 数が 0Vertices 数が 1 つ以上 与えられており、 bool DefaultRendering フラグが true の場合に動作し、 Vertices 数が 1 の場合は点、 1 より大きな場合は連続した接続する線分として簡易描画する。

usagi commented 6 years ago

また、 G3 でも地物を実寸で実装した直後からユーザーから「カメラの距離によらず画面上で一定の大きさを保つよう自動的にスケーリングされる機能が欲しい」と要望があった事を踏まえ、 GeoObject に bool FixedScaling フラグ、 float Scaling を追加する事とした。

usagi commented 6 years ago

追加 APIs:

void GeoObject.SetDefaultRendering( <number> id, <bool> enabling );
bool GeoObject.IsDefaultRenderingEnabled( <number> id ) const;

void GeoObject.SetFixedScaling( <number> id, <bool> enabling );
bool GeoObject.IsFixedScalingEnabled( <number> id ) const;

void GeoObject.SetScaling( <number> id, <float> scaling );
float GeoObject.GetScaling( <number> id ) const;
usagi commented 6 years ago

DefaultRendering の場合で、 GeoObject の Propertiesname キーが存在する場合はその値を表示する実装を加えてみるとしよう。

usagi commented 6 years ago

Propertiesname がある場合の表示例:

image

もっと視認性良く、などはさしあたりの実装をしたあとで対応する事にする。

usagi commented 6 years ago

name プロパティーの表示機能は DefaultRendering の Point ( LineString ) 以外の GeoObject 全般でも少なくとも機能実装がまだ未熟な現時点ではとても有用と思うので、 GeoObject に新たに bool ShowName プロパティーを追加して制御可能にする事にした。

もっと見やすく、あるいは tags もクラウドで表示したい、などのニーズは予想されるけれど、開発リソースの都合、そうした拡張はおいおいニーズとリソースを考慮して、という事にする。

usagi commented 6 years ago

地図画像やワイヤーフレーム、空模様によっては実用性がかなり低く感じられる程度まで見難くなってしまうようだ。

image

このため、視認性を向上する工夫も一緒に実装したい。いくらかの簡単なアイデアを試みて、良好そうならば採用する。

usagi commented 6 years ago

さしあたり、デバッグ用の機能を用いて簡易的に実装した段階ということもあり、その機能回りでは視認性を向上する工夫を低コストに実装するのは難しかった。視認性の向上は本チケットからは分離して後で行う事とし、本チケットの本質である GeoJSON の Point へのデータ的な対応を優先する事とした。残念。

usagi commented 6 years ago

GeoJSON の座標データは GSI の現実のサンプルでも [ <float:lon>, <float:lat> ] 形式で定義されている。 G4 GeoObject では altitude に NaN 値を入れ、 altitude が NaN の座標値は G4 の空間内では Terrain の altitude を読み出して採用する仕様が便利だろうと考えた。この仕様は G3 の地物システムでも同様で、使い勝手に問題は報告されなかった。 G4 の実装をすすめる現時点でも特に問題となる事は無いか、十分に回避する実装を施せるであろうと推量するので、 altitude = NaN の場合の挙動は altitude = Terrain としてひとまず実装し、 CBT ユーザーからのフィードバック等あれば徐々に改善していくこととした。

usagi commented 6 years ago

cat new_from_geojson.json:

{ "jsonrpc": "2.0"
, "id": null
, "method": "GeoObject.NewFromGeoJSON"
, "params":
  { "GeoJSON":
    { "type": "Feature"
    , "geometry":
      { "type": "Point"
      , "coordinates": [ 140.811389, 42.826667 ]
      }
    , "properties":
      { "name": "羊蹄山"
      }
    }
  }
}

curl -Ss -i http://127.0.0.1:50080/api/json-rpc-2.0/ -X POST -d @new_from_geojson.json:

HTTP/1.1 200 OK
Content-Length: 91
Content-Type: application/json

{
        "jsonrpc": "2.0",
        "id": null,
        "result":
        {
                "ids": [ 0 ],
                "errors": []
        }
}

image

GeoJSON から G4 の GeoObject を生成する NewFromGeoJSON API を本チケットの範囲である Point への対応と暫定的な点、名称の表示の対応で完了した。 altitude = NaN における自動的な地形システムの標高採用も絵の通り意図したとおりに動作している。

usagi commented 6 years ago

視認性について検討した際に、次の仕様を盛り込んでおいた。

curl -Ss -i http://127.0.0.1:50080/api/json-rpc-2.0/ -X POST --data '{ "jsonrpc": "2.0", "id": null, "method": "GeoObject.SetVertexColor", "params": { "id": 0, "vertexcolors": [ 1,1,1,1, 0,0,0,1 ] } }'

image

usagi commented 6 years ago

GeoJSON にエラーがあった場合のレポートも何個目の要素にどんなエラーがあったのか通知されるように実装した。

HTTP/1.1 200 OK
Content-Length: 160
Content-Type: application/json

{
        "jsonrpc": "2.0",
        "id": null,
        "result":
        {
                "ids": [],
                "errors": [
                        "Feature[0]: count of `geometry` are must be 2 in `Point` type"
                ]
        }
}
usagi commented 6 years ago

image

cat new_from_geojson_b.json:

{ "jsonrpc": "2.0"
, "id": null
, "method": "GeoObject.NewFromGeoJSON"
, "params":
  { "GeoJSON":
    {"type":"FeatureCollection","features":[
    {"type":"Feature","geometry":{"type":"Point","coordinates":[140.73248811749,43.039277047092]},"properties":{"name":"銀山小学校グランド","address":"北海道仁木町銀山2丁目446番地","disaster1":1,"disaster4":1,"disaster6":1}},
    {"type":"Feature","geometry":{"type":"Point","coordinates":[140.72563244118,43.042264096845]},"properties":{"name":"銀山中学校グランド","address":"北海道仁木町銀山2丁目113番地","disaster1":1,"disaster2":1,"disaster4":1,"disaster6":1}},
    {"type":"Feature","geometry":{"type":"Point","coordinates":[140.76213107485,43.03786777423]},"properties":{"name":"長沢会館前","address":"北海道仁木町長沢南464番地2","disaster1":1,"disaster2":1,"disaster4":1,"disaster6":1}},
    {"type":"Feature","geometry":{"type":"Point","coordinates":[140.78652844805,43.037552143532]},"properties":{"name":"尾根内会館前","address":"北海道仁木町尾根内221番地4","disaster1":1,"disaster2":1,"disaster4":1,"disaster6":1}},
    {"type":"Feature","geometry":{"type":"Point","coordinates":[140.83610217177,43.049954911592]},"properties":{"name":"赤井川村立都小学校校舎","address":"北海道余市郡赤井川村字都113","disaster2":1,"disaster4":1,"disaster6":1,"disaster7":1}},
    {"type":"Feature","geometry":{"type":"Point","coordinates":[140.83558718765,43.049954911592]},"properties":{"name":"赤井川村立都小学校体育館","address":"北海道余市郡赤井川村字都113","disaster2":1,"disaster4":1,"disaster6":1,"disaster7":1}},
    {"type":"Feature","geometry":{"type":"Point","coordinates":[140.83681027496,43.050299879043]},"properties":{"name":"赤井川村立都小学校グラウンド","address":"北海道余市郡赤井川村字都113","disaster2":1,"disaster4":1,"disaster6":1,"disaster7":1}},
    {"type":"Feature","geometry":{"type":"Point","coordinates":[140.83290467531,43.051110200296]},"properties":{"name":"赤井川村都住民センター","address":"北海道余市郡赤井川村字都127-15","disaster2":1,"disaster4":1,"disaster6":1,"disaster7":1}},
    {"type":"Feature","geometry":{"type":"Point","coordinates":[140.84440948051,43.051395167595]},"properties":{"name":"村の駅あかいがわ","address":"北海道余市郡赤井川村字都190-16","disaster1":1,"disaster2":1,"disaster4":1,"disaster6":1,"disaster7":1}}
    ]}
  }
}

curl -Ss -i http://127.0.0.1:50080/api/json-rpc-2.0/ -X POST -d @new_from_geojson_b.json:

HTTP/1.1 200 OK
Content-Length: 115
Content-Type: application/json

{
        "jsonrpc": "2.0",
        "id": null,
        "result":
        {
                "ids": [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ],
                "errors": []
        }
}

image

実際に GSI が提供している GeoJSON タイル ( サンプルとして「指定緊急避難場所(地震)」より https://cyberjapandata.gsi.go.jp/xyz/skhb04/10/912/376.geojson を使用 ) の .geojson データも意図通り G4 地物システムへ API で読み込める事を確認できた。

usagi commented 6 years ago

以上までは実装試験の目的のため LOD=10 に固定していた。 wiki やリリースノート用に LOD=14 の綺麗なスクリーンショットを撮影した:

image

image