import assert from 'node:assert/strict' import * as THREE from 'three' import { planPipeEnhancement } from '../../../src/modules/cockpit/domain/pipeEnhancement.js' import { mountPipeEnhancement } from '../../../src/modules/cockpit/services/threePipeEnhancement.js' const manhole = { code: 'MH-1', sourceId: 'source-manhole', networkId: 'unknown-ref', industry: 'MANHOLE', kind: 'other', position: [110, 28], name: '真实窨井' } const nearby = { code: 'P', industry: 'DRAINAGE', networkLevel: 0, positions: [[109.9999, 28], [110.0001, 28]] } const plan = planPipeEnhancement({ selected: { kind: 'component', code: 'MH-1' }, visiblePipes: [nearby], visibleComponents: [manhole] }) assert.equal(plan.object.renderKind, 'manhole') assert.equal(plan.object.title, '真实窨井') assert.match(plan.connectionNote, /接管关系未提供/) assert.equal(plan.objects.length, 2) assert.equal(plan.object.stateText, '状态未提供') let scene const canvas = new EventTarget() const host = { clientWidth: 900, clientHeight: 500, appendChild(n) { n.parentNode = this }, removeChild(n) { n.parentNode = null } } const viewer = mountPipeEnhancement(host, plan, { rendererFactory: () => ({ domElement: canvas, setSize() {}, dispose() {}, render(s) { scene = s } }) }) assert.ok(scene.getObjectByName('manhole-shaft')) assert.ok(scene.getObjectByName('manhole-cover')) assert.ok(!scene.getObjectByName('invented-connection')) assert.ok(scene.getObjectByName('pipe-enhancement:P')) viewer.destroy() const isolated = planPipeEnhancement({ selected: { kind: 'component', code: 'MH-1' }, visibleComponents: [manhole] }) for (const position of [[110.0002, 28], [110, 28]]) { isolated.devices = [{ code: 'standalone', industry: 'WATER_SUPPLY', colorKey: 'WATER_SUPPLY', depthM: 4, slot: 0, position }] let isolatedCamera const next = mountPipeEnhancement(host, isolated, { rendererFactory: () => ({ domElement: canvas, setSize() {}, dispose() {}, render(s, c) { scene = s; isolatedCamera = c } }) }) const device = scene.getObjectByName('device:standalone') scene.updateMatrixWorld(true); isolatedCamera.updateMatrixWorld() const screen = device.getWorldPosition(new THREE.Vector3()).project(isolatedCamera) assert.ok(Math.abs(screen.x) < 1 && Math.abs(screen.y) < 1 && screen.z < 1, '井边独立设备须纳入相机可见范围') next.destroy() } console.log('PASS 无管线源时独立设备坐标及深度参与取景,设备模型不会落到远裁面外') const deep = planPipeEnhancement({ selected: { kind: 'pipe', code: 'deep' }, visiblePipes: [ { code: 'deep', industry: 'DRAINAGE', networkLevel: 1, positions: [[110, 28], [110.00001, 28]] }, ] }) deep.devices = [{ code: 'shallow', industry: 'GAS', colorKey: 'GAS', depthM: 1.5, slot: 0, position: [110, 28] }] let view const deepViewer = mountPipeEnhancement(host, deep, { rendererFactory: () => ({ domElement: canvas, setSize() {}, dispose() {}, render(s, camera) { scene = s; view = camera } }) }) scene.updateMatrixWorld(true); view.updateMatrixWorld() const projected = scene.getObjectByName('device:shallow').getWorldPosition(new THREE.Vector3()).project(view) assert.ok(Math.abs(projected.x) < 1 && Math.abs(projected.y) < 1 && projected.z > -1 && projected.z < 1, '浅层设备必须在初始视锥内') deepViewer.destroy() console.log('PASS 深层雨水管与浅层独立燃气设备三维居中,设备初始投影在视锥内') console.log('PASS 窨井身份计划 → 剖切井筒和井盖+邻近管道,不造接管/状态')