import * as THREE from "three"; import type { Vector3Tuple } from "three"; import { ObjectGroup } from "./nestedgroup.js"; import type { Theme, ClipIndex } from "../core/types"; /** * Cap-culling thresholds (see {@link Clipping.cull}). The per-solid stencil + cap * meshes are correct but O(N) in draw calls; on a large assembly (~1300 solids × * 3 planes × 3 meshes ≈ 12000 draws/frame) a zoomed-out clip+rotate overruns the * GPU watchdog → context loss. Culling bounds the per-frame work: * - `CAP_CULL_MIN_PX`: skip a solid's caps when its projected screen radius is * below this (sub-pixel solids contribute nothing visible zoomed out). * - `CAP_CULL_BUDGET`: hard cap on the number of capped solids (largest-first); * the real crash guard for pathologically dense views. Tune on a real GPU. */ export declare const CAP_CULL_MIN_PX = 3; export declare const CAP_CULL_BUDGET = 400; /** * A THREE.Plane that maintains a constant relative to a center point. */ declare class CenteredPlane extends THREE.Plane { center: number[]; centeredConstant: number; /** * Create a CenteredPlane. * @param normal - The plane normal vector. * @param constant - The centered constant value. * @param center - The center point [x, y, z]. */ constructor(normal: THREE.Vector3, constant: number, center: number[]); /** * Set the constant relative to the center point. * @param value - The centered constant value. */ setConstant(value: number): void; /** * Clone this CenteredPlane. * Overrides THREE.Plane.clone() which calls `new this.constructor()` without * arguments, causing `center` to be undefined during shadow map generation. */ clone(): CenteredPlane; } /** * A THREE.Group that only contains PlaneMesh children. */ declare class PlaneMeshGroup extends THREE.Group { children: PlaneMesh[]; } /** * A mesh that visually represents a clipping plane. */ declare class PlaneMesh extends THREE.Mesh { type: string; material: THREE.MeshBasicMaterial | THREE.MeshStandardMaterial; /** Shared matrix for lookAt calculations */ static matrix: THREE.Matrix4; index: number; plane: CenteredPlane; size: number; center: number[]; /** * Create a PlaneMesh. * @param index - The plane index (0, 1, or 2). * @param plane - The clipping plane. * @param center - The center point [x, y, z]. * @param size - The size of the plane mesh. * @param material - The material for the mesh. * @param color - The color as hex value. * @param type - The mesh type identifier. */ constructor(index: number, plane: CenteredPlane, center: number[], size: number, material: THREE.MeshBasicMaterial | THREE.MeshStandardMaterial, color: number, type: string); /** * Clear stencil buffer after rendering stencil planes. * @param renderer - The renderer. */ onAfterRender: (renderer: THREE.WebGLRenderer) => void; /** * Update the mesh's world matrix to align with the clipping plane. * @param force - Force update even if not needed. */ updateMatrixWorld(force?: boolean): void; } interface NestedGroupLike { groups: Record; rootGroup: THREE.Group | null; } interface ClippingOptions { onNormalChange?: (index: ClipIndex, normalArray: Vector3Tuple) => void; } /** * Saved clipping state for mode transitions (e.g., entering/leaving Studio mode). * Captures only Clipping-internal state; renderer flags and ViewerState keys * are managed by the caller. */ interface ClippingState { /** Centered constant (position) for each of the 3 clip planes */ planeConstants: [number, number, number]; /** Whether the plane helper meshes (translucent colored rectangles) are visible */ helperVisible: boolean; /** Whether the stencil plane meshes (solid colored caps) are visible */ planesVisible: boolean; } /** * Manages clipping planes, stencil rendering, and plane visualization. */ declare class Clipping extends THREE.Group { center: number[] | null; distance: number; onNormalChange: ((index: ClipIndex, normalArray: Vector3Tuple) => void) | null; theme: Theme; nestedGroup: NestedGroupLike; size: number; clipPlanes: CenteredPlane[]; reverseClipPlanes: CenteredPlane[]; objectColors: number[]; objectColorCaps: boolean; planeHelpers: PlaneMeshGroup | null; private _planeMeshGroup; /** Per-solid stencil/cap units, the unit of screen-size culling. */ private _capUnits; /** Shared uniforms of the section hatching on all cap quads. */ private _hatchUniforms; private _hatchCenter; /** * Whether {@link cull} last ran with clipping active. Lets the inactive path * gate stencils/caps off exactly once, then early-return on later still frames. * Starts `true` so the first inactive call performs the initial gate-off (the * meshes default to `visible:true`). */ private _cullActive; /** Reused buffer for the budget threshold sort (no per-frame alloc). */ private _radiiScratch; /** * Create a Clipping instance. * @param center - The center point [x, y, z]. * @param size - The size of the clipping region. * @param nestedGroup - The nested group containing objects to clip. * @param options - Configuration options. * @param theme - The UI theme ('light' or 'dark'). */ constructor(center: number[], size: number, nestedGroup: NestedGroupLike, options: ClippingOptions, theme: Theme); /** * Create the three clipping planes and their reverse counterparts. * @param center - The center point. */ private _createClipPlanes; /** * Create the visual plane helpers. * @param center - The center point. * @param size - The size of the plane helpers. * @param theme - The UI theme. */ private _createPlaneHelpers; /** * Create stencil meshes for solid objects. * @param center - The center point. * @param size - The size of the stencil planes. * @param theme - The UI theme. */ private _createStencils; /** * Rebuild stencil meshes after scene changes (part add/remove). * Clears existing stencils from all ObjectGroups and rebuilds from scratch. * Also updates clipping region size if center/size changed. * @param center - The new center point [x, y, z]. * @param size - The new size of the clipping region. */ rebuildStencils(center: number[], size: number): void; /** * Set the constant (distance from center) for a clipping plane. * @param index - The plane index (0, 1, or 2). * @param value - The constant value relative to center. */ setConstant(index: ClipIndex, value: number): void; /** * Set the normal vector for a clipping plane. * @param index - The plane index (0, 1, or 2). * @param normal - The new normal vector. */ setNormal: (index: ClipIndex, normal: THREE.Vector3) => void; /** * Get whether object color caps mode is enabled. * @returns True if object color caps mode is enabled. */ getObjectColorCaps: () => boolean; /** * Toggle object color caps mode. * When enabled, stencil planes use the original object colors. * When disabled, stencil planes use theme-based plane colors. * @param flag - True to enable object color caps. */ setObjectColorCaps: (flag: boolean) => void; /** * Set visibility of stencil plane meshes. * @param flag - True to show, false to hide. */ setVisible: (flag: boolean) => void; /** Whether any solid has clip caps (the cap outline pass has work to do). */ get hasCaps(): boolean; /** Switch all cap materials between shaded output and outline id output. */ setCapIdPass: (flag: boolean) => void; /** * Bound the per-frame stencil/cap draw work to keep large assemblies from * overrunning the GPU watchdog on clip+rotate (see {@link CAP_CULL_MIN_PX}). * * Toggles each unit's `Object3D.visible` (NOT material.visible), which composes * by AND with the existing material-level toggles — `setShapeVisible` (per-solid * hide) and `setVisible` (clip-tab on/off) — so a unit renders only when it is * un-culled AND its solid is shown AND the clip tab is active. Render order and * the per-solid `clearStencil` isolation are untouched (removing a whole solid's * units never affects the remaining solids' cap correctness). * * @param camera - The active camera (ortho or perspective). * @param width - Canvas width in CSS px. * @param height - Canvas height in CSS px. * @param clipActive - `renderer.localClippingEnabled` (clip tab selected). */ cull(camera: THREE.Camera, width: number, height: number, clipActive: boolean): void; /** * World-space AABB of a solid (local bounding box transformed by the front * mesh's world matrix, which folds in GDS z-scale). Returns a shared scratch * Box3 (valid only until the next call) or `null` when geometry is missing. */ private _solidWorldBox; /** * Projected screen radius (px) of a solid's bounding sphere. Projects the world * sphere center and a point one world-radius along the camera-right axis, and * measures their screen-space separation — correct for both ortho and * perspective. Returns `Infinity` (never cull) when geometry is missing. */ private _solidScreenRadius; /** * Save the current clipping state for later restoration. * Captures plane positions, helper visibility, and stencil plane visibility. * Used by Studio mode to snapshot clipping state before disabling clipping. * * Note: `renderer.localClippingEnabled` and `clipPlaneHelpers` ViewerState * are managed by the caller (Display/Viewer layer), not captured here. */ saveState(): ClippingState; /** * Restore a previously saved clipping state. * Re-applies plane positions, helper visibility, and stencil plane visibility. * Used by Studio mode when leaving to restore the clipping configuration. * * @param state - The state previously captured by `saveState()`. */ restoreState(state: ClippingState): void; /** * Clean up resources. * Note: We don't null out arrays/references as GC handles cleanup when the Clipping object is collected. */ dispose(): void; } export { Clipping }; export type { ClippingState };