| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111 |
- /**
- * T30 进入引导与视角预设 纯逻辑检查。
- *
- * 覆盖:`map.home` / `map.intro` 的归一化与默认值;预设视角解析;归位判定 `isAtHome()` 的容差与
- * 经度环绕;以及「配置里那组沅陵坐标」确实被解析成预期值(防止手抄坐标时写错)。
- *
- * 运行:node .scratch/cockpit-shell-panel-layout/verify/t30-view-presets.mjs
- */
- import assert from 'node:assert/strict'
- import { existsSync, readFileSync } from 'node:fs'
- import {
- HOME_DEFAULTS,
- INTRO_DEFAULTS,
- homeLabel,
- isAtHome,
- planHome,
- planIntro,
- } from '../../../src/modules/cockpit/domain/viewPresets.js'
- import { builtinConfig, normalizeConfig } from '../../../src/modules/cockpit/services/cockpitConfig.js'
- // ---------------------------------------------------------------- 1. 默认值
- const defaults = planHome({})
- assert.equal(defaults.lon, HOME_DEFAULTS.lon, '缺省经度应回落到默认(沅陵)')
- assert.equal(defaults.lat, HOME_DEFAULTS.lat, '缺省纬度应回落到默认')
- assert.ok(defaults.range > 1000, '默认距离应是县域级(>1km)')
- assert.ok(defaults.pitch < 0, '默认俯角应为负(从上往下看)')
- const introDefaults = planIntro({})
- assert.equal(introDefaults.enabled, true, '默认开启引导')
- assert.equal(introDefaults.title, INTRO_DEFAULTS.title, '默认文案')
- assert.ok(introDefaults.spinSeconds > 0, '默认开启自转')
- // ---------------------------------------------------------------- 2. 归一化
- const normalized = normalizeConfig({
- map: {
- home: { lon: 110.39028164, lat: 28.4436787, pitch: -55, range: 12000, label: '沅陵县城' },
- intro: { enabled: false, title: '进入', spinSeconds: 0 },
- },
- })
- assert.equal(normalized.config.map.home.lon, 110.39028164, '经度应透传(不丢精度)')
- assert.equal(normalized.config.map.home.lat, 28.4436787, '纬度应透传')
- assert.equal(normalized.config.map.home.label, '沅陵县城', '标签应透传')
- assert.equal(normalized.config.map.intro.enabled, false, '引导开关应透传')
- assert.equal(normalized.config.map.intro.spinSeconds, 0, '自转秒数应透传')
- const badTypes = normalizeConfig({ map: { home: { lon: '东经110', pitch: {} }, intro: { enabled: 'yes' } } })
- assert.equal(badTypes.config.map.home.lon, null, '非数字经度应为 null(回落默认)')
- assert.equal(badTypes.config.map.home.pitch, null, '非数字俯角应为 null')
- assert.equal(badTypes.config.map.intro.enabled, true, '非布尔开关应回落默认 true')
- assert.equal(badTypes.issues.length, 3, `三个错字段各记一条 issue,实际 ${JSON.stringify(badTypes.issues)}`)
- // ---------------------------------------------------------------- 3. 计划层
- const home = planHome({ home: { lon: 110.5, lat: 28.5, heading: 30, pitch: -40, range: 5000 } })
- assert.equal(home.lon, 110.5, '配置优先')
- assert.equal(home.heading, 30, 'heading 透传')
- assert.equal(home.range, 5000, 'range 透传')
- assert.equal(home.label, '目标区域', '没给 label 时有默认文案')
- const introOff = planIntro({ intro: { enabled: false } })
- assert.equal(introOff.enabled, false, '可关闭引导(走查自隔离用)')
- assert.equal(planIntro({ intro: { spinSeconds: -5 } }).spinSeconds, 0, '负数自转秒数应夹到 0')
- // label 文案:归位按钮的 tooltip 用它,必须带上坐标
- const label = homeLabel({ lon: 110.39028164, lat: 28.4436787, label: '沅陵县城' })
- assert.match(label, /沅陵县城/, '标签应含地名')
- assert.match(label, /110\.3903/, '标签应含经度(4 位小数)')
- assert.match(label, /28\.4437/, '标签应含纬度(4 位小数)')
- // ---------------------------------------------------------------- 4. 归位判定
- const homeRef = { lon: 110.39028164, lat: 28.4436787, heading: 0, pitch: -55, range: 12000 }
- const atHomeState = { pivot: { lon: 110.39028164, lat: 28.4436787, height: 0 }, hpr: { heading: 0, pitch: -55, range: 12000 } }
- assert.equal(isAtHome(atHomeState, homeRef), true, '同一视角应判为在家')
- assert.equal(
- isAtHome({ pivot: { lon: 110.4, lat: 28.44 }, hpr: { heading: 0, pitch: -55, range: 12000 } }, homeRef),
- false,
- '中心偏出容差(>1e-4°)不应判为在家',
- )
- assert.equal(
- isAtHome({ pivot: atHomeState.pivot, hpr: { heading: 0, pitch: -55, range: 30000 } }, homeRef),
- false,
- '距离差太多不应判为在家',
- )
- assert.equal(
- isAtHome({ pivot: atHomeState.pivot, hpr: { heading: 0, pitch: -20, range: 12000 } }, homeRef),
- false,
- '俯角差太多不应判为在家',
- )
- // 经度环绕:heading 0 与 360 是同一个朝向
- assert.equal(
- isAtHome({ pivot: atHomeState.pivot, hpr: { heading: 360, pitch: -55, range: 12000 } }, homeRef),
- true,
- 'heading 360 等价于 0(经度/朝向环绕)',
- )
- assert.equal(isAtHome(null, homeRef), false, '没有相机状态时不应判为在家')
- // ---------------------------------------------------------------- 5. 与真实配置对齐(本机)
- const configPath = new URL('../../../public/cockpit/config.json', import.meta.url)
- if (existsSync(configPath)) {
- const raw = JSON.parse(readFileSync(configPath, 'utf8'))
- const { config } = normalizeConfig(raw)
- const actual = planHome(config.map)
- assert.equal(actual.lon, 110.39028164, '配置里的经度应等于维护者给的沅陵坐标')
- assert.equal(actual.lat, 28.4436787, '配置里的纬度应等于维护者给的沅陵坐标')
- assert.ok(config.map.intro.enabled !== false, '本机配置应开启进入引导')
- console.log(` (已按本机配置核对:home=${actual.lon}, ${actual.lat} label=${actual.label} intro=${config.map.intro.enabled})`)
- }
- console.log(
- 'T30 检查通过:home/intro 默认值与归一化(含错字段 issue)、预设解析与 label 文案、归位判定(容差 + heading 环绕 + 无状态),并与本机配置里的沅陵坐标对齐核对。',
- )
|