@toolpath/viewer 1.4.0 → 1.5.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 +287 -55
- package/dist/assets/banana.glb +0 -0
- package/dist/{chunk-HH3W5T42.js → chunk-4TBLMR4Z.js} +727 -168
- package/dist/engine/index.d.ts +2 -2
- package/dist/engine/index.js +1 -1
- package/dist/index.d.ts +205 -19
- package/dist/index.js +739 -409
- package/dist/{normalize-DHOSNiuO.d.ts → normalize-CvnV9Ggh.d.ts} +55 -18
- package/dist/toolbar.css +108 -0
- package/package.json +5 -4
package/dist/index.js
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
import {
|
|
2
|
+
ANGLE_ARC_FRACTION,
|
|
3
|
+
ANGLE_ARC_SEGMENTS,
|
|
2
4
|
AXES_PLANE_OFFSET,
|
|
3
5
|
AXES_PLANE_SCALE,
|
|
6
|
+
AXIS_COLORS,
|
|
4
7
|
CAD_CAMERA_UP,
|
|
5
8
|
CANDIDATE_WEIGHT,
|
|
6
9
|
CAP_HATCH,
|
|
7
10
|
CHAMFER,
|
|
8
11
|
CONE_AXIS,
|
|
12
|
+
CONTROL_SCHEME_OPTIONS,
|
|
9
13
|
CadCameraControls,
|
|
10
14
|
DEFAULT_FIT_MARGIN,
|
|
11
15
|
DEFAULT_SECTION_NORMAL,
|
|
12
16
|
DEFAULT_THEME,
|
|
17
|
+
DELTA_DASH_PIXELS,
|
|
13
18
|
DIRECTION_COLORS,
|
|
14
19
|
DISABLED_SECTION,
|
|
15
20
|
DOUBLE_TAP_MS,
|
|
@@ -24,6 +29,9 @@ import {
|
|
|
24
29
|
HIGHLIGHT_WEIGHT,
|
|
25
30
|
HOVER_WEIGHT,
|
|
26
31
|
MAX_FRAME_RATIO,
|
|
32
|
+
MEASURE_LINE_PIXELS,
|
|
33
|
+
MEASURE_MARKER_PIXELS,
|
|
34
|
+
MEASURE_RENDER_ORDER,
|
|
27
35
|
MIN_FRAME_RATIO,
|
|
28
36
|
NO_MODIFIERS,
|
|
29
37
|
ORBIT_TARGET_COLOR,
|
|
@@ -37,12 +45,17 @@ import {
|
|
|
37
45
|
OUTLINE_SCALE,
|
|
38
46
|
PERSPECTIVE_FOV,
|
|
39
47
|
PICKED_SURFACE_LABEL,
|
|
48
|
+
POINTS_PER_MEASUREMENT,
|
|
40
49
|
PREVIEW_SCALE,
|
|
41
50
|
PartMesh,
|
|
42
51
|
PartReportFormatError,
|
|
43
52
|
REGION_ATTRIBUTE,
|
|
53
|
+
SECTION_GIZMO_FRAME_SCALE,
|
|
44
54
|
SECTION_RENDER_ORDER,
|
|
45
55
|
SHAFT_RADIUS,
|
|
56
|
+
SNAP_MARKER_PIXELS,
|
|
57
|
+
SNAP_PIXELS,
|
|
58
|
+
STOCK_OBJECT,
|
|
46
59
|
SectionView,
|
|
47
60
|
TAP_SLOP,
|
|
48
61
|
UnsupportedKernelVersionError,
|
|
@@ -50,6 +63,9 @@ import {
|
|
|
50
63
|
VIEW_SIGNS,
|
|
51
64
|
Viewer,
|
|
52
65
|
adaptedUp,
|
|
66
|
+
angleArc,
|
|
67
|
+
angleArcRadius,
|
|
68
|
+
angleAt,
|
|
53
69
|
applyCapTheme,
|
|
54
70
|
applyHighlightLayers,
|
|
55
71
|
applyProjection,
|
|
@@ -76,19 +92,30 @@ import {
|
|
|
76
92
|
currentViewDirection,
|
|
77
93
|
cycleOwner,
|
|
78
94
|
defaultBounds,
|
|
95
|
+
deltaBetween,
|
|
96
|
+
deltaLegs,
|
|
79
97
|
directionColor,
|
|
80
98
|
directionIndexOf,
|
|
81
99
|
directionLabel,
|
|
100
|
+
distanceBetween,
|
|
82
101
|
dragPlane,
|
|
83
102
|
excludedFromFrame,
|
|
84
103
|
featureTypeRank,
|
|
85
104
|
fitDistance,
|
|
86
105
|
focusForPick,
|
|
106
|
+
formatDegrees,
|
|
107
|
+
formatMillimetres,
|
|
87
108
|
groupByDirection,
|
|
88
109
|
hitUnderRay,
|
|
89
110
|
labelGeometry,
|
|
90
111
|
labelTexture,
|
|
112
|
+
lockToAxis,
|
|
113
|
+
measurementFromPoints,
|
|
114
|
+
measurementLabel,
|
|
115
|
+
measurementLabelAnchor,
|
|
116
|
+
midpoint,
|
|
91
117
|
movedFar,
|
|
118
|
+
nextMeasurementId,
|
|
92
119
|
normalizePartReport,
|
|
93
120
|
orbitTargetOpacity,
|
|
94
121
|
orthographicHalfHeight,
|
|
@@ -103,6 +130,7 @@ import {
|
|
|
103
130
|
retargetPose,
|
|
104
131
|
sameDirection,
|
|
105
132
|
screenLength,
|
|
133
|
+
screenPoint,
|
|
106
134
|
sectionAnchor,
|
|
107
135
|
sectionBounds,
|
|
108
136
|
sectionConstant,
|
|
@@ -110,10 +138,12 @@ import {
|
|
|
110
138
|
sectionDepthConstant,
|
|
111
139
|
sectionDepthRange,
|
|
112
140
|
sectionFromPick,
|
|
141
|
+
sectionMeasurement,
|
|
113
142
|
sectionOffset,
|
|
114
143
|
sectionOptionsFromState,
|
|
115
144
|
sectionPlane,
|
|
116
145
|
smoothRegionNormals,
|
|
146
|
+
snapAt,
|
|
117
147
|
squaredUp,
|
|
118
148
|
startPosition,
|
|
119
149
|
surfaceUnderRay,
|
|
@@ -131,21 +161,505 @@ import {
|
|
|
131
161
|
viewUp,
|
|
132
162
|
viewVector,
|
|
133
163
|
visualSurfaces
|
|
134
|
-
} from "./chunk-
|
|
164
|
+
} from "./chunk-4TBLMR4Z.js";
|
|
165
|
+
|
|
166
|
+
// src/hover-card.tsx
|
|
167
|
+
import { useEffect, useState } from "react";
|
|
168
|
+
import { jsx } from "react/jsx-runtime";
|
|
169
|
+
var HoverCard = ({ pick, children, className: className2, offset = 16 }) => {
|
|
170
|
+
const [pointer, setPointer] = useState(pick?.pointer);
|
|
171
|
+
useEffect(() => {
|
|
172
|
+
setPointer(pick?.pointer);
|
|
173
|
+
if (pick === null) return;
|
|
174
|
+
const follow = (event) => setPointer({ clientX: event.clientX, clientY: event.clientY });
|
|
175
|
+
window.addEventListener("pointermove", follow);
|
|
176
|
+
return () => window.removeEventListener("pointermove", follow);
|
|
177
|
+
}, [pick]);
|
|
178
|
+
if (pick === null || pointer === void 0) return null;
|
|
179
|
+
const style = {
|
|
180
|
+
position: "fixed",
|
|
181
|
+
left: pointer.clientX + offset,
|
|
182
|
+
top: pointer.clientY + offset,
|
|
183
|
+
pointerEvents: "none",
|
|
184
|
+
zIndex: 4
|
|
185
|
+
};
|
|
186
|
+
return /* @__PURE__ */ jsx(
|
|
187
|
+
"div",
|
|
188
|
+
{
|
|
189
|
+
className: ["viewer-hover-card", className2].filter(Boolean).join(" "),
|
|
190
|
+
"data-viewer-hover-card": "true",
|
|
191
|
+
role: "tooltip",
|
|
192
|
+
style,
|
|
193
|
+
children: children(pick)
|
|
194
|
+
}
|
|
195
|
+
);
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
// src/viewer-toolbar.tsx
|
|
199
|
+
import { createContext, useContext } from "react";
|
|
200
|
+
|
|
201
|
+
// src/toolbar-icons.tsx
|
|
202
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
203
|
+
var SvgIcon = ({ viewBox = "0 0 24 24", fill = "none", children }) => /* @__PURE__ */ jsx2(
|
|
204
|
+
"svg",
|
|
205
|
+
{
|
|
206
|
+
className: "viewer-toolbar-icon",
|
|
207
|
+
"data-viewer-toolbar-icon": "true",
|
|
208
|
+
viewBox,
|
|
209
|
+
fill,
|
|
210
|
+
stroke: fill === "none" ? "currentColor" : "none",
|
|
211
|
+
strokeWidth: "1.5",
|
|
212
|
+
strokeLinecap: "round",
|
|
213
|
+
strokeLinejoin: "round",
|
|
214
|
+
"aria-hidden": "true",
|
|
215
|
+
children
|
|
216
|
+
}
|
|
217
|
+
);
|
|
218
|
+
var FitIcon = () => /* @__PURE__ */ jsx2(SvgIcon, { children: /* @__PURE__ */ jsx2("path", { d: "M8 3H3v5m13-5h5v5M3 16v5h5m13-5v5h-5M8 8h8v8H8z" }) });
|
|
219
|
+
var ResetIcon = () => /* @__PURE__ */ jsx2(SvgIcon, { children: /* @__PURE__ */ jsx2("path", { d: "M3 10a9 9 0 1 1 2 8M3 4v6h6" }) });
|
|
220
|
+
var TopIcon = () => /* @__PURE__ */ jsx2(SvgIcon, { children: /* @__PURE__ */ jsx2("path", { d: "M4 7l8-4 8 4-8 4zM4 7v10l8 4 8-4V7M12 11v10" }) });
|
|
221
|
+
var StockIcon = () => /* @__PURE__ */ jsx2(SvgIcon, { children: /* @__PURE__ */ jsx2("path", { d: "M3 6l9-4 9 4v12l-9 4-9-4zM3 6l9 4 9-4M12 10v12M7 8v8l5 2 5-2V8" }) });
|
|
222
|
+
var AxesIcon = () => /* @__PURE__ */ jsx2(SvgIcon, { children: /* @__PURE__ */ jsx2("path", { d: "M5 19V3m0 16h16M5 19l10-10M2 6l3-3 3 3m10 10 3 3-3 3M11 9h4v4" }) });
|
|
223
|
+
var GridIcon = () => /* @__PURE__ */ jsx2(SvgIcon, { children: /* @__PURE__ */ jsx2("path", { d: "M3 8l9-5 9 5-9 5zM3 8v8l9 5 9-5V8M12 13v8M7.5 5.5v8M16.5 5.5v8" }) });
|
|
224
|
+
var BananaIcon = () => /* @__PURE__ */ jsx2(SvgIcon, { viewBox: "0 0 576 512", fill: "currentColor", children: /* @__PURE__ */ jsx2("path", { d: "M284.2 245.6c12.99 6.929 25.35 15.14 36.08 25.8L334.5 285.6l65.75-23.47c14.75-5.265 30.18-7.849 45.81-8.389c1.154-10.73 1.764-21.38 1.764-31.87c0-118.5-81.33-221.9-119.7-221.9c-21.01 0-40.91 17.04-40.91 39.25c0 16.18 16.74 41.9 16.74 103C303.1 170.1 300.6 203.1 284.2 245.6zM575.1 389.6c0-3.687-.8637-7.429-2.687-10.93l-15.12-29.11c-21.05-40.53-63.08-64.51-106.9-64.51c-13.43 0-27.02 2.252-40.22 6.969l-84.84 30.27l-28.59-28.41C274.4 270.9 243.7 258.1 212.8 258.1c-23.72 0-47.57 6.97-68.29 21.2L106.3 306.4c-6.732 4.631-10.35 12.07-10.35 19.63c0 14.93 12.7 23.87 24.04 23.87c4.695 0 9.443-1.376 13.61-4.26l38.13-26.23c12.43-8.525 26.71-12.69 40.91-12.69c10.64 0 21.24 2.339 30.97 6.934c-50.62 62.23-128.3 99.85-211.4 99.85C14.42 413.5 0 427.8 0 445.5v31.38c0 17.68 14.66 32.02 32.46 32.02l28.98.0009c14.15 0 34.69 1.098 59.07 1.098c93.51 0 243.4-16.15 304.8-172.4c9.021-3.22 17.95-4.712 26.53-4.712c27.65 0 51.7 15.49 63.7 38.55l15.12 29.11c3.484 6.723 11.74 12.98 21.41 12.98C564.1 413.6 575.1 403.8 575.1 389.6z" }) });
|
|
225
|
+
var DirectionsIcon = () => /* @__PURE__ */ jsx2(SvgIcon, { children: /* @__PURE__ */ jsx2("path", { d: "M7 3v18m-4-4 4 4 4-4M17 21V3m-4 4 4-4 4 4" }) });
|
|
226
|
+
var HoverIcon = () => /* @__PURE__ */ jsx2(SvgIcon, { children: /* @__PURE__ */ jsx2("path", { d: "M4 4h16v12H9l-5 4zm4 5h8m-8 3h5" }) });
|
|
227
|
+
var FocusIcon = () => /* @__PURE__ */ jsx2(SvgIcon, { children: /* @__PURE__ */ jsx2("path", { d: "M4 4h16v16H4zM8 8h8v8H8zM2 12h4m12 0h4M12 2v4m0 12v4" }) });
|
|
228
|
+
var WireframeIcon = () => /* @__PURE__ */ jsx2(SvgIcon, { children: /* @__PURE__ */ jsx2("path", { d: "M4 7l8-4 8 4v10l-8 4-8-4zM4 7l8 4 8-4M12 11v10M4 17l8-4 8 4M12 3v10" }) });
|
|
229
|
+
var SectionIcon = () => /* @__PURE__ */ jsx2(SvgIcon, { children: /* @__PURE__ */ jsx2("path", { d: "M3 6h9v12H3zM12 3v18M16 6h2m3 3v2m0 3v2m-5 3h-2" }) });
|
|
230
|
+
var MeasureIcon = () => /* @__PURE__ */ jsx2(SvgIcon, { children: /* @__PURE__ */ jsx2("path", { d: "M3 16L16 3l5 5L8 21zM8 11l3 3m1-7 3 3m-11 5 3 3" }) });
|
|
231
|
+
var ICONS = {
|
|
232
|
+
fit: FitIcon,
|
|
233
|
+
reset: ResetIcon,
|
|
234
|
+
top: TopIcon,
|
|
235
|
+
stock: StockIcon,
|
|
236
|
+
axes: AxesIcon,
|
|
237
|
+
grid: GridIcon,
|
|
238
|
+
banana: BananaIcon,
|
|
239
|
+
directions: DirectionsIcon,
|
|
240
|
+
hover: HoverIcon,
|
|
241
|
+
focus: FocusIcon,
|
|
242
|
+
wireframe: WireframeIcon,
|
|
243
|
+
section: SectionIcon,
|
|
244
|
+
measure: MeasureIcon
|
|
245
|
+
};
|
|
246
|
+
var ToolbarIcon = ({ name }) => {
|
|
247
|
+
const Icon = ICONS[name];
|
|
248
|
+
return /* @__PURE__ */ jsx2(Icon, {});
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
// src/viewer-toolbar.tsx
|
|
252
|
+
import { jsx as jsx3, jsxs } from "react/jsx-runtime";
|
|
253
|
+
var ViewerToolbarContext = createContext(null);
|
|
254
|
+
var ViewerToolbarProvider = ({
|
|
255
|
+
controls,
|
|
256
|
+
children
|
|
257
|
+
}) => /* @__PURE__ */ jsx3(ViewerToolbarContext.Provider, { value: controls, children });
|
|
258
|
+
var useViewerToolbar = () => {
|
|
259
|
+
const controls = useContext(ViewerToolbarContext);
|
|
260
|
+
if (!controls) throw new Error("useViewerToolbar must be used inside <ViewerToolbarProvider>");
|
|
261
|
+
return controls;
|
|
262
|
+
};
|
|
263
|
+
var buttonName = (action) => `${action.slice(0, 1).toUpperCase()}${action.slice(1)}Button`;
|
|
264
|
+
var ToolbarButton = ({ action, icon, label, toggle = true }) => {
|
|
265
|
+
const control = useViewerToolbar()[action];
|
|
266
|
+
if (!control) {
|
|
267
|
+
throw new Error(`<ViewerToolbar.${buttonName(action)}> requires a '${action}' toolbar control`);
|
|
268
|
+
}
|
|
269
|
+
const pressed = control.pressed ?? false;
|
|
270
|
+
return /* @__PURE__ */ jsxs(
|
|
271
|
+
"button",
|
|
272
|
+
{
|
|
273
|
+
className: "viewer-toolbar-button",
|
|
274
|
+
"data-viewer-toolbar-action": action,
|
|
275
|
+
type: "button",
|
|
276
|
+
"aria-label": label(pressed),
|
|
277
|
+
"aria-pressed": toggle ? pressed : void 0,
|
|
278
|
+
onClick: control.onClick,
|
|
279
|
+
children: [
|
|
280
|
+
/* @__PURE__ */ jsx3(ToolbarIcon, { name: icon }),
|
|
281
|
+
/* @__PURE__ */ jsx3("span", { className: "viewer-toolbar-tooltip", "data-viewer-toolbar-tooltip": "true", role: "tooltip", children: label(pressed) })
|
|
282
|
+
]
|
|
283
|
+
}
|
|
284
|
+
);
|
|
285
|
+
};
|
|
286
|
+
var StockButton = () => /* @__PURE__ */ jsx3(
|
|
287
|
+
ToolbarButton,
|
|
288
|
+
{
|
|
289
|
+
action: "stock",
|
|
290
|
+
icon: "stock",
|
|
291
|
+
label: (pressed) => pressed ? "Hide stock" : "Show stock"
|
|
292
|
+
}
|
|
293
|
+
);
|
|
294
|
+
var AxesButton = () => /* @__PURE__ */ jsx3(
|
|
295
|
+
ToolbarButton,
|
|
296
|
+
{
|
|
297
|
+
action: "axes",
|
|
298
|
+
icon: "axes",
|
|
299
|
+
label: (pressed) => pressed ? "Hide axis" : "Show axis"
|
|
300
|
+
}
|
|
301
|
+
);
|
|
302
|
+
var GridButton = () => /* @__PURE__ */ jsx3(
|
|
303
|
+
ToolbarButton,
|
|
304
|
+
{
|
|
305
|
+
action: "grid",
|
|
306
|
+
icon: "grid",
|
|
307
|
+
label: (pressed) => pressed ? "Hide grid" : "Show grid"
|
|
308
|
+
}
|
|
309
|
+
);
|
|
310
|
+
var BananaButton = () => /* @__PURE__ */ jsx3(
|
|
311
|
+
ToolbarButton,
|
|
312
|
+
{
|
|
313
|
+
action: "banana",
|
|
314
|
+
icon: "banana",
|
|
315
|
+
label: (pressed) => pressed ? "Banana for scale (on)" : "Banana for scale"
|
|
316
|
+
}
|
|
317
|
+
);
|
|
318
|
+
var DirectionsButton = () => /* @__PURE__ */ jsx3(
|
|
319
|
+
ToolbarButton,
|
|
320
|
+
{
|
|
321
|
+
action: "directions",
|
|
322
|
+
icon: "directions",
|
|
323
|
+
label: () => "Highlight faces by direction"
|
|
324
|
+
}
|
|
325
|
+
);
|
|
326
|
+
var HoverButton = () => /* @__PURE__ */ jsx3(
|
|
327
|
+
ToolbarButton,
|
|
328
|
+
{
|
|
329
|
+
action: "hover",
|
|
330
|
+
icon: "hover",
|
|
331
|
+
label: (pressed) => pressed ? "Disable feature hover" : "Enable feature hover"
|
|
332
|
+
}
|
|
333
|
+
);
|
|
334
|
+
var FocusButton = () => /* @__PURE__ */ jsx3(
|
|
335
|
+
ToolbarButton,
|
|
336
|
+
{
|
|
337
|
+
action: "focus",
|
|
338
|
+
icon: "focus",
|
|
339
|
+
label: (pressed) => pressed ? "Show full part" : "Focus selection"
|
|
340
|
+
}
|
|
341
|
+
);
|
|
342
|
+
var WireframeButton = () => /* @__PURE__ */ jsx3(ToolbarButton, { action: "wireframe", icon: "wireframe", label: () => "Wireframe" });
|
|
343
|
+
var SectionButton = () => /* @__PURE__ */ jsx3(
|
|
344
|
+
ToolbarButton,
|
|
345
|
+
{
|
|
346
|
+
action: "section",
|
|
347
|
+
icon: "section",
|
|
348
|
+
label: (pressed) => pressed ? "Exit section" : "Section"
|
|
349
|
+
}
|
|
350
|
+
);
|
|
351
|
+
var MeasureButton = () => /* @__PURE__ */ jsx3(
|
|
352
|
+
ToolbarButton,
|
|
353
|
+
{
|
|
354
|
+
action: "measure",
|
|
355
|
+
icon: "measure",
|
|
356
|
+
label: (pressed) => pressed ? "Exit measure" : "Measure"
|
|
357
|
+
}
|
|
358
|
+
);
|
|
359
|
+
var FitButton = () => /* @__PURE__ */ jsx3(ToolbarButton, { action: "fit", icon: "fit", label: () => "Fit", toggle: false });
|
|
360
|
+
var ResetButton = () => /* @__PURE__ */ jsx3(ToolbarButton, { action: "reset", icon: "reset", label: () => "Reset", toggle: false });
|
|
361
|
+
var TopButton = () => /* @__PURE__ */ jsx3(ToolbarButton, { action: "top", icon: "top", label: () => "Top view", toggle: false });
|
|
362
|
+
var Divider = () => /* @__PURE__ */ jsx3("span", { className: "viewer-toolbar-divider", "data-viewer-toolbar-divider": "true" });
|
|
363
|
+
var Controls = ({ children, className: className2 }) => /* @__PURE__ */ jsx3(
|
|
364
|
+
"div",
|
|
365
|
+
{
|
|
366
|
+
className: ["viewer-toolbar", className2].filter(Boolean).join(" "),
|
|
367
|
+
"data-viewer-toolbar-controls": "true",
|
|
368
|
+
role: "group",
|
|
369
|
+
"aria-label": "Viewer controls",
|
|
370
|
+
children
|
|
371
|
+
}
|
|
372
|
+
);
|
|
373
|
+
var DefaultControls = () => {
|
|
374
|
+
const controls = useViewerToolbar();
|
|
375
|
+
const display = [
|
|
376
|
+
controls.stock ? /* @__PURE__ */ jsx3(StockButton, {}, "stock") : null,
|
|
377
|
+
controls.axes ? /* @__PURE__ */ jsx3(AxesButton, {}, "axes") : null,
|
|
378
|
+
controls.grid ? /* @__PURE__ */ jsx3(GridButton, {}, "grid") : null,
|
|
379
|
+
controls.banana ? /* @__PURE__ */ jsx3(BananaButton, {}, "banana") : null
|
|
380
|
+
].filter(Boolean);
|
|
381
|
+
const analysis = [
|
|
382
|
+
controls.directions ? /* @__PURE__ */ jsx3(DirectionsButton, {}, "directions") : null,
|
|
383
|
+
controls.hover ? /* @__PURE__ */ jsx3(HoverButton, {}, "hover") : null,
|
|
384
|
+
controls.focus ? /* @__PURE__ */ jsx3(FocusButton, {}, "focus") : null,
|
|
385
|
+
controls.wireframe ? /* @__PURE__ */ jsx3(WireframeButton, {}, "wireframe") : null,
|
|
386
|
+
controls.section ? /* @__PURE__ */ jsx3(SectionButton, {}, "section") : null,
|
|
387
|
+
controls.measure ? /* @__PURE__ */ jsx3(MeasureButton, {}, "measure") : null
|
|
388
|
+
].filter(Boolean);
|
|
389
|
+
const camera = [
|
|
390
|
+
controls.fit ? /* @__PURE__ */ jsx3(FitButton, {}, "fit") : null,
|
|
391
|
+
controls.reset ? /* @__PURE__ */ jsx3(ResetButton, {}, "reset") : null,
|
|
392
|
+
controls.top ? /* @__PURE__ */ jsx3(TopButton, {}, "top") : null
|
|
393
|
+
].filter(Boolean);
|
|
394
|
+
return /* @__PURE__ */ jsxs(Controls, { children: [
|
|
395
|
+
display,
|
|
396
|
+
display.length && analysis.length ? /* @__PURE__ */ jsx3(Divider, {}) : null,
|
|
397
|
+
analysis,
|
|
398
|
+
(display.length || analysis.length) && camera.length ? /* @__PURE__ */ jsx3(Divider, {}) : null,
|
|
399
|
+
camera
|
|
400
|
+
] });
|
|
401
|
+
};
|
|
402
|
+
var ViewerToolbarRoot = ({ className: className2, children }) => {
|
|
403
|
+
useViewerToolbar();
|
|
404
|
+
return /* @__PURE__ */ jsx3(
|
|
405
|
+
"div",
|
|
406
|
+
{
|
|
407
|
+
className: ["viewer-toolbar-stack", className2].filter(Boolean).join(" "),
|
|
408
|
+
"data-viewer-toolbar": "true",
|
|
409
|
+
children: children ?? /* @__PURE__ */ jsx3(DefaultControls, {})
|
|
410
|
+
}
|
|
411
|
+
);
|
|
412
|
+
};
|
|
413
|
+
var ViewerToolbar = Object.assign(ViewerToolbarRoot, {
|
|
414
|
+
Controls,
|
|
415
|
+
Divider,
|
|
416
|
+
StockButton,
|
|
417
|
+
AxesButton,
|
|
418
|
+
GridButton,
|
|
419
|
+
BananaButton,
|
|
420
|
+
DirectionsButton,
|
|
421
|
+
HoverButton,
|
|
422
|
+
FocusButton,
|
|
423
|
+
WireframeButton,
|
|
424
|
+
SectionButton,
|
|
425
|
+
MeasureButton,
|
|
426
|
+
FitButton,
|
|
427
|
+
ResetButton,
|
|
428
|
+
TopButton
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
// src/stock.tsx
|
|
432
|
+
import { useThree } from "@react-three/fiber";
|
|
433
|
+
import { useEffect as useEffect2, useLayoutEffect, useMemo } from "react";
|
|
434
|
+
import { BoxGeometry, Vector3 as Vector32 } from "three";
|
|
435
|
+
|
|
436
|
+
// src/render/stock.ts
|
|
437
|
+
import {
|
|
438
|
+
Box3,
|
|
439
|
+
EdgesGeometry,
|
|
440
|
+
Group,
|
|
441
|
+
LineBasicMaterial,
|
|
442
|
+
LineSegments,
|
|
443
|
+
Mesh,
|
|
444
|
+
MeshLambertMaterial,
|
|
445
|
+
Vector3
|
|
446
|
+
} from "three";
|
|
447
|
+
function fixedBoxStockBounds(geometry, dimensions, position = "model_centered", positionOffset = 0, offset = { x: 0, y: 0, z: 0 }) {
|
|
448
|
+
if (![dimensions.x, dimensions.y, dimensions.z].every(Number.isFinite) || [dimensions.x, dimensions.y, dimensions.z].some((value) => value <= 0)) {
|
|
449
|
+
throw new RangeError("Fixed stock dimensions must be finite and positive.");
|
|
450
|
+
}
|
|
451
|
+
if (!Number.isFinite(positionOffset)) {
|
|
452
|
+
throw new RangeError("Fixed stock position offset must be finite.");
|
|
453
|
+
}
|
|
454
|
+
if (![offset.x, offset.y, offset.z].every(Number.isFinite)) {
|
|
455
|
+
throw new RangeError("Fixed stock offset must be finite.");
|
|
456
|
+
}
|
|
457
|
+
const part = partBounds(geometry);
|
|
458
|
+
const center = part.getCenter(new Vector3());
|
|
459
|
+
const z = position === "offset_from_top" ? part.max.z + positionOffset - dimensions.z / 2 : position === "offset_from_bottom" ? part.min.z - positionOffset + dimensions.z / 2 : center.z;
|
|
460
|
+
const half = new Vector3(dimensions.x / 2, dimensions.y / 2, dimensions.z / 2);
|
|
461
|
+
return new Box3(
|
|
462
|
+
new Vector3(center.x, center.y, z).sub(half),
|
|
463
|
+
new Vector3(center.x, center.y, z).add(half)
|
|
464
|
+
).translate(new Vector3(offset.x, offset.y, offset.z));
|
|
465
|
+
}
|
|
466
|
+
function boxStockBounds(geometry, allowance = 0, offset = { x: 0, y: 0, z: 0 }) {
|
|
467
|
+
const padding = typeof allowance === "number" ? new Vector3(allowance, allowance, allowance) : "wall" in allowance ? new Vector3(allowance.wall, allowance.wall, allowance.floor) : new Vector3(allowance.x, allowance.y, allowance.z);
|
|
468
|
+
if (padding.toArray().some((value) => !Number.isFinite(value) || value < 0)) {
|
|
469
|
+
throw new RangeError("Stock allowance must be finite and non-negative.");
|
|
470
|
+
}
|
|
471
|
+
if (![offset.x, offset.y, offset.z].every(Number.isFinite)) {
|
|
472
|
+
throw new RangeError("Stock offset must be finite.");
|
|
473
|
+
}
|
|
474
|
+
const box = partBounds(geometry);
|
|
475
|
+
box.expandByVector(padding).translate(new Vector3(offset.x, offset.y, offset.z));
|
|
476
|
+
const size = box.getSize(new Vector3());
|
|
477
|
+
if (size.toArray().some((value) => !Number.isFinite(value) || value <= 0)) {
|
|
478
|
+
throw new RangeError("Stock dimensions must be finite and positive.");
|
|
479
|
+
}
|
|
480
|
+
return box;
|
|
481
|
+
}
|
|
482
|
+
function partBounds(geometry) {
|
|
483
|
+
const position = geometry.getAttribute("position");
|
|
484
|
+
if (!position || position.count === 0)
|
|
485
|
+
throw new RangeError("Stock needs non-empty part geometry.");
|
|
486
|
+
const box = new Box3();
|
|
487
|
+
const point = new Vector3();
|
|
488
|
+
for (let index = 0; index < position.count; index += 1) {
|
|
489
|
+
point.fromBufferAttribute(position, index);
|
|
490
|
+
if (!Number.isFinite(point.x) || !Number.isFinite(point.y) || !Number.isFinite(point.z)) {
|
|
491
|
+
throw new RangeError("Stock needs finite part coordinates.");
|
|
492
|
+
}
|
|
493
|
+
box.expandByPoint(point);
|
|
494
|
+
}
|
|
495
|
+
return box;
|
|
496
|
+
}
|
|
497
|
+
function createStock(geometry) {
|
|
498
|
+
const material = new MeshLambertMaterial({ transparent: true, depthWrite: false });
|
|
499
|
+
const edgeMaterial = new LineBasicMaterial({ transparent: true, depthWrite: false });
|
|
500
|
+
const mesh = new Mesh(geometry, material);
|
|
501
|
+
const edgeGeometry = new EdgesGeometry(geometry, 15);
|
|
502
|
+
const edges = new LineSegments(edgeGeometry, edgeMaterial);
|
|
503
|
+
const object = new Group();
|
|
504
|
+
object.userData[STOCK_OBJECT] = true;
|
|
505
|
+
mesh.renderOrder = 5;
|
|
506
|
+
edges.renderOrder = 6;
|
|
507
|
+
mesh.raycast = () => {
|
|
508
|
+
};
|
|
509
|
+
edges.raycast = () => {
|
|
510
|
+
};
|
|
511
|
+
object.add(mesh, edges);
|
|
512
|
+
return {
|
|
513
|
+
object,
|
|
514
|
+
material,
|
|
515
|
+
edgeMaterial,
|
|
516
|
+
edges,
|
|
517
|
+
dispose() {
|
|
518
|
+
material.dispose();
|
|
519
|
+
edgeMaterial.dispose();
|
|
520
|
+
edgeGeometry.dispose();
|
|
521
|
+
}
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// src/stock.tsx
|
|
526
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
527
|
+
var Stock = ({
|
|
528
|
+
geometry,
|
|
529
|
+
color = 12176354,
|
|
530
|
+
opacity = 0.2,
|
|
531
|
+
edgeColor = 11058648,
|
|
532
|
+
edgeOpacity = 0.75,
|
|
533
|
+
showEdges = true
|
|
534
|
+
}) => {
|
|
535
|
+
const invalidate = useThree((state) => state.invalidate);
|
|
536
|
+
const stock = useMemo(() => createStock(geometry), [geometry]);
|
|
537
|
+
useEffect2(() => () => stock.dispose(), [stock]);
|
|
538
|
+
useLayoutEffect(() => {
|
|
539
|
+
stock.material.color.setHex(color);
|
|
540
|
+
stock.material.opacity = opacity;
|
|
541
|
+
stock.edgeMaterial.color.setHex(edgeColor);
|
|
542
|
+
stock.edgeMaterial.opacity = edgeOpacity;
|
|
543
|
+
stock.edges.visible = showEdges;
|
|
544
|
+
invalidate();
|
|
545
|
+
}, [color, edgeColor, edgeOpacity, invalidate, opacity, showEdges, stock]);
|
|
546
|
+
return /* @__PURE__ */ jsx4("primitive", { object: stock.object, dispose: null });
|
|
547
|
+
};
|
|
548
|
+
var BoxStock = ({
|
|
549
|
+
partGeometry,
|
|
550
|
+
dimensions,
|
|
551
|
+
position = "model_centered",
|
|
552
|
+
positionOffset = 0,
|
|
553
|
+
allowance = 0,
|
|
554
|
+
offset,
|
|
555
|
+
...props
|
|
556
|
+
}) => {
|
|
557
|
+
const ox = offset?.x ?? 0;
|
|
558
|
+
const oy = offset?.y ?? 0;
|
|
559
|
+
const oz = offset?.z ?? 0;
|
|
560
|
+
const geometry = useMemo(() => {
|
|
561
|
+
const box = dimensions ? fixedBoxStockBounds(partGeometry, dimensions, position, positionOffset, {
|
|
562
|
+
x: ox,
|
|
563
|
+
y: oy,
|
|
564
|
+
z: oz
|
|
565
|
+
}) : boxStockBounds(partGeometry, allowance, { x: ox, y: oy, z: oz });
|
|
566
|
+
const size = box.getSize(new Vector32());
|
|
567
|
+
const center = box.getCenter(new Vector32());
|
|
568
|
+
return new BoxGeometry(size.x, size.y, size.z).translate(center.x, center.y, center.z);
|
|
569
|
+
}, [allowance, dimensions, ox, oy, oz, partGeometry, position, positionOffset]);
|
|
570
|
+
useEffect2(() => () => geometry.dispose(), [geometry]);
|
|
571
|
+
return /* @__PURE__ */ jsx4(Stock, { geometry, ...props });
|
|
572
|
+
};
|
|
573
|
+
|
|
574
|
+
// src/banana.tsx
|
|
575
|
+
import { useGLTF } from "@react-three/drei";
|
|
576
|
+
import { useThree as useThree2 } from "@react-three/fiber";
|
|
577
|
+
import { useLayoutEffect as useLayoutEffect2, useMemo as useMemo2, useRef } from "react";
|
|
578
|
+
|
|
579
|
+
// src/render/banana.ts
|
|
580
|
+
import { Vector3 as Vector33 } from "three";
|
|
581
|
+
var BANANA_GAP = 0.1;
|
|
582
|
+
function bananaPosition(part, banana) {
|
|
583
|
+
const size = part.getSize(new Vector33());
|
|
584
|
+
const reach = Math.max(size.x, size.y, size.z);
|
|
585
|
+
const centre = part.getCenter(new Vector33());
|
|
586
|
+
return new Vector33(
|
|
587
|
+
part.max.x + reach * BANANA_GAP - banana.min.x,
|
|
588
|
+
centre.y - (banana.min.y + banana.max.y) / 2,
|
|
589
|
+
part.min.z - banana.min.z
|
|
590
|
+
);
|
|
591
|
+
}
|
|
592
|
+
function bananaFrameBounds(part, banana, position) {
|
|
593
|
+
return part.clone().union(banana.clone().translate(position));
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
// src/banana.tsx
|
|
597
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
598
|
+
var BANANA_MODEL_URL = new URL("./assets/banana.glb", import.meta.url).href;
|
|
599
|
+
var SKIN = "#e8b530";
|
|
600
|
+
var FURNITURE = { [EXCLUDE_FROM_FRAME]: true };
|
|
601
|
+
var Banana = ({ onPlaced }) => {
|
|
602
|
+
const part = useContentBox();
|
|
603
|
+
const invalidate = useThree2((state) => state.invalidate);
|
|
604
|
+
const gltf = useGLTF(BANANA_MODEL_URL);
|
|
605
|
+
const group = useRef(null);
|
|
606
|
+
const geometry = useMemo2(() => {
|
|
607
|
+
let found = null;
|
|
608
|
+
gltf.scene.traverse((object) => {
|
|
609
|
+
const mesh = object;
|
|
610
|
+
if (found === null && mesh.isMesh) found = mesh.geometry;
|
|
611
|
+
});
|
|
612
|
+
const source = found;
|
|
613
|
+
if (!source) return null;
|
|
614
|
+
const own = source.clone();
|
|
615
|
+
own.computeVertexNormals();
|
|
616
|
+
own.rotateY(Math.PI / 2);
|
|
617
|
+
own.rotateX(Math.PI / 2);
|
|
618
|
+
own.computeBoundingBox();
|
|
619
|
+
return own;
|
|
620
|
+
}, [gltf]);
|
|
621
|
+
useLayoutEffect2(() => {
|
|
622
|
+
const node = group.current;
|
|
623
|
+
const own = geometry?.boundingBox;
|
|
624
|
+
if (!node || !own || part.isEmpty()) return;
|
|
625
|
+
const position = bananaPosition(part, own);
|
|
626
|
+
node.position.copy(position);
|
|
627
|
+
node.visible = true;
|
|
628
|
+
node.updateWorldMatrix(true, true);
|
|
629
|
+
onPlaced?.(bananaFrameBounds(part, own, position));
|
|
630
|
+
invalidate();
|
|
631
|
+
}, [geometry, invalidate, onPlaced, part]);
|
|
632
|
+
if (!geometry) return null;
|
|
633
|
+
return /* @__PURE__ */ jsx5("group", { ref: group, userData: FURNITURE, visible: false, children: /* @__PURE__ */ jsx5("mesh", { geometry, children: /* @__PURE__ */ jsx5("meshStandardMaterial", { color: SKIN, roughness: 0.85, metalness: 0 }) }) });
|
|
634
|
+
};
|
|
635
|
+
|
|
636
|
+
// src/render/direction-highlights.ts
|
|
637
|
+
function directionHighlights(model, activeDirection = null) {
|
|
638
|
+
const features = model.features.map((feature) => ({ feature, index: directionIndexOf(model, feature.machiningDirection) })).filter(({ index }) => index >= 0 && (activeDirection === null || index === activeDirection)).sort(
|
|
639
|
+
(a, b) => featureTypeRank(a.feature.featureType) - featureTypeRank(b.feature.featureType) || a.index - b.index || (a.feature.tag < b.feature.tag ? -1 : a.feature.tag > b.feature.tag ? 1 : 0)
|
|
640
|
+
);
|
|
641
|
+
const colors = /* @__PURE__ */ new Map();
|
|
642
|
+
for (const { feature, index } of features) {
|
|
643
|
+
for (const region of model.regionIndex.regionsForFeature(feature.tag)) {
|
|
644
|
+
if (!colors.has(region)) colors.set(region, { region, color: directionColor(index) });
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
return [...colors.values()].sort((a, b) => a.region - b.region);
|
|
648
|
+
}
|
|
135
649
|
|
|
136
650
|
// src/primitives.tsx
|
|
137
651
|
import { GizmoHelper } from "@react-three/drei";
|
|
138
|
-
import { useThree } from "@react-three/fiber";
|
|
139
|
-
import { useEffect, useMemo, useRef, useState } from "react";
|
|
652
|
+
import { useThree as useThree3 } from "@react-three/fiber";
|
|
653
|
+
import { useEffect as useEffect3, useMemo as useMemo3, useRef as useRef2, useState as useState2 } from "react";
|
|
140
654
|
|
|
141
655
|
// src/render/grid.ts
|
|
142
|
-
import { BufferGeometry, Float32BufferAttribute, Vector3 } from "three";
|
|
656
|
+
import { BufferGeometry, Float32BufferAttribute, Vector3 as Vector34 } from "three";
|
|
143
657
|
var STEPS = [0.1, 0.2, 0.5, 1, 2, 5, 10, 20, 25, 50, 100, 200, 250, 500, 1e3];
|
|
144
658
|
var TARGET_CELLS = 10;
|
|
145
659
|
var OVERHANG = 1.6;
|
|
146
660
|
function gridSpec(box) {
|
|
147
|
-
const size = box.getSize(new
|
|
148
|
-
const center = box.getCenter(new
|
|
661
|
+
const size = box.getSize(new Vector34());
|
|
662
|
+
const center = box.getCenter(new Vector34());
|
|
149
663
|
const largest = Math.max(size.x, size.y, 1e-6);
|
|
150
664
|
const ideal = largest / TARGET_CELLS;
|
|
151
665
|
const step = [...STEPS].reverse().find((candidate) => candidate <= ideal) ?? STEPS[0];
|
|
@@ -189,26 +703,26 @@ function gridFor(box, options = {}) {
|
|
|
189
703
|
}
|
|
190
704
|
|
|
191
705
|
// src/primitives.tsx
|
|
192
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
193
|
-
var
|
|
706
|
+
import { jsx as jsx6, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
707
|
+
var FURNITURE2 = { [EXCLUDE_FROM_FRAME]: true };
|
|
194
708
|
var Grid = ({ step, extent, color, opacity = 0.35 }) => {
|
|
195
709
|
const theme = resolveTheme();
|
|
196
710
|
const box = useContentBox();
|
|
197
|
-
const geometry =
|
|
198
|
-
|
|
711
|
+
const geometry = useMemo3(() => gridFor(box, { step, extent }), [box, extent, step]);
|
|
712
|
+
useEffect3(() => () => geometry?.dispose(), [geometry]);
|
|
199
713
|
if (!geometry) return null;
|
|
200
|
-
return /* @__PURE__ */
|
|
714
|
+
return /* @__PURE__ */ jsx6("lineSegments", { geometry, renderOrder: -1, raycast: () => null, userData: FURNITURE2, children: /* @__PURE__ */ jsx6("lineBasicMaterial", { color: color ?? theme.cubeEdge, transparent: true, opacity }) });
|
|
201
715
|
};
|
|
202
|
-
var Axes = ({ size = 25 }) => /* @__PURE__ */
|
|
716
|
+
var Axes = ({ size = 25 }) => /* @__PURE__ */ jsx6("axesHelper", { args: [size], userData: FURNITURE2, raycast: () => null });
|
|
203
717
|
var ViewCube = ({
|
|
204
718
|
alignment = "top-right",
|
|
205
719
|
margin = [80, 80],
|
|
206
720
|
theme,
|
|
207
721
|
onViewChange
|
|
208
722
|
}) => {
|
|
209
|
-
const resolved =
|
|
210
|
-
const zones =
|
|
211
|
-
return /* @__PURE__ */
|
|
723
|
+
const resolved = useMemo3(() => resolveTheme(theme), [theme]);
|
|
724
|
+
const zones = useMemo3(() => cubeZones(), []);
|
|
725
|
+
return /* @__PURE__ */ jsx6(GizmoHelper, { alignment, margin, children: /* @__PURE__ */ jsx6(CubePanels, { zones, theme: resolved, onViewChange }) });
|
|
212
726
|
};
|
|
213
727
|
var CubePanels = ({
|
|
214
728
|
zones,
|
|
@@ -216,15 +730,15 @@ var CubePanels = ({
|
|
|
216
730
|
onViewChange
|
|
217
731
|
}) => {
|
|
218
732
|
const controls = useViewerControls();
|
|
219
|
-
const invalidate =
|
|
220
|
-
const groupRef =
|
|
221
|
-
const [hovered, setHovered] =
|
|
222
|
-
const panels =
|
|
733
|
+
const invalidate = useThree3((state) => state.invalidate);
|
|
734
|
+
const groupRef = useRef2(null);
|
|
735
|
+
const [hovered, setHovered] = useState2(null);
|
|
736
|
+
const panels = useMemo3(
|
|
223
737
|
() => zones.map((zone) => ({ zone, geometry: panelGeometry(zone) })),
|
|
224
738
|
[zones]
|
|
225
739
|
);
|
|
226
|
-
const outline =
|
|
227
|
-
const labels =
|
|
740
|
+
const outline = useMemo3(() => cubeOutlineGeometry(zones), [zones]);
|
|
741
|
+
const labels = useMemo3(
|
|
228
742
|
() => zones.filter((zone) => zone.kind === "face").map((zone) => ({
|
|
229
743
|
zone,
|
|
230
744
|
geometry: labelGeometry(zone),
|
|
@@ -232,7 +746,7 @@ var CubePanels = ({
|
|
|
232
746
|
})),
|
|
233
747
|
[theme.cubeLabel, zones]
|
|
234
748
|
);
|
|
235
|
-
|
|
749
|
+
useEffect3(
|
|
236
750
|
() => () => {
|
|
237
751
|
for (const panel of panels) panel.geometry.dispose();
|
|
238
752
|
for (const label of labels) {
|
|
@@ -251,8 +765,8 @@ var CubePanels = ({
|
|
|
251
765
|
setHovered(name);
|
|
252
766
|
invalidate();
|
|
253
767
|
};
|
|
254
|
-
return /* @__PURE__ */
|
|
255
|
-
panels.map(({ zone, geometry }) => /* @__PURE__ */
|
|
768
|
+
return /* @__PURE__ */ jsxs2("group", { ref: groupRef, scale: 38, children: [
|
|
769
|
+
panels.map(({ zone, geometry }) => /* @__PURE__ */ jsx6(
|
|
256
770
|
"mesh",
|
|
257
771
|
{
|
|
258
772
|
geometry,
|
|
@@ -265,7 +779,7 @@ var CubePanels = ({
|
|
|
265
779
|
event.stopPropagation();
|
|
266
780
|
choose(zone);
|
|
267
781
|
},
|
|
268
|
-
children: /* @__PURE__ */
|
|
782
|
+
children: /* @__PURE__ */ jsx6(
|
|
269
783
|
"meshLambertMaterial",
|
|
270
784
|
{
|
|
271
785
|
color: hovered === zone.name ? theme.hover : theme.cube,
|
|
@@ -277,19 +791,19 @@ var CubePanels = ({
|
|
|
277
791
|
},
|
|
278
792
|
zone.name
|
|
279
793
|
)),
|
|
280
|
-
labels.map(({ zone, geometry, texture }) => /* @__PURE__ */
|
|
281
|
-
/* @__PURE__ */
|
|
282
|
-
/* @__PURE__ */
|
|
283
|
-
/* @__PURE__ */
|
|
794
|
+
labels.map(({ zone, geometry, texture }) => /* @__PURE__ */ jsx6("mesh", { geometry, raycast: () => null, children: /* @__PURE__ */ jsx6("meshBasicMaterial", { map: texture, transparent: true }) }, `${zone.name}-label`)),
|
|
795
|
+
/* @__PURE__ */ jsx6("lineSegments", { geometry: outline, raycast: () => null, children: /* @__PURE__ */ jsx6("lineBasicMaterial", { color: theme.cubeEdge }) }),
|
|
796
|
+
/* @__PURE__ */ jsx6("ambientLight", { intensity: 1.4 }),
|
|
797
|
+
/* @__PURE__ */ jsx6("directionalLight", { position: [viewVector("top-front-right").x, 1, 2], intensity: 1.1 })
|
|
284
798
|
] });
|
|
285
799
|
};
|
|
286
800
|
|
|
287
801
|
// src/direction-arrows.tsx
|
|
288
|
-
import { useThree as
|
|
289
|
-
import { useMemo as
|
|
290
|
-
import { Quaternion, Vector3 as
|
|
291
|
-
import { jsx as
|
|
292
|
-
var
|
|
802
|
+
import { useThree as useThree4 } from "@react-three/fiber";
|
|
803
|
+
import { useMemo as useMemo4 } from "react";
|
|
804
|
+
import { Quaternion, Vector3 as Vector35 } from "three";
|
|
805
|
+
import { jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
806
|
+
var FURNITURE3 = { [EXCLUDE_FROM_FRAME]: true };
|
|
293
807
|
var DirectionArrows = ({
|
|
294
808
|
directions,
|
|
295
809
|
activeDirection = null,
|
|
@@ -301,7 +815,7 @@ var DirectionArrows = ({
|
|
|
301
815
|
visible = true
|
|
302
816
|
}) => {
|
|
303
817
|
const box = useContentBox();
|
|
304
|
-
const resolved =
|
|
818
|
+
const resolved = useMemo4(() => resolveTheme(theme), [theme]);
|
|
305
819
|
const shown = shownDirection === void 0 ? activeDirection : shownDirection;
|
|
306
820
|
const drawn = (index) => {
|
|
307
821
|
if (shown === null) return true;
|
|
@@ -313,10 +827,10 @@ var DirectionArrows = ({
|
|
|
313
827
|
// Excluded from framing: the arrows are deliberately placed outside the
|
|
314
828
|
// part, so a Fit that measured them would frame the arrows and leave the
|
|
315
829
|
// part small in the middle of them.
|
|
316
|
-
/* @__PURE__ */
|
|
830
|
+
/* @__PURE__ */ jsxs3("group", { userData: FURNITURE3, children: [
|
|
317
831
|
directions.map((direction, index) => {
|
|
318
832
|
if (!drawn(index)) return null;
|
|
319
|
-
return /* @__PURE__ */
|
|
833
|
+
return /* @__PURE__ */ jsx7(
|
|
320
834
|
Arrow,
|
|
321
835
|
{
|
|
322
836
|
direction,
|
|
@@ -328,7 +842,7 @@ var DirectionArrows = ({
|
|
|
328
842
|
`candidate-${index}`
|
|
329
843
|
);
|
|
330
844
|
}),
|
|
331
|
-
namedDirections.map((named) => /* @__PURE__ */
|
|
845
|
+
namedDirections.map((named) => /* @__PURE__ */ jsx7(
|
|
332
846
|
Arrow,
|
|
333
847
|
{
|
|
334
848
|
direction: named.direction,
|
|
@@ -339,17 +853,17 @@ var DirectionArrows = ({
|
|
|
339
853
|
},
|
|
340
854
|
`named-${named.index}`
|
|
341
855
|
)),
|
|
342
|
-
previewDirection ? /* @__PURE__ */
|
|
856
|
+
previewDirection ? /* @__PURE__ */ jsx7(Arrow, { direction: previewDirection, box, color: resolved.hover, opacity: 0.95, onTop: true }) : null
|
|
343
857
|
] })
|
|
344
858
|
);
|
|
345
859
|
};
|
|
346
860
|
var Arrow = ({ direction, box, color, opacity, onPick, onTop = false }) => {
|
|
347
|
-
const invalidate =
|
|
348
|
-
const { tip, length, quaternion } =
|
|
861
|
+
const invalidate = useThree4((state) => state.invalidate);
|
|
862
|
+
const { tip, length, quaternion } = useMemo4(() => {
|
|
349
863
|
const placement = arrowPlacement(direction, box);
|
|
350
864
|
const aim = new Quaternion().setFromUnitVectors(
|
|
351
865
|
CONE_AXIS,
|
|
352
|
-
new
|
|
866
|
+
new Vector35(direction.x, direction.y, direction.z).normalize()
|
|
353
867
|
);
|
|
354
868
|
return { tip: placement.tip, length: placement.length, quaternion: aim };
|
|
355
869
|
}, [box, direction]);
|
|
@@ -362,234 +876,32 @@ var Arrow = ({ direction, box, color, opacity, onPick, onTop = false }) => {
|
|
|
362
876
|
invalidate();
|
|
363
877
|
}
|
|
364
878
|
} : {};
|
|
365
|
-
return /* @__PURE__ */
|
|
366
|
-
/* @__PURE__ */
|
|
367
|
-
/* @__PURE__ */
|
|
368
|
-
/* @__PURE__ */
|
|
879
|
+
return /* @__PURE__ */ jsxs3("group", { position: tip, quaternion, renderOrder: onTop ? 10 : 3, children: [
|
|
880
|
+
/* @__PURE__ */ jsxs3("mesh", { position: [0, head * 0.5, 0], rotation: [Math.PI, 0, 0], ...press, children: [
|
|
881
|
+
/* @__PURE__ */ jsx7("coneGeometry", { args: [length * HEAD_RADIUS, head, 20] }),
|
|
882
|
+
/* @__PURE__ */ jsx7("meshBasicMaterial", { color, transparent: true, opacity, depthTest: !onTop })
|
|
369
883
|
] }),
|
|
370
|
-
/* @__PURE__ */
|
|
371
|
-
/* @__PURE__ */
|
|
372
|
-
/* @__PURE__ */
|
|
884
|
+
/* @__PURE__ */ jsxs3("mesh", { position: [0, head + shaft * 0.5, 0], ...press, children: [
|
|
885
|
+
/* @__PURE__ */ jsx7("cylinderGeometry", { args: [length * SHAFT_RADIUS, length * SHAFT_RADIUS, shaft, 12] }),
|
|
886
|
+
/* @__PURE__ */ jsx7("meshBasicMaterial", { color, transparent: true, opacity, depthTest: !onTop })
|
|
373
887
|
] })
|
|
374
888
|
] });
|
|
375
889
|
};
|
|
376
890
|
|
|
377
891
|
// src/section-tool.tsx
|
|
378
|
-
import { useFrame, useThree as
|
|
379
|
-
import { useEffect as
|
|
892
|
+
import { useFrame, useThree as useThree5 } from "@react-three/fiber";
|
|
893
|
+
import { useEffect as useEffect4, useMemo as useMemo5, useRef as useRef3, useState as useState3, useSyncExternalStore } from "react";
|
|
380
894
|
import {
|
|
381
895
|
BufferGeometry as BufferGeometry2,
|
|
382
896
|
DoubleSide,
|
|
383
897
|
Quaternion as Quaternion2,
|
|
384
898
|
Raycaster,
|
|
385
|
-
Vector2
|
|
386
|
-
Vector3 as
|
|
899
|
+
Vector2,
|
|
900
|
+
Vector3 as Vector36
|
|
387
901
|
} from "three";
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
var MEASURE_RENDER_ORDER = 7;
|
|
392
|
-
var AXIS_COLORS = { x: 16739179, y: 7331978, z: 7314431 };
|
|
393
|
-
var SNAP_PIXELS = {
|
|
394
|
-
vertex: 14,
|
|
395
|
-
midpoint: 12,
|
|
396
|
-
edge: 9
|
|
397
|
-
};
|
|
398
|
-
var SNAP_MARKER_PIXELS = {
|
|
399
|
-
vertex: 6,
|
|
400
|
-
midpoint: 5,
|
|
401
|
-
edge: 4,
|
|
402
|
-
face: 3.5
|
|
403
|
-
};
|
|
404
|
-
var MEASURE_MARKER_PIXELS = 3.5;
|
|
405
|
-
var MEASURE_LINE_PIXELS = {
|
|
406
|
-
line: 2,
|
|
407
|
-
leg: 1.5,
|
|
408
|
-
edge: 3
|
|
409
|
-
};
|
|
410
|
-
var DELTA_DASH_PIXELS = 6;
|
|
411
|
-
var ANGLE_ARC_FRACTION = 0.3;
|
|
412
|
-
var ANGLE_ARC_SEGMENTS = 24;
|
|
413
|
-
function snapAt(hit, edges, camera, viewport) {
|
|
414
|
-
const face = {
|
|
415
|
-
kind: "face",
|
|
416
|
-
point: hit.point.clone(),
|
|
417
|
-
normal: hit.normal.clone(),
|
|
418
|
-
edge: null
|
|
419
|
-
};
|
|
420
|
-
if (!edges) return face;
|
|
421
|
-
const positions = edges.positions;
|
|
422
|
-
const segments = Math.floor(positions.length / 6);
|
|
423
|
-
if (segments === 0) return face;
|
|
424
|
-
const inverse = edges.matrixWorld.clone().invert();
|
|
425
|
-
const p = hit.point.clone().applyMatrix4(inverse);
|
|
426
|
-
const n = hit.normal.clone().transformDirection(inverse);
|
|
427
|
-
const reach = screenLength(camera, hit.point, viewport, SNAP_PIXELS.vertex) * 1.5;
|
|
428
|
-
const reachSq = reach * reach;
|
|
429
|
-
const pointer = screenPoint(camera, hit.point, viewport);
|
|
430
|
-
const best = {
|
|
431
|
-
vertex: { distance: Number.POSITIVE_INFINITY, index: -1, t: 0 },
|
|
432
|
-
midpoint: { distance: Number.POSITIVE_INFINITY, index: -1, t: 0 },
|
|
433
|
-
edge: { distance: Number.POSITIVE_INFINITY, index: -1, t: 0 }
|
|
434
|
-
};
|
|
435
|
-
const a = new Vector33();
|
|
436
|
-
const b = new Vector33();
|
|
437
|
-
const ab = new Vector33();
|
|
438
|
-
const ap = new Vector33();
|
|
439
|
-
const q = new Vector33();
|
|
440
|
-
const pixel = new Vector2();
|
|
441
|
-
const consider = (kind, point, index, t) => {
|
|
442
|
-
const distance = screenPoint(
|
|
443
|
-
camera,
|
|
444
|
-
q.copy(point).applyMatrix4(edges.matrixWorld),
|
|
445
|
-
viewport,
|
|
446
|
-
pixel
|
|
447
|
-
).distanceTo(pointer);
|
|
448
|
-
if (distance <= SNAP_PIXELS[kind] && distance < best[kind].distance) {
|
|
449
|
-
best[kind] = { distance, index, t };
|
|
450
|
-
}
|
|
451
|
-
};
|
|
452
|
-
for (let index = 0; index < segments; index += 1) {
|
|
453
|
-
const offset = index * 6;
|
|
454
|
-
a.set(positions[offset], positions[offset + 1], positions[offset + 2]);
|
|
455
|
-
b.set(positions[offset + 3], positions[offset + 4], positions[offset + 5]);
|
|
456
|
-
if (Math.abs(ap.subVectors(a, p).dot(n)) > reach) continue;
|
|
457
|
-
if (Math.abs(ap.subVectors(b, p).dot(n)) > reach) continue;
|
|
458
|
-
ab.subVectors(b, a);
|
|
459
|
-
ap.subVectors(p, a);
|
|
460
|
-
const lengthSq = ab.lengthSq();
|
|
461
|
-
const t = lengthSq === 0 ? 0 : Math.min(1, Math.max(0, ap.dot(ab) / lengthSq));
|
|
462
|
-
q.copy(a).addScaledVector(ab, t);
|
|
463
|
-
if (q.distanceToSquared(p) > reachSq) continue;
|
|
464
|
-
consider("vertex", a, index, 0);
|
|
465
|
-
consider("vertex", b, index, 1);
|
|
466
|
-
consider("midpoint", q.copy(a).addScaledVector(ab, 0.5), index, 0.5);
|
|
467
|
-
consider("edge", q.copy(a).addScaledVector(ab, t), index, t);
|
|
468
|
-
}
|
|
469
|
-
for (const kind of ["vertex", "midpoint", "edge"]) {
|
|
470
|
-
const found = best[kind];
|
|
471
|
-
if (found.index < 0) continue;
|
|
472
|
-
const offset = found.index * 6;
|
|
473
|
-
const start = new Vector33(positions[offset], positions[offset + 1], positions[offset + 2]);
|
|
474
|
-
const end = new Vector33(positions[offset + 3], positions[offset + 4], positions[offset + 5]);
|
|
475
|
-
const point = start.clone().lerp(end, found.t);
|
|
476
|
-
start.applyMatrix4(edges.matrixWorld);
|
|
477
|
-
end.applyMatrix4(edges.matrixWorld);
|
|
478
|
-
point.applyMatrix4(edges.matrixWorld);
|
|
479
|
-
return {
|
|
480
|
-
kind,
|
|
481
|
-
point,
|
|
482
|
-
normal: hit.normal.clone(),
|
|
483
|
-
edge: kind === "vertex" ? null : [start, end]
|
|
484
|
-
};
|
|
485
|
-
}
|
|
486
|
-
return face;
|
|
487
|
-
}
|
|
488
|
-
function screenPoint(camera, point, viewport, into = new Vector2()) {
|
|
489
|
-
const ndc = point.clone().project(camera);
|
|
490
|
-
return into.set((ndc.x + 1) / 2 * viewport.width, (1 - ndc.y) / 2 * viewport.height);
|
|
491
|
-
}
|
|
492
|
-
var POINTS_PER_MEASUREMENT = {
|
|
493
|
-
distance: 2,
|
|
494
|
-
angle: 3
|
|
495
|
-
};
|
|
496
|
-
function measurementFromPoints(kind, points, id) {
|
|
497
|
-
if (points.length < POINTS_PER_MEASUREMENT[kind]) return null;
|
|
498
|
-
const [a, b, c] = points;
|
|
499
|
-
if (kind === "distance") return { id, kind, points: [copy(a), copy(b)] };
|
|
500
|
-
return { id, kind, points: [copy(a), copy(b), copy(c)] };
|
|
501
|
-
}
|
|
502
|
-
function nextMeasurementId(held) {
|
|
503
|
-
return held.reduce((top, entry) => Math.max(top, entry.id), 0) + 1;
|
|
504
|
-
}
|
|
505
|
-
function distanceBetween(a, b) {
|
|
506
|
-
return Math.hypot(b.x - a.x, b.y - a.y, b.z - a.z);
|
|
507
|
-
}
|
|
508
|
-
function deltaBetween(a, b) {
|
|
509
|
-
return { x: b.x - a.x, y: b.y - a.y, z: b.z - a.z };
|
|
510
|
-
}
|
|
511
|
-
function midpoint(a, b) {
|
|
512
|
-
return { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2, z: (a.z + b.z) / 2 };
|
|
513
|
-
}
|
|
514
|
-
function angleAt(vertex, a, b) {
|
|
515
|
-
const u = new Vector33(a.x - vertex.x, a.y - vertex.y, a.z - vertex.z);
|
|
516
|
-
const w = new Vector33(b.x - vertex.x, b.y - vertex.y, b.z - vertex.z);
|
|
517
|
-
if (u.lengthSq() === 0 || w.lengthSq() === 0) return 0;
|
|
518
|
-
return u.angleTo(w) * 180 / Math.PI;
|
|
519
|
-
}
|
|
520
|
-
function lockToAxis(from, to) {
|
|
521
|
-
const delta = deltaBetween(from, to);
|
|
522
|
-
let axis = "x";
|
|
523
|
-
for (const candidate of ["y", "z"]) {
|
|
524
|
-
if (Math.abs(delta[candidate]) > Math.abs(delta[axis])) axis = candidate;
|
|
525
|
-
}
|
|
526
|
-
return { axis, point: { ...from, [axis]: to[axis] } };
|
|
527
|
-
}
|
|
528
|
-
function deltaLegs(a, b) {
|
|
529
|
-
const delta = deltaBetween(a, b);
|
|
530
|
-
const threshold = Math.max(1e-9, distanceBetween(a, b) * 1e-6);
|
|
531
|
-
const legs = [];
|
|
532
|
-
let cursor = copy(a);
|
|
533
|
-
for (const axis of ["x", "y", "z"]) {
|
|
534
|
-
if (Math.abs(delta[axis]) <= threshold) continue;
|
|
535
|
-
const to = { ...cursor, [axis]: b[axis] };
|
|
536
|
-
legs.push({ axis, from: cursor, to, length: Math.abs(delta[axis]) });
|
|
537
|
-
cursor = to;
|
|
538
|
-
}
|
|
539
|
-
return legs.length > 1 ? legs : [];
|
|
540
|
-
}
|
|
541
|
-
function angleArc(vertex, a, b, radius, segments = ANGLE_ARC_SEGMENTS) {
|
|
542
|
-
const v = new Vector33(vertex.x, vertex.y, vertex.z);
|
|
543
|
-
const u = new Vector33(a.x, a.y, a.z).sub(v);
|
|
544
|
-
const w = new Vector33(b.x, b.y, b.z).sub(v);
|
|
545
|
-
if (u.lengthSq() === 0 || w.lengthSq() === 0) return [];
|
|
546
|
-
u.normalize();
|
|
547
|
-
w.normalize();
|
|
548
|
-
const theta = u.angleTo(w);
|
|
549
|
-
const sine = Math.sin(theta);
|
|
550
|
-
if (sine < 1e-6) {
|
|
551
|
-
return [v.clone().addScaledVector(u, radius), v.clone().addScaledVector(w, radius)];
|
|
552
|
-
}
|
|
553
|
-
const points = [];
|
|
554
|
-
for (let i = 0; i <= segments; i += 1) {
|
|
555
|
-
const t = i / segments;
|
|
556
|
-
const direction = u.clone().multiplyScalar(Math.sin((1 - t) * theta) / sine).addScaledVector(w, Math.sin(t * theta) / sine);
|
|
557
|
-
points.push(v.clone().addScaledVector(direction, radius));
|
|
558
|
-
}
|
|
559
|
-
return points;
|
|
560
|
-
}
|
|
561
|
-
function angleArcRadius(vertex, a, b) {
|
|
562
|
-
return Math.min(distanceBetween(vertex, a), distanceBetween(vertex, b)) * ANGLE_ARC_FRACTION;
|
|
563
|
-
}
|
|
564
|
-
function formatMillimetres(mm, digits = 2) {
|
|
565
|
-
return `${mm.toFixed(digits)} mm`;
|
|
566
|
-
}
|
|
567
|
-
function formatDegrees(degrees, digits = 1) {
|
|
568
|
-
return `${degrees.toFixed(digits)}\xB0`;
|
|
569
|
-
}
|
|
570
|
-
function measurementLabel(measurement, format = formatMillimetres) {
|
|
571
|
-
if (measurement.kind === "distance") {
|
|
572
|
-
const [a2, b2] = measurement.points;
|
|
573
|
-
return format(distanceBetween(a2, b2));
|
|
574
|
-
}
|
|
575
|
-
const [a, vertex, b] = measurement.points;
|
|
576
|
-
return formatDegrees(angleAt(vertex, a, b));
|
|
577
|
-
}
|
|
578
|
-
function measurementLabelAnchor(measurement) {
|
|
579
|
-
if (measurement.kind === "distance") return midpoint(measurement.points[0], measurement.points[1]);
|
|
580
|
-
const [a, vertex, b] = measurement.points;
|
|
581
|
-
const arc = angleArc(vertex, a, b, angleArcRadius(vertex, a, b) * 1.6, 2);
|
|
582
|
-
const middle = arc[1] ?? arc[0];
|
|
583
|
-
return middle ? { x: middle.x, y: middle.y, z: middle.z } : copy(vertex);
|
|
584
|
-
}
|
|
585
|
-
function copy(v) {
|
|
586
|
-
return { x: v.x, y: v.y, z: v.z };
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
// src/section-tool.tsx
|
|
590
|
-
import { Fragment, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
591
|
-
var FURNITURE3 = { [EXCLUDE_FROM_FRAME]: true };
|
|
592
|
-
var Z = new Vector34(0, 0, 1);
|
|
902
|
+
import { Fragment, jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
903
|
+
var FURNITURE4 = { [EXCLUDE_FROM_FRAME]: true };
|
|
904
|
+
var Z = new Vector36(0, 0, 1);
|
|
593
905
|
var AXIS_ROTATIONS = {
|
|
594
906
|
x: [0, Math.PI / 2, 0],
|
|
595
907
|
y: [Math.PI / 2, 0, 0],
|
|
@@ -601,12 +913,12 @@ var SectionTool = ({ theme }) => {
|
|
|
601
913
|
const store = useSectionStore();
|
|
602
914
|
const section = useSyncExternalStore(store.subscribe, store.get, store.get);
|
|
603
915
|
const box = useContentBox();
|
|
604
|
-
const resolved =
|
|
605
|
-
|
|
916
|
+
const resolved = useMemo5(() => resolveTheme(theme), [theme]);
|
|
917
|
+
useEffect4(() => {
|
|
606
918
|
store.setEngaged(true);
|
|
607
919
|
return () => store.setEngaged(false);
|
|
608
920
|
}, [store]);
|
|
609
|
-
|
|
921
|
+
useEffect4(() => {
|
|
610
922
|
if (!section) return void 0;
|
|
611
923
|
const clear = (event) => {
|
|
612
924
|
if (event.key === "Escape") store.set(null);
|
|
@@ -615,43 +927,43 @@ var SectionTool = ({ theme }) => {
|
|
|
615
927
|
return () => window.removeEventListener("keydown", clear);
|
|
616
928
|
}, [section, store]);
|
|
617
929
|
if (box.isEmpty()) return null;
|
|
618
|
-
return /* @__PURE__ */
|
|
930
|
+
return /* @__PURE__ */ jsx8("group", { userData: FURNITURE4, children: section ? /* @__PURE__ */ jsx8(CutSheet, { box, section, theme: resolved }) : /* @__PURE__ */ jsx8(Picker, { box, theme: resolved }) });
|
|
619
931
|
};
|
|
620
932
|
var useSquare = () => {
|
|
621
|
-
const square =
|
|
933
|
+
const square = useMemo5(
|
|
622
934
|
() => new BufferGeometry2().setFromPoints([
|
|
623
|
-
new
|
|
624
|
-
new
|
|
625
|
-
new
|
|
626
|
-
new
|
|
935
|
+
new Vector36(-1, 1, 0),
|
|
936
|
+
new Vector36(1, 1, 0),
|
|
937
|
+
new Vector36(1, -1, 0),
|
|
938
|
+
new Vector36(-1, -1, 0)
|
|
627
939
|
]),
|
|
628
940
|
[]
|
|
629
941
|
);
|
|
630
|
-
|
|
942
|
+
useEffect4(() => () => square.dispose(), [square]);
|
|
631
943
|
return square;
|
|
632
944
|
};
|
|
633
945
|
var Picker = ({ box, theme }) => {
|
|
634
946
|
const store = useSectionStore();
|
|
635
|
-
const camera =
|
|
636
|
-
const scene =
|
|
637
|
-
const domElement =
|
|
638
|
-
const invalidate =
|
|
947
|
+
const camera = useThree5((state) => state.camera);
|
|
948
|
+
const scene = useThree5((state) => state.scene);
|
|
949
|
+
const domElement = useThree5((state) => state.gl.domElement);
|
|
950
|
+
const invalidate = useThree5((state) => state.invalidate);
|
|
639
951
|
const isTap = useTapGuard();
|
|
640
952
|
const square = useSquare();
|
|
641
|
-
const previewRef =
|
|
642
|
-
const hover =
|
|
643
|
-
const [hoveredPlane, setHoveredPlane] =
|
|
644
|
-
const span =
|
|
645
|
-
const centre =
|
|
953
|
+
const previewRef = useRef3(null);
|
|
954
|
+
const hover = useRef3(null);
|
|
955
|
+
const [hoveredPlane, setHoveredPlane] = useState3(null);
|
|
956
|
+
const span = useMemo5(() => box.getSize(new Vector36()).length(), [box]);
|
|
957
|
+
const centre = useMemo5(() => box.getCenter(new Vector36()), [box]);
|
|
646
958
|
const previewSize = span * PREVIEW_SCALE;
|
|
647
|
-
|
|
959
|
+
useEffect4(() => {
|
|
648
960
|
store.setPicking(true);
|
|
649
961
|
return () => store.setPicking(false);
|
|
650
962
|
}, [store]);
|
|
651
|
-
|
|
963
|
+
useEffect4(() => {
|
|
652
964
|
const raycaster = new Raycaster();
|
|
653
|
-
const pointer = new
|
|
654
|
-
const aim = new
|
|
965
|
+
const pointer = new Vector2();
|
|
966
|
+
const aim = new Vector36();
|
|
655
967
|
const hide = () => {
|
|
656
968
|
if (!hover.current) return;
|
|
657
969
|
hover.current = null;
|
|
@@ -678,6 +990,7 @@ var Picker = ({ box, theme }) => {
|
|
|
678
990
|
invalidate();
|
|
679
991
|
};
|
|
680
992
|
const up = (event) => {
|
|
993
|
+
move(event);
|
|
681
994
|
const hit = hover.current;
|
|
682
995
|
if (event.button !== 0 || !hit || !isTap(event)) return;
|
|
683
996
|
store.set({
|
|
@@ -695,7 +1008,7 @@ var Picker = ({ box, theme }) => {
|
|
|
695
1008
|
domElement.removeEventListener("pointerup", up);
|
|
696
1009
|
};
|
|
697
1010
|
}, [box, camera, domElement, invalidate, isTap, scene, span, store]);
|
|
698
|
-
const [planes, setPlanes] =
|
|
1011
|
+
const [planes, setPlanes] = useState3(() => axesPlanes(box, camera.position));
|
|
699
1012
|
const key = planes.map((plane) => plane.sign).join();
|
|
700
1013
|
useFrame(() => {
|
|
701
1014
|
const next = [camera.position.x, camera.position.y, camera.position.z].map((eye, axis) => eye - [centre.x, centre.y, centre.z][axis] < 0 ? -1 : 1).join();
|
|
@@ -721,11 +1034,11 @@ var Picker = ({ box, theme }) => {
|
|
|
721
1034
|
store.set(plane.options);
|
|
722
1035
|
}
|
|
723
1036
|
});
|
|
724
|
-
return /* @__PURE__ */
|
|
725
|
-
/* @__PURE__ */
|
|
726
|
-
/* @__PURE__ */
|
|
727
|
-
/* @__PURE__ */
|
|
728
|
-
/* @__PURE__ */
|
|
1037
|
+
return /* @__PURE__ */ jsxs4(Fragment, { children: [
|
|
1038
|
+
/* @__PURE__ */ jsxs4("group", { ref: previewRef, visible: false, children: [
|
|
1039
|
+
/* @__PURE__ */ jsxs4("mesh", { renderOrder: SECTION_RENDER_ORDER.outline, raycast: () => null, children: [
|
|
1040
|
+
/* @__PURE__ */ jsx8("planeGeometry", { args: [previewSize, previewSize] }),
|
|
1041
|
+
/* @__PURE__ */ jsx8(
|
|
729
1042
|
"meshBasicMaterial",
|
|
730
1043
|
{
|
|
731
1044
|
color: theme.sectionOutline,
|
|
@@ -736,14 +1049,14 @@ var Picker = ({ box, theme }) => {
|
|
|
736
1049
|
}
|
|
737
1050
|
)
|
|
738
1051
|
] }),
|
|
739
|
-
/* @__PURE__ */
|
|
1052
|
+
/* @__PURE__ */ jsx8(
|
|
740
1053
|
"lineLoop",
|
|
741
1054
|
{
|
|
742
1055
|
geometry: square,
|
|
743
1056
|
scale: previewSize / 2,
|
|
744
1057
|
renderOrder: SECTION_RENDER_ORDER.outline,
|
|
745
1058
|
raycast: () => null,
|
|
746
|
-
children: /* @__PURE__ */
|
|
1059
|
+
children: /* @__PURE__ */ jsx8(
|
|
747
1060
|
"lineBasicMaterial",
|
|
748
1061
|
{
|
|
749
1062
|
color: theme.sectionOutline,
|
|
@@ -756,15 +1069,15 @@ var Picker = ({ box, theme }) => {
|
|
|
756
1069
|
}
|
|
757
1070
|
)
|
|
758
1071
|
] }),
|
|
759
|
-
planes.map((plane) => /* @__PURE__ */
|
|
1072
|
+
planes.map((plane) => /* @__PURE__ */ jsxs4(
|
|
760
1073
|
"group",
|
|
761
1074
|
{
|
|
762
1075
|
position: [plane.position.x, plane.position.y, plane.position.z],
|
|
763
1076
|
rotation: AXIS_ROTATIONS[plane.axis],
|
|
764
1077
|
children: [
|
|
765
|
-
/* @__PURE__ */
|
|
766
|
-
/* @__PURE__ */
|
|
767
|
-
/* @__PURE__ */
|
|
1078
|
+
/* @__PURE__ */ jsxs4("mesh", { renderOrder: SECTION_RENDER_ORDER.outline, ...planeHandlers(plane), children: [
|
|
1079
|
+
/* @__PURE__ */ jsx8("planeGeometry", { args: [plane.size, plane.size] }),
|
|
1080
|
+
/* @__PURE__ */ jsx8(
|
|
768
1081
|
"meshBasicMaterial",
|
|
769
1082
|
{
|
|
770
1083
|
color: AXIS_COLORS[plane.axis],
|
|
@@ -775,14 +1088,14 @@ var Picker = ({ box, theme }) => {
|
|
|
775
1088
|
}
|
|
776
1089
|
)
|
|
777
1090
|
] }),
|
|
778
|
-
/* @__PURE__ */
|
|
1091
|
+
/* @__PURE__ */ jsx8(
|
|
779
1092
|
"lineLoop",
|
|
780
1093
|
{
|
|
781
1094
|
geometry: square,
|
|
782
1095
|
scale: plane.size / 2,
|
|
783
1096
|
renderOrder: SECTION_RENDER_ORDER.outline,
|
|
784
1097
|
raycast: () => null,
|
|
785
|
-
children: /* @__PURE__ */
|
|
1098
|
+
children: /* @__PURE__ */ jsx8("lineBasicMaterial", { color: AXIS_COLORS[plane.axis], transparent: true, opacity: 0.7 })
|
|
786
1099
|
}
|
|
787
1100
|
)
|
|
788
1101
|
]
|
|
@@ -793,9 +1106,9 @@ var Picker = ({ box, theme }) => {
|
|
|
793
1106
|
};
|
|
794
1107
|
var CutSheet = ({ box, section, theme }) => {
|
|
795
1108
|
const square = useSquare();
|
|
796
|
-
const cut =
|
|
797
|
-
const span =
|
|
798
|
-
const placement =
|
|
1109
|
+
const cut = useMemo5(() => resolveSectionPlane(section, box), [box, section]);
|
|
1110
|
+
const span = useMemo5(() => box.getSize(new Vector36()).length(), [box]);
|
|
1111
|
+
const placement = useMemo5(() => {
|
|
799
1112
|
if (!cut) return null;
|
|
800
1113
|
const position = sectionAnchor(box, cut.plane).addScaledVector(
|
|
801
1114
|
cut.plane.normal,
|
|
@@ -805,10 +1118,10 @@ var CutSheet = ({ box, section, theme }) => {
|
|
|
805
1118
|
}, [box, cut, span]);
|
|
806
1119
|
if (!placement) return null;
|
|
807
1120
|
const size = span * OUTLINE_SCALE;
|
|
808
|
-
return /* @__PURE__ */
|
|
809
|
-
/* @__PURE__ */
|
|
810
|
-
/* @__PURE__ */
|
|
811
|
-
/* @__PURE__ */
|
|
1121
|
+
return /* @__PURE__ */ jsxs4("group", { position: placement.position, quaternion: placement.quaternion, children: [
|
|
1122
|
+
/* @__PURE__ */ jsxs4("mesh", { renderOrder: SECTION_RENDER_ORDER.outline, raycast: () => null, children: [
|
|
1123
|
+
/* @__PURE__ */ jsx8("planeGeometry", { args: [size, size] }),
|
|
1124
|
+
/* @__PURE__ */ jsx8(
|
|
812
1125
|
"meshBasicMaterial",
|
|
813
1126
|
{
|
|
814
1127
|
color: theme.sectionOutline,
|
|
@@ -819,14 +1132,14 @@ var CutSheet = ({ box, section, theme }) => {
|
|
|
819
1132
|
}
|
|
820
1133
|
)
|
|
821
1134
|
] }),
|
|
822
|
-
/* @__PURE__ */
|
|
1135
|
+
/* @__PURE__ */ jsx8(
|
|
823
1136
|
"lineLoop",
|
|
824
1137
|
{
|
|
825
1138
|
geometry: square,
|
|
826
1139
|
scale: size / 2,
|
|
827
1140
|
renderOrder: SECTION_RENDER_ORDER.outline,
|
|
828
1141
|
raycast: () => null,
|
|
829
|
-
children: /* @__PURE__ */
|
|
1142
|
+
children: /* @__PURE__ */ jsx8(
|
|
830
1143
|
"lineBasicMaterial",
|
|
831
1144
|
{
|
|
832
1145
|
color: theme.sectionOutline,
|
|
@@ -843,32 +1156,32 @@ var CutSheet = ({ box, section, theme }) => {
|
|
|
843
1156
|
|
|
844
1157
|
// src/measure-tool.tsx
|
|
845
1158
|
import { Html, Line } from "@react-three/drei";
|
|
846
|
-
import { useFrame as useFrame2, useThree as
|
|
1159
|
+
import { useFrame as useFrame2, useThree as useThree6 } from "@react-three/fiber";
|
|
847
1160
|
import {
|
|
848
|
-
useEffect as
|
|
849
|
-
useLayoutEffect,
|
|
850
|
-
useMemo as
|
|
851
|
-
useRef as
|
|
852
|
-
useState as
|
|
1161
|
+
useEffect as useEffect5,
|
|
1162
|
+
useLayoutEffect as useLayoutEffect3,
|
|
1163
|
+
useMemo as useMemo6,
|
|
1164
|
+
useRef as useRef4,
|
|
1165
|
+
useState as useState4,
|
|
853
1166
|
useSyncExternalStore as useSyncExternalStore2
|
|
854
1167
|
} from "react";
|
|
855
1168
|
import {
|
|
856
1169
|
Matrix4,
|
|
857
1170
|
Raycaster as Raycaster2,
|
|
858
1171
|
SphereGeometry,
|
|
859
|
-
Vector2 as
|
|
860
|
-
Vector3 as
|
|
1172
|
+
Vector2 as Vector22,
|
|
1173
|
+
Vector3 as Vector38
|
|
861
1174
|
} from "three";
|
|
862
1175
|
|
|
863
1176
|
// src/render/resample.ts
|
|
864
|
-
import { Vector3 as
|
|
1177
|
+
import { Vector3 as Vector37 } from "three";
|
|
865
1178
|
var ON_PLANE = 1e-7;
|
|
866
1179
|
var STITCH = 1e-5;
|
|
867
1180
|
var COLLINEAR = 1e-6;
|
|
868
1181
|
function clipSegments(positions, plane) {
|
|
869
1182
|
const out = [];
|
|
870
|
-
const a = new
|
|
871
|
-
const b = new
|
|
1183
|
+
const a = new Vector37();
|
|
1184
|
+
const b = new Vector37();
|
|
872
1185
|
const count = Math.floor(positions.length / 6);
|
|
873
1186
|
for (let i = 0; i < count; i += 1) {
|
|
874
1187
|
a.set(positions[i * 6], positions[i * 6 + 1], positions[i * 6 + 2]);
|
|
@@ -883,11 +1196,11 @@ function clipSegments(positions, plane) {
|
|
|
883
1196
|
return Float32Array.from(out);
|
|
884
1197
|
}
|
|
885
1198
|
function sectionContour(positions, regionOf, plane) {
|
|
886
|
-
const a = new
|
|
887
|
-
const b = new
|
|
888
|
-
const c = new
|
|
889
|
-
const p = new
|
|
890
|
-
const q = new
|
|
1199
|
+
const a = new Vector37();
|
|
1200
|
+
const b = new Vector37();
|
|
1201
|
+
const c = new Vector37();
|
|
1202
|
+
const p = new Vector37();
|
|
1203
|
+
const q = new Vector37();
|
|
891
1204
|
const byRegion = /* @__PURE__ */ new Map();
|
|
892
1205
|
const triangleCount = Math.floor(positions.length / 9);
|
|
893
1206
|
for (let t = 0; t < triangleCount; t += 1) {
|
|
@@ -945,17 +1258,17 @@ function stitch(segments, out) {
|
|
|
945
1258
|
return into.set(segments[o], segments[o + 1], segments[o + 2]);
|
|
946
1259
|
};
|
|
947
1260
|
const direction = (i, into) => {
|
|
948
|
-
const s = new
|
|
949
|
-
const e = new
|
|
1261
|
+
const s = new Vector37();
|
|
1262
|
+
const e = new Vector37();
|
|
950
1263
|
point(i, 0, s);
|
|
951
1264
|
point(i, 1, e);
|
|
952
1265
|
return into.subVectors(e, s).normalize();
|
|
953
1266
|
};
|
|
954
1267
|
const consumed = new Uint8Array(count);
|
|
955
|
-
const d = new
|
|
956
|
-
const n = new
|
|
1268
|
+
const d = new Vector37();
|
|
1269
|
+
const n = new Vector37();
|
|
957
1270
|
const next = (i, end) => {
|
|
958
|
-
const at = point(i, end, new
|
|
1271
|
+
const at = point(i, end, new Vector37());
|
|
959
1272
|
const list = ends.get(key(at.x, at.y, at.z)) ?? [];
|
|
960
1273
|
if (list.length !== 2) return null;
|
|
961
1274
|
const other = list.find((entry) => entry >> 1 !== i);
|
|
@@ -984,8 +1297,8 @@ function stitch(segments, out) {
|
|
|
984
1297
|
};
|
|
985
1298
|
const back = walk(0);
|
|
986
1299
|
const forward = walk(1);
|
|
987
|
-
const s = point(back.index, back.end, new
|
|
988
|
-
const e = point(forward.index, forward.end, new
|
|
1300
|
+
const s = point(back.index, back.end, new Vector37());
|
|
1301
|
+
const e = point(forward.index, forward.end, new Vector37());
|
|
989
1302
|
out.push(s.x, s.y, s.z, e.x, e.y, e.z);
|
|
990
1303
|
}
|
|
991
1304
|
}
|
|
@@ -993,8 +1306,8 @@ function pointInContour(point, plane, contour) {
|
|
|
993
1306
|
const [u, v] = planeAxes(plane);
|
|
994
1307
|
const px = point.dot(u);
|
|
995
1308
|
const py = point.dot(v);
|
|
996
|
-
const a = new
|
|
997
|
-
const b = new
|
|
1309
|
+
const a = new Vector37();
|
|
1310
|
+
const b = new Vector37();
|
|
998
1311
|
let inside = false;
|
|
999
1312
|
const count = Math.floor(contour.length / 6);
|
|
1000
1313
|
for (let i = 0; i < count; i += 1) {
|
|
@@ -1011,15 +1324,15 @@ function pointInContour(point, plane, contour) {
|
|
|
1011
1324
|
return inside;
|
|
1012
1325
|
}
|
|
1013
1326
|
function capHit(ray, plane, contour) {
|
|
1014
|
-
const point = ray.intersectPlane(plane, new
|
|
1327
|
+
const point = ray.intersectPlane(plane, new Vector37());
|
|
1015
1328
|
if (!point) return null;
|
|
1016
1329
|
return pointInContour(point, plane, contour) ? point : null;
|
|
1017
1330
|
}
|
|
1018
1331
|
function planeAxes(plane) {
|
|
1019
1332
|
const n = plane.normal;
|
|
1020
|
-
const seed = Math.abs(n.x) < 0.9 ? new
|
|
1021
|
-
const u = new
|
|
1022
|
-
const v = new
|
|
1333
|
+
const seed = Math.abs(n.x) < 0.9 ? new Vector37(1, 0, 0) : new Vector37(0, 1, 0);
|
|
1334
|
+
const u = new Vector37().crossVectors(n, seed).normalize();
|
|
1335
|
+
const v = new Vector37().crossVectors(n, u).normalize();
|
|
1023
1336
|
return [u, v];
|
|
1024
1337
|
}
|
|
1025
1338
|
function sampleSection(meshPositions, regionOf, edgePositions, plane) {
|
|
@@ -1032,8 +1345,8 @@ function sampleSection(meshPositions, regionOf, edgePositions, plane) {
|
|
|
1032
1345
|
}
|
|
1033
1346
|
|
|
1034
1347
|
// src/measure-tool.tsx
|
|
1035
|
-
import { Fragment as Fragment2, jsx as
|
|
1036
|
-
var
|
|
1348
|
+
import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1349
|
+
var FURNITURE5 = { [EXCLUDE_FROM_FRAME]: true };
|
|
1037
1350
|
var MEASURE_LABEL_CLASS = "toolpath-measure-label";
|
|
1038
1351
|
var MeasureTool = ({
|
|
1039
1352
|
mode = "distance",
|
|
@@ -1046,26 +1359,26 @@ var MeasureTool = ({
|
|
|
1046
1359
|
}) => {
|
|
1047
1360
|
const store = useSectionStore();
|
|
1048
1361
|
const box = useContentBox();
|
|
1049
|
-
const resolved =
|
|
1362
|
+
const resolved = useMemo6(() => resolveTheme(theme), [theme]);
|
|
1050
1363
|
const picking = useSyncExternalStore2(store.subscribe, store.isPicking, store.isPicking);
|
|
1051
|
-
const [held, setHeld] =
|
|
1364
|
+
const [held, setHeld] = useState4([]);
|
|
1052
1365
|
const controlled = measurements !== void 0;
|
|
1053
1366
|
const list = controlled ? measurements : held;
|
|
1054
|
-
const [draft, setDraft] =
|
|
1055
|
-
|
|
1367
|
+
const [draft, setDraft] = useState4([]);
|
|
1368
|
+
useEffect5(() => {
|
|
1056
1369
|
store.setEngaged(true);
|
|
1057
1370
|
return () => store.setEngaged(false);
|
|
1058
1371
|
}, [store]);
|
|
1059
|
-
|
|
1372
|
+
useEffect5(() => {
|
|
1060
1373
|
setDraft([]);
|
|
1061
1374
|
}, [mode]);
|
|
1062
1375
|
const commit = (next) => {
|
|
1063
1376
|
if (!controlled) setHeld(next);
|
|
1064
1377
|
onChange?.(next);
|
|
1065
1378
|
};
|
|
1066
|
-
const latest =
|
|
1379
|
+
const latest = useRef4({ list, commit });
|
|
1067
1380
|
latest.current = { list, commit };
|
|
1068
|
-
|
|
1381
|
+
useEffect5(() => {
|
|
1069
1382
|
const onKey = (event) => {
|
|
1070
1383
|
if (event.key === "Escape") {
|
|
1071
1384
|
setDraft([]);
|
|
@@ -1093,8 +1406,8 @@ var MeasureTool = ({
|
|
|
1093
1406
|
};
|
|
1094
1407
|
if (box.isEmpty()) return null;
|
|
1095
1408
|
const label = className(labelClassName);
|
|
1096
|
-
return /* @__PURE__ */
|
|
1097
|
-
picking ? null : /* @__PURE__ */
|
|
1409
|
+
return /* @__PURE__ */ jsxs5("group", { userData: FURNITURE5, children: [
|
|
1410
|
+
picking ? null : /* @__PURE__ */ jsx9(
|
|
1098
1411
|
Snapper,
|
|
1099
1412
|
{
|
|
1100
1413
|
mode,
|
|
@@ -1105,7 +1418,7 @@ var MeasureTool = ({
|
|
|
1105
1418
|
label
|
|
1106
1419
|
}
|
|
1107
1420
|
),
|
|
1108
|
-
draft.map((point, index) => /* @__PURE__ */
|
|
1421
|
+
draft.map((point, index) => /* @__PURE__ */ jsx9(
|
|
1109
1422
|
ScreenDot,
|
|
1110
1423
|
{
|
|
1111
1424
|
point,
|
|
@@ -1114,8 +1427,8 @@ var MeasureTool = ({
|
|
|
1114
1427
|
},
|
|
1115
1428
|
index
|
|
1116
1429
|
)),
|
|
1117
|
-
draft.length === 2 ? /* @__PURE__ */
|
|
1118
|
-
list.map((measurement) => /* @__PURE__ */
|
|
1430
|
+
draft.length === 2 ? /* @__PURE__ */ jsx9(Segment, { points: [draft[0], draft[1]], color: resolved.measure }) : null,
|
|
1431
|
+
list.map((measurement) => /* @__PURE__ */ jsx9(
|
|
1119
1432
|
MeasurementView,
|
|
1120
1433
|
{
|
|
1121
1434
|
measurement,
|
|
@@ -1129,30 +1442,30 @@ var MeasureTool = ({
|
|
|
1129
1442
|
] });
|
|
1130
1443
|
};
|
|
1131
1444
|
var NO_POINTER = { pointerEvents: "none" };
|
|
1132
|
-
var NOWHERE = [new
|
|
1445
|
+
var NOWHERE = [new Vector38(), new Vector38()];
|
|
1133
1446
|
var Snapper = ({ mode, draft, onPlace, theme, format, label }) => {
|
|
1134
|
-
const camera =
|
|
1135
|
-
const scene =
|
|
1136
|
-
const size =
|
|
1137
|
-
const domElement =
|
|
1138
|
-
const invalidate =
|
|
1447
|
+
const camera = useThree6((state) => state.camera);
|
|
1448
|
+
const scene = useThree6((state) => state.scene);
|
|
1449
|
+
const size = useThree6((state) => state.size);
|
|
1450
|
+
const domElement = useThree6((state) => state.gl.domElement);
|
|
1451
|
+
const invalidate = useThree6((state) => state.invalidate);
|
|
1139
1452
|
const isTap = useTapGuard();
|
|
1140
|
-
const marker =
|
|
1141
|
-
const edgeLine =
|
|
1142
|
-
const band =
|
|
1143
|
-
const bandLabel =
|
|
1144
|
-
const bandText =
|
|
1145
|
-
const snap =
|
|
1453
|
+
const marker = useRef4(null);
|
|
1454
|
+
const edgeLine = useRef4(null);
|
|
1455
|
+
const band = useRef4(null);
|
|
1456
|
+
const bandLabel = useRef4(null);
|
|
1457
|
+
const bandText = useRef4(null);
|
|
1458
|
+
const snap = useRef4(null);
|
|
1146
1459
|
const dot = useDot();
|
|
1147
|
-
|
|
1460
|
+
useLayoutEffect3(() => {
|
|
1148
1461
|
if (edgeLine.current) edgeLine.current.visible = false;
|
|
1149
1462
|
if (band.current) band.current.visible = false;
|
|
1150
1463
|
}, []);
|
|
1151
|
-
const current =
|
|
1464
|
+
const current = useRef4({ mode, draft, onPlace, format, size });
|
|
1152
1465
|
current.current = { mode, draft, onPlace, format, size };
|
|
1153
|
-
|
|
1466
|
+
useEffect5(() => {
|
|
1154
1467
|
const raycaster = new Raycaster2();
|
|
1155
|
-
const pointer = new
|
|
1468
|
+
const pointer = new Vector22();
|
|
1156
1469
|
const samples = new SampleCache();
|
|
1157
1470
|
const hide = () => {
|
|
1158
1471
|
if (!snap.current) return;
|
|
@@ -1182,7 +1495,7 @@ var Snapper = ({ mode, draft, onPlace, theme, format, label }) => {
|
|
|
1182
1495
|
const snapped = snapAt(target, target.edges, camera, viewport);
|
|
1183
1496
|
const from = placed[placed.length - 1];
|
|
1184
1497
|
const lock = shift && from ? lockToAxis(from, snapped.point) : null;
|
|
1185
|
-
const found = lock ? { ...snapped, point: new
|
|
1498
|
+
const found = lock ? { ...snapped, point: new Vector38(lock.point.x, lock.point.y, lock.point.z), edge: null } : snapped;
|
|
1186
1499
|
snap.current = found;
|
|
1187
1500
|
const node = marker.current;
|
|
1188
1501
|
if (node) {
|
|
@@ -1256,7 +1569,7 @@ var Snapper = ({ mode, draft, onPlace, theme, format, label }) => {
|
|
|
1256
1569
|
window.removeEventListener("keyup", key);
|
|
1257
1570
|
};
|
|
1258
1571
|
}, [camera, domElement, invalidate, isTap, scene, theme.measure]);
|
|
1259
|
-
|
|
1572
|
+
useEffect5(() => {
|
|
1260
1573
|
if (draft.length === 0 && band.current) {
|
|
1261
1574
|
band.current.visible = false;
|
|
1262
1575
|
if (bandLabel.current) bandLabel.current.visible = false;
|
|
@@ -1267,9 +1580,9 @@ var Snapper = ({ mode, draft, onPlace, theme, format, label }) => {
|
|
|
1267
1580
|
invalidate();
|
|
1268
1581
|
}
|
|
1269
1582
|
}, [draft, invalidate]);
|
|
1270
|
-
return /* @__PURE__ */
|
|
1271
|
-
/* @__PURE__ */
|
|
1272
|
-
/* @__PURE__ */
|
|
1583
|
+
return /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
1584
|
+
/* @__PURE__ */ jsx9("group", { ref: marker, visible: false, children: /* @__PURE__ */ jsx9("mesh", { geometry: dot, renderOrder: MEASURE_RENDER_ORDER, raycast: () => null, children: /* @__PURE__ */ jsx9("meshBasicMaterial", { color: theme.measureSnap, depthTest: false, depthWrite: false }) }) }),
|
|
1585
|
+
/* @__PURE__ */ jsx9(
|
|
1273
1586
|
Line,
|
|
1274
1587
|
{
|
|
1275
1588
|
ref: edgeLine,
|
|
@@ -1283,7 +1596,7 @@ var Snapper = ({ mode, draft, onPlace, theme, format, label }) => {
|
|
|
1283
1596
|
raycast: () => null
|
|
1284
1597
|
}
|
|
1285
1598
|
),
|
|
1286
|
-
/* @__PURE__ */
|
|
1599
|
+
/* @__PURE__ */ jsx9(
|
|
1287
1600
|
Line,
|
|
1288
1601
|
{
|
|
1289
1602
|
ref: band,
|
|
@@ -1297,7 +1610,7 @@ var Snapper = ({ mode, draft, onPlace, theme, format, label }) => {
|
|
|
1297
1610
|
raycast: () => null
|
|
1298
1611
|
}
|
|
1299
1612
|
),
|
|
1300
|
-
/* @__PURE__ */
|
|
1613
|
+
/* @__PURE__ */ jsx9("group", { ref: bandLabel, visible: false, children: /* @__PURE__ */ jsx9(Html, { center: true, zIndexRange: [0, 0], style: NO_POINTER, children: /* @__PURE__ */ jsx9(
|
|
1301
1614
|
"div",
|
|
1302
1615
|
{
|
|
1303
1616
|
ref: bandText,
|
|
@@ -1462,35 +1775,35 @@ var MeasurementView = ({
|
|
|
1462
1775
|
const anchor = measurementLabelAnchor(measurement);
|
|
1463
1776
|
if (measurement.kind === "distance") {
|
|
1464
1777
|
const [a2, b2] = measurement.points;
|
|
1465
|
-
return /* @__PURE__ */
|
|
1466
|
-
/* @__PURE__ */
|
|
1467
|
-
/* @__PURE__ */
|
|
1468
|
-
/* @__PURE__ */
|
|
1469
|
-
showDeltas ? /* @__PURE__ */
|
|
1470
|
-
/* @__PURE__ */
|
|
1778
|
+
return /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
1779
|
+
/* @__PURE__ */ jsx9(Segment, { points: [a2, b2], color: theme.measure }),
|
|
1780
|
+
/* @__PURE__ */ jsx9(ScreenDot, { point: a2, pixels: MEASURE_MARKER_PIXELS, color: theme.measure }),
|
|
1781
|
+
/* @__PURE__ */ jsx9(ScreenDot, { point: b2, pixels: MEASURE_MARKER_PIXELS, color: theme.measure }),
|
|
1782
|
+
showDeltas ? /* @__PURE__ */ jsx9(DeltaLegs, { a: a2, b: b2, id: measurement.id, format, label }) : null,
|
|
1783
|
+
/* @__PURE__ */ jsx9(Label, { at: anchor, text, kind: "distance", id: measurement.id, className: label })
|
|
1471
1784
|
] });
|
|
1472
1785
|
}
|
|
1473
1786
|
const [a, vertex, b] = measurement.points;
|
|
1474
1787
|
const arc = angleArc(vertex, a, b, angleArcRadius(vertex, a, b));
|
|
1475
|
-
return /* @__PURE__ */
|
|
1476
|
-
/* @__PURE__ */
|
|
1477
|
-
/* @__PURE__ */
|
|
1478
|
-
/* @__PURE__ */
|
|
1479
|
-
/* @__PURE__ */
|
|
1480
|
-
/* @__PURE__ */
|
|
1481
|
-
/* @__PURE__ */
|
|
1482
|
-
/* @__PURE__ */
|
|
1788
|
+
return /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
1789
|
+
/* @__PURE__ */ jsx9(Segment, { points: [vertex, a], color: theme.measure }),
|
|
1790
|
+
/* @__PURE__ */ jsx9(Segment, { points: [vertex, b], color: theme.measure }),
|
|
1791
|
+
/* @__PURE__ */ jsx9(Polyline, { points: arc, color: theme.measure }),
|
|
1792
|
+
/* @__PURE__ */ jsx9(ScreenDot, { point: a, pixels: MEASURE_MARKER_PIXELS, color: theme.measure }),
|
|
1793
|
+
/* @__PURE__ */ jsx9(ScreenDot, { point: vertex, pixels: MEASURE_MARKER_PIXELS, color: theme.measure }),
|
|
1794
|
+
/* @__PURE__ */ jsx9(ScreenDot, { point: b, pixels: MEASURE_MARKER_PIXELS, color: theme.measure }),
|
|
1795
|
+
/* @__PURE__ */ jsx9(Label, { at: anchor, text, kind: "angle", id: measurement.id, className: label })
|
|
1483
1796
|
] });
|
|
1484
1797
|
};
|
|
1485
1798
|
var DeltaLegs = ({ a, b, id, format, label }) => {
|
|
1486
|
-
const camera =
|
|
1487
|
-
const size =
|
|
1488
|
-
const invalidate =
|
|
1489
|
-
const legs =
|
|
1490
|
-
const lines =
|
|
1491
|
-
const centre =
|
|
1799
|
+
const camera = useThree6((state) => state.camera);
|
|
1800
|
+
const size = useThree6((state) => state.size);
|
|
1801
|
+
const invalidate = useThree6((state) => state.invalidate);
|
|
1802
|
+
const legs = useMemo6(() => deltaLegs(a, b), [a, b]);
|
|
1803
|
+
const lines = useRef4([]);
|
|
1804
|
+
const centre = useMemo6(() => {
|
|
1492
1805
|
const at = midpoint(a, b);
|
|
1493
|
-
return new
|
|
1806
|
+
return new Vector38(at.x, at.y, at.z);
|
|
1494
1807
|
}, [a, b]);
|
|
1495
1808
|
useFrame2(() => {
|
|
1496
1809
|
const dash = screenLength(camera, centre, size, DELTA_DASH_PIXELS);
|
|
@@ -1504,16 +1817,16 @@ var DeltaLegs = ({ a, b, id, format, label }) => {
|
|
|
1504
1817
|
}
|
|
1505
1818
|
if (changed) invalidate();
|
|
1506
1819
|
});
|
|
1507
|
-
return /* @__PURE__ */
|
|
1508
|
-
legs.map((leg, index) => /* @__PURE__ */
|
|
1820
|
+
return /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
1821
|
+
legs.map((leg, index) => /* @__PURE__ */ jsx9(
|
|
1509
1822
|
Line,
|
|
1510
1823
|
{
|
|
1511
1824
|
ref: (line) => {
|
|
1512
1825
|
lines.current[index] = line;
|
|
1513
1826
|
},
|
|
1514
1827
|
points: [
|
|
1515
|
-
new
|
|
1516
|
-
new
|
|
1828
|
+
new Vector38(leg.from.x, leg.from.y, leg.from.z),
|
|
1829
|
+
new Vector38(leg.to.x, leg.to.y, leg.to.z)
|
|
1517
1830
|
],
|
|
1518
1831
|
color: AXIS_COLORS[leg.axis],
|
|
1519
1832
|
lineWidth: MEASURE_LINE_PIXELS.leg,
|
|
@@ -1528,7 +1841,7 @@ var DeltaLegs = ({ a, b, id, format, label }) => {
|
|
|
1528
1841
|
},
|
|
1529
1842
|
leg.axis
|
|
1530
1843
|
)),
|
|
1531
|
-
legs.map((leg) => /* @__PURE__ */
|
|
1844
|
+
legs.map((leg) => /* @__PURE__ */ jsx9(
|
|
1532
1845
|
Label,
|
|
1533
1846
|
{
|
|
1534
1847
|
at: midpoint(leg.from, leg.to),
|
|
@@ -1542,14 +1855,14 @@ var DeltaLegs = ({ a, b, id, format, label }) => {
|
|
|
1542
1855
|
))
|
|
1543
1856
|
] });
|
|
1544
1857
|
};
|
|
1545
|
-
var Label = ({ at, text, kind, id, axis, className: name }) => /* @__PURE__ */
|
|
1858
|
+
var Label = ({ at, text, kind, id, axis, className: name }) => /* @__PURE__ */ jsx9("group", { position: [at.x, at.y, at.z], children: /* @__PURE__ */ jsx9(Html, { center: true, zIndexRange: [0, 0], style: NO_POINTER, children: /* @__PURE__ */ jsx9("div", { className: name, "data-measure-label": kind, "data-measurement-id": id, "data-axis": axis, children: text }) }) });
|
|
1546
1859
|
var ScreenDot = ({ point, pixels, color }) => {
|
|
1547
|
-
const camera =
|
|
1548
|
-
const size =
|
|
1549
|
-
const invalidate =
|
|
1550
|
-
const node =
|
|
1860
|
+
const camera = useThree6((state) => state.camera);
|
|
1861
|
+
const size = useThree6((state) => state.size);
|
|
1862
|
+
const invalidate = useThree6((state) => state.invalidate);
|
|
1863
|
+
const node = useRef4(null);
|
|
1551
1864
|
const dot = useDot();
|
|
1552
|
-
const position =
|
|
1865
|
+
const position = useMemo6(() => new Vector38(point.x, point.y, point.z), [point]);
|
|
1553
1866
|
useFrame2(() => {
|
|
1554
1867
|
const group = node.current;
|
|
1555
1868
|
if (!group) return;
|
|
@@ -1559,21 +1872,21 @@ var ScreenDot = ({ point, pixels, color }) => {
|
|
|
1559
1872
|
invalidate();
|
|
1560
1873
|
}
|
|
1561
1874
|
});
|
|
1562
|
-
return /* @__PURE__ */
|
|
1875
|
+
return /* @__PURE__ */ jsx9("group", { ref: node, position, children: /* @__PURE__ */ jsx9("mesh", { geometry: dot, renderOrder: MEASURE_RENDER_ORDER, raycast: () => null, children: /* @__PURE__ */ jsx9("meshBasicMaterial", { color, depthTest: false, depthWrite: false }) }) });
|
|
1563
1876
|
};
|
|
1564
1877
|
var Segment = ({ points, color }) => {
|
|
1565
1878
|
const [a, b] = points;
|
|
1566
|
-
const ends =
|
|
1567
|
-
() => [new
|
|
1879
|
+
const ends = useMemo6(
|
|
1880
|
+
() => [new Vector38(a.x, a.y, a.z), new Vector38(b.x, b.y, b.z)],
|
|
1568
1881
|
// Keyed on the numbers: a draft's tuple is a fresh array on every render,
|
|
1569
1882
|
// and a rebuilt array would rebuild the line's geometry with it.
|
|
1570
1883
|
[a.x, a.y, a.z, b.x, b.y, b.z]
|
|
1571
1884
|
);
|
|
1572
|
-
return /* @__PURE__ */
|
|
1885
|
+
return /* @__PURE__ */ jsx9(Polyline, { points: ends, color });
|
|
1573
1886
|
};
|
|
1574
1887
|
var Polyline = ({ points, color }) => {
|
|
1575
1888
|
if (points.length < 2) return null;
|
|
1576
|
-
return /* @__PURE__ */
|
|
1889
|
+
return /* @__PURE__ */ jsx9(
|
|
1577
1890
|
Line,
|
|
1578
1891
|
{
|
|
1579
1892
|
points,
|
|
@@ -1588,8 +1901,8 @@ var Polyline = ({ points, color }) => {
|
|
|
1588
1901
|
);
|
|
1589
1902
|
};
|
|
1590
1903
|
function useDot() {
|
|
1591
|
-
const geometry =
|
|
1592
|
-
|
|
1904
|
+
const geometry = useMemo6(() => new SphereGeometry(1, 16, 12), []);
|
|
1905
|
+
useEffect5(() => () => geometry.dispose(), [geometry]);
|
|
1593
1906
|
return geometry;
|
|
1594
1907
|
}
|
|
1595
1908
|
function isEditing(target) {
|
|
@@ -1640,10 +1953,15 @@ export {
|
|
|
1640
1953
|
AXES_PLANE_SCALE,
|
|
1641
1954
|
AXIS_COLORS,
|
|
1642
1955
|
Axes,
|
|
1956
|
+
BANANA_GAP,
|
|
1957
|
+
BANANA_MODEL_URL,
|
|
1958
|
+
Banana,
|
|
1959
|
+
BoxStock,
|
|
1643
1960
|
CAD_CAMERA_UP,
|
|
1644
1961
|
CANDIDATE_WEIGHT,
|
|
1645
1962
|
CAP_HATCH,
|
|
1646
1963
|
CHAMFER,
|
|
1964
|
+
CONTROL_SCHEME_OPTIONS,
|
|
1647
1965
|
CadCameraControls,
|
|
1648
1966
|
DEFAULT_FIT_MARGIN,
|
|
1649
1967
|
DEFAULT_SECTION_NORMAL,
|
|
@@ -1662,6 +1980,7 @@ export {
|
|
|
1662
1980
|
HIGHLIGHT_COLORS,
|
|
1663
1981
|
HIGHLIGHT_WEIGHT,
|
|
1664
1982
|
HOVER_WEIGHT,
|
|
1983
|
+
HoverCard,
|
|
1665
1984
|
MAX_FRAME_RATIO,
|
|
1666
1985
|
MEASURE_LABEL_CLASS,
|
|
1667
1986
|
MEASURE_LINE_PIXELS,
|
|
@@ -1686,17 +2005,21 @@ export {
|
|
|
1686
2005
|
PartMesh,
|
|
1687
2006
|
PartReportFormatError,
|
|
1688
2007
|
REGION_ATTRIBUTE,
|
|
2008
|
+
SECTION_GIZMO_FRAME_SCALE,
|
|
1689
2009
|
SECTION_RENDER_ORDER,
|
|
1690
2010
|
SNAP_MARKER_PIXELS,
|
|
1691
2011
|
SNAP_PIXELS,
|
|
1692
2012
|
SectionTool,
|
|
1693
2013
|
SectionView,
|
|
2014
|
+
Stock,
|
|
1694
2015
|
TAP_SLOP,
|
|
1695
2016
|
UnsupportedKernelVersionError,
|
|
1696
2017
|
VIEW_NAMES,
|
|
1697
2018
|
VIEW_SIGNS,
|
|
1698
2019
|
ViewCube,
|
|
1699
2020
|
Viewer,
|
|
2021
|
+
ViewerToolbar,
|
|
2022
|
+
ViewerToolbarProvider,
|
|
1700
2023
|
adaptedUp,
|
|
1701
2024
|
angleArc,
|
|
1702
2025
|
angleArcRadius,
|
|
@@ -1707,8 +2030,11 @@ export {
|
|
|
1707
2030
|
arrowPlacement,
|
|
1708
2031
|
aspectRatio,
|
|
1709
2032
|
axesPlanes,
|
|
2033
|
+
bananaFrameBounds,
|
|
2034
|
+
bananaPosition,
|
|
1710
2035
|
bestOwner,
|
|
1711
2036
|
boundsFromBox,
|
|
2037
|
+
boxStockBounds,
|
|
1712
2038
|
buildPick,
|
|
1713
2039
|
buildRegionAttribute,
|
|
1714
2040
|
buildRegionIndex,
|
|
@@ -1732,6 +2058,7 @@ export {
|
|
|
1732
2058
|
deltaBetween,
|
|
1733
2059
|
deltaLegs,
|
|
1734
2060
|
directionColor,
|
|
2061
|
+
directionHighlights,
|
|
1735
2062
|
directionIndexOf,
|
|
1736
2063
|
directionLabel,
|
|
1737
2064
|
distanceBetween,
|
|
@@ -1739,6 +2066,7 @@ export {
|
|
|
1739
2066
|
excludedFromFrame,
|
|
1740
2067
|
featureTypeRank,
|
|
1741
2068
|
fitDistance,
|
|
2069
|
+
fixedBoxStockBounds,
|
|
1742
2070
|
focusForPick,
|
|
1743
2071
|
formatDegrees,
|
|
1744
2072
|
formatMillimetres,
|
|
@@ -1781,6 +2109,7 @@ export {
|
|
|
1781
2109
|
sectionDepthConstant,
|
|
1782
2110
|
sectionDepthRange,
|
|
1783
2111
|
sectionFromPick,
|
|
2112
|
+
sectionMeasurement,
|
|
1784
2113
|
sectionOffset,
|
|
1785
2114
|
sectionOptionsFromState,
|
|
1786
2115
|
sectionPlane,
|
|
@@ -1798,6 +2127,7 @@ export {
|
|
|
1798
2127
|
useSectionStore,
|
|
1799
2128
|
useTapGuard,
|
|
1800
2129
|
useViewerControls,
|
|
2130
|
+
useViewerToolbar,
|
|
1801
2131
|
viewDirection,
|
|
1802
2132
|
viewKind,
|
|
1803
2133
|
viewUp,
|