Files
Aislo/B04_wf1_Surface/B04_wf1_Surface_UI_Camera.ts
T
2026-07-17 17:26:11 +09:00

43 lines
1.6 KiB
TypeScript

import type { SurfaceBounds } from "./B04_wf1_Surface_Api_Fetch";
export const SURFACE_CAMERA_FOV = 50;
export interface SurfaceCameraState {
direction: [number, number, number];
distanceMeters: number;
targetMeters: [number, number, number];
}
export function getReferenceCenter(bounds: SurfaceBounds): [number, number, number] {
return [
(bounds.x_min + bounds.x_max) / 2,
(bounds.y_min + bounds.y_max) / 2,
(bounds.z_min + bounds.z_max) / 2,
];
}
export function getTopFitDistance(bounds: SurfaceBounds, aspect: number): number {
const width = Math.max(bounds.x_max - bounds.x_min, 1);
const depth = Math.max(bounds.y_max - bounds.y_min, 1);
const verticalFov = (SURFACE_CAMERA_FOV * Math.PI) / 180;
const horizontalFov = 2 * Math.atan(Math.tan(verticalFov / 2) * Math.max(aspect, 0.1));
const verticalDistance = depth / (2 * Math.tan(verticalFov / 2));
const horizontalDistance = width / (2 * Math.tan(horizontalFov / 2));
return Math.max(verticalDistance, horizontalDistance, 1) * 1.12;
}
export function targetPlaneMetersPerPixel(distanceMeters: number, viewportHeight: number): number {
const verticalFov = (SURFACE_CAMERA_FOV * Math.PI) / 180;
return (
(2 * Math.tan(verticalFov / 2) * Math.max(distanceMeters, 0.001)) / Math.max(viewportHeight, 1)
);
}
export function niceScaleDistance(roughMeters: number): number {
const exponent = Math.floor(Math.log10(Math.max(roughMeters, 0.001)));
const base = 10 ** exponent;
const normalized = roughMeters / base;
const step = normalized <= 1 ? 1 : normalized <= 2 ? 2 : normalized <= 5 ? 5 : 10;
return step * base;
}