@toolpath/viewer 0.3.1 → 1.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 +12 -2
- package/dist/{chunk-RICG6UVH.js → chunk-4BU4QZCL.js} +921 -202
- package/dist/engine/index.d.ts +2 -2
- package/dist/engine/index.js +1 -1
- package/dist/index.d.ts +491 -12
- package/dist/index.js +60 -231
- package/dist/{normalize-Bzzwwxt4.d.ts → normalize-DsoIyM8B.d.ts} +37 -95
- package/package.json +7 -3
package/dist/index.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CAD_CAMERA_UP,
|
|
3
3
|
CANDIDATE_WEIGHT,
|
|
4
|
+
CHAMFER,
|
|
4
5
|
CONE_AXIS,
|
|
5
6
|
CadCameraControls,
|
|
6
7
|
DEFAULT_FIT_MARGIN,
|
|
7
8
|
DEFAULT_THEME,
|
|
8
9
|
DIRECTION_COLORS,
|
|
10
|
+
DOUBLE_TAP_MS,
|
|
9
11
|
EXCLUDE_FROM_FRAME,
|
|
10
12
|
EnginePart,
|
|
11
13
|
ExtendedCameraControls,
|
|
@@ -16,7 +18,17 @@ import {
|
|
|
16
18
|
HIGHLIGHT_COLORS,
|
|
17
19
|
HIGHLIGHT_WEIGHT,
|
|
18
20
|
HOVER_WEIGHT,
|
|
21
|
+
MAX_FRAME_RATIO,
|
|
22
|
+
MIN_FRAME_RATIO,
|
|
19
23
|
NO_MODIFIERS,
|
|
24
|
+
ORBIT_TARGET_COLOR,
|
|
25
|
+
ORBIT_TARGET_FADE_MS,
|
|
26
|
+
ORBIT_TARGET_FLASH_MS,
|
|
27
|
+
ORBIT_TARGET_PIXELS,
|
|
28
|
+
ORBIT_TARGET_RING_COLOR,
|
|
29
|
+
ORBIT_TARGET_RING_OPACITY,
|
|
30
|
+
ORBIT_TARGET_RING_PIXELS,
|
|
31
|
+
ORBIT_TARGET_RING_WIDTH,
|
|
20
32
|
PERSPECTIVE_FOV,
|
|
21
33
|
PICKED_SURFACE_LABEL,
|
|
22
34
|
PartMesh,
|
|
@@ -27,7 +39,10 @@ import {
|
|
|
27
39
|
SectionView,
|
|
28
40
|
TAP_SLOP,
|
|
29
41
|
UnsupportedKernelVersionError,
|
|
42
|
+
VIEW_NAMES,
|
|
43
|
+
VIEW_SIGNS,
|
|
30
44
|
Viewer,
|
|
45
|
+
adaptedUp,
|
|
31
46
|
applyHighlightLayers,
|
|
32
47
|
applyProjection,
|
|
33
48
|
arrowPlacement,
|
|
@@ -39,8 +54,11 @@ import {
|
|
|
39
54
|
buildRegionIndex,
|
|
40
55
|
buildRegionTexels,
|
|
41
56
|
cadViewDirections,
|
|
57
|
+
cameraLimits,
|
|
42
58
|
contentBounds,
|
|
43
59
|
createPart,
|
|
60
|
+
cubeOutlineGeometry,
|
|
61
|
+
cubeZones,
|
|
44
62
|
currentViewDirection,
|
|
45
63
|
cycleOwner,
|
|
46
64
|
defaultBounds,
|
|
@@ -52,15 +70,21 @@ import {
|
|
|
52
70
|
fitDistance,
|
|
53
71
|
focusForPick,
|
|
54
72
|
groupByDirection,
|
|
73
|
+
labelGeometry,
|
|
74
|
+
labelTexture,
|
|
55
75
|
movedFar,
|
|
56
76
|
normalizePartReport,
|
|
77
|
+
orbitTargetOpacity,
|
|
57
78
|
orthographicHalfHeight,
|
|
79
|
+
panelGeometry,
|
|
58
80
|
perspectiveFitDistance,
|
|
59
81
|
pickedStartDepth,
|
|
60
82
|
rankOwners,
|
|
83
|
+
regionAdjacency,
|
|
61
84
|
regionEdgesGeometry,
|
|
62
85
|
resolveSectionPlane,
|
|
63
86
|
resolveTheme,
|
|
87
|
+
retargetPose,
|
|
64
88
|
sameDirection,
|
|
65
89
|
screenLength,
|
|
66
90
|
sectionBounds,
|
|
@@ -72,15 +96,22 @@ import {
|
|
|
72
96
|
sectionOffset,
|
|
73
97
|
sectionPlane,
|
|
74
98
|
smoothRegionNormals,
|
|
99
|
+
squaredUp,
|
|
75
100
|
startPosition,
|
|
101
|
+
targetBoundary,
|
|
76
102
|
themesEqual,
|
|
103
|
+
trackDoubleTaps,
|
|
77
104
|
trackTaps,
|
|
78
105
|
useContentBox,
|
|
106
|
+
useRetarget,
|
|
79
107
|
useTapGuard,
|
|
80
108
|
useViewerControls,
|
|
81
109
|
viewDirection,
|
|
110
|
+
viewKind,
|
|
111
|
+
viewUp,
|
|
112
|
+
viewVector,
|
|
82
113
|
visualSurfaces
|
|
83
|
-
} from "./chunk-
|
|
114
|
+
} from "./chunk-4BU4QZCL.js";
|
|
84
115
|
|
|
85
116
|
// src/primitives.tsx
|
|
86
117
|
import { GizmoHelper } from "@react-three/drei";
|
|
@@ -125,233 +156,6 @@ function gridGeometry(spec) {
|
|
|
125
156
|
return geometry;
|
|
126
157
|
}
|
|
127
158
|
|
|
128
|
-
// src/render/view-cube.ts
|
|
129
|
-
import {
|
|
130
|
-
BufferGeometry as BufferGeometry2,
|
|
131
|
-
CanvasTexture,
|
|
132
|
-
Float32BufferAttribute as Float32BufferAttribute2,
|
|
133
|
-
SRGBColorSpace,
|
|
134
|
-
Vector3 as Vector32
|
|
135
|
-
} from "three";
|
|
136
|
-
var VIEW_NAMES = [
|
|
137
|
-
// The six faces.
|
|
138
|
-
"top",
|
|
139
|
-
"bottom",
|
|
140
|
-
"front",
|
|
141
|
-
"back",
|
|
142
|
-
"left",
|
|
143
|
-
"right",
|
|
144
|
-
// The twelve edges.
|
|
145
|
-
"top-front",
|
|
146
|
-
"top-back",
|
|
147
|
-
"top-left",
|
|
148
|
-
"top-right",
|
|
149
|
-
"bottom-front",
|
|
150
|
-
"bottom-back",
|
|
151
|
-
"bottom-left",
|
|
152
|
-
"bottom-right",
|
|
153
|
-
"front-left",
|
|
154
|
-
"front-right",
|
|
155
|
-
"back-left",
|
|
156
|
-
"back-right",
|
|
157
|
-
// The eight corners.
|
|
158
|
-
"top-front-left",
|
|
159
|
-
"top-front-right",
|
|
160
|
-
"top-back-left",
|
|
161
|
-
"top-back-right",
|
|
162
|
-
"bottom-front-left",
|
|
163
|
-
"bottom-front-right",
|
|
164
|
-
"bottom-back-left",
|
|
165
|
-
"bottom-back-right"
|
|
166
|
-
];
|
|
167
|
-
var VIEW_SIGNS = {
|
|
168
|
-
top: [0, 0, 1],
|
|
169
|
-
bottom: [0, 0, -1],
|
|
170
|
-
front: [0, -1, 0],
|
|
171
|
-
back: [0, 1, 0],
|
|
172
|
-
left: [-1, 0, 0],
|
|
173
|
-
right: [1, 0, 0],
|
|
174
|
-
"top-front": [0, -1, 1],
|
|
175
|
-
"top-back": [0, 1, 1],
|
|
176
|
-
"top-left": [-1, 0, 1],
|
|
177
|
-
"top-right": [1, 0, 1],
|
|
178
|
-
"bottom-front": [0, -1, -1],
|
|
179
|
-
"bottom-back": [0, 1, -1],
|
|
180
|
-
"bottom-left": [-1, 0, -1],
|
|
181
|
-
"bottom-right": [1, 0, -1],
|
|
182
|
-
"front-left": [-1, -1, 0],
|
|
183
|
-
"front-right": [1, -1, 0],
|
|
184
|
-
"back-left": [-1, 1, 0],
|
|
185
|
-
"back-right": [1, 1, 0],
|
|
186
|
-
"top-front-left": [-1, -1, 1],
|
|
187
|
-
"top-front-right": [1, -1, 1],
|
|
188
|
-
"top-back-left": [-1, 1, 1],
|
|
189
|
-
"top-back-right": [1, 1, 1],
|
|
190
|
-
"bottom-front-left": [-1, -1, -1],
|
|
191
|
-
"bottom-front-right": [1, -1, -1],
|
|
192
|
-
"bottom-back-left": [-1, 1, -1],
|
|
193
|
-
"bottom-back-right": [1, 1, -1]
|
|
194
|
-
};
|
|
195
|
-
function viewKind(name) {
|
|
196
|
-
const off = VIEW_SIGNS[name].filter((sign) => sign !== 0).length;
|
|
197
|
-
if (off === 1) return "face";
|
|
198
|
-
if (off === 2) return "edge";
|
|
199
|
-
return "corner";
|
|
200
|
-
}
|
|
201
|
-
var DIRECTIONS = new Map(
|
|
202
|
-
VIEW_NAMES.map((name) => {
|
|
203
|
-
const [x, y, z] = VIEW_SIGNS[name];
|
|
204
|
-
const length = Math.hypot(x, y, z);
|
|
205
|
-
return [name, { x: x / length, y: y / length, z: z / length }];
|
|
206
|
-
})
|
|
207
|
-
);
|
|
208
|
-
function viewVector(name) {
|
|
209
|
-
return DIRECTIONS.get(name) ?? { x: 0, y: 0, z: 1 };
|
|
210
|
-
}
|
|
211
|
-
function viewUp(direction) {
|
|
212
|
-
if (direction.x === 0 && direction.y === 0) {
|
|
213
|
-
return { x: 0, y: direction.z > 0 ? 1 : -1, z: 0 };
|
|
214
|
-
}
|
|
215
|
-
return { x: 0, y: 0, z: 1 };
|
|
216
|
-
}
|
|
217
|
-
var CHAMFER = 0.5834;
|
|
218
|
-
function vec(v) {
|
|
219
|
-
return { x: v.x, y: v.y, z: v.z };
|
|
220
|
-
}
|
|
221
|
-
function cubeZones(chamfer = CHAMFER) {
|
|
222
|
-
const AXES = [0, 1, 2];
|
|
223
|
-
return VIEW_NAMES.map((name) => {
|
|
224
|
-
const kind = viewKind(name);
|
|
225
|
-
const direction = viewVector(name);
|
|
226
|
-
const [sx, sy, sz] = VIEW_SIGNS[name];
|
|
227
|
-
const sign = (axis) => VIEW_SIGNS[name][axis] ?? 0;
|
|
228
|
-
const normal = new Vector32(direction.x, direction.y, direction.z);
|
|
229
|
-
let polygon;
|
|
230
|
-
if (kind === "face") {
|
|
231
|
-
const up = viewUp(direction);
|
|
232
|
-
const upVector = new Vector32(up.x, up.y, up.z);
|
|
233
|
-
const right = normal.clone().negate().cross(upVector).normalize();
|
|
234
|
-
const square = [
|
|
235
|
-
[-1, -1],
|
|
236
|
-
[1, -1],
|
|
237
|
-
[1, 1],
|
|
238
|
-
[-1, 1]
|
|
239
|
-
];
|
|
240
|
-
polygon = square.map(
|
|
241
|
-
([u, v]) => normal.clone().addScaledVector(right, u * chamfer).addScaledVector(upVector, v * chamfer)
|
|
242
|
-
);
|
|
243
|
-
} else if (kind === "edge") {
|
|
244
|
-
const a = AXES.find((axis) => sign(axis) !== 0) ?? 0;
|
|
245
|
-
const b = [...AXES].reverse().find((axis) => sign(axis) !== 0) ?? 0;
|
|
246
|
-
const c = AXES.find((axis) => sign(axis) === 0) ?? 0;
|
|
247
|
-
const rectangle = [
|
|
248
|
-
[1, chamfer, -chamfer],
|
|
249
|
-
[1, chamfer, chamfer],
|
|
250
|
-
[chamfer, 1, chamfer],
|
|
251
|
-
[chamfer, 1, -chamfer]
|
|
252
|
-
];
|
|
253
|
-
polygon = rectangle.map(
|
|
254
|
-
([onA, onB, onC]) => new Vector32().setComponent(a, sign(a) * onA).setComponent(b, sign(b) * onB).setComponent(c, onC)
|
|
255
|
-
);
|
|
256
|
-
} else {
|
|
257
|
-
const triangle = [
|
|
258
|
-
[1, chamfer, chamfer],
|
|
259
|
-
[chamfer, 1, chamfer],
|
|
260
|
-
[chamfer, chamfer, 1]
|
|
261
|
-
];
|
|
262
|
-
polygon = triangle.map(([onX, onY, onZ]) => new Vector32(sx * onX, sy * onY, sz * onZ));
|
|
263
|
-
}
|
|
264
|
-
const [first, second, third] = polygon;
|
|
265
|
-
if (first && second && third) {
|
|
266
|
-
const facing = new Vector32().subVectors(second, first).cross(new Vector32().subVectors(third, first));
|
|
267
|
-
if (facing.dot(normal) < 0) polygon.reverse();
|
|
268
|
-
}
|
|
269
|
-
return { name, kind, direction, polygon: polygon.map(vec) };
|
|
270
|
-
});
|
|
271
|
-
}
|
|
272
|
-
function panelGeometry(zone) {
|
|
273
|
-
const positions = [];
|
|
274
|
-
const normals = [];
|
|
275
|
-
const [first] = zone.polygon;
|
|
276
|
-
const geometry = new BufferGeometry2();
|
|
277
|
-
if (!first) return geometry;
|
|
278
|
-
for (let index = 1; index + 1 < zone.polygon.length; index += 1) {
|
|
279
|
-
const b = zone.polygon[index];
|
|
280
|
-
const c = zone.polygon[index + 1];
|
|
281
|
-
if (!b || !c) continue;
|
|
282
|
-
positions.push(first.x, first.y, first.z, b.x, b.y, b.z, c.x, c.y, c.z);
|
|
283
|
-
for (let vertex = 0; vertex < 3; vertex += 1) {
|
|
284
|
-
normals.push(zone.direction.x, zone.direction.y, zone.direction.z);
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
geometry.setAttribute("position", new Float32BufferAttribute2(positions, 3));
|
|
288
|
-
geometry.setAttribute("normal", new Float32BufferAttribute2(normals, 3));
|
|
289
|
-
return geometry;
|
|
290
|
-
}
|
|
291
|
-
function cubeOutlineGeometry(zones) {
|
|
292
|
-
const positions = [];
|
|
293
|
-
for (const zone of zones) {
|
|
294
|
-
for (let index = 0; index < zone.polygon.length; index += 1) {
|
|
295
|
-
const from = zone.polygon[index];
|
|
296
|
-
const to = zone.polygon[(index + 1) % zone.polygon.length];
|
|
297
|
-
if (!from || !to) continue;
|
|
298
|
-
positions.push(from.x, from.y, from.z, to.x, to.y, to.z);
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
const geometry = new BufferGeometry2();
|
|
302
|
-
geometry.setAttribute("position", new Float32BufferAttribute2(positions, 3));
|
|
303
|
-
return geometry;
|
|
304
|
-
}
|
|
305
|
-
function labelGeometry(zone) {
|
|
306
|
-
const positions = [];
|
|
307
|
-
const uvs = [];
|
|
308
|
-
const corners = [0, 1, 2, 0, 2, 3];
|
|
309
|
-
const corner = [
|
|
310
|
-
[0, 0],
|
|
311
|
-
[1, 0],
|
|
312
|
-
[1, 1],
|
|
313
|
-
[0, 1]
|
|
314
|
-
];
|
|
315
|
-
for (const index of corners) {
|
|
316
|
-
const point = zone.polygon[index];
|
|
317
|
-
const uv = corner[index];
|
|
318
|
-
if (!point || !uv) continue;
|
|
319
|
-
positions.push(
|
|
320
|
-
point.x + zone.direction.x * 4e-3,
|
|
321
|
-
point.y + zone.direction.y * 4e-3,
|
|
322
|
-
point.z + zone.direction.z * 4e-3
|
|
323
|
-
);
|
|
324
|
-
uvs.push(uv[0] ?? 0, uv[1] ?? 0);
|
|
325
|
-
}
|
|
326
|
-
const geometry = new BufferGeometry2();
|
|
327
|
-
geometry.setAttribute("position", new Float32BufferAttribute2(positions, 3));
|
|
328
|
-
geometry.setAttribute("uv", new Float32BufferAttribute2(uvs, 2));
|
|
329
|
-
return geometry;
|
|
330
|
-
}
|
|
331
|
-
function labelTexture(label, color) {
|
|
332
|
-
const size = 128;
|
|
333
|
-
const canvas = document.createElement("canvas");
|
|
334
|
-
canvas.width = size;
|
|
335
|
-
canvas.height = size;
|
|
336
|
-
const context = canvas.getContext("2d");
|
|
337
|
-
if (context) {
|
|
338
|
-
const text = label.toUpperCase();
|
|
339
|
-
const hex = `#${color.toString(16).padStart(6, "0")}`;
|
|
340
|
-
context.font = `600 ${size / 4}px system-ui, sans-serif`;
|
|
341
|
-
const width = context.measureText("BOTTOM").width || 1;
|
|
342
|
-
const scale = Math.min(1, size * 0.78 / width);
|
|
343
|
-
context.font = `600 ${size / 4 * scale}px system-ui, sans-serif`;
|
|
344
|
-
context.textAlign = "center";
|
|
345
|
-
context.textBaseline = "middle";
|
|
346
|
-
context.fillStyle = hex;
|
|
347
|
-
context.fillText(text, size / 2, size / 2);
|
|
348
|
-
}
|
|
349
|
-
const texture = new CanvasTexture(canvas);
|
|
350
|
-
texture.colorSpace = SRGBColorSpace;
|
|
351
|
-
texture.needsUpdate = true;
|
|
352
|
-
return texture;
|
|
353
|
-
}
|
|
354
|
-
|
|
355
159
|
// src/primitives.tsx
|
|
356
160
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
357
161
|
var FURNITURE = { [EXCLUDE_FROM_FRAME]: true };
|
|
@@ -460,7 +264,7 @@ var CubePanels = ({
|
|
|
460
264
|
// src/direction-arrows.tsx
|
|
461
265
|
import { useThree as useThree2 } from "@react-three/fiber";
|
|
462
266
|
import { useMemo as useMemo2 } from "react";
|
|
463
|
-
import { Quaternion, Vector3 as
|
|
267
|
+
import { Quaternion, Vector3 as Vector32 } from "three";
|
|
464
268
|
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
465
269
|
var FURNITURE2 = { [EXCLUDE_FROM_FRAME]: true };
|
|
466
270
|
var DirectionArrows = ({
|
|
@@ -476,6 +280,11 @@ var DirectionArrows = ({
|
|
|
476
280
|
const box = useContentBox();
|
|
477
281
|
const resolved = useMemo2(() => resolveTheme(theme), [theme]);
|
|
478
282
|
const shown = shownDirection === void 0 ? activeDirection : shownDirection;
|
|
283
|
+
const drawn = (index) => {
|
|
284
|
+
if (shown === null) return true;
|
|
285
|
+
if (typeof shown === "number") return shown === index;
|
|
286
|
+
return shown.includes(index);
|
|
287
|
+
};
|
|
479
288
|
if (!visible) return null;
|
|
480
289
|
return (
|
|
481
290
|
// Excluded from framing: the arrows are deliberately placed outside the
|
|
@@ -483,7 +292,7 @@ var DirectionArrows = ({
|
|
|
483
292
|
// part small in the middle of them.
|
|
484
293
|
/* @__PURE__ */ jsxs2("group", { userData: FURNITURE2, children: [
|
|
485
294
|
directions.map((direction, index) => {
|
|
486
|
-
if (
|
|
295
|
+
if (!drawn(index)) return null;
|
|
487
296
|
return /* @__PURE__ */ jsx2(
|
|
488
297
|
Arrow,
|
|
489
298
|
{
|
|
@@ -517,7 +326,7 @@ var Arrow = ({ direction, box, color, opacity, onPick, onTop = false }) => {
|
|
|
517
326
|
const placement = arrowPlacement(direction, box);
|
|
518
327
|
const aim = new Quaternion().setFromUnitVectors(
|
|
519
328
|
CONE_AXIS,
|
|
520
|
-
new
|
|
329
|
+
new Vector32(direction.x, direction.y, direction.z).normalize()
|
|
521
330
|
);
|
|
522
331
|
return { tip: placement.tip, length: placement.length, quaternion: aim };
|
|
523
332
|
}, [box, direction]);
|
|
@@ -584,6 +393,7 @@ export {
|
|
|
584
393
|
DEFAULT_FIT_MARGIN,
|
|
585
394
|
DEFAULT_THEME,
|
|
586
395
|
DIRECTION_COLORS,
|
|
396
|
+
DOUBLE_TAP_MS,
|
|
587
397
|
DirectionArrows,
|
|
588
398
|
EXCLUDE_FROM_FRAME,
|
|
589
399
|
EnginePart,
|
|
@@ -594,7 +404,17 @@ export {
|
|
|
594
404
|
HIGHLIGHT_COLORS,
|
|
595
405
|
HIGHLIGHT_WEIGHT,
|
|
596
406
|
HOVER_WEIGHT,
|
|
407
|
+
MAX_FRAME_RATIO,
|
|
408
|
+
MIN_FRAME_RATIO,
|
|
597
409
|
NO_MODIFIERS,
|
|
410
|
+
ORBIT_TARGET_COLOR,
|
|
411
|
+
ORBIT_TARGET_FADE_MS,
|
|
412
|
+
ORBIT_TARGET_FLASH_MS,
|
|
413
|
+
ORBIT_TARGET_PIXELS,
|
|
414
|
+
ORBIT_TARGET_RING_COLOR,
|
|
415
|
+
ORBIT_TARGET_RING_OPACITY,
|
|
416
|
+
ORBIT_TARGET_RING_PIXELS,
|
|
417
|
+
ORBIT_TARGET_RING_WIDTH,
|
|
598
418
|
PERSPECTIVE_FOV,
|
|
599
419
|
PICKED_SURFACE_LABEL,
|
|
600
420
|
PartMesh,
|
|
@@ -608,6 +428,7 @@ export {
|
|
|
608
428
|
VIEW_SIGNS,
|
|
609
429
|
ViewCube,
|
|
610
430
|
Viewer,
|
|
431
|
+
adaptedUp,
|
|
611
432
|
applyHighlightLayers,
|
|
612
433
|
applyProjection,
|
|
613
434
|
arrowPlacement,
|
|
@@ -619,6 +440,7 @@ export {
|
|
|
619
440
|
buildRegionIndex,
|
|
620
441
|
buildRegionTexels,
|
|
621
442
|
cadViewDirections,
|
|
443
|
+
cameraLimits,
|
|
622
444
|
contentBounds,
|
|
623
445
|
createPart,
|
|
624
446
|
cubeOutlineGeometry,
|
|
@@ -640,15 +462,18 @@ export {
|
|
|
640
462
|
labelTexture,
|
|
641
463
|
movedFar,
|
|
642
464
|
normalizePartReport,
|
|
465
|
+
orbitTargetOpacity,
|
|
643
466
|
orthographicHalfHeight,
|
|
644
467
|
panelGeometry,
|
|
645
468
|
perspectiveFitDistance,
|
|
646
469
|
pickedStartDepth,
|
|
647
470
|
rankOwners,
|
|
471
|
+
regionAdjacency,
|
|
648
472
|
regionEdgesGeometry,
|
|
649
473
|
regionNormals,
|
|
650
474
|
resolveSectionPlane,
|
|
651
475
|
resolveTheme,
|
|
476
|
+
retargetPose,
|
|
652
477
|
sameDirection,
|
|
653
478
|
screenLength,
|
|
654
479
|
sectionBounds,
|
|
@@ -660,10 +485,14 @@ export {
|
|
|
660
485
|
sectionOffset,
|
|
661
486
|
sectionPlane,
|
|
662
487
|
smoothRegionNormals,
|
|
488
|
+
squaredUp,
|
|
663
489
|
startPosition,
|
|
490
|
+
targetBoundary,
|
|
664
491
|
themesEqual,
|
|
492
|
+
trackDoubleTaps,
|
|
665
493
|
trackTaps,
|
|
666
494
|
useContentBox,
|
|
495
|
+
useRetarget,
|
|
667
496
|
useTapGuard,
|
|
668
497
|
useViewerControls,
|
|
669
498
|
viewDirection,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import { Group, Mesh, LineSegments, Box3, Plane, BufferGeometry, Camera, Vector3
|
|
2
|
+
import { Group, Mesh, LineSegments, Box3, Plane, BufferGeometry, Camera, Vector3 } from 'three';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* The normalized part — the only thing the renderer consumes.
|
|
@@ -215,7 +215,7 @@ declare const HIGHLIGHT_COLORS: {
|
|
|
215
215
|
* of the palette — it is an identity, not a ranking, which is why the colors
|
|
216
216
|
* are unordered and deliberately not a scale.
|
|
217
217
|
*/
|
|
218
|
-
declare const DIRECTION_COLORS: readonly [3900150,
|
|
218
|
+
declare const DIRECTION_COLORS: readonly [3900150, 889992, 14239471, 6809849, 6660877, 15485081, 9741240, 4906624, 1981066];
|
|
219
219
|
declare const DEFAULT_THEME: ViewerTheme;
|
|
220
220
|
declare function resolveTheme(overrides?: Partial<ViewerTheme>): ViewerTheme;
|
|
221
221
|
/**
|
|
@@ -303,11 +303,15 @@ declare function buildRegionAttribute(model: RegionTable, texels: Map<number, nu
|
|
|
303
303
|
/**
|
|
304
304
|
* Builds the renderable part.
|
|
305
305
|
*
|
|
306
|
-
* Takes
|
|
306
|
+
* Takes working use of `geometry`: it adds {@link REGION_ATTRIBUTE} to it and
|
|
307
307
|
* removes that again on dispose, but never disposes the geometry itself — the
|
|
308
308
|
* loader's caller owns it, and a viewer destroying an object it was handed is a
|
|
309
|
-
* good way to break a cache that is legitimately sharing it.
|
|
310
|
-
*
|
|
309
|
+
* good way to break a cache that is legitimately sharing it.
|
|
310
|
+
*
|
|
311
|
+
* Two parts on one geometry is still not a thing to *render*, but it is a state
|
|
312
|
+
* that happens: a report changing identity rebuilds the part against the same
|
|
313
|
+
* cached mesh, and for a moment both exist. So dispose removes the attribute
|
|
314
|
+
* only if it is still the one this part set — see the note where it is built.
|
|
311
315
|
*/
|
|
312
316
|
declare function createPart(model: PartModel, geometry: BufferGeometry, theme: ViewerTheme): PartObject;
|
|
313
317
|
|
|
@@ -430,6 +434,21 @@ interface PartPick {
|
|
|
430
434
|
/** The surface's outward normal in world space — the plane under the cursor. */
|
|
431
435
|
readonly normal: readonly [number, number, number];
|
|
432
436
|
readonly modifiers: PickModifiers;
|
|
437
|
+
/**
|
|
438
|
+
* Whether this click completed a double click on the part.
|
|
439
|
+
*
|
|
440
|
+
* Reported rather than interpreted, for the same reason the modifiers are:
|
|
441
|
+
* what a second click means belongs to the app. A viewer that decided —
|
|
442
|
+
* withholding the pick so a double click could not disturb the selection —
|
|
443
|
+
* would be right for a list that walks through a face's readings and wrong
|
|
444
|
+
* for an editor where clicking a face twice puts it in and takes it out
|
|
445
|
+
* again. Both are ordinary, and only the app knows which one it is showing.
|
|
446
|
+
*
|
|
447
|
+
* The viewport still acts on the gesture itself: `retargetOnDoubleClick`
|
|
448
|
+
* re-aims the orbit, which is a question about the view rather than about the
|
|
449
|
+
* part, and is nobody else's to answer.
|
|
450
|
+
*/
|
|
451
|
+
readonly doubled: boolean;
|
|
433
452
|
}
|
|
434
453
|
/** A unit vector from the part toward the camera, for the owner ranking. */
|
|
435
454
|
declare function viewDirection(camera: Camera, target: Vector3): Vec3;
|
|
@@ -448,6 +467,8 @@ interface BuildPickInput {
|
|
|
448
467
|
*/
|
|
449
468
|
readonly activeDirection?: number | null;
|
|
450
469
|
readonly viewDirection?: Vec3 | null;
|
|
470
|
+
/** Whether this click completed a double click. Defaults to `false`. */
|
|
471
|
+
readonly doubled?: boolean;
|
|
451
472
|
}
|
|
452
473
|
declare function buildPick(input: BuildPickInput): PartPick;
|
|
453
474
|
/**
|
|
@@ -459,86 +480,6 @@ declare function buildPick(input: BuildPickInput): PartPick;
|
|
|
459
480
|
*/
|
|
460
481
|
declare function focusForPick(pick: PartPick, previousRegion: number | null, previousFocus: FeatureTag | null): FeatureTag | null;
|
|
461
482
|
|
|
462
|
-
type Projection = 'orthographic' | 'perspective';
|
|
463
|
-
type ViewerCamera = OrthographicCamera | PerspectiveCamera;
|
|
464
|
-
interface ViewportSize {
|
|
465
|
-
readonly width: number;
|
|
466
|
-
readonly height: number;
|
|
467
|
-
}
|
|
468
|
-
/** Vertical field of view, in degrees, for the perspective camera. */
|
|
469
|
-
declare const PERSPECTIVE_FOV = 30;
|
|
470
|
-
/** Padding around the framed bounds, as a multiple of its radius. */
|
|
471
|
-
declare const DEFAULT_FIT_MARGIN = 1.2;
|
|
472
|
-
/** Marks scene furniture — grid, axes — that the camera should not frame. */
|
|
473
|
-
declare const EXCLUDE_FROM_FRAME = "viewerExcludeFromFrame";
|
|
474
|
-
/**
|
|
475
|
-
* What the camera frames: a bounding *sphere*, not a box.
|
|
476
|
-
*
|
|
477
|
-
* A sphere makes framing rotation-invariant — the part stays fully visible from
|
|
478
|
-
* every angle, and a resize never needs to know the current pose. Framing
|
|
479
|
-
* per-axis box dimensions instead means recomputing the camera distance on
|
|
480
|
-
* every resize, and still clipping on some orientations.
|
|
481
|
-
*/
|
|
482
|
-
interface SceneBounds {
|
|
483
|
-
readonly center: Vector3;
|
|
484
|
-
readonly radius: number;
|
|
485
|
-
}
|
|
486
|
-
/**
|
|
487
|
-
* Bounds for a scene with nothing in it. A viewer is mounted before it has a
|
|
488
|
-
* part, and a camera with a zero-size frustum renders nothing at all.
|
|
489
|
-
*/
|
|
490
|
-
declare function defaultBounds(): SceneBounds;
|
|
491
|
-
/**
|
|
492
|
-
* A container can be laid out at zero size, and a degenerate aspect ratio
|
|
493
|
-
* produces a `NaN` projection matrix that never recovers. Fall back to square.
|
|
494
|
-
*/
|
|
495
|
-
declare function aspectRatio(size: ViewportSize): number;
|
|
496
|
-
declare function boundsFromBox(box: Box3): SceneBounds;
|
|
497
|
-
/**
|
|
498
|
-
* The bounds of everything worth framing under `root`.
|
|
499
|
-
*
|
|
500
|
-
* Skips objects flagged with {@link EXCLUDE_FROM_FRAME} and their descendants:
|
|
501
|
-
* a 100 mm grid around a 6 mm part would otherwise frame the grid, and the part
|
|
502
|
-
* would be a speck.
|
|
503
|
-
*/
|
|
504
|
-
declare function contentBounds(root: Object3D, into: Box3): SceneBounds;
|
|
505
|
-
/**
|
|
506
|
-
* The distance at which a sphere of `radius` fits inside a perspective frustum.
|
|
507
|
-
* Uses the narrower of the two field-of-view angles, so a portrait viewport
|
|
508
|
-
* frames on width and a landscape one on height.
|
|
509
|
-
*/
|
|
510
|
-
declare function perspectiveFitDistance(fovDegrees: number, aspect: number, radius: number): number;
|
|
511
|
-
/**
|
|
512
|
-
* Half-height of an orthographic frustum that fits a sphere of `radius`. A
|
|
513
|
-
* portrait viewport grows the height so the width still clears the sphere.
|
|
514
|
-
*/
|
|
515
|
-
declare function orthographicHalfHeight(aspect: number, radius: number): number;
|
|
516
|
-
declare function fitDistance(projection: Projection, size: ViewportSize, bounds: SceneBounds, margin?: number): number;
|
|
517
|
-
declare function startPosition(projection: Projection, size: ViewportSize, bounds: SceneBounds, margin?: number): Vector3;
|
|
518
|
-
/**
|
|
519
|
-
* Points an existing camera's frustum at `bounds` for the current viewport.
|
|
520
|
-
* Pose is untouched — that belongs to the controls.
|
|
521
|
-
*/
|
|
522
|
-
declare function applyProjection(camera: ViewerCamera, size: ViewportSize, bounds: SceneBounds, margin?: number): void;
|
|
523
|
-
/**
|
|
524
|
-
* The world-up convention. The part data is Z-up (millimetres, no conversion) —
|
|
525
|
-
* not the glTF-conventional Y-up — so the camera has to say so explicitly.
|
|
526
|
-
*/
|
|
527
|
-
declare const CAD_CAMERA_UP: Vector3;
|
|
528
|
-
/** Named viewing directions, as unit vectors from the part toward the camera. */
|
|
529
|
-
declare const cadViewDirections: {
|
|
530
|
-
readonly front: Vector3;
|
|
531
|
-
readonly back: Vector3;
|
|
532
|
-
readonly left: Vector3;
|
|
533
|
-
readonly right: Vector3;
|
|
534
|
-
readonly top: Vector3;
|
|
535
|
-
readonly bottom: Vector3;
|
|
536
|
-
readonly isometric: Vector3;
|
|
537
|
-
};
|
|
538
|
-
type ViewerView = keyof typeof cadViewDirections;
|
|
539
|
-
/** The current orbit direction, so Fit can retain the direction being looked from. */
|
|
540
|
-
declare function currentViewDirection(camera: ViewerCamera, target: Vector3, into: Vector3): Vector3;
|
|
541
|
-
|
|
542
483
|
/**
|
|
543
484
|
* Render order. The stencil pass must precede the cap, and the part must draw
|
|
544
485
|
* after both or it overwrites the cap it is supposed to be capped by. The part
|
|
@@ -635,14 +576,6 @@ declare function sectionFromPick(surface: {
|
|
|
635
576
|
declare function pickedStartDepth(box: Box3): number;
|
|
636
577
|
/** The plane a cut sits on, for a placement or a swept offset. */
|
|
637
578
|
declare function sectionPlane(box: Box3, normal: Vec3, offset: number, into?: Plane): Plane;
|
|
638
|
-
/**
|
|
639
|
-
* A world length that covers `pixels` on screen at `point`.
|
|
640
|
-
*
|
|
641
|
-
* A handle sized in world units is a thumbnail on a plate and a wall on an
|
|
642
|
-
* insert; the whole reason it is measured this way is that it is a control
|
|
643
|
-
* rather than part of the model.
|
|
644
|
-
*/
|
|
645
|
-
declare function screenLength(camera: ViewerCamera, point: Vector3, viewport: ViewportSize, pixels: number): number;
|
|
646
579
|
/**
|
|
647
580
|
* The plane a drag is projected onto: the one containing the handle's axis and
|
|
648
581
|
* facing the camera as squarely as it can.
|
|
@@ -772,6 +705,15 @@ interface PartMeshProps {
|
|
|
772
705
|
* real change, so echoing it into state is safe.
|
|
773
706
|
*/
|
|
774
707
|
onSectionChange?: (state: SectionState) => void;
|
|
708
|
+
/**
|
|
709
|
+
* Which faces touch which, once the mesh is in.
|
|
710
|
+
*
|
|
711
|
+
* The consumer cannot work this out: it has a region table with areas and
|
|
712
|
+
* shape kinds, and the topology only exists in the geometry. Handed over
|
|
713
|
+
* rather than queried, because it is computed once per mesh and the consumer
|
|
714
|
+
* needs it to answer questions about faces it has not clicked yet.
|
|
715
|
+
*/
|
|
716
|
+
onAdjacency?: (adjacency: ReadonlyMap<number, ReadonlySet<number>>) => void;
|
|
775
717
|
/**
|
|
776
718
|
* A feature to frame. Framed when it changes, so setting it to the feature
|
|
777
719
|
* already framed does nothing — a zoom is a request, not a state to hold.
|
|
@@ -801,7 +743,7 @@ interface PartMeshProps {
|
|
|
801
743
|
* React render at all: the hovered face lives in a ref, and routing it through
|
|
802
744
|
* state is what this rewrite exists to stop doing.
|
|
803
745
|
*/
|
|
804
|
-
declare const PartMesh: ({ model, geometry, selection, candidates, highlights, regionHighlights, pickedRegions, hoveredFeatureIds, activeDirection, section, onSectionChange, focusFeature, onHover, onPick, theme, showEdges, }: PartMeshProps) => react.JSX.Element;
|
|
746
|
+
declare const PartMesh: ({ model, geometry, selection, candidates, highlights, regionHighlights, pickedRegions, hoveredFeatureIds, activeDirection, section, onSectionChange, onAdjacency, focusFeature, onHover, onPick, theme, showEdges, }: PartMeshProps) => react.JSX.Element;
|
|
805
747
|
|
|
806
748
|
interface EnginePartProps extends Omit<PartMeshProps, 'model' | 'geometry'> {
|
|
807
749
|
/**
|
|
@@ -876,4 +818,4 @@ declare function normalizePartReport(report: unknown): PartModel;
|
|
|
876
818
|
*/
|
|
877
819
|
declare function assertSupportedKernelVersion(kernelVersion: string): void;
|
|
878
820
|
|
|
879
|
-
export {
|
|
821
|
+
export { resolveSectionPlane as $, type SectionOptions as A, type BuildPickInput as B, CANDIDATE_WEIGHT as C, DEFAULT_THEME as D, EnginePart as E, type FeatureTag as F, type SectionPlacement as G, HANDLE_PIXELS as H, type SectionState as I, SectionView as J, type KnownFeatureType as K, applyHighlightLayers as L, MIN_KERNEL_VERSION as M, NO_MODIFIERS as N, buildPick as O, type PartModel as P, buildRegionAttribute as Q, type RegionIndex as R, SECTION_RENDER_ORDER as S, type TriangleRange as T, buildRegionTexels as U, type Vec3 as V, createPart as W, directionColor as X, dragPlane as Y, focusForPick as Z, pickedStartDepth as _, type PartMeshRefs as a, resolveTheme as a0, sectionBounds as a1, sectionConstant as a2, sectionDepth as a3, sectionDepthConstant as a4, sectionDepthRange as a5, sectionFromPick as a6, sectionOffset as a7, sectionPlane as a8, themesEqual as a9, viewDirection as aa, type EnginePartProps as b, assertSupportedKernelVersion as c, type ViewerTheme as d, type PartModelRegion as e, type PartModelFeature as f, type FeatureType as g, DIRECTION_COLORS as h, type FeatureHighlight as i, HIGHLIGHT_COLORS as j, HIGHLIGHT_WEIGHT as k, HOVER_WEIGHT as l, type HighlightLayers as m, normalizePartReport as n, PICKED_SURFACE_LABEL as o, PartMesh as p, type PartMeshProps as q, type PartObject as r, smoothRegionNormals as s, type PartPick as t, type PickModifiers as u, REGION_ATTRIBUTE as v, type RegionHighlight as w, type RegionPaint as x, type SectionAnchor as y, type SectionBounds as z };
|
package/package.json
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@toolpath/viewer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "React Three Fiber viewer for Toolpath Engine part reports",
|
|
5
5
|
"license": "MIT",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=20"
|
|
8
|
+
},
|
|
6
9
|
"repository": {
|
|
7
10
|
"type": "git",
|
|
8
|
-
"url": "https://github.com/toolpath/
|
|
11
|
+
"url": "https://github.com/toolpath/ui-packages.git",
|
|
9
12
|
"directory": "packages/viewer"
|
|
10
13
|
},
|
|
11
14
|
"homepage": "https://developers.toolpath.com",
|
|
12
15
|
"bugs": {
|
|
13
|
-
"url": "https://github.com/toolpath/
|
|
16
|
+
"url": "https://github.com/toolpath/ui-packages/issues"
|
|
14
17
|
},
|
|
15
18
|
"publishConfig": {
|
|
16
19
|
"access": "public",
|
|
@@ -62,6 +65,7 @@
|
|
|
62
65
|
},
|
|
63
66
|
"scripts": {
|
|
64
67
|
"build": "tsup src/index.ts src/engine/index.ts --format esm --dts --clean --external react --external react-dom --external three --external @react-three/fiber --external @react-three/drei",
|
|
68
|
+
"build:watch": "tsup src/index.ts src/engine/index.ts --format esm --dts --watch --external react --external react-dom --external three --external @react-three/fiber --external @react-three/drei",
|
|
65
69
|
"check-types": "tsc --noEmit",
|
|
66
70
|
"test": "vitest run"
|
|
67
71
|
}
|