three-cad-viewer 4.3.9 → 5.0.0
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.
- package/{README.md → Readme.md} +7 -5
- package/dist/core/picking-controller.d.ts +125 -0
- package/dist/core/types.d.ts +13 -6
- package/dist/core/viewer-state.d.ts +1 -1
- package/dist/core/viewer.d.ts +44 -48
- package/dist/rendering/highlight.d.ts +209 -0
- package/dist/rendering/id-picking.d.ts +464 -0
- package/dist/rendering/light-detection.d.ts +3 -3
- package/dist/rendering/material-factory.d.ts +3 -1
- package/dist/rendering/picked.d.ts +55 -0
- package/dist/rendering/studio-composer.d.ts +2 -2
- package/dist/scene/clipping.d.ts +53 -0
- package/dist/scene/nestedgroup.d.ts +46 -4
- package/dist/scene/objectgroup.d.ts +17 -0
- package/dist/scene/render-shape.d.ts +3 -19
- package/dist/three-cad-viewer.css +54 -20
- package/dist/three-cad-viewer.esm.js +4095 -1381
- package/dist/three-cad-viewer.esm.js.map +1 -1
- package/dist/three-cad-viewer.esm.min.js +3 -3
- package/dist/three-cad-viewer.js +4095 -1381
- package/dist/three-cad-viewer.min.js +4 -4
- package/dist/tools/cad_tools/measure.d.ts +8 -9
- package/dist/tools/cad_tools/mesh-measure.d.ts +264 -0
- package/dist/tools/cad_tools/select.d.ts +4 -3
- package/dist/tools/cad_tools/tools.d.ts +16 -4
- package/dist/tools/cad_tools/ui.d.ts +8 -6
- package/dist/ui/display.d.ts +25 -2
- package/package.json +3 -2
- package/dist/rendering/raycast.d.ts +0 -111
package/{README.md → Readme.md}
RENAMED
|
@@ -314,7 +314,7 @@ The keymap serves two purposes:
|
|
|
314
314
|
- **Modifier keys** (`shift`, `ctrl`, `meta`, `alt`) remap which physical modifier key is used for mouse interactions (e.g. shift-click to isolate, ctrl-rotate). Values are DOM event properties like `"shiftKey"`, `"ctrlKey"`, `"metaKey"`, `"altKey"`.
|
|
315
315
|
- **Action shortcuts** map single keys (with or without Shift) to toolbar buttons, camera presets, tab switches, and animation control. Only plain keys are supported — Ctrl/Alt/Meta combinations are reserved for modifier-based mouse interactions.
|
|
316
316
|
|
|
317
|
-
Click on the viewer to give it focus, then press shortcut keys to trigger actions. Button tooltips show
|
|
317
|
+
Click on the viewer to give it focus, then press shortcut keys to trigger actions. Button and tab tooltips show a `› key` suffix when shortcuts are configured.
|
|
318
318
|
|
|
319
319
|
The default keymap:
|
|
320
320
|
|
|
@@ -323,19 +323,19 @@ keymap: {
|
|
|
323
323
|
// Modifier keys (remap physical keys for mouse interactions)
|
|
324
324
|
shift: "shiftKey", ctrl: "ctrlKey", meta: "metaKey", alt: "altKey",
|
|
325
325
|
// Toggle buttons
|
|
326
|
-
axes: "
|
|
326
|
+
axes: "A", axes0: "0", grid: "g", gridxy: "G",
|
|
327
327
|
perspective: "p", transparent: "t", blackedges: "b",
|
|
328
328
|
explode: "x", zscale: "L",
|
|
329
|
-
distance: "D", properties: "P", select: "
|
|
329
|
+
distance: "D", properties: "P", select: "I",
|
|
330
330
|
// Execute buttons
|
|
331
331
|
reset: "R", resize: "r",
|
|
332
|
-
iso: "
|
|
332
|
+
iso: "5", front: "1", rear: "3", top: "8", bottom: "2", left: "4", right: "6",
|
|
333
333
|
// Help
|
|
334
334
|
help: "h",
|
|
335
335
|
// Animation
|
|
336
336
|
play: " ", stop: "Escape",
|
|
337
337
|
// Tab selection
|
|
338
|
-
tree: "T", clip: "C", material: "M", zebra: "Z",
|
|
338
|
+
tree: "T", clip: "C", material: "M", zebra: "Z", studio: "S",
|
|
339
339
|
}
|
|
340
340
|
```
|
|
341
341
|
|
|
@@ -347,6 +347,8 @@ const displayOptions = {
|
|
|
347
347
|
};
|
|
348
348
|
```
|
|
349
349
|
|
|
350
|
+
**Topo filter shortcuts.** When the shape filter is visible (B-rep models), the lowercase keys `a` (All), `v` (Vertex), `e` (Edge), `f` (Face), `s` (Solid) set the picking filter. These are fixed (not part of the configurable keymap) — which is why `axes` and `studio` default to the uppercase `A`/`S`.
|
|
351
|
+
|
|
350
352
|
## Examples
|
|
351
353
|
|
|
352
354
|
To understand the data format, a look at the simple 1 unit sized box might be helpful:
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import * as THREE from "three";
|
|
2
|
+
import { type IdPicker } from "../rendering/id-picking.js";
|
|
3
|
+
import { type PickedComponent } from "../rendering/picked.js";
|
|
4
|
+
import type { Shapes } from "./types.js";
|
|
5
|
+
import type { RenderedState } from "./viewer.js";
|
|
6
|
+
import type { Display } from "../ui/display.js";
|
|
7
|
+
import type { Tools } from "../tools/cad_tools/tools.js";
|
|
8
|
+
/**
|
|
9
|
+
* The narrow surface {@link PickingController} needs from its host (the Viewer).
|
|
10
|
+
* Keeps the controller decoupled from the rest of the Viewer god-object and
|
|
11
|
+
* unit-testable. `rendered` is a lazy getter that throws before render() — the
|
|
12
|
+
* controller must always read through it (never cache `nestedGroup`/`highlight`,
|
|
13
|
+
* which are rebuilt every render()).
|
|
14
|
+
*/
|
|
15
|
+
export interface PickHost {
|
|
16
|
+
readonly idPicker: IdPicker | null;
|
|
17
|
+
readonly ready: boolean;
|
|
18
|
+
readonly hasAnimationLoop: boolean;
|
|
19
|
+
/** True while the Studio (presentation) tab owns the render. */
|
|
20
|
+
readonly studioActive: boolean;
|
|
21
|
+
readonly shapes: Shapes | null;
|
|
22
|
+
readonly renderer: THREE.WebGLRenderer;
|
|
23
|
+
readonly rendered: RenderedState;
|
|
24
|
+
readonly display: Display;
|
|
25
|
+
readonly cadTools: Tools;
|
|
26
|
+
update(updateMarker: boolean, notify: boolean): void;
|
|
27
|
+
/** Restore the most recently meta-double-click-hidden leaf (hide-undo stack). */
|
|
28
|
+
showLastHidden(): void;
|
|
29
|
+
handlePick(path: string, name: string, meta: boolean, shift: boolean, alt: boolean, point: THREE.Vector3 | null, nodeType?: string | null, tree?: boolean): void;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Owns all pointer-driven picking on the compact graph: hover preselection
|
|
33
|
+
* (highlight + status line), left-click selection commit, right-click/key removal,
|
|
34
|
+
* and double-click pick. Hover proposes the component under the cursor
|
|
35
|
+
* ({@link lastObject}); a left-click commits it ({@link lastSelection}) — one state
|
|
36
|
+
* machine, so both fields live here.
|
|
37
|
+
*
|
|
38
|
+
* Listener lifecycle: hover (pointermove/leave) is always-on and added at
|
|
39
|
+
* construction; selection (mousedown/mouseup + document keydown) is tool-scoped via
|
|
40
|
+
* {@link setSelectionInput}; double-click via {@link setPickHandler}. {@link dispose}
|
|
41
|
+
* tears them all down.
|
|
42
|
+
*/
|
|
43
|
+
export declare class PickingController {
|
|
44
|
+
private readonly host;
|
|
45
|
+
/** Component under the cursor (hover); committed on left-click. */
|
|
46
|
+
lastObject: PickedComponent | null;
|
|
47
|
+
/** Last committed selection. */
|
|
48
|
+
lastSelection: PickedComponent | null;
|
|
49
|
+
private idHoverClientX;
|
|
50
|
+
private idHoverClientY;
|
|
51
|
+
private idHoverInside;
|
|
52
|
+
private idHoverRenderQueued;
|
|
53
|
+
/** Per-component hover status text (fixed per mesh; cleared on reload / z-scale). */
|
|
54
|
+
private hoverStatusCache;
|
|
55
|
+
private selectionInputActive;
|
|
56
|
+
private selectDownPosition;
|
|
57
|
+
private pickHandlerActive;
|
|
58
|
+
constructor(host: PickHost);
|
|
59
|
+
/** Remove every listener this controller owns. */
|
|
60
|
+
dispose(): void;
|
|
61
|
+
/** Record the cursor position over the canvas. */
|
|
62
|
+
private onIdHoverMove;
|
|
63
|
+
/** Cursor left the canvas → clear any hover highlight. */
|
|
64
|
+
private onIdHoverLeave;
|
|
65
|
+
/**
|
|
66
|
+
* Whether hover preselection (highlight + status line) is active. Disabled for GDS:
|
|
67
|
+
* dense, stacked, instance-unrolled layout data where per-pixel hover flickers
|
|
68
|
+
* endlessly and the B-rep readout ("area ≈ …") is meaningless, so GDS is
|
|
69
|
+
* double-click-identify only. Also disabled in Studio (presentation) mode: hover
|
|
70
|
+
* tint/status is a CAD/analysis affordance, not wanted in Studio, and skipping it
|
|
71
|
+
* means the id buffer is never re-rendered for a bare mouse-move there.
|
|
72
|
+
*/
|
|
73
|
+
private hoverPreselectActive;
|
|
74
|
+
/**
|
|
75
|
+
* Called once per render: drive hover preselection unless a model is GDS or the
|
|
76
|
+
* camera is being dragged.
|
|
77
|
+
*/
|
|
78
|
+
handleHover(): void;
|
|
79
|
+
/**
|
|
80
|
+
* Hover via the GPU id picker on the compact graph: resolve the component under the
|
|
81
|
+
* cursor and drive the shader `HighlightController`. Sets {@link lastObject}
|
|
82
|
+
* (committed on left-click by {@link commitSelection} when a tool is active).
|
|
83
|
+
*/
|
|
84
|
+
private handleIdHover;
|
|
85
|
+
/** Drop the cached hover texts (e.g. on z-scale change — world lengths change). */
|
|
86
|
+
invalidateHoverCache(): void;
|
|
87
|
+
/**
|
|
88
|
+
* Drop any lingering hover highlight + status line (keeping the committed selection).
|
|
89
|
+
* Called when entering Studio mode: hover preselection is disabled there, so the
|
|
90
|
+
* per-render {@link handleHover} no longer runs its own release and a stale tint/status
|
|
91
|
+
* from CAD mode would otherwise persist.
|
|
92
|
+
*/
|
|
93
|
+
clearHover(): void;
|
|
94
|
+
/**
|
|
95
|
+
* Whether the component a pick resolved to is currently visible — used to drop picks
|
|
96
|
+
* of hidden geometry. Visibility is the owning group's material `visible` flag
|
|
97
|
+
* (faces for solids/standalone faces; edge/vertex materials for standalone leaves).
|
|
98
|
+
*/
|
|
99
|
+
private pickVisible;
|
|
100
|
+
clearSelection: () => void;
|
|
101
|
+
private releaseLastSelected;
|
|
102
|
+
removeLastSelected(): void;
|
|
103
|
+
/** Drop selection state + hover cache + status line (on model reload). */
|
|
104
|
+
reset(): void;
|
|
105
|
+
/**
|
|
106
|
+
* Add/remove the canvas mousedown+mouseup and document keydown listeners
|
|
107
|
+
* (idempotent, guarded on `selectionInputActive`). Hover maintains
|
|
108
|
+
* {@link lastObject}; these handlers commit it on left-click and handle the key +
|
|
109
|
+
* right-click actions.
|
|
110
|
+
*/
|
|
111
|
+
setSelectionInput(flag: boolean): void;
|
|
112
|
+
private onSelectMouseDown;
|
|
113
|
+
private onSelectMouseUp;
|
|
114
|
+
private onSelectKeyDown;
|
|
115
|
+
private commitSelection;
|
|
116
|
+
setPickHandler(flag: boolean): void;
|
|
117
|
+
/**
|
|
118
|
+
* Double-click pick via the GPU id picker: `idPicker.pickAt` resolves the component
|
|
119
|
+
* under the cursor, the registry gives its owning tree-leaf path ({@link leafPath}),
|
|
120
|
+
* and the readback world-space `point` feeds `handlePick` (the `shift && meta` camera
|
|
121
|
+
* target, with a bbox-center fallback when `point` is null). No topo filter: a
|
|
122
|
+
* double-click selects whatever is under the cursor and resolves it to its leaf.
|
|
123
|
+
*/
|
|
124
|
+
private onDoubleClick;
|
|
125
|
+
}
|
package/dist/core/types.d.ts
CHANGED
|
@@ -185,8 +185,12 @@ export interface DisplayOptions {
|
|
|
185
185
|
zebraTool?: boolean;
|
|
186
186
|
/** Show studio tool (default: true) */
|
|
187
187
|
studioTool?: boolean;
|
|
188
|
-
/**
|
|
189
|
-
|
|
188
|
+
/**
|
|
189
|
+
* Use an external (Python/`ocp_vscode`) measurement backend (default: false).
|
|
190
|
+
* When false, the built-in TypeScript mesh-based measurement backend answers
|
|
191
|
+
* measurements locally — so measure works without a backend connection.
|
|
192
|
+
*/
|
|
193
|
+
externalMeasurementBackend?: boolean;
|
|
190
194
|
/** External canvas element to use for the WebGL renderer, enabling shared WebGL context scenarios (default: undefined — renderer creates its own canvas) */
|
|
191
195
|
canvas?: HTMLCanvasElement;
|
|
192
196
|
/** External WebGL context to use for the renderer. When provided together with `canvas`, the renderer will use this context instead of creating a new one. Useful for sharing a context with other renderers like PixiJS. (default: undefined) */
|
|
@@ -338,7 +342,7 @@ export interface ViewerStateShape {
|
|
|
338
342
|
zscaleTool: boolean;
|
|
339
343
|
zebraTool: boolean;
|
|
340
344
|
studioTool: boolean;
|
|
341
|
-
|
|
345
|
+
externalMeasurementBackend: boolean;
|
|
342
346
|
ambientIntensity: number;
|
|
343
347
|
directIntensity: number;
|
|
344
348
|
metalness: number;
|
|
@@ -501,9 +505,12 @@ export interface MaterialAppearance {
|
|
|
501
505
|
*
|
|
502
506
|
* This format is produced by the threejs-materials Python library, which catalogs
|
|
503
507
|
* PBR materials from ambientCG, GPUOpen, PolyHaven, and PhysicallyBased.
|
|
504
|
-
* `values` contains scalar properties (e.g., color as
|
|
505
|
-
* roughness as float).
|
|
506
|
-
*
|
|
508
|
+
* `values` contains scalar properties (e.g., color as an sRGB RGB array,
|
|
509
|
+
* roughness as float). Note the per-key color-space convention: `color` is
|
|
510
|
+
* sRGB-stored, while `emissive`/`specularColor`/`sheenColor`/`attenuationColor`
|
|
511
|
+
* are linear-stored (see MaterialFactory.createStudioMaterialFromMaterialX).
|
|
512
|
+
* `textures` contains texture references (inline data URIs or file paths)
|
|
513
|
+
* keyed by property name.
|
|
507
514
|
*
|
|
508
515
|
* Detected by the presence of the `values` key.
|
|
509
516
|
* Extra keys from threejs-materials (id, name, source, url, license) pass through
|
package/dist/core/viewer.d.ts
CHANGED
|
@@ -19,7 +19,10 @@ import { Controls } from "../camera/controls.js";
|
|
|
19
19
|
import { Camera, type CameraDirection } from "../camera/camera.js";
|
|
20
20
|
import { BoundingBox, BoxHelper } from "../scene/bbox.js";
|
|
21
21
|
import { Tools } from "../tools/cad_tools/tools.js";
|
|
22
|
-
import {
|
|
22
|
+
import { MeshMeasureBackend } from "../tools/cad_tools/mesh-measure.js";
|
|
23
|
+
import { IdPicker } from "../rendering/id-picking.js";
|
|
24
|
+
import { type PickedComponent } from "../rendering/picked.js";
|
|
25
|
+
import { PickingController } from "./picking-controller.js";
|
|
23
26
|
import { ViewerState } from "./viewer-state.js";
|
|
24
27
|
import type { Display } from "../ui/display.js";
|
|
25
28
|
import type { Vector3Tuple, QuaternionTuple } from "three";
|
|
@@ -70,14 +73,6 @@ interface ImageResult {
|
|
|
70
73
|
task: string;
|
|
71
74
|
dataUrl: string | ArrayBuffer | null;
|
|
72
75
|
}
|
|
73
|
-
/**
|
|
74
|
-
* Raycast event from keyboard or mouse.
|
|
75
|
-
*/
|
|
76
|
-
interface RaycastEvent {
|
|
77
|
-
key?: string;
|
|
78
|
-
mouse?: "left" | "right";
|
|
79
|
-
shift?: boolean;
|
|
80
|
-
}
|
|
81
76
|
/**
|
|
82
77
|
* Backend response structure.
|
|
83
78
|
*/
|
|
@@ -90,7 +85,7 @@ interface BackendResponse {
|
|
|
90
85
|
*/
|
|
91
86
|
interface DisplayOptionsInternal {
|
|
92
87
|
measureTools?: boolean;
|
|
93
|
-
|
|
88
|
+
externalMeasurementBackend?: boolean;
|
|
94
89
|
selectTool?: boolean;
|
|
95
90
|
explodeTool?: boolean;
|
|
96
91
|
zscaleTool?: boolean;
|
|
@@ -106,7 +101,7 @@ interface DisplayOptionsInternal {
|
|
|
106
101
|
* State that exists only after render() and before clear().
|
|
107
102
|
* Groups all resources that are created together during rendering.
|
|
108
103
|
*/
|
|
109
|
-
interface RenderedState {
|
|
104
|
+
export interface RenderedState {
|
|
110
105
|
scene: THREE.Scene;
|
|
111
106
|
ambientLight: THREE.AmbientLight;
|
|
112
107
|
directLight: THREE.DirectionalLight;
|
|
@@ -167,6 +162,12 @@ declare class Viewer {
|
|
|
167
162
|
onAfterRender: (() => void) | null;
|
|
168
163
|
mouse: THREE.Vector2;
|
|
169
164
|
cadTools: Tools;
|
|
165
|
+
/**
|
|
166
|
+
* Internal mesh-based measurement backend, used when
|
|
167
|
+
* `externalMeasurementBackend === false` (the default). Resolves component paths
|
|
168
|
+
* against the compact group's {@link MeshGeometrySource}.
|
|
169
|
+
*/
|
|
170
|
+
meshBackend: MeshMeasureBackend;
|
|
170
171
|
animation: Animation;
|
|
171
172
|
clipNormals: [THREE.Vector3, THREE.Vector3, THREE.Vector3];
|
|
172
173
|
private _rendered;
|
|
@@ -183,7 +184,6 @@ declare class Viewer {
|
|
|
183
184
|
private _pendingDisposal;
|
|
184
185
|
shapes: Shapes | null;
|
|
185
186
|
gridSize: number;
|
|
186
|
-
private _previousGridSize;
|
|
187
187
|
hasAnimationLoop: boolean;
|
|
188
188
|
mixer: THREE.AnimationMixer | null;
|
|
189
189
|
continueAnimation: boolean;
|
|
@@ -194,19 +194,24 @@ declare class Viewer {
|
|
|
194
194
|
renderOptions: RenderOptions | null;
|
|
195
195
|
lastNotification: Record<string, unknown>;
|
|
196
196
|
lastBbox: LastBboxInfo | null;
|
|
197
|
-
|
|
198
|
-
lastSelection: PickedObject | null;
|
|
197
|
+
private _hiddenUndo;
|
|
199
198
|
lastPosition: THREE.Vector3 | null;
|
|
200
199
|
bboxNeedsUpdate: boolean;
|
|
201
200
|
keepHighlight: boolean;
|
|
202
|
-
expandedTree: ShapeTreeData | null;
|
|
203
201
|
compactTree: ShapeTreeData | null;
|
|
204
|
-
expandedNestedGroup: NestedGroup | null;
|
|
205
202
|
compactNestedGroup: NestedGroup | null;
|
|
206
|
-
|
|
203
|
+
private _lastPickCam;
|
|
204
|
+
private _lastPickProj;
|
|
205
|
+
private _lastClipSig;
|
|
206
|
+
private _suppressUpdate;
|
|
207
|
+
private _zebraSettingsApplied;
|
|
208
|
+
idPicker: IdPicker | null;
|
|
209
|
+
pickingController: PickingController;
|
|
207
210
|
private _studioManager;
|
|
208
211
|
/** Environment manager — proxied from StudioManager for display.ts access. */
|
|
209
212
|
get envManager(): import("../index.js").EnvironmentManager;
|
|
213
|
+
/** True while the Studio (presentation) tab owns the render. PickHost member. */
|
|
214
|
+
get studioActive(): boolean;
|
|
210
215
|
zScale: number;
|
|
211
216
|
clipNormal0: Vector3Tuple | null;
|
|
212
217
|
clipNormal1: Vector3Tuple | null;
|
|
@@ -251,11 +256,10 @@ declare class Viewer {
|
|
|
251
256
|
private getShapeRenderer;
|
|
252
257
|
/**
|
|
253
258
|
* Render the shapes of the CAD object.
|
|
254
|
-
* @param exploded - Whether to render the compact or exploded version
|
|
255
259
|
* @param shapes - The Shapes object.
|
|
256
260
|
* @returns A nested THREE.Group object and navigation tree.
|
|
257
261
|
*/
|
|
258
|
-
renderTessellatedShapes(
|
|
262
|
+
renderTessellatedShapes(shapes: Shapes): RenderResult;
|
|
259
263
|
/**
|
|
260
264
|
* Add a position animation track (full 3D translation).
|
|
261
265
|
* @param selector - path/id of group to be animated.
|
|
@@ -342,7 +346,7 @@ declare class Viewer {
|
|
|
342
346
|
* - WebGL renderer and context
|
|
343
347
|
* - All Three.js objects (geometries, materials, textures)
|
|
344
348
|
* - Event listeners
|
|
345
|
-
* - CAD tools and
|
|
349
|
+
* - CAD tools and id picker
|
|
346
350
|
*
|
|
347
351
|
* After calling dispose(), the viewer instance should not be used.
|
|
348
352
|
*
|
|
@@ -358,15 +362,6 @@ declare class Viewer {
|
|
|
358
362
|
* @public
|
|
359
363
|
*/
|
|
360
364
|
clear(): void;
|
|
361
|
-
/**
|
|
362
|
-
* Synchronizes the states of two tree structures recursively.
|
|
363
|
-
*
|
|
364
|
-
* @param compactTree - The compact tree structure.
|
|
365
|
-
* @param expandedTree - The expanded tree structure.
|
|
366
|
-
* @param exploded - Whether rendering in exploded mode.
|
|
367
|
-
* @param path - The current path in the tree structure.
|
|
368
|
-
*/
|
|
369
|
-
syncTreeStates: (compactTree: ShapeTreeData | VisibilityState, expandedTree: ShapeTreeData | VisibilityState, exploded: boolean, path: string) => void;
|
|
370
365
|
/**
|
|
371
366
|
* Get the color of a node from its path
|
|
372
367
|
* @param path - path of the CAD object
|
|
@@ -375,16 +370,9 @@ declare class Viewer {
|
|
|
375
370
|
/**
|
|
376
371
|
* Build nestedGroup and treeview for initial render.
|
|
377
372
|
* @param scene - The scene to add the group to
|
|
378
|
-
* @param expanded - whether to render the exploded or compact version
|
|
379
373
|
* @returns The nestedGroup and treeview
|
|
380
374
|
*/
|
|
381
375
|
private buildInitialGroup;
|
|
382
|
-
/**
|
|
383
|
-
* Toggle the two version of the NestedGroup.
|
|
384
|
-
* Must only be called after render() has completed.
|
|
385
|
-
* @param expanded - whether to render the exploded or compact version
|
|
386
|
-
*/
|
|
387
|
-
toggleGroup(expanded: boolean): void;
|
|
388
376
|
/**
|
|
389
377
|
* Set the active sidebar tab.
|
|
390
378
|
* @param tabName - Tab name: "tree", "clip", "material", "zebra", or "studio"
|
|
@@ -534,22 +522,30 @@ declare class Viewer {
|
|
|
534
522
|
* @param tree - whether from tree
|
|
535
523
|
*/
|
|
536
524
|
handlePick: (path: string, name: string, meta: boolean, shift: boolean, alt: boolean, point: THREE.Vector3 | null, nodeType?: string | null, tree?: boolean) => void;
|
|
537
|
-
setPickHandler(flag: boolean): void;
|
|
538
525
|
/**
|
|
539
|
-
*
|
|
540
|
-
*
|
|
526
|
+
* Record a leaf about to be hidden via meta-double-click onto the hide-undo stack,
|
|
527
|
+
* capturing its current (pre-hide) visibility state for a faithful restore. Dedups:
|
|
528
|
+
* an existing entry for the same id is dropped so the id moves to the top.
|
|
541
529
|
*/
|
|
542
|
-
|
|
543
|
-
clearSelection: () => void;
|
|
544
|
-
_releaseLastSelected: () => void;
|
|
545
|
-
_removeLastSelected: () => void;
|
|
530
|
+
private _recordHidden;
|
|
546
531
|
/**
|
|
547
|
-
*
|
|
548
|
-
*
|
|
532
|
+
* Restore the most recently meta-double-click-hidden leaf (LIFO), skipping entries
|
|
533
|
+
* that no longer apply — removed objects, or ones already shown again via the tree.
|
|
534
|
+
* In Studio the restored leaf keeps edges off (presentation); in CAD its pre-hide
|
|
535
|
+
* edge state is restored. Bound to a meta-double-click on empty space, so a hidden
|
|
536
|
+
* object can be brought back without the tree (notably in Studio). @public
|
|
549
537
|
*/
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
538
|
+
showLastHidden: () => void;
|
|
539
|
+
/** Component under the cursor (hover); committed on left-click. */
|
|
540
|
+
get lastObject(): PickedComponent | null;
|
|
541
|
+
/** Last committed selection. */
|
|
542
|
+
get lastSelection(): PickedComponent | null;
|
|
543
|
+
/** Enable/disable the double-click pick handler (on when no tool is active). */
|
|
544
|
+
setPickHandler(flag: boolean): void;
|
|
545
|
+
/** Enable/disable click+key selection input (on while a select/measure tool is active). */
|
|
546
|
+
setSelectionInput(flag: boolean): void;
|
|
547
|
+
/** Clear the current selection (and reset the select tool). */
|
|
548
|
+
clearSelection: () => void;
|
|
553
549
|
/**
|
|
554
550
|
* Handle a backend response sent by the backend
|
|
555
551
|
* The response is a JSON object sent by the Python backend through VSCode
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import * as THREE from "three";
|
|
2
|
+
import type { ComponentRegistry } from "./id-picking.js";
|
|
3
|
+
/**
|
|
4
|
+
* Shader-based component highlight (compact graph).
|
|
5
|
+
*
|
|
6
|
+
* Design:
|
|
7
|
+
* - Per-component highlight state lives in ONE `R8UI` data texture indexed by
|
|
8
|
+
* `componentId` (the attribute already on the compact geometry). The texture is
|
|
9
|
+
* shared by every compact visual material via `onBeforeCompile`, so a state
|
|
10
|
+
* write is reflected by all materials with no recompile.
|
|
11
|
+
* - State is BIT FLAGS ({@link HighlightFlag}); SELECTED wins over HOVER.
|
|
12
|
+
* - `selectSolid` sets the flag for every registry component sharing a `solidPath`.
|
|
13
|
+
*
|
|
14
|
+
* Driven by the live event loop via `IdPicker.pickAt → registry → controller`.
|
|
15
|
+
*/
|
|
16
|
+
/** Highlight color for a selected component (was `ObjectGroup.HIGHLIGHT_COLOR_SELECTED`). */
|
|
17
|
+
export declare const HIGHLIGHT_COLOR_SELECTED = 5480675;
|
|
18
|
+
/** Highlight color for a hovered, not-selected component (was `HIGHLIGHT_COLOR_HOVER`). */
|
|
19
|
+
export declare const HIGHLIGHT_COLOR_HOVER = 9026019;
|
|
20
|
+
/**
|
|
21
|
+
* Per-topo FOCUS BASE sizes (was `ObjectGroup.vertexFocusSize` / `edgeFocusWidth`).
|
|
22
|
+
* These are injected PER-MATERIAL by the `patch*Material` methods (a `#define` /
|
|
23
|
+
* material-local uniform), NOT via the shared {@link HighlightUniforms} — edges
|
|
24
|
+
* (5) and vertices (8) need different values, and the hover-vs-selected `−2` delta
|
|
25
|
+
* (`objectgroup.ts:285-298 widen()`) is resolved in-shader from the {@link
|
|
26
|
+
* HighlightFlag} bits: `HOVER → base`, `SELECTED && !HOVER → base − 2`, else the
|
|
27
|
+
* material's authored size.
|
|
28
|
+
*/
|
|
29
|
+
export declare const VERTEX_FOCUS_SIZE = 6;
|
|
30
|
+
export declare const EDGE_FOCUS_WIDTH = 5;
|
|
31
|
+
/**
|
|
32
|
+
* Per-component highlight state, stored as bit flags in one texel of the state
|
|
33
|
+
* texture. SELECTED takes precedence over HOVER when both are set, so hovering an
|
|
34
|
+
* already-selected component keeps the selected color (matches the old
|
|
35
|
+
* `_getHighlightColor` / `unhighlight(true)`).
|
|
36
|
+
*/
|
|
37
|
+
export declare const HighlightFlag: {
|
|
38
|
+
readonly NONE: 0;
|
|
39
|
+
readonly SELECTED: number;
|
|
40
|
+
readonly HOVER: number;
|
|
41
|
+
};
|
|
42
|
+
export type HighlightFlagValue = (typeof HighlightFlag)[keyof typeof HighlightFlag];
|
|
43
|
+
/**
|
|
44
|
+
* Width of the highlight-state data texture in texels. Height grows with the
|
|
45
|
+
* component count: `height = ceil((maxId + 1) / WIDTH)`. A component's texel is at
|
|
46
|
+
* `(id % WIDTH, floor(id / WIDTH))` — the same mapping the shader recomputes.
|
|
47
|
+
*/
|
|
48
|
+
export declare const HIGHLIGHT_STATE_TEXTURE_WIDTH = 2048;
|
|
49
|
+
/** Uniform: the shared `usampler2D` highlight-state texture (R8UI). */
|
|
50
|
+
export declare const U_HIGHLIGHT_STATE = "uHighlightState";
|
|
51
|
+
/** Uniform: texture width, for `id -> ivec2` texel coordinates. */
|
|
52
|
+
export declare const U_HIGHLIGHT_TEX_WIDTH = "uHighlightTexWidth";
|
|
53
|
+
/** Uniform: selected color (linear RGB vec3). */
|
|
54
|
+
export declare const U_HIGHLIGHT_SELECTED_COLOR = "uHighlightSelectedColor";
|
|
55
|
+
/** Uniform: hover color (linear RGB vec3). */
|
|
56
|
+
export declare const U_HIGHLIGHT_HOVER_COLOR = "uHighlightHoverColor";
|
|
57
|
+
/**
|
|
58
|
+
* The shared `THREE.IUniform` set bound into every patched compact material. One
|
|
59
|
+
* instance per {@link HighlightController}; the same object is referenced by all
|
|
60
|
+
* materials so a single write updates them together. Property names MUST match the
|
|
61
|
+
* `U_HIGHLIGHT_*` GLSL identifier constants above.
|
|
62
|
+
*
|
|
63
|
+
* Intentionally TOPO-AGNOSTIC: focus sizes are per-topo and the original (authored)
|
|
64
|
+
* size is per-material, so those are injected by `patch*Material` per material —
|
|
65
|
+
* NOT here. See {@link VERTEX_FOCUS_SIZE} / {@link EDGE_FOCUS_WIDTH}.
|
|
66
|
+
*/
|
|
67
|
+
export interface HighlightUniforms {
|
|
68
|
+
uHighlightState: {
|
|
69
|
+
value: THREE.DataTexture | null;
|
|
70
|
+
};
|
|
71
|
+
uHighlightTexWidth: {
|
|
72
|
+
value: number;
|
|
73
|
+
};
|
|
74
|
+
uHighlightSelectedColor: {
|
|
75
|
+
value: THREE.Color;
|
|
76
|
+
};
|
|
77
|
+
uHighlightHoverColor: {
|
|
78
|
+
value: THREE.Color;
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Minimal material surface the patch methods need. Declared structurally because
|
|
83
|
+
* three's examples-jsm `LineMaterial` has a `vertexColors: string | boolean` field
|
|
84
|
+
* that is not assignable to the nominal `THREE.Material` type.
|
|
85
|
+
*/
|
|
86
|
+
type PatchableMaterial = Pick<THREE.Material, "onBeforeCompile" | "customProgramCacheKey" | "needsUpdate" | "userData">;
|
|
87
|
+
/**
|
|
88
|
+
* Owns the per-component highlight state texture and patches compact visual
|
|
89
|
+
* materials to read it. Created by the compact `NestedGroup` alongside its
|
|
90
|
+
* `ComponentRegistry`.
|
|
91
|
+
*
|
|
92
|
+
* Lifecycle: construct → `patch*Material` on each compact face/edge/vertex visual
|
|
93
|
+
* material as it is built → `resize(registry.maxId)` once all components are
|
|
94
|
+
* registered → `setHover` / `setSelected` / `selectSolid` / `clear` to drive
|
|
95
|
+
* highlight → `dispose`.
|
|
96
|
+
*/
|
|
97
|
+
export declare class HighlightController {
|
|
98
|
+
/** The registry whose ids index the state texture. */
|
|
99
|
+
readonly registry: ComponentRegistry;
|
|
100
|
+
/** Shared uniforms bound into every patched material. */
|
|
101
|
+
readonly uniforms: HighlightUniforms;
|
|
102
|
+
/** Backing R8UI state texture (one byte = {@link HighlightFlag} bits per id). */
|
|
103
|
+
private texture;
|
|
104
|
+
/** CPU-side mirror of the texture data (length = `capacity`). */
|
|
105
|
+
private data;
|
|
106
|
+
/** Number of texels currently allocated (= width * height ≥ maxId + 1). */
|
|
107
|
+
private capacity;
|
|
108
|
+
/** Ids currently carrying the HOVER flag (one component, or a whole solid). */
|
|
109
|
+
private hoverIds;
|
|
110
|
+
/** Cheap identity of the current hover target so a repeat is a no-op. */
|
|
111
|
+
private hoverKey;
|
|
112
|
+
/**
|
|
113
|
+
* @param registry - the compact group's component registry; sizes the texture
|
|
114
|
+
* and resolves `solidPath` for {@link selectSolid}.
|
|
115
|
+
*/
|
|
116
|
+
constructor(registry: ComponentRegistry);
|
|
117
|
+
/**
|
|
118
|
+
* Allocate an R8UI data texture (+ CPU mirror) holding at least `texelCount`
|
|
119
|
+
* texels. `NearestFilter`, no mips — the shader reads exact integer flags via
|
|
120
|
+
* `texelFetch`. This is the FROZEN texture format.
|
|
121
|
+
*/
|
|
122
|
+
private _allocate;
|
|
123
|
+
/** The shared state texture (re-created by {@link resize}). */
|
|
124
|
+
get stateTexture(): THREE.DataTexture;
|
|
125
|
+
/**
|
|
126
|
+
* Set or clear `bit` on a component's texel and flag the texture for re-upload
|
|
127
|
+
* on change. The linear data index equals the id (row-major, width-W texels), so
|
|
128
|
+
* texel `(id % W, floor(id / W))` is `data[id]`. Ignores background (0) and ids
|
|
129
|
+
* past the current capacity (caller must {@link resize} first).
|
|
130
|
+
*/
|
|
131
|
+
private _setBit;
|
|
132
|
+
/**
|
|
133
|
+
* Move the HOVER flag onto exactly the given `ids` (clearing it from the
|
|
134
|
+
* previously hovered set). `key` is a cheap identity so a repeat target is a
|
|
135
|
+
* no-op — without it, re-hovering the same target every mouse-move would toggle
|
|
136
|
+
* the bits off→on and re-upload the texture each frame. Does not touch SELECTED.
|
|
137
|
+
*/
|
|
138
|
+
private _applyHover;
|
|
139
|
+
/**
|
|
140
|
+
* Move the HOVER flag onto a single component `id` (clearing the previous hover),
|
|
141
|
+
* or clear hover entirely when `id` is `null`/background.
|
|
142
|
+
*/
|
|
143
|
+
setHover(id: number | null): void;
|
|
144
|
+
/**
|
|
145
|
+
* HOVER a whole solid (its FACES only — see {@link selectSolid}), or clear hover
|
|
146
|
+
* when `null`. Mirrors {@link selectSolid} for the transient hover state.
|
|
147
|
+
*/
|
|
148
|
+
setHoverSolid(solidPath: string | null): void;
|
|
149
|
+
/** Set or clear the SELECTED flag for a single component id. */
|
|
150
|
+
setSelected(id: number, flag: boolean): void;
|
|
151
|
+
/** Whether a component currently carries the SELECTED flag. */
|
|
152
|
+
isSelected(id: number): boolean;
|
|
153
|
+
/**
|
|
154
|
+
* Whether a solid is selected — every one of its faces carries SELECTED (false if it
|
|
155
|
+
* has no faces). Used for solid toggle, so a solid that is only partially selected
|
|
156
|
+
* (e.g. one face previously single-selected) is treated as not-selected and a click
|
|
157
|
+
* selects the whole solid rather than clearing it.
|
|
158
|
+
*/
|
|
159
|
+
isSolidSelected(solidPath: string): boolean;
|
|
160
|
+
/**
|
|
161
|
+
* Set or clear SELECTED for a whole solid. Flags only the solid's **faces**
|
|
162
|
+
* (`topo === "face"`) — the body tints while edges keep their colour and corners
|
|
163
|
+
* stay hidden. Iterates {@link ComponentRegistry.entries}.
|
|
164
|
+
*/
|
|
165
|
+
selectSolid(solidPath: string, flag: boolean): void;
|
|
166
|
+
/** Clear all highlight state (hover + selection) for every component. */
|
|
167
|
+
clear(): void;
|
|
168
|
+
/**
|
|
169
|
+
* Grow the state texture to hold at least `maxId + 1` texels, preserving existing
|
|
170
|
+
* state, and re-bind the new texture object into {@link uniforms}. No-op when the
|
|
171
|
+
* current capacity already suffices.
|
|
172
|
+
*/
|
|
173
|
+
resize(maxId: number): void;
|
|
174
|
+
/**
|
|
175
|
+
* Shared `onBeforeCompile` installer: binds the shared uniforms, prepends the
|
|
176
|
+
* common vertex/fragment headers, forwards the component id, then runs the
|
|
177
|
+
* topo-specific `customize` (color override / widening). Idempotent per material.
|
|
178
|
+
*/
|
|
179
|
+
private _install;
|
|
180
|
+
/**
|
|
181
|
+
* Install `onBeforeCompile` on a face (`MeshStandardMaterial`) visual material.
|
|
182
|
+
* Overwrites `diffuseColor.rgb` with the highlight color BEFORE lighting (after
|
|
183
|
+
* the base color/map is applied) so a highlighted face is lit exactly as the old
|
|
184
|
+
* `material.color` swap was — selected wins over hover.
|
|
185
|
+
*/
|
|
186
|
+
patchFaceMaterial(material: PatchableMaterial): void;
|
|
187
|
+
/**
|
|
188
|
+
* Install `onBeforeCompile` on an edge (`LineMaterial`) visual material (Option A).
|
|
189
|
+
* Widens the screen-space half-width for flagged segments by patching the stock
|
|
190
|
+
* LineMaterial expansion (`offset *= linewidth;`, screen-space branch) and recolors
|
|
191
|
+
* via the shared fragment override. `vertexColors` axes/trihedron carry no
|
|
192
|
+
* registry id (state 0) so they stay inert.
|
|
193
|
+
*/
|
|
194
|
+
patchEdgeMaterial(material: PatchableMaterial): void;
|
|
195
|
+
/**
|
|
196
|
+
* Install `onBeforeCompile` on a vertex (`PointsMaterial`) visual material.
|
|
197
|
+
* Flagged points widen to the focus size and recolor. When `cullUnhighlighted`
|
|
198
|
+
* (the solid highlight-Points cloud, invisible until selected), non-flagged points
|
|
199
|
+
* are culled — `gl_PointSize = 0` AND a fragment `discard` (the discard is the
|
|
200
|
+
* real guard; size-0 rasterization is driver-defined). Standalone visible vertices
|
|
201
|
+
* (default) keep their authored `size` and color when unflagged.
|
|
202
|
+
*/
|
|
203
|
+
patchVertexMaterial(material: PatchableMaterial, options?: {
|
|
204
|
+
cullUnhighlighted?: boolean;
|
|
205
|
+
}): void;
|
|
206
|
+
/** Dispose the state texture and release tracking. */
|
|
207
|
+
dispose(): void;
|
|
208
|
+
}
|
|
209
|
+
export {};
|