Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Go で緯度経度から円を「うまい・やすい・はやい」で描く方法

Avatar for m.nishida m.nishida
September 30, 2026

Go で緯度経度から円を「うまい・やすい・はやい」で描く方法

https://connpass.com/event/404193/
2026/09/30 Go Bash vol.3登壇資料です。

Avatar for m.nishida

m.nishida

September 30, 2026

More Decks by m.nishida

Other Decks in Technology

Transcript

  1. 自己紹介 経歴 • 早稲田大学社会科学部卒業後、客先常駐で金融、物流、製造業 Resilire Inc. プロダクトエンジニア 西田 暢 Mitsuru

    Nishida (EDI)、求人サイト、グルメサイトなどの現場を toB / toC・言 語問わず幅広く経験 • 前職では建築系 SaaS の ANDPAD に入社し、新規プロダクトの 立ち上げを経験。テックリードを務める • 2024 年 12 月から Resilire にプロダクトエンジニアとして入社 し、現在に至る X(Twitter):bbbar326 GitHub:bbbar326 趣味 家族キャンプ。バイクは安全を第一に一旦お休み中。夢は自宅にバ イクガレージを作ること
  2. 要件: 災害発生地点を中心に5つの距離で円を描き、5つの円それぞれに含まれる拠点を抽出 30km 1. 地図に円を描く リスクが発生した緯度経度を中心に、半径 1 / 3 /

    5 / 10 / 30km の円を描く 10km 5km 2. 円の中の拠点を一覧にする 3km 1km 円の中の拠点一覧と、影響拠点が紐づくリスクイベントの一覧を出すので、地図を見なくても DB から 引ける形が要る 境界上の拠点 リスク地点 3. 地図と一覧の答えをそろえる 円の縁にある拠点を「影響あり / なし」のどちらかに安定して振り分ける。円の縁ぎりぎりの拠点が 「地図では中なのに一覧に出ない」ということを起こさないようにする。 そこで、円を「タイルの集まり」= QuadKey で表す方針にした 縁はタイル 1 枚分ギザギザになるが、同じタイル集合から円も描き、拠点も引くので、答えが食い違わ ない
  3. QuadKey:世界を 4 分割し続けた番地 0 1 10 11 130 131 12

    2 13 132 133 3 zoom 1:世界を 4 分割 zoom 2:その中をまた 4 分割 zoom 3:桁数 = 分割回数 1 13 133
  4. 全体の流れ 3 つの工程で、緯度経度から地図のポリゴンまで 入力 緯度経度と 半径 ① buckhx/tiles ② 自社実装

    ③ polygol 1 点 → 1 タイル 円 → QuadKey の集合 集合 → 外周のポリゴン 投影・格子・番地 zoom・マス選び・畳み込み 長方形化・結合・GeoJSON ① 1 点を 1 タイルにする 緯度経度 1 つを、格子のマスと その番地 QuadKey に変える 出力 地図に描く ② 円を QuadKey の 集まりにする ③ 集まりを 外周のポリゴンにする 円を覆うタイルを選び、4 兄弟 が揃った親に畳む。内側は大き く、外縁は細かく残る タイルの内部の仕切りを消し て、外周だけの GeoJSON にす る
  5. ① 1 点 → 1 タイル 地球を 0〜1 の正方形に潰す(メルカトル投影) 0

    経度は等間隔 u = (経度 + 180) ÷ 360 経度 135 → 0.875 u = 0.875 v = 0.396 緯度はメルカトルで引き伸ばす v = 0.5 − ln((1 + sin 緯度) ÷ (1 − sin 緯度)) ÷ 4π 緯度 35 → 0.396(上が北。0.5 が赤道) 1 経度 −180 → 180 緯度 85(上)→ −85(下) 1 緯度は ±85.05 度で切る。メルカトル投影は極を描けないため、それより 外は端に張り付く。
  6. ① 1 点 → 1 タイル 何列目・何行目かを決める zoom 列数 =

    2^zoom X(列) Y(行) 1 2 1 0 2 4 3 1 3 8 7 3 4 16 14 6 23 8,388,608 7,340,032 3,322,709 0 1 2 3 4 5 6 7 0 1 2 3 4 5 • zoom が 1 上がるごとに 4 分割されるので、列も行も倍になる(列数 = 2^zoom) • X = u × 列数、Y = v × 行数 を切り捨てる(u, v は前のスライドの値。どちらも 0 始まり) • zoom 3 は 8 列 8 行:X = 0.875 × 8 = 7.0 → 7、Y = 0.396 × 8 = 3.2 → 3 ここで分かるのは X = 7、Y = 3 の 2 つの整数まで。これを番地の文字列にするのは次 のスライド。 6 7 zoom 3:8 × 8 枚。上が列番号 X、右が行番号 Y X = 7 の列と Y = 3 の行が交わるマスが答え
  7. ① 1 点 → 1 タイル マスを QuadKey に変換する:4 区画のどこかを

    zoom ごとに 1 桁 ずつ 0 0 1 2 3 2 1 3 0 1 2 3 zoom 1:右上の区画 zoom 2:その中の右下 zoom 3:さらに右下 1 3 3 QuadKey = 133
  8. ② 自社実装 GetQuadkeysForCircle 円 → QuadKey の集まり:3 ステップ 入力 緯度経度と

    半径 ① buckhx/tiles ② 自社実装 ③ polygol 1 点 → 1 タイル 円 → QuadKey の集合 集合 → 外周のポリゴン 投影・格子・番地 zoom・マス選び・畳み込み 長方形化・結合・GeoJSON 出力 地図に描く Step 1 Step 2 Step 3 外のふちの細かさを決める 一番細かい zoom で円を作る 4 兄弟が揃った親に畳む 円に見えるまで細かくする。それ以上は枚数 が増えるだけ 1 マスずつ調べて、円にかかるタイルを選ぶ 内側は粗く、外のふちは細かく残る
  9. ② 円 → QuadKey の集合 外のふちの細かさを決める:円に見えるまで細かくする 採用 目安のまま(zoom 17、幅 250

    m) 2 段細かく(zoom 19、幅 63 m) 5 段細かく(zoom 22、幅 7.8 m) 円に見えない。畳んだ後 18 枚 まだ角張る。畳んだ後 106 枚 円に見える。畳んだ後 1,002 枚 目安の zoom:タイル幅が半径 ÷ 3 になる zoom 外のふちの zoom:見た目で円に見えるまで細かくした、目安の 5 段下 1 km なら 333 m を初めて下回る zoom 17(250 m)。円の大きさに対する粗さの目安 zoom 22(7.8 m)。マス選びと円の判定はこの細かさで行う。6 段下は見た目が変わらず枚数だけ 2 倍(2,022 枚)
  10. ② 円 → QuadKey の集合 一番細かい zoom で円を作る 129 1

    129 1 まず、円を囲む正方形の範囲に絞る 地球上の全マスは見ない。円の中心が入るマス(青)を起点に、上下左右へ「半径がタイル何枚分か + 余裕 1 枚」ずつ広げた正方形(青枠)だけを見る。1 km なら、タイル幅は 7.8 m。半径は 1000 ÷ 7.8 ≈ 128 枚分 なので余裕を足して 129 マスずつ。一辺は 129 + 1 + 129 = 259 マスで、259 × 259 = 67,081 マス。 半径 1,000 m 採用の境目 1,003.9 m = 1,000 + 7.8 ÷ 2 (半径 + タイル幅 ÷ 2) 1,010 m 不採用 1,002 m 採用 990 m 採用 1,002 m は円の外だが 青の内側なので採用 2 マスの中心と円の中心の距離を測り、少しで もかかるマスは採用 • 距離は Haversine 公式(地球を球とみなして 2 点間の地 表距離を出す式)で測る • 採用の条件は、中心(•)の距離が 半径 + タイル幅 ÷ 2 以 内(青の破線。1 km なら 1,003.9 m)。中心が円の外で も縁にかかるマスは拾える 51,684 枚の 22 桁 QuadKey が残る(1 km、緯度 35・経度 135)
  11. ② 円 → QuadKey の集合 4 兄弟が揃った親だけ畳む:内側は粗く、外縁は細かく 末尾 1 桁を削って、0〜3

    が全部あれば親 1 枚に置き換える 1230 1231 1232 1240 1241 1242 0〜3 が揃った → 親 123 だけ残して子を消す 123 1233 1240 1241 1242 1243 が無い → 畳まず 3 枚のまま出力 残った親にも同じことをして、zoom 5 まで繰り返す。内側は大きく畳まれ、外縁は細かいまま残る。 51,684 → 1,002 枚(1 km) 採用した QuadKey をどう持つか:ここが速さを分けた 32 × 32 の模式図。濃いほど大きく畳まれたタイル ✕ 遅かった:採用した QuadKey を 1 枚ずつ持つ 1230 1231 1232 1233 1240 1241 14.3 ms メモリ確保 69,315 回 1242 … 段ごとに、末尾を削って親でまとめ直す → 4 枚揃った親を出す → 揃わなかった子を詰め直す。3 つの入れ物を毎段作り直すので、5 万枚ぶ んの小さなメモリ確保が積み上がる ◦ 速かった:親をキーに「0〜3 のどれがあるか」を 4 ビットで持つ 123 → 1111 2.1 ms メモリ確保 1,412 回 124 → 0111 … 採用した瞬間に、末尾を削った親の欄でその桁のビットを立てるだけ。1111 の親は、さらに上の親のビットを立てる。0111 はそのまま出 力。入れ物はこの表 1 つで済む ms は 1 km 単独の単体ベンチ。 画面では 1・3・5・10・30 km の 5 つの円を一度に生成する。5 本が同時に走るので、生成の CPU 時間がそのま 応答は CPU 0.5 コアに制限した ま応答時間に効く(次のページ)。5 距離の応答は 557 → 130 ms BFF の中央値
  12. ② 円 → QuadKey の集合 API 応答:5 つの円の 5 リクエストが全部返るまで

    557 → 130 ms 応答の内訳:生成・固定費・待ち なぜ生成の数十 ms が応答の数百 ms になるか BFF は CPU 0.5 コア:100 ms ごとに 50 ms しか動けない 5 リクエスト(1・3・5・10・30 km)を同時に送り、全部返るまでの時間(ms、中央値) 0 前 100 200 300 400 500 600 557 ms 生成 111 + 固定費 45 前 + 5 本の取り合い・割当待ち 401 557 ms CPU 約 111 ms 後 130 ms 生成 24 + 固定費 45 + 生成→結合→JSON(CPU) 後 固定費(認証・DB・転送) 130 ms CPU 約 24 ms 5 本の取り合い・割当待ち 61 取り合い・割当待ち CPU を使っている 固定費は 1 km を 1 本だけ投げた応答 49 ms − 生成 3.7 ms の推定。並列でも待ちが重なるので 5 倍にはならない 1 画面は 5 つの円を一度に生成する 1・3・5・10・30 km を並列に要求するので、BFF では 5 本の生成が同時に走り CPU を取り合う 2 割当を使い切って止められている 区切りは模式図。CPU は生成→結合→JSON の 5 距離合計(単体ベンチ)。残りは認証・DB・転送と割当待ち CPU 0.5 コアなので CPU 時間が応答に直結 CPU 1 ms が壁時計 2 ms 以上になり、割当を使い 切ると次の 100 ms まで止められる。生成の差は 1 km で 12 ms、5 距離の合計で 88 ms。応答では 427 ms の差になる 3 固定費は並列で重なるので 5 倍にならない 認証・DB・転送は待ち時間が主で、5 本同時でも 1 本ぶんの約 45 ms に近い。後の 130 ms は生成 24 + 固定費 45 + 5 本の取り合い約 60。生成はも うボトルネックではない
  13. ② のタイル集合 → 拠点の抽出 1,002 枚のタイルで、拠点を正確・簡単に抽出 要件 2 一覧に抽出する:円の中に自社拠点があるリスクだけを、DB から引いて

    一覧に出す 要件 3 境界で正確に判定する:円の縁の拠点を、見る人や回数によらず同じよう に振り分ける 1. 緯度経度の外接矩形で絞る 中心 ± 0.01 度の範囲比較。③ は外なので除外。② はタイル群の外でもここでは残る(まだ候補) 2. 保存済みの QuadKey 集合と先頭一致で照合 → 要件 2 拠点 ① の QuadKey は 120301 → 先頭が 1203 と一致。該当 120300 120301 12031 120302 120303 拠点 ② の QuadKey は 120001 → 1203 で始まらない。該当しない 実装:保存したタイル 1203 から範囲を作り、拠点の QuadKey を引く 拠点の QuadKey(辞書順) 1203 以上 12032 12033 親 1203 を 4 分割、左上の 12030 をさらに 4 分割 120001 ② 12034 未満 120301 ① 12033… 1210… 始まりはタイルの QuadKey 1203、終わりはその末尾に 4 を足した 12034。桁は 0〜3 なので、 1203 の子孫はすべてこの間に並ぶ 青いタイル:円を覆うタイルの集合(DB に保存)。濃い 1 枚 が親タイル 1203 点線の四角:外接矩形(粗い候補絞り)。• はリスク地点 境界が安定する理由 → 要件 3 拠点は zoom 23 の 1 タイルに固定され、影響範囲はタイルの集合。距離の丸めに依存せず、同じ拠 点は必ず同じ答えになる
  14. ③ polygol github.com/engelsjk/polygol QuadKey の集まり → 外周のポリゴン:3 つの候補から選ぶ 入力 緯度経度と

    半径 ① buckhx/tiles ② 自社実装 ③ polygol 1 点 → 1 タイル 円 → QuadKey の集合 集合 → 外周のポリゴン 投影・格子・番地 zoom・マス選び・畳み込み 長方形化・結合・GeoJSON 出力 地図に描く ポイント 1 ポイント 2 ポイント 3 3 つの候補を比べる polygol を選んだ理由 隠し味:長方形にまとめる polyclip-go・simplefeatures・polygol の中身 を追い、速さと正しさを実データで比べる 正しく、全部渡すだけで、十分に速い。うま い・やすい・はやいの 3 点で選ぶ 横につながるタイルを長方形にまとめてから 渡し、もう一段速くする
  15. ③ 集合 → 外周のポリゴン 結合の目的:タイルの内部の仕切りを消し、全体の外周だけを返す 入力 ② で作った QuadKey の集合。1km

    なら 1,002 枚で、大きさは混在する 出力 複数のタイルを合わせた 1 つ以上のポリゴ ン。内部の仕切りは残さない。全体は単一の QuadKey ではない 結合で直らないもの 選別した 12 枚(同じ大きさの模式図) 必要なのはこの外周 選別タイルと理想の円との近似誤差。それは タイル選別の zoom で決まる
  16. ③ 集合 → 外周のポリゴン 外周を作るライブラリの候補は 3 つ 候補 1 polyclip-go

    候補 2 simplefeatures 候補 3 polygol 2 入力の結合。呼び出し側 汎用の GIS ライブラリ。 全入力の端点を 1 つのキュ が隣接する 2 つを選び、途 結合順も辺の候補探しも任 ーに入れ、左から右へ 1 回 中結果に 1 枚ずつ足してい せられるが、その分の仕事 なぞって外周だけを返す く が中で走る github.com/akavel/polyclip-go github.com/peterstace/simplefeatures github.com/engelsjk/polygol 現行で採用 この後の流れ 候補 1 → 2 → 3 の順に、同じ 12 枚をどう結合するかを追う。次に 3 つの比較実験、最後に現行の polygol と、その入力を減らす隠し味の行矩形化へ 進む
  17. ③ 集合 → 外周のポリゴン › 候補 1 / 3 polyclip-go

    polyclip-go:2 入力の結合を、呼び出し側が 11 回繰り返す 1 回目 2 回目 3 回目 Construct Construct Construct … 4〜11 回目 最初 1 回目の結果 2 回目の結果 3 回目の結果 11 回目の結果 隣接する 2 枚を選ぶ 長方形 + 次の 1 枚 途中結果 + 次の 1 枚 途中結果 + 次の 1 枚 全体の外周 毎回やること 途中結果 + 次の 1 枚 新しい途中結果 メリット:入力に合う結合順を選べる。2 入力の処理を追いやすい 12 枚なら Construct(UNION) を 11 回。どの 2 つを渡すか、どの順で回すかは 呼び出し側が決める。途中結果の辺は次の結合で再び処理される デメリット:結合順を自分で設計する。途中結果の辺を毎回処理し直す
  18. ③ 集合 → 外周のポリゴン › 候補 1 / 3 polyclip-go

    polyclip-go:見つけた辺を、輪郭の点の列の前後に足していく 1.左の縦辺 f 2.上の辺(左半分) 3.下の辺(左半分) 4.上の辺(右半分) 5.右の縦辺 a b c a b c a b c a b c a b c f e d f e d f e d f e d f e d a 新しい列を作る f a 後ろに足す b e f a b e 先頭に足す → 全部を書き写す 辺は左から右へなぞった順に見つかる。輪郭は 1 周の輪なので、左の縦辺から上 側は列の後ろへ、下側は列の先頭へ伸びていく f 後ろに足す a b c e f a b c d 後ろに足す 先頭に足すときは、新しい配列を作って全部を書き写す。輪郭が長いほど、1 回 の書き写しが重くなる
  19. ③ 集合 → 外周のポリゴン › 候補 2 / 3 simplefeatures

    simplefeatures:箱が重なる間だけ半分に分けて絞る 捨てた箱 前半 上辺 7 後半 重なるので分割 図形 1 P まだ重なるので分割 前半 上辺 1 右辺 8 右辺 2 捨てた箱 後半 図形 2 重なった対を拡大 ① 全体の箱同士が重なる 折り返さない 8 辺は、両端 2 点の箱に必ず収ま る。2 つの箱が重なるので 8 × 8 = 64 通りが候 補。離れていればここで終わり ポイント ② 半分に分け、重なる対だけ残す どこで切っても両端の箱に収まるので、4 辺ずつ の箱で比べられる。重なるのは図形 1 の後半 × 図形 2 の前半だけ。離れた 3 組(48 通り)は捨 てる ③ さらに半分。残った 4 通りを元の辺で比べる 上辺 7・右辺 8 × 上辺 1・右辺 2 の 4 通りだけ座 標で比べ、8 と 1 が P で交差。64 通りのうち 60 通りは辺を見ずに済んだ 輪郭を「折り返さない区間」の組に分けておく(右か下へ進み続ける階段の 8 辺が 1 組。左へ戻る辺、上へ戻る辺は別の組)。折り返さないから、どこで切っても両端の 箱に収まり、この分割が成り立つ
  20. ③ 集合 → 外周のポリゴン › 候補 2 / 3 simplefeatures

    simplefeatures:P から Q の間を消して、外周をたどる ① 輪郭が交わる点 P と Q を見つける 前のページの箱で絞り込んだ辺だけを調べて見つける ② P から Q の間を消す(橙の破線) P 図形 1 図形 1 の中 P の点に立って、その場でぐるっと一周見回す。P から出る辺は 4 本 • 図形 1 の辺:P から上へ、P から下へ • 図形 2 の辺:P から右へ、P から左へ Q 時計の針のように 1 本ずつ回り、相手の辺をまたぐたびに「相手の中か外か」を切り替 える。図形ごとに 1 周ずつ回ると、下へ出る辺は図形 2 の中、左へ出る辺は図形 1 の中 と分かり、どちらも消す。Q でも同じ 図形 2 消す P 消す 図形 2 の中 ③ 残りを順にたどると 1 周の外周になる(青) 図形 1 の外周を進み、P で図形 2 へ乗り換え、図形 2 の外周を回って Q で図形 1 に戻る
  21. ③ 集合 → 外周のポリゴン › 候補 3 / 3 polygol

    polygol:全入力を 1 回だけ、左から右へなぞる x=0 左端の辺が始まる 1 枚のタイルだけの辺 x=1 上下にも広がる x=2 中央で入れ替わる 上下 2 枚のタイルの辺が同じ場所に重なっている 全 12 枚の端点を、左から順に 1 つずつ処理す る。2 枚ずつ結合する途中結果は作らない x=3 上下が終わる x=4 なぞり終わる 縦辺は省略 上下に隣り合うタイルでは、同じ場所に辺が 2 本重なる(二重線)。QuadKey のタイルは格 子に沿った正方形なので、辺どうしは交差せ ず、起きるのは重なりだけ(大きさの違うタイ ルが混ざっても同じ) この時点では輪郭を描かない。どの辺を残すか は、なぞり終えた後に決める(次のページ)
  22. ③ 集合 → 外周のポリゴン › 候補 3 / 3 polygol

    polygol:下から見て、片側が外の辺だけを残す ① 図形が重なっているとき ② タイルに当てはめると 両側とも内の 二重線を 捨てる 矢印に沿って下から上へ見て、辺の上下を比べる • 片側だけ外 → 残す(外周になる) ◦ 両側ともどれかの図形の内 → 捨てる(内側の仕切り) 斜めの辺でも同じ なぞり終えた時点の全部の辺 残した辺をつなぐと外周だけ • 1 枚のタイルだけの辺 → 残す ◦ 二重線 → 捨てる 片側が外なので、外周になる 両側ともタイルの内なので仕切り。重なった 2 本 は 1 本にまとめてから判定する
  23. ③ 集合 → 外周のポリゴン 比較実験:入力の形によって速い方式が変わる 結合処理のプロセッサ使用時間(ミリ秒、短いほど速い)。橙が各入力で最速。棒の長さは行ごとの相対値。polyclip-go は 1 枚ずつ足した値を基準に、二分結合の値を補足 polyclip-go(1

    枚ずつ) 隣接する正方形 256 枚 タイルが敷き詰まった形 2.75 └ 二分結合にすると simplefeatures 5.76 polygol 重なる円形 32 個(各 64 辺) 滑らかな輪郭 polyclip-go(1 枚ずつ) 3.2 └ 二分結合にすると 1.64 simplefeatures 互いに離れた形 2.74 結合順で大きく変わる 31.5 0.07 simplefeatures polygol simplefeatures が速い 滑らかな輪郭は折り返さない長い組を作りやすく、 箱で比較を省きやすい 1.57 polyclip-go(1 枚ずつ) └ 二分結合にすると 1 枚ずつ足す polyclip-go は、育った途中結果の辺を 毎回処理し直す 0.96 polygol 離散した正方形 256 枚 polygol が速い 0.78 12.6 polygol が速い 1 枚ずつだと途中結果が離散のまま大きくなる。二分 なら外接矩形が離れた対の交点計算を省ける 1.09 polyclip-go は結合順を呼び出し側が決める。1 枚ずつ足すと途中結果の辺を毎回処理し直すので枚数の 2 乗で遅くなる(隣接 4,096 枚で 263 ms)。2 枚 → 4 枚 → 8 枚と二 分して結合すると 3 条件とも最速級になり、隣接 4,096 枚でも 21 ms で polygol の 25 ms と同程度。図形数も 256 と 32 で異なり、形だけの差ではない
  24. ③ 集合 → 外周のポリゴン polyclip-go は壊れやすい:タイルの順番しだいで外周が消える 1 km の実データ(畳んだタイル 1,002

    枚、緯度 35・経度 135)。今の生成処理は QuadKey を辞書から取り出すので、返す順番が実行ごとに変わる ランダム順(5 通り) QuadKey 順に並べ直す polyclip-go 二分結合 5 回とも壊れる 正しい polyclip-go 1 枚ずつ 5 回とも壊れる 正しい polygol 5 回とも正しい 正しい QuadKey 順は並びが 1 通りに決まるので、試したのはその 1 通り。今回の入力では正しく結合できた 入力:1,002 枚 polygol の結果 polyclip-go の結果 ランダムな順番の 1 通り 外周 1 つ 二分結合。断片 39 個。破線は本来の 外周 → 入力 本来の結果 polyclip-go 灰色の 2 つが同じ図 形。橙の破線が捨てられ る辺 外周 1 つ 結果は空。破線は本来の 外周 なぜ壊れる:polyclip-go の不具合 ライブラリの中だけでは防ぎきれない • 辺が重なる場所で内側と外側を取り違え、橙の辺を捨てる • 辺の重なりや点での接触は、元のアルゴリズムでも抜けている • 欠けて閉じない輪郭を、エラーにせず捨てる。外周ごと消えて断片 だけが残る • 形が複雑なほど重なり方が増え、1 つ直しても別の配置で壊れうる • 結局、呼び出し側が入力を整え続ける。壊れてもエラーにならない
  25. ③ 集合 → 外周のポリゴン polygol を選んでいる理由:うまい・やすい・はやい 1 km の実データ(畳んだタイル 1,002

    枚)で、3 つの候補を正しさと速さで比べた 正しさ(ランダムな 5 通りの順番) polyclip-go 二分 順番しだいで壊れる simplefeatures 5 回とも正しい polygol 5 回とも正しい 使用時間 5.19 ms 47.4 ms 6.23 ms 使用時間は QuadKey 順に並べて全方式が正しく結合できる条件で測った値。M4 Pro、GOMAXPROCS=1、3 反復の中央値 うまい 正しい やすい 手間いらず はやい 十分に速い どの順番で渡しても、外周 1 つの正しい結果が返 る。polyclip-go は並べ方しだいで壊れる 全部を渡すだけ。polyclip-go は二分結合と並べ替え を自分で書き、守り続ける必要がある 1,002 枚を約 6 ms で結合する。simplefeatures は正 しいが約 47 ms かかる
  26. ③ 集合 → 外周のポリゴン 隠し味 隠し味:横につながるタイルを長方形にまとめて渡す 畳んだ後のタイル(大きさ混在) 行ごとに左端・右端を求め長方形に 主地点 1km:親タイル

    1,002 枚 → 行矩形 150 個(試作)。polygol が扱 う辺が減り、全体は 32.5 → 18.0 ms 上下で区間が一致すれば縦にも統合 混在 zoom を整数座標に変換して帯ごとに統合。長方形は単一の QuadKey ではなく、結合へ渡すポリゴン表現
  27. まとめ ② で作ったタイル集合を、円の描画と拠点の抽出の両方に使う 円を描く:① → ② → ③ ① 1

    点 → 1 タイル ② 円 → QuadKey の集合 ③ 集合 → 外周 buckhx/tiles 自社実装 polygol • メルカトル投影で地球を 0〜1 の正方形に潰し、何列 目・何行目かを決める に入るタイルを選ぶ • マスの位置を、zoom ごとに 4 区画のどこかを 1 桁 ずつ書いた番地 QuadKey にする • 半径から zoom を 2 つ決め、一番細かい zoom で円 • 4 兄弟が揃った親だけ畳む。1 km は 51,684 枚が 1,002 枚になる • 正確さ、速さ、メンテしやすさを確かめ、polygol を 採用している • 隠し味:行矩形にまとめてから渡すと、もう一段速 くなる(1 km の全体 32.5 → 18.0 ms、試作) 拠点を引く:② のタイル集合を使う 拠点の抽出 • 緯度経度の外接矩形(点線)で粗く絞り、保存したタイル(濃い 1 枚が 1203)の QuadKey から始まるかの範囲比較で確定する PostgreSQL • 判定はタイル単位なので、円の縁の拠点も毎回同じ答えになる