three-cad-viewer 4.3.8 → 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/studio-manager.d.ts +7 -0
- package/dist/core/types.d.ts +24 -6
- package/dist/core/viewer-state.d.ts +1 -1
- package/dist/core/viewer.d.ts +44 -47
- package/dist/index.d.ts +5 -5
- package/dist/rendering/environment.d.ts +3 -19
- 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 +11 -7
- package/dist/rendering/picked.d.ts +55 -0
- package/dist/rendering/studio-composer.d.ts +3 -3
- package/dist/rendering/tree-model.d.ts +1 -1
- 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 +4867 -1562
- 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 +4867 -1562
- 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 +17 -5
- package/dist/tools/cad_tools/ui.d.ts +8 -6
- package/dist/ui/display.d.ts +25 -2
- package/dist/utils/utils.d.ts +1 -1
- package/package.json +4 -1
- package/dist/rendering/raycast.d.ts +0 -111
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as THREE from "three";
|
|
2
2
|
import { DistancePanel, PropertiesPanel, DistanceResponseData, PropertiesResponseData } from "./ui.js";
|
|
3
|
-
import type {
|
|
3
|
+
import type { PickedComponent } from "../../rendering/picked.js";
|
|
4
4
|
import type { ViewerLike } from "./tools.js";
|
|
5
5
|
interface PanelDragData {
|
|
6
6
|
x: number | null;
|
|
@@ -8,7 +8,7 @@ interface PanelDragData {
|
|
|
8
8
|
clicked: boolean;
|
|
9
9
|
}
|
|
10
10
|
declare class Measurement {
|
|
11
|
-
selectedShapes:
|
|
11
|
+
selectedShapes: PickedComponent[];
|
|
12
12
|
point1: THREE.Vector3 | null;
|
|
13
13
|
point2: THREE.Vector3 | null;
|
|
14
14
|
middlePoint: THREE.Vector3 | null;
|
|
@@ -26,7 +26,8 @@ declare class Measurement {
|
|
|
26
26
|
coneLength: number | undefined;
|
|
27
27
|
panelDragData: PanelDragData;
|
|
28
28
|
shift: boolean;
|
|
29
|
-
|
|
29
|
+
/** Monotonic request id; invalidates stale `_waitResponse` polls (see `_waitResponse`). */
|
|
30
|
+
_responseGen: number;
|
|
30
31
|
constructor(viewer: ViewerLike, panel: DistancePanel | PropertiesPanel);
|
|
31
32
|
enableContext(): void;
|
|
32
33
|
disableContext(): void;
|
|
@@ -45,7 +46,7 @@ declare class Measurement {
|
|
|
45
46
|
/**
|
|
46
47
|
* Wait for the backend to send the data needed to display the real BREP measurement.
|
|
47
48
|
*/
|
|
48
|
-
_waitResponse(resolve: (data: DistanceResponseData | PropertiesResponseData) => void, _reject: (reason?: Error) => void): void;
|
|
49
|
+
_waitResponse(resolve: (data: DistanceResponseData | PropertiesResponseData) => void, _reject: (reason?: Error) => void, gen: number): void;
|
|
49
50
|
/**
|
|
50
51
|
* Update the measurement panel, if enough shapes have been selected for the current tool,
|
|
51
52
|
* ask the backend for the real measurement data and display it.
|
|
@@ -54,7 +55,7 @@ declare class Measurement {
|
|
|
54
55
|
/**
|
|
55
56
|
* React to each new selected element in the viewer.
|
|
56
57
|
*/
|
|
57
|
-
handleSelection: (selectedObj:
|
|
58
|
+
handleSelection: (selectedObj: PickedComponent, shift?: boolean) => void;
|
|
58
59
|
_mouseup: (e: MouseEvent) => void;
|
|
59
60
|
_movePanel: () => void;
|
|
60
61
|
/**
|
|
@@ -71,8 +72,7 @@ declare class Measurement {
|
|
|
71
72
|
dispose(): void;
|
|
72
73
|
}
|
|
73
74
|
declare class DistanceMeasurement extends Measurement {
|
|
74
|
-
|
|
75
|
-
constructor(viewer: ViewerLike, debug: boolean);
|
|
75
|
+
constructor(viewer: ViewerLike);
|
|
76
76
|
_createPanel(): void;
|
|
77
77
|
_getMaxObjSelected(): number;
|
|
78
78
|
_getPoints(): void;
|
|
@@ -84,8 +84,7 @@ declare class DistanceMeasurement extends Measurement {
|
|
|
84
84
|
handleResponse(response: DistanceResponseData): void;
|
|
85
85
|
}
|
|
86
86
|
declare class PropertiesMeasurement extends Measurement {
|
|
87
|
-
|
|
88
|
-
constructor(viewer: ViewerLike, debug: boolean);
|
|
87
|
+
constructor(viewer: ViewerLike);
|
|
89
88
|
_createPanel(): void;
|
|
90
89
|
_getMaxObjSelected(): number;
|
|
91
90
|
_getPoint(): void;
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import * as THREE from "three";
|
|
2
|
+
import type { TopoType, ComponentInfo } from "../../rendering/id-picking.js";
|
|
3
|
+
import type { ToolType } from "./tools.js";
|
|
4
|
+
/**
|
|
5
|
+
* A measurement response. Carries both `subtype` (so the viewer's
|
|
6
|
+
* `handleBackendResponse` routes it like a Python response) and `tool_type` (so
|
|
7
|
+
* `Tools.handleResponse` dispatches to the right measurement). The remaining fields
|
|
8
|
+
* (`result`, `refpoint*`, `shape_type`, `geom_type`, …) mirror the Python backend.
|
|
9
|
+
*/
|
|
10
|
+
export interface MeasureResponse {
|
|
11
|
+
type: "backend_response";
|
|
12
|
+
subtype: "tool_response";
|
|
13
|
+
tool_type: ToolType;
|
|
14
|
+
[key: string]: unknown;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* TypeScript mesh-based measurement backend.
|
|
18
|
+
*
|
|
19
|
+
* Computes meaningful measurements (area, length, volume, bounding box, min/center
|
|
20
|
+
* distance, angle) from the tessellated mesh, so the measure tools work WITHOUT the
|
|
21
|
+
* external Python (`ocp_vscode`) backend — the default when developing three-cad-viewer
|
|
22
|
+
* standalone. Selected via the `externalMeasurementBackend` option (default `false` =
|
|
23
|
+
* this backend; `ocp_vscode` sets `true` to use Python). See MeshBackend.md.
|
|
24
|
+
*
|
|
25
|
+
* Accuracy: `shape_type` / `geom_type` are EXACT (carried per-component in the
|
|
26
|
+
* tessellation `face_types` / `edge_types`). Numeric values are mesh-accurate — exact
|
|
27
|
+
* for planar faces / straight edges, within tessellation deflection for curved geometry.
|
|
28
|
+
*
|
|
29
|
+
* This module is the FROZEN contract (APPROACH.md "contracts-first"): the GeomAbs name
|
|
30
|
+
* tables, the {@link MeshComponentGeometry} shape the provider yields, the
|
|
31
|
+
* {@link MeshGeometryProvider} interface, and the pure geometry math operate on
|
|
32
|
+
* world-space coordinates (the provider applies each node's transform).
|
|
33
|
+
*/
|
|
34
|
+
/** GeomAbs_SurfaceType ordinals → name (face_types). */
|
|
35
|
+
export declare const SURFACE_TYPE_NAMES: readonly ["Plane", "Cylinder", "Cone", "Sphere", "Torus", "BezierSurface", "BSplineSurface", "SurfaceOfRevolution", "SurfaceOfExtrusion", "OffsetSurface", "OtherSurface"];
|
|
36
|
+
/** GeomAbs_CurveType ordinals → name (edge_types). */
|
|
37
|
+
export declare const CURVE_TYPE_NAMES: readonly ["Line", "Circle", "Ellipse", "Hyperbola", "Parabola", "BezierCurve", "BSplineCurve", "OffsetCurve", "OtherCurve"];
|
|
38
|
+
/** Resolve a face's `face_types` code to its geom_type name (`"Other"` if unknown). */
|
|
39
|
+
export declare function faceGeomType(code: number): string;
|
|
40
|
+
/** Resolve an edge's `edge_types` code to its geom_type name (`"Other"` if unknown). */
|
|
41
|
+
export declare function edgeGeomType(code: number): string;
|
|
42
|
+
/**
|
|
43
|
+
* Short, lowercase geom_type for a status-line readout. Drops the trailing
|
|
44
|
+
* `Curve`/`Surface` suffix (`BSplineSurface`/`BSplineCurve` → `bspline`,
|
|
45
|
+
* `Plane` → `plane`, `Line` → `line`) and spaces the remaining CamelCase words
|
|
46
|
+
* for readability (`SurfaceOfExtrusion` → `surface of extrusion`,
|
|
47
|
+
* `SurfaceOfRevolution` → `surface of revolution`). The lowercase→uppercase
|
|
48
|
+
* split leaves single words and the leading-caps `BSpline` untouched. Topo
|
|
49
|
+
* selects the surface vs curve table.
|
|
50
|
+
*/
|
|
51
|
+
export declare function displayGeomType(topo: TopoType, code: number): string;
|
|
52
|
+
/**
|
|
53
|
+
* Mesh geometry for one resolved component, in WORLD space (the provider has already
|
|
54
|
+
* applied the owning node's transform). Discriminated by {@link topo}:
|
|
55
|
+
* - `face` / `solid`: {@link positions} is a vertex pool, {@link indices} are triangle
|
|
56
|
+
* index triples into it (a solid merges all its faces).
|
|
57
|
+
* - `edge`: {@link positions} is a flat list of segment endpoint pairs (6 floats per
|
|
58
|
+
* segment: `x0,y0,z0, x1,y1,z1`); {@link indices} is undefined.
|
|
59
|
+
* - `vertex`: {@link positions} is exactly one point (3 floats); {@link indices} undefined.
|
|
60
|
+
*/
|
|
61
|
+
export interface MeshComponentGeometry {
|
|
62
|
+
topo: TopoType;
|
|
63
|
+
/** Raw GeomAbs code (`face_types`/`edge_types` entry); `-1` for vertex/solid. */
|
|
64
|
+
geomType: number;
|
|
65
|
+
/** World-space coordinates (layout depends on {@link topo}; see interface doc). */
|
|
66
|
+
positions: Float32Array;
|
|
67
|
+
/** Triangle index triples into {@link positions} (face/solid only). */
|
|
68
|
+
indices?: Uint32Array;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Resolves a backend component path (e.g. `"/box/faces/faces_3"`, `"/box/edges/edges_1"`,
|
|
72
|
+
* `"/box/vertices/vertices_0"`, or a bare solid path `"/box"`) to its world-space mesh
|
|
73
|
+
* geometry. Returns `null` for unknown paths or components with no captured geometry.
|
|
74
|
+
* Populated at tessellation time (see Phase task: render-shape / nestedgroup).
|
|
75
|
+
*/
|
|
76
|
+
export interface MeshGeometryProvider {
|
|
77
|
+
resolve(path: string): MeshComponentGeometry | null;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Decomposition of a component into closest-distance primitives. The minimum distance
|
|
81
|
+
* between two triangle meshes is always realized by a vertex-vs-triangle or an
|
|
82
|
+
* edge-vs-edge pair, so these three lists are sufficient (and exact for the mesh).
|
|
83
|
+
*/
|
|
84
|
+
export interface MeshFeatures {
|
|
85
|
+
/** All vertices (world space). */
|
|
86
|
+
points: THREE.Vector3[];
|
|
87
|
+
/** Triangles as [a, b, c] vertex triples (face/solid). */
|
|
88
|
+
tris: [THREE.Vector3, THREE.Vector3, THREE.Vector3][];
|
|
89
|
+
/** Line segments as [a, b] endpoint pairs (edges, and triangle edges of faces). */
|
|
90
|
+
segs: [THREE.Vector3, THREE.Vector3][];
|
|
91
|
+
}
|
|
92
|
+
/** Build the {@link MeshFeatures} primitive sets from a component's geometry. */
|
|
93
|
+
export declare function buildFeatures(geom: MeshComponentGeometry): MeshFeatures;
|
|
94
|
+
/** Total surface area of a triangulated face/solid (Σ ½·|(b−a)×(c−a)|). */
|
|
95
|
+
export declare function triangulatedArea(geom: MeshComponentGeometry): number;
|
|
96
|
+
/** Total length of an edge polyline (Σ segment lengths). */
|
|
97
|
+
export declare function polylineLength(geom: MeshComponentGeometry): number;
|
|
98
|
+
/**
|
|
99
|
+
* Signed volume of a closed triangulated solid via the divergence theorem
|
|
100
|
+
* (Σ (1/6)·a·(b×c) over triangles). The tessellation winds triangles CCW outward, so
|
|
101
|
+
* the sum is positive; returned as an absolute value for robustness.
|
|
102
|
+
*/
|
|
103
|
+
export declare function meshVolume(geom: MeshComponentGeometry): number;
|
|
104
|
+
/**
|
|
105
|
+
* Exact circle (center + radius) through three well-separated points of a circular
|
|
106
|
+
* edge's tessellation polyline. The tessellation vertices lie ON the true curve, so
|
|
107
|
+
* the circumcircle of any three is exact (up to float precision). `positions` is the
|
|
108
|
+
* flat segment-endpoint list (works for both arcs and closed circles). Returns `null`
|
|
109
|
+
* if the three points are degenerate/collinear.
|
|
110
|
+
*/
|
|
111
|
+
export declare function circleFromPolyline(positions: Float32Array): {
|
|
112
|
+
center: number[];
|
|
113
|
+
radius: number;
|
|
114
|
+
} | null;
|
|
115
|
+
/**
|
|
116
|
+
* Status-line text for a hovered component — FIXED attributes only, no backend, no
|
|
117
|
+
* live cursor coord, NO path (the object is identified via the tree on double-click).
|
|
118
|
+
* Mesh-estimated length/area/volume are shown with `≈` (BRep-grade values come from
|
|
119
|
+
* the measurement tool). face: `geom: area ≈ A`; edge: `geom: len ≈ L, start/end`;
|
|
120
|
+
* vertex: coords; solid: `solid: N faces, M edges, vol ≈ V`.
|
|
121
|
+
*/
|
|
122
|
+
export declare function hoverStatusText(info: ComponentInfo, fromSolid: boolean, provider: MeshGeometrySource): string;
|
|
123
|
+
/** Axis-aligned bounding box of a component's vertices. */
|
|
124
|
+
export declare function boundingBox(geom: MeshComponentGeometry): {
|
|
125
|
+
min: number[];
|
|
126
|
+
center: number[];
|
|
127
|
+
max: number[];
|
|
128
|
+
size: number[];
|
|
129
|
+
};
|
|
130
|
+
/**
|
|
131
|
+
* Representative center point of a component (mesh approximation of `refpoint`):
|
|
132
|
+
* - vertex → the point;
|
|
133
|
+
* - edge → length-weighted midpoint of its segments;
|
|
134
|
+
* - face → area-weighted centroid of its triangles;
|
|
135
|
+
* - solid → volume-weighted centroid of its tetrahedra (apex at origin).
|
|
136
|
+
*/
|
|
137
|
+
export declare function centroid(geom: MeshComponentGeometry): THREE.Vector3;
|
|
138
|
+
/** Area-weighted average triangle normal of a face (unit length), or `null`. */
|
|
139
|
+
export declare function averageNormal(geom: MeshComponentGeometry): THREE.Vector3 | null;
|
|
140
|
+
/** Overall direction of an edge (first → last endpoint, unit length), or `null`. */
|
|
141
|
+
export declare function edgeDirection(geom: MeshComponentGeometry): THREE.Vector3 | null;
|
|
142
|
+
/** Closest point on segment [a,b] to point p, written into `out`. */
|
|
143
|
+
export declare function closestPointOnSegment(p: THREE.Vector3, a: THREE.Vector3, b: THREE.Vector3, out: THREE.Vector3): THREE.Vector3;
|
|
144
|
+
/** Closest point on triangle (a,b,c) to point p, written into `out` (Ericson §5.1.5). */
|
|
145
|
+
export declare function closestPointOnTriangle(p: THREE.Vector3, a: THREE.Vector3, b: THREE.Vector3, c: THREE.Vector3, out: THREE.Vector3): THREE.Vector3;
|
|
146
|
+
/**
|
|
147
|
+
* Closest points between segments [p1,q1] and [p2,q2], written into `outA`/`outB`;
|
|
148
|
+
* returns the squared distance (Ericson §5.1.9).
|
|
149
|
+
*/
|
|
150
|
+
export declare function closestSegmentSegment(p1: THREE.Vector3, q1: THREE.Vector3, p2: THREE.Vector3, q2: THREE.Vector3, outA: THREE.Vector3, outB: THREE.Vector3): number;
|
|
151
|
+
/**
|
|
152
|
+
* Brute-force minimum distance between two components and the realizing points.
|
|
153
|
+
* Evaluates every closest-feature pair, in BOTH argument orders, over the feature sets:
|
|
154
|
+
* point-vs-triangle, point-vs-segment, segment-vs-segment, and point-vs-point. This is
|
|
155
|
+
* the complete set of closest-feature pairs for triangle meshes and their lower-dim
|
|
156
|
+
* degenerations (edges = segments, vertices = points), so the result is exact for the
|
|
157
|
+
* mesh and independent of which component is passed first.
|
|
158
|
+
*
|
|
159
|
+
* O(Ta·Tb) — quadratic. {@link minDistance} is the production entry: it uses this
|
|
160
|
+
* directly for small components and the BVH branch-and-bound above the pair threshold.
|
|
161
|
+
* Kept exported as the reference oracle the BVH path is property-tested against.
|
|
162
|
+
*/
|
|
163
|
+
export declare function minDistanceBrute(ga: MeshComponentGeometry, gb: MeshComponentGeometry): {
|
|
164
|
+
distance: number;
|
|
165
|
+
point1: THREE.Vector3;
|
|
166
|
+
point2: THREE.Vector3;
|
|
167
|
+
};
|
|
168
|
+
/**
|
|
169
|
+
* Minimum squared distance between triangle (ta,tb,tc) and segment (sa,sb), with the
|
|
170
|
+
* realizing points (on the triangle → `outTri`, on the segment → `outSeg`). Complete
|
|
171
|
+
* set: each segment endpoint vs the triangle (covers face interior + edges + vertices)
|
|
172
|
+
* and each triangle edge vs the segment.
|
|
173
|
+
*/
|
|
174
|
+
export declare function triSegDistance(ta: THREE.Vector3, tb: THREE.Vector3, tc: THREE.Vector3, sa: THREE.Vector3, sb: THREE.Vector3, outTri: THREE.Vector3, outSeg: THREE.Vector3): number;
|
|
175
|
+
/**
|
|
176
|
+
* Minimum squared distance between triangles (a0,a1,a2) and (b0,b1,b2), with the
|
|
177
|
+
* realizing points (`outA` on the first, `outB` on the second). Complete set for
|
|
178
|
+
* disjoint triangles: each vertex vs the other triangle, plus all 9 edge-edge pairs.
|
|
179
|
+
* (Interpenetrating triangles can report a small positive value rather than 0 — the
|
|
180
|
+
* same limitation the brute oracle has, and irrelevant for distance between surfaces.)
|
|
181
|
+
*/
|
|
182
|
+
export declare function triTriDistance(a0: THREE.Vector3, a1: THREE.Vector3, a2: THREE.Vector3, b0: THREE.Vector3, b1: THREE.Vector3, b2: THREE.Vector3, outA: THREE.Vector3, outB: THREE.Vector3): number;
|
|
183
|
+
/**
|
|
184
|
+
* Minimum distance between two components and the realizing points — the production
|
|
185
|
+
* entry. Exact and sub-quadratic via a per-component AABB tree + branch-and-bound
|
|
186
|
+
* (see {@link minDistanceBrute} for the O(Ta·Tb) reference it is property-tested
|
|
187
|
+
* against, and which it delegates to for small inputs). Result is identical to the
|
|
188
|
+
* brute force and independent of argument order.
|
|
189
|
+
*/
|
|
190
|
+
export declare function minDistance(ga: MeshComponentGeometry, gb: MeshComponentGeometry): {
|
|
191
|
+
distance: number;
|
|
192
|
+
point1: THREE.Vector3;
|
|
193
|
+
point2: THREE.Vector3;
|
|
194
|
+
};
|
|
195
|
+
/** Angle (degrees) between two unit directions. */
|
|
196
|
+
export declare function angleBetween(d1: THREE.Vector3, d2: THREE.Vector3): number;
|
|
197
|
+
/**
|
|
198
|
+
* Angle (degrees) of a face normal or edge tangent to the world XY plane (+Z up),
|
|
199
|
+
* mirroring `measure.py` `angle to XY`: for a face normal, the angle to +Z; for an edge
|
|
200
|
+
* direction `abs(90 − angle(dir, +Z))`.
|
|
201
|
+
*/
|
|
202
|
+
export declare function angleToXY(dir: THREE.Vector3, isEdge: boolean): number;
|
|
203
|
+
/** Raw per-node tessellation arrays the source needs (subset of `Shape`). */
|
|
204
|
+
export interface RawNodeShape {
|
|
205
|
+
vertices?: number[] | number[][] | Float32Array | undefined;
|
|
206
|
+
triangles?: number[] | number[][] | Uint32Array | undefined;
|
|
207
|
+
triangles_per_face?: number[] | Uint32Array | undefined;
|
|
208
|
+
edges?: number[] | number[][] | Float32Array | undefined;
|
|
209
|
+
segments_per_edge?: number[] | Uint32Array | undefined;
|
|
210
|
+
obj_vertices?: number[] | Float32Array | undefined;
|
|
211
|
+
face_types?: number[] | Uint32Array | undefined;
|
|
212
|
+
edge_types?: number[] | Uint8Array | Uint32Array | undefined;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Populated as the compact `NestedGroup` tessellates each node (faces/edges/vertices),
|
|
216
|
+
* keyed by the node's `/`-path — the SAME paths the `ComponentRegistry` uses, so a
|
|
217
|
+
* backend component id resolves directly. Mode-independent: it stores the raw per-node
|
|
218
|
+
* arrays + the owning group (for `matrixWorld`) and slices/transforms on demand.
|
|
219
|
+
*/
|
|
220
|
+
export declare class MeshGeometrySource implements MeshGeometryProvider {
|
|
221
|
+
private nodes;
|
|
222
|
+
constructor();
|
|
223
|
+
/** Record a node's raw tessellation arrays. `object` provides the world transform. */
|
|
224
|
+
register(path: string, shape: RawNodeShape, object: THREE.Object3D, subtype: string | null): void;
|
|
225
|
+
/** Drop all entries (called from `NestedGroup.clear`/`dispose`). */
|
|
226
|
+
clear(): void;
|
|
227
|
+
/**
|
|
228
|
+
* Drop nodes whose path is `prefix` or lies under it (`prefix + "/"`), for
|
|
229
|
+
* {@link Viewer.removePart} — keeps the provider from growing across remove/add
|
|
230
|
+
* cycles.
|
|
231
|
+
*/
|
|
232
|
+
removeByPathPrefix(prefix: string): void;
|
|
233
|
+
/**
|
|
234
|
+
* Static face/edge counts of a node from its tessellation type arrays
|
|
235
|
+
* (`len(face_types)` / `len(edge_types)`). For a solid node these are the solid's
|
|
236
|
+
* total face/edge counts. `null` for an unknown node.
|
|
237
|
+
*/
|
|
238
|
+
nodeCounts(path: string): {
|
|
239
|
+
faces: number;
|
|
240
|
+
edges: number;
|
|
241
|
+
} | null;
|
|
242
|
+
resolve(path: string): MeshComponentGeometry | null;
|
|
243
|
+
private _typeAt;
|
|
244
|
+
/** Index triples for face `i` into the vertex pool (flat-with-counts or nested). */
|
|
245
|
+
private _faceTriangleIndices;
|
|
246
|
+
/** All triangle index triples (every face) for a solid. */
|
|
247
|
+
private _allTriangleIndices;
|
|
248
|
+
/** World-local segment endpoint pairs (6 floats/segment) for edge `i`. */
|
|
249
|
+
private _edgeSegments;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Computes measurement responses from the mesh (no external Python backend). The
|
|
253
|
+
* default measurement backend when `externalMeasurementBackend === false`. Returns a
|
|
254
|
+
* `ToolResponse` ready for `viewer.handleBackendResponse`, or `null` if a component
|
|
255
|
+
* can't be resolved (caller leaves the panel unanswered, same as a backend timeout).
|
|
256
|
+
*/
|
|
257
|
+
export declare class MeshMeasureBackend {
|
|
258
|
+
private getProvider;
|
|
259
|
+
constructor(getProvider: () => MeshGeometryProvider | null);
|
|
260
|
+
/** PropertiesMeasurement response for a single component. */
|
|
261
|
+
properties(path: string): MeasureResponse | null;
|
|
262
|
+
/** DistanceMeasurement response between two components. */
|
|
263
|
+
distance(path1: string, path2: string, center: boolean): MeasureResponse | null;
|
|
264
|
+
}
|
|
@@ -1,17 +1,18 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { PickedComponent } from "../../rendering/picked.js";
|
|
2
2
|
import type { ViewerLike } from "./tools.js";
|
|
3
3
|
declare class SelectObject {
|
|
4
4
|
viewer: ViewerLike;
|
|
5
|
-
selectedShapes:
|
|
5
|
+
selectedShapes: PickedComponent[];
|
|
6
6
|
contextEnabled: boolean;
|
|
7
7
|
constructor(viewer: ViewerLike);
|
|
8
8
|
enableContext(): void;
|
|
9
9
|
disableContext(): void;
|
|
10
10
|
_getMaxObjSelected(): null;
|
|
11
|
+
/** Numeric sub-index from a leaf name like "faces_3" → "3". */
|
|
11
12
|
private _getIndex;
|
|
12
13
|
private _includes;
|
|
13
14
|
notify(): void;
|
|
14
|
-
handleSelection(selectedObj:
|
|
15
|
+
handleSelection(selectedObj: PickedComponent | null): void;
|
|
15
16
|
private _removeLastSelectedObj;
|
|
16
17
|
removeLastSelectedObj(force: boolean): void;
|
|
17
18
|
update(): void;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as THREE from "three";
|
|
2
2
|
import { DistanceMeasurement, PropertiesMeasurement } from "./measure.js";
|
|
3
3
|
import { SelectObject } from "./select.js";
|
|
4
|
-
import type {
|
|
4
|
+
import type { PickedComponent } from "../../rendering/picked.js";
|
|
5
|
+
import type { MeshMeasureBackend, MeasureResponse } from "./mesh-measure.js";
|
|
5
6
|
/**
|
|
6
7
|
* Enum representing tool types.
|
|
7
8
|
*/
|
|
@@ -11,7 +12,7 @@ export declare const ToolTypes: {
|
|
|
11
12
|
readonly PROPERTIES: "PropertiesMeasurement";
|
|
12
13
|
readonly SELECT: "SelectObjects";
|
|
13
14
|
};
|
|
14
|
-
export type ToolType = typeof ToolTypes[keyof typeof ToolTypes];
|
|
15
|
+
export type ToolType = (typeof ToolTypes)[keyof typeof ToolTypes];
|
|
15
16
|
/**
|
|
16
17
|
* UI elements for measurement panels.
|
|
17
18
|
*/
|
|
@@ -66,6 +67,10 @@ export interface ViewerLike {
|
|
|
66
67
|
ortho: boolean;
|
|
67
68
|
bb_radius: number;
|
|
68
69
|
checkChanges(changes: Record<string, unknown>, notify?: boolean): void;
|
|
70
|
+
/** Internal mesh measurement backend (answers when no external/Python backend). */
|
|
71
|
+
meshBackend: MeshMeasureBackend;
|
|
72
|
+
/** Dispatch a (mesh or backend) measurement response to the tools. */
|
|
73
|
+
handleBackendResponse(response: MeasureResponse): void;
|
|
69
74
|
}
|
|
70
75
|
export interface ToolResponse {
|
|
71
76
|
tool_type: ToolType;
|
|
@@ -77,7 +82,7 @@ export declare class Tools {
|
|
|
77
82
|
propertiesMeasurement: PropertiesMeasurement;
|
|
78
83
|
selectObject: SelectObject;
|
|
79
84
|
enabledTool: ToolType | null;
|
|
80
|
-
constructor(viewer: ViewerLike
|
|
85
|
+
constructor(viewer: ViewerLike);
|
|
81
86
|
/**
|
|
82
87
|
* Enables a specific tool. (Disables the currently enabled tool if any)
|
|
83
88
|
*/
|
|
@@ -89,10 +94,17 @@ export declare class Tools {
|
|
|
89
94
|
_disable(): void;
|
|
90
95
|
handleRemoveLastSelection(force?: boolean): void;
|
|
91
96
|
/**
|
|
92
|
-
* Handle selected object from
|
|
97
|
+
* Handle a selected object from the picker.
|
|
93
98
|
*/
|
|
94
|
-
handleSelectedObj(selectedObj:
|
|
99
|
+
handleSelectedObj(selectedObj: PickedComponent, isNewObject: boolean, shift: boolean): void;
|
|
95
100
|
handleResetSelection(): void;
|
|
101
|
+
/**
|
|
102
|
+
* Compute and dispatch a measurement response from the internal mesh backend for the
|
|
103
|
+
* active measure tool. `payload` is `[...selectedPaths, shift]` (the same array
|
|
104
|
+
* measure sends to the Python backend): Distance = 2 paths + shift, Properties = 1
|
|
105
|
+
* path + shift. No-op for any other tool / shape count.
|
|
106
|
+
*/
|
|
107
|
+
answerMeasurement(payload: unknown): void;
|
|
96
108
|
/**
|
|
97
109
|
* Handle the response from the backend.
|
|
98
110
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { type TopoFilterType } from "../../rendering/id-picking.js";
|
|
2
2
|
import type { DisplayLike } from "./tools.js";
|
|
3
3
|
interface CallbackEntry {
|
|
4
4
|
callback: EventListener;
|
|
@@ -12,6 +12,8 @@ declare abstract class Panel {
|
|
|
12
12
|
constructor(display: DisplayLike);
|
|
13
13
|
private removeTable;
|
|
14
14
|
protected resetTable(): void;
|
|
15
|
+
/** Set the panel title (e.g. "Distance" or "Distance (mesh based)"). */
|
|
16
|
+
protected setHeader(text: string): void;
|
|
15
17
|
protected abstract getHtmlElement(): HTMLElement;
|
|
16
18
|
/**
|
|
17
19
|
* Show or hide the panel
|
|
@@ -60,15 +62,15 @@ declare class PropertiesPanel extends Panel {
|
|
|
60
62
|
declare class FilterByDropDownMenu {
|
|
61
63
|
private display;
|
|
62
64
|
private elements;
|
|
63
|
-
private raycaster;
|
|
64
65
|
/**
|
|
65
|
-
*
|
|
66
|
+
* The current topo filter the GPU id picker reads. `[TopoFilter.none]` means
|
|
67
|
+
* "no filter" (all topos eligible).
|
|
66
68
|
*/
|
|
67
|
-
|
|
69
|
+
currentFilter: TopoFilterType[];
|
|
68
70
|
/**
|
|
69
|
-
*
|
|
71
|
+
* Initialize a new filter drop down menu.
|
|
70
72
|
*/
|
|
71
|
-
|
|
73
|
+
constructor(display: DisplayLike);
|
|
72
74
|
private setValue;
|
|
73
75
|
private toggleDropdown;
|
|
74
76
|
private closeDropdown;
|
package/dist/ui/display.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ import type { ThemeInput, ClipIndex } from "../core/types.js";
|
|
|
14
14
|
*/
|
|
15
15
|
export interface DisplayOptions {
|
|
16
16
|
measureTools: boolean;
|
|
17
|
-
|
|
17
|
+
externalMeasurementBackend: boolean;
|
|
18
18
|
selectTool: boolean;
|
|
19
19
|
explodeTool: boolean;
|
|
20
20
|
zscaleTool: boolean;
|
|
@@ -100,6 +100,7 @@ declare class Display {
|
|
|
100
100
|
container: HTMLElement;
|
|
101
101
|
cadBody: HTMLElement;
|
|
102
102
|
cadView: HTMLElement;
|
|
103
|
+
statusLine: HTMLElement;
|
|
103
104
|
cadTree: HTMLElement;
|
|
104
105
|
cadTreeScrollContainer: HTMLElement;
|
|
105
106
|
cadTreeToggles: HTMLElement;
|
|
@@ -158,7 +159,6 @@ declare class Display {
|
|
|
158
159
|
viewer: Viewer;
|
|
159
160
|
state: ViewerState;
|
|
160
161
|
measureTools: boolean;
|
|
161
|
-
measurementDebug: boolean;
|
|
162
162
|
selectTool: boolean;
|
|
163
163
|
explodeTool: boolean;
|
|
164
164
|
zscaleTool: boolean;
|
|
@@ -247,6 +247,12 @@ declare class Display {
|
|
|
247
247
|
* @param center - The center coordinates [x, y, z].
|
|
248
248
|
*/
|
|
249
249
|
showCenterInfo(center: Vector3Tuple): void;
|
|
250
|
+
/**
|
|
251
|
+
* Set the hover status line (preselection readout). Empty string clears it.
|
|
252
|
+
* A rounded overlay badge stacked below the grid-size indicator at the bottom
|
|
253
|
+
* left of the canvas; hidden entirely when empty so no empty badge shows.
|
|
254
|
+
*/
|
|
255
|
+
setStatusLine(text: string): void;
|
|
250
256
|
/**
|
|
251
257
|
* Display bounding box information for a selected object.
|
|
252
258
|
* @param path - The object's path in the tree.
|
|
@@ -389,6 +395,16 @@ declare class Display {
|
|
|
389
395
|
* @internal
|
|
390
396
|
*/
|
|
391
397
|
private _restoreToolsAfterStudio;
|
|
398
|
+
/**
|
|
399
|
+
* Entering Clip mode: hide the measure + select tool buttons (a measure/select
|
|
400
|
+
* tool can't be active here — it disables the clip tab — but the buttons must not
|
|
401
|
+
* be invocable while clipping). Mirrors {@link _deactivateToolsForStudio};
|
|
402
|
+
* explode/zscale stay enabled for consistency with studio mode. Restored by
|
|
403
|
+
* {@link _restoreToolsAfterClip} on leave.
|
|
404
|
+
*/
|
|
405
|
+
private _deactivateToolsForClip;
|
|
406
|
+
/** Leaving Clip mode: restore measure + select buttons per their feature flags. */
|
|
407
|
+
private _restoreToolsAfterClip;
|
|
392
408
|
/**
|
|
393
409
|
* Checkbox Handler for setting the clip planes parameter
|
|
394
410
|
*/
|
|
@@ -668,6 +684,13 @@ declare class Display {
|
|
|
668
684
|
* Show or hide tools panel (tabs + content) in glass mode.
|
|
669
685
|
* Also toggles the orientation marker and animation/explode slider.
|
|
670
686
|
*/
|
|
687
|
+
/**
|
|
688
|
+
* Show the shape-filter dropdown only for a B-rep model with the tools panel open:
|
|
689
|
+
* `tools` enabled AND not collapsed AND a non-GDS model is rendered. Hidden otherwise
|
|
690
|
+
* (clean canvas; also detaches the a/v/e/f/s keyboard shortcuts). Hover preselection
|
|
691
|
+
* is always-on for B-rep, so the filter is independent of which tool (if any) is active.
|
|
692
|
+
*/
|
|
693
|
+
updateShapeFilter: () => void;
|
|
671
694
|
showToolsPanel: (flag: boolean) => void;
|
|
672
695
|
/**
|
|
673
696
|
* Toggle tools panel visibility
|
package/dist/utils/utils.d.ts
CHANGED
|
@@ -143,4 +143,4 @@ declare class EventListenerManager {
|
|
|
143
143
|
dispose(): void;
|
|
144
144
|
}
|
|
145
145
|
export { flatten, isEqual, sceneTraverse, prettyPrintVector, KeyMapper, scaleLight, deepDispose, disposeGeometry, EventListenerManager, isMesh, isLine, isPoints, isOrthographicCamera, isPerspectiveCamera, isLineSegments2, hasColor, hasEmissive, isMeshStandardMaterial, toVector3Tuple, toQuaternionTuple, };
|
|
146
|
-
export type { KeyEventKey, KeyMappingConfig, DisposableTree
|
|
146
|
+
export type { KeyEventKey, KeyMappingConfig, DisposableTree };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "three-cad-viewer",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "WebGL-based CAD viewer built on Three.js with clipping planes, measurement tools, and tree navigation",
|
|
6
6
|
"repository": {
|
|
@@ -40,6 +40,8 @@
|
|
|
40
40
|
"docs": "./scripts/build_docs.sh",
|
|
41
41
|
"release": "./scripts/release.sh",
|
|
42
42
|
"lint": "eslint src/",
|
|
43
|
+
"format": "prettier --write \"src/**/*.{ts,js,css}\" \"tests/**/*.{ts,js}\" \"*.{html,md,json}\" \".prettierrc\" \".vscode/*.json\"",
|
|
44
|
+
"format:check": "prettier --check \"src/**/*.{ts,js,css}\" \"tests/**/*.{ts,js}\" \"*.{html,md,json}\" \".prettierrc\" \".vscode/*.json\"",
|
|
43
45
|
"test": "vitest",
|
|
44
46
|
"test:ui": "vitest --ui",
|
|
45
47
|
"test:run": "vitest run",
|
|
@@ -56,6 +58,7 @@
|
|
|
56
58
|
"devDependencies": {
|
|
57
59
|
"@babel/core": "7.29.0",
|
|
58
60
|
"@babel/eslint-parser": "7.28.6",
|
|
61
|
+
"@eslint/js": "10.0.1",
|
|
59
62
|
"@rollup/plugin-image": "3.0.3",
|
|
60
63
|
"@rollup/plugin-node-resolve": "16.0.3",
|
|
61
64
|
"@rollup/plugin-terser": "1.0.0",
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import * as THREE from "three";
|
|
2
|
-
import { type ObjectGroup } from "../scene/objectgroup.js";
|
|
3
|
-
import type { Camera } from "../camera/camera.js";
|
|
4
|
-
/**
|
|
5
|
-
* Filter types for topology-based raycasting.
|
|
6
|
-
*/
|
|
7
|
-
export declare const TopoFilter: {
|
|
8
|
-
none: null;
|
|
9
|
-
vertex: "vertex";
|
|
10
|
-
edge: "edge";
|
|
11
|
-
face: "face";
|
|
12
|
-
solid: "solid";
|
|
13
|
-
};
|
|
14
|
-
export type TopoFilterType = typeof TopoFilter[keyof typeof TopoFilter];
|
|
15
|
-
interface RaycastFilters {
|
|
16
|
-
topoFilter: TopoFilterType[];
|
|
17
|
-
}
|
|
18
|
-
interface RaycastCallback {
|
|
19
|
-
(event: {
|
|
20
|
-
mouse?: "left" | "right";
|
|
21
|
-
shift?: boolean;
|
|
22
|
-
key?: string;
|
|
23
|
-
}): void;
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Represents a picked object from raycasting.
|
|
27
|
-
* Can represent either a single shape or all faces of a solid.
|
|
28
|
-
*/
|
|
29
|
-
export declare class PickedObject {
|
|
30
|
-
obj: ObjectGroup;
|
|
31
|
-
fromSolid: boolean;
|
|
32
|
-
/**
|
|
33
|
-
* Create a PickedObject.
|
|
34
|
-
* @param objectGroup - The picked ObjectGroup.
|
|
35
|
-
* @param fromSolid - Whether this pick is from a solid selection.
|
|
36
|
-
*/
|
|
37
|
-
constructor(objectGroup: ObjectGroup, fromSolid: boolean);
|
|
38
|
-
/**
|
|
39
|
-
* Returns all the faces ObjectGroups that define the solid from the picked object.
|
|
40
|
-
*/
|
|
41
|
-
private _getSolidObjectGroups;
|
|
42
|
-
/**
|
|
43
|
-
* If the picked object is part of a solid, returns all the faces ObjectGroups that define the solid.
|
|
44
|
-
* Otherwise, returns the picked object.
|
|
45
|
-
*/
|
|
46
|
-
objs(): ObjectGroup[];
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Handles mouse-based raycasting for object selection in the 3D scene.
|
|
50
|
-
* Supports topology filtering and provides click/keyboard callbacks.
|
|
51
|
-
*/
|
|
52
|
-
declare class Raycaster {
|
|
53
|
-
camera: Camera | null;
|
|
54
|
-
group: THREE.Object3D | null;
|
|
55
|
-
domElement: HTMLElement | null;
|
|
56
|
-
width: number;
|
|
57
|
-
height: number;
|
|
58
|
-
threshold: number;
|
|
59
|
-
callback: RaycastCallback;
|
|
60
|
-
raycaster: THREE.Raycaster;
|
|
61
|
-
raycastMode: boolean;
|
|
62
|
-
lastPosition: THREE.Vector3 | null;
|
|
63
|
-
mouse: THREE.Vector2;
|
|
64
|
-
mouseMoved: boolean;
|
|
65
|
-
filters: RaycastFilters;
|
|
66
|
-
/**
|
|
67
|
-
* Create a Raycaster for object picking.
|
|
68
|
-
* @param camera - The camera used for ray projection.
|
|
69
|
-
* @param domElement - The DOM element to listen for events.
|
|
70
|
-
* @param width - Viewport width in pixels.
|
|
71
|
-
* @param height - Viewport height in pixels.
|
|
72
|
-
* @param threshold - Point picking threshold in world units.
|
|
73
|
-
* @param group - The scene group to raycast against.
|
|
74
|
-
* @param callback - Callback for pick events.
|
|
75
|
-
*/
|
|
76
|
-
constructor(camera: Camera, domElement: HTMLElement, width: number, height: number, threshold: number, group: THREE.Object3D, callback: RaycastCallback);
|
|
77
|
-
/**
|
|
78
|
-
* Dispose of event listeners and clean up resources.
|
|
79
|
-
*/
|
|
80
|
-
dispose(): void;
|
|
81
|
-
/**
|
|
82
|
-
* Initialize event listeners and enable raycast mode.
|
|
83
|
-
*/
|
|
84
|
-
init(): void;
|
|
85
|
-
/**
|
|
86
|
-
* Retrieve all the valid intersected objects by a ray caster from the mouse.
|
|
87
|
-
*/
|
|
88
|
-
getIntersectedObjs(): THREE.Intersection[];
|
|
89
|
-
/**
|
|
90
|
-
* Retrieve all the valid intersected objects by a ray caster from the mouse.
|
|
91
|
-
* The objects are sorted by their distance from the ray. (The closest first)
|
|
92
|
-
*/
|
|
93
|
-
getValidIntersectedObjs(): THREE.Intersection[];
|
|
94
|
-
/**
|
|
95
|
-
* Handle left mouse button down event
|
|
96
|
-
*/
|
|
97
|
-
onMouseKeyDown: (e: MouseEvent) => void;
|
|
98
|
-
/**
|
|
99
|
-
* Handle left mouse button up event
|
|
100
|
-
*/
|
|
101
|
-
onMouseKeyUp: (e: MouseEvent) => void;
|
|
102
|
-
/**
|
|
103
|
-
* Handle key down event
|
|
104
|
-
*/
|
|
105
|
-
onKeyDown: (e: KeyboardEvent) => void;
|
|
106
|
-
/**
|
|
107
|
-
* Get the current mouse position
|
|
108
|
-
*/
|
|
109
|
-
onPointerMove: (e: MouseEvent) => void;
|
|
110
|
-
}
|
|
111
|
-
export { Raycaster };
|