import { EventDispatcher, Sphere, Vector3, Vector3Like } from 'three/webgpu'; import { DIVENode, DIVETicker, DIVECameraComponent, DIVEInput, DIVEInputChannel } from '../../../index.ts'; import { OrbitControllerState } from '../types/index.ts'; /** What a movement on an input channel does to the camera. */ export type OrbitControllerAction = 'rotate' | 'pan' | 'dolly'; export type OrbitControllerBinding = { action: OrbitControllerAction; speed: number; }; /** Which channel does what. A channel without a binding is ignored. */ export type OrbitControllerBindings = Partial>; export type OrbitControllerSettings = { enableDamping?: boolean; dampingFactor?: number; enabled?: boolean; inputEnabled?: boolean; target?: Vector3; minDistance?: number; maxDistance?: number; minZoom?: number; maxZoom?: number; minPolarAngle?: number; maxPolarAngle?: number; minAzimuthAngle?: number; maxAzimuthAngle?: number; enableZoom?: boolean; zoomSpeed?: number; enableRotate?: boolean; enablePan?: boolean; screenSpacePanning?: boolean; autoRotate?: boolean; autoRotateSpeed?: number; bindings?: OrbitControllerBindings; }; export declare const OrbitControllerDefaultSettings: Required; type EventMap = { dispose: { type: 'dispose'; }; change: { type: 'change'; }; start: { type: 'start'; }; end: { type: 'end'; }; }; /** * Orbits the camera around a target, driven by input devices. * * Devices are connected with {@link connect} and report in the shared input * format; {@link bindings} decides what each channel does. The controller never * touches the DOM itself. */ export declare class OrbitController extends EventDispatcher implements DIVETicker { static readonly DEFAULT_ZOOM_FACTOR = 1; /** * The camera component this controller drives. * * The component rather than the camera: `setCameraLayer` and `onResize` live * there, and handing out the bare camera meant every caller had to search its * way back. What orbiting moves is `object.owner`, the node it sits on. */ object: DIVECameraComponent; /** * The camera, narrowed to the two kinds whose projection this can pan. * * `DIVECameraComponent` types its camera as the base `Camera`, which has no * `zoom` or `fov`; the branches below narrow it further. */ private get _camera(); /** * Whether the controller moves the camera at all. * * Turning it back on drops whatever movement was still pending, so damping * from before does not carry over into a camera someone else has moved since. */ get enabled(): boolean; set enabled(enabled: boolean); private _enabled; /** * Whether input moves the camera. Unlike {@link enabled}, the camera keeps * ticking -- damping runs out and auto-rotation goes on. For a tool that * needs the pointer for itself. */ inputEnabled: boolean; target: Vector3; minDistance: number; maxDistance: number; minZoom: number; maxZoom: number; minPolarAngle: number; maxPolarAngle: number; minAzimuthAngle: number; maxAzimuthAngle: number; enableDamping: boolean; dampingFactor: number; enableZoom: boolean; zoomSpeed: number; enableRotate: boolean; enablePan: boolean; screenSpacePanning: boolean; autoRotate: boolean; autoRotateSpeed: number; bindings: OrbitControllerBindings; target0: Vector3; position0: Vector3; zoom0: number; uuid: string; private readonly EPS; private readonly spherical; private readonly sphericalDelta; private scale; private readonly panOffset; private zoomChanged; private readonly connections; private readonly offset; private readonly quat; private readonly quatInverse; private readonly lastPosition; private readonly lastQuaternion; private readonly lastTarget; constructor(cameraComponent: DIVECameraComponent, settings?: OrbitControllerSettings); tick(): void; /** Lets an input device move the camera. Connecting twice changes nothing. */ connect(input: DIVEInput): void; /** Stops listening to an input device. Its gesture in progress is dropped. */ disconnect(input: DIVEInput): void; /** Whether any connected input has a gesture in progress. */ isInteracting(): boolean; getPolarAngle(): number; getAzimuthalAngle(): number; getDistance(): number; saveState(): void; reset(): void; update(): boolean; dispose(): void; /** * Where to put the camera so a sphere fills the view. * * Takes a `Sphere` rather than a bounding box: framing needs a centre and a * radius, and nothing else. Build one with `new BoundingBox().enclose(...)`, * or read `sphere` off a `BoundingBoxComponent` that already measures a node. * * @param sphere - What to frame, in world space. * @param padding - Extra distance as a fraction of the fitted one. */ computeEncompassingView(sphere: Sphere, padding?: number): { position: Vector3Like; target: Vector3Like; }; /** * Puts the camera where the whole node fits in the view. * * One node, not a list: a node already is the handle for everything below it, * so anything worth framing together belongs under a common parent. * * @param node - What to frame. * @param padding - Extra distance as a fraction of the fitted one. */ focusObject(node: DIVENode, padding?: number): void; zoomIn(by?: number): void; zoomOut(by?: number): void; getState(): OrbitControllerState; setState(state: OrbitControllerState): void; private onInputMove; private onInputScale; private getAutoRotationAngle; private getZoomScale; private rotateLeft; private rotateUp; private panLeft; private panUp; /** * Pans by a distance in viewport units: fractions of the view's height. * * The orthographic branch measures both axes by the frustum's height, which * equals measuring x by its width as long as the frustum has the viewport's * aspect. */ private pan; private dollyIn; private dollyOut; } export {};