/** * Camera and orbit controls * * Uses composition pattern: delegates to CameraControls (orbit/pan/zoom), * CameraAnimator (transitions/inertia/presets), and CameraProjection * (screen-world conversion/bounds fitting). */ import type { Vec3, Mat4 } from './types.js'; import { type ProjectionMode } from './camera-controls.js'; import { type Bounds3, type FitPolicy } from './camera-fit-policy.js'; export declare class Camera { private state; private controls; private animator; private projection; constructor(); /** * Set camera aspect ratio */ setAspect(aspect: number): void; /** * Set camera position */ setPosition(x: number, y: number, z: number): void; /** * Set camera target */ setTarget(x: number, y: number, z: number): void; /** * Set camera up vector */ setUp(x: number, y: number, z: number): void; /** * Set camera field of view in radians */ setFOV(fov: number): void; /** * Set the orbit center without moving the camera. * Future orbit() calls will rotate around this point. * Pass null to revert to orbiting around camera.target. */ setOrbitCenter(center: Vec3 | null): void; /** * Orbit camera around the current pivot (Y-up coordinate system). * If orbitCenter is set, both position and target rotate around it. * Otherwise, position rotates around target (standard orbit). */ orbit(deltaX: number, deltaY: number, addVelocity?: boolean): void; /** * Pan camera (Y-up coordinate system) */ pan(deltaX: number, deltaY: number, addVelocity?: boolean): void; /** * Zoom camera towards mouse position * @param delta - Zoom delta (positive = zoom out, negative = zoom in) * @param addVelocity - Whether to add velocity for inertia * @param mouseX - Mouse X position in canvas coordinates * @param mouseY - Mouse Y position in canvas coordinates * @param canvasWidth - Canvas width * @param canvasHeight - Canvas height */ zoom(delta: number, addVelocity?: boolean, mouseX?: number, mouseY?: number, canvasWidth?: number, canvasHeight?: number, fastZoom?: boolean): void; /** * Fit view to bounding box * Sets camera to southeast isometric view (typical BIM starting view) * Y-up coordinate system: Y is vertical */ fitToBounds(min: Vec3, max: Vec3): void; /** * Update camera animation and inertia * Returns true if camera is still animating */ update(deltaTime: number): boolean; /** * Frame/center view on a point (keeps current distance and direction) * Standard CAD "Frame Selection" behavior */ framePoint(point: Vec3, duration?: number): Promise; /** * Frame selection - zoom to fit bounds while keeping current view direction * This is what "Frame Selection" should do - zoom to fill screen */ frameBounds(min: Vec3, max: Vec3, duration?: number): Promise; zoomExtent(min: Vec3, max: Vec3, duration?: number): Promise; /** * Apply a `FitPolicy` snapshot to the camera without animation. Used by * the post-load auto-fit where any in-flight tween would compete with * the streaming-complete frame and produce a visible camera jump. */ snapToFitPolicy(policy: FitPolicy): void; /** * Animate the camera to a `FitPolicy` pose. Used by the Home button so * the transition matches the rest of the navigation tweens. */ applyFitPolicy(policy: FitPolicy, duration?: number): Promise; /** * Convenience: pick + apply the adaptive fit policy for the given bounds * in one call. The default behaviour delegates to `pickFitPolicy()` so * callers don't have to thread the FOV through themselves. */ fitBoundsAdaptive(bounds: Bounds3, options?: { animate?: boolean; duration?: number; viewportShortPx?: number; }): FitPolicy; /** * Animate camera to position and target */ animateTo(endPos: Vec3, endTarget: Vec3, duration?: number): Promise; /** * Animate camera to position, target, and up vector (for orthogonal preset views) */ animateToWithUp(endPos: Vec3, endTarget: Vec3, endUp: Vec3, duration?: number): Promise; /** * Set first-person mode */ enableFirstPersonMode(enabled: boolean): void; /** * Move in first-person mode (Y-up coordinate system) */ moveFirstPerson(forward: number, right: number, up: number): void; /** * Set preset view with explicit bounds (Y-up coordinate system) * Clicking the same view again rotates 90 degrees around the view axis * @param buildingRotation Optional building rotation in radians (from IfcSite placement) */ setPresetView(view: 'top' | 'bottom' | 'front' | 'back' | 'left' | 'right', bounds?: { min: Vec3; max: Vec3; }, buildingRotation?: number): void; /** * Reset velocity (stop inertia) */ stopInertia(): void; /** * Reset camera state (clear orbit center, stop inertia, cancel animations) * Called when loading a new model to ensure clean state */ reset(): void; getViewProjMatrix(): Mat4; getPosition(): Vec3; getTarget(): Vec3; /** * Get camera up vector */ getUp(): Vec3; /** * Get camera FOV in radians */ getFOV(): number; /** * Get distance from camera position to target */ getDistance(): number; /** * Get current camera rotation angles in degrees * Returns { azimuth, elevation } where: * - azimuth: horizontal rotation (0-360), 0 = front * - elevation: vertical rotation (-90 to 90), 0 = horizon */ getRotation(): { azimuth: number; elevation: number; }; /** * Unproject screen coordinates to a ray in world space * @param screenX - X position in screen coordinates * @param screenY - Y position in screen coordinates * @param canvasWidth - Canvas width in pixels * @param canvasHeight - Canvas height in pixels * @returns Ray origin and direction in world space */ unprojectToRay(screenX: number, screenY: number, canvasWidth: number, canvasHeight: number): { origin: Vec3; direction: Vec3; }; /** * Project a world position to screen coordinates * @param worldPos - Position in world space * @param canvasWidth - Canvas width in pixels * @param canvasHeight - Canvas height in pixels * @returns Screen coordinates { x, y } or null if behind camera */ projectToScreen(worldPos: Vec3, canvasWidth: number, canvasHeight: number): { x: number; y: number; } | null; /** * Set projection mode (perspective or orthographic) * When switching to orthographic, calculates initial orthoSize from current view. */ setProjectionMode(mode: ProjectionMode): void; /** * Toggle between perspective and orthographic projection */ toggleProjectionMode(): void; /** * Get current projection mode */ getProjectionMode(): ProjectionMode; /** * Get orthographic view half-height */ getOrthoSize(): number; /** * Set orthographic view half-height */ setOrthoSize(size: number): void; /** * Set scene bounds for tight orthographic near/far plane computation. * Call this when geometry is loaded or changed. */ setSceneBounds(bounds: { min: { x: number; y: number; z: number; }; max: { x: number; y: number; z: number; }; } | null): void; /** * The cached scene bounds last set via {@link setSceneBounds} (null if never * set). O(1) — does not recompute from geometry, so it is cheap enough to * read on the orbit hot path (e.g. anchoring the orbit pivot to the scene * centre on large models). Returns the live reference; callers must not mutate. */ getSceneBounds(): { min: { x: number; y: number; z: number; }; max: { x: number; y: number; z: number; }; } | null; /** * Set the outlier-robust orbit-pivot anchor bounds (issue #1394), or `null` * to clear it (the pivot then falls back to {@link getSceneBounds}). The * renderer never touches this, so it survives the per-upload `setSceneBounds` * syncs that keep `sceneBounds` pinned to the full model AABB. */ setOrbitAnchorBounds(bounds: { min: { x: number; y: number; z: number; }; max: { x: number; y: number; z: number; }; } | null): void; /** * The robust orbit-pivot anchor bounds last set via {@link setOrbitAnchorBounds} * (null if never set / cleared). O(1); safe on the orbit hot path. Returns the * live reference; callers must not mutate. */ getOrbitAnchorBounds(): { min: { x: number; y: number; z: number; }; max: { x: number; y: number; z: number; }; } | null; private updateMatrices; /** * Compute tight near/far for orthographic mode by projecting the scene * bounding sphere onto the camera view direction. * * This gives optimal depth precision (minimizing z-fighting) while ensuring * no geometry is clipped regardless of camera position or view angle. */ private computeOrthoNearFar; } //# sourceMappingURL=camera.d.ts.map