@toolpath/viewer 2.2.1 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +110 -43
- package/dist/{chunk-7S6SIYHL.js → chunk-N54FHMTG.js} +753 -178
- package/dist/engine/index.d.ts +2 -2
- package/dist/engine/index.js +1 -1
- package/dist/index.d.ts +7 -205
- package/dist/index.js +290 -121
- package/dist/{normalize--FiXUhO4.d.ts → normalize-C4Wj4IGK.d.ts} +333 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -99,6 +99,7 @@ import {
|
|
|
99
99
|
dragPlane,
|
|
100
100
|
excludedFromFrame,
|
|
101
101
|
featureTypeRank,
|
|
102
|
+
findSharpCorners,
|
|
102
103
|
fitDistance,
|
|
103
104
|
focusForPick,
|
|
104
105
|
formatDegrees,
|
|
@@ -140,10 +141,12 @@ import {
|
|
|
140
141
|
sectionOffset,
|
|
141
142
|
sectionOptionsFromState,
|
|
142
143
|
sectionPlane,
|
|
144
|
+
sharpCornerPositions,
|
|
143
145
|
smoothRegionNormals,
|
|
144
146
|
snapAt,
|
|
145
147
|
squaredUp,
|
|
146
148
|
startPosition,
|
|
149
|
+
surfaceCreases,
|
|
147
150
|
surfaceUnderRay,
|
|
148
151
|
targetBoundary,
|
|
149
152
|
themesEqual,
|
|
@@ -160,7 +163,7 @@ import {
|
|
|
160
163
|
viewUp,
|
|
161
164
|
viewVector,
|
|
162
165
|
visualSurfaces
|
|
163
|
-
} from "./chunk-
|
|
166
|
+
} from "./chunk-N54FHMTG.js";
|
|
164
167
|
|
|
165
168
|
// src/render/feature-triangles.ts
|
|
166
169
|
var EMPTY = { positions: new Float32Array(), normals: new Float32Array() };
|
|
@@ -170,13 +173,13 @@ function featureTriangles(model, geometry, tag) {
|
|
|
170
173
|
const normal = geometry.getAttribute("normal");
|
|
171
174
|
const index = geometry.getIndex();
|
|
172
175
|
const vertex = (corner) => index ? index.getX(corner) : corner;
|
|
173
|
-
const
|
|
176
|
+
const triangleCount2 = Math.floor((index ? index.count : position.count) / 3);
|
|
174
177
|
const positions = [];
|
|
175
178
|
const normals = [];
|
|
176
179
|
for (const region of new Set(model.regionIndex.regionsForFeature(tag))) {
|
|
177
180
|
const range = model.regionIndex.rangeForRegion(region);
|
|
178
181
|
if (!range) continue;
|
|
179
|
-
for (let triangle = range.start; triangle < Math.min(range.end,
|
|
182
|
+
for (let triangle = range.start; triangle < Math.min(range.end, triangleCount2); triangle++) {
|
|
180
183
|
const corners = [vertex(triangle * 3), vertex(triangle * 3 + 1), vertex(triangle * 3 + 2)];
|
|
181
184
|
const at = corners.map((corner) => [
|
|
182
185
|
position.getX(corner),
|
|
@@ -241,7 +244,7 @@ var HoverCard = ({ pick, children, className: className2, offset = 16 }) => {
|
|
|
241
244
|
import { createContext, useContext } from "react";
|
|
242
245
|
|
|
243
246
|
// src/toolbar-icons.tsx
|
|
244
|
-
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
247
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
245
248
|
var SvgIcon = ({ viewBox = "0 0 24 24", fill = "none", children }) => /* @__PURE__ */ jsx2(
|
|
246
249
|
"svg",
|
|
247
250
|
{
|
|
@@ -267,6 +270,10 @@ var BananaIcon = () => /* @__PURE__ */ jsx2(SvgIcon, { viewBox: "0 0 576 512", f
|
|
|
267
270
|
var ToolsIcon = () => /* @__PURE__ */ jsx2(SvgIcon, { children: /* @__PURE__ */ jsx2("path", { d: "M9 2h6v7H9zM9.5 9v9.5l2.5 3.5 2.5-3.5V9M9.5 12l5 2.5M9.5 15.5l5 2.5" }) });
|
|
268
271
|
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" }) });
|
|
269
272
|
var DfmIcon = () => /* @__PURE__ */ jsx2(SvgIcon, { children: /* @__PURE__ */ jsx2("path", { d: "M8.3 3h7.4L21 8.3v7.4L15.7 21H8.3L3 15.7V8.3zM12 7.5v5.5m0 3.5v.01" }) });
|
|
273
|
+
var SharpCornersIcon = () => /* @__PURE__ */ jsxs(SvgIcon, { children: [
|
|
274
|
+
/* @__PURE__ */ jsx2("path", { d: "M4 3v17h17" }),
|
|
275
|
+
/* @__PURE__ */ jsx2("circle", { cx: "9", cy: "15", r: "4" })
|
|
276
|
+
] });
|
|
270
277
|
var HoverIcon = () => /* @__PURE__ */ jsx2(SvgIcon, { children: /* @__PURE__ */ jsx2("path", { d: "M4 4h16v12H9l-5 4zm4 5h8m-8 3h5" }) });
|
|
271
278
|
var FocusIcon = () => /* @__PURE__ */ jsx2(SvgIcon, { children: /* @__PURE__ */ jsx2("path", { d: "M4 4h16v16H4zM8 8h8v8H8zM2 12h4m12 0h4M12 2v4m0 12v4" }) });
|
|
272
279
|
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" }) });
|
|
@@ -283,6 +290,7 @@ var ICONS = {
|
|
|
283
290
|
tools: ToolsIcon,
|
|
284
291
|
directions: DirectionsIcon,
|
|
285
292
|
dfm: DfmIcon,
|
|
293
|
+
sharpCorners: SharpCornersIcon,
|
|
286
294
|
hover: HoverIcon,
|
|
287
295
|
focus: FocusIcon,
|
|
288
296
|
wireframe: WireframeIcon,
|
|
@@ -295,7 +303,7 @@ var ToolbarIcon = ({ name }) => {
|
|
|
295
303
|
};
|
|
296
304
|
|
|
297
305
|
// src/viewer-toolbar.tsx
|
|
298
|
-
import { jsx as jsx3, jsxs } from "react/jsx-runtime";
|
|
306
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
299
307
|
var ViewerToolbarContext = createContext(null);
|
|
300
308
|
var ViewerToolbarProvider = ({
|
|
301
309
|
controls,
|
|
@@ -313,7 +321,7 @@ var ToolbarButton = ({ action, icon, label, toggle = true }) => {
|
|
|
313
321
|
throw new Error(`<ViewerToolbar.${buttonName(action)}> requires a '${action}' toolbar control`);
|
|
314
322
|
}
|
|
315
323
|
const pressed = control.pressed ?? false;
|
|
316
|
-
return /* @__PURE__ */
|
|
324
|
+
return /* @__PURE__ */ jsxs2(
|
|
317
325
|
"button",
|
|
318
326
|
{
|
|
319
327
|
className: "viewer-toolbar-button",
|
|
@@ -385,6 +393,14 @@ var DfmButton = () => /* @__PURE__ */ jsx3(
|
|
|
385
393
|
label: (pressed) => pressed ? "Hide DFM flags" : "Show DFM flags"
|
|
386
394
|
}
|
|
387
395
|
);
|
|
396
|
+
var SharpCornersButton = () => /* @__PURE__ */ jsx3(
|
|
397
|
+
ToolbarButton,
|
|
398
|
+
{
|
|
399
|
+
action: "sharpCorners",
|
|
400
|
+
icon: "sharpCorners",
|
|
401
|
+
label: (pressed) => pressed ? "Hide sharp corners" : "Show sharp corners"
|
|
402
|
+
}
|
|
403
|
+
);
|
|
388
404
|
var HoverButton = () => /* @__PURE__ */ jsx3(
|
|
389
405
|
ToolbarButton,
|
|
390
406
|
{
|
|
@@ -444,6 +460,7 @@ var DefaultControls = () => {
|
|
|
444
460
|
const analysis = [
|
|
445
461
|
controls.directions ? /* @__PURE__ */ jsx3(DirectionsButton, {}, "directions") : null,
|
|
446
462
|
controls.dfm ? /* @__PURE__ */ jsx3(DfmButton, {}, "dfm") : null,
|
|
463
|
+
controls.sharpCorners ? /* @__PURE__ */ jsx3(SharpCornersButton, {}, "sharpCorners") : null,
|
|
447
464
|
controls.hover ? /* @__PURE__ */ jsx3(HoverButton, {}, "hover") : null,
|
|
448
465
|
controls.focus ? /* @__PURE__ */ jsx3(FocusButton, {}, "focus") : null,
|
|
449
466
|
controls.wireframe ? /* @__PURE__ */ jsx3(WireframeButton, {}, "wireframe") : null,
|
|
@@ -455,7 +472,7 @@ var DefaultControls = () => {
|
|
|
455
472
|
controls.reset ? /* @__PURE__ */ jsx3(ResetButton, {}, "reset") : null,
|
|
456
473
|
controls.top ? /* @__PURE__ */ jsx3(TopButton, {}, "top") : null
|
|
457
474
|
].filter(Boolean);
|
|
458
|
-
return /* @__PURE__ */
|
|
475
|
+
return /* @__PURE__ */ jsxs2(Controls, { children: [
|
|
459
476
|
display,
|
|
460
477
|
display.length && analysis.length ? /* @__PURE__ */ jsx3(Divider, {}) : null,
|
|
461
478
|
analysis,
|
|
@@ -484,6 +501,7 @@ var ViewerToolbar = Object.assign(ViewerToolbarRoot, {
|
|
|
484
501
|
ToolsButton,
|
|
485
502
|
DirectionsButton,
|
|
486
503
|
DfmButton,
|
|
504
|
+
SharpCornersButton,
|
|
487
505
|
HoverButton,
|
|
488
506
|
FocusButton,
|
|
489
507
|
WireframeButton,
|
|
@@ -576,8 +594,9 @@ function createStockMeshBuffer() {
|
|
|
576
594
|
import {
|
|
577
595
|
Box3,
|
|
578
596
|
BoxGeometry,
|
|
597
|
+
BufferGeometry,
|
|
579
598
|
CylinderGeometry,
|
|
580
|
-
|
|
599
|
+
Float32BufferAttribute,
|
|
581
600
|
Group,
|
|
582
601
|
LineBasicMaterial,
|
|
583
602
|
LineSegments,
|
|
@@ -585,8 +604,134 @@ import {
|
|
|
585
604
|
Mesh as Mesh2,
|
|
586
605
|
MeshLambertMaterial,
|
|
587
606
|
Quaternion,
|
|
588
|
-
Vector3
|
|
607
|
+
Vector3 as Vector32
|
|
589
608
|
} from "three";
|
|
609
|
+
|
|
610
|
+
// src/render/stock-edges.ts
|
|
611
|
+
import { MathUtils, Triangle, Vector3 } from "three";
|
|
612
|
+
var STOCK_EDGE_ANGLE = 15;
|
|
613
|
+
var SYNC_EDGE_TRIANGLES = 2e4;
|
|
614
|
+
var SLICE_MS = 4;
|
|
615
|
+
var CHECK_EVERY = 256;
|
|
616
|
+
var _v0 = new Vector3();
|
|
617
|
+
var _v1 = new Vector3();
|
|
618
|
+
var _normal = new Vector3();
|
|
619
|
+
var _triangle = new Triangle();
|
|
620
|
+
function* edgeWork(geometry, thresholdAngle) {
|
|
621
|
+
const precision = Math.pow(10, 4);
|
|
622
|
+
const thresholdDot = Math.cos(MathUtils.DEG2RAD * thresholdAngle);
|
|
623
|
+
const indexAttr = geometry.getIndex();
|
|
624
|
+
const positionAttr = geometry.getAttribute("position");
|
|
625
|
+
const indexCount = indexAttr ? indexAttr.count : positionAttr.count;
|
|
626
|
+
const indexArr = [0, 0, 0];
|
|
627
|
+
const corners = [_triangle.a, _triangle.b, _triangle.c];
|
|
628
|
+
const hashes = ["", "", ""];
|
|
629
|
+
const edgeData = /* @__PURE__ */ new Map();
|
|
630
|
+
const vertices = [];
|
|
631
|
+
const key = (v) => `${Math.round(v.x * precision)},${Math.round(v.y * precision)},${Math.round(v.z * precision)}`;
|
|
632
|
+
for (let i = 0, step2 = 0; i < indexCount; i += 3, step2 += 1) {
|
|
633
|
+
if (step2 % CHECK_EVERY === 0 && step2 > 0) yield;
|
|
634
|
+
if (indexAttr) {
|
|
635
|
+
indexArr[0] = indexAttr.getX(i);
|
|
636
|
+
indexArr[1] = indexAttr.getX(i + 1);
|
|
637
|
+
indexArr[2] = indexAttr.getX(i + 2);
|
|
638
|
+
} else {
|
|
639
|
+
indexArr[0] = i;
|
|
640
|
+
indexArr[1] = i + 1;
|
|
641
|
+
indexArr[2] = i + 2;
|
|
642
|
+
}
|
|
643
|
+
_triangle.a.fromBufferAttribute(positionAttr, indexArr[0]);
|
|
644
|
+
_triangle.b.fromBufferAttribute(positionAttr, indexArr[1]);
|
|
645
|
+
_triangle.c.fromBufferAttribute(positionAttr, indexArr[2]);
|
|
646
|
+
_triangle.getNormal(_normal);
|
|
647
|
+
hashes[0] = key(_triangle.a);
|
|
648
|
+
hashes[1] = key(_triangle.b);
|
|
649
|
+
hashes[2] = key(_triangle.c);
|
|
650
|
+
if (hashes[0] === hashes[1] || hashes[1] === hashes[2] || hashes[2] === hashes[0]) continue;
|
|
651
|
+
for (let j = 0; j < 3; j += 1) {
|
|
652
|
+
const jNext = (j + 1) % 3;
|
|
653
|
+
const v0 = corners[j];
|
|
654
|
+
const v1 = corners[jNext];
|
|
655
|
+
const hash = `${hashes[j]}_${hashes[jNext]}`;
|
|
656
|
+
const reverse = edgeData.get(`${hashes[jNext]}_${hashes[j]}`);
|
|
657
|
+
if (reverse) {
|
|
658
|
+
if (_normal.dot(reverse.normal) <= thresholdDot) {
|
|
659
|
+
vertices.push(v0.x, v0.y, v0.z, v1.x, v1.y, v1.z);
|
|
660
|
+
}
|
|
661
|
+
edgeData.set(`${hashes[jNext]}_${hashes[j]}`, null);
|
|
662
|
+
} else if (!edgeData.has(hash)) {
|
|
663
|
+
edgeData.set(hash, {
|
|
664
|
+
index0: indexArr[j],
|
|
665
|
+
index1: indexArr[jNext],
|
|
666
|
+
normal: _normal.clone()
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
let step = 0;
|
|
672
|
+
for (const edge of edgeData.values()) {
|
|
673
|
+
step += 1;
|
|
674
|
+
if (step % CHECK_EVERY === 0) yield;
|
|
675
|
+
if (!edge) continue;
|
|
676
|
+
_v0.fromBufferAttribute(positionAttr, edge.index0);
|
|
677
|
+
_v1.fromBufferAttribute(positionAttr, edge.index1);
|
|
678
|
+
vertices.push(_v0.x, _v0.y, _v0.z, _v1.x, _v1.y, _v1.z);
|
|
679
|
+
}
|
|
680
|
+
return new Float32Array(vertices);
|
|
681
|
+
}
|
|
682
|
+
function stockEdgePositions(geometry, thresholdAngle = STOCK_EDGE_ANGLE) {
|
|
683
|
+
const work = edgeWork(geometry, thresholdAngle);
|
|
684
|
+
for (; ; ) {
|
|
685
|
+
const next = work.next();
|
|
686
|
+
if (next.done) return next.value;
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
function triangleCount(geometry) {
|
|
690
|
+
const index = geometry.getIndex();
|
|
691
|
+
return Math.floor((index ? index.count : geometry.getAttribute("position")?.count ?? 0) / 3);
|
|
692
|
+
}
|
|
693
|
+
var nextTurn = (run) => {
|
|
694
|
+
if (typeof MessageChannel === "undefined") {
|
|
695
|
+
const timer = setTimeout(run, 0);
|
|
696
|
+
return () => clearTimeout(timer);
|
|
697
|
+
}
|
|
698
|
+
const channel = new MessageChannel();
|
|
699
|
+
let live = true;
|
|
700
|
+
channel.port1.onmessage = () => {
|
|
701
|
+
channel.port1.close();
|
|
702
|
+
if (live) run();
|
|
703
|
+
};
|
|
704
|
+
channel.port2.postMessage(null);
|
|
705
|
+
return () => {
|
|
706
|
+
live = false;
|
|
707
|
+
channel.port1.close();
|
|
708
|
+
};
|
|
709
|
+
};
|
|
710
|
+
function buildStockEdges(geometry, onDone, thresholdAngle = STOCK_EDGE_ANGLE) {
|
|
711
|
+
const work = edgeWork(geometry, thresholdAngle);
|
|
712
|
+
let cancelTurn = () => {
|
|
713
|
+
};
|
|
714
|
+
let cancelled = false;
|
|
715
|
+
const slice = () => {
|
|
716
|
+
const until = performance.now() + SLICE_MS;
|
|
717
|
+
for (; ; ) {
|
|
718
|
+
const next = work.next();
|
|
719
|
+
if (next.done) {
|
|
720
|
+
onDone(next.value);
|
|
721
|
+
return;
|
|
722
|
+
}
|
|
723
|
+
if (performance.now() >= until) break;
|
|
724
|
+
}
|
|
725
|
+
if (!cancelled) cancelTurn = nextTurn(slice);
|
|
726
|
+
};
|
|
727
|
+
cancelTurn = nextTurn(slice);
|
|
728
|
+
return () => {
|
|
729
|
+
cancelled = true;
|
|
730
|
+
cancelTurn();
|
|
731
|
+
};
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
// src/render/stock.ts
|
|
590
735
|
function boxFigure(bounds) {
|
|
591
736
|
return {
|
|
592
737
|
lower: { x: bounds.min.x, y: bounds.min.y, z: bounds.min.z },
|
|
@@ -594,7 +739,7 @@ function boxFigure(bounds) {
|
|
|
594
739
|
};
|
|
595
740
|
}
|
|
596
741
|
var CYLINDER_SEGMENTS = 64;
|
|
597
|
-
var CYLINDER_AXIS = new
|
|
742
|
+
var CYLINDER_AXIS = new Vector32(0, 1, 0);
|
|
598
743
|
function fixedBoxStockBounds(geometry, dimensions, position = "model_centered", positionOffset = 0, offset = { x: 0, y: 0, z: 0 }) {
|
|
599
744
|
if (![dimensions.x, dimensions.y, dimensions.z].every(Number.isFinite) || [dimensions.x, dimensions.y, dimensions.z].some((value) => value <= 0)) {
|
|
600
745
|
throw new RangeError("Fixed stock dimensions must be finite and positive.");
|
|
@@ -606,12 +751,12 @@ function fixedBoxStockBounds(geometry, dimensions, position = "model_centered",
|
|
|
606
751
|
throw new RangeError("Fixed stock offset must be finite.");
|
|
607
752
|
}
|
|
608
753
|
const part = partBounds(geometry);
|
|
609
|
-
const center = part.getCenter(new
|
|
754
|
+
const center = part.getCenter(new Vector32());
|
|
610
755
|
const z = fixedStockLowerZ(part, dimensions.z, position, positionOffset);
|
|
611
756
|
return new Box3(
|
|
612
|
-
new
|
|
613
|
-
new
|
|
614
|
-
).translate(new
|
|
757
|
+
new Vector32(center.x - dimensions.x / 2, center.y - dimensions.y / 2, z),
|
|
758
|
+
new Vector32(center.x + dimensions.x / 2, center.y + dimensions.y / 2, z + dimensions.z)
|
|
759
|
+
).translate(new Vector32(offset.x, offset.y, offset.z));
|
|
615
760
|
}
|
|
616
761
|
function fixedCylinderStock(geometry, size, position = "model_centered", positionOffset = 0) {
|
|
617
762
|
if (![size.diameter, size.length].every((value) => Number.isFinite(value) && value > 0)) {
|
|
@@ -621,7 +766,7 @@ function fixedCylinderStock(geometry, size, position = "model_centered", positio
|
|
|
621
766
|
throw new RangeError("Fixed stock position offset must be finite.");
|
|
622
767
|
}
|
|
623
768
|
const part = partBounds(geometry);
|
|
624
|
-
const center = part.getCenter(new
|
|
769
|
+
const center = part.getCenter(new Vector32());
|
|
625
770
|
return {
|
|
626
771
|
origin: {
|
|
627
772
|
x: center.x,
|
|
@@ -647,13 +792,13 @@ function cylinderStockGeometry(input) {
|
|
|
647
792
|
if (![diameter, length].every((value) => Number.isFinite(value) && value > 0)) {
|
|
648
793
|
throw new RangeError("Cylinder stock diameter and length must be finite and positive.");
|
|
649
794
|
}
|
|
650
|
-
const axis = new
|
|
795
|
+
const axis = new Vector32(figure.axis.x, figure.axis.y, figure.axis.z);
|
|
651
796
|
const norm = axis.length();
|
|
652
797
|
if (!Number.isFinite(norm) || norm === 0) {
|
|
653
798
|
throw new RangeError("Cylinder stock axis must be finite and non-zero.");
|
|
654
799
|
}
|
|
655
800
|
axis.divideScalar(norm);
|
|
656
|
-
const center = axis.clone().multiplyScalar(length / 2).add(new
|
|
801
|
+
const center = axis.clone().multiplyScalar(length / 2).add(new Vector32(origin.x, origin.y, origin.z));
|
|
657
802
|
return new CylinderGeometry(diameter / 2, diameter / 2, length, CYLINDER_SEGMENTS).applyQuaternion(new Quaternion().setFromUnitVectors(CYLINDER_AXIS, axis)).translate(center.x, center.y, center.z);
|
|
658
803
|
}
|
|
659
804
|
function boxStockGeometry(input) {
|
|
@@ -681,12 +826,12 @@ function orientedBoxStockGeometry(figure) {
|
|
|
681
826
|
)) {
|
|
682
827
|
throw new RangeError("Box stock frame and corners must be finite.");
|
|
683
828
|
}
|
|
684
|
-
const size = new
|
|
829
|
+
const size = new Vector32(upper.x - lower.x, upper.y - lower.y, upper.z - lower.z);
|
|
685
830
|
if (size.toArray().some((value) => !(value > 0))) {
|
|
686
831
|
throw new RangeError("Box stock upper corner must be above its lower corner on every axis.");
|
|
687
832
|
}
|
|
688
|
-
const z = new
|
|
689
|
-
const x = new
|
|
833
|
+
const z = new Vector32(axis.x, axis.y, axis.z).normalize();
|
|
834
|
+
const x = new Vector32(refDirection.x, refDirection.y, refDirection.z);
|
|
690
835
|
const reference = x.length();
|
|
691
836
|
x.addScaledVector(z, -x.dot(z));
|
|
692
837
|
if (!(z.lengthSq() > 0 && x.length() > 1e-9 * reference)) {
|
|
@@ -695,11 +840,11 @@ function orientedBoxStockGeometry(figure) {
|
|
|
695
840
|
);
|
|
696
841
|
}
|
|
697
842
|
x.normalize();
|
|
698
|
-
const y = new
|
|
843
|
+
const y = new Vector32().crossVectors(z, x);
|
|
699
844
|
return new BoxGeometry(size.x, size.y, size.z).translate((lower.x + upper.x) / 2, (lower.y + upper.y) / 2, (lower.z + upper.z) / 2).applyMatrix4(new Matrix4().makeBasis(x, y, z).setPosition(location.x, location.y, location.z));
|
|
700
845
|
}
|
|
701
846
|
function boxStockBounds(geometry, allowance = 0, offset = { x: 0, y: 0, z: 0 }) {
|
|
702
|
-
const padding = typeof allowance === "number" ? new
|
|
847
|
+
const padding = typeof allowance === "number" ? new Vector32(allowance, allowance, allowance) : "wall" in allowance ? new Vector32(allowance.wall, allowance.wall, allowance.floor) : new Vector32(allowance.x, allowance.y, allowance.z);
|
|
703
848
|
if (padding.toArray().some((value) => !Number.isFinite(value) || value < 0)) {
|
|
704
849
|
throw new RangeError("Stock allowance must be finite and non-negative.");
|
|
705
850
|
}
|
|
@@ -707,8 +852,8 @@ function boxStockBounds(geometry, allowance = 0, offset = { x: 0, y: 0, z: 0 })
|
|
|
707
852
|
throw new RangeError("Stock offset must be finite.");
|
|
708
853
|
}
|
|
709
854
|
const box = partBounds(geometry);
|
|
710
|
-
box.expandByVector(padding).translate(new
|
|
711
|
-
const size = box.getSize(new
|
|
855
|
+
box.expandByVector(padding).translate(new Vector32(offset.x, offset.y, offset.z));
|
|
856
|
+
const size = box.getSize(new Vector32());
|
|
712
857
|
if (size.toArray().some((value) => !Number.isFinite(value) || value <= 0)) {
|
|
713
858
|
throw new RangeError("Stock dimensions must be finite and positive.");
|
|
714
859
|
}
|
|
@@ -719,7 +864,7 @@ function partBounds(geometry) {
|
|
|
719
864
|
if (!position || position.count === 0)
|
|
720
865
|
throw new RangeError("Stock needs non-empty part geometry.");
|
|
721
866
|
const box = new Box3();
|
|
722
|
-
const point = new
|
|
867
|
+
const point = new Vector32();
|
|
723
868
|
for (let index = 0; index < position.count; index += 1) {
|
|
724
869
|
point.fromBufferAttribute(position, index);
|
|
725
870
|
if (!Number.isFinite(point.x) || !Number.isFinite(point.y) || !Number.isFinite(point.z)) {
|
|
@@ -729,7 +874,7 @@ function partBounds(geometry) {
|
|
|
729
874
|
}
|
|
730
875
|
return box;
|
|
731
876
|
}
|
|
732
|
-
function createStock(geometry, legacyWorkpiece = false) {
|
|
877
|
+
function createStock(geometry, legacyWorkpiece = false, onEdges) {
|
|
733
878
|
const material = new MeshLambertMaterial({ transparent: true, depthWrite: false });
|
|
734
879
|
const edgeMaterial = new LineBasicMaterial({ transparent: true, depthWrite: false });
|
|
735
880
|
const mesh = new Mesh2(geometry, material);
|
|
@@ -747,6 +892,18 @@ function createStock(geometry, legacyWorkpiece = false) {
|
|
|
747
892
|
edgeMaterial.depthWrite = true;
|
|
748
893
|
}
|
|
749
894
|
let edges = null;
|
|
895
|
+
let building = null;
|
|
896
|
+
let shown = false;
|
|
897
|
+
const attach = (positions) => {
|
|
898
|
+
const outline = new BufferGeometry();
|
|
899
|
+
outline.setAttribute("position", new Float32BufferAttribute(positions, 3));
|
|
900
|
+
edges = new LineSegments(outline, edgeMaterial);
|
|
901
|
+
edges.renderOrder = legacyWorkpiece ? 1 : 6;
|
|
902
|
+
edges.raycast = () => {
|
|
903
|
+
};
|
|
904
|
+
edges.visible = shown;
|
|
905
|
+
object.add(edges);
|
|
906
|
+
};
|
|
750
907
|
return {
|
|
751
908
|
object,
|
|
752
909
|
material,
|
|
@@ -754,19 +911,28 @@ function createStock(geometry, legacyWorkpiece = false) {
|
|
|
754
911
|
/**
|
|
755
912
|
* Shows or hides the outline, building it the first time it is shown: the
|
|
756
913
|
* edge pass reads every triangle, and stock cut by a toolpath has a great
|
|
757
|
-
* many of them.
|
|
914
|
+
* many of them. A small mesh's outline is built at once; a large one's in
|
|
915
|
+
* slices between frames, so the stock shows first and its outline joins it
|
|
916
|
+
* a moment later, the same lines `EdgesGeometry` would have drawn.
|
|
758
917
|
*/
|
|
759
918
|
showEdges(show) {
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
}
|
|
765
|
-
|
|
919
|
+
shown = show;
|
|
920
|
+
if (show && !edges && !building) {
|
|
921
|
+
if (triangleCount(geometry) <= SYNC_EDGE_TRIANGLES) {
|
|
922
|
+
attach(stockEdgePositions(geometry));
|
|
923
|
+
} else {
|
|
924
|
+
building = buildStockEdges(geometry, (positions) => {
|
|
925
|
+
building = null;
|
|
926
|
+
attach(positions);
|
|
927
|
+
onEdges?.();
|
|
928
|
+
});
|
|
929
|
+
}
|
|
766
930
|
}
|
|
767
931
|
if (edges) edges.visible = show;
|
|
768
932
|
},
|
|
769
933
|
dispose() {
|
|
934
|
+
building?.();
|
|
935
|
+
building = null;
|
|
770
936
|
material.dispose();
|
|
771
937
|
edgeMaterial.dispose();
|
|
772
938
|
edges?.geometry.dispose();
|
|
@@ -790,8 +956,8 @@ var GeometryStock = ({
|
|
|
790
956
|
}) => {
|
|
791
957
|
const invalidate = useThree((state) => state.invalidate);
|
|
792
958
|
const stock = useMemo(
|
|
793
|
-
() => createStock(geometry, renderStyle === "legacy-workpiece"),
|
|
794
|
-
[geometry, renderStyle]
|
|
959
|
+
() => createStock(geometry, renderStyle === "legacy-workpiece", invalidate),
|
|
960
|
+
[geometry, renderStyle, invalidate]
|
|
795
961
|
);
|
|
796
962
|
useEffect2(() => () => stock.dispose(), [stock]);
|
|
797
963
|
useLayoutEffect(() => {
|
|
@@ -898,13 +1064,13 @@ import { useThree as useThree2 } from "@react-three/fiber";
|
|
|
898
1064
|
import { useLayoutEffect as useLayoutEffect2, useMemo as useMemo2, useRef } from "react";
|
|
899
1065
|
|
|
900
1066
|
// src/render/banana.ts
|
|
901
|
-
import { Vector3 as
|
|
1067
|
+
import { Vector3 as Vector33 } from "three";
|
|
902
1068
|
var BANANA_GAP = 0.1;
|
|
903
1069
|
function bananaPosition(part, banana) {
|
|
904
|
-
const size = part.getSize(new
|
|
1070
|
+
const size = part.getSize(new Vector33());
|
|
905
1071
|
const reach = Math.max(size.x, size.y, size.z);
|
|
906
|
-
const centre = part.getCenter(new
|
|
907
|
-
return new
|
|
1072
|
+
const centre = part.getCenter(new Vector33());
|
|
1073
|
+
return new Vector33(
|
|
908
1074
|
part.max.x + reach * BANANA_GAP - banana.min.x,
|
|
909
1075
|
centre.y - (banana.min.y + banana.max.y) / 2,
|
|
910
1076
|
part.min.z - banana.min.z
|
|
@@ -974,13 +1140,13 @@ import { useThree as useThree3 } from "@react-three/fiber";
|
|
|
974
1140
|
import { useEffect as useEffect3, useMemo as useMemo3, useRef as useRef2, useState as useState3 } from "react";
|
|
975
1141
|
|
|
976
1142
|
// src/render/grid.ts
|
|
977
|
-
import { BufferGeometry, Float32BufferAttribute, Vector3 as
|
|
1143
|
+
import { BufferGeometry as BufferGeometry2, Float32BufferAttribute as Float32BufferAttribute2, Vector3 as Vector34 } from "three";
|
|
978
1144
|
var STEPS = [0.1, 0.2, 0.5, 1, 2, 5, 10, 20, 25, 50, 100, 200, 250, 500, 1e3];
|
|
979
1145
|
var TARGET_CELLS = 10;
|
|
980
1146
|
var OVERHANG = 1.6;
|
|
981
1147
|
function gridSpec(box) {
|
|
982
|
-
const size = box.getSize(new
|
|
983
|
-
const center = box.getCenter(new
|
|
1148
|
+
const size = box.getSize(new Vector34());
|
|
1149
|
+
const center = box.getCenter(new Vector34());
|
|
984
1150
|
const largest = Math.max(size.x, size.y, 1e-6);
|
|
985
1151
|
const ideal = largest / TARGET_CELLS;
|
|
986
1152
|
const step = [...STEPS].reverse().find((candidate) => candidate <= ideal) ?? STEPS[0];
|
|
@@ -1006,8 +1172,8 @@ function gridGeometry(spec) {
|
|
|
1006
1172
|
z
|
|
1007
1173
|
);
|
|
1008
1174
|
}
|
|
1009
|
-
const geometry = new
|
|
1010
|
-
geometry.setAttribute("position", new
|
|
1175
|
+
const geometry = new BufferGeometry2();
|
|
1176
|
+
geometry.setAttribute("position", new Float32BufferAttribute2(positions, 3));
|
|
1011
1177
|
return geometry;
|
|
1012
1178
|
}
|
|
1013
1179
|
function gridFor(box, options = {}) {
|
|
@@ -1024,7 +1190,7 @@ function gridFor(box, options = {}) {
|
|
|
1024
1190
|
}
|
|
1025
1191
|
|
|
1026
1192
|
// src/primitives.tsx
|
|
1027
|
-
import { jsx as jsx6, jsxs as
|
|
1193
|
+
import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1028
1194
|
var FURNITURE2 = { [EXCLUDE_FROM_FRAME]: true };
|
|
1029
1195
|
var Grid = ({ step, extent, color, opacity = 0.35 }) => {
|
|
1030
1196
|
const theme = resolveTheme();
|
|
@@ -1086,7 +1252,7 @@ var CubePanels = ({
|
|
|
1086
1252
|
setHovered(name);
|
|
1087
1253
|
invalidate();
|
|
1088
1254
|
};
|
|
1089
|
-
return /* @__PURE__ */
|
|
1255
|
+
return /* @__PURE__ */ jsxs3("group", { ref: groupRef, scale: 38, children: [
|
|
1090
1256
|
panels.map(({ zone, geometry }) => /* @__PURE__ */ jsx6(
|
|
1091
1257
|
"mesh",
|
|
1092
1258
|
{
|
|
@@ -1122,17 +1288,17 @@ var CubePanels = ({
|
|
|
1122
1288
|
// src/direction-arrows.tsx
|
|
1123
1289
|
import { useThree as useThree4 } from "@react-three/fiber";
|
|
1124
1290
|
import { useEffect as useEffect4, useMemo as useMemo4 } from "react";
|
|
1125
|
-
import { Quaternion as Quaternion2, Vector3 as
|
|
1291
|
+
import { Quaternion as Quaternion2, Vector3 as Vector36 } from "three";
|
|
1126
1292
|
|
|
1127
1293
|
// src/render/directions.ts
|
|
1128
|
-
import { Vector3 as
|
|
1294
|
+
import { Vector3 as Vector35 } from "three";
|
|
1129
1295
|
var LENGTH = 0.33;
|
|
1130
1296
|
var GAP = 0.2;
|
|
1131
1297
|
function arrowPlacement(direction, box) {
|
|
1132
|
-
const center = box.getCenter(new
|
|
1133
|
-
const half = box.getSize(new
|
|
1298
|
+
const center = box.getCenter(new Vector35());
|
|
1299
|
+
const half = box.getSize(new Vector35()).multiplyScalar(0.5);
|
|
1134
1300
|
const radius = half.length() || 1;
|
|
1135
|
-
const axis = new
|
|
1301
|
+
const axis = new Vector35(direction.x, direction.y, direction.z);
|
|
1136
1302
|
if (axis.lengthSq() === 0) axis.set(0, 0, 1);
|
|
1137
1303
|
axis.normalize();
|
|
1138
1304
|
let exit = Number.POSITIVE_INFINITY;
|
|
@@ -1148,7 +1314,7 @@ function arrowPlacement(direction, box) {
|
|
|
1148
1314
|
}
|
|
1149
1315
|
|
|
1150
1316
|
// src/direction-arrows.tsx
|
|
1151
|
-
import { jsx as jsx7, jsxs as
|
|
1317
|
+
import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1152
1318
|
var FURNITURE3 = { [EXCLUDE_FROM_FRAME]: true };
|
|
1153
1319
|
var DirectionArrows = ({
|
|
1154
1320
|
directions,
|
|
@@ -1175,7 +1341,7 @@ var DirectionArrows = ({
|
|
|
1175
1341
|
// Excluded from framing: the arrows are deliberately placed outside the
|
|
1176
1342
|
// part, so a Fit that measured them would frame the arrows and leave the
|
|
1177
1343
|
// part small in the middle of them.
|
|
1178
|
-
/* @__PURE__ */
|
|
1344
|
+
/* @__PURE__ */ jsxs4("group", { userData: FURNITURE3, children: [
|
|
1179
1345
|
directions.map((direction, index) => {
|
|
1180
1346
|
if (!drawn(index)) return null;
|
|
1181
1347
|
return /* @__PURE__ */ jsx7(
|
|
@@ -1223,7 +1389,7 @@ var Arrow = ({ direction, box, geometry, color, opacity, onPick, onTop = false }
|
|
|
1223
1389
|
const placement = arrowPlacement(direction, box);
|
|
1224
1390
|
const aim = new Quaternion2().setFromUnitVectors(
|
|
1225
1391
|
ARROW_AXIS,
|
|
1226
|
-
new
|
|
1392
|
+
new Vector36(direction.x, direction.y, direction.z).normalize()
|
|
1227
1393
|
);
|
|
1228
1394
|
return { tip: placement.tip, length: placement.length, quaternion: aim };
|
|
1229
1395
|
}, [box, direction]);
|
|
@@ -1241,16 +1407,16 @@ var Arrow = ({ direction, box, geometry, color, opacity, onPick, onTop = false }
|
|
|
1241
1407
|
import { useFrame, useThree as useThree5 } from "@react-three/fiber";
|
|
1242
1408
|
import { useEffect as useEffect5, useMemo as useMemo5, useRef as useRef3, useState as useState4, useSyncExternalStore } from "react";
|
|
1243
1409
|
import {
|
|
1244
|
-
BufferGeometry as
|
|
1410
|
+
BufferGeometry as BufferGeometry3,
|
|
1245
1411
|
DoubleSide,
|
|
1246
1412
|
Quaternion as Quaternion3,
|
|
1247
1413
|
Raycaster,
|
|
1248
1414
|
Vector2,
|
|
1249
|
-
Vector3 as
|
|
1415
|
+
Vector3 as Vector37
|
|
1250
1416
|
} from "three";
|
|
1251
|
-
import { Fragment, jsx as jsx8, jsxs as
|
|
1417
|
+
import { Fragment, jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1252
1418
|
var FURNITURE4 = { [EXCLUDE_FROM_FRAME]: true };
|
|
1253
|
-
var Z = new
|
|
1419
|
+
var Z = new Vector37(0, 0, 1);
|
|
1254
1420
|
var AXIS_ROTATIONS = {
|
|
1255
1421
|
x: [0, Math.PI / 2, 0],
|
|
1256
1422
|
y: [Math.PI / 2, 0, 0],
|
|
@@ -1280,11 +1446,11 @@ var SectionTool = ({ theme }) => {
|
|
|
1280
1446
|
};
|
|
1281
1447
|
var useSquare = () => {
|
|
1282
1448
|
const square = useMemo5(
|
|
1283
|
-
() => new
|
|
1284
|
-
new
|
|
1285
|
-
new
|
|
1286
|
-
new
|
|
1287
|
-
new
|
|
1449
|
+
() => new BufferGeometry3().setFromPoints([
|
|
1450
|
+
new Vector37(-1, 1, 0),
|
|
1451
|
+
new Vector37(1, 1, 0),
|
|
1452
|
+
new Vector37(1, -1, 0),
|
|
1453
|
+
new Vector37(-1, -1, 0)
|
|
1288
1454
|
]),
|
|
1289
1455
|
[]
|
|
1290
1456
|
);
|
|
@@ -1302,8 +1468,8 @@ var Picker = ({ box, theme }) => {
|
|
|
1302
1468
|
const previewRef = useRef3(null);
|
|
1303
1469
|
const hover = useRef3(null);
|
|
1304
1470
|
const [hoveredPlane, setHoveredPlane] = useState4(null);
|
|
1305
|
-
const span = useMemo5(() => box.getSize(new
|
|
1306
|
-
const centre = useMemo5(() => box.getCenter(new
|
|
1471
|
+
const span = useMemo5(() => box.getSize(new Vector37()).length(), [box]);
|
|
1472
|
+
const centre = useMemo5(() => box.getCenter(new Vector37()), [box]);
|
|
1307
1473
|
const previewSize = span * PREVIEW_SCALE;
|
|
1308
1474
|
useEffect5(() => {
|
|
1309
1475
|
store.setPicking(true);
|
|
@@ -1312,7 +1478,7 @@ var Picker = ({ box, theme }) => {
|
|
|
1312
1478
|
useEffect5(() => {
|
|
1313
1479
|
const raycaster = new Raycaster();
|
|
1314
1480
|
const pointer = new Vector2();
|
|
1315
|
-
const aim = new
|
|
1481
|
+
const aim = new Vector37();
|
|
1316
1482
|
const hide = () => {
|
|
1317
1483
|
if (!hover.current) return;
|
|
1318
1484
|
hover.current = null;
|
|
@@ -1383,9 +1549,9 @@ var Picker = ({ box, theme }) => {
|
|
|
1383
1549
|
store.set(plane.options);
|
|
1384
1550
|
}
|
|
1385
1551
|
});
|
|
1386
|
-
return /* @__PURE__ */
|
|
1387
|
-
/* @__PURE__ */
|
|
1388
|
-
/* @__PURE__ */
|
|
1552
|
+
return /* @__PURE__ */ jsxs5(Fragment, { children: [
|
|
1553
|
+
/* @__PURE__ */ jsxs5("group", { ref: previewRef, visible: false, children: [
|
|
1554
|
+
/* @__PURE__ */ jsxs5("mesh", { renderOrder: SECTION_RENDER_ORDER.outline, raycast: () => null, children: [
|
|
1389
1555
|
/* @__PURE__ */ jsx8("planeGeometry", { args: [previewSize, previewSize] }),
|
|
1390
1556
|
/* @__PURE__ */ jsx8(
|
|
1391
1557
|
"meshBasicMaterial",
|
|
@@ -1418,13 +1584,13 @@ var Picker = ({ box, theme }) => {
|
|
|
1418
1584
|
}
|
|
1419
1585
|
)
|
|
1420
1586
|
] }),
|
|
1421
|
-
planes.map((plane) => /* @__PURE__ */
|
|
1587
|
+
planes.map((plane) => /* @__PURE__ */ jsxs5(
|
|
1422
1588
|
"group",
|
|
1423
1589
|
{
|
|
1424
1590
|
position: [plane.position.x, plane.position.y, plane.position.z],
|
|
1425
1591
|
rotation: AXIS_ROTATIONS[plane.axis],
|
|
1426
1592
|
children: [
|
|
1427
|
-
/* @__PURE__ */
|
|
1593
|
+
/* @__PURE__ */ jsxs5("mesh", { renderOrder: SECTION_RENDER_ORDER.outline, ...planeHandlers(plane), children: [
|
|
1428
1594
|
/* @__PURE__ */ jsx8("planeGeometry", { args: [plane.size, plane.size] }),
|
|
1429
1595
|
/* @__PURE__ */ jsx8(
|
|
1430
1596
|
"meshBasicMaterial",
|
|
@@ -1456,7 +1622,7 @@ var Picker = ({ box, theme }) => {
|
|
|
1456
1622
|
var CutSheet = ({ box, section, theme }) => {
|
|
1457
1623
|
const square = useSquare();
|
|
1458
1624
|
const cut = useMemo5(() => resolveSectionPlane(section, box), [box, section]);
|
|
1459
|
-
const span = useMemo5(() => box.getSize(new
|
|
1625
|
+
const span = useMemo5(() => box.getSize(new Vector37()).length(), [box]);
|
|
1460
1626
|
const placement = useMemo5(() => {
|
|
1461
1627
|
if (!cut) return null;
|
|
1462
1628
|
const position = sectionAnchor(box, cut.plane).addScaledVector(
|
|
@@ -1467,8 +1633,8 @@ var CutSheet = ({ box, section, theme }) => {
|
|
|
1467
1633
|
}, [box, cut, span]);
|
|
1468
1634
|
if (!placement) return null;
|
|
1469
1635
|
const size = span * OUTLINE_SCALE;
|
|
1470
|
-
return /* @__PURE__ */
|
|
1471
|
-
/* @__PURE__ */
|
|
1636
|
+
return /* @__PURE__ */ jsxs5("group", { position: placement.position, quaternion: placement.quaternion, children: [
|
|
1637
|
+
/* @__PURE__ */ jsxs5("mesh", { renderOrder: SECTION_RENDER_ORDER.outline, raycast: () => null, children: [
|
|
1472
1638
|
/* @__PURE__ */ jsx8("planeGeometry", { args: [size, size] }),
|
|
1473
1639
|
/* @__PURE__ */ jsx8(
|
|
1474
1640
|
"meshBasicMaterial",
|
|
@@ -1519,18 +1685,18 @@ import {
|
|
|
1519
1685
|
Raycaster as Raycaster2,
|
|
1520
1686
|
SphereGeometry,
|
|
1521
1687
|
Vector2 as Vector22,
|
|
1522
|
-
Vector3 as
|
|
1688
|
+
Vector3 as Vector39
|
|
1523
1689
|
} from "three";
|
|
1524
1690
|
|
|
1525
1691
|
// src/render/resample.ts
|
|
1526
|
-
import { Vector3 as
|
|
1692
|
+
import { Vector3 as Vector38 } from "three";
|
|
1527
1693
|
var ON_PLANE = 1e-7;
|
|
1528
1694
|
var STITCH = 1e-5;
|
|
1529
1695
|
var COLLINEAR = 1e-6;
|
|
1530
1696
|
function clipSegments(positions, plane) {
|
|
1531
1697
|
const out = [];
|
|
1532
|
-
const a = new
|
|
1533
|
-
const b = new
|
|
1698
|
+
const a = new Vector38();
|
|
1699
|
+
const b = new Vector38();
|
|
1534
1700
|
const count = Math.floor(positions.length / 6);
|
|
1535
1701
|
for (let i = 0; i < count; i += 1) {
|
|
1536
1702
|
a.set(positions[i * 6], positions[i * 6 + 1], positions[i * 6 + 2]);
|
|
@@ -1545,14 +1711,14 @@ function clipSegments(positions, plane) {
|
|
|
1545
1711
|
return Float32Array.from(out);
|
|
1546
1712
|
}
|
|
1547
1713
|
function sectionContour(positions, regionOf, plane) {
|
|
1548
|
-
const a = new
|
|
1549
|
-
const b = new
|
|
1550
|
-
const c = new
|
|
1551
|
-
const p = new
|
|
1552
|
-
const q = new
|
|
1714
|
+
const a = new Vector38();
|
|
1715
|
+
const b = new Vector38();
|
|
1716
|
+
const c = new Vector38();
|
|
1717
|
+
const p = new Vector38();
|
|
1718
|
+
const q = new Vector38();
|
|
1553
1719
|
const byRegion = /* @__PURE__ */ new Map();
|
|
1554
|
-
const
|
|
1555
|
-
for (let t = 0; t <
|
|
1720
|
+
const triangleCount2 = Math.floor(positions.length / 9);
|
|
1721
|
+
for (let t = 0; t < triangleCount2; t += 1) {
|
|
1556
1722
|
a.set(positions[t * 9], positions[t * 9 + 1], positions[t * 9 + 2]);
|
|
1557
1723
|
b.set(positions[t * 9 + 3], positions[t * 9 + 4], positions[t * 9 + 5]);
|
|
1558
1724
|
c.set(positions[t * 9 + 6], positions[t * 9 + 7], positions[t * 9 + 8]);
|
|
@@ -1607,17 +1773,17 @@ function stitch(segments, out) {
|
|
|
1607
1773
|
return into.set(segments[o], segments[o + 1], segments[o + 2]);
|
|
1608
1774
|
};
|
|
1609
1775
|
const direction = (i, into) => {
|
|
1610
|
-
const s = new
|
|
1611
|
-
const e = new
|
|
1776
|
+
const s = new Vector38();
|
|
1777
|
+
const e = new Vector38();
|
|
1612
1778
|
point(i, 0, s);
|
|
1613
1779
|
point(i, 1, e);
|
|
1614
1780
|
return into.subVectors(e, s).normalize();
|
|
1615
1781
|
};
|
|
1616
1782
|
const consumed = new Uint8Array(count);
|
|
1617
|
-
const d = new
|
|
1618
|
-
const n = new
|
|
1783
|
+
const d = new Vector38();
|
|
1784
|
+
const n = new Vector38();
|
|
1619
1785
|
const next = (i, end) => {
|
|
1620
|
-
const at = point(i, end, new
|
|
1786
|
+
const at = point(i, end, new Vector38());
|
|
1621
1787
|
const list = ends.get(key(at.x, at.y, at.z)) ?? [];
|
|
1622
1788
|
if (list.length !== 2) return null;
|
|
1623
1789
|
const other = list.find((entry) => entry >> 1 !== i);
|
|
@@ -1646,8 +1812,8 @@ function stitch(segments, out) {
|
|
|
1646
1812
|
};
|
|
1647
1813
|
const back = walk(0);
|
|
1648
1814
|
const forward = walk(1);
|
|
1649
|
-
const s = point(back.index, back.end, new
|
|
1650
|
-
const e = point(forward.index, forward.end, new
|
|
1815
|
+
const s = point(back.index, back.end, new Vector38());
|
|
1816
|
+
const e = point(forward.index, forward.end, new Vector38());
|
|
1651
1817
|
out.push(s.x, s.y, s.z, e.x, e.y, e.z);
|
|
1652
1818
|
}
|
|
1653
1819
|
}
|
|
@@ -1655,8 +1821,8 @@ function pointInContour(point, plane, contour) {
|
|
|
1655
1821
|
const [u, v] = planeAxes(plane);
|
|
1656
1822
|
const px = point.dot(u);
|
|
1657
1823
|
const py = point.dot(v);
|
|
1658
|
-
const a = new
|
|
1659
|
-
const b = new
|
|
1824
|
+
const a = new Vector38();
|
|
1825
|
+
const b = new Vector38();
|
|
1660
1826
|
let inside = false;
|
|
1661
1827
|
const count = Math.floor(contour.length / 6);
|
|
1662
1828
|
for (let i = 0; i < count; i += 1) {
|
|
@@ -1673,15 +1839,15 @@ function pointInContour(point, plane, contour) {
|
|
|
1673
1839
|
return inside;
|
|
1674
1840
|
}
|
|
1675
1841
|
function capHit(ray, plane, contour) {
|
|
1676
|
-
const point = ray.intersectPlane(plane, new
|
|
1842
|
+
const point = ray.intersectPlane(plane, new Vector38());
|
|
1677
1843
|
if (!point) return null;
|
|
1678
1844
|
return pointInContour(point, plane, contour) ? point : null;
|
|
1679
1845
|
}
|
|
1680
1846
|
function planeAxes(plane) {
|
|
1681
1847
|
const n = plane.normal;
|
|
1682
|
-
const seed = Math.abs(n.x) < 0.9 ? new
|
|
1683
|
-
const u = new
|
|
1684
|
-
const v = new
|
|
1848
|
+
const seed = Math.abs(n.x) < 0.9 ? new Vector38(1, 0, 0) : new Vector38(0, 1, 0);
|
|
1849
|
+
const u = new Vector38().crossVectors(n, seed).normalize();
|
|
1850
|
+
const v = new Vector38().crossVectors(n, u).normalize();
|
|
1685
1851
|
return [u, v];
|
|
1686
1852
|
}
|
|
1687
1853
|
function sampleSection(meshPositions, regionOf, edgePositions, plane) {
|
|
@@ -1694,7 +1860,7 @@ function sampleSection(meshPositions, regionOf, edgePositions, plane) {
|
|
|
1694
1860
|
}
|
|
1695
1861
|
|
|
1696
1862
|
// src/measure-tool.tsx
|
|
1697
|
-
import { Fragment as Fragment2, jsx as jsx9, jsxs as
|
|
1863
|
+
import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1698
1864
|
var FURNITURE5 = { [EXCLUDE_FROM_FRAME]: true };
|
|
1699
1865
|
var MEASURE_LABEL_CLASS = "toolpath-measure-label";
|
|
1700
1866
|
var MeasureTool = ({
|
|
@@ -1755,7 +1921,7 @@ var MeasureTool = ({
|
|
|
1755
1921
|
};
|
|
1756
1922
|
if (box.isEmpty()) return null;
|
|
1757
1923
|
const label = className(labelClassName);
|
|
1758
|
-
return /* @__PURE__ */
|
|
1924
|
+
return /* @__PURE__ */ jsxs6("group", { userData: FURNITURE5, children: [
|
|
1759
1925
|
picking ? null : /* @__PURE__ */ jsx9(
|
|
1760
1926
|
Snapper,
|
|
1761
1927
|
{
|
|
@@ -1791,7 +1957,7 @@ var MeasureTool = ({
|
|
|
1791
1957
|
] });
|
|
1792
1958
|
};
|
|
1793
1959
|
var NO_POINTER = { pointerEvents: "none" };
|
|
1794
|
-
var NOWHERE = [new
|
|
1960
|
+
var NOWHERE = [new Vector39(), new Vector39()];
|
|
1795
1961
|
var Snapper = ({ mode, draft, onPlace, theme, format, label }) => {
|
|
1796
1962
|
const camera = useThree6((state) => state.camera);
|
|
1797
1963
|
const scene = useThree6((state) => state.scene);
|
|
@@ -1844,7 +2010,7 @@ var Snapper = ({ mode, draft, onPlace, theme, format, label }) => {
|
|
|
1844
2010
|
const snapped = snapAt(target, target.edges, camera, viewport);
|
|
1845
2011
|
const from = placed[placed.length - 1];
|
|
1846
2012
|
const lock = shift && from ? lockToAxis(from, snapped.point) : null;
|
|
1847
|
-
const found = lock ? { ...snapped, point: new
|
|
2013
|
+
const found = lock ? { ...snapped, point: new Vector39(lock.point.x, lock.point.y, lock.point.z), edge: null } : snapped;
|
|
1848
2014
|
snap.current = found;
|
|
1849
2015
|
const node = marker.current;
|
|
1850
2016
|
if (node) {
|
|
@@ -1929,7 +2095,7 @@ var Snapper = ({ mode, draft, onPlace, theme, format, label }) => {
|
|
|
1929
2095
|
invalidate();
|
|
1930
2096
|
}
|
|
1931
2097
|
}, [draft, invalidate]);
|
|
1932
|
-
return /* @__PURE__ */
|
|
2098
|
+
return /* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
1933
2099
|
/* @__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 }) }) }),
|
|
1934
2100
|
/* @__PURE__ */ jsx9(
|
|
1935
2101
|
Line,
|
|
@@ -2124,7 +2290,7 @@ var MeasurementView = ({
|
|
|
2124
2290
|
const anchor = measurementLabelAnchor(measurement);
|
|
2125
2291
|
if (measurement.kind === "distance") {
|
|
2126
2292
|
const [a2, b2] = measurement.points;
|
|
2127
|
-
return /* @__PURE__ */
|
|
2293
|
+
return /* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
2128
2294
|
/* @__PURE__ */ jsx9(Segment, { points: [a2, b2], color: theme.measure }),
|
|
2129
2295
|
/* @__PURE__ */ jsx9(ScreenDot, { point: a2, pixels: MEASURE_MARKER_PIXELS, color: theme.measure }),
|
|
2130
2296
|
/* @__PURE__ */ jsx9(ScreenDot, { point: b2, pixels: MEASURE_MARKER_PIXELS, color: theme.measure }),
|
|
@@ -2134,7 +2300,7 @@ var MeasurementView = ({
|
|
|
2134
2300
|
}
|
|
2135
2301
|
const [a, vertex, b] = measurement.points;
|
|
2136
2302
|
const arc = angleArc(vertex, a, b, angleArcRadius(vertex, a, b));
|
|
2137
|
-
return /* @__PURE__ */
|
|
2303
|
+
return /* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
2138
2304
|
/* @__PURE__ */ jsx9(Segment, { points: [vertex, a], color: theme.measure }),
|
|
2139
2305
|
/* @__PURE__ */ jsx9(Segment, { points: [vertex, b], color: theme.measure }),
|
|
2140
2306
|
/* @__PURE__ */ jsx9(Polyline, { points: arc, color: theme.measure }),
|
|
@@ -2152,7 +2318,7 @@ var DeltaLegs = ({ a, b, id, format, label }) => {
|
|
|
2152
2318
|
const lines = useRef4([]);
|
|
2153
2319
|
const centre = useMemo6(() => {
|
|
2154
2320
|
const at = midpoint(a, b);
|
|
2155
|
-
return new
|
|
2321
|
+
return new Vector39(at.x, at.y, at.z);
|
|
2156
2322
|
}, [a, b]);
|
|
2157
2323
|
useFrame2(() => {
|
|
2158
2324
|
const dash = screenLength(camera, centre, size, DELTA_DASH_PIXELS);
|
|
@@ -2166,7 +2332,7 @@ var DeltaLegs = ({ a, b, id, format, label }) => {
|
|
|
2166
2332
|
}
|
|
2167
2333
|
if (changed) invalidate();
|
|
2168
2334
|
});
|
|
2169
|
-
return /* @__PURE__ */
|
|
2335
|
+
return /* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
2170
2336
|
legs.map((leg, index) => /* @__PURE__ */ jsx9(
|
|
2171
2337
|
Line,
|
|
2172
2338
|
{
|
|
@@ -2174,8 +2340,8 @@ var DeltaLegs = ({ a, b, id, format, label }) => {
|
|
|
2174
2340
|
lines.current[index] = line;
|
|
2175
2341
|
},
|
|
2176
2342
|
points: [
|
|
2177
|
-
new
|
|
2178
|
-
new
|
|
2343
|
+
new Vector39(leg.from.x, leg.from.y, leg.from.z),
|
|
2344
|
+
new Vector39(leg.to.x, leg.to.y, leg.to.z)
|
|
2179
2345
|
],
|
|
2180
2346
|
color: AXIS_COLORS[leg.axis],
|
|
2181
2347
|
lineWidth: MEASURE_LINE_PIXELS.leg,
|
|
@@ -2211,7 +2377,7 @@ var ScreenDot = ({ point, pixels, color }) => {
|
|
|
2211
2377
|
const invalidate = useThree6((state) => state.invalidate);
|
|
2212
2378
|
const node = useRef4(null);
|
|
2213
2379
|
const dot = useDot();
|
|
2214
|
-
const position = useMemo6(() => new
|
|
2380
|
+
const position = useMemo6(() => new Vector39(point.x, point.y, point.z), [point]);
|
|
2215
2381
|
useFrame2(() => {
|
|
2216
2382
|
const group = node.current;
|
|
2217
2383
|
if (!group) return;
|
|
@@ -2226,7 +2392,7 @@ var ScreenDot = ({ point, pixels, color }) => {
|
|
|
2226
2392
|
var Segment = ({ points, color }) => {
|
|
2227
2393
|
const [a, b] = points;
|
|
2228
2394
|
const ends = useMemo6(
|
|
2229
|
-
() => [new
|
|
2395
|
+
() => [new Vector39(a.x, a.y, a.z), new Vector39(b.x, b.y, b.z)],
|
|
2230
2396
|
// Keyed on the numbers: a draft's tuple is a fresh array on every render,
|
|
2231
2397
|
// and a rebuilt array would rebuild the line's geometry with it.
|
|
2232
2398
|
[a.x, a.y, a.z, b.x, b.y, b.z]
|
|
@@ -2268,7 +2434,7 @@ import { useMemo as useMemo7 } from "react";
|
|
|
2268
2434
|
import { DoubleSide as DoubleSide2 } from "three";
|
|
2269
2435
|
|
|
2270
2436
|
// src/render/tool-marks.ts
|
|
2271
|
-
import { Quaternion as Quaternion4, Vector2 as Vector23, Vector3 as
|
|
2437
|
+
import { Quaternion as Quaternion4, Vector2 as Vector23, Vector3 as Vector310 } from "three";
|
|
2272
2438
|
var TOOL_CORNER_STEPS = 12;
|
|
2273
2439
|
var TOOL_ROUND = 64;
|
|
2274
2440
|
function toolProfile(radius, corner, height) {
|
|
@@ -2288,9 +2454,9 @@ function toolProfile(radius, corner, height) {
|
|
|
2288
2454
|
points.push(new Vector23(radius, Math.max(height, rounded)));
|
|
2289
2455
|
return points;
|
|
2290
2456
|
}
|
|
2291
|
-
var UP = new
|
|
2292
|
-
var AXES = [new
|
|
2293
|
-
var toVector = ({ x, y, z }) => new
|
|
2457
|
+
var UP = new Vector310(0, 1, 0);
|
|
2458
|
+
var AXES = [new Vector310(1, 0, 0), new Vector310(0, 1, 0), new Vector310(0, 0, 1)];
|
|
2459
|
+
var toVector = ({ x, y, z }) => new Vector310(x, y, z);
|
|
2294
2460
|
var squareTo = (w, along) => {
|
|
2295
2461
|
const wanted = along ? toVector(along) : null;
|
|
2296
2462
|
const flat = wanted?.clone().addScaledVector(w, -wanted.dot(w));
|
|
@@ -2310,7 +2476,7 @@ function toolMarkShape(mark) {
|
|
|
2310
2476
|
if (!(mark.diameter > 0) || axis.lengthSq() === 0) return null;
|
|
2311
2477
|
const w = axis.normalize();
|
|
2312
2478
|
const u = squareTo(w, mark.across);
|
|
2313
|
-
const v = new
|
|
2479
|
+
const v = new Vector310().crossVectors(w, u);
|
|
2314
2480
|
const radius = mark.diameter / 2;
|
|
2315
2481
|
const corner = Math.min(Math.max(mark.cornerRadius ?? 0, 0), radius);
|
|
2316
2482
|
const height = Math.max(mark.height, corner);
|
|
@@ -2340,7 +2506,7 @@ function toolMarkShape(mark) {
|
|
|
2340
2506
|
}
|
|
2341
2507
|
|
|
2342
2508
|
// src/tool-marks.tsx
|
|
2343
|
-
import { jsx as jsx10, jsxs as
|
|
2509
|
+
import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
2344
2510
|
var BODY = { color: 16317180, opacity: 0.32 };
|
|
2345
2511
|
var NO_POINTER2 = { pointerEvents: "none" };
|
|
2346
2512
|
var ignoreRay = () => void 0;
|
|
@@ -2354,7 +2520,7 @@ var ToolMarks = ({ marks, visible = true, labelClassName, theme }) => {
|
|
|
2354
2520
|
[marks]
|
|
2355
2521
|
);
|
|
2356
2522
|
const label = labelClassName ? `${MEASURE_LABEL_CLASS} ${labelClassName}` : MEASURE_LABEL_CLASS;
|
|
2357
|
-
return /* @__PURE__ */ jsx10("group", { visible, userData: { [EXCLUDE_FROM_FRAME]: true }, children: shapes.map(({ mark, shape }, index) => /* @__PURE__ */
|
|
2523
|
+
return /* @__PURE__ */ jsx10("group", { visible, userData: { [EXCLUDE_FROM_FRAME]: true }, children: shapes.map(({ mark, shape }, index) => /* @__PURE__ */ jsxs7("group", { children: [
|
|
2358
2524
|
/* @__PURE__ */ jsx10(ToolBody, { shape }),
|
|
2359
2525
|
[...shape.rims, shape.dimension, ...shape.ticks].map((points, line) => /* @__PURE__ */ jsx10(
|
|
2360
2526
|
Line2,
|
|
@@ -2369,16 +2535,16 @@ var ToolMarks = ({ marks, visible = true, labelClassName, theme }) => {
|
|
|
2369
2535
|
},
|
|
2370
2536
|
line
|
|
2371
2537
|
)),
|
|
2372
|
-
mark.label && visible ? /* @__PURE__ */ jsx10(Html2, { position: shape.labelAt, center: true, zIndexRange: [0, 0], style: NO_POINTER2, children: /* @__PURE__ */
|
|
2538
|
+
mark.label && visible ? /* @__PURE__ */ jsx10(Html2, { position: shape.labelAt, center: true, zIndexRange: [0, 0], style: NO_POINTER2, children: /* @__PURE__ */ jsxs7("div", { className: label, "data-measure-label": "tool", children: [
|
|
2373
2539
|
/* @__PURE__ */ jsx10("span", { "data-measure-value": true, children: mark.label }),
|
|
2374
|
-
mark.note ? /* @__PURE__ */
|
|
2540
|
+
mark.note ? /* @__PURE__ */ jsxs7("span", { "data-measure-note": true, children: [
|
|
2375
2541
|
" ",
|
|
2376
2542
|
mark.note
|
|
2377
2543
|
] }) : null
|
|
2378
2544
|
] }) }) : null
|
|
2379
2545
|
] }, index)) });
|
|
2380
2546
|
};
|
|
2381
|
-
var ToolBody = ({ shape }) => /* @__PURE__ */
|
|
2547
|
+
var ToolBody = ({ shape }) => /* @__PURE__ */ jsxs7(
|
|
2382
2548
|
"mesh",
|
|
2383
2549
|
{
|
|
2384
2550
|
position: shape.base,
|
|
@@ -2554,6 +2720,7 @@ export {
|
|
|
2554
2720
|
excludedFromFrame,
|
|
2555
2721
|
featureTriangles,
|
|
2556
2722
|
featureTypeRank,
|
|
2723
|
+
findSharpCorners,
|
|
2557
2724
|
fitDistance,
|
|
2558
2725
|
fixedBoxStockBounds,
|
|
2559
2726
|
focusForPick,
|
|
@@ -2602,10 +2769,12 @@ export {
|
|
|
2602
2769
|
sectionOffset,
|
|
2603
2770
|
sectionOptionsFromState,
|
|
2604
2771
|
sectionPlane,
|
|
2772
|
+
sharpCornerPositions,
|
|
2605
2773
|
smoothRegionNormals,
|
|
2606
2774
|
snapAt,
|
|
2607
2775
|
squaredUp,
|
|
2608
2776
|
startPosition,
|
|
2777
|
+
surfaceCreases,
|
|
2609
2778
|
surfaceUnderRay,
|
|
2610
2779
|
targetBoundary,
|
|
2611
2780
|
themesEqual,
|