@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
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
useRef as useRef6,
|
|
12
12
|
useSyncExternalStore
|
|
13
13
|
} from "react";
|
|
14
|
-
import { Vector3 as
|
|
14
|
+
import { Vector3 as Vector311 } from "three";
|
|
15
15
|
|
|
16
16
|
// src/model/directions.ts
|
|
17
17
|
var EPSILON = 1e-6;
|
|
@@ -193,14 +193,31 @@ function applyHighlightLayers(part, layers, theme) {
|
|
|
193
193
|
}
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
+
// src/render/focus.ts
|
|
197
|
+
var DEFAULT_FOCUS_OPACITY = 0.15;
|
|
198
|
+
function focusOpacity(options) {
|
|
199
|
+
return Math.min(Math.max(options?.opacity ?? DEFAULT_FOCUS_OPACITY, 0), 1);
|
|
200
|
+
}
|
|
201
|
+
function focusStateKey(options, selection) {
|
|
202
|
+
return `${options === void 0 ? "off" : `on:${options.opacity ?? ""}`}|${selection.join(" ")}`;
|
|
203
|
+
}
|
|
204
|
+
function focusedRegions(model, selection) {
|
|
205
|
+
const regions = /* @__PURE__ */ new Set();
|
|
206
|
+
for (const tag of selection) {
|
|
207
|
+
for (const region of model.regionIndex.regionsForFeature(tag)) regions.add(region);
|
|
208
|
+
}
|
|
209
|
+
return regions;
|
|
210
|
+
}
|
|
211
|
+
|
|
196
212
|
// src/render/section.ts
|
|
197
|
-
import { Plane, Vector3 as
|
|
213
|
+
import { Plane, Vector3 as Vector33 } from "three";
|
|
198
214
|
|
|
199
215
|
// src/render/camera.ts
|
|
200
216
|
import { OrthographicCamera, Vector3 } from "three";
|
|
201
217
|
var PERSPECTIVE_FOV = 30;
|
|
202
218
|
var DEFAULT_FIT_MARGIN = 1.2;
|
|
203
219
|
var EXCLUDE_FROM_FRAME = "viewerExcludeFromFrame";
|
|
220
|
+
var STOCK_OBJECT = "viewerStock";
|
|
204
221
|
function defaultBounds() {
|
|
205
222
|
return { center: new Vector3(0, 0, 0), radius: 1 };
|
|
206
223
|
}
|
|
@@ -221,16 +238,30 @@ function boundsFromBox(box) {
|
|
|
221
238
|
return { center, radius: radius > 0 ? radius : 1 };
|
|
222
239
|
}
|
|
223
240
|
function contentBounds(root, into) {
|
|
241
|
+
return measureBounds(root, into, false);
|
|
242
|
+
}
|
|
243
|
+
function partBounds(root, into) {
|
|
244
|
+
return measureBounds(root, into, true);
|
|
245
|
+
}
|
|
246
|
+
function measureBounds(root, into, partOnly) {
|
|
224
247
|
into.makeEmpty();
|
|
225
248
|
root.updateWorldMatrix(true, true);
|
|
226
249
|
root.traverse((object) => {
|
|
227
|
-
if (excludedFromFrame(object, root)) return;
|
|
250
|
+
if (partOnly ? excludedFromPart(object, root) : excludedFromFrame(object, root)) return;
|
|
228
251
|
if ("isMesh" in object || "isLine" in object || "isPoints" in object) {
|
|
229
252
|
into.expandByObject(object);
|
|
230
253
|
}
|
|
231
254
|
});
|
|
232
255
|
return boundsFromBox(into);
|
|
233
256
|
}
|
|
257
|
+
function excludedFromPart(object, root) {
|
|
258
|
+
let current = object;
|
|
259
|
+
while (current && current !== root) {
|
|
260
|
+
if (current.userData[STOCK_OBJECT]) return true;
|
|
261
|
+
current = current.parent;
|
|
262
|
+
}
|
|
263
|
+
return excludedFromFrame(object, root);
|
|
264
|
+
}
|
|
234
265
|
function excludedFromFrame(object, root) {
|
|
235
266
|
let current = object;
|
|
236
267
|
while (current && current !== root) {
|
|
@@ -351,6 +382,206 @@ function currentViewDirection(camera, target, into) {
|
|
|
351
382
|
return into.normalize();
|
|
352
383
|
}
|
|
353
384
|
|
|
385
|
+
// src/render/measure.ts
|
|
386
|
+
import { Vector2, Vector3 as Vector32 } from "three";
|
|
387
|
+
var MEASURE_RENDER_ORDER = 7;
|
|
388
|
+
var AXIS_COLORS = { x: 16739179, y: 7331978, z: 7314431 };
|
|
389
|
+
var SNAP_PIXELS = {
|
|
390
|
+
vertex: 14,
|
|
391
|
+
midpoint: 12,
|
|
392
|
+
edge: 9
|
|
393
|
+
};
|
|
394
|
+
var SNAP_MARKER_PIXELS = {
|
|
395
|
+
vertex: 6,
|
|
396
|
+
midpoint: 5,
|
|
397
|
+
edge: 4,
|
|
398
|
+
face: 3.5
|
|
399
|
+
};
|
|
400
|
+
var MEASURE_MARKER_PIXELS = 3.5;
|
|
401
|
+
var MEASURE_LINE_PIXELS = {
|
|
402
|
+
line: 2,
|
|
403
|
+
leg: 1.5,
|
|
404
|
+
edge: 3
|
|
405
|
+
};
|
|
406
|
+
var DELTA_DASH_PIXELS = 6;
|
|
407
|
+
var ANGLE_ARC_FRACTION = 0.3;
|
|
408
|
+
var ANGLE_ARC_SEGMENTS = 24;
|
|
409
|
+
function snapAt(hit, edges, camera, viewport) {
|
|
410
|
+
const face = {
|
|
411
|
+
kind: "face",
|
|
412
|
+
point: hit.point.clone(),
|
|
413
|
+
normal: hit.normal.clone(),
|
|
414
|
+
edge: null
|
|
415
|
+
};
|
|
416
|
+
if (!edges) return face;
|
|
417
|
+
const positions = edges.positions;
|
|
418
|
+
const segments = Math.floor(positions.length / 6);
|
|
419
|
+
if (segments === 0) return face;
|
|
420
|
+
const inverse = edges.matrixWorld.clone().invert();
|
|
421
|
+
const p = hit.point.clone().applyMatrix4(inverse);
|
|
422
|
+
const n = hit.normal.clone().transformDirection(inverse);
|
|
423
|
+
const reach = screenLength(camera, hit.point, viewport, SNAP_PIXELS.vertex) * 1.5;
|
|
424
|
+
const reachSq = reach * reach;
|
|
425
|
+
const pointer = screenPoint(camera, hit.point, viewport);
|
|
426
|
+
const best = {
|
|
427
|
+
vertex: { distance: Number.POSITIVE_INFINITY, index: -1, t: 0 },
|
|
428
|
+
midpoint: { distance: Number.POSITIVE_INFINITY, index: -1, t: 0 },
|
|
429
|
+
edge: { distance: Number.POSITIVE_INFINITY, index: -1, t: 0 }
|
|
430
|
+
};
|
|
431
|
+
const a = new Vector32();
|
|
432
|
+
const b = new Vector32();
|
|
433
|
+
const ab = new Vector32();
|
|
434
|
+
const ap = new Vector32();
|
|
435
|
+
const q = new Vector32();
|
|
436
|
+
const pixel = new Vector2();
|
|
437
|
+
const consider = (kind, point, index, t) => {
|
|
438
|
+
const distance = screenPoint(
|
|
439
|
+
camera,
|
|
440
|
+
q.copy(point).applyMatrix4(edges.matrixWorld),
|
|
441
|
+
viewport,
|
|
442
|
+
pixel
|
|
443
|
+
).distanceTo(pointer);
|
|
444
|
+
if (distance <= SNAP_PIXELS[kind] && distance < best[kind].distance) {
|
|
445
|
+
best[kind] = { distance, index, t };
|
|
446
|
+
}
|
|
447
|
+
};
|
|
448
|
+
for (let index = 0; index < segments; index += 1) {
|
|
449
|
+
const offset = index * 6;
|
|
450
|
+
a.set(positions[offset], positions[offset + 1], positions[offset + 2]);
|
|
451
|
+
b.set(positions[offset + 3], positions[offset + 4], positions[offset + 5]);
|
|
452
|
+
if (Math.abs(ap.subVectors(a, p).dot(n)) > reach) continue;
|
|
453
|
+
if (Math.abs(ap.subVectors(b, p).dot(n)) > reach) continue;
|
|
454
|
+
ab.subVectors(b, a);
|
|
455
|
+
ap.subVectors(p, a);
|
|
456
|
+
const lengthSq = ab.lengthSq();
|
|
457
|
+
const t = lengthSq === 0 ? 0 : Math.min(1, Math.max(0, ap.dot(ab) / lengthSq));
|
|
458
|
+
q.copy(a).addScaledVector(ab, t);
|
|
459
|
+
if (q.distanceToSquared(p) > reachSq) continue;
|
|
460
|
+
consider("vertex", a, index, 0);
|
|
461
|
+
consider("vertex", b, index, 1);
|
|
462
|
+
consider("midpoint", q.copy(a).addScaledVector(ab, 0.5), index, 0.5);
|
|
463
|
+
consider("edge", q.copy(a).addScaledVector(ab, t), index, t);
|
|
464
|
+
}
|
|
465
|
+
for (const kind of ["vertex", "midpoint", "edge"]) {
|
|
466
|
+
const found = best[kind];
|
|
467
|
+
if (found.index < 0) continue;
|
|
468
|
+
const offset = found.index * 6;
|
|
469
|
+
const start = new Vector32(positions[offset], positions[offset + 1], positions[offset + 2]);
|
|
470
|
+
const end = new Vector32(positions[offset + 3], positions[offset + 4], positions[offset + 5]);
|
|
471
|
+
const point = start.clone().lerp(end, found.t);
|
|
472
|
+
start.applyMatrix4(edges.matrixWorld);
|
|
473
|
+
end.applyMatrix4(edges.matrixWorld);
|
|
474
|
+
point.applyMatrix4(edges.matrixWorld);
|
|
475
|
+
return {
|
|
476
|
+
kind,
|
|
477
|
+
point,
|
|
478
|
+
normal: hit.normal.clone(),
|
|
479
|
+
edge: kind === "vertex" ? null : [start, end]
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
return face;
|
|
483
|
+
}
|
|
484
|
+
function screenPoint(camera, point, viewport, into = new Vector2()) {
|
|
485
|
+
const ndc = point.clone().project(camera);
|
|
486
|
+
return into.set((ndc.x + 1) / 2 * viewport.width, (1 - ndc.y) / 2 * viewport.height);
|
|
487
|
+
}
|
|
488
|
+
var POINTS_PER_MEASUREMENT = {
|
|
489
|
+
distance: 2,
|
|
490
|
+
angle: 3
|
|
491
|
+
};
|
|
492
|
+
function measurementFromPoints(kind, points, id) {
|
|
493
|
+
if (points.length < POINTS_PER_MEASUREMENT[kind]) return null;
|
|
494
|
+
const [a, b, c] = points;
|
|
495
|
+
if (kind === "distance") return { id, kind, points: [copy(a), copy(b)] };
|
|
496
|
+
return { id, kind, points: [copy(a), copy(b), copy(c)] };
|
|
497
|
+
}
|
|
498
|
+
function nextMeasurementId(held) {
|
|
499
|
+
return held.reduce((top, entry) => Math.max(top, entry.id), 0) + 1;
|
|
500
|
+
}
|
|
501
|
+
function distanceBetween(a, b) {
|
|
502
|
+
return Math.hypot(b.x - a.x, b.y - a.y, b.z - a.z);
|
|
503
|
+
}
|
|
504
|
+
function deltaBetween(a, b) {
|
|
505
|
+
return { x: b.x - a.x, y: b.y - a.y, z: b.z - a.z };
|
|
506
|
+
}
|
|
507
|
+
function midpoint(a, b) {
|
|
508
|
+
return { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2, z: (a.z + b.z) / 2 };
|
|
509
|
+
}
|
|
510
|
+
function angleAt(vertex, a, b) {
|
|
511
|
+
const u = new Vector32(a.x - vertex.x, a.y - vertex.y, a.z - vertex.z);
|
|
512
|
+
const w = new Vector32(b.x - vertex.x, b.y - vertex.y, b.z - vertex.z);
|
|
513
|
+
if (u.lengthSq() === 0 || w.lengthSq() === 0) return 0;
|
|
514
|
+
return u.angleTo(w) * 180 / Math.PI;
|
|
515
|
+
}
|
|
516
|
+
function lockToAxis(from, to) {
|
|
517
|
+
const delta = deltaBetween(from, to);
|
|
518
|
+
let axis = "x";
|
|
519
|
+
for (const candidate of ["y", "z"]) {
|
|
520
|
+
if (Math.abs(delta[candidate]) > Math.abs(delta[axis])) axis = candidate;
|
|
521
|
+
}
|
|
522
|
+
return { axis, point: { ...from, [axis]: to[axis] } };
|
|
523
|
+
}
|
|
524
|
+
function deltaLegs(a, b) {
|
|
525
|
+
const delta = deltaBetween(a, b);
|
|
526
|
+
const threshold = Math.max(1e-9, distanceBetween(a, b) * 1e-6);
|
|
527
|
+
const legs = [];
|
|
528
|
+
let cursor = copy(a);
|
|
529
|
+
for (const axis of ["x", "y", "z"]) {
|
|
530
|
+
if (Math.abs(delta[axis]) <= threshold) continue;
|
|
531
|
+
const to = { ...cursor, [axis]: b[axis] };
|
|
532
|
+
legs.push({ axis, from: cursor, to, length: Math.abs(delta[axis]) });
|
|
533
|
+
cursor = to;
|
|
534
|
+
}
|
|
535
|
+
return legs.length > 1 ? legs : [];
|
|
536
|
+
}
|
|
537
|
+
function angleArc(vertex, a, b, radius, segments = ANGLE_ARC_SEGMENTS) {
|
|
538
|
+
const v = new Vector32(vertex.x, vertex.y, vertex.z);
|
|
539
|
+
const u = new Vector32(a.x, a.y, a.z).sub(v);
|
|
540
|
+
const w = new Vector32(b.x, b.y, b.z).sub(v);
|
|
541
|
+
if (u.lengthSq() === 0 || w.lengthSq() === 0) return [];
|
|
542
|
+
u.normalize();
|
|
543
|
+
w.normalize();
|
|
544
|
+
const theta = u.angleTo(w);
|
|
545
|
+
const sine = Math.sin(theta);
|
|
546
|
+
if (sine < 1e-6) {
|
|
547
|
+
return [v.clone().addScaledVector(u, radius), v.clone().addScaledVector(w, radius)];
|
|
548
|
+
}
|
|
549
|
+
const points = [];
|
|
550
|
+
for (let i = 0; i <= segments; i += 1) {
|
|
551
|
+
const t = i / segments;
|
|
552
|
+
const direction = u.clone().multiplyScalar(Math.sin((1 - t) * theta) / sine).addScaledVector(w, Math.sin(t * theta) / sine);
|
|
553
|
+
points.push(v.clone().addScaledVector(direction, radius));
|
|
554
|
+
}
|
|
555
|
+
return points;
|
|
556
|
+
}
|
|
557
|
+
function angleArcRadius(vertex, a, b) {
|
|
558
|
+
return Math.min(distanceBetween(vertex, a), distanceBetween(vertex, b)) * ANGLE_ARC_FRACTION;
|
|
559
|
+
}
|
|
560
|
+
function formatMillimetres(mm, digits = 2) {
|
|
561
|
+
return `${mm.toFixed(digits)} mm`;
|
|
562
|
+
}
|
|
563
|
+
function formatDegrees(degrees, digits = 1) {
|
|
564
|
+
return `${degrees.toFixed(digits)}\xB0`;
|
|
565
|
+
}
|
|
566
|
+
function measurementLabel(measurement, format = formatMillimetres) {
|
|
567
|
+
if (measurement.kind === "distance") {
|
|
568
|
+
const [a2, b2] = measurement.points;
|
|
569
|
+
return format(distanceBetween(a2, b2));
|
|
570
|
+
}
|
|
571
|
+
const [a, vertex, b] = measurement.points;
|
|
572
|
+
return formatDegrees(angleAt(vertex, a, b));
|
|
573
|
+
}
|
|
574
|
+
function measurementLabelAnchor(measurement) {
|
|
575
|
+
if (measurement.kind === "distance") return midpoint(measurement.points[0], measurement.points[1]);
|
|
576
|
+
const [a, vertex, b] = measurement.points;
|
|
577
|
+
const arc = angleArc(vertex, a, b, angleArcRadius(vertex, a, b) * 1.6, 2);
|
|
578
|
+
const middle = arc[1] ?? arc[0];
|
|
579
|
+
return middle ? { x: middle.x, y: middle.y, z: middle.z } : copy(vertex);
|
|
580
|
+
}
|
|
581
|
+
function copy(v) {
|
|
582
|
+
return { x: v.x, y: v.y, z: v.z };
|
|
583
|
+
}
|
|
584
|
+
|
|
354
585
|
// src/render/section.ts
|
|
355
586
|
var SECTION_RENDER_ORDER = {
|
|
356
587
|
stencil: 1,
|
|
@@ -361,6 +592,7 @@ var SECTION_RENDER_ORDER = {
|
|
|
361
592
|
};
|
|
362
593
|
var START_DEPTH = 5e-3;
|
|
363
594
|
var HANDLE_PIXELS = 78;
|
|
595
|
+
var SECTION_GIZMO_FRAME_SCALE = 1.1;
|
|
364
596
|
var CAP_HATCH = {
|
|
365
597
|
pitch: 9,
|
|
366
598
|
line: 1.25,
|
|
@@ -371,7 +603,7 @@ var AXES_PLANE_SCALE = 1.2;
|
|
|
371
603
|
var PREVIEW_SCALE = 0.125;
|
|
372
604
|
var OUTLINE_SCALE = 1.2;
|
|
373
605
|
var EPSILON2 = 1e-9;
|
|
374
|
-
var ARROW_AXIS = new
|
|
606
|
+
var ARROW_AXIS = new Vector33(0, 1, 0);
|
|
375
607
|
var DEFAULT_SECTION_NORMAL = { x: 0, y: 0, z: 1 };
|
|
376
608
|
var DISABLED_SECTION = {
|
|
377
609
|
enabled: false,
|
|
@@ -380,8 +612,25 @@ var DISABLED_SECTION = {
|
|
|
380
612
|
constant: 0,
|
|
381
613
|
plane: null,
|
|
382
614
|
depth: null,
|
|
615
|
+
cutDistance: 0,
|
|
383
616
|
depthRange: null
|
|
384
617
|
};
|
|
618
|
+
function sectionMeasurement(state) {
|
|
619
|
+
return `${(state.depth ?? state.cutDistance ?? 0).toFixed(2)} mm`;
|
|
620
|
+
}
|
|
621
|
+
function sectionDirectionColor(normal) {
|
|
622
|
+
const x = Math.abs(normal.x);
|
|
623
|
+
const y = Math.abs(normal.y);
|
|
624
|
+
const z = Math.abs(normal.z);
|
|
625
|
+
const total = x + y + z || 1;
|
|
626
|
+
const channel = (shift) => Math.round(
|
|
627
|
+
((AXIS_COLORS.x >> shift & 255) * x + (AXIS_COLORS.y >> shift & 255) * y + (AXIS_COLORS.z >> shift & 255) * z) / total
|
|
628
|
+
);
|
|
629
|
+
return channel(16) << 16 | channel(8) << 8 | channel(0);
|
|
630
|
+
}
|
|
631
|
+
function sectionHandleColor(themeColor, directionColor2) {
|
|
632
|
+
return themeColor ?? directionColor2;
|
|
633
|
+
}
|
|
385
634
|
function sectionOptionsFromState(state) {
|
|
386
635
|
if (state.plane) {
|
|
387
636
|
return { enabled: state.enabled, plane: state.plane, depth: state.depth ?? 0 };
|
|
@@ -389,8 +638,8 @@ function sectionOptionsFromState(state) {
|
|
|
389
638
|
return { enabled: state.enabled, normal: state.normal, offset: state.offset };
|
|
390
639
|
}
|
|
391
640
|
function axesPlanes(box, eye) {
|
|
392
|
-
const centre = box.getCenter(new
|
|
393
|
-
const extent = box.getSize(new
|
|
641
|
+
const centre = box.getCenter(new Vector33());
|
|
642
|
+
const extent = box.getSize(new Vector33());
|
|
394
643
|
const largest = Math.max(extent.x, extent.y, extent.z);
|
|
395
644
|
const size = largest * AXES_PLANE_SCALE;
|
|
396
645
|
const offset = largest * AXES_PLANE_OFFSET;
|
|
@@ -425,7 +674,7 @@ function axesPlanes(box, eye) {
|
|
|
425
674
|
function hitUnderRay(raycaster, root) {
|
|
426
675
|
for (const hit of raycaster.intersectObjects(root.children, true)) {
|
|
427
676
|
if (!("isMesh" in hit.object) || !hit.face) continue;
|
|
428
|
-
if (!hit.object.visible ||
|
|
677
|
+
if (!hit.object.visible || excludedFromPart(hit.object, root)) continue;
|
|
429
678
|
if (clippedAway(hit)) continue;
|
|
430
679
|
return hit;
|
|
431
680
|
}
|
|
@@ -447,21 +696,21 @@ function surfaceUnderRay(raycaster, root) {
|
|
|
447
696
|
const normal = hit.face.normal.clone().transformDirection(hit.object.matrixWorld);
|
|
448
697
|
return { point: hit.point, normal };
|
|
449
698
|
}
|
|
450
|
-
function sectionAnchor(box, plane, into = new
|
|
699
|
+
function sectionAnchor(box, plane, into = new Vector33()) {
|
|
451
700
|
const centre = box.getCenter(into);
|
|
452
701
|
return centre.addScaledVector(plane.normal, -(plane.constant + plane.normal.dot(centre)));
|
|
453
702
|
}
|
|
454
703
|
var PICKED_SURFACE_LABEL = "Part surface";
|
|
455
704
|
function unit(v) {
|
|
456
|
-
const vector = new
|
|
705
|
+
const vector = new Vector33(v.x, v.y, v.z);
|
|
457
706
|
return vector.lengthSq() === 0 ? vector.set(0, 0, 1) : vector.normalize();
|
|
458
707
|
}
|
|
459
708
|
function clamp01(value) {
|
|
460
709
|
return Math.min(1, Math.max(0, value));
|
|
461
710
|
}
|
|
462
|
-
function
|
|
711
|
+
function projectedBounds(box, normal) {
|
|
463
712
|
const axis = unit(normal);
|
|
464
|
-
const corner = new
|
|
713
|
+
const corner = new Vector33();
|
|
465
714
|
let low = Number.POSITIVE_INFINITY;
|
|
466
715
|
let high = Number.NEGATIVE_INFINITY;
|
|
467
716
|
for (let i = 0; i < 8; i += 1) {
|
|
@@ -474,9 +723,17 @@ function sectionBounds(box, normal) {
|
|
|
474
723
|
low = Math.min(low, distance);
|
|
475
724
|
high = Math.max(high, distance);
|
|
476
725
|
}
|
|
726
|
+
return { low, high };
|
|
727
|
+
}
|
|
728
|
+
function sectionBounds(box, normal) {
|
|
729
|
+
const { low, high } = projectedBounds(box, normal);
|
|
477
730
|
const margin = Math.max((high - low) * 5e-3, 1e-6);
|
|
478
731
|
return { min: -(high + margin), max: -(low - margin) };
|
|
479
732
|
}
|
|
733
|
+
function sectionCutDistance(box, normal, constant) {
|
|
734
|
+
const { low, high } = projectedBounds(box, normal);
|
|
735
|
+
return Math.max(0, Math.min(high - low, -constant - low));
|
|
736
|
+
}
|
|
480
737
|
function sectionConstant(bounds, t) {
|
|
481
738
|
return bounds.max + clamp01(t) * (bounds.min - bounds.max);
|
|
482
739
|
}
|
|
@@ -485,7 +742,7 @@ function sectionOffset(bounds, constant) {
|
|
|
485
742
|
return span === 0 ? 0 : clamp01((constant - bounds.max) / span);
|
|
486
743
|
}
|
|
487
744
|
function sectionDepth(normal, anchor, constant) {
|
|
488
|
-
return -unit(normal).dot(new
|
|
745
|
+
return -unit(normal).dot(new Vector33(anchor.x, anchor.y, anchor.z)) - constant;
|
|
489
746
|
}
|
|
490
747
|
function sectionDepthConstant(normal, anchor, depth) {
|
|
491
748
|
return sectionDepth(normal, anchor, depth);
|
|
@@ -504,7 +761,7 @@ function sectionFromPick(surface, label = PICKED_SURFACE_LABEL) {
|
|
|
504
761
|
};
|
|
505
762
|
}
|
|
506
763
|
function pickedStartDepth(box) {
|
|
507
|
-
return box.getSize(new
|
|
764
|
+
return box.getSize(new Vector33()).length() * START_DEPTH;
|
|
508
765
|
}
|
|
509
766
|
function sectionPlane(box, normal, offset, into = new Plane()) {
|
|
510
767
|
const axis = unit(normal);
|
|
@@ -512,12 +769,12 @@ function sectionPlane(box, normal, offset, into = new Plane()) {
|
|
|
512
769
|
}
|
|
513
770
|
function dragPlane(axis, view, point, into = new Plane()) {
|
|
514
771
|
const along = axis.lengthSq() === 0 ? ARROW_AXIS.clone() : axis.clone().normalize();
|
|
515
|
-
const side = new
|
|
772
|
+
const side = new Vector33().crossVectors(view, along);
|
|
516
773
|
if (side.lengthSq() < EPSILON2) side.copy(perpendicular(along));
|
|
517
774
|
return into.setFromNormalAndCoplanarPoint(side.cross(along).normalize(), point);
|
|
518
775
|
}
|
|
519
776
|
function perpendicular(axis) {
|
|
520
|
-
const candidate = Math.abs(axis.x) < 0.9 ? new
|
|
777
|
+
const candidate = Math.abs(axis.x) < 0.9 ? new Vector33(1, 0, 0) : new Vector33(0, 1, 0);
|
|
521
778
|
return candidate.cross(axis).normalize();
|
|
522
779
|
}
|
|
523
780
|
|
|
@@ -593,15 +850,17 @@ import {
|
|
|
593
850
|
Box3,
|
|
594
851
|
Color,
|
|
595
852
|
DataTexture,
|
|
853
|
+
DoubleSide,
|
|
596
854
|
Float32BufferAttribute as Float32BufferAttribute2,
|
|
597
855
|
Group,
|
|
598
856
|
LineBasicMaterial,
|
|
599
857
|
LineSegments,
|
|
600
858
|
Mesh,
|
|
601
859
|
MeshLambertMaterial,
|
|
860
|
+
RedFormat,
|
|
602
861
|
RGBAFormat,
|
|
603
862
|
UnsignedByteType,
|
|
604
|
-
Vector3 as
|
|
863
|
+
Vector3 as Vector34
|
|
605
864
|
} from "three";
|
|
606
865
|
|
|
607
866
|
// src/render/edges.ts
|
|
@@ -700,6 +959,13 @@ function createPart(model, geometry, theme) {
|
|
|
700
959
|
const state = new Uint8Array(width * 4);
|
|
701
960
|
const stateTexture = new DataTexture(state, width, 1, RGBAFormat, UnsignedByteType);
|
|
702
961
|
stateTexture.needsUpdate = true;
|
|
962
|
+
const opacity = new Uint8Array(width).fill(255);
|
|
963
|
+
const opacityTexture = new DataTexture(opacity, width, 1, RedFormat, UnsignedByteType);
|
|
964
|
+
opacityTexture.needsUpdate = true;
|
|
965
|
+
const focusState = { value: false };
|
|
966
|
+
const wireframe = { value: false };
|
|
967
|
+
let focused = false;
|
|
968
|
+
let currentTheme = theme;
|
|
703
969
|
const material = new MeshLambertMaterial({
|
|
704
970
|
color: theme.part,
|
|
705
971
|
emissive: theme.partEmissive,
|
|
@@ -709,40 +975,64 @@ function createPart(model, geometry, theme) {
|
|
|
709
975
|
polygonOffsetFactor: 1,
|
|
710
976
|
polygonOffsetUnits: 1
|
|
711
977
|
});
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
"
|
|
716
|
-
|
|
978
|
+
const configureShader = (target, opaqueFocusPass) => {
|
|
979
|
+
target.onBeforeCompile = (shader) => {
|
|
980
|
+
shader.uniforms["uRegionState"] = { value: stateTexture };
|
|
981
|
+
shader.uniforms["uRegionOpacity"] = { value: opacityTexture };
|
|
982
|
+
shader.uniforms["uWireframe"] = wireframe;
|
|
983
|
+
shader.uniforms["uFocus"] = focusState;
|
|
984
|
+
shader.uniforms["uOpaqueFocusPass"] = { value: opaqueFocusPass };
|
|
985
|
+
shader.vertexShader = shader.vertexShader.replace(
|
|
986
|
+
"#include <common>",
|
|
987
|
+
`#include <common>
|
|
717
988
|
attribute float ${REGION_ATTRIBUTE};
|
|
718
989
|
varying float vRegion;`
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
990
|
+
).replace(
|
|
991
|
+
"#include <begin_vertex>",
|
|
992
|
+
`#include <begin_vertex>
|
|
722
993
|
vRegion = ${REGION_ATTRIBUTE};`
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
994
|
+
);
|
|
995
|
+
shader.fragmentShader = shader.fragmentShader.replace(
|
|
996
|
+
"#include <common>",
|
|
997
|
+
`#include <common>
|
|
727
998
|
uniform sampler2D uRegionState;
|
|
999
|
+
uniform sampler2D uRegionOpacity;
|
|
1000
|
+
uniform bool uWireframe;
|
|
1001
|
+
uniform bool uFocus;
|
|
1002
|
+
uniform bool uOpaqueFocusPass;
|
|
728
1003
|
varying float vRegion;
|
|
729
1004
|
vec4 regionState;`
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
1005
|
+
).replace(
|
|
1006
|
+
"#include <color_fragment>",
|
|
1007
|
+
`#include <color_fragment>
|
|
733
1008
|
regionState = texelFetch(uRegionState, ivec2(int(vRegion + 0.5), 0), 0);
|
|
734
1009
|
diffuseColor.rgb = mix(diffuseColor.rgb, regionState.rgb, regionState.a);
|
|
1010
|
+
float regionOpacity = texelFetch(uRegionOpacity, ivec2(int(vRegion + 0.5), 0), 0).r;
|
|
1011
|
+
if (uFocus && uOpaqueFocusPass && regionOpacity < 0.999) discard;
|
|
1012
|
+
if (uFocus && !uOpaqueFocusPass && regionOpacity >= 0.999) discard;
|
|
1013
|
+
diffuseColor.a *= regionOpacity;
|
|
1014
|
+
if (uWireframe) diffuseColor.a *= regionState.a;
|
|
735
1015
|
`
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
1016
|
+
).replace(
|
|
1017
|
+
"#include <emissivemap_fragment>",
|
|
1018
|
+
`#include <emissivemap_fragment>
|
|
739
1019
|
totalEmissiveRadiance = mix(
|
|
740
1020
|
totalEmissiveRadiance,
|
|
741
1021
|
regionState.rgb * ${EMISSIVE_MIX.toFixed(2)},
|
|
742
1022
|
regionState.a
|
|
743
1023
|
);`
|
|
744
|
-
|
|
1024
|
+
);
|
|
1025
|
+
};
|
|
745
1026
|
};
|
|
1027
|
+
const focusMaterial = new MeshLambertMaterial({
|
|
1028
|
+
color: theme.part,
|
|
1029
|
+
emissive: theme.partEmissive,
|
|
1030
|
+
// A selected face can be viewed through the part from the side its normal
|
|
1031
|
+
// faces away from.
|
|
1032
|
+
side: DoubleSide
|
|
1033
|
+
});
|
|
1034
|
+
configureShader(focusMaterial, true);
|
|
1035
|
+
configureShader(material, false);
|
|
746
1036
|
const mesh = new Mesh(geometry, material);
|
|
747
1037
|
mesh.renderOrder = 3;
|
|
748
1038
|
const edgeGeometry = regionEdgesGeometry(geometry, model);
|
|
@@ -755,10 +1045,25 @@ function createPart(model, geometry, theme) {
|
|
|
755
1045
|
edges.renderOrder = 4;
|
|
756
1046
|
edges.raycast = () => {
|
|
757
1047
|
};
|
|
1048
|
+
const focusMesh = new Mesh(geometry, focusMaterial);
|
|
1049
|
+
focusMesh.renderOrder = 3;
|
|
1050
|
+
focusMesh.visible = false;
|
|
1051
|
+
focusMesh.raycast = () => {
|
|
1052
|
+
};
|
|
1053
|
+
const syncTransparency = () => {
|
|
1054
|
+
const transparent = wireframe.value || focused;
|
|
1055
|
+
if (material.transparent !== transparent || material.depthWrite !== !transparent) {
|
|
1056
|
+
material.transparent = transparent;
|
|
1057
|
+
material.depthWrite = !transparent;
|
|
1058
|
+
material.needsUpdate = true;
|
|
1059
|
+
}
|
|
1060
|
+
focusState.value = focused;
|
|
1061
|
+
focusMesh.visible = focused;
|
|
1062
|
+
};
|
|
758
1063
|
const object = new Group();
|
|
759
|
-
object.add(mesh, edges);
|
|
1064
|
+
object.add(focusMesh, mesh, edges);
|
|
760
1065
|
const scratchColor = new Color();
|
|
761
|
-
const scratchVector = new
|
|
1066
|
+
const scratchVector = new Vector34();
|
|
762
1067
|
const paintRegion = (region, color, weight) => {
|
|
763
1068
|
const column = texels.get(region);
|
|
764
1069
|
if (column === void 0) return;
|
|
@@ -796,6 +1101,27 @@ function createPart(model, geometry, theme) {
|
|
|
796
1101
|
state.fill(0);
|
|
797
1102
|
stateTexture.needsUpdate = true;
|
|
798
1103
|
},
|
|
1104
|
+
setFocus(selection, focus) {
|
|
1105
|
+
const regions = focus === void 0 ? null : focusedRegions(model, selection);
|
|
1106
|
+
const outside = focusOpacity(focus);
|
|
1107
|
+
let changed = false;
|
|
1108
|
+
let hasTransparency = false;
|
|
1109
|
+
for (const [region, column] of texels) {
|
|
1110
|
+
const value = regions === null || regions.size === 0 || regions.has(region) ? 255 : Math.round(outside * 255);
|
|
1111
|
+
if (opacity[column] !== value) {
|
|
1112
|
+
opacity[column] = value;
|
|
1113
|
+
changed = true;
|
|
1114
|
+
}
|
|
1115
|
+
hasTransparency ||= value < 255;
|
|
1116
|
+
}
|
|
1117
|
+
focused = hasTransparency;
|
|
1118
|
+
syncTransparency();
|
|
1119
|
+
if (changed) opacityTexture.needsUpdate = true;
|
|
1120
|
+
},
|
|
1121
|
+
regionOpacity(region) {
|
|
1122
|
+
const column = texels.get(region);
|
|
1123
|
+
return column === void 0 ? null : (opacity[column] ?? 0) / 255;
|
|
1124
|
+
},
|
|
799
1125
|
boxForFeature(tag) {
|
|
800
1126
|
const regions = model.regionIndex.regionsForFeature(tag);
|
|
801
1127
|
if (regions.length === 0) return null;
|
|
@@ -812,13 +1138,27 @@ function createPart(model, geometry, theme) {
|
|
|
812
1138
|
setClippingPlanes(planes) {
|
|
813
1139
|
const value = planes === null ? null : [...planes];
|
|
814
1140
|
material.clippingPlanes = value;
|
|
1141
|
+
focusMaterial.clippingPlanes = value;
|
|
815
1142
|
edgeMaterial.clippingPlanes = value;
|
|
816
1143
|
},
|
|
817
1144
|
setTheme(next) {
|
|
1145
|
+
currentTheme = next;
|
|
818
1146
|
material.color.setHex(next.part);
|
|
819
1147
|
material.emissive.setHex(next.partEmissive);
|
|
820
|
-
|
|
821
|
-
|
|
1148
|
+
focusMaterial.color.setHex(next.part);
|
|
1149
|
+
focusMaterial.emissive.setHex(next.partEmissive);
|
|
1150
|
+
edgeMaterial.color.setHex(wireframe.value ? next.part : next.edge);
|
|
1151
|
+
edgeMaterial.opacity = wireframe.value ? 1 : next.edgeOpacity;
|
|
1152
|
+
},
|
|
1153
|
+
setDisplay(display, showEdges = true) {
|
|
1154
|
+
const enabled = display === "wireframe";
|
|
1155
|
+
if (wireframe.value !== enabled) {
|
|
1156
|
+
wireframe.value = enabled;
|
|
1157
|
+
syncTransparency();
|
|
1158
|
+
}
|
|
1159
|
+
edges.visible = enabled || showEdges;
|
|
1160
|
+
edgeMaterial.color.setHex(enabled ? currentTheme.part : currentTheme.edge);
|
|
1161
|
+
edgeMaterial.opacity = enabled ? 1 : currentTheme.edgeOpacity;
|
|
822
1162
|
},
|
|
823
1163
|
dispose() {
|
|
824
1164
|
object.clear();
|
|
@@ -826,9 +1166,11 @@ function createPart(model, geometry, theme) {
|
|
|
826
1166
|
geometry.deleteAttribute(REGION_ATTRIBUTE);
|
|
827
1167
|
}
|
|
828
1168
|
material.dispose();
|
|
1169
|
+
focusMaterial.dispose();
|
|
829
1170
|
edgeGeometry.dispose();
|
|
830
1171
|
edgeMaterial.dispose();
|
|
831
1172
|
stateTexture.dispose();
|
|
1173
|
+
opacityTexture.dispose();
|
|
832
1174
|
}
|
|
833
1175
|
};
|
|
834
1176
|
}
|
|
@@ -962,6 +1304,7 @@ function buildPick(input) {
|
|
|
962
1304
|
triangleIndex: input.triangleIndex,
|
|
963
1305
|
point: input.point,
|
|
964
1306
|
normal: input.normal,
|
|
1307
|
+
...input.pointer === void 0 ? {} : { pointer: input.pointer },
|
|
965
1308
|
modifiers: input.modifiers ?? NO_MODIFIERS,
|
|
966
1309
|
doubled: input.doubled ?? false
|
|
967
1310
|
};
|
|
@@ -985,7 +1328,7 @@ import {
|
|
|
985
1328
|
useMemo as useMemo4,
|
|
986
1329
|
useRef as useRef3
|
|
987
1330
|
} from "react";
|
|
988
|
-
import { Box3 as Box33, Vector3 as
|
|
1331
|
+
import { Box3 as Box33, Vector3 as Vector38 } from "three";
|
|
989
1332
|
|
|
990
1333
|
// src/camera.tsx
|
|
991
1334
|
import { useFrame, useThree as useThree2 } from "@react-three/fiber";
|
|
@@ -1001,10 +1344,96 @@ import {
|
|
|
1001
1344
|
Raycaster,
|
|
1002
1345
|
Sphere,
|
|
1003
1346
|
Spherical,
|
|
1004
|
-
Vector2,
|
|
1005
|
-
Vector3 as
|
|
1347
|
+
Vector2 as Vector22,
|
|
1348
|
+
Vector3 as Vector35,
|
|
1006
1349
|
Vector4
|
|
1007
1350
|
} from "three";
|
|
1351
|
+
|
|
1352
|
+
// src/render/control-schemes.ts
|
|
1353
|
+
var CONTROL_SCHEME_OPTIONS = [
|
|
1354
|
+
{ value: "toolpath", label: "Toolpath" },
|
|
1355
|
+
{ value: "fusion", label: "Fusion" },
|
|
1356
|
+
{ value: "alias", label: "Alias" },
|
|
1357
|
+
{ value: "inventor", label: "Inventor" },
|
|
1358
|
+
{ value: "solidworks", label: "SolidWorks" },
|
|
1359
|
+
{ value: "tinkercad", label: "Tinkercad" },
|
|
1360
|
+
{ value: "powermill", label: "PowerMill" },
|
|
1361
|
+
{ value: "onshape", label: "Onshape" }
|
|
1362
|
+
];
|
|
1363
|
+
var DEFAULT_TOUCHES = {
|
|
1364
|
+
one: "rotate",
|
|
1365
|
+
two: "dolly-truck",
|
|
1366
|
+
three: "truck"
|
|
1367
|
+
};
|
|
1368
|
+
var wheelFor = (orthographic) => orthographic ? "zoom" : "dolly";
|
|
1369
|
+
var mapping = (environment, mouse, options, touches = DEFAULT_TOUCHES) => ({
|
|
1370
|
+
mouse: {
|
|
1371
|
+
left: "none",
|
|
1372
|
+
middle: "none",
|
|
1373
|
+
right: "none",
|
|
1374
|
+
wheel: wheelFor(environment.orthographic),
|
|
1375
|
+
...mouse
|
|
1376
|
+
},
|
|
1377
|
+
touches,
|
|
1378
|
+
...options
|
|
1379
|
+
});
|
|
1380
|
+
var resolveControlScheme = (scheme, environment) => {
|
|
1381
|
+
const { shift, ctrl } = environment.modifiers;
|
|
1382
|
+
switch (scheme) {
|
|
1383
|
+
case "fusion":
|
|
1384
|
+
case "inventor": {
|
|
1385
|
+
const rotating = shift;
|
|
1386
|
+
return mapping(
|
|
1387
|
+
environment,
|
|
1388
|
+
{ middle: rotating ? "rotate" : "truck", wheel: "none" },
|
|
1389
|
+
{ usesCadWheel: true, immediate: true },
|
|
1390
|
+
{
|
|
1391
|
+
one: "rotate",
|
|
1392
|
+
two: rotating ? "rotate" : "truck",
|
|
1393
|
+
three: "truck"
|
|
1394
|
+
}
|
|
1395
|
+
);
|
|
1396
|
+
}
|
|
1397
|
+
case "solidworks":
|
|
1398
|
+
return mapping(
|
|
1399
|
+
environment,
|
|
1400
|
+
{ middle: shift ? "zoom" : ctrl ? "truck" : "rotate" },
|
|
1401
|
+
{ usesCadWheel: false, immediate: false }
|
|
1402
|
+
);
|
|
1403
|
+
case "alias":
|
|
1404
|
+
return mapping(
|
|
1405
|
+
environment,
|
|
1406
|
+
{ left: "rotate", middle: "truck" },
|
|
1407
|
+
{ usesCadWheel: false, immediate: false }
|
|
1408
|
+
);
|
|
1409
|
+
case "tinkercad":
|
|
1410
|
+
return mapping(
|
|
1411
|
+
environment,
|
|
1412
|
+
{ right: shift ? "truck" : "rotate" },
|
|
1413
|
+
{ usesCadWheel: false, immediate: false }
|
|
1414
|
+
);
|
|
1415
|
+
case "powermill":
|
|
1416
|
+
return mapping(
|
|
1417
|
+
environment,
|
|
1418
|
+
{ middle: shift ? "truck" : "rotate" },
|
|
1419
|
+
{ usesCadWheel: false, immediate: false }
|
|
1420
|
+
);
|
|
1421
|
+
case "onshape":
|
|
1422
|
+
return mapping(
|
|
1423
|
+
environment,
|
|
1424
|
+
{ middle: "truck", right: "rotate" },
|
|
1425
|
+
{ usesCadWheel: false, immediate: false }
|
|
1426
|
+
);
|
|
1427
|
+
case "toolpath":
|
|
1428
|
+
return mapping(
|
|
1429
|
+
environment,
|
|
1430
|
+
{ left: "rotate", right: "truck" },
|
|
1431
|
+
{ usesCadWheel: false, immediate: false }
|
|
1432
|
+
);
|
|
1433
|
+
}
|
|
1434
|
+
};
|
|
1435
|
+
|
|
1436
|
+
// src/render/controls.ts
|
|
1008
1437
|
CameraControls.install({
|
|
1009
1438
|
THREE: {
|
|
1010
1439
|
Box3: Box32,
|
|
@@ -1013,8 +1442,8 @@ CameraControls.install({
|
|
|
1013
1442
|
Raycaster,
|
|
1014
1443
|
Sphere,
|
|
1015
1444
|
Spherical,
|
|
1016
|
-
Vector2,
|
|
1017
|
-
Vector3:
|
|
1445
|
+
Vector2: Vector22,
|
|
1446
|
+
Vector3: Vector35,
|
|
1018
1447
|
Vector4
|
|
1019
1448
|
}
|
|
1020
1449
|
});
|
|
@@ -1032,13 +1461,14 @@ var ExtendedCameraControls = class extends CameraControls {
|
|
|
1032
1461
|
#attached = false;
|
|
1033
1462
|
#autoUpEnabled = false;
|
|
1034
1463
|
#shiftPressed = false;
|
|
1464
|
+
#ctrlPressed = false;
|
|
1035
1465
|
#wheelHandler = null;
|
|
1036
1466
|
// Scratch objects — `#onPointerMove` and `#adaptUpVector` run at pointer and
|
|
1037
1467
|
// frame rate respectively, so neither may allocate.
|
|
1038
1468
|
#spherical = new Spherical();
|
|
1039
|
-
#scratchA = new
|
|
1040
|
-
#scratchB = new
|
|
1041
|
-
#scratchC = new
|
|
1469
|
+
#scratchA = new Vector35();
|
|
1470
|
+
#scratchB = new Vector35();
|
|
1471
|
+
#scratchC = new Vector35();
|
|
1042
1472
|
constructor(camera, domElement, options = {}) {
|
|
1043
1473
|
super(camera, domElement);
|
|
1044
1474
|
this.#domElement = domElement;
|
|
@@ -1101,7 +1531,7 @@ var ExtendedCameraControls = class extends CameraControls {
|
|
|
1101
1531
|
view?.removeEventListener("keyup", this.#onModifierChange);
|
|
1102
1532
|
view?.removeEventListener("blur", this.#onWindowBlur);
|
|
1103
1533
|
this.#disableAutoUp();
|
|
1104
|
-
this.#
|
|
1534
|
+
this.#disableCadWheel();
|
|
1105
1535
|
}
|
|
1106
1536
|
dispose() {
|
|
1107
1537
|
this.detach();
|
|
@@ -1114,29 +1544,38 @@ var ExtendedCameraControls = class extends CameraControls {
|
|
|
1114
1544
|
*/
|
|
1115
1545
|
applyScheme(scheme) {
|
|
1116
1546
|
this.#scheme = scheme;
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
this
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1547
|
+
const mapping2 = resolveControlScheme(scheme, {
|
|
1548
|
+
orthographic: this.camera instanceof OrthographicCamera2,
|
|
1549
|
+
modifiers: { shift: this.#shiftPressed, ctrl: this.#ctrlPressed }
|
|
1550
|
+
});
|
|
1551
|
+
this.#applyMapping(mapping2);
|
|
1552
|
+
}
|
|
1553
|
+
#applyMapping(mapping2) {
|
|
1554
|
+
const action = {
|
|
1555
|
+
none: CameraControls.ACTION.NONE,
|
|
1556
|
+
rotate: CameraControls.ACTION.ROTATE,
|
|
1557
|
+
truck: CameraControls.ACTION.TRUCK,
|
|
1558
|
+
zoom: CameraControls.ACTION.ZOOM,
|
|
1559
|
+
dolly: CameraControls.ACTION.DOLLY
|
|
1560
|
+
};
|
|
1561
|
+
const touchAction = {
|
|
1562
|
+
rotate: CameraControls.ACTION.TOUCH_ROTATE,
|
|
1563
|
+
truck: CameraControls.ACTION.TOUCH_TRUCK,
|
|
1564
|
+
"dolly-truck": CameraControls.ACTION.TOUCH_DOLLY_TRUCK
|
|
1565
|
+
};
|
|
1566
|
+
this.#disableCadWheel();
|
|
1567
|
+
this.mouseButtons.left = action[mapping2.mouse.left];
|
|
1568
|
+
this.mouseButtons.middle = action[mapping2.mouse.middle];
|
|
1569
|
+
this.mouseButtons.right = action[mapping2.mouse.right];
|
|
1570
|
+
this.mouseButtons.wheel = action[mapping2.mouse.wheel];
|
|
1571
|
+
this.touches.one = touchAction[mapping2.touches.one];
|
|
1572
|
+
this.touches.two = touchAction[mapping2.touches.two];
|
|
1573
|
+
this.touches.three = touchAction[mapping2.touches.three];
|
|
1574
|
+
this.smoothTime = mapping2.immediate ? 0 : DEFAULT_SMOOTH_TIME;
|
|
1575
|
+
this.draggingSmoothTime = mapping2.immediate ? 0 : DEFAULT_SMOOTH_TIME;
|
|
1576
|
+
if (mapping2.usesCadWheel) {
|
|
1577
|
+
this.#enableCadWheel();
|
|
1135
1578
|
}
|
|
1136
|
-
this.mouseButtons.left = CameraControls.ACTION.ROTATE;
|
|
1137
|
-
this.mouseButtons.right = CameraControls.ACTION.TRUCK;
|
|
1138
|
-
this.mouseButtons.middle = CameraControls.ACTION.TRUCK;
|
|
1139
|
-
this.mouseButtons.wheel = this.camera instanceof OrthographicCamera2 ? CameraControls.ACTION.ZOOM : CameraControls.ACTION.DOLLY;
|
|
1140
1579
|
}
|
|
1141
1580
|
setFreeOrbit(freeOrbit) {
|
|
1142
1581
|
if (this.#freeOrbit === freeOrbit) {
|
|
@@ -1174,13 +1613,16 @@ var ExtendedCameraControls = class extends CameraControls {
|
|
|
1174
1613
|
this.#autoUpEnabled = false;
|
|
1175
1614
|
this.removeEventListener("update", this.#adaptUpVector);
|
|
1176
1615
|
}
|
|
1177
|
-
#
|
|
1178
|
-
this.#
|
|
1616
|
+
#enableCadWheel() {
|
|
1617
|
+
if (!this.#attached || this.#wheelHandler) {
|
|
1618
|
+
return;
|
|
1619
|
+
}
|
|
1620
|
+
this.#wheelHandler = (event) => this.#onCadWheel(event);
|
|
1179
1621
|
this.#domElement.addEventListener("wheel", this.#wheelHandler, {
|
|
1180
1622
|
passive: false
|
|
1181
1623
|
});
|
|
1182
1624
|
}
|
|
1183
|
-
#
|
|
1625
|
+
#disableCadWheel() {
|
|
1184
1626
|
if (!this.#wheelHandler) {
|
|
1185
1627
|
return;
|
|
1186
1628
|
}
|
|
@@ -1223,7 +1665,7 @@ var ExtendedCameraControls = class extends CameraControls {
|
|
|
1223
1665
|
void this.rotateTo(azimuth, polar, false);
|
|
1224
1666
|
this.update(0);
|
|
1225
1667
|
};
|
|
1226
|
-
#
|
|
1668
|
+
#onCadWheel = (event) => {
|
|
1227
1669
|
event.preventDefault();
|
|
1228
1670
|
if (event.ctrlKey) {
|
|
1229
1671
|
void this.zoom(-event.deltaY * FUSION_PINCH_ZOOM_SCALE, false);
|
|
@@ -1241,19 +1683,18 @@ var ExtendedCameraControls = class extends CameraControls {
|
|
|
1241
1683
|
this.dispatchEvent({ type: "control" });
|
|
1242
1684
|
};
|
|
1243
1685
|
#onModifierChange = (event) => {
|
|
1244
|
-
this.#
|
|
1686
|
+
this.#setModifiers(event.shiftKey, event.ctrlKey);
|
|
1245
1687
|
};
|
|
1246
1688
|
#onWindowBlur = () => {
|
|
1247
|
-
this.#
|
|
1689
|
+
this.#setModifiers(false, false);
|
|
1248
1690
|
};
|
|
1249
|
-
#
|
|
1250
|
-
if (this.#shiftPressed ===
|
|
1691
|
+
#setModifiers(shift, ctrl) {
|
|
1692
|
+
if (this.#shiftPressed === shift && this.#ctrlPressed === ctrl) {
|
|
1251
1693
|
return;
|
|
1252
1694
|
}
|
|
1253
|
-
this.#shiftPressed =
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
}
|
|
1695
|
+
this.#shiftPressed = shift;
|
|
1696
|
+
this.#ctrlPressed = ctrl;
|
|
1697
|
+
this.applyScheme(this.#scheme);
|
|
1257
1698
|
}
|
|
1258
1699
|
};
|
|
1259
1700
|
|
|
@@ -1369,10 +1810,10 @@ function counted(notify) {
|
|
|
1369
1810
|
import { useFrame as useFrame2, useThree as useThree3 } from "@react-three/fiber";
|
|
1370
1811
|
import { useEffect as useEffect3, useMemo as useMemo3, useRef as useRef2 } from "react";
|
|
1371
1812
|
import {
|
|
1372
|
-
DoubleSide,
|
|
1813
|
+
DoubleSide as DoubleSide2,
|
|
1373
1814
|
RingGeometry,
|
|
1374
1815
|
SphereGeometry,
|
|
1375
|
-
Vector3 as
|
|
1816
|
+
Vector3 as Vector36
|
|
1376
1817
|
} from "three";
|
|
1377
1818
|
|
|
1378
1819
|
// src/render/target.ts
|
|
@@ -1415,8 +1856,8 @@ var TargetMarker = ({ controlsRef }) => {
|
|
|
1415
1856
|
const heldUntil = useRef2(0);
|
|
1416
1857
|
const painted = useRef2(-1);
|
|
1417
1858
|
const placed = useRef2(false);
|
|
1418
|
-
const lastTarget = useMemo3(() => new
|
|
1419
|
-
const scratch = useMemo3(() => new
|
|
1859
|
+
const lastTarget = useMemo3(() => new Vector36(), []);
|
|
1860
|
+
const scratch = useMemo3(() => new Vector36(), []);
|
|
1420
1861
|
useEffect3(() => {
|
|
1421
1862
|
const controls = controlsRef.current;
|
|
1422
1863
|
if (!controls) return void 0;
|
|
@@ -1482,7 +1923,7 @@ var TargetMarker = ({ controlsRef }) => {
|
|
|
1482
1923
|
opacity: 0,
|
|
1483
1924
|
depthTest: false,
|
|
1484
1925
|
depthWrite: false,
|
|
1485
|
-
side:
|
|
1926
|
+
side: DoubleSide2
|
|
1486
1927
|
}
|
|
1487
1928
|
)
|
|
1488
1929
|
}
|
|
@@ -1516,7 +1957,7 @@ import {
|
|
|
1516
1957
|
CanvasTexture,
|
|
1517
1958
|
Float32BufferAttribute as Float32BufferAttribute3,
|
|
1518
1959
|
SRGBColorSpace,
|
|
1519
|
-
Vector3 as
|
|
1960
|
+
Vector3 as Vector37
|
|
1520
1961
|
} from "three";
|
|
1521
1962
|
var VIEW_NAMES = [
|
|
1522
1963
|
// The six faces.
|
|
@@ -1600,12 +2041,12 @@ function viewUp(direction) {
|
|
|
1600
2041
|
return { x: 0, y: 0, z: 1 };
|
|
1601
2042
|
}
|
|
1602
2043
|
function squaredUp(direction, currentUp) {
|
|
1603
|
-
const forward = new
|
|
2044
|
+
const forward = new Vector37(direction.x, direction.y, direction.z).normalize();
|
|
1604
2045
|
const canonical = viewUp(direction);
|
|
1605
|
-
const zero = new
|
|
2046
|
+
const zero = new Vector37(canonical.x, canonical.y, canonical.z);
|
|
1606
2047
|
zero.addScaledVector(forward, -forward.dot(zero)).normalize();
|
|
1607
|
-
const quarter = new
|
|
1608
|
-
const current = new
|
|
2048
|
+
const quarter = new Vector37().crossVectors(forward, zero);
|
|
2049
|
+
const current = new Vector37(currentUp.x, currentUp.y, currentUp.z);
|
|
1609
2050
|
const rolls = [zero, quarter, zero.clone().negate(), quarter.clone().negate()];
|
|
1610
2051
|
const nearest = rolls.reduce(
|
|
1611
2052
|
(best, roll) => roll.dot(current) > best.dot(current) ? roll : best
|
|
@@ -1623,11 +2064,11 @@ function cubeZones(chamfer = CHAMFER) {
|
|
|
1623
2064
|
const direction = viewVector(name);
|
|
1624
2065
|
const [sx, sy, sz] = VIEW_SIGNS[name];
|
|
1625
2066
|
const sign = (axis) => VIEW_SIGNS[name][axis] ?? 0;
|
|
1626
|
-
const normal = new
|
|
2067
|
+
const normal = new Vector37(direction.x, direction.y, direction.z);
|
|
1627
2068
|
let polygon;
|
|
1628
2069
|
if (kind === "face") {
|
|
1629
2070
|
const up = viewUp(direction);
|
|
1630
|
-
const upVector = new
|
|
2071
|
+
const upVector = new Vector37(up.x, up.y, up.z);
|
|
1631
2072
|
const right = normal.clone().negate().cross(upVector).normalize();
|
|
1632
2073
|
const square = [
|
|
1633
2074
|
[-1, -1],
|
|
@@ -1649,7 +2090,7 @@ function cubeZones(chamfer = CHAMFER) {
|
|
|
1649
2090
|
[chamfer, 1, -chamfer]
|
|
1650
2091
|
];
|
|
1651
2092
|
polygon = rectangle.map(
|
|
1652
|
-
([onA, onB, onC]) => new
|
|
2093
|
+
([onA, onB, onC]) => new Vector37().setComponent(a, sign(a) * onA).setComponent(b, sign(b) * onB).setComponent(c, onC)
|
|
1653
2094
|
);
|
|
1654
2095
|
} else {
|
|
1655
2096
|
const triangle = [
|
|
@@ -1657,11 +2098,11 @@ function cubeZones(chamfer = CHAMFER) {
|
|
|
1657
2098
|
[chamfer, 1, chamfer],
|
|
1658
2099
|
[chamfer, chamfer, 1]
|
|
1659
2100
|
];
|
|
1660
|
-
polygon = triangle.map(([onX, onY, onZ]) => new
|
|
2101
|
+
polygon = triangle.map(([onX, onY, onZ]) => new Vector37(sx * onX, sy * onY, sz * onZ));
|
|
1661
2102
|
}
|
|
1662
2103
|
const [first, second, third] = polygon;
|
|
1663
2104
|
if (first && second && third) {
|
|
1664
|
-
const facing = new
|
|
2105
|
+
const facing = new Vector37().subVectors(second, first).cross(new Vector37().subVectors(third, first));
|
|
1665
2106
|
if (facing.dot(normal) < 0) polygon.reverse();
|
|
1666
2107
|
}
|
|
1667
2108
|
return { name, kind, direction, polygon: polygon.map(vec) };
|
|
@@ -1791,10 +2232,10 @@ var ViewerScene = ({
|
|
|
1791
2232
|
const framedRef = useRef3(null);
|
|
1792
2233
|
const scratchBox = useMemo4(() => new Box33(), []);
|
|
1793
2234
|
const scratchBoundary = useMemo4(() => new Box33(), []);
|
|
1794
|
-
const scratchDirection = useMemo4(() => new
|
|
1795
|
-
const scratchView = useMemo4(() => new
|
|
1796
|
-
const scratchTarget = useMemo4(() => new
|
|
1797
|
-
const scratchPosition = useMemo4(() => new
|
|
2235
|
+
const scratchDirection = useMemo4(() => new Vector38(), []);
|
|
2236
|
+
const scratchView = useMemo4(() => new Vector38(), []);
|
|
2237
|
+
const scratchTarget = useMemo4(() => new Vector38(), []);
|
|
2238
|
+
const scratchPosition = useMemo4(() => new Vector38(), []);
|
|
1798
2239
|
const applyLimits = useCallback(
|
|
1799
2240
|
(bounds, framed) => {
|
|
1800
2241
|
controlsRef.current?.applyLimits(
|
|
@@ -1843,8 +2284,8 @@ var ViewerScene = ({
|
|
|
1843
2284
|
(bounds) => {
|
|
1844
2285
|
const controls = controlsRef.current;
|
|
1845
2286
|
if (!controls) return false;
|
|
1846
|
-
const target = controls.getTarget(new
|
|
1847
|
-
const direction = currentViewDirection(camera, target, new
|
|
2287
|
+
const target = controls.getTarget(new Vector38());
|
|
2288
|
+
const direction = currentViewDirection(camera, target, new Vector38());
|
|
1848
2289
|
const distance = fitDistance(projection, size, bounds, DEFAULT_FIT_MARGIN);
|
|
1849
2290
|
const position = direction.multiplyScalar(distance).add(bounds.center);
|
|
1850
2291
|
void controls.setLookAt(
|
|
@@ -1869,8 +2310,8 @@ var ViewerScene = ({
|
|
|
1869
2310
|
const fitContent = useCallback(() => {
|
|
1870
2311
|
const controls = controlsRef.current;
|
|
1871
2312
|
if (!controls) return false;
|
|
1872
|
-
const target = controls.getTarget(new
|
|
1873
|
-
return frame(currentViewDirection(camera, target, new
|
|
2313
|
+
const target = controls.getTarget(new Vector38());
|
|
2314
|
+
return frame(currentViewDirection(camera, target, new Vector38()), true);
|
|
1874
2315
|
}, [camera, frame]);
|
|
1875
2316
|
const resetContent = useCallback(() => {
|
|
1876
2317
|
const bounds = measure();
|
|
@@ -2025,7 +2466,8 @@ var Viewer = forwardRef(function Viewer2({
|
|
|
2025
2466
|
return /* @__PURE__ */ jsx3(ViewerControlsContext.Provider, { value: proxy, children: /* @__PURE__ */ jsx3(SectionStoreContext.Provider, { value: sectionStore, children: /* @__PURE__ */ jsx3(
|
|
2026
2467
|
"div",
|
|
2027
2468
|
{
|
|
2028
|
-
className,
|
|
2469
|
+
className: ["viewer-root", className].filter(Boolean).join(" "),
|
|
2470
|
+
"data-viewer-root": "true",
|
|
2029
2471
|
ref: hold,
|
|
2030
2472
|
onMouseDown: (event) => {
|
|
2031
2473
|
if (event.target instanceof HTMLCanvasElement) event.preventDefault();
|
|
@@ -2034,11 +2476,20 @@ var Viewer = forwardRef(function Viewer2({
|
|
|
2034
2476
|
children: /* @__PURE__ */ jsx3(
|
|
2035
2477
|
Canvas,
|
|
2036
2478
|
{
|
|
2479
|
+
className: "viewer-canvas-container",
|
|
2480
|
+
"data-viewer-canvas-container": "true",
|
|
2037
2481
|
orthographic: projection === "orthographic",
|
|
2038
2482
|
camera: { fov: PERSPECTIVE_FOV, up: [0, 0, 1], position: [1, -1, 1] },
|
|
2039
2483
|
dpr: [1, 2],
|
|
2040
2484
|
frameloop: "demand",
|
|
2041
2485
|
gl: { antialias: true, alpha: true, stencil: true, localClippingEnabled: true },
|
|
2486
|
+
onCreated: ({ gl }) => {
|
|
2487
|
+
const canvas = gl.domElement;
|
|
2488
|
+
canvas.classList.add("viewer-canvas");
|
|
2489
|
+
canvas.dataset.viewerCanvas = "true";
|
|
2490
|
+
canvas.parentElement?.classList.add("viewer-canvas-frame");
|
|
2491
|
+
canvas.parentElement?.setAttribute("data-viewer-canvas-frame", "true");
|
|
2492
|
+
},
|
|
2042
2493
|
onPointerMissed: (event) => {
|
|
2043
2494
|
if (event.button !== 0) return;
|
|
2044
2495
|
if (tracker.current?.isTap(event) ?? true) onPointerMissed?.();
|
|
@@ -2070,29 +2521,31 @@ import { useFrame as useFrame4, useThree as useThree5 } from "@react-three/fiber
|
|
|
2070
2521
|
import { useCallback as useCallback2, useEffect as useEffect5, useLayoutEffect, useMemo as useMemo5, useRef as useRef4, useState } from "react";
|
|
2071
2522
|
import {
|
|
2072
2523
|
Color as Color3,
|
|
2524
|
+
DoubleSide as DoubleSide4,
|
|
2525
|
+
EdgesGeometry,
|
|
2073
2526
|
Mesh as Mesh3,
|
|
2074
2527
|
Plane as Plane2,
|
|
2075
2528
|
PlaneGeometry,
|
|
2076
2529
|
Quaternion as Quaternion2,
|
|
2077
2530
|
Raycaster as Raycaster2,
|
|
2078
2531
|
Scene,
|
|
2079
|
-
Vector2 as
|
|
2080
|
-
Vector3 as
|
|
2532
|
+
Vector2 as Vector24,
|
|
2533
|
+
Vector3 as Vector310
|
|
2081
2534
|
} from "three";
|
|
2082
2535
|
|
|
2083
2536
|
// src/render/directions.ts
|
|
2084
|
-
import { Vector3 as
|
|
2085
|
-
var CONE_AXIS = new
|
|
2537
|
+
import { Vector3 as Vector39 } from "three";
|
|
2538
|
+
var CONE_AXIS = new Vector39(0, 1, 0);
|
|
2086
2539
|
var LENGTH = 0.45;
|
|
2087
2540
|
var HEAD = 0.45;
|
|
2088
2541
|
var HEAD_RADIUS = 0.3;
|
|
2089
2542
|
var SHAFT_RADIUS = 0.09;
|
|
2090
2543
|
var GAP = 0.2;
|
|
2091
2544
|
function arrowPlacement(direction, box) {
|
|
2092
|
-
const center = box.getCenter(new
|
|
2093
|
-
const half = box.getSize(new
|
|
2545
|
+
const center = box.getCenter(new Vector39());
|
|
2546
|
+
const half = box.getSize(new Vector39()).multiplyScalar(0.5);
|
|
2094
2547
|
const radius = half.length() || 1;
|
|
2095
|
-
const axis = new
|
|
2548
|
+
const axis = new Vector39(direction.x, direction.y, direction.z);
|
|
2096
2549
|
if (axis.lengthSq() === 0) axis.set(0, 0, 1);
|
|
2097
2550
|
axis.normalize();
|
|
2098
2551
|
let exit = Number.POSITIVE_INFINITY;
|
|
@@ -2113,7 +2566,7 @@ import {
|
|
|
2113
2566
|
BackSide,
|
|
2114
2567
|
Color as Color2,
|
|
2115
2568
|
DecrementWrapStencilOp,
|
|
2116
|
-
DoubleSide as
|
|
2569
|
+
DoubleSide as DoubleSide3,
|
|
2117
2570
|
FrontSide,
|
|
2118
2571
|
IncrementWrapStencilOp,
|
|
2119
2572
|
LinearFilter,
|
|
@@ -2121,7 +2574,7 @@ import {
|
|
|
2121
2574
|
NotEqualStencilFunc,
|
|
2122
2575
|
ReplaceStencilOp,
|
|
2123
2576
|
ShaderMaterial,
|
|
2124
|
-
Vector2 as
|
|
2577
|
+
Vector2 as Vector23,
|
|
2125
2578
|
WebGLRenderTarget
|
|
2126
2579
|
} from "three";
|
|
2127
2580
|
var VERTEX = (
|
|
@@ -2180,7 +2633,7 @@ function createMaskTarget() {
|
|
|
2180
2633
|
function createCapMaterial(mask) {
|
|
2181
2634
|
const uniforms = {
|
|
2182
2635
|
uMask: { value: mask },
|
|
2183
|
-
uResolution: { value: new
|
|
2636
|
+
uResolution: { value: new Vector23(1, 1) },
|
|
2184
2637
|
uFill: { value: new Color2() },
|
|
2185
2638
|
uHatch: { value: new Color2() },
|
|
2186
2639
|
uOutline: { value: new Color2() },
|
|
@@ -2192,7 +2645,7 @@ function createCapMaterial(mask) {
|
|
|
2192
2645
|
vertexShader: VERTEX,
|
|
2193
2646
|
fragmentShader: FRAGMENT,
|
|
2194
2647
|
uniforms,
|
|
2195
|
-
side:
|
|
2648
|
+
side: DoubleSide3,
|
|
2196
2649
|
stencilWrite: true,
|
|
2197
2650
|
stencilRef: 0,
|
|
2198
2651
|
stencilFunc: NotEqualStencilFunc,
|
|
@@ -2238,7 +2691,7 @@ function createStencilMaterials(clip) {
|
|
|
2238
2691
|
function createMaskMaterial() {
|
|
2239
2692
|
return new MeshBasicMaterial2({
|
|
2240
2693
|
color: 16777215,
|
|
2241
|
-
side:
|
|
2694
|
+
side: DoubleSide3,
|
|
2242
2695
|
stencilWrite: true,
|
|
2243
2696
|
stencilRef: 0,
|
|
2244
2697
|
stencilFunc: NotEqualStencilFunc,
|
|
@@ -2249,12 +2702,12 @@ function createMaskMaterial() {
|
|
|
2249
2702
|
}
|
|
2250
2703
|
|
|
2251
2704
|
// src/section-view.tsx
|
|
2252
|
-
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
2705
|
+
import { Fragment, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
2253
2706
|
var FURNITURE2 = { [EXCLUDE_FROM_FRAME]: true };
|
|
2254
2707
|
function resolveSectionPlane(options, box) {
|
|
2255
2708
|
if (!options?.enabled || box.isEmpty()) return null;
|
|
2256
2709
|
const normal = options.plane?.normal ?? options.normal ?? DEFAULT_SECTION_NORMAL;
|
|
2257
|
-
const axis = new
|
|
2710
|
+
const axis = new Vector310(normal.x, normal.y, normal.z);
|
|
2258
2711
|
if (axis.lengthSq() === 0) axis.set(0, 0, 1);
|
|
2259
2712
|
axis.normalize();
|
|
2260
2713
|
const bounds = sectionBounds(box, normal);
|
|
@@ -2270,16 +2723,18 @@ function resolveSectionPlane(options, box) {
|
|
|
2270
2723
|
constant,
|
|
2271
2724
|
plane: options.plane ?? null,
|
|
2272
2725
|
depth: anchor === null ? null : sectionDepth(normal, anchor, constant),
|
|
2726
|
+
cutDistance: sectionCutDistance(box, normal, constant),
|
|
2273
2727
|
depthRange: anchor === null ? null : sectionDepthRange(bounds, normal, anchor)
|
|
2274
2728
|
}
|
|
2275
2729
|
};
|
|
2276
2730
|
}
|
|
2277
|
-
var Z = new
|
|
2731
|
+
var Z = new Vector310(0, 0, 1);
|
|
2278
2732
|
var SectionView = ({
|
|
2279
2733
|
geometry,
|
|
2280
2734
|
box,
|
|
2281
2735
|
plane,
|
|
2282
2736
|
theme,
|
|
2737
|
+
handleColor,
|
|
2283
2738
|
showHandle,
|
|
2284
2739
|
onDrag
|
|
2285
2740
|
}) => {
|
|
@@ -2293,7 +2748,10 @@ var SectionView = ({
|
|
|
2293
2748
|
const handleRef = useRef4(null);
|
|
2294
2749
|
const [hovered, setHovered] = useState(false);
|
|
2295
2750
|
const dragging = useRef4(null);
|
|
2296
|
-
const span = useMemo5(() => box.getSize(new
|
|
2751
|
+
const span = useMemo5(() => box.getSize(new Vector310()).length(), [box]);
|
|
2752
|
+
const frameSize = span * SECTION_GIZMO_FRAME_SCALE;
|
|
2753
|
+
const directionColor2 = useMemo5(() => sectionDirectionColor(plane.normal), [plane]);
|
|
2754
|
+
const resolvedHandleColor = sectionHandleColor(handleColor, directionColor2);
|
|
2297
2755
|
const clip = useMemo5(() => [plane], [plane]);
|
|
2298
2756
|
const capPosition = useMemo5(() => sectionAnchor(box, plane), [box, plane]);
|
|
2299
2757
|
const capQuaternion = useMemo5(() => new Quaternion2().setFromUnitVectors(Z, plane.normal), [plane]);
|
|
@@ -2301,6 +2759,10 @@ var SectionView = ({
|
|
|
2301
2759
|
() => new Quaternion2().setFromUnitVectors(CONE_AXIS, plane.normal.clone().negate()),
|
|
2302
2760
|
[plane]
|
|
2303
2761
|
);
|
|
2762
|
+
const frameSurface = useMemo5(() => new PlaneGeometry(frameSize, frameSize), [frameSize]);
|
|
2763
|
+
useEffect5(() => () => frameSurface.dispose(), [frameSurface]);
|
|
2764
|
+
const frameEdges = useMemo5(() => new EdgesGeometry(frameSurface), [frameSurface]);
|
|
2765
|
+
useEffect5(() => () => frameEdges.dispose(), [frameEdges]);
|
|
2304
2766
|
const stencils = useMemo5(() => createStencilMaterials([]), []);
|
|
2305
2767
|
useEffect5(() => () => stencils.forEach((material) => material.dispose()), [stencils]);
|
|
2306
2768
|
useLayoutEffect(() => {
|
|
@@ -2330,7 +2792,7 @@ var SectionView = ({
|
|
|
2330
2792
|
maskScene.maskMesh.quaternion.copy(capQuaternion);
|
|
2331
2793
|
}, [capPosition, capQuaternion, maskScene]);
|
|
2332
2794
|
useLayoutEffect(() => {
|
|
2333
|
-
const buffer = gl.getDrawingBufferSize(new
|
|
2795
|
+
const buffer = gl.getDrawingBufferSize(new Vector24());
|
|
2334
2796
|
mask.setSize(buffer.x, buffer.y);
|
|
2335
2797
|
cap.uniforms.uResolution.value.copy(buffer);
|
|
2336
2798
|
applyCapTheme(cap, theme, dpr);
|
|
@@ -2368,7 +2830,7 @@ var SectionView = ({
|
|
|
2368
2830
|
event.stopPropagation();
|
|
2369
2831
|
const view = camera.position.clone().sub(capPosition).normalize();
|
|
2370
2832
|
const surface = dragPlane(plane.normal.clone(), view, capPosition);
|
|
2371
|
-
const hit = event.ray.intersectPlane(surface, new
|
|
2833
|
+
const hit = event.ray.intersectPlane(surface, new Vector310());
|
|
2372
2834
|
const start = {
|
|
2373
2835
|
plane: surface,
|
|
2374
2836
|
from: hit ? hit.dot(plane.normal) : 0,
|
|
@@ -2377,7 +2839,7 @@ var SectionView = ({
|
|
|
2377
2839
|
dragging.current = start;
|
|
2378
2840
|
setControlsEnabled(false);
|
|
2379
2841
|
const raycaster = new Raycaster2();
|
|
2380
|
-
const pointer = new
|
|
2842
|
+
const pointer = new Vector24();
|
|
2381
2843
|
const move = (native) => {
|
|
2382
2844
|
const rect = domElement.getBoundingClientRect();
|
|
2383
2845
|
pointer.set(
|
|
@@ -2385,7 +2847,7 @@ var SectionView = ({
|
|
|
2385
2847
|
-((native.clientY - rect.top) / rect.height) * 2 + 1
|
|
2386
2848
|
);
|
|
2387
2849
|
raycaster.setFromCamera(pointer, camera);
|
|
2388
|
-
const point = raycaster.ray.intersectPlane(start.plane, new
|
|
2850
|
+
const point = raycaster.ray.intersectPlane(start.plane, new Vector310());
|
|
2389
2851
|
if (!point) return;
|
|
2390
2852
|
onDrag(start.constant - (point.dot(plane.normal) - start.from));
|
|
2391
2853
|
invalidate();
|
|
@@ -2447,37 +2909,81 @@ var SectionView = ({
|
|
|
2447
2909
|
raycast: () => null
|
|
2448
2910
|
}
|
|
2449
2911
|
),
|
|
2450
|
-
showHandle && onDrag ? /* @__PURE__ */ jsxs3(
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
/* @__PURE__ */ jsx4("coneGeometry", { args: [0.16, 0.34, 20] }),
|
|
2460
|
-
/* @__PURE__ */ jsx4(
|
|
2461
|
-
"meshBasicMaterial",
|
|
2462
|
-
{
|
|
2463
|
-
color: hovered ? theme.hover : theme.sectionHandle,
|
|
2464
|
-
depthTest: false
|
|
2465
|
-
}
|
|
2466
|
-
)
|
|
2467
|
-
] }),
|
|
2468
|
-
/* @__PURE__ */ jsxs3("mesh", { position: [0, 0.08, 0], ...grab, children: [
|
|
2469
|
-
/* @__PURE__ */ jsx4("cylinderGeometry", { args: [0.045, 0.045, 0.4, 12] }),
|
|
2470
|
-
/* @__PURE__ */ jsx4(
|
|
2912
|
+
showHandle && onDrag ? /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
2913
|
+
/* @__PURE__ */ jsxs3(
|
|
2914
|
+
"group",
|
|
2915
|
+
{
|
|
2916
|
+
position: capPosition,
|
|
2917
|
+
quaternion: capQuaternion,
|
|
2918
|
+
renderOrder: SECTION_RENDER_ORDER.outline,
|
|
2919
|
+
children: [
|
|
2920
|
+
/* @__PURE__ */ jsx4("mesh", { geometry: frameSurface, raycast: () => null, children: /* @__PURE__ */ jsx4(
|
|
2471
2921
|
"meshBasicMaterial",
|
|
2472
2922
|
{
|
|
2473
|
-
color:
|
|
2474
|
-
|
|
2923
|
+
color: directionColor2,
|
|
2924
|
+
transparent: true,
|
|
2925
|
+
opacity: 0.18,
|
|
2926
|
+
side: DoubleSide4,
|
|
2927
|
+
depthTest: false,
|
|
2928
|
+
depthWrite: false
|
|
2475
2929
|
}
|
|
2476
|
-
)
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2930
|
+
) }),
|
|
2931
|
+
/* @__PURE__ */ jsx4("lineSegments", { geometry: frameEdges, raycast: () => null, children: /* @__PURE__ */ jsx4("lineBasicMaterial", { color: directionColor2, depthTest: false, depthWrite: false }) })
|
|
2932
|
+
]
|
|
2933
|
+
}
|
|
2934
|
+
),
|
|
2935
|
+
/* @__PURE__ */ jsxs3(
|
|
2936
|
+
"group",
|
|
2937
|
+
{
|
|
2938
|
+
ref: handleRef,
|
|
2939
|
+
position: capPosition,
|
|
2940
|
+
quaternion: handleQuaternion,
|
|
2941
|
+
renderOrder: SECTION_RENDER_ORDER.handle,
|
|
2942
|
+
children: [
|
|
2943
|
+
/* @__PURE__ */ jsxs3("mesh", { ...grab, children: [
|
|
2944
|
+
/* @__PURE__ */ jsx4("sphereGeometry", { args: [0.1, 16, 12] }),
|
|
2945
|
+
/* @__PURE__ */ jsx4(
|
|
2946
|
+
"meshBasicMaterial",
|
|
2947
|
+
{
|
|
2948
|
+
color: hovered ? theme.hover : resolvedHandleColor,
|
|
2949
|
+
depthTest: false
|
|
2950
|
+
}
|
|
2951
|
+
)
|
|
2952
|
+
] }),
|
|
2953
|
+
/* @__PURE__ */ jsxs3("mesh", { ...grab, children: [
|
|
2954
|
+
/* @__PURE__ */ jsx4("cylinderGeometry", { args: [0.035, 0.035, 0.9, 12] }),
|
|
2955
|
+
/* @__PURE__ */ jsx4(
|
|
2956
|
+
"meshBasicMaterial",
|
|
2957
|
+
{
|
|
2958
|
+
color: hovered ? theme.hover : resolvedHandleColor,
|
|
2959
|
+
depthTest: false
|
|
2960
|
+
}
|
|
2961
|
+
)
|
|
2962
|
+
] }),
|
|
2963
|
+
/* @__PURE__ */ jsxs3("mesh", { position: [0, 0.61, 0], ...grab, children: [
|
|
2964
|
+
/* @__PURE__ */ jsx4("coneGeometry", { args: [0.15, 0.3, 20] }),
|
|
2965
|
+
/* @__PURE__ */ jsx4(
|
|
2966
|
+
"meshBasicMaterial",
|
|
2967
|
+
{
|
|
2968
|
+
color: hovered ? theme.hover : resolvedHandleColor,
|
|
2969
|
+
depthTest: false
|
|
2970
|
+
}
|
|
2971
|
+
)
|
|
2972
|
+
] }),
|
|
2973
|
+
/* @__PURE__ */ jsxs3("mesh", { position: [0, -0.61, 0], rotation: [Math.PI, 0, 0], ...grab, children: [
|
|
2974
|
+
/* @__PURE__ */ jsx4("coneGeometry", { args: [0.15, 0.3, 20] }),
|
|
2975
|
+
/* @__PURE__ */ jsx4(
|
|
2976
|
+
"meshBasicMaterial",
|
|
2977
|
+
{
|
|
2978
|
+
color: hovered ? theme.hover : resolvedHandleColor,
|
|
2979
|
+
depthTest: false
|
|
2980
|
+
}
|
|
2981
|
+
)
|
|
2982
|
+
] })
|
|
2983
|
+
]
|
|
2984
|
+
}
|
|
2985
|
+
)
|
|
2986
|
+
] }) : null
|
|
2481
2987
|
] })
|
|
2482
2988
|
);
|
|
2483
2989
|
};
|
|
@@ -2493,7 +2999,7 @@ function useContentBox() {
|
|
|
2493
2999
|
useFrame5(() => {
|
|
2494
3000
|
if (measured.current) return;
|
|
2495
3001
|
const next = new Box34();
|
|
2496
|
-
|
|
3002
|
+
partBounds(scene, next);
|
|
2497
3003
|
if (next.isEmpty()) return;
|
|
2498
3004
|
measured.current = true;
|
|
2499
3005
|
setBox(next);
|
|
@@ -2502,16 +3008,18 @@ function useContentBox() {
|
|
|
2502
3008
|
}
|
|
2503
3009
|
|
|
2504
3010
|
// src/part-mesh.tsx
|
|
2505
|
-
import { Fragment, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
3011
|
+
import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
2506
3012
|
var PartMesh = ({
|
|
2507
3013
|
model,
|
|
2508
3014
|
geometry,
|
|
2509
3015
|
selection = [],
|
|
3016
|
+
focus,
|
|
2510
3017
|
candidates = [],
|
|
2511
3018
|
highlights = [],
|
|
2512
3019
|
regionHighlights = [],
|
|
2513
3020
|
pickedRegions = [],
|
|
2514
3021
|
hoveredFeatureIds = [],
|
|
3022
|
+
hover = true,
|
|
2515
3023
|
activeDirection = null,
|
|
2516
3024
|
section,
|
|
2517
3025
|
onSectionChange,
|
|
@@ -2520,7 +3028,8 @@ var PartMesh = ({
|
|
|
2520
3028
|
onHover,
|
|
2521
3029
|
onPick,
|
|
2522
3030
|
theme,
|
|
2523
|
-
showEdges = true
|
|
3031
|
+
showEdges = true,
|
|
3032
|
+
display = "solid"
|
|
2524
3033
|
}) => {
|
|
2525
3034
|
const { camera, controls, invalidate } = useThree7();
|
|
2526
3035
|
const viewerControls = useViewerControls();
|
|
@@ -2529,6 +3038,8 @@ var PartMesh = ({
|
|
|
2529
3038
|
currentTheme.current = resolved;
|
|
2530
3039
|
const part = useMemo6(() => createPart(model, geometry, currentTheme.current), [geometry, model]);
|
|
2531
3040
|
const hoverRegion = useRef6(null);
|
|
3041
|
+
const onHoverRef = useRef6(onHover);
|
|
3042
|
+
onHoverRef.current = onHover;
|
|
2532
3043
|
const box = useContentBox();
|
|
2533
3044
|
const store = useSectionStore();
|
|
2534
3045
|
const shared = useSyncExternalStore(store.subscribe, store.get, store.get);
|
|
@@ -2578,10 +3089,19 @@ var PartMesh = ({
|
|
|
2578
3089
|
part.setTheme(resolved);
|
|
2579
3090
|
repaint();
|
|
2580
3091
|
}, [part, repaint, resolved]);
|
|
3092
|
+
const focusRef = useRef6(focus);
|
|
3093
|
+
focusRef.current = focus;
|
|
3094
|
+
const selectionRef = useRef6(selection);
|
|
3095
|
+
selectionRef.current = selection;
|
|
3096
|
+
const focusKey = focusStateKey(focus, selection);
|
|
2581
3097
|
useLayoutEffect2(() => {
|
|
2582
|
-
part.
|
|
3098
|
+
part.setFocus(selectionRef.current, focusRef.current);
|
|
2583
3099
|
invalidate();
|
|
2584
|
-
}, [invalidate, part
|
|
3100
|
+
}, [focusKey, invalidate, part]);
|
|
3101
|
+
useLayoutEffect2(() => {
|
|
3102
|
+
part.setDisplay(display, showEdges);
|
|
3103
|
+
invalidate();
|
|
3104
|
+
}, [display, invalidate, part, showEdges]);
|
|
2585
3105
|
useLayoutEffect2(() => {
|
|
2586
3106
|
part.setClippingPlanes(cut ? [cut.plane] : null);
|
|
2587
3107
|
invalidate();
|
|
@@ -2624,6 +3144,7 @@ var PartMesh = ({
|
|
|
2624
3144
|
triangleIndex,
|
|
2625
3145
|
point: [event.point.x, event.point.y, event.point.z],
|
|
2626
3146
|
normal: [normal.x, normal.y, normal.z],
|
|
3147
|
+
pointer: { clientX: source.clientX, clientY: source.clientY },
|
|
2627
3148
|
activeDirection,
|
|
2628
3149
|
doubled,
|
|
2629
3150
|
viewDirection: viewDirection(camera, target),
|
|
@@ -2643,8 +3164,12 @@ var PartMesh = ({
|
|
|
2643
3164
|
repaint();
|
|
2644
3165
|
onHover?.(next);
|
|
2645
3166
|
};
|
|
2646
|
-
|
|
2647
|
-
|
|
3167
|
+
useLayoutEffect2(() => {
|
|
3168
|
+
if (hover || hoverRegion.current === null) return;
|
|
3169
|
+
hoverRegion.current = null;
|
|
3170
|
+
repaint();
|
|
3171
|
+
onHoverRef.current?.(null);
|
|
3172
|
+
}, [hover, repaint]);
|
|
2648
3173
|
useLayoutEffect2(() => {
|
|
2649
3174
|
if (!engaged || hoverRegion.current === null) return;
|
|
2650
3175
|
hoverRegion.current = null;
|
|
@@ -2655,18 +3180,21 @@ var PartMesh = ({
|
|
|
2655
3180
|
(constant) => {
|
|
2656
3181
|
if (!cut) return;
|
|
2657
3182
|
const anchor = options?.plane?.point;
|
|
3183
|
+
const bounds = sectionBounds(box, cut.state.normal);
|
|
3184
|
+
const offset = sectionOffset(bounds, constant);
|
|
2658
3185
|
const state = {
|
|
2659
3186
|
...cut.state,
|
|
2660
3187
|
constant,
|
|
2661
|
-
offset
|
|
2662
|
-
depth: anchor ? sectionDepth(cut.state.normal, anchor, constant) : null
|
|
3188
|
+
offset,
|
|
3189
|
+
depth: anchor ? sectionDepth(cut.state.normal, anchor, constant) : null,
|
|
3190
|
+
cutDistance: sectionCutDistance(box, cut.state.normal, constant)
|
|
2663
3191
|
};
|
|
2664
3192
|
if (!controlled) store.set(sectionOptionsFromState(state));
|
|
2665
3193
|
onSectionChange?.(state);
|
|
2666
3194
|
},
|
|
2667
3195
|
[box, controlled, cut, onSectionChange, options, store]
|
|
2668
3196
|
);
|
|
2669
|
-
return /* @__PURE__ */ jsxs4(
|
|
3197
|
+
return /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
2670
3198
|
/* @__PURE__ */ jsx5(
|
|
2671
3199
|
"primitive",
|
|
2672
3200
|
{
|
|
@@ -2675,7 +3203,7 @@ var PartMesh = ({
|
|
|
2675
3203
|
pressedWhileEngaged.current = engaged;
|
|
2676
3204
|
},
|
|
2677
3205
|
onPointerMove: (event) => {
|
|
2678
|
-
if (!engaged) emitHover(pickFor(event));
|
|
3206
|
+
if (!engaged && hover) emitHover(pickFor(event));
|
|
2679
3207
|
},
|
|
2680
3208
|
onPointerOut: () => {
|
|
2681
3209
|
emitHover(null);
|
|
@@ -2711,15 +3239,16 @@ var PartMesh = ({
|
|
|
2711
3239
|
box,
|
|
2712
3240
|
plane: cut.plane,
|
|
2713
3241
|
theme: resolved,
|
|
3242
|
+
handleColor: theme?.sectionHandle,
|
|
2714
3243
|
showHandle: !controlled || onSectionChange !== void 0,
|
|
2715
3244
|
onDrag: !controlled || onSectionChange ? dragSection : void 0
|
|
2716
3245
|
}
|
|
2717
3246
|
) : null
|
|
2718
3247
|
] });
|
|
2719
3248
|
};
|
|
2720
|
-
var ORIGIN = new
|
|
2721
|
-
var UP = new
|
|
2722
|
-
var TARGET = new
|
|
3249
|
+
var ORIGIN = new Vector311();
|
|
3250
|
+
var UP = new Vector311(0, 0, 1);
|
|
3251
|
+
var TARGET = new Vector311();
|
|
2723
3252
|
function readTarget(controls) {
|
|
2724
3253
|
if (controls && typeof controls.getTarget === "function") {
|
|
2725
3254
|
return controls.getTarget(TARGET);
|
|
@@ -3378,6 +3907,7 @@ export {
|
|
|
3378
3907
|
PERSPECTIVE_FOV,
|
|
3379
3908
|
DEFAULT_FIT_MARGIN,
|
|
3380
3909
|
EXCLUDE_FROM_FRAME,
|
|
3910
|
+
STOCK_OBJECT,
|
|
3381
3911
|
defaultBounds,
|
|
3382
3912
|
aspectRatio,
|
|
3383
3913
|
screenLength,
|
|
@@ -3397,8 +3927,35 @@ export {
|
|
|
3397
3927
|
adaptedUp,
|
|
3398
3928
|
cadViewDirections,
|
|
3399
3929
|
currentViewDirection,
|
|
3930
|
+
MEASURE_RENDER_ORDER,
|
|
3931
|
+
AXIS_COLORS,
|
|
3932
|
+
SNAP_PIXELS,
|
|
3933
|
+
SNAP_MARKER_PIXELS,
|
|
3934
|
+
MEASURE_MARKER_PIXELS,
|
|
3935
|
+
MEASURE_LINE_PIXELS,
|
|
3936
|
+
DELTA_DASH_PIXELS,
|
|
3937
|
+
ANGLE_ARC_FRACTION,
|
|
3938
|
+
ANGLE_ARC_SEGMENTS,
|
|
3939
|
+
snapAt,
|
|
3940
|
+
screenPoint,
|
|
3941
|
+
POINTS_PER_MEASUREMENT,
|
|
3942
|
+
measurementFromPoints,
|
|
3943
|
+
nextMeasurementId,
|
|
3944
|
+
distanceBetween,
|
|
3945
|
+
deltaBetween,
|
|
3946
|
+
midpoint,
|
|
3947
|
+
angleAt,
|
|
3948
|
+
lockToAxis,
|
|
3949
|
+
deltaLegs,
|
|
3950
|
+
angleArc,
|
|
3951
|
+
angleArcRadius,
|
|
3952
|
+
formatMillimetres,
|
|
3953
|
+
formatDegrees,
|
|
3954
|
+
measurementLabel,
|
|
3955
|
+
measurementLabelAnchor,
|
|
3400
3956
|
SECTION_RENDER_ORDER,
|
|
3401
3957
|
HANDLE_PIXELS,
|
|
3958
|
+
SECTION_GIZMO_FRAME_SCALE,
|
|
3402
3959
|
CAP_HATCH,
|
|
3403
3960
|
AXES_PLANE_OFFSET,
|
|
3404
3961
|
AXES_PLANE_SCALE,
|
|
@@ -3406,6 +3963,7 @@ export {
|
|
|
3406
3963
|
OUTLINE_SCALE,
|
|
3407
3964
|
DEFAULT_SECTION_NORMAL,
|
|
3408
3965
|
DISABLED_SECTION,
|
|
3966
|
+
sectionMeasurement,
|
|
3409
3967
|
sectionOptionsFromState,
|
|
3410
3968
|
axesPlanes,
|
|
3411
3969
|
hitUnderRay,
|
|
@@ -3444,6 +4002,7 @@ export {
|
|
|
3444
4002
|
viewDirection,
|
|
3445
4003
|
buildPick,
|
|
3446
4004
|
focusForPick,
|
|
4005
|
+
CONTROL_SCHEME_OPTIONS,
|
|
3447
4006
|
ExtendedCameraControls,
|
|
3448
4007
|
CadCameraControls,
|
|
3449
4008
|
retargetPose,
|