import * as THREE from 'three'; import { describe, expect, it } from 'vitest'; import { buildPier, type PierModel } from '../src/core/geometry'; import { buildAllPiers, pierOffset } from '../src/view/all-piers'; import { loadP1 } from './helpers'; const model = buildPier(loadP1()); describe('pierOffset', () => { it('is zero for the reference pier', () => { expect(pierOffset(model.pivot, model.pivot)).toEqual({ x: 0, z: 0 }); }); it('moves east by the E difference and north by the N difference (z = −N)', () => { const ref = { e: 259865, n: 179138 }; const other = { e: 260117, n: 179177 }; expect(pierOffset(other, ref)).toEqual({ x: 252, z: -39 }); }); }); describe('buildAllPiers', () => { it('places a pier at the same world box whatever pivot it is built around', () => { // The same pier with its pivot shifted: the geometry shifts by the opposite amount, so the world box must not change. const shifted: PierModel = { ...model, pivot: { e: model.pivot.e + 50, n: model.pivot.n - 20 } }; const all = buildAllPiers([{ name: 'P1', model }, { name: 'P2', model: shifted }]); all.piers.updateMatrixWorld(true); const a = new THREE.Box3().setFromObject(all.scenes.get('P1')!.root); const b = new THREE.Box3().setFromObject(all.scenes.get('P2')!.root); // Float32 geometry: allow 0.1 mm. expect(b.min.distanceTo(a.min)).toBeLessThan(1e-4); expect(b.max.distanceTo(a.max)).toBeLessThan(1e-4); }); it('keeps each pier 지반고 line without terrain, and hides it when the shared terrain is drawn', () => { const without = buildAllPiers([{ name: 'P1', model }]); expect([...without.scenes.keys()]).toEqual(['P1']); expect(without.scenes.get('P1')!.parts.ground.visible).toBe(true); expect(without.terrain).toBeNull(); expect(without.view.size).toBeGreaterThan(0); const withTerrain = buildAllPiers([{ name: 'P1', model }], { origin: [259815.676, 179088.094], step: 5, nx: 2, ny: 2, z: [30, 31, 32, 33] }); expect(withTerrain.scenes.get('P1')!.parts.ground.visible).toBe(false); expect(withTerrain.terrain).not.toBeNull(); }); it('keeps pier ground pads visible when the imported terrain grid has no complete cells', () => { const all = buildAllPiers([{ name: 'P1', model }], { origin: [259815.676, 179088.094], step: 5, nx: 2, ny: 2, z: [null, null, null, null], }); expect(all.terrain).toBeNull(); expect(all.scenes.get('P1')!.parts.ground.visible).toBe(true); }); it('uses the imported ground elevation for each pier fallback pad', () => { const all = buildAllPiers([{ name: 'P1', model, groundEl: 31.25 }]); const pad = all.scenes.get('P1')!.parts.ground.children[0] as THREE.Mesh; pad.geometry.computeBoundingBox(); expect(pad.geometry.boundingBox!.getCenter(new THREE.Vector3()).y).toBeCloseTo(31.25, 5); }); });