03-locate-camera-view-contract.md 15 KB

镜头「定位到监测点」的视角契约

Type: grilling Status: resolved Labels: wayfinder:grilling Blocked by: None

进度:100%

已收口(resolved,2026-09-18):Q1–Q8 全部确认;独立复审完成并并入修正(中心高程取实测地形、断言口径补 height 并去冗余、±200 m 复核口补推导、全球态点选不进区记为边界)+ ADR / 票 04 改后原文全文落票面。下游落盘已执行:ADR 0008 原位修订、决策地图票 04 同步、CONTEXT.md 补词条、本图收口。决策要点见 ## Answer。

Question

需求①原句:「点击监测点位后,首先应该将镜头移动定位到该监测点位置,首先要能够在三维场景下观察该监测点的状况」——即点一下就该看得清这个点位及其周边,而不是只把旋转中心挪过去。

现状与冲突(本图 map.md 事实 3):

  • 决策地图票 04 已锁:选中对象时中心改为该对象的地表高程点,保持当前 heading 与 range(只换中心);取消选中不回退中心,只有左键平移才回退。
  • services/cameraControl.js 的 setFocus() 就是这个语义;只有 applyViewPreset()(票 30 引入)能连 hpr 一起换。
  • 当前 range 是县域级(票 30 home pitch −55 / range 12000),因此「只换中心」到不了「能观察该监测点」。

请裁决并定量:

  1. 定位后的相机三元组:中心(点位地表点?高程取椭球 0 还是实测地形——票 30 已引入 sampleTerrainMostDetailed 的实测口径)、pitch、range(多少米算「看清一个监测点」?是否要分「点位级 / 设备级」两档,与需求⑤的「定位到设备」对齐)。
  2. heading 保留还是取预设:保留的话,从任意角度点一个点位会不会落到「背光 / 被楼挡住 / 贴着地形」的视角(票 34 的体块是示意几何,票 21 的 3D Tiles 也在变)。若取预设,预设值是多少、由配置给还是写死。
  3. 与主场景区限位的合成:.scratch/cockpit-primary-area-guardrails 的 02(已 resolved)定了 range ∈ [120, range_max],range_max = 1651 / (2·tan(fovY/2))(16:9 ≈ 2,542 m,1:1 ≈ 1,430 m)、相机离地高度 h ≥ 正下方地形 + 10 m,并写明「最低仍须能贴近看设备」。本票定的定位 range 与它们取交集后是多少?是否存在「在县城视角下能定位、在全球/区外视角下不能」的分叉,若有,谁优先?
  4. 与票 30 的「归位」关系:定位语义与「家」视角是否互斥?归位按钮要不要接管「回到定位前」?是否需要「返回点位清单/上一视角」?
  5. 是否收窄票 04 的决策:若定位需要连 hpr 一起换,票 04 的「只换中心」要显式收窄为「手动轨道旋转 / 滚轮 / 平移时的中心规则」,并写明是否要在 ADR 0008 补一行指向。(本图只产决策;要改哪句、改成什么,写清原文与改后原文。)
  6. 可复现口径:定位结果如何被断言(mapService.getCameraState() 的 pivot/hpr 期望值,或 DEV 把手),以便将来的走查脚本不靠肉眼。

Answer

已确认决策:第 1 轮(Q1–Q4,2026-09-18 维护者逐条答复)

  1. 验收判据(Q1=A):点位级定位完成后 —— 点位标记清晰落在画面中心、周边一小片区域(街区级)可辨,且该点位下的所有具体设备点位都可见(与需求②联动;「能容纳全部设备点位」这个口径保留到票 05/11 复核 —— 若设备分布比画面跨度宽,数值要重议)。
  2. 机制(Q2=A):定位=applyViewPreset,中心 + heading/pitch/range 一起换(不是 setFocus 的只换中心)。因此决策地图票 04 的「只换中心」收窄为「手动三键(右键轨道 / 滚轮 / 左键平移)的中心规则」;ADR 0008 第 20 行那两句按第 2 轮确认的改后原文修订。
  3. 与主场景区限位(Q3=A):定位不设例外,定位 hpr 必须落在限位内(range ∈ [120, range_max]、h ≥ 正下方地形 + 10 m),被夹就如实呈现;不另设更保守的固定上限。
  4. 与归位(Q4=A):定位不改 home;归位永远回 home;不新增「回到定位前 / 上一视角历史栈」。(术语:往 CONTEXT.md 补「定位」「归位」两条,只锁「指哪个动作」,不进实现细节。)

已确认决策:第 2 轮(Q5–Q8,2026-09-18 维护者逐条答复)

  1. 点位级定位的 hpr(Q5=a):heading 0 / pitch −55 / range 500 m;由配置给(建议 map.locate 一节,缺省 0 / −55 / 500),组件不硬编码,后续可在配置中修改。复核口保留:若票 05/11 表明设备分布超出 ±200 m(Q1=A 的「设备全可见」不成立),回来重议此数值。
  2. 设备级第二档(Q6=a):本票定义两档 —— 点位级(500 m)与设备级(heading 0 / pitch −55 / range 150 m),共用同一配置入口 map.locate(含 point / device 两组),后续可在配置中修改;票 06 引用本票数值,不另发明第二套。
  3. 取消选中 / 关闭面板后(Q7=a):完全不回退 —— 镜头留在定位视角,用户自己滚轮 / 平移 / 归位离开;换一个点位时直接从当前视角飞向下一个点位的定位视角,不先回退再定位。
  4. ADR 0008 与决策地图票 04(Q8=a):原位修订 ADR 0008(新增「定位视角」语义,不新开 ADR);决策地图票 04 同步那一句;地图雾区「定位契约是否回写 ADR 0008 或新开一条 ADR」随之清掉。改后原文全文(复审补落,2026-09-18):

ADR 0008「旋转中心」节,改后:

  • 选中监测点或设备时,中心是该对象的地表高程点(对象高程 + 0;票 30 起按实测地形)。
  • 选中监测点时(从无选中到选中),镜头平滑飞向该点位的定位视角:中心 + heading/pitch/range 一起换(数值与配置入口见 .scratch/cockpit-point-locate-and-device-link 票 03;缺省 heading 0 / pitch −55 / range 500 m;取消选中或关闭详情不回退,换点位直接从当前视角飞向下一个定位视角)。
  • 选中非监测点对象(未关联设备、事件等)或手动三键操作(右键轨道 / 滚轮 / 左键平移)时,中心规则不变:只换中心,保持当前 heading 与 range。
  • 取消选中不立即回退中心或视角;左键平移才把中心更新为地面拾取点。

决策地图票 04(.scratch/web-cockpit-decision-map/issues/04)同步句,改后:

从无选中到选中监测点:镜头飞向该点位的定位视角(中心 + hpr 一起换,契约见 .scratch/cockpit-point-locate-and-device-link 票 03;取消选中不回退);选中非监测点对象或手动操作时仍只换中心、保持 heading 与 range。

默认确认(无异议,一并落盘):① 定位飞行复用 applyViewPreset 既有阻尼 / 动画路径,不新增时长开关;② 断言口径(复审修正)= mapService.getCameraState() + 宿主 dataset.camera:定位完成 = settled(其经纬容差 1e-7° 已含 pivot 对齐,不再另比 1e-4°)且 hpr 匹配预设(对应档位),并断言相机离地高度 ≥ 点位地表高程 + 10 m(防入地由 guardrails 兜底,走查补一道)。

落盘状态(2026-09-18 维护者确认收口后执行):ADR 0008 已按上文改后原文原位修订;决策地图票 04 已同步;CONTEXT.md 已补「定位 / 归位」词条;本图已收口(Decisions so far + 进度 + 清雾区)。

跨图修正(2026-09-18 已核实,guardrails 03 收口)

.scratch/cockpit-primary-area-guardrails 的 03(限位与既有相机契约的合成 + 进出状态机)已落 Answer(该图待收口),并产出 docs/adr/0009:range_max 由 02 的 1651/(2·tan(fovY/2))(16:9 ≈ 2,542 m)改为 home.range = 12,000 m(归位即最远视野,再往外滚轮即夹);home 预设不改;pitch 不参与区域收紧;防入地 h ≥ 正下方地形 + 10 m 不变。

对本票的影响:Q3=A(定位不设例外、落在限位内)结论不变,取值锚点改为 12,000 m —— 点位级 500 m 与设备级 150 m 两档均远低于上限,任何画布比例下都不会被夹,走查断言可写死。实现时以 guardrails 03 与 ADR 0009 为准。

复审补答与修正(2026-09-18 独立只读复审后并入)

  1. 中心高程(复审补答 —— 原 Question 第 1 问漏答):定位中心=点位地表实测地形高程(沿用票 30 的 sampleTerrainHeight 口径),不取椭球 0。理由(复审算实):椭球 0 会把旋转中心埋进沅陵约 111.6 m 的地形里,贴地(CLAMP_TO_GROUND)标记偏离画面中心,直接违背 Q1=A 的「点位标记清晰落在画面中心」且断言测不出(旧断言不比高度);设备级 150 m 时相机离地 ≈ 123 m、距地形只剩 ≈ 11 m(贴着 ADR 0009 的防入地 10 m 边),到 120 m 档会入地 ≈ 13 m。中心高程进断言口径(见默认确认 ②)。
  2. 「±200 m」复核口的推导(复审补):点位级 500 m / pitch −55° / 16:9 的屏幕竖直地面跨度 ≈ 2·500·tan(fovY/2)/sin55° ≈ 396 m,即点位两侧各 ≈ ±200 m。复核口即「该跨度须容纳该点位下全部设备点位;若设备散出跨度外(票 05/11 数据落地时验证),回来重议 500 m」。
  3. 全球态点选定位(复审发现,跨图边界,记为已知边界、不裁决):guardrails 03 状态机只认「进入系统 / 归位」两条进区锁(ADR 0009)—— 全球态下点选监测点得到定位视角但不进区,5 秒闲置会回引导页(既定行为)。本票不裁决「点选是否进区」;若实现后体验不佳,另开票评估。定位两档均远低于 12,000 m,是否有区锁不影响本票数值。
  4. 措辞澄清(复审 note):「手动三键」不包含「点选」;准确表述是「选中(点选)监测点 → 定位换 hpr;手动三键(轨道 / 滚轮 / 平移)与非监测点对象 → 只换中心」—— 已并入 ADR 0008 改后原文。

Comments

2026-09-18 第 1 轮:fact-check 与 frontier 发出

事实核实(只读,均已在本仓或 .scratch/cockpit-primary-area-guardrails 内复核):

  1. domain/camera.js 的域层只有弹簧臂三元组 {heading, pitch, range},没有「相机离地高度 h」这个量;RANGE_LIMITS = { min: 120, max: 30000000 } 是全局常量,限位(02 的 range_max)尚未实现在代码里 —— 也就是说本票的 range 目前只会被 [120, 3×10⁷] 夹住。
  2. 定位链路现有两条且语义不同:cameraControl.setFocus(point) = 只换中心(保持 heading/pitch/range,ADR 0008 第 20 行);cameraControl.applyViewPreset(中心, hpr, opts) = 中心 + hpr 一起换(票 30 为 home 预设引入)。mapService 只把「家/归位」接到了后者。
  3. home 预设实测口径:pitch −55 / range 12000 是县域级(代码注释:4.6 km 街区级、12 km 县域级);isAtHome() 的容差是 pivot 1e-4°、range 相对 2%、角度 0.5°。
  4. 主场景区限位(.scratch/.../02,已 resolved):range ∈ [120, range_max],range_max = 1651/(2·tan(fovY/2))(16:9 ≈ 2,542 m、4:3 ≈ 1,906 m、1:1 ≈ 1,430 m,随画布 aspect 变);相机离地高度 h ≥ 正下方地形 + 10 m(不足时夹 range,不夹 pitch、不动 pivot);pitch 不参与收紧;侧视露出的范围外交给 07 的雾气。该图的 home 预设超标 5.8× 冲突归其票 03(尚未 resolved)。
  5. 中心高程口径:票 30 已把「家」的高程改成 sampleTerrainMostDetailed 实测(沅陵实测 111.6 m);票 10 的走查实测「贴地标记与高度 0 的中心差约 30px 的地形高程差」—— 即中心取椭球 0 还是实测地形,肉眼可见。
  6. 相机状态已有只读出口:mapService.getCameraState()(pivot/hpr/focus/dragging/settled)与 formatCameraState() 写进宿主 dataset.camera,DEV 下另有 __cockpitMap.projectCameraPivot() —— 断言口径现成,不必新造。

第 1 轮四问已发维护者:Q1「看清」的验收判据 / Q2 定位机制(只换中心还是连 hpr 一起换)/ Q3 与主场景区限位的关系与优先级 / Q4 与票 30 归位的职责边界。

2026-09-18 第 2 轮:Q1–Q4 答复已收,frontier 重算

维护者答复:Q1=A(点位级定位须能看到该点位下所有设备点位)、Q2=A(定位=中心 + hpr 一起换)、Q3=A(定位不设例外、落在限位内)、Q4=A(定位不改 home、归位永远回 home、无历史栈)。已写入 ## Answer 第 1 轮。

第 2 轮四问已发维护者:Q5 点位级定位的 hpr 数值(heading/pitch/range 与配置入口)/ Q6 是否在本票定义「设备级」第二档视角供票 06 引用(需求⑤「定位到设备」)/ Q7 取消选中与关闭面板后镜头是否回退 / Q8 ADR 0008 与决策地图票 04 的改后原文。

2026-09-18 跨图提示:主场景区限位数值已更新(03 取代 02 锚点)

cockpit-primary-area-guardrails 的 03(限位与既有相机契约的合成 + 进出状态机)已收口 Answer(维护者 Q1–Q5 + R2-1…R2-6 确认),其中一项取代本票事实 #4 引用的数值:

  • 旧(02):range_max = 1651 / (2·tan(fovY/2)) ≈ 2,542 m(16:9),随画布 aspect 变。
  • 新(03):range_max = home.range = 12,000 m —— 最远视野 = 归位默认视角;home 预设不改;pitch 不参与区域收紧;防入地 h ≥ 正下方地形 + 10 m(不足夹 range)不变。

本票 Q3「与主场景区限位合成(不设例外、落在限位内)」结论仍然成立,只是取值按 12,000 m 而非 2,542 m。后续实现以 .scratch/cockpit-primary-area-guardrails/issues/03 与其 docs/adr/0009 为准。雾的门控与 areaState 输入契约见该图 07(open)。

2026-09-18 第 3 轮:Q5–Q8 答复已收,待最终确认

维护者答复:Q5=a(点位级 0/−55/500,配置可改)、Q6=a(两档,设备级 0/−55/150,配置可改)、Q7=a(取消选中/关闭不回退)、Q8=a(ADR 0008 原位修订 + 票 04 同步,按第 2 轮拟文)。已写入 ## Answer 第 2 轮;跨图修正(guardrails 03 的 range_max = 12,000 m)已核实并入 Answer。

2026-09-18 第 4 轮:独立复审 + 收口

按维护者要求做独立只读复审(全新上下文子代理,只读不改文件),发现并并入 ## Answer:① 中心高程口径补答(取实测地形、不取椭球 0 —— 否则破坏 Q1=A 的点位居中验收,150/120 m 档贴地/入地);② ADR 0008 与票 04 的改后原文全文落票面(此前只引用未落全文);③ 断言口径去冗余(settled 的 1e-7° 已含 pivot)并补 height 断言;④ 「±200 m」复核口补推导;⑤ 全球态点选定位不进区记为已知边界(guardrails 03 状态机,本票不裁决)。

维护者确认收口:Status: claimed → resolved、进度 100%。下游落盘已执行:ADR 0008 原位修订、决策地图票 04 同步、CONTEXT.md 补「定位 / 归位」、本图 Decisions so far + 进度 + 清雾区。按维护者要求,本票结论另以 /to-spec 固化为 .scratch/cockpit-point-locate-and-device-link/spec.md。