# 30: 进入系统的引导与视角预设(星球自转 + 点击进入 + 快速归位) **What to build:** 进入 `/cockpit` 时先看到一个自转的星球与中央闪烁的「点击进入系统」提示;点击后镜头飞到目标城市(沅陵县 110.39028164, 28.44367870)的预设视角;进入后有一个按钮可随时一键归位到该视角。视角坐标与intro开关都由部署配置给,不硬编码在组件里。 (本票来自维护者 2026-09-17 反馈:「当前我完全找不到目标位置,无法判断 DEM 及精细影像是否成功部署」+ 明确要求自转星球/点击进入/归位按钮。原先没有任何票覆盖「进入系统的引导体验」与「命名视角预设」;票 03 只管三键输入契约,票 21 只管资源加载,故独立成票。) Blocked by: 03, 21 Status: resolved Labels: ready-for-agent > 请勿据标签重复接单:本票已完成并有关闭记录,`Labels` 保留只是为了让面板不把它退化成 `needs-triage`。 ## 依赖与事实 - 相机契约与引擎都已就绪:票 03(三键输入 + `cameraControl`)、票 21(地形/影像已接上)。 - **地形感知的拾取**是本票顺手做掉的前置动作:原先中心点走 `pickEllipsoid`(纯椭球,高程 0), 而沅陵县城地面高程一百多米起,所以拉近后相机会落进山体、画面全黑。本票: ① `pickGroundAtCenter()` 用 `globe.getHeight` 把拾取点抬到真实地表; ② 地形就绪后用 `sampleTerrainMostDetailed` 采样「家」视角的**实测高程**,写进预设。 实测:拉到距离下限 120 m 时中心高程 111.6 m(不再是 0),近景截图内容丰富(约 1 MB),**不再黑屏**。 - 坐标口径:维护者给的 `110.39028164, 28.44367870` 是 **CGCS2000 · 天地图**坐标(与 WGS-84 在本项目精度下一致)。 ## 验收 - [x] 进入 `/cockpit` 先看到**自转的星球**(不是静止球),且中央有**闪烁的「点击进入系统」**提示。 - [x] 点击后镜头**飞到沅陵县预设视角**(默认 `110.39028164, 28.44367870`,可被配置覆盖),落点与目标坐标一致(走查实测误差 `1.4e-14°`)。 - [x] 进入后有**快速归位按钮**(顶栏「归位」):平移/缩放后点它回到同一预设视角(中心、heading、pitch、range 都回;走查实测距离误差 0)。 - [x] 预设视角与 intro 开关**由配置给**(`map.home` / `map.intro`),组件里不硬编码坐标。 - [x] 引导层不影响既有验收:`intro.enabled=false` 可直接进系统(其它票走查用它自隔离);进入后外壳与地图行为不变。 - [x] 近景不黑屏:地形加载后拉到公里级/下限仍能看到地面(地形感知拾取生效)。 - [x] 有纯逻辑断言(`verify/t30-view-presets.mjs`)与真机走查记录(`verify/t30-intro-walkthrough.mjs` 7/7)。 ## 进度:100% **已完成并关闭(2026-09-17)。** 维护者「完全找不到目标位置、无法判断 DEM 与影像是否部署成功」的问题解决了: 进系统就是自转星球 + 点击进入 → 落到沅陵县城上空 12 km(县域级),顶栏「归位」随时回到该视角。 ### 改动 - 新增 `domain/viewPresets.js`(纯函数):`planHome()` / `planIntro()` 计划层、`homeLabel()` 文案、`isAtHome()` 归位判定(含容差与 heading 环绕)。 - 新增 `components/CockpitIntro.vue`:全屏引导层(点击/Enter/Space 进入、闪烁文案、`prefers-reduced-motion` 时不动画)。 - `services/cameraControl.js`:新增 `applyViewPreset(pivot, hpr, { immediate })` —— 整段视角(中心 + heading/pitch/range)一次到位,与票 03 的 `setFocus()`(只换中心、保持距离)区分开。 - `services/mapService.js`:`getHomeView()` / `goHome()` / `atHome()` / `setGlobeSpin()`;**自转与飞行互斥**(飞行前先 `stopSpin()` 并置 `spinPaused`,否则自转每帧 `immediate` 写中心会把飞行目标冲掉 —— 实测踩过);`getLifecycleStats()` 增 `spin`。 - `services/cesiumEngine.js`:`pickGroundAtCenter()` 改为地形感知(`globe.getHeight`);新增 `sampleTerrainHeight()`(`sampleTerrainMostDetailed`)。 - `services/cockpitConfig.js`:`map.home{lon,lat,height,heading,pitch,range,label}` 与 `map.intro{enabled,title,subtitle,spinSeconds}` 的归一化与校验。 - `CockpitShell.vue`:引导层挂载 + 顶栏「归位」按钮(`data-home-at` 供走查)+ 进入/归位都要等引擎就绪(重试到相机接上)。 - `public/cockpit/config.json`:本机配置补上 `home`(沅陵 110.39028164, 28.4436787,pitch -55,range 12 km)与 `intro`;`config.example.json` 同步补该两节与说明。 ### 验证证据(`yarn dev` @ 8001,Chrome 152 headless) - 纯逻辑 `t30-view-presets.mjs`:通过(默认值、归一化含三处错字段 issue、预设解析、`homeLabel` 文案、归位判定含 heading 360≡0 与「无相机状态」、并与本机配置的沅陵坐标对齐核对)。 - 真机走查 `t30-intro-walkthrough.mjs` → **7/7**:引导层在位且闪烁动画生效(`animationName` 非 none);**星球确实在自转**(2.6 s 内中心经度 Δ≈-19.6°);点击后引导消失且**镜头落在沅陵**(Δlon 1.4e-14°,Δlat 0,range 12 km);进入后**自转停止**(2 s 内零漂移);手动平移+缩放推离后按钮显示未在家,点「归位」回到同一视角(中心误差 1.4e-14°、距离误差 0)且按钮显示已在家;全程无页面级报错。 - 视觉:引导页(自转星球 + 「点击进入系统」)与进入后(沅陵县城 12 km,河道/桥/地形起伏,顶栏有「归位」)。 - 近景回归:拉到距离下限 120 m 时中心高程 **111.6 m**(地形感知生效),近景截图约 1 MB(内容非纯黑)。 —— 注:先前用 `drawImage(canvas)` 读回判定「黑屏」是**测错了**:WebGL 默认 `preserveDrawingBuffer:false`, 读回永远全黑;改用 CDP 截图判定。 - 回归:`t01` 走查 **20/20**、`t04` **9/9**、`t29` **6/6**、`t21` **9/9**、`t28` **7/7**; 8 个逻辑脚本(t01/t03/t04/t06/t21/t28/t29/t30)全通过;`yarn build` exit 0。 - 兼容处理:票 30 起 `/cockpit` 默认有引导层(z-index 20,进入前挡住交互),所以 `t01` 与 `t21` 的走查 显式注入 `intro:{enabled:false}`(它们是测「进入之后」的行为)——这是配置开关的正当用法,不是绕过断言。 ### 遗留 - 引导层目前是**每次进入 `/cockpit` 都显示**(刷新即重生)。要不要"记住已进入"(localStorage)由维护者定; 加的话是一行判断,但会影响走查的可重复性,故未擅自加。 - 「自转」是绕地轴推进中心经度实现的(因为 `cameraControl` 每帧 `lookAtTransform` 会覆盖直接转相机); 观感是星球自转,但严格说转的是相机。若将来要真正的"地球自转"(经纬网动、相机不动),需另立票。 - **(2026-09-24 维护者新增要求,来自票 08 原型验收)进入前地球视图不得出现业务点位**:最初的地球引导视图 只展示地球整体形态,不展示监测点、设备点位或点位详情;点击「点击进入系统」后才挂载/显示业务点位。 本票当时的验收只覆盖「引导层在场、自转、落点、归位」,未覆盖"引导期间摘要标记是否已画"——原型走查发现 引导期间地图标记已可被画出,与本要求不符。实现归属:摘要标记的挂载时机归本图的地图摘要实现票; 「什么时候显示什么」的完整矩阵归 `.scratch/cockpit-point-locate-and-device-link` 票 13。本条在此留档,不改变本票已验收范围。