Issue #65 Phase 3の実装仕様。Drogger Tablet本体ではなく、別APK
dev.drogger.simulatorの地図編集画面を対象とする。共通のタップ寸法、コントラスト、
状態を色だけで表さない原則はUIデザイン指針に従う。
利用者が実在の筆を地図で確認しながら、次の2種類の操作だけで未送信の走行シナリオを作る。
入力と編集を同じジェスチャーへ暗黙に割り当てない。タブレットには右クリックや修飾キーがなく、
一本指ドラッグへ地図移動・曲線入力・点移動・曲線変形を同時に持たせると、操作結果を予測しにくく
なるためである。Issue #65に以前記載された「描画モード切替なし」は利用者指示ではなく、設計整理の
過程で入った前提だったため、本仕様で撤回する。
800×1340相当の縦画面を基準とし、高さを状態遷移で変えない。
入力/編集の2状態トグル1個、直線/曲線の2状態トグル1個。直線/曲線トグルは入力時だけ有効とし、編集時は位置を変えず無効表示にする。2状態トグルは
それぞれ1つのsegmented controlとして実装し、選択中の文言を常に表示する。強い緑の操作は右下の
主操作1つだけとする。
主操作は状態により次のように差し替える。
| 状態 | 主操作 |
|---|---|
| IPC接続待ち・取得中 | 無効の「接続待ち」 |
| IPC切断・version不一致 | 「再接続」 |
| 開始点未指定 | 無効の「経路を入力」 |
| 入力済み・未送信経路あり | 「Drogger Tabletへ送る」 |
| 送信中 | 無効の「送信中」 |
| 送信成功 | 「続きを入力」 |
| 送信失敗 | 「経路を修正」 |
PC検証用の+/−は「現在地/経路へ戻る」とまとめて地図右下へ常設する。Android Emulatorは
ホイールをアプリのACTION_SCROLLではなく縦スワイプへ変換する環境があり、アプリ側だけでは
確実にzoomへ割り当てられないためである。この例外は開発用シミュレータだけに適用し、本番の
Drogger Tabletへ常設ボタンを追加する根拠にはしない。
+/−を使う。Controlを使ったピンチ再現も利用できるが、必須操作にはしない。編集モードへ切り替えても地図カメラ、選択筆、未送信経路を保持する。Tabletへ送信済みの経路は
シミュレータへ返されないため編集対象にしない。
形状ハンドルの移動量は、曲線内の各点へ端点で0、中央で最大になる連続的な重みで適用する。
実装上は正規化位置tに対するsin(πt)等を使用し、始点・終点が動かず、折れを生じないことを単体テストする。
現在の:simulator-protocolにあるGENTLE_CURVEは、両端間を常に開角30°の円弧で結ぶ暫定モデルであり、
手描き形状、左右の曲がり分け、形状ハンドル編集を表現できない。地図UIでこれをそのまま使わない。
シミュレータ側の未送信ドラフトは、次の論理区間を保持するAndroid非依存モデルへ拡張する。
StraightSection(start, end)DrawnCurveSection(start, sampledPoints, end)曲線ドラッグ中は画面上で約4dp以上移動した点を採取し、確定時に地理距離で間引き・RDP単純化して
sampledPoints(制御点)として保持する。初期値は最小点間隔0.25m、RDP許容誤差0.10mとし、実際の
圃場・倍率でpreviewを比較して確定する。始点・終点は必ず保持する。
sampledPointsは編集用の制御点であり、そのまま線で結ぶと鋭い折れ線に見える。地図表示と
Drogger Tabletへの送信は、この制御点列(始点・終点を含む)をCatmull-Romスプラインで滑らかに
補間した同一の点列を使う。表示専用の点列と送信専用の点列を別々に持つことはしない。以前は
表示だけ滑らかにし送信は制御点列のまま(直線補間)にする設計を検討したが、Tablet側が実際に走行する
経路が地図に見えている曲線とずれてしまうため撤回した(利用者レビュー反映)。曲率変更(菱形ハンドル)・
終点移動の後も、表示とTablet送信の最大ずれが0.10m以内であることを自動テストで検証する。
展開した補間済み点列を、隣接点間を直線補間するwaypoint列としてDrogger Tabletへ送る。固定30°円弧は
互換性のため残してよいが、新しい手描き曲線の生成には使わない。
展開後のpayload全体(補間済みの最終点列)が500点を超える場合は送信せず、「点が多すぎます。曲線を
短くするか区間を減らしてください」と表示する。精度を黙って大きく落として上限内へ収めない。
航空写真とベクター地図の両方で識別でき、色だけに依存しない。
| 対象 | 表示 |
|---|---|
| 選択筆 | 橙の3dp輪郭+薄い半透明塗り。未選択筆は細い橙輪郭 |
| 登録済み経路の最終地点 | 濃いチャコールのピン+白い外周。近傍の不透明チップに「登録済み経路の最終地点」 |
| 初回シナリオの開始点 | 白い外周を持つ緑の丸+「開始」チップ |
| 未送信経路 | 白いcasingの上に青の実線。入力中previewは青の破線 |
| 現在の終点 | 青い丸+白い外周。入力時は48dpの薄い開始領域を一時表示 |
| 選択区間 | 通常線より太い白casing+濃い青。下部案内に「直線を編集中」または「曲線を編集中」 |
| 共有点ハンドル | 白い外周を持つ青い丸。固定点は鍵アイコン付きのチャコールピン |
| 曲線形状ハンドル | 白い外周を持つ紫の菱形+選択中だけ「曲線」チップ |
文字チップは航空写真へ直接置かず、不透明なsurfaceと十分な文字コントラストを持たせる。常時すべての点へ
ラベルを出さず、開始点・現在終点・選択対象に限定する。
+/−で確実にzoomでき、Emulator標準のピンチ再現も利用できる。Phase 3で実装する: 地図・筆選択、2トグル、直線/曲線入力、点移動、曲線形状ハンドル、パン/zoom、undo、
表示区別、IPCへの展開・送信、800×1340確認、WorkMenu三点アイコン視認性修正。
後続候補: 複数形状ハンドル、途中への制御点追加、途中区間だけの削除と再接続、未送信シナリオ保存、
複数シナリオ。初版で先回りして実装しない。
Phase 3実装(Track #65)で確定した、本文だけでは読み取れない実装判断を記録する。
DraftPointId/DraftSectionId/DraftPoint/DraftSectionStraight/DrawnCurve)/DraftRouteを:simulator-protocol(Android非依存)に追加した。DraftRouteEditor(区間追加・点移動・形状ハンドル・選択区間以降削除)、CurveSimplification.ktDraftHistory(undo)、MapEditUiStateTouchGeometry.kt(48dp判定、screen px距離のみで判定しSimulatorPrimaryAction(状態→主操作の対応表を純粋関数化)もこのモジュールにSimulatorSessionState.Editing等のdraft型はList<RouteWaypoint>からDraftRouteへ、startPointFixed: Boolean(Tablet起源の開始点かどうか)をAwaitingStartPoint)時: タップが未選択の筆に当たれば筆を選択するだけで終わる。MapLibreMap.queryRenderedFeaturesは描画線幅に限定されるためDraftSection.DrawnCurve.arcLengthMidpoint)方式へ修正した。機能(始点・終点固定・sin(πt)重み変形)DraftSection.DrawnCurve.smoothDisplayPolyline(Catmull-Romスプライン、SimulatorMapStyle.updateDraftRouteLine)と送信payloadDraftRoute.toRouteWaypoints、内部的には共通のDraftRoute.toExpandedPoints)の両方が呼び出すDisplaySubmissionParityTestで自動検証する。exceedsSubmissionLimit)もこの展開済み点列の実点数で判定するため、制御点が少なくてもapps/android-tablet/shared-map-assets/map/(PMTiles・航空写真タイル・:appと:simulator-appの両build.gradle.ktsがsourceSets.main.assets.srcDirs("../shared-map-assets")で同じ物理ディレクトリを参照するapp/src/main/assets/mapから移設、コピーはしない)。筆GeoJSONはGeoJsonSource(id, url)の:appのOfflineMapStyleと同じく、styleのJSON内で"type":"geojson","data":"asset://..."}とWorkMenu(:app)にModifier.fillMaxHeight()を使うと、周囲のRowが緩い(実質無制約に近い)WorkStatusBarと同じheightIn(min = 64.dp, max = 72.dp)に修正した。SubmitSucceeded、draftを持たない)に、直前の未送信経路の線が地図上に残り続けるDraftRouteを渡して明示的に線を消すよう修正した。