three-cad-viewer 5.0.7 → 5.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -62,6 +62,23 @@ export declare class PickingController {
62
62
  private onIdHoverMove;
63
63
  /** Cursor left the canvas → clear any hover highlight. */
64
64
  private onIdHoverLeave;
65
+ /**
66
+ * Pick the visible component under the cursor with the current topo filter, or
67
+ * `null` when the cursor is off the canvas or over background.
68
+ */
69
+ private pickUnderCursor;
70
+ /**
71
+ * World-space point on the visible component under the cursor (same pick as the
72
+ * hover), or `null` when there is none or the GPU lacks the position attachment.
73
+ */
74
+ pointUnderCursor(): THREE.Vector3 | null;
75
+ /**
76
+ * Tree-row hover: HOVER the faces of the tree node at `path` (leaf or group), or
77
+ * clear when `null`. Drops the canvas hover target first — otherwise the next
78
+ * render's {@link handleIdHover} (cursor outside the canvas) would release that
79
+ * stale target and wipe the tree hover with it.
80
+ */
81
+ setTreeHover(path: string | null): void;
65
82
  /**
66
83
  * Whether hover preselection (highlight + status line) is active. Disabled for GDS:
67
84
  * dense, stacked, instance-unrolled layout data where per-pixel hover flickers
@@ -136,6 +136,8 @@ export interface ChangeNotification {
136
136
  clip_normal_1?: StateChange<Vector3Tuple | null>;
137
137
  clip_normal_2?: StateChange<Vector3Tuple | null>;
138
138
  lastPick?: StateChange<PickInfo | null>;
139
+ /** Point copied with Ctrl/Cmd-C (event, sent on every copy; `old` is always null). */
140
+ copiedPoint?: StateChange<Vector3Tuple>;
139
141
  [key: string]: StateChange<unknown> | undefined;
140
142
  }
141
143
  /** Callback for notifications */
@@ -27,6 +27,11 @@ import { ViewerState } from "./viewer-state.js";
27
27
  import type { Display } from "../ui/display.js";
28
28
  import type { Vector3Tuple, QuaternionTuple } from "three";
29
29
  import { CollapseState, type ZebraColorScheme, type ZebraMappingMode, type StudioToneMapping, type StudioTextureMapping, type StudioBackground, type NotificationCallback, type RenderOptions, type ViewerOptions, type Shapes, type VisibilityState, type ActiveTab, type Axis, type ClipIndex, type ThemeInput, type BoundingBoxFlat, type Keymap } from "./types.js";
30
+ /**
31
+ * Why the viewer renders continuously (see {@link Viewer.setLoopReason}): an
32
+ * animation is playing, a measure/select tool is active, or a screenshot is taken.
33
+ */
34
+ export type LoopReason = "animation" | "tool" | "capture";
30
35
  /**
31
36
  * Material settings for the viewer.
32
37
  */
@@ -187,6 +192,8 @@ declare class Viewer {
187
192
  hasAnimationLoop: boolean;
188
193
  mixer: THREE.AnimationMixer | null;
189
194
  continueAnimation: boolean;
195
+ /** Reasons for continuous rendering; the render loop runs while any is set. */
196
+ private _loopReasons;
190
197
  clipAction: THREE.AnimationAction | null;
191
198
  shapeRenderer: ShapeRenderer | null;
192
199
  camera_distance: number;
@@ -206,6 +213,12 @@ declare class Viewer {
206
213
  private _suppressUpdate;
207
214
  private _zebraSettingsApplied;
208
215
  idPicker: IdPicker | null;
216
+ /** Outline of the clip caps; created on first use, kept across renders. */
217
+ private _capOutline;
218
+ /** Camera world + projection matrix of the previous outline frame (motion test). */
219
+ private _capOutlineCamera;
220
+ /** Pending redraw that adds the outline once the camera has settled. */
221
+ private _capOutlineSettle;
209
222
  pickingController: PickingController;
210
223
  private _studioManager;
211
224
  /** Environment manager — proxied from StudioManager for display.ts access. */
@@ -213,6 +226,8 @@ declare class Viewer {
213
226
  /** True while the Studio (presentation) tab owns the render. PickHost member. */
214
227
  get studioActive(): boolean;
215
228
  zScale: number;
229
+ /** Whether the attached animation has moved parts (Play pressed or time slider moved). */
230
+ private _animationStarted;
216
231
  clipNormal0: Vector3Tuple | null;
217
232
  clipNormal1: Vector3Tuple | null;
218
233
  clipNormal2: Vector3Tuple | null;
@@ -338,7 +353,38 @@ declare class Viewer {
338
353
  * Start the animation loop
339
354
  */
340
355
  animate: () => void;
356
+ /**
357
+ * Add or remove a reason for continuous rendering. The render loop runs while at
358
+ * least one reason is set; otherwise the viewer renders on demand (camera changes
359
+ * and explicit updates), so an idle viewer costs no CPU/GPU time.
360
+ * @param reason - why continuous rendering is needed.
361
+ * @param flag - whether the reason applies.
362
+ */
363
+ setLoopReason(reason: LoopReason, flag: boolean): void;
364
+ /**
365
+ * Run the render loop only while the animation plays. When it stops (pause,
366
+ * stop, slider), render once so the final pose is shown.
367
+ */
368
+ private _setAnimationPlaying;
369
+ /**
370
+ * Start or stop the render loop directly. Prefer {@link setLoopReason}, which keeps
371
+ * the loop running while any other reason still needs it.
372
+ * @param flag - whether the render loop should run.
373
+ */
341
374
  toggleAnimationLoop(flag: boolean): void;
375
+ /**
376
+ * Draw the outline of the clip caps over the frame (Clip tab active only). Skipped
377
+ * while the camera moves (drag, wheel, damping, preset views): the outline pass
378
+ * renders faces and caps a second time, so it is drawn once the camera has been
379
+ * still for {@link CAP_OUTLINE_SETTLE_MS}.
380
+ */
381
+ private _renderCapOutline;
382
+ /** Whether the camera's world or projection matrix changed since the last call. */
383
+ private _cameraMovedSinceLastOutline;
384
+ /** Redraw once the camera has settled, so the skipped outline appears. */
385
+ private _scheduleCapOutline;
386
+ /** Cancel a pending outline redraw. */
387
+ private _cancelCapOutline;
342
388
  /**
343
389
  * Remove all assets and event handlers. Call when done with the viewer.
344
390
  *
@@ -540,6 +586,17 @@ declare class Viewer {
540
586
  get lastObject(): PickedComponent | null;
541
587
  /** Last committed selection. */
542
588
  get lastSelection(): PickedComponent | null;
589
+ /** Tree-row hover: highlight the faces of the node at `path`, or clear on `null`. */
590
+ handleTreeHover: (path: string | null) => void;
591
+ /**
592
+ * Copy the world-space point under the cursor as `"x, y, z"` to the clipboard and
593
+ * send it to the host as a `copiedPoint` notification (for hosts that block the
594
+ * browser clipboard). Does nothing while parts may be displaced from their model
595
+ * positions — explode mode, an animation once started (Play or time slider), a
596
+ * z-scale other than 1 — or when no visible component is under the cursor.
597
+ * @returns true when a point was copied (the caller then consumes the key event).
598
+ */
599
+ copyPointUnderCursor(): boolean;
543
600
  /** Enable/disable the double-click pick handler (on when no tool is active). */
544
601
  setPickHandler(flag: boolean): void;
545
602
  /** Enable/disable click+key selection input (on while a select/measure tool is active). */
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Screen-space outline of the clip caps (CAD mode).
3
+ *
4
+ * The caps carry no geometry of their own outline, and the faces next to a cut may
5
+ * face away from the camera or belong to a touching solid, so the outline is found
6
+ * in screen space instead:
7
+ *
8
+ * 1. Id pass into an offscreen target (color + depth + stencil):
9
+ * - visible faces as black occluders (face pick layer + override material), so a
10
+ * cap hidden behind another part gets no outline; face pixels within the line
11
+ * width of a clip plane write {@link CUT_EDGE_ID} instead, which draws the cut
12
+ * contour on the faces themselves (needed when the caps are behind the faces),
13
+ * - the stencil meshes and caps (on {@link CAP_LAYER}) with each cap writing its
14
+ * own id instead of its shaded color — the same stencil sequence as the main
15
+ * render, since three orders them identically (material creation order).
16
+ * 2. Composite over the canvas: a pixel is drawn in the edge color when its id is
17
+ * larger than a neighbour's id, which yields a line on one side of every boundary
18
+ * cap↔cap, cap↔surface and cap↔background. Cut-edge pixels are the largest id, so
19
+ * where they meet a cap only they are drawn — one line, not two.
20
+ */
21
+ import * as THREE from "three";
22
+ /** Render layer of the clip stencil meshes and cap quads (pick layers use 1-3). */
23
+ export declare const CAP_LAYER = 4;
24
+ /** Id of face pixels on the cut contour (larger than any cap id). */
25
+ export declare const CUT_EDGE_ID = 16777215;
26
+ /** Encode a cap id (1..2^24-1) as an exact 8-bit RGB color (0 = no cap). */
27
+ export declare function capIdColor(id: number): THREE.Vector3;
28
+ /** Per-frame inputs of {@link CapOutlinePass.render}. */
29
+ export interface CapOutlineOptions {
30
+ /** Clip planes and mode of the face materials (for the occluders). */
31
+ planes: THREE.Plane[];
32
+ intersection: boolean;
33
+ /** Draw faces as occluders (off in transparent mode: caps show through faces). */
34
+ occlude: boolean;
35
+ /** Outline color (sRGB hex). */
36
+ color: number;
37
+ /** Switch the cap materials between shaded output and id output. */
38
+ setCapIdPass: (flag: boolean) => void;
39
+ }
40
+ export declare class CapOutlinePass {
41
+ private target;
42
+ private readonly occluder;
43
+ /** Width of the cut contour on the faces, in device pixels (= outline width). */
44
+ private readonly cutWidth;
45
+ private readonly composite;
46
+ private readonly quadScene;
47
+ private readonly quadCamera;
48
+ private readonly quad;
49
+ private readonly size;
50
+ private readonly savedClearColor;
51
+ private readonly savedViewport;
52
+ constructor();
53
+ private ensureTarget;
54
+ /**
55
+ * Render the id pass and draw the outline over the current (canvas) framebuffer.
56
+ * Call right after the main scene render.
57
+ */
58
+ render(renderer: THREE.WebGLRenderer, scene: THREE.Scene, camera: THREE.Camera, options: CapOutlineOptions): void;
59
+ dispose(): void;
60
+ }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Section hatching for clip caps (CAD mode, shader-only). The per-solid cap quads
3
+ * draw hatch lines anchored to the plane (stable while rotating/panning) whose
4
+ * spacing is kept at a constant pixel distance by a per-frame world-per-pixel
5
+ * uniform. The outline of the caps is drawn separately (see cap-outline.ts); for its
6
+ * id pass the same cap shader can output the cap's id instead of its color.
7
+ *
8
+ * All shared uniforms are plain `{ value }` objects held by reference, so a single
9
+ * write (e.g. the per-frame hatch spacing) updates every patched material without a
10
+ * recompile.
11
+ */
12
+ import * as THREE from "three";
13
+ /** Distance between hatch lines in pixels. */
14
+ export declare const HATCH_SPACING_PX = 8;
15
+ /** Width of a hatch line in pixels. */
16
+ export declare const HATCH_LINE_WIDTH_PX = 1;
17
+ /** Uniforms shared by all hatch patched cap materials of one clipping setup. */
18
+ export interface HatchUniforms {
19
+ /** World units between hatch lines (before the per-solid scale); set per frame. */
20
+ uHatchSpacing: {
21
+ value: number;
22
+ };
23
+ /** Half the cap quad size: maps the quad's [-1, 1] geometry to plane units. */
24
+ uCapHalfSize: {
25
+ value: number;
26
+ };
27
+ uHatchLineWidth: {
28
+ value: number;
29
+ };
30
+ uHatchOn: {
31
+ value: number;
32
+ };
33
+ /** 1 while the cap outline id pass renders: caps output their id, not a color. */
34
+ uCapIdPass: {
35
+ value: number;
36
+ };
37
+ }
38
+ export declare function createHatchUniforms(capHalfSize: number): HatchUniforms;
39
+ /**
40
+ * World units covered by one screen pixel at the given point (exact for an
41
+ * orthographic camera; at the point's distance for a perspective camera).
42
+ */
43
+ export declare function worldPerPixel(camera: THREE.Camera, point: THREE.Vector3, height: number): number;
44
+ /**
45
+ * Patch a cap quad material to draw section hatching. `index` is the solid's index
46
+ * among the caps of its plane; it selects the hatch direction and spacing. `capId`
47
+ * is the cap's unique id color for the outline id pass (see `capIdColor`).
48
+ */
49
+ export declare function patchHatchMaterial(material: THREE.Material, uniforms: HatchUniforms, index: number, capId: THREE.Vector3): void;
@@ -146,6 +146,11 @@ export declare class HighlightController {
146
146
  * when `null`. Mirrors {@link selectSolid} for the transient hover state.
147
147
  */
148
148
  setHoverSolid(solidPath: string | null): void;
149
+ /**
150
+ * HOVER every FACE at or below the tree path `prefix` (a leaf or a whole group),
151
+ * or clear hover when `null`. Drives the tree-row hover highlight.
152
+ */
153
+ setHoverPath(prefix: string | null): void;
149
154
  /** Set or clear the SELECTED flag for a single component id. */
150
155
  setSelected(id: number, flag: boolean): void;
151
156
  /** Whether a component currently carries the SELECTED flag. */
@@ -116,6 +116,16 @@ declare class Animation {
116
116
  * Dispose of animation resources.
117
117
  */
118
118
  dispose(): void;
119
+ /**
120
+ * Apply the current animation time to the objects without advancing it, so a
121
+ * single on-demand render shows the pose (e.g. after {@link setRelativeTime}).
122
+ */
123
+ apply(): void;
124
+ /**
125
+ * Restart the frame-time measurement, so resuming playback after a pause does
126
+ * not advance the animation by the whole pause.
127
+ */
128
+ resetClock(): void;
119
129
  /**
120
130
  * Update the animation mixer (call each frame when animating).
121
131
  */
@@ -117,6 +117,9 @@ declare class Clipping extends THREE.Group {
117
117
  private _planeMeshGroup;
118
118
  /** Per-solid stencil/cap units, the unit of screen-size culling. */
119
119
  private _capUnits;
120
+ /** Shared uniforms of the section hatching on all cap quads. */
121
+ private _hatchUniforms;
122
+ private _hatchCenter;
120
123
  /**
121
124
  * Whether {@link cull} last ran with clipping active. Lets the inactive path
122
125
  * gate stencils/caps off exactly once, then early-return on later still frames.
@@ -191,6 +194,10 @@ declare class Clipping extends THREE.Group {
191
194
  * @param flag - True to show, false to hide.
192
195
  */
193
196
  setVisible: (flag: boolean) => void;
197
+ /** Whether any solid has clip caps (the cap outline pass has work to do). */
198
+ get hasCaps(): boolean;
199
+ /** Switch all cap materials between shaded output and outline id output. */
200
+ setCapIdPass: (flag: boolean) => void;
194
201
  /**
195
202
  * Bound the per-frame stencil/cap draw work to keep large assemblies from
196
203
  * overrunning the GPU watchdog on clip+rotate (see {@link CAP_CULL_MIN_PX}).