import * as THREE from 'three'; import { describe, expect, it } from 'vitest'; import { fitCamera } from '../src/view/fit'; describe('카메라 맞춤 (전체 모델이 화면에 들어옴)', () => { const sphere = new THREE.Sphere(new THREE.Vector3(10, 30, 0), 50); it('the target moves to the sphere centre and the sphere lies inside the view cone', () => { const cam = fitCamera(new THREE.Vector3(1, 1, 1).multiplyScalar(20), new THREE.Vector3(), sphere, 40, 1.6); expect(cam.target.distanceTo(sphere.center)).toBeLessThan(1e-9); // The distance from the camera to the centre must cover the radius at the vertical half-angle. const d = cam.position.distanceTo(sphere.center); expect(d * Math.sin(THREE.MathUtils.degToRad(20))).toBeGreaterThanOrEqual(sphere.radius - 1e-6); }); it('a narrow window (aspect < 1) backs off further than a wide one', () => { const wide = fitCamera(new THREE.Vector3(0, 0, 100), new THREE.Vector3(), sphere, 40, 2); const narrow = fitCamera(new THREE.Vector3(0, 0, 100), new THREE.Vector3(), sphere, 40, 0.5); expect(narrow.position.distanceTo(sphere.center)).toBeGreaterThan(wide.position.distanceTo(sphere.center)); }); it('a camera already far enough keeps its distance', () => { const far = new THREE.Vector3(0, 0, 1000); const cam = fitCamera(far, new THREE.Vector3(), sphere, 40, 1.6); // The distance is kept from the old target (origin): 1000 m, measured from the new centre. expect(cam.position.distanceTo(sphere.center)).toBeCloseTo(1000, 6); }); });