| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115 |
- import assert from 'node:assert/strict'
- import { readFileSync } from 'node:fs'
- import vm from 'node:vm'
- import * as Cesium from 'cesium'
- import { enhancementSelection, PIPE_ENHANCEMENT_KIND, planPipeEnhancement } from '../../../src/modules/cockpit/domain/pipeEnhancement.js'
- import { mountPipeEnhancement } from '../../../src/modules/cockpit/services/threePipeEnhancement.js'
- import { createPinia, setActivePinia } from 'pinia'
- import { usePipeEnhancementStore } from '../../../src/modules/cockpit/stores/pipeEnhancementStore.js'
- setActivePinia(createPinia())
- const enhancementStore = usePipeEnhancementStore()
- const pipe = { code: 'P-001', name: '城南燃气管段', industry: 'GAS', diameter: 160, material: '钢', positions: [[110.1, 28.4], [110.101, 28.401]] }
- const component = { code: 'V-001', name: '城南阀门', industry: 'GAS', kind: 'valve', position: [110.1, 28.4] }
- const base = { visiblePipes: [pipe], visibleComponents: [component] }
- let checks = 0
- function check(name, fn) { checks += 1; fn(); console.log(`PASS ${name}`) }
- check('Pinia store 持有并清理局部增强选择', () => {
- enhancementStore.select(PIPE_ENHANCEMENT_KIND.PIPE, 'P-001')
- assert.equal(enhancementStore.selected.kind, PIPE_ENHANCEMENT_KIND.PIPE)
- assert.equal(enhancementStore.selected.code, 'P-001')
- enhancementStore.clear()
- assert.equal(enhancementStore.selected, null)
- })
- check('没有选中对象时不创建增强计划', () => {
- assert.equal(planPipeEnhancement(base).visible, false)
- assert.equal(planPipeEnhancement(base).reason, 'no-selection')
- })
- check('局部计划只保留当前被选中的管段', () => {
- const plan = planPipeEnhancement({ ...base, selected: enhancementSelection(PIPE_ENHANCEMENT_KIND.PIPE, 'P-001') })
- assert.equal(plan.visible, true)
- assert.equal(plan.object.code, 'P-001')
- assert.equal(plan.object.path.length, 2)
- assert.match(plan.disclaimer, /不代表工程竣工模型/)
- })
- check('筛选移除对象时增强视图自动不可见', () => {
- const plan = planPipeEnhancement({ selected: enhancementSelection('pipe', 'P-001'), visiblePipes: [] })
- assert.equal(plan.visible, false)
- assert.equal(plan.reason, 'object-not-visible')
- })
- check('构件计划保留构件类型但不伪造管径', () => {
- const plan = planPipeEnhancement({ ...base, selected: enhancementSelection(PIPE_ENHANCEMENT_KIND.COMPONENT, 'V-001') })
- assert.equal(plan.visible, true)
- assert.equal(plan.object.renderKind, 'valve')
- assert.equal(plan.object.diameter, null)
- })
- check('未知选择类型被拒绝而不是默认成管段', () => {
- const plan = planPipeEnhancement({ ...base, selected: { kind: 'foreign', code: 'P-001' } })
- assert.equal(plan.visible, false)
- assert.equal(plan.reason, 'invalid-selection')
- })
- class Canvas {
- constructor() { this.listeners = new Map(); this.parentNode = null }
- addEventListener(name, fn) { this.listeners.set(name, fn) }
- removeEventListener(name) { this.listeners.delete(name) }
- }
- class Host {
- constructor() { this.clientWidth = 320; this.clientHeight = 220; this.children = []; this.ownerDocument = { createElement: () => new Canvas() } }
- appendChild(node) { node.parentNode = this; this.children.push(node) }
- removeChild(node) { this.children = this.children.filter((item) => item !== node); node.parentNode = null }
- }
- function rendererFactory({ canvas }) {
- const domElement = canvas || new Canvas()
- return { domElement, setPixelRatio() {}, setSize() {}, render() {}, dispose() {} }
- }
- check('渲染服务支持相同编码但不同对象类型的替换', () => {
- const host = new Host()
- const first = planPipeEnhancement({ ...base, selected: enhancementSelection('pipe', 'P-001') })
- const viewer = mountPipeEnhancement(host, first, { rendererFactory })
- const sameCodeComponent = { ...component, code: 'P-001' }
- const second = planPipeEnhancement({ visiblePipes: [pipe], visibleComponents: [sameCodeComponent], selected: enhancementSelection('component', 'P-001') })
- viewer.sync(second)
- assert.equal(viewer.getState().title, '地下管线详情视图 · 构件')
- assert.equal(viewer.getState().code, 'P-001')
- viewer.destroy()
- assert.equal(viewer.getState().status, 'destroyed')
- })
- const engineSource = readFileSync(new URL('../../../src/modules/cockpit/services/cesiumEngine.js', import.meta.url), 'utf8')
- const engineCode = engineSource
- .replace(/^import\s+[^]*?from\s+['"][^'"\n]+['"][ \t]*$/gm, '')
- .replace(/^import\s+['"][^'"\n]+['"][ \t]*$/gm, '')
- .replace(/^export /gm, '')
- const engineContext = vm.createContext({ ...Cesium, CesiumMath: Cesium.Math })
- vm.runInContext(`${engineCode}\nglobalThis.pipePicker = pickPipeObjectAt;`, engineContext)
- const pipeSource = new Cesium.CustomDataSource('cockpit-pipelines')
- const entity = pipeSource.entities.add({ id: 'pipe:P-001', properties: { kind: 'pipe', code: 'P-001' } })
- let picked = { id: entity }
- const pickViewer = {
- dataSources: { getByName: (name) => name === 'cockpit-pipelines' ? [pipeSource] : [] },
- canvas: { getBoundingClientRect: () => ({ left: 20, top: 30 }) },
- scene: { pick: () => picked },
- }
- check('Cesium entity pick returns the selected pipeline identity', () => {
- const hit = engineContext.pipePicker(pickViewer, 120, 230)
- assert.equal(hit.kind, 'pipeline')
- assert.equal(hit.code, 'P-001')
- assert.equal(hit.objectKind, 'pipe')
- })
- check('GPU instance pick resolves instanceId instead of batch first item', () => {
- picked = { id: { kind: 'pipe-model-batch', instances: ['pipe:P-001', 'component:V-001'] }, instanceId: 1 }
- const hit = engineContext.pipePicker(pickViewer, 120, 230)
- assert.equal(hit.kind, 'pipeline')
- assert.equal(hit.code, 'V-001')
- assert.equal(hit.objectKind, 'component')
- picked = { id: { kind: 'pipe-model-batch', instances: ['pipe:P-001'] }, instanceId: 7 }
- assert.equal(engineContext.pipePicker(pickViewer, 120, 230), null)
- })
- console.log(`T23 Three.js enhancement: ${checks}/${checks}`)
|