@toolpath/viewer 0.4.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -2
- package/dist/{chunk-ILZ2KQUK.js → chunk-4BU4QZCL.js} +498 -167
- package/dist/engine/index.d.ts +2 -2
- package/dist/engine/index.js +1 -1
- package/dist/index.d.ts +405 -8
- package/dist/index.js +33 -1
- package/dist/{normalize-BXIGoZmc.d.ts → normalize-DsoIyM8B.d.ts} +19 -90
- package/package.json +5 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// src/engine/engine-part.tsx
|
|
2
|
-
import { useEffect as
|
|
2
|
+
import { useEffect as useEffect6, useMemo as useMemo7 } from "react";
|
|
3
3
|
|
|
4
4
|
// src/part-mesh.tsx
|
|
5
|
-
import { useThree as
|
|
6
|
-
import { useCallback as useCallback3, useEffect as
|
|
7
|
-
import { Vector3 as
|
|
5
|
+
import { useThree as useThree7 } from "@react-three/fiber";
|
|
6
|
+
import { useCallback as useCallback3, useEffect as useEffect5, useLayoutEffect, useMemo as useMemo6, useRef as useRef6 } from "react";
|
|
7
|
+
import { Vector3 as Vector310 } from "three";
|
|
8
8
|
|
|
9
9
|
// src/model/directions.ts
|
|
10
10
|
var EPSILON = 1e-6;
|
|
@@ -178,7 +178,7 @@ function applyHighlightLayers(part, layers, theme) {
|
|
|
178
178
|
}
|
|
179
179
|
|
|
180
180
|
// src/render/section.ts
|
|
181
|
-
import {
|
|
181
|
+
import { Plane, Vector3 } from "three";
|
|
182
182
|
var SECTION_RENDER_ORDER = {
|
|
183
183
|
stencil: 1,
|
|
184
184
|
cap: 2,
|
|
@@ -247,12 +247,6 @@ function sectionPlane(box, normal, offset, into = new Plane()) {
|
|
|
247
247
|
const axis = unit(normal);
|
|
248
248
|
return into.set(axis, sectionConstant(sectionBounds(box, normal), offset));
|
|
249
249
|
}
|
|
250
|
-
function screenLength(camera, point, viewport, pixels) {
|
|
251
|
-
const height = viewport.height > 0 ? viewport.height : 1;
|
|
252
|
-
const zoom = camera.zoom || 1;
|
|
253
|
-
const visible = camera instanceof OrthographicCamera ? (camera.top - camera.bottom) / zoom : 2 * Math.tan(camera.fov / 2 * Math.PI / 180) * Math.max(camera.position.distanceTo(point), EPSILON2) / zoom;
|
|
254
|
-
return visible / height * pixels;
|
|
255
|
-
}
|
|
256
250
|
function dragPlane(axis, view, point, into = new Plane()) {
|
|
257
251
|
const along = axis.lengthSq() === 0 ? ARROW_AXIS.clone() : axis.clone().normalize();
|
|
258
252
|
const side = new Vector3().crossVectors(view, along);
|
|
@@ -266,7 +260,13 @@ function perpendicular(axis) {
|
|
|
266
260
|
|
|
267
261
|
// src/tap.tsx
|
|
268
262
|
import { useThree } from "@react-three/fiber";
|
|
269
|
-
import {
|
|
263
|
+
import {
|
|
264
|
+
createContext,
|
|
265
|
+
useContext,
|
|
266
|
+
useEffect,
|
|
267
|
+
useMemo,
|
|
268
|
+
useRef
|
|
269
|
+
} from "react";
|
|
270
270
|
|
|
271
271
|
// src/render/tap.ts
|
|
272
272
|
var TAP_SLOP = 4;
|
|
@@ -294,23 +294,35 @@ function trackDoubleTaps(within = DOUBLE_TAP_MS, slop = TAP_SLOP) {
|
|
|
294
294
|
const paired = last !== null && event.timeStamp - last.timeStamp <= within && !movedFar(last, event, slop);
|
|
295
295
|
last = paired ? null : event;
|
|
296
296
|
return paired;
|
|
297
|
+
},
|
|
298
|
+
reset: () => {
|
|
299
|
+
last = null;
|
|
297
300
|
}
|
|
298
301
|
};
|
|
299
302
|
}
|
|
300
303
|
|
|
301
304
|
// src/tap.tsx
|
|
305
|
+
import { jsx } from "react/jsx-runtime";
|
|
306
|
+
var ViewerTapContext = createContext(null);
|
|
307
|
+
var ViewerTapProvider = ({ value, children }) => /* @__PURE__ */ jsx(ViewerTapContext.Provider, { value, children });
|
|
302
308
|
function useTapGuard() {
|
|
309
|
+
const shared = useContext(ViewerTapContext);
|
|
303
310
|
const domElement = useThree((state) => state.gl.domElement);
|
|
304
311
|
const tracker = useRef(null);
|
|
305
312
|
useEffect(() => {
|
|
313
|
+
if (shared) return;
|
|
306
314
|
const tracked = trackTaps(domElement);
|
|
307
315
|
tracker.current = tracked;
|
|
308
316
|
return () => {
|
|
309
317
|
tracked.dispose();
|
|
310
318
|
if (tracker.current === tracked) tracker.current = null;
|
|
311
319
|
};
|
|
312
|
-
}, [domElement]);
|
|
313
|
-
|
|
320
|
+
}, [domElement, shared]);
|
|
321
|
+
const own = useMemo(
|
|
322
|
+
() => (event) => tracker.current?.isTap(event) ?? true,
|
|
323
|
+
[]
|
|
324
|
+
);
|
|
325
|
+
return shared ?? own;
|
|
314
326
|
}
|
|
315
327
|
|
|
316
328
|
// src/render/part.ts
|
|
@@ -687,7 +699,8 @@ function buildPick(input) {
|
|
|
687
699
|
triangleIndex: input.triangleIndex,
|
|
688
700
|
point: input.point,
|
|
689
701
|
normal: input.normal,
|
|
690
|
-
modifiers: input.modifiers ?? NO_MODIFIERS
|
|
702
|
+
modifiers: input.modifiers ?? NO_MODIFIERS,
|
|
703
|
+
doubled: input.doubled ?? false
|
|
691
704
|
};
|
|
692
705
|
}
|
|
693
706
|
function focusForPick(pick, previousRegion, previousFocus) {
|
|
@@ -698,25 +711,25 @@ function focusForPick(pick, previousRegion, previousFocus) {
|
|
|
698
711
|
}
|
|
699
712
|
|
|
700
713
|
// src/viewer.tsx
|
|
701
|
-
import { Canvas, useFrame as
|
|
714
|
+
import { Canvas, useFrame as useFrame3, useThree as useThree4 } from "@react-three/fiber";
|
|
702
715
|
import {
|
|
703
|
-
createContext,
|
|
716
|
+
createContext as createContext2,
|
|
704
717
|
forwardRef,
|
|
705
718
|
useCallback,
|
|
706
|
-
useContext,
|
|
707
|
-
useEffect as
|
|
719
|
+
useContext as useContext2,
|
|
720
|
+
useEffect as useEffect4,
|
|
708
721
|
useImperativeHandle,
|
|
709
|
-
useMemo as
|
|
710
|
-
useRef as
|
|
722
|
+
useMemo as useMemo4,
|
|
723
|
+
useRef as useRef3
|
|
711
724
|
} from "react";
|
|
712
|
-
import { Box3 as Box33, Vector3 as
|
|
725
|
+
import { Box3 as Box33, Vector3 as Vector37 } from "three";
|
|
713
726
|
|
|
714
727
|
// src/camera.tsx
|
|
715
728
|
import { useFrame, useThree as useThree2 } from "@react-three/fiber";
|
|
716
729
|
import { useEffect as useEffect2, useMemo as useMemo2 } from "react";
|
|
717
730
|
|
|
718
731
|
// src/render/camera.ts
|
|
719
|
-
import { OrthographicCamera
|
|
732
|
+
import { OrthographicCamera, Vector3 as Vector33 } from "three";
|
|
720
733
|
var PERSPECTIVE_FOV = 30;
|
|
721
734
|
var DEFAULT_FIT_MARGIN = 1.2;
|
|
722
735
|
var EXCLUDE_FROM_FRAME = "viewerExcludeFromFrame";
|
|
@@ -726,6 +739,13 @@ function defaultBounds() {
|
|
|
726
739
|
function aspectRatio(size) {
|
|
727
740
|
return size.width > 0 && size.height > 0 ? size.width / size.height : 1;
|
|
728
741
|
}
|
|
742
|
+
var SCREEN_LENGTH_EPSILON = 1e-9;
|
|
743
|
+
function screenLength(camera, point, viewport, pixels) {
|
|
744
|
+
const height = viewport.height > 0 ? viewport.height : 1;
|
|
745
|
+
const zoom = camera.zoom || 1;
|
|
746
|
+
const visible = camera instanceof OrthographicCamera ? (camera.top - camera.bottom) / zoom : 2 * Math.tan(camera.fov / 2 * Math.PI / 180) * Math.max(camera.position.distanceTo(point), SCREEN_LENGTH_EPSILON) / zoom;
|
|
747
|
+
return visible / height * pixels;
|
|
748
|
+
}
|
|
729
749
|
function boundsFromBox(box) {
|
|
730
750
|
if (box.isEmpty()) return defaultBounds();
|
|
731
751
|
const center = box.getCenter(new Vector33());
|
|
@@ -774,10 +794,53 @@ function startPosition(projection, size, bounds, margin = DEFAULT_FIT_MARGIN) {
|
|
|
774
794
|
const [x, y, z] = START_DIRECTION[projection];
|
|
775
795
|
return new Vector33(x, y, z).normalize().multiplyScalar(fitDistance(projection, size, bounds, margin)).add(bounds.center);
|
|
776
796
|
}
|
|
797
|
+
var MIN_FRAME_RATIO = 0.25;
|
|
798
|
+
var MAX_FRAME_RATIO = 10;
|
|
799
|
+
var TARGET_BOUNDARY_RATIO = 4;
|
|
800
|
+
function cameraLimits(projection, size, bounds, margin = DEFAULT_FIT_MARGIN, framed) {
|
|
801
|
+
const fit = fitDistance(projection, size, bounds, margin);
|
|
802
|
+
const framedRadius = framed && framed.radius > 0 ? framed.radius : bounds.radius;
|
|
803
|
+
if (projection === "orthographic") {
|
|
804
|
+
const reach = bounds.radius > 0 ? bounds.radius / framedRadius : 1;
|
|
805
|
+
return {
|
|
806
|
+
minZoom: Math.min(MIN_FRAME_RATIO, MIN_FRAME_RATIO * reach),
|
|
807
|
+
maxZoom: Math.max(MAX_FRAME_RATIO, MAX_FRAME_RATIO * reach),
|
|
808
|
+
// Distance does not change apparent size under an orthographic camera, so
|
|
809
|
+
// these are not the zoom clamps in another form — they only keep the
|
|
810
|
+
// camera clear of the geometry it is looking at, and bounded.
|
|
811
|
+
minDistance: bounds.radius * margin,
|
|
812
|
+
maxDistance: fit / MIN_FRAME_RATIO
|
|
813
|
+
};
|
|
814
|
+
}
|
|
815
|
+
const framedFit = fitDistance(
|
|
816
|
+
projection,
|
|
817
|
+
size,
|
|
818
|
+
framedRadius === bounds.radius ? bounds : { ...bounds, radius: framedRadius },
|
|
819
|
+
margin
|
|
820
|
+
);
|
|
821
|
+
return {
|
|
822
|
+
// The wheel is `ACTION.DOLLY` under a perspective camera, so nothing here
|
|
823
|
+
// moves `camera.zoom`. They are set to the same pair anyway: a consumer
|
|
824
|
+
// that does zoom should not find the two cameras disagreeing about how far
|
|
825
|
+
// in is too far.
|
|
826
|
+
minZoom: MIN_FRAME_RATIO,
|
|
827
|
+
maxZoom: MAX_FRAME_RATIO,
|
|
828
|
+
minDistance: Math.min(fit, framedFit) / MAX_FRAME_RATIO,
|
|
829
|
+
maxDistance: Math.max(fit, framedFit) / MIN_FRAME_RATIO
|
|
830
|
+
};
|
|
831
|
+
}
|
|
832
|
+
var scratchBoundarySize = new Vector33();
|
|
833
|
+
function targetBoundary(bounds, into, margin = DEFAULT_FIT_MARGIN) {
|
|
834
|
+
const reach = bounds.radius * margin * TARGET_BOUNDARY_RATIO;
|
|
835
|
+
return into.setFromCenterAndSize(
|
|
836
|
+
bounds.center,
|
|
837
|
+
scratchBoundarySize.set(reach * 2, reach * 2, reach * 2)
|
|
838
|
+
);
|
|
839
|
+
}
|
|
777
840
|
function applyProjection(camera, size, bounds, margin = DEFAULT_FIT_MARGIN) {
|
|
778
841
|
const aspect = aspectRatio(size);
|
|
779
842
|
const radius = bounds.radius * margin;
|
|
780
|
-
if (camera instanceof
|
|
843
|
+
if (camera instanceof OrthographicCamera) {
|
|
781
844
|
const halfHeight = orthographicHalfHeight(aspect, radius);
|
|
782
845
|
const halfWidth = halfHeight * aspect;
|
|
783
846
|
camera.left = -halfWidth;
|
|
@@ -797,6 +860,11 @@ function applyProjection(camera, size, bounds, margin = DEFAULT_FIT_MARGIN) {
|
|
|
797
860
|
camera.updateProjectionMatrix();
|
|
798
861
|
}
|
|
799
862
|
var CAD_CAMERA_UP = new Vector33(0, 0, 1);
|
|
863
|
+
var scratchSide = new Vector33();
|
|
864
|
+
function adaptedUp(view, up, into) {
|
|
865
|
+
const side = scratchSide.crossVectors(view, up).normalize();
|
|
866
|
+
return into.crossVectors(side, view).normalize();
|
|
867
|
+
}
|
|
800
868
|
var cadViewDirections = {
|
|
801
869
|
front: new Vector33(0, -1, 0),
|
|
802
870
|
back: new Vector33(0, 1, 0),
|
|
@@ -817,7 +885,7 @@ import CameraControls from "camera-controls";
|
|
|
817
885
|
import {
|
|
818
886
|
Box3 as Box32,
|
|
819
887
|
Matrix4,
|
|
820
|
-
OrthographicCamera as
|
|
888
|
+
OrthographicCamera as OrthographicCamera2,
|
|
821
889
|
Quaternion,
|
|
822
890
|
Raycaster,
|
|
823
891
|
Sphere,
|
|
@@ -844,6 +912,8 @@ var FUSION_PINCH_ZOOM_SCALE = 0.04;
|
|
|
844
912
|
var FUSION_ROTATE_SCALE = 2.2;
|
|
845
913
|
var FUSION_TRUCK_SCALE = 0.33;
|
|
846
914
|
var DEFAULT_SMOOTH_TIME = 1e-3;
|
|
915
|
+
var DOLLY_SPEED = 1.15;
|
|
916
|
+
var REST_THRESHOLD = 5e-3;
|
|
847
917
|
var ExtendedCameraControls = class extends CameraControls {
|
|
848
918
|
#domElement;
|
|
849
919
|
#freeOrbit;
|
|
@@ -858,13 +928,34 @@ var ExtendedCameraControls = class extends CameraControls {
|
|
|
858
928
|
#scratchA = new Vector34();
|
|
859
929
|
#scratchB = new Vector34();
|
|
860
930
|
#scratchC = new Vector34();
|
|
861
|
-
#scratchD = new Vector34();
|
|
862
931
|
constructor(camera, domElement, options = {}) {
|
|
863
932
|
super(camera, domElement);
|
|
864
933
|
this.#domElement = domElement;
|
|
865
934
|
this.#freeOrbit = options.freeOrbit ?? true;
|
|
866
935
|
this.azimuthRotateSpeed = 0;
|
|
867
936
|
this.polarRotateSpeed = 0;
|
|
937
|
+
this.dollySpeed = DOLLY_SPEED;
|
|
938
|
+
this.restThreshold = REST_THRESHOLD;
|
|
939
|
+
}
|
|
940
|
+
/**
|
|
941
|
+
* Bounds how far the wheel may travel, and where the orbit target may go.
|
|
942
|
+
*
|
|
943
|
+
* Re-applied whenever the scene is re-measured rather than set once: the
|
|
944
|
+
* limits are derived from the part's bounds, and a viewer that loads a second
|
|
945
|
+
* part would otherwise keep the first part's idea of far.
|
|
946
|
+
*
|
|
947
|
+
* The boundary confines the *target*. Zoom-to-cursor moves it, and goes on
|
|
948
|
+
* moving it after the zoom clamp bites — which is a runaway no zoom clamp can
|
|
949
|
+
* catch. `boundaryEnclosesCamera` stays off: under an orthographic camera the
|
|
950
|
+
* camera sits well outside the framing it is looking at, so enclosing it would
|
|
951
|
+
* drag the target back in on every frame.
|
|
952
|
+
*/
|
|
953
|
+
applyLimits(limits, boundary) {
|
|
954
|
+
this.minZoom = limits.minZoom;
|
|
955
|
+
this.maxZoom = limits.maxZoom;
|
|
956
|
+
this.minDistance = limits.minDistance;
|
|
957
|
+
this.maxDistance = limits.maxDistance;
|
|
958
|
+
this.setBoundary(boundary);
|
|
868
959
|
}
|
|
869
960
|
get freeOrbit() {
|
|
870
961
|
return this.#freeOrbit;
|
|
@@ -934,7 +1025,7 @@ var ExtendedCameraControls = class extends CameraControls {
|
|
|
934
1025
|
this.mouseButtons.left = CameraControls.ACTION.ROTATE;
|
|
935
1026
|
this.mouseButtons.right = CameraControls.ACTION.TRUCK;
|
|
936
1027
|
this.mouseButtons.middle = CameraControls.ACTION.TRUCK;
|
|
937
|
-
this.mouseButtons.wheel = this.camera instanceof
|
|
1028
|
+
this.mouseButtons.wheel = this.camera instanceof OrthographicCamera2 ? CameraControls.ACTION.ZOOM : CameraControls.ACTION.DOLLY;
|
|
938
1029
|
}
|
|
939
1030
|
setFreeOrbit(freeOrbit) {
|
|
940
1031
|
if (this.#freeOrbit === freeOrbit) {
|
|
@@ -992,9 +1083,7 @@ var ExtendedCameraControls = class extends CameraControls {
|
|
|
992
1083
|
#adaptUpVector = () => {
|
|
993
1084
|
const target = this.getTarget(this.#scratchA);
|
|
994
1085
|
const view = this.#scratchB.subVectors(target, this.camera.position).normalize();
|
|
995
|
-
|
|
996
|
-
const up = this.#scratchD.crossVectors(side, view).normalize();
|
|
997
|
-
this.camera.up.copy(up);
|
|
1086
|
+
this.camera.up.copy(adaptedUp(view, this.camera.up, this.#scratchC));
|
|
998
1087
|
const position = this.getPosition(this.#scratchA);
|
|
999
1088
|
this.updateCameraUp();
|
|
1000
1089
|
void this.setPosition(position.x, position.y, position.z, false);
|
|
@@ -1110,13 +1199,173 @@ var CadCameraControls = ({
|
|
|
1110
1199
|
return null;
|
|
1111
1200
|
};
|
|
1112
1201
|
|
|
1202
|
+
// src/render/retarget.ts
|
|
1203
|
+
function retargetPose(cameraPosition, currentTarget, hitPoint) {
|
|
1204
|
+
const dx = hitPoint.x - currentTarget.x;
|
|
1205
|
+
const dy = hitPoint.y - currentTarget.y;
|
|
1206
|
+
const dz = hitPoint.z - currentTarget.z;
|
|
1207
|
+
return {
|
|
1208
|
+
position: {
|
|
1209
|
+
x: cameraPosition.x + dx,
|
|
1210
|
+
y: cameraPosition.y + dy,
|
|
1211
|
+
z: cameraPosition.z + dz
|
|
1212
|
+
},
|
|
1213
|
+
target: { x: hitPoint.x, y: hitPoint.y, z: hitPoint.z }
|
|
1214
|
+
};
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
// src/target-marker.tsx
|
|
1218
|
+
import { useFrame as useFrame2, useThree as useThree3 } from "@react-three/fiber";
|
|
1219
|
+
import { useEffect as useEffect3, useMemo as useMemo3, useRef as useRef2 } from "react";
|
|
1220
|
+
import {
|
|
1221
|
+
DoubleSide,
|
|
1222
|
+
RingGeometry,
|
|
1223
|
+
SphereGeometry,
|
|
1224
|
+
Vector3 as Vector35
|
|
1225
|
+
} from "three";
|
|
1226
|
+
|
|
1227
|
+
// src/render/target.ts
|
|
1228
|
+
var ORBIT_TARGET_PIXELS = 3;
|
|
1229
|
+
var ORBIT_TARGET_RING_PIXELS = 14;
|
|
1230
|
+
var ORBIT_TARGET_RING_WIDTH = 0.16;
|
|
1231
|
+
var ORBIT_TARGET_COLOR = 3948625;
|
|
1232
|
+
var ORBIT_TARGET_RING_COLOR = 7057587;
|
|
1233
|
+
var ORBIT_TARGET_RING_OPACITY = 0.9;
|
|
1234
|
+
var ORBIT_TARGET_FLASH_MS = 100;
|
|
1235
|
+
var ORBIT_TARGET_FADE_MS = 1e3;
|
|
1236
|
+
function orbitTargetOpacity(sinceHold, fade = ORBIT_TARGET_FADE_MS) {
|
|
1237
|
+
if (sinceHold <= 0) return 1;
|
|
1238
|
+
if (fade <= 0 || sinceHold >= fade) return 0;
|
|
1239
|
+
return 1 - sinceHold / fade;
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
// src/target-marker.tsx
|
|
1243
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
1244
|
+
var FURNITURE = { [EXCLUDE_FROM_FRAME]: true };
|
|
1245
|
+
var TargetMarker = ({ controlsRef }) => {
|
|
1246
|
+
const camera = useThree3((state) => state.camera);
|
|
1247
|
+
const size = useThree3((state) => state.size);
|
|
1248
|
+
const invalidate = useThree3((state) => state.invalidate);
|
|
1249
|
+
const registered = useThree3((state) => state.controls);
|
|
1250
|
+
const group = useRef2(null);
|
|
1251
|
+
const ring = useRef2(null);
|
|
1252
|
+
const dotMaterial = useRef2(null);
|
|
1253
|
+
const ringMaterial = useRef2(null);
|
|
1254
|
+
const dotGeometry = useMemo3(() => new SphereGeometry(1, 16, 12), []);
|
|
1255
|
+
const ringGeometry = useMemo3(() => new RingGeometry(1 - ORBIT_TARGET_RING_WIDTH, 1, 48), []);
|
|
1256
|
+
useEffect3(
|
|
1257
|
+
() => () => {
|
|
1258
|
+
dotGeometry.dispose();
|
|
1259
|
+
ringGeometry.dispose();
|
|
1260
|
+
},
|
|
1261
|
+
[dotGeometry, ringGeometry]
|
|
1262
|
+
);
|
|
1263
|
+
const dragging = useRef2(false);
|
|
1264
|
+
const heldUntil = useRef2(0);
|
|
1265
|
+
const painted = useRef2(-1);
|
|
1266
|
+
const placed = useRef2(false);
|
|
1267
|
+
const lastTarget = useMemo3(() => new Vector35(), []);
|
|
1268
|
+
const scratch = useMemo3(() => new Vector35(), []);
|
|
1269
|
+
useEffect3(() => {
|
|
1270
|
+
const controls = controlsRef.current;
|
|
1271
|
+
if (!controls) return void 0;
|
|
1272
|
+
const start = () => {
|
|
1273
|
+
dragging.current = true;
|
|
1274
|
+
invalidate();
|
|
1275
|
+
};
|
|
1276
|
+
const end = () => {
|
|
1277
|
+
dragging.current = false;
|
|
1278
|
+
heldUntil.current = performance.now();
|
|
1279
|
+
invalidate();
|
|
1280
|
+
};
|
|
1281
|
+
controls.addEventListener("controlstart", start);
|
|
1282
|
+
controls.addEventListener("controlend", end);
|
|
1283
|
+
return () => {
|
|
1284
|
+
controls.removeEventListener("controlstart", start);
|
|
1285
|
+
controls.removeEventListener("controlend", end);
|
|
1286
|
+
};
|
|
1287
|
+
}, [controlsRef, invalidate, registered]);
|
|
1288
|
+
useFrame2(() => {
|
|
1289
|
+
const controls = controlsRef.current;
|
|
1290
|
+
const node = group.current;
|
|
1291
|
+
if (!controls || !node) return;
|
|
1292
|
+
const now = performance.now();
|
|
1293
|
+
const target = controls.getTarget(scratch);
|
|
1294
|
+
if (!placed.current) {
|
|
1295
|
+
placed.current = true;
|
|
1296
|
+
lastTarget.copy(target);
|
|
1297
|
+
node.position.copy(target);
|
|
1298
|
+
} else if (!target.equals(lastTarget)) {
|
|
1299
|
+
lastTarget.copy(target);
|
|
1300
|
+
node.position.copy(target);
|
|
1301
|
+
heldUntil.current = Math.max(heldUntil.current, now + ORBIT_TARGET_FLASH_MS);
|
|
1302
|
+
}
|
|
1303
|
+
const opacity = dragging.current ? 1 : orbitTargetOpacity(now - heldUntil.current);
|
|
1304
|
+
if (opacity !== painted.current) {
|
|
1305
|
+
painted.current = opacity;
|
|
1306
|
+
node.visible = opacity > 0;
|
|
1307
|
+
if (dotMaterial.current) dotMaterial.current.opacity = opacity;
|
|
1308
|
+
if (ringMaterial.current) ringMaterial.current.opacity = opacity * ORBIT_TARGET_RING_OPACITY;
|
|
1309
|
+
invalidate();
|
|
1310
|
+
}
|
|
1311
|
+
if (node.visible) {
|
|
1312
|
+
node.scale.setScalar(screenLength(camera, target, size, 1));
|
|
1313
|
+
ring.current?.quaternion.copy(camera.quaternion);
|
|
1314
|
+
}
|
|
1315
|
+
});
|
|
1316
|
+
return /* @__PURE__ */ jsxs("group", { ref: group, visible: false, userData: FURNITURE, children: [
|
|
1317
|
+
/* @__PURE__ */ jsx2(
|
|
1318
|
+
"mesh",
|
|
1319
|
+
{
|
|
1320
|
+
ref: ring,
|
|
1321
|
+
geometry: ringGeometry,
|
|
1322
|
+
scale: ORBIT_TARGET_RING_PIXELS,
|
|
1323
|
+
renderOrder: 998,
|
|
1324
|
+
raycast: () => null,
|
|
1325
|
+
children: /* @__PURE__ */ jsx2(
|
|
1326
|
+
"meshBasicMaterial",
|
|
1327
|
+
{
|
|
1328
|
+
ref: ringMaterial,
|
|
1329
|
+
color: ORBIT_TARGET_RING_COLOR,
|
|
1330
|
+
transparent: true,
|
|
1331
|
+
opacity: 0,
|
|
1332
|
+
depthTest: false,
|
|
1333
|
+
depthWrite: false,
|
|
1334
|
+
side: DoubleSide
|
|
1335
|
+
}
|
|
1336
|
+
)
|
|
1337
|
+
}
|
|
1338
|
+
),
|
|
1339
|
+
/* @__PURE__ */ jsx2(
|
|
1340
|
+
"mesh",
|
|
1341
|
+
{
|
|
1342
|
+
geometry: dotGeometry,
|
|
1343
|
+
scale: ORBIT_TARGET_PIXELS,
|
|
1344
|
+
renderOrder: 999,
|
|
1345
|
+
raycast: () => null,
|
|
1346
|
+
children: /* @__PURE__ */ jsx2(
|
|
1347
|
+
"meshBasicMaterial",
|
|
1348
|
+
{
|
|
1349
|
+
ref: dotMaterial,
|
|
1350
|
+
color: ORBIT_TARGET_COLOR,
|
|
1351
|
+
transparent: true,
|
|
1352
|
+
opacity: 0,
|
|
1353
|
+
depthTest: false,
|
|
1354
|
+
depthWrite: false
|
|
1355
|
+
}
|
|
1356
|
+
)
|
|
1357
|
+
}
|
|
1358
|
+
)
|
|
1359
|
+
] });
|
|
1360
|
+
};
|
|
1361
|
+
|
|
1113
1362
|
// src/render/view-cube.ts
|
|
1114
1363
|
import {
|
|
1115
1364
|
BufferGeometry,
|
|
1116
1365
|
CanvasTexture,
|
|
1117
1366
|
Float32BufferAttribute as Float32BufferAttribute3,
|
|
1118
1367
|
SRGBColorSpace,
|
|
1119
|
-
Vector3 as
|
|
1368
|
+
Vector3 as Vector36
|
|
1120
1369
|
} from "three";
|
|
1121
1370
|
var VIEW_NAMES = [
|
|
1122
1371
|
// The six faces.
|
|
@@ -1200,12 +1449,12 @@ function viewUp(direction) {
|
|
|
1200
1449
|
return { x: 0, y: 0, z: 1 };
|
|
1201
1450
|
}
|
|
1202
1451
|
function squaredUp(direction, currentUp) {
|
|
1203
|
-
const forward = new
|
|
1452
|
+
const forward = new Vector36(direction.x, direction.y, direction.z).normalize();
|
|
1204
1453
|
const canonical = viewUp(direction);
|
|
1205
|
-
const zero = new
|
|
1454
|
+
const zero = new Vector36(canonical.x, canonical.y, canonical.z);
|
|
1206
1455
|
zero.addScaledVector(forward, -forward.dot(zero)).normalize();
|
|
1207
|
-
const quarter = new
|
|
1208
|
-
const current = new
|
|
1456
|
+
const quarter = new Vector36().crossVectors(forward, zero);
|
|
1457
|
+
const current = new Vector36(currentUp.x, currentUp.y, currentUp.z);
|
|
1209
1458
|
const rolls = [zero, quarter, zero.clone().negate(), quarter.clone().negate()];
|
|
1210
1459
|
const nearest = rolls.reduce(
|
|
1211
1460
|
(best, roll) => roll.dot(current) > best.dot(current) ? roll : best
|
|
@@ -1223,11 +1472,11 @@ function cubeZones(chamfer = CHAMFER) {
|
|
|
1223
1472
|
const direction = viewVector(name);
|
|
1224
1473
|
const [sx, sy, sz] = VIEW_SIGNS[name];
|
|
1225
1474
|
const sign = (axis) => VIEW_SIGNS[name][axis] ?? 0;
|
|
1226
|
-
const normal = new
|
|
1475
|
+
const normal = new Vector36(direction.x, direction.y, direction.z);
|
|
1227
1476
|
let polygon;
|
|
1228
1477
|
if (kind === "face") {
|
|
1229
1478
|
const up = viewUp(direction);
|
|
1230
|
-
const upVector = new
|
|
1479
|
+
const upVector = new Vector36(up.x, up.y, up.z);
|
|
1231
1480
|
const right = normal.clone().negate().cross(upVector).normalize();
|
|
1232
1481
|
const square = [
|
|
1233
1482
|
[-1, -1],
|
|
@@ -1249,7 +1498,7 @@ function cubeZones(chamfer = CHAMFER) {
|
|
|
1249
1498
|
[chamfer, 1, -chamfer]
|
|
1250
1499
|
];
|
|
1251
1500
|
polygon = rectangle.map(
|
|
1252
|
-
([onA, onB, onC]) => new
|
|
1501
|
+
([onA, onB, onC]) => new Vector36().setComponent(a, sign(a) * onA).setComponent(b, sign(b) * onB).setComponent(c, onC)
|
|
1253
1502
|
);
|
|
1254
1503
|
} else {
|
|
1255
1504
|
const triangle = [
|
|
@@ -1257,11 +1506,11 @@ function cubeZones(chamfer = CHAMFER) {
|
|
|
1257
1506
|
[chamfer, 1, chamfer],
|
|
1258
1507
|
[chamfer, chamfer, 1]
|
|
1259
1508
|
];
|
|
1260
|
-
polygon = triangle.map(([onX, onY, onZ]) => new
|
|
1509
|
+
polygon = triangle.map(([onX, onY, onZ]) => new Vector36(sx * onX, sy * onY, sz * onZ));
|
|
1261
1510
|
}
|
|
1262
1511
|
const [first, second, third] = polygon;
|
|
1263
1512
|
if (first && second && third) {
|
|
1264
|
-
const facing = new
|
|
1513
|
+
const facing = new Vector36().subVectors(second, first).cross(new Vector36().subVectors(third, first));
|
|
1265
1514
|
if (facing.dot(normal) < 0) polygon.reverse();
|
|
1266
1515
|
}
|
|
1267
1516
|
return { name, kind, direction, polygon: polygon.map(vec) };
|
|
@@ -1351,13 +1600,15 @@ function labelTexture(label, color) {
|
|
|
1351
1600
|
}
|
|
1352
1601
|
|
|
1353
1602
|
// src/viewer.tsx
|
|
1354
|
-
import {
|
|
1355
|
-
var ViewerControlsContext =
|
|
1603
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1604
|
+
var ViewerControlsContext = createContext2(null);
|
|
1356
1605
|
var useViewerControls = () => {
|
|
1357
|
-
const controls =
|
|
1606
|
+
const controls = useContext2(ViewerControlsContext);
|
|
1358
1607
|
if (!controls) throw new Error("useViewerControls must be used inside <Viewer>");
|
|
1359
1608
|
return controls;
|
|
1360
1609
|
};
|
|
1610
|
+
var ViewerRetargetContext = createContext2(null);
|
|
1611
|
+
var useRetarget = () => useContext2(ViewerRetargetContext);
|
|
1361
1612
|
var ViewerScene = ({
|
|
1362
1613
|
children,
|
|
1363
1614
|
setControls,
|
|
@@ -1366,20 +1617,36 @@ var ViewerScene = ({
|
|
|
1366
1617
|
freeOrbit,
|
|
1367
1618
|
zoomTo,
|
|
1368
1619
|
recentreOnDoubleClick,
|
|
1620
|
+
retargetOnDoubleClick,
|
|
1621
|
+
showOrbitTarget,
|
|
1369
1622
|
theme
|
|
1370
1623
|
}) => {
|
|
1371
|
-
const camera =
|
|
1372
|
-
const size =
|
|
1373
|
-
const invalidate =
|
|
1374
|
-
const domElement =
|
|
1375
|
-
const
|
|
1376
|
-
const
|
|
1377
|
-
const
|
|
1378
|
-
const
|
|
1379
|
-
const
|
|
1380
|
-
const
|
|
1381
|
-
const
|
|
1382
|
-
const
|
|
1624
|
+
const camera = useThree4((state) => state.camera);
|
|
1625
|
+
const size = useThree4((state) => state.size);
|
|
1626
|
+
const invalidate = useThree4((state) => state.invalidate);
|
|
1627
|
+
const domElement = useThree4((state) => state.gl.domElement);
|
|
1628
|
+
const isTap = useTapGuard();
|
|
1629
|
+
const controlsRef = useRef3(null);
|
|
1630
|
+
const contentRef = useRef3(null);
|
|
1631
|
+
const lightsRef = useRef3(null);
|
|
1632
|
+
const initialFrameComplete = useRef3(false);
|
|
1633
|
+
const boundsRef = useRef3(defaultBounds());
|
|
1634
|
+
const framedRef = useRef3(null);
|
|
1635
|
+
const scratchBox = useMemo4(() => new Box33(), []);
|
|
1636
|
+
const scratchBoundary = useMemo4(() => new Box33(), []);
|
|
1637
|
+
const scratchDirection = useMemo4(() => new Vector37(), []);
|
|
1638
|
+
const scratchView = useMemo4(() => new Vector37(), []);
|
|
1639
|
+
const scratchTarget = useMemo4(() => new Vector37(), []);
|
|
1640
|
+
const scratchPosition = useMemo4(() => new Vector37(), []);
|
|
1641
|
+
const applyLimits = useCallback(
|
|
1642
|
+
(bounds, framed) => {
|
|
1643
|
+
controlsRef.current?.applyLimits(
|
|
1644
|
+
cameraLimits(projection, size, bounds, DEFAULT_FIT_MARGIN, framed),
|
|
1645
|
+
targetBoundary(bounds, scratchBoundary, DEFAULT_FIT_MARGIN)
|
|
1646
|
+
);
|
|
1647
|
+
},
|
|
1648
|
+
[projection, scratchBoundary, size]
|
|
1649
|
+
);
|
|
1383
1650
|
const measure = useCallback(() => {
|
|
1384
1651
|
const content = contentRef.current;
|
|
1385
1652
|
boundsRef.current = content ? contentBounds(content, scratchBox) : defaultBounds();
|
|
@@ -1408,17 +1675,19 @@ var ViewerScene = ({
|
|
|
1408
1675
|
transition
|
|
1409
1676
|
);
|
|
1410
1677
|
if (projection === "orthographic") void controls.zoomTo(1, transition);
|
|
1678
|
+
framedRef.current = null;
|
|
1679
|
+
applyLimits(bounds);
|
|
1411
1680
|
invalidate();
|
|
1412
1681
|
return true;
|
|
1413
1682
|
},
|
|
1414
|
-
[camera, invalidate, measure, projection, scratchDirection, size]
|
|
1683
|
+
[applyLimits, camera, invalidate, measure, projection, scratchDirection, size]
|
|
1415
1684
|
);
|
|
1416
1685
|
const frameBounds = useCallback(
|
|
1417
1686
|
(bounds) => {
|
|
1418
1687
|
const controls = controlsRef.current;
|
|
1419
1688
|
if (!controls) return false;
|
|
1420
|
-
const target = controls.getTarget(new
|
|
1421
|
-
const direction = currentViewDirection(camera, target, new
|
|
1689
|
+
const target = controls.getTarget(new Vector37());
|
|
1690
|
+
const direction = currentViewDirection(camera, target, new Vector37());
|
|
1422
1691
|
const distance = fitDistance(projection, size, bounds, DEFAULT_FIT_MARGIN);
|
|
1423
1692
|
const position = direction.multiplyScalar(distance).add(bounds.center);
|
|
1424
1693
|
void controls.setLookAt(
|
|
@@ -1430,36 +1699,65 @@ var ViewerScene = ({
|
|
|
1430
1699
|
bounds.center.z,
|
|
1431
1700
|
true
|
|
1432
1701
|
);
|
|
1702
|
+
framedRef.current = bounds;
|
|
1703
|
+
applyLimits(boundsRef.current, bounds);
|
|
1433
1704
|
if (projection === "orthographic") {
|
|
1434
1705
|
void controls.zoomTo(boundsRef.current.radius / bounds.radius, true);
|
|
1435
1706
|
}
|
|
1436
1707
|
invalidate();
|
|
1437
1708
|
return true;
|
|
1438
1709
|
},
|
|
1439
|
-
[camera, invalidate, projection, size]
|
|
1710
|
+
[applyLimits, camera, invalidate, projection, size]
|
|
1440
1711
|
);
|
|
1441
1712
|
const fitContent = useCallback(() => {
|
|
1442
1713
|
const controls = controlsRef.current;
|
|
1443
1714
|
if (!controls) return false;
|
|
1444
|
-
const target = controls.getTarget(new
|
|
1445
|
-
return frame(currentViewDirection(camera, target, new
|
|
1715
|
+
const target = controls.getTarget(new Vector37());
|
|
1716
|
+
return frame(currentViewDirection(camera, target, new Vector37()), true);
|
|
1446
1717
|
}, [camera, frame]);
|
|
1447
1718
|
const resetContent = useCallback(() => {
|
|
1448
1719
|
const bounds = measure();
|
|
1449
1720
|
const start = startPosition(projection, size, bounds).sub(bounds.center);
|
|
1450
|
-
return frame(start, true);
|
|
1721
|
+
return frame(start, true, CAD_CAMERA_UP);
|
|
1451
1722
|
}, [frame, measure, projection, size]);
|
|
1452
|
-
|
|
1723
|
+
const retarget = useCallback(
|
|
1724
|
+
(point) => {
|
|
1725
|
+
const controls = controlsRef.current;
|
|
1726
|
+
if (!controls) return;
|
|
1727
|
+
const pose = retargetPose(
|
|
1728
|
+
controls.getPosition(scratchPosition),
|
|
1729
|
+
controls.getTarget(scratchTarget),
|
|
1730
|
+
point
|
|
1731
|
+
);
|
|
1732
|
+
void controls.setLookAt(
|
|
1733
|
+
pose.position.x,
|
|
1734
|
+
pose.position.y,
|
|
1735
|
+
pose.position.z,
|
|
1736
|
+
pose.target.x,
|
|
1737
|
+
pose.target.y,
|
|
1738
|
+
pose.target.z,
|
|
1739
|
+
true
|
|
1740
|
+
);
|
|
1741
|
+
invalidate();
|
|
1742
|
+
},
|
|
1743
|
+
[invalidate, scratchPosition, scratchTarget]
|
|
1744
|
+
);
|
|
1745
|
+
const retargetOn = useMemo4(
|
|
1746
|
+
() => retargetOnDoubleClick ? retarget : null,
|
|
1747
|
+
[retarget, retargetOnDoubleClick]
|
|
1748
|
+
);
|
|
1749
|
+
useEffect4(() => {
|
|
1453
1750
|
if (!recentreOnDoubleClick) return void 0;
|
|
1454
1751
|
const doubles = trackDoubleTaps();
|
|
1455
1752
|
const recentre = (event) => {
|
|
1456
1753
|
if (event.button !== 1) return;
|
|
1754
|
+
if (!isTap(event)) return;
|
|
1457
1755
|
if (doubles.isDouble(event)) fitContent();
|
|
1458
1756
|
};
|
|
1459
1757
|
domElement.addEventListener("auxclick", recentre);
|
|
1460
1758
|
return () => domElement.removeEventListener("auxclick", recentre);
|
|
1461
|
-
}, [domElement, fitContent, recentreOnDoubleClick]);
|
|
1462
|
-
|
|
1759
|
+
}, [domElement, fitContent, isTap, recentreOnDoubleClick]);
|
|
1760
|
+
useEffect4(() => {
|
|
1463
1761
|
setControls({
|
|
1464
1762
|
fit: () => {
|
|
1465
1763
|
fitContent();
|
|
@@ -1482,37 +1780,38 @@ var ViewerScene = ({
|
|
|
1482
1780
|
}
|
|
1483
1781
|
});
|
|
1484
1782
|
}, [camera, fitContent, frame, frameBounds, resetContent, scratchView, setControls]);
|
|
1485
|
-
|
|
1783
|
+
useEffect4(() => {
|
|
1486
1784
|
if (initialFrameComplete.current) resetContent();
|
|
1487
1785
|
}, [projection]);
|
|
1488
|
-
|
|
1786
|
+
useEffect4(() => {
|
|
1489
1787
|
applyProjection(camera, size, boundsRef.current, DEFAULT_FIT_MARGIN);
|
|
1788
|
+
if (initialFrameComplete.current) applyLimits(boundsRef.current, framedRef.current ?? void 0);
|
|
1490
1789
|
invalidate();
|
|
1491
|
-
}, [camera, invalidate, size]);
|
|
1492
|
-
|
|
1790
|
+
}, [applyLimits, camera, invalidate, size]);
|
|
1791
|
+
useFrame3(() => {
|
|
1493
1792
|
const lights = lightsRef.current;
|
|
1494
1793
|
if (lights && !lights.quaternion.equals(camera.quaternion)) {
|
|
1495
1794
|
lights.quaternion.copy(camera.quaternion);
|
|
1496
1795
|
invalidate();
|
|
1497
1796
|
}
|
|
1498
1797
|
});
|
|
1499
|
-
|
|
1798
|
+
useFrame3(() => {
|
|
1500
1799
|
if (!initialFrameComplete.current && contentRef.current?.children.length) {
|
|
1501
1800
|
initialFrameComplete.current = resetContent();
|
|
1502
1801
|
}
|
|
1503
1802
|
});
|
|
1504
|
-
return /* @__PURE__ */
|
|
1505
|
-
/* @__PURE__ */
|
|
1506
|
-
/* @__PURE__ */
|
|
1507
|
-
/* @__PURE__ */
|
|
1803
|
+
return /* @__PURE__ */ jsx3(ViewerTapProvider, { value: isTap, children: /* @__PURE__ */ jsxs2(ViewerRetargetContext.Provider, { value: retargetOn, children: [
|
|
1804
|
+
/* @__PURE__ */ jsxs2("group", { ref: lightsRef, children: [
|
|
1805
|
+
/* @__PURE__ */ jsx3("ambientLight", { color: theme.ambient, intensity: theme.ambientIntensity }),
|
|
1806
|
+
/* @__PURE__ */ jsx3(
|
|
1508
1807
|
"hemisphereLight",
|
|
1509
1808
|
{
|
|
1510
1809
|
args: [theme.hemisphereSky, theme.hemisphereGround, theme.hemisphereIntensity]
|
|
1511
1810
|
}
|
|
1512
1811
|
)
|
|
1513
1812
|
] }),
|
|
1514
|
-
/* @__PURE__ */
|
|
1515
|
-
/* @__PURE__ */
|
|
1813
|
+
/* @__PURE__ */ jsx3("group", { ref: contentRef, children }),
|
|
1814
|
+
/* @__PURE__ */ jsx3(
|
|
1516
1815
|
CadCameraControls,
|
|
1517
1816
|
{
|
|
1518
1817
|
controlsRef,
|
|
@@ -1520,24 +1819,27 @@ var ViewerScene = ({
|
|
|
1520
1819
|
freeOrbit,
|
|
1521
1820
|
zoomTo
|
|
1522
1821
|
}
|
|
1523
|
-
)
|
|
1524
|
-
|
|
1822
|
+
),
|
|
1823
|
+
showOrbitTarget ? /* @__PURE__ */ jsx3(TargetMarker, { controlsRef }) : null
|
|
1824
|
+
] }) });
|
|
1525
1825
|
};
|
|
1526
1826
|
var Viewer = forwardRef(function Viewer2({
|
|
1527
1827
|
children,
|
|
1528
1828
|
className,
|
|
1529
1829
|
style,
|
|
1530
|
-
projection = "
|
|
1830
|
+
projection = "orthographic",
|
|
1531
1831
|
controls = "toolpath",
|
|
1532
1832
|
freeOrbit = true,
|
|
1533
1833
|
zoomTo = "cursor",
|
|
1534
1834
|
recentreOnDoubleClick = true,
|
|
1835
|
+
retargetOnDoubleClick = true,
|
|
1836
|
+
showOrbitTarget = false,
|
|
1535
1837
|
theme,
|
|
1536
1838
|
onPointerMissed
|
|
1537
1839
|
}, ref) {
|
|
1538
|
-
const actionsRef =
|
|
1539
|
-
const resolved =
|
|
1540
|
-
const proxy =
|
|
1840
|
+
const actionsRef = useRef3(null);
|
|
1841
|
+
const resolved = useMemo4(() => resolveTheme(theme), [theme]);
|
|
1842
|
+
const proxy = useMemo4(
|
|
1541
1843
|
() => ({
|
|
1542
1844
|
fit: () => actionsRef.current?.fit(),
|
|
1543
1845
|
reset: () => actionsRef.current?.reset(),
|
|
@@ -1551,12 +1853,12 @@ var Viewer = forwardRef(function Viewer2({
|
|
|
1551
1853
|
const setControls = useCallback((next) => {
|
|
1552
1854
|
actionsRef.current = next;
|
|
1553
1855
|
}, []);
|
|
1554
|
-
const tracker =
|
|
1856
|
+
const tracker = useRef3(null);
|
|
1555
1857
|
const hold = useCallback((element) => {
|
|
1556
1858
|
tracker.current?.dispose();
|
|
1557
1859
|
tracker.current = element ? trackTaps(element) : null;
|
|
1558
1860
|
}, []);
|
|
1559
|
-
return /* @__PURE__ */
|
|
1861
|
+
return /* @__PURE__ */ jsx3(ViewerControlsContext.Provider, { value: proxy, children: /* @__PURE__ */ jsx3(
|
|
1560
1862
|
"div",
|
|
1561
1863
|
{
|
|
1562
1864
|
className,
|
|
@@ -1565,7 +1867,7 @@ var Viewer = forwardRef(function Viewer2({
|
|
|
1565
1867
|
if (event.target instanceof HTMLCanvasElement) event.preventDefault();
|
|
1566
1868
|
},
|
|
1567
1869
|
style: { height: "100%", width: "100%", ...style },
|
|
1568
|
-
children: /* @__PURE__ */
|
|
1870
|
+
children: /* @__PURE__ */ jsx3(
|
|
1569
1871
|
Canvas,
|
|
1570
1872
|
{
|
|
1571
1873
|
orthographic: projection === "orthographic",
|
|
@@ -1577,7 +1879,7 @@ var Viewer = forwardRef(function Viewer2({
|
|
|
1577
1879
|
if (event.button !== 0) return;
|
|
1578
1880
|
if (tracker.current?.isTap(event) ?? true) onPointerMissed?.();
|
|
1579
1881
|
},
|
|
1580
|
-
children: /* @__PURE__ */
|
|
1882
|
+
children: /* @__PURE__ */ jsx3(
|
|
1581
1883
|
ViewerScene,
|
|
1582
1884
|
{
|
|
1583
1885
|
setControls,
|
|
@@ -1586,6 +1888,8 @@ var Viewer = forwardRef(function Viewer2({
|
|
|
1586
1888
|
freeOrbit,
|
|
1587
1889
|
zoomTo,
|
|
1588
1890
|
recentreOnDoubleClick,
|
|
1891
|
+
retargetOnDoubleClick,
|
|
1892
|
+
showOrbitTarget,
|
|
1589
1893
|
theme: resolved,
|
|
1590
1894
|
children
|
|
1591
1895
|
}
|
|
@@ -1598,13 +1902,13 @@ var Viewer = forwardRef(function Viewer2({
|
|
|
1598
1902
|
});
|
|
1599
1903
|
|
|
1600
1904
|
// src/section-view.tsx
|
|
1601
|
-
import { useFrame as
|
|
1602
|
-
import { useCallback as useCallback2, useMemo as
|
|
1905
|
+
import { useFrame as useFrame4, useThree as useThree5 } from "@react-three/fiber";
|
|
1906
|
+
import { useCallback as useCallback2, useMemo as useMemo5, useRef as useRef4, useState } from "react";
|
|
1603
1907
|
import {
|
|
1604
1908
|
AlwaysStencilFunc,
|
|
1605
1909
|
BackSide,
|
|
1606
1910
|
DecrementWrapStencilOp,
|
|
1607
|
-
DoubleSide,
|
|
1911
|
+
DoubleSide as DoubleSide2,
|
|
1608
1912
|
FrontSide,
|
|
1609
1913
|
IncrementWrapStencilOp,
|
|
1610
1914
|
NotEqualStencilFunc,
|
|
@@ -1613,22 +1917,22 @@ import {
|
|
|
1613
1917
|
Raycaster as Raycaster2,
|
|
1614
1918
|
ReplaceStencilOp,
|
|
1615
1919
|
Vector2 as Vector22,
|
|
1616
|
-
Vector3 as
|
|
1920
|
+
Vector3 as Vector39
|
|
1617
1921
|
} from "three";
|
|
1618
1922
|
|
|
1619
1923
|
// src/render/directions.ts
|
|
1620
|
-
import { Vector3 as
|
|
1621
|
-
var CONE_AXIS = new
|
|
1924
|
+
import { Vector3 as Vector38 } from "three";
|
|
1925
|
+
var CONE_AXIS = new Vector38(0, 1, 0);
|
|
1622
1926
|
var LENGTH = 0.45;
|
|
1623
1927
|
var HEAD = 0.45;
|
|
1624
1928
|
var HEAD_RADIUS = 0.3;
|
|
1625
1929
|
var SHAFT_RADIUS = 0.09;
|
|
1626
1930
|
var GAP = 0.2;
|
|
1627
1931
|
function arrowPlacement(direction, box) {
|
|
1628
|
-
const center = box.getCenter(new
|
|
1629
|
-
const half = box.getSize(new
|
|
1932
|
+
const center = box.getCenter(new Vector38());
|
|
1933
|
+
const half = box.getSize(new Vector38()).multiplyScalar(0.5);
|
|
1630
1934
|
const radius = half.length() || 1;
|
|
1631
|
-
const axis = new
|
|
1935
|
+
const axis = new Vector38(direction.x, direction.y, direction.z);
|
|
1632
1936
|
if (axis.lengthSq() === 0) axis.set(0, 0, 1);
|
|
1633
1937
|
axis.normalize();
|
|
1634
1938
|
let exit = Number.POSITIVE_INFINITY;
|
|
@@ -1644,13 +1948,13 @@ function arrowPlacement(direction, box) {
|
|
|
1644
1948
|
}
|
|
1645
1949
|
|
|
1646
1950
|
// src/section-view.tsx
|
|
1647
|
-
import { jsx as
|
|
1951
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1648
1952
|
var DEFAULT_NORMAL = { x: 0, y: 0, z: 1 };
|
|
1649
|
-
var
|
|
1953
|
+
var FURNITURE2 = { [EXCLUDE_FROM_FRAME]: true };
|
|
1650
1954
|
function resolveSectionPlane(options, box) {
|
|
1651
1955
|
if (!options?.enabled || box.isEmpty()) return null;
|
|
1652
1956
|
const normal = options.plane?.normal ?? options.normal ?? DEFAULT_NORMAL;
|
|
1653
|
-
const axis = new
|
|
1957
|
+
const axis = new Vector39(normal.x, normal.y, normal.z);
|
|
1654
1958
|
if (axis.lengthSq() === 0) axis.set(0, 0, 1);
|
|
1655
1959
|
axis.normalize();
|
|
1656
1960
|
const bounds = sectionBounds(box, normal);
|
|
@@ -1678,31 +1982,31 @@ var SectionView = ({
|
|
|
1678
1982
|
showHandle,
|
|
1679
1983
|
onDrag
|
|
1680
1984
|
}) => {
|
|
1681
|
-
const camera =
|
|
1682
|
-
const size =
|
|
1683
|
-
const invalidate =
|
|
1684
|
-
const controls =
|
|
1685
|
-
const domElement =
|
|
1686
|
-
const capRef =
|
|
1687
|
-
const handleRef =
|
|
1985
|
+
const camera = useThree5((state) => state.camera);
|
|
1986
|
+
const size = useThree5((state) => state.size);
|
|
1987
|
+
const invalidate = useThree5((state) => state.invalidate);
|
|
1988
|
+
const controls = useThree5((state) => state.controls);
|
|
1989
|
+
const domElement = useThree5((state) => state.gl.domElement);
|
|
1990
|
+
const capRef = useRef4(null);
|
|
1991
|
+
const handleRef = useRef4(null);
|
|
1688
1992
|
const [hovered, setHovered] = useState(false);
|
|
1689
|
-
const dragging =
|
|
1690
|
-
const centre =
|
|
1691
|
-
const span =
|
|
1692
|
-
const clip =
|
|
1693
|
-
const capPosition =
|
|
1993
|
+
const dragging = useRef4(null);
|
|
1994
|
+
const centre = useMemo5(() => box.getCenter(new Vector39()), [box]);
|
|
1995
|
+
const span = useMemo5(() => box.getSize(new Vector39()).length(), [box]);
|
|
1996
|
+
const clip = useMemo5(() => [plane], [plane]);
|
|
1997
|
+
const capPosition = useMemo5(() => {
|
|
1694
1998
|
const point = centre.clone();
|
|
1695
1999
|
return point.addScaledVector(plane.normal, -(plane.constant + plane.normal.dot(centre)));
|
|
1696
2000
|
}, [centre, plane]);
|
|
1697
|
-
const capQuaternion =
|
|
1698
|
-
() => new Quaternion2().setFromUnitVectors(new
|
|
2001
|
+
const capQuaternion = useMemo5(
|
|
2002
|
+
() => new Quaternion2().setFromUnitVectors(new Vector39(0, 0, 1), plane.normal),
|
|
1699
2003
|
[plane]
|
|
1700
2004
|
);
|
|
1701
|
-
const handleQuaternion =
|
|
2005
|
+
const handleQuaternion = useMemo5(
|
|
1702
2006
|
() => new Quaternion2().setFromUnitVectors(CONE_AXIS, plane.normal.clone().negate()),
|
|
1703
2007
|
[plane]
|
|
1704
2008
|
);
|
|
1705
|
-
|
|
2009
|
+
useFrame4(() => {
|
|
1706
2010
|
const handle = handleRef.current;
|
|
1707
2011
|
if (!handle) return;
|
|
1708
2012
|
const length = screenLength(camera, capPosition, size, HANDLE_PIXELS);
|
|
@@ -1723,7 +2027,7 @@ var SectionView = ({
|
|
|
1723
2027
|
event.stopPropagation();
|
|
1724
2028
|
const view = camera.position.clone().sub(capPosition).normalize();
|
|
1725
2029
|
const surface = dragPlane(plane.normal.clone(), view, capPosition);
|
|
1726
|
-
const hit = event.ray.intersectPlane(surface, new
|
|
2030
|
+
const hit = event.ray.intersectPlane(surface, new Vector39());
|
|
1727
2031
|
const start = {
|
|
1728
2032
|
plane: surface,
|
|
1729
2033
|
from: hit ? hit.dot(plane.normal) : 0,
|
|
@@ -1740,7 +2044,7 @@ var SectionView = ({
|
|
|
1740
2044
|
-((native.clientY - rect.top) / rect.height) * 2 + 1
|
|
1741
2045
|
);
|
|
1742
2046
|
raycaster.setFromCamera(pointer, camera);
|
|
1743
|
-
const point = raycaster.ray.intersectPlane(start.plane, new
|
|
2047
|
+
const point = raycaster.ray.intersectPlane(start.plane, new Vector39());
|
|
1744
2048
|
if (!point) return;
|
|
1745
2049
|
onDrag(start.constant - (point.dot(plane.normal) - start.from));
|
|
1746
2050
|
invalidate();
|
|
@@ -1772,8 +2076,8 @@ var SectionView = ({
|
|
|
1772
2076
|
// Excluded from framing, all of it. The cap is a quad half again as wide as
|
|
1773
2077
|
// the part's diagonal, so a Fit that measured it would frame the cut rather
|
|
1774
2078
|
// than the part and leave the part a speck in the middle of it.
|
|
1775
|
-
/* @__PURE__ */
|
|
1776
|
-
/* @__PURE__ */
|
|
2079
|
+
/* @__PURE__ */ jsxs3("group", { userData: FURNITURE2, children: [
|
|
2080
|
+
/* @__PURE__ */ jsx4("mesh", { geometry, renderOrder: SECTION_RENDER_ORDER.stencil, raycast: () => null, children: /* @__PURE__ */ jsx4(
|
|
1777
2081
|
"meshBasicMaterial",
|
|
1778
2082
|
{
|
|
1779
2083
|
side: BackSide,
|
|
@@ -1788,7 +2092,7 @@ var SectionView = ({
|
|
|
1788
2092
|
clippingPlanes: clip
|
|
1789
2093
|
}
|
|
1790
2094
|
) }),
|
|
1791
|
-
/* @__PURE__ */
|
|
2095
|
+
/* @__PURE__ */ jsx4("mesh", { geometry, renderOrder: SECTION_RENDER_ORDER.stencil, raycast: () => null, children: /* @__PURE__ */ jsx4(
|
|
1792
2096
|
"meshBasicMaterial",
|
|
1793
2097
|
{
|
|
1794
2098
|
side: FrontSide,
|
|
@@ -1803,13 +2107,13 @@ var SectionView = ({
|
|
|
1803
2107
|
clippingPlanes: clip
|
|
1804
2108
|
}
|
|
1805
2109
|
) }),
|
|
1806
|
-
/* @__PURE__ */
|
|
1807
|
-
/* @__PURE__ */
|
|
1808
|
-
/* @__PURE__ */
|
|
2110
|
+
/* @__PURE__ */ jsx4("group", { ref: capRef, position: capPosition, quaternion: capQuaternion, children: /* @__PURE__ */ jsxs3("mesh", { renderOrder: SECTION_RENDER_ORDER.cap, raycast: () => null, children: [
|
|
2111
|
+
/* @__PURE__ */ jsx4("planeGeometry", { args: [span * 1.5, span * 1.5] }),
|
|
2112
|
+
/* @__PURE__ */ jsx4(
|
|
1809
2113
|
"meshBasicMaterial",
|
|
1810
2114
|
{
|
|
1811
2115
|
color: theme.sectionCap,
|
|
1812
|
-
side:
|
|
2116
|
+
side: DoubleSide2,
|
|
1813
2117
|
stencilWrite: true,
|
|
1814
2118
|
stencilRef: 0,
|
|
1815
2119
|
stencilFunc: NotEqualStencilFunc,
|
|
@@ -1819,7 +2123,7 @@ var SectionView = ({
|
|
|
1819
2123
|
}
|
|
1820
2124
|
)
|
|
1821
2125
|
] }) }),
|
|
1822
|
-
showHandle && onDrag ? /* @__PURE__ */
|
|
2126
|
+
showHandle && onDrag ? /* @__PURE__ */ jsxs3(
|
|
1823
2127
|
"group",
|
|
1824
2128
|
{
|
|
1825
2129
|
ref: handleRef,
|
|
@@ -1827,9 +2131,9 @@ var SectionView = ({
|
|
|
1827
2131
|
quaternion: handleQuaternion,
|
|
1828
2132
|
renderOrder: SECTION_RENDER_ORDER.handle,
|
|
1829
2133
|
children: [
|
|
1830
|
-
/* @__PURE__ */
|
|
1831
|
-
/* @__PURE__ */
|
|
1832
|
-
/* @__PURE__ */
|
|
2134
|
+
/* @__PURE__ */ jsxs3("mesh", { position: [0, 0.28, 0], ...grab, children: [
|
|
2135
|
+
/* @__PURE__ */ jsx4("coneGeometry", { args: [0.16, 0.34, 20] }),
|
|
2136
|
+
/* @__PURE__ */ jsx4(
|
|
1833
2137
|
"meshBasicMaterial",
|
|
1834
2138
|
{
|
|
1835
2139
|
color: hovered ? theme.hover : theme.sectionHandle,
|
|
@@ -1837,9 +2141,9 @@ var SectionView = ({
|
|
|
1837
2141
|
}
|
|
1838
2142
|
)
|
|
1839
2143
|
] }),
|
|
1840
|
-
/* @__PURE__ */
|
|
1841
|
-
/* @__PURE__ */
|
|
1842
|
-
/* @__PURE__ */
|
|
2144
|
+
/* @__PURE__ */ jsxs3("mesh", { position: [0, 0.08, 0], ...grab, children: [
|
|
2145
|
+
/* @__PURE__ */ jsx4("cylinderGeometry", { args: [0.045, 0.045, 0.4, 12] }),
|
|
2146
|
+
/* @__PURE__ */ jsx4(
|
|
1843
2147
|
"meshBasicMaterial",
|
|
1844
2148
|
{
|
|
1845
2149
|
color: hovered ? theme.hover : theme.sectionHandle,
|
|
@@ -1855,14 +2159,14 @@ var SectionView = ({
|
|
|
1855
2159
|
};
|
|
1856
2160
|
|
|
1857
2161
|
// src/content-box.ts
|
|
1858
|
-
import { useFrame as
|
|
1859
|
-
import { useRef as
|
|
2162
|
+
import { useFrame as useFrame5, useThree as useThree6 } from "@react-three/fiber";
|
|
2163
|
+
import { useRef as useRef5, useState as useState2 } from "react";
|
|
1860
2164
|
import { Box3 as Box34 } from "three";
|
|
1861
2165
|
function useContentBox() {
|
|
1862
|
-
const scene =
|
|
2166
|
+
const scene = useThree6((state) => state.scene);
|
|
1863
2167
|
const [box, setBox] = useState2(() => new Box34());
|
|
1864
|
-
const measured =
|
|
1865
|
-
|
|
2168
|
+
const measured = useRef5(false);
|
|
2169
|
+
useFrame5(() => {
|
|
1866
2170
|
if (measured.current) return;
|
|
1867
2171
|
const next = new Box34();
|
|
1868
2172
|
contentBounds(scene, next);
|
|
@@ -1874,7 +2178,7 @@ function useContentBox() {
|
|
|
1874
2178
|
}
|
|
1875
2179
|
|
|
1876
2180
|
// src/part-mesh.tsx
|
|
1877
|
-
import { Fragment
|
|
2181
|
+
import { Fragment, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1878
2182
|
var PartMesh = ({
|
|
1879
2183
|
model,
|
|
1880
2184
|
geometry,
|
|
@@ -1894,16 +2198,16 @@ var PartMesh = ({
|
|
|
1894
2198
|
theme,
|
|
1895
2199
|
showEdges = true
|
|
1896
2200
|
}) => {
|
|
1897
|
-
const { camera, controls, invalidate } =
|
|
2201
|
+
const { camera, controls, invalidate } = useThree7();
|
|
1898
2202
|
const viewerControls = useViewerControls();
|
|
1899
2203
|
const resolved = useStableTheme(theme);
|
|
1900
|
-
const currentTheme =
|
|
2204
|
+
const currentTheme = useRef6(resolved);
|
|
1901
2205
|
currentTheme.current = resolved;
|
|
1902
|
-
const part =
|
|
1903
|
-
const hoverRegion =
|
|
2206
|
+
const part = useMemo6(() => createPart(model, geometry, currentTheme.current), [geometry, model]);
|
|
2207
|
+
const hoverRegion = useRef6(null);
|
|
1904
2208
|
const box = useContentBox();
|
|
1905
|
-
const cut =
|
|
1906
|
-
const layers =
|
|
2209
|
+
const cut = useMemo6(() => resolveSectionPlane(section, box), [box, section]);
|
|
2210
|
+
const layers = useRef6({
|
|
1907
2211
|
selection,
|
|
1908
2212
|
candidates,
|
|
1909
2213
|
highlights,
|
|
@@ -1928,13 +2232,13 @@ var PartMesh = ({
|
|
|
1928
2232
|
);
|
|
1929
2233
|
invalidate();
|
|
1930
2234
|
}, [invalidate, part]);
|
|
1931
|
-
|
|
1932
|
-
const adjacency =
|
|
1933
|
-
|
|
2235
|
+
useEffect5(() => () => part.dispose(), [part]);
|
|
2236
|
+
const adjacency = useMemo6(() => regionAdjacency(model, geometry), [model, geometry]);
|
|
2237
|
+
useEffect5(() => {
|
|
1934
2238
|
onAdjacency?.(adjacency);
|
|
1935
2239
|
}, [adjacency, onAdjacency]);
|
|
1936
|
-
const framed =
|
|
1937
|
-
|
|
2240
|
+
const framed = useRef6(null);
|
|
2241
|
+
useEffect5(() => {
|
|
1938
2242
|
if (focusFeature === null || focusFeature === framed.current) return;
|
|
1939
2243
|
framed.current = focusFeature;
|
|
1940
2244
|
const box2 = part.boxForFeature(focusFeature);
|
|
@@ -1952,7 +2256,7 @@ var PartMesh = ({
|
|
|
1952
2256
|
part.setClippingPlanes(cut ? [cut.plane] : null);
|
|
1953
2257
|
invalidate();
|
|
1954
2258
|
}, [cut, invalidate, part]);
|
|
1955
|
-
const reportedSection =
|
|
2259
|
+
const reportedSection = useRef6("");
|
|
1956
2260
|
useLayoutEffect(() => {
|
|
1957
2261
|
const state = cut?.state ?? null;
|
|
1958
2262
|
const key = state ? `${state.constant}|${state.normal.x},${state.normal.y},${state.normal.z}` : "";
|
|
@@ -1972,7 +2276,9 @@ var PartMesh = ({
|
|
|
1972
2276
|
repaint();
|
|
1973
2277
|
}, [layerKey, repaint]);
|
|
1974
2278
|
const isTap = useTapGuard();
|
|
1975
|
-
const
|
|
2279
|
+
const retarget = useRetarget();
|
|
2280
|
+
const doubles = useMemo6(() => trackDoubleTaps(), []);
|
|
2281
|
+
const pickFor = (event, doubled = false) => {
|
|
1976
2282
|
const triangleIndex = event.faceIndex;
|
|
1977
2283
|
if (triangleIndex == null) return null;
|
|
1978
2284
|
const region = model.regionIndex.regionForTriangle(triangleIndex);
|
|
@@ -1987,6 +2293,7 @@ var PartMesh = ({
|
|
|
1987
2293
|
point: [event.point.x, event.point.y, event.point.z],
|
|
1988
2294
|
normal: [normal.x, normal.y, normal.z],
|
|
1989
2295
|
activeDirection,
|
|
2296
|
+
doubled,
|
|
1990
2297
|
viewDirection: viewDirection(camera, target),
|
|
1991
2298
|
modifiers: {
|
|
1992
2299
|
alt: source.altKey,
|
|
@@ -2017,16 +2324,24 @@ var PartMesh = ({
|
|
|
2017
2324
|
},
|
|
2018
2325
|
[box, cut, onSectionChange, section]
|
|
2019
2326
|
);
|
|
2020
|
-
return /* @__PURE__ */
|
|
2021
|
-
/* @__PURE__ */
|
|
2327
|
+
return /* @__PURE__ */ jsxs4(Fragment, { children: [
|
|
2328
|
+
/* @__PURE__ */ jsx5(
|
|
2022
2329
|
"primitive",
|
|
2023
2330
|
{
|
|
2024
2331
|
object: part.object,
|
|
2025
2332
|
onPointerMove: (event) => emitHover(pickFor(event)),
|
|
2026
|
-
onPointerOut: () =>
|
|
2333
|
+
onPointerOut: () => {
|
|
2334
|
+
emitHover(null);
|
|
2335
|
+
doubles.reset();
|
|
2336
|
+
},
|
|
2027
2337
|
onClick: (event) => {
|
|
2028
|
-
if (!isTap(event.nativeEvent))
|
|
2029
|
-
|
|
2338
|
+
if (!isTap(event.nativeEvent)) {
|
|
2339
|
+
doubles.reset();
|
|
2340
|
+
return;
|
|
2341
|
+
}
|
|
2342
|
+
const doubled = doubles.isDouble(event.nativeEvent);
|
|
2343
|
+
const pick = pickFor(event, doubled);
|
|
2344
|
+
if (doubled && retarget) retarget(event.point);
|
|
2030
2345
|
if (pick) onPick?.(pick);
|
|
2031
2346
|
},
|
|
2032
2347
|
onPointerUp: (event) => {
|
|
@@ -2040,7 +2355,7 @@ var PartMesh = ({
|
|
|
2040
2355
|
}
|
|
2041
2356
|
}
|
|
2042
2357
|
),
|
|
2043
|
-
cut ? /* @__PURE__ */
|
|
2358
|
+
cut ? /* @__PURE__ */ jsx5(
|
|
2044
2359
|
SectionView,
|
|
2045
2360
|
{
|
|
2046
2361
|
geometry,
|
|
@@ -2053,9 +2368,9 @@ var PartMesh = ({
|
|
|
2053
2368
|
) : null
|
|
2054
2369
|
] });
|
|
2055
2370
|
};
|
|
2056
|
-
var ORIGIN = new
|
|
2057
|
-
var UP = new
|
|
2058
|
-
var TARGET = new
|
|
2371
|
+
var ORIGIN = new Vector310();
|
|
2372
|
+
var UP = new Vector310(0, 0, 1);
|
|
2373
|
+
var TARGET = new Vector310();
|
|
2059
2374
|
function readTarget(controls) {
|
|
2060
2375
|
if (controls && typeof controls.getTarget === "function") {
|
|
2061
2376
|
return controls.getTarget(TARGET);
|
|
@@ -2064,14 +2379,14 @@ function readTarget(controls) {
|
|
|
2064
2379
|
return target ?? ORIGIN;
|
|
2065
2380
|
}
|
|
2066
2381
|
function useStableTheme(theme) {
|
|
2067
|
-
const held =
|
|
2382
|
+
const held = useRef6(null);
|
|
2068
2383
|
const next = resolveTheme(theme);
|
|
2069
2384
|
if (held.current === null || !themesEqual(held.current, next)) held.current = next;
|
|
2070
2385
|
return held.current;
|
|
2071
2386
|
}
|
|
2072
2387
|
|
|
2073
2388
|
// src/engine/geometry.ts
|
|
2074
|
-
import { Matrix4 as Matrix42, Mesh as
|
|
2389
|
+
import { Matrix4 as Matrix42, Mesh as Mesh3 } from "three";
|
|
2075
2390
|
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
2076
2391
|
import { STLLoader } from "three/examples/jsm/loaders/STLLoader.js";
|
|
2077
2392
|
var PartMeshError = class extends Error {
|
|
@@ -2146,7 +2461,7 @@ function parseStl(data, mesh) {
|
|
|
2146
2461
|
function singleMesh(scene) {
|
|
2147
2462
|
const meshes = [];
|
|
2148
2463
|
scene.traverse((object) => {
|
|
2149
|
-
if (object instanceof
|
|
2464
|
+
if (object instanceof Mesh3) meshes.push(object);
|
|
2150
2465
|
});
|
|
2151
2466
|
const [mesh] = meshes;
|
|
2152
2467
|
if (mesh === void 0 || meshes.length !== 1) {
|
|
@@ -2182,7 +2497,7 @@ function assertCounts(geometry, expected) {
|
|
|
2182
2497
|
}
|
|
2183
2498
|
function disposeMaterials(scene) {
|
|
2184
2499
|
scene.traverse((object) => {
|
|
2185
|
-
if (!(object instanceof
|
|
2500
|
+
if (!(object instanceof Mesh3)) return;
|
|
2186
2501
|
for (const material of Array.isArray(object.material) ? object.material : [object.material]) {
|
|
2187
2502
|
material.dispose();
|
|
2188
2503
|
}
|
|
@@ -2679,15 +2994,15 @@ function compareVersions(a, b) {
|
|
|
2679
2994
|
}
|
|
2680
2995
|
|
|
2681
2996
|
// src/engine/engine-part.tsx
|
|
2682
|
-
import { jsx as
|
|
2997
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
2683
2998
|
var EnginePart = ({ report, ...props }) => {
|
|
2684
|
-
const model =
|
|
2999
|
+
const model = useMemo7(() => normalizePartReport(report), [report]);
|
|
2685
3000
|
const resource = useGeometryResource(model);
|
|
2686
|
-
|
|
3001
|
+
useEffect6(() => {
|
|
2687
3002
|
engineGeometryCache.retain(resource);
|
|
2688
3003
|
return () => engineGeometryCache.release(resource);
|
|
2689
3004
|
}, [resource]);
|
|
2690
|
-
return /* @__PURE__ */
|
|
3005
|
+
return /* @__PURE__ */ jsx6(PartMesh, { model, geometry: resource.geometry, ...props });
|
|
2691
3006
|
};
|
|
2692
3007
|
function useGeometryResource(part) {
|
|
2693
3008
|
const resource = engineGeometryCache.get(part);
|
|
@@ -2723,7 +3038,6 @@ export {
|
|
|
2723
3038
|
sectionFromPick,
|
|
2724
3039
|
pickedStartDepth,
|
|
2725
3040
|
sectionPlane,
|
|
2726
|
-
screenLength,
|
|
2727
3041
|
dragPlane,
|
|
2728
3042
|
TAP_SLOP,
|
|
2729
3043
|
movedFar,
|
|
@@ -2752,18 +3066,34 @@ export {
|
|
|
2752
3066
|
EXCLUDE_FROM_FRAME,
|
|
2753
3067
|
defaultBounds,
|
|
2754
3068
|
aspectRatio,
|
|
3069
|
+
screenLength,
|
|
2755
3070
|
boundsFromBox,
|
|
2756
3071
|
contentBounds,
|
|
2757
3072
|
perspectiveFitDistance,
|
|
2758
3073
|
orthographicHalfHeight,
|
|
2759
3074
|
fitDistance,
|
|
2760
3075
|
startPosition,
|
|
3076
|
+
MIN_FRAME_RATIO,
|
|
3077
|
+
MAX_FRAME_RATIO,
|
|
3078
|
+
cameraLimits,
|
|
3079
|
+
targetBoundary,
|
|
2761
3080
|
applyProjection,
|
|
2762
3081
|
CAD_CAMERA_UP,
|
|
3082
|
+
adaptedUp,
|
|
2763
3083
|
cadViewDirections,
|
|
2764
3084
|
currentViewDirection,
|
|
2765
3085
|
ExtendedCameraControls,
|
|
2766
3086
|
CadCameraControls,
|
|
3087
|
+
retargetPose,
|
|
3088
|
+
ORBIT_TARGET_PIXELS,
|
|
3089
|
+
ORBIT_TARGET_RING_PIXELS,
|
|
3090
|
+
ORBIT_TARGET_RING_WIDTH,
|
|
3091
|
+
ORBIT_TARGET_COLOR,
|
|
3092
|
+
ORBIT_TARGET_RING_COLOR,
|
|
3093
|
+
ORBIT_TARGET_RING_OPACITY,
|
|
3094
|
+
ORBIT_TARGET_FLASH_MS,
|
|
3095
|
+
ORBIT_TARGET_FADE_MS,
|
|
3096
|
+
orbitTargetOpacity,
|
|
2767
3097
|
VIEW_NAMES,
|
|
2768
3098
|
VIEW_SIGNS,
|
|
2769
3099
|
viewKind,
|
|
@@ -2777,6 +3107,7 @@ export {
|
|
|
2777
3107
|
labelGeometry,
|
|
2778
3108
|
labelTexture,
|
|
2779
3109
|
useViewerControls,
|
|
3110
|
+
useRetarget,
|
|
2780
3111
|
Viewer,
|
|
2781
3112
|
CONE_AXIS,
|
|
2782
3113
|
HEAD,
|