fix(plateau): 編集の確定で判定を作り直し、1 つ受理しても残りを候補に残す - #56
Merged
Merged
Conversation
すでに OSM にある建物を動かしても、重なっている候補が消えたり現れたりしません。 重なりの判定の結果を記憶している集合を消しているのが、新しいデータを取り込んだときの合図だけで、編集が確定したときの合図を購読していないためです。 編集が確定したときの合図を購読し、差分に建物が含まれるときだけ記憶を消す設計にしました。 記憶は候補の id で引く形で、建物の id からは引けないため、当たった候補だけを消さず全部消します。 同じ量の計算は、データを取り込むたびにすでに起きています。 描画はこちらから要求しません。 編集の途中の合図を受けた側が次の描画を予約しており、記憶を消す処理はその前に終わります。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
設計を 5 つの作業に分けました。 購読を足す段、建物と無関係な編集を除く段、親をたどる段、削除とタグの除去を扱う段、仕上げの段です。 各段は、失敗する試験を書き、失敗を確認し、通す実装を書き、通ることを確認し、コミットする流れで進みます。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
すでに OSM にある建物を動かしても、重なっている候補の表示が変わりませんでした。 判定の結果を記憶している集合を消しているのが、新しいデータを取り込んだときの合図だけだったためです。 編集が確定したときの合図を購読し、記憶を消すようにしました。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
判定が見ているのは OSM の建物だけです。 建物が含まれない編集で記憶を消すと、次の描画で表示範囲の候補すべてを計算し直すことになります。 差分に建物が含まれるかを見る関数を足し、含まれるときだけ消すようにしました。 記憶を消す 2 行は、`merge` の側と共通の関数にまとめました。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
建物の node を動かすと、差分にはその node しか載りません。 node には building タグが無いため、建物の変更として数えられませんでした。 変更後の地物を complete() から取る形に変えました。 親の way と relation を含むため、node を動かした場合も親の建物が現れます。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
どちらも変更後の地物に建物が現れません。 削除では値が無く、タグを外した場合は building タグが残らないためです。 変更前の地物も見るようにしました。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Rapid のレイヤーを表示に切り替えるたびに startAsync() が呼ばれ、購読が積み上がっていました。 早期に返す 1 行を足しました。 差分が読めないときに記憶を消す動きと、merge でも記憶が消えることを、試験で固定しました。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
type=building の relation の outline を「この地物だけを追加」で受理すると、その直後に残りの parts が候補から消えます。 画面の文言は「外形とほかの部分は提案のまま残ります」と約束しており、守られていません。 判定の材料に出どころを持たせ、relation を判定するときは、その relation とメンバーの way から来た面を外す設計にしました。 受理した地物は Plateau 側と同じ id のまま OSM のグラフに入るので、id の照合だけで足ります。 この食い違いは、約束が画面の文言にしか書かれていなかったために起きました。 重なりの判定と候補の表示について、守るべきものを 8 項目に並べ、出どころと試験を対で書きました。 試験が無いのは 2 項目で、どちらもこの設計で足します。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
外形の役割を持つメンバーが無い relation では、メンバーが 1 本ずつ判定されます。 この経路にも同じ集合を渡さないと、1 本を受理したときに残りが消えます。 約束は relation の形によらないため、この経路を設計に足しました。 試験も 1 件足して 6 件にしました。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
公開中の API は parts に building:part を付けます。 判定の材料に入るのは building タグを持つ地物だけなので、実際の運用で約束が破れるのは outline を受理したときだけです。 試験のヘルパは parts にも building を付けます。 約束はタグの付き方によらず守るべきものなので、ヘルパはそのままにすることを書きました。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
設計を 5 つの作業に分けました。 材料に出どころを持たせる段、relation の判定で自分自身の面を外す段、外形の無い relation の経路の段、守るべきものの取りこぼしを埋める段、仕上げの段です。 足す試験を 7 件にし、設計の側もその数に直しました。 下位の関数の動きを固定する 1 件を加えたためです。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
重なりの判定の材料に、その面がどの地物から来たかを sourceID として持たせました。 判定の関数に、外す id の集合を受ける引数を足しました。 この段では、まだどこからも集合を渡していません。 動きはこれまでと同じです。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
type=building の relation のメンバーを受理すると、その地物は Plateau 側と同じ id のまま OSM のグラフに入ります。 外形と同じ形なので必ず重なると判定され、残りのメンバーまで候補から外れていました。 画面の文言は「外形とほかの部分は提案のまま残ります」と約束しています。 relation を判定するときに、その relation 自身とメンバーの way から来た面を材料から外すようにしました。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
外形の役割を持つメンバーが無い relation では、メンバーが 1 本ずつ判定されます。 この経路には、同じ relation から来た面を外す集合が渡っていませんでした。 約束は relation の形によらないため、この経路にも同じ集合を渡すようにしました。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
設計に並べた守るべきもののうち、試験が無かったものを埋めました。 別の建物との重なりがこれまでどおり隠れること、relation に属さない候補の判定が変わらないこと、重なりの除去を止めているときは除去しないことの 3 件です。 いまの動きを固定するための試験で、実装は変えていません。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
実装を終えたので、表の「この設計で足す」を実際の試験の名前に置き換えました。 表に挙げた 14 件の名前が、試験ファイルに 1 件ずつ存在することを確かめています。 8 項目すべてに対応する試験がある状態になりました。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
試験のコメントの 1 行 2 文を 2 行に分けます。 _differenceTouchesBuilding の判定順序を入れ替えます。 軽い changes を先に見て、重い complete() を後に見ます。 JSDoc も同じ順序に書き直します。 設計文書に id の空間の説明を足します。 Plateau 側の負の id と実在の id は一致しませんが、 負の id の空間自体は他の地物とも共有されている旨を記します。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
直したこと
2 つの不具合を直しました。
1. 編集を確定しても重なりの判定が古いまま残る
すでに OSM にある建物を動かしても、重なっている Plateau の候補が消えたり現れたりしませんでした。
報告者はモードを往復させて、候補を作り直させていました。
重なりの判定の結果は
PlateauService._plateauConflationCacheに記憶されます。この記憶を消していたのは
mergeの合図だけで、編集システムが新しい OSM のデータを取り込んだときにしか出ません。編集が確定したときに出る
stablechangeを購読していませんでした。stablechangeを購読し、差分に建物が含まれるときだけ記憶を消すようにしました。建物が含まれるかどうかは
_differenceTouchesBuilding()で見ます。difference.changesの変更前と変更後の地物を先に見ます。建物の way を編集した場合、建物を作った場合、建物を消した場合、
buildingタグを外した場合は、ここで片付きます。残る「建物の node だけを動かした場合」のために、そのあと
difference.complete()を見ます。親の way と relation を含むためです。描画はこちらから要求していません。
MapSystemがstagingchangeを受けて次の描画を予約し、その予約はstablechangeの後で実行されるためです。取り消しとやり直しも同じ経路を通ります。
2. 1 つ受理すると同じ relation の残りが消える
1 を入れた結果、
type=buildingの relation のメンバーを「この地物だけを追加」で受理すると、その直後に残りが候補から消えるようになりました。受理した地物は、Plateau 側と同じ id のまま OSM のグラフに入ります。
evalRelationOverlapは relation の判定を外形の重なりだけで決めるため、受理した建物と重なって relation ごと外れていました。画面の文言は「外形とほかの部分は提案のまま残ります」と約束しています。
この規則自体は以前からありましたが、これまでは次にデータを取り込むまで残りが見えたままでした。
重なりの判定の材料に
sourceIDを持たせました。relation を判定するときは、その relation 自身とメンバーの way から来た面を材料から外します。
外形の役割を持つメンバーが無い relation では、メンバーが 1 本ずつ判定されるため、その経路にも同じ集合を渡します。
relation に属さない候補の判定は変えていません。
別の建物として受理したものは、これまでどおり重複の判定に使われます。
守るべきもの
この食い違いは、約束が画面の文言にしか書かれていなかったために起きました。
重なりの判定と候補の表示について、守るべきものを 8 項目に並べました。
出どころと、それを固定する試験の名前を対で書いています。
出どころには画面の文言も含めました。
8 項目すべてに対応する試験がある状態にしました。
表に挙げた 14 件の名前が試験ファイルに 1 件ずつ存在することを、実装のあとに確かめています。
一覧は設計文書の「守るべきもの」の節にあります。
変えていないもの
mergeの購読はそのまま残しています。高さの転記の経路(
skipConflation)とisAddBlockedの動きは変えていません。Plateau 以外のデータセット(mapwithai、esri、overture)には触れていません。
上流のファイルには手を入れていません。
試験
npm run build && npm run dist && npm run test:browserで 805 件成功、5 件スキップ、失敗 0 件です。起点の
28996a427では 791 件成功、5 件スキップ、失敗 0 件でした。足した 14 件の内訳です。
各段の 1 件目は、実装の前に失敗することを確認しています。
最後の 3 件は、いまの動きを固定するための試験で、実装は変えていません。
npm run lintは誤り 0 件、警告 42 件で、起点と同じ内容です。未検証の事項
自動の試験はグラフを組み立てて呼ぶ形で、実際の操作は通っていません。
公開中のサイトへ反映する前に、parts のある建物で外形を受理し、残りが候補として残ることを画面で確かめます。
分かっている弱点
負の id の空間は、利用者が新しく引いた地物や、id を持たない他のデータセットの地物と共有されています。
負の連番が Plateau の id の範囲まで進み、かつ同じ表示範囲に建物として存在した場合に限り、無関係な面が材料から外れます。
そのときの結果は「すでに OSM にある建物の候補が 1 件余分に出る」で、被害は小さいものです。
relation の可否は毎回計算し直す一方、メンバーの way は記憶から返ります。
編集を挟まずに地図を動かして材料が変わると、両者が食い違いえます。
これは変更前からある性質で、今回の修正は記憶を消す機会を増やす方向なので、食い違いが起きる範囲はむしろ狭くなっています。
設計と計画
docs/superpowers/specs/2026-09-10-plateau-conflation-cache-invalidation-design.ja.mddocs/superpowers/plans/2026-09-10-plateau-conflation-cache-invalidation.mddocs/superpowers/specs/2026-09-11-plateau-keep-relation-members-after-accept-design.ja.mddocs/superpowers/plans/2026-09-11-plateau-keep-relation-members-after-accept.md🤖 Generated with Claude Code