fix(view): 교대만 그려진 상태에서 정면·측면·평면 버튼이 동작하도록 함

- 원인: 교대를 고르면 교각 장면이 없어서 setView가 바로 반환. 정면 버튼이 아무 동작도 하지 않았음
- 교대만 보일 때는 교대 그룹의 좌표계(+x = 교대축, +z = 전면)에서 카메라 방향을 잡고, 보이는 교대 전체를 맞춤
- 테스트 640건 통과, 타입 검사·빌드 통과. 브라우저 시각 확인은 미실시

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
ypshimandClaude Haiku 5.5 committed 2026-11-03 17:37:43 +09:00
1 parent 686d87bad9
commit d3440e9158
1 file changed
+32 -2
+32 -2
View File
@@ -479,9 +479,12 @@ function setView(kind: ViewKind): void {
$('views-toggle').textContent = `${VIEWS.find((v) => v.kind === kind)?.label ?? ''} ▾`;
setMenuOpen('views', false);
const scene = allPiers ? allPiers.view : state.scene;
if (!scene) return;
const pier = activePier();
if (!pier?.model) return;
if (!scene || !pier?.model) {
// No pier is drawn (an abutment is selected in ②): the views follow the abutment's own frame (2026-11-03).
abutView(kind);
return;
}
const framed = viewPosition(scene, kind, pier.model);
// Keep the chosen view direction but fit every model (piers and abutments) in the window (2026-11-03).
const fitted = fitToModels(framed.position, framed.target);
@@ -490,6 +493,33 @@ function setView(kind: ViewKind): void {
controls.update();
}
/** Camera for the drawn abutments alone: the directions come from the abutment group (local +x = 교대축 IP1→IP3, +z = 전면). */
function abutView(kind: ViewKind): void {
const shown = abutGroups.filter((g) => g.visible);
if (shown.length === 0) return;
const box = new THREE.Box3();
for (const g of shown) {
g.updateWorldMatrix(true, true);
box.expandByObject(g);
}
const sphere = box.getBoundingSphere(new THREE.Sphere());
const ref = shown[0];
const axisX = new THREE.Vector3(1, 0, 0).transformDirection(ref.matrixWorld);
const front = new THREE.Vector3(0, 0, 1).transformDirection(ref.matrixWorld);
const lift = new THREE.Vector3(0, 0.15, 0);
const dirs: Record<ViewKind, THREE.Vector3> = {
iso: new THREE.Vector3(1, 0.7, 1).normalize(),
front: front.clone().add(lift).normalize(),
side: axisX.clone().add(lift).normalize(),
top: new THREE.Vector3(0, 1, 0.001).normalize(),
};
const target = sphere.center.clone();
const dist = sphere.radius * 2.6;
camera.position.copy(target.clone().add(dirs[kind].multiplyScalar(dist)));
controls.target.copy(target);
controls.update();
}
/** Bounding sphere of everything drawn (the piers or the all-piers view, plus the abutments) fitted to the camera. */
function fitToModels(position: THREE.Vector3, target: THREE.Vector3): { position: THREE.Vector3; target: THREE.Vector3 } {
const box = new THREE.Box3();