feat(B05): 3D 화면 검증용 카메라 이동 창구 추가
- `__corridorScene.lookAt(x, y, z, distance, view)` — 모델 좌표 한 점으로 카메라를 바로 보냄. 측점 확인을 마우스 휠·드래그로 하면 한 번에 20~30초가 걸리고 우클릭이 구조물 메뉴를 여는 문제 해소. - `fit()` 의 카메라 배치를 `placeCamera()` 로 공용화 — 뷰 4종(iso/top/front/side) 위치·근평면·직교 반높이 계산이 한 곳.
This commit is contained in:
@@ -26,6 +26,8 @@ import { TerrainHeightIndex } from "./B05_Profile_UI_Corridor_Terrain";
|
||||
import { buildPatchSkirts } from "./B05_Profile_UI_Corridor_Skirt";
|
||||
import { BAND_MARGIN_M, TerrainBandSplit, type SceneBox } from "./B05_Profile_UI_Corridor_Split";
|
||||
|
||||
type ViewKind = "iso" | "top" | "front" | "side";
|
||||
|
||||
const LIGHT_VIEWER_BACKGROUND = 0xf5f7fa;
|
||||
const DARK_VIEWER_BACKGROUND = 0x251f38;
|
||||
|
||||
@@ -207,6 +209,13 @@ export function createRouteViewer(): RouteViewer {
|
||||
toScene: (x: number, y: number, z: number) =>
|
||||
bounds ? modelToScene({ x, y, z }, bounds) : null,
|
||||
topZ: () => (bounds ? bounds.z[1] + 100 : null),
|
||||
// 카메라를 모델 좌표 한 점으로 바로 보낸다 — 측점 확인을 마우스 휠·드래그로 하면
|
||||
// 한 번에 20~30초가 걸리고 우클릭이 구조물 메뉴를 연다(2026-09-02). 화면 검증 전용.
|
||||
lookAt: (x: number, y: number, z: number, distance: number, view: ViewKind = "top") => {
|
||||
if (!bounds) return false;
|
||||
placeCamera(modelToScene({ x, y, z }, bounds), distance, view);
|
||||
return true;
|
||||
},
|
||||
};
|
||||
const markers = createRouteMarkers(scene, () => bounds, terrainElevation);
|
||||
// 회전·줌 중심을 커서 아래 지형 지점으로 (B04 뷰어들과 공용 유틸).
|
||||
@@ -234,12 +243,8 @@ export function createRouteViewer(): RouteViewer {
|
||||
const resizeObserver = new ResizeObserver(resize);
|
||||
resizeObserver.observe(root);
|
||||
|
||||
function fit(view: "iso" | "top" | "front" | "side" = "top"): void {
|
||||
if (!bounds) return;
|
||||
const width = bounds.x[1] - bounds.x[0];
|
||||
const depth = bounds.y[1] - bounds.y[0];
|
||||
const distance = Math.max(width, depth, 20) * 1.35;
|
||||
controls.target.set(0, 0, 0);
|
||||
function placeCamera(target: THREE.Vector3, distance: number, view: ViewKind): void {
|
||||
controls.target.copy(target);
|
||||
const positions = {
|
||||
iso: [distance, distance, distance],
|
||||
// 정확히 수직이면 lookAt이 화면 방향을 못 정해 첫 드래그에 화면이 뒤집힌다.
|
||||
@@ -248,7 +253,7 @@ export function createRouteViewer(): RouteViewer {
|
||||
side: [distance, distance * 0.25, 0],
|
||||
} as const;
|
||||
const [x, y, z] = positions[view];
|
||||
camera.position.set(x, y, z);
|
||||
camera.position.set(target.x + x, target.y + y, target.z + z);
|
||||
camera.near = Math.max(0.1, distance / 1000);
|
||||
camera.far = distance * 10;
|
||||
// 원근 45°(반각 tan ≈ 0.414)와 비슷한 화면 배율 — 뷰 전환 시 크기감이 유지된다.
|
||||
@@ -256,6 +261,13 @@ export function createRouteViewer(): RouteViewer {
|
||||
controls.update();
|
||||
}
|
||||
|
||||
function fit(view: ViewKind = "top"): void {
|
||||
if (!bounds) return;
|
||||
const width = bounds.x[1] - bounds.x[0];
|
||||
const depth = bounds.y[1] - bounds.y[0];
|
||||
placeCamera(new THREE.Vector3(0, 0, 0), Math.max(width, depth, 20) * 1.35, view);
|
||||
}
|
||||
|
||||
async function reloadContours(interval: number): Promise<void> {
|
||||
if (!current || !bounds) return;
|
||||
current.interval = interval;
|
||||
|
||||
Reference in New Issue
Block a user