@vitessce/all 4.0.0-test.1 → 4.0.0-test.3

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.
@@ -0,0 +1,247 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import { useRef, useEffect, useState } from "react";
3
+ import { useThree, useFrame } from "@react-three/fiber";
4
+ import { Bvh } from "@react-three/drei";
5
+ import { useXR, useXRInputSourceState } from "@react-three/xr";
6
+ import { Matrix4, Vector3, Box3, FrontSide } from "three";
7
+ import { i as isValidGeometrySize, M as MeasureLine, s as stringifyLineData } from "./index-CIJWVuYa.js";
8
+ function getHandJoint(hand, jointName) {
9
+ return hand.get(jointName);
10
+ }
11
+ function getJointPosition(hand, jointName, frame, refSpace) {
12
+ if (!hand?.inputSource?.hand)
13
+ return null;
14
+ const jointSpace = getHandJoint(hand.inputSource.hand, jointName);
15
+ if (!jointSpace)
16
+ return null;
17
+ const pose = frame.getJointPose?.(jointSpace, refSpace);
18
+ if (!pose)
19
+ return null;
20
+ return new Vector3(pose.transform.position.x, pose.transform.position.y, pose.transform.position.z);
21
+ }
22
+ function isPinching(hand, frame, refSpace, threshold = 0.02) {
23
+ const thumbPos = getJointPosition(hand, "thumb-tip", frame, refSpace);
24
+ const indexPos = getJointPosition(hand, "index-finger-tip", frame, refSpace);
25
+ if (!thumbPos || !indexPos)
26
+ return false;
27
+ return thumbPos.distanceTo(indexPos) < threshold;
28
+ }
29
+ function GeometryAndMeshXR(props) {
30
+ const { segmentationGroup, segmentationSettings, segmentationSceneScale, renderingSettings, materialRef, highlightEntity, setObsHighlight } = props;
31
+ const model = useRef(null);
32
+ const distanceRef = useRef(null);
33
+ const rayGrabGroup = useRef(null);
34
+ const grabControllerRef = useRef(null);
35
+ useRef(new Matrix4());
36
+ const initialScale = useRef(null);
37
+ const secondPointerId = useRef(null);
38
+ const initialDistance = useRef(0);
39
+ const lastPointerPositions = useRef(/* @__PURE__ */ new Map());
40
+ const session = useXR((state) => state.session);
41
+ const isPresenting = session != null;
42
+ useEffect(() => {
43
+ if (materialRef?.current?.material?.uniforms?.u_physical_Pixel) {
44
+ materialRef.current.material.uniforms.u_physical_Pixel.value = isPresenting ? 0.2 : 2.5;
45
+ }
46
+ }, [isPresenting, materialRef]);
47
+ const { scene, gl } = useThree();
48
+ const rightHand = useXRInputSourceState("hand", "right");
49
+ const leftHand = useXRInputSourceState("hand", "left");
50
+ const [measureState, setMeasureState] = useState(false);
51
+ const [highlighted, setHighlighted] = useState(false);
52
+ const [showLine, setShowLine] = useState(false);
53
+ const [currentLine, setCurrentLine] = useState({
54
+ startPoint: new Vector3(),
55
+ midPoint: new Vector3(),
56
+ endPoint: new Vector3(),
57
+ setStartPoint: false,
58
+ setEndPoint: false
59
+ });
60
+ const [lines, setLines] = useState([]);
61
+ const [debounce, setDebounce] = useState(0);
62
+ const measureStateRef = useRef(measureState);
63
+ measureStateRef.current = measureState;
64
+ const highlightedRef = useRef(highlighted);
65
+ highlightedRef.current = highlighted;
66
+ const currentLineRef = useRef(currentLine);
67
+ currentLineRef.current = currentLine;
68
+ const linesRef = useRef(lines);
69
+ linesRef.current = lines;
70
+ const debounceRef = useRef(debounce);
71
+ debounceRef.current = debounce;
72
+ useFrame((_state, _delta, frame) => {
73
+ if (!isPresenting || !frame)
74
+ return;
75
+ const refSpace = gl.xr.getReferenceSpace();
76
+ if (!refSpace)
77
+ return;
78
+ const rightTipBbox = scene.getObjectByName("rightTipBbox");
79
+ const leftTipBbox = scene.getObjectByName("leftTipBbox");
80
+ if (!rightTipBbox || !leftTipBbox)
81
+ return;
82
+ const leftTipBB = new Box3().setFromObject(leftTipBbox);
83
+ const rightTipBB = new Box3().setFromObject(rightTipBbox);
84
+ let intersected = false;
85
+ setDebounce((prev) => prev - 1);
86
+ if (leftTipBB.intersectsBox(rightTipBB) && leftTipBB.max.x !== -rightTipBB.min.x) {
87
+ setMeasureState(true);
88
+ setShowLine(true);
89
+ setCurrentLine({
90
+ startPoint: new Vector3(),
91
+ midPoint: new Vector3(),
92
+ endPoint: new Vector3(),
93
+ setStartPoint: false,
94
+ setEndPoint: false
95
+ });
96
+ }
97
+ const curMeasureState = measureStateRef.current;
98
+ const curLine = currentLineRef.current;
99
+ if (curMeasureState) {
100
+ let leftFingerPosition = getJointPosition(leftHand, "index-finger-tip", frame, refSpace);
101
+ let rightFingerPosition = getJointPosition(rightHand, "index-finger-tip", frame, refSpace);
102
+ if (!leftFingerPosition || !rightFingerPosition)
103
+ return;
104
+ if (rayGrabGroup.current) {
105
+ leftFingerPosition = leftFingerPosition.applyMatrix4(rayGrabGroup.current.matrixWorld.clone().invert());
106
+ rightFingerPosition = rightFingerPosition.applyMatrix4(rayGrabGroup.current.matrixWorld.clone().invert());
107
+ }
108
+ let currentStart = leftFingerPosition.clone();
109
+ let currentEnd = rightFingerPosition.clone();
110
+ if (curLine.setStartPoint) {
111
+ currentStart = curLine.startPoint;
112
+ }
113
+ if (curLine.setEndPoint) {
114
+ currentEnd = curLine.endPoint;
115
+ }
116
+ setCurrentLine({
117
+ startPoint: currentStart,
118
+ midPoint: new Vector3().addVectors(currentStart, currentEnd).multiplyScalar(0.5),
119
+ endPoint: currentEnd,
120
+ setStartPoint: curLine.setStartPoint,
121
+ setEndPoint: curLine.setEndPoint
122
+ });
123
+ if (isPinching(rightHand, frame, refSpace)) {
124
+ setCurrentLine((prev) => ({
125
+ ...prev,
126
+ setEndPoint: true
127
+ }));
128
+ }
129
+ if (isPinching(leftHand, frame, refSpace)) {
130
+ setCurrentLine((prev) => ({
131
+ ...prev,
132
+ setStartPoint: true
133
+ }));
134
+ }
135
+ if (curLine.setStartPoint && curLine.setEndPoint) {
136
+ setLines((prev) => [...prev, curLine]);
137
+ setShowLine(false);
138
+ setMeasureState(false);
139
+ setDebounce(8);
140
+ }
141
+ } else if (debounceRef.current <= 0 && model.current && isPresenting) {
142
+ const modelScene = model.current;
143
+ modelScene.children[0].children.forEach((_childVal, childID) => {
144
+ const child = modelScene.children[0].children[childID];
145
+ const currentObjectBB = new Box3().setFromObject(child);
146
+ const intersectsLeftTip = leftTipBB.intersectsBox(currentObjectBB);
147
+ const intersectsRightTip = rightTipBB.intersectsBox(currentObjectBB);
148
+ if (intersectsLeftTip || intersectsRightTip) {
149
+ intersected = true;
150
+ setObsHighlight(child.name);
151
+ setHighlighted(true);
152
+ if (intersectsLeftTip && isPinching(leftHand, frame, refSpace)) {
153
+ setDebounce(10);
154
+ intersected = false;
155
+ }
156
+ if (intersectsRightTip && isPinching(rightHand, frame, refSpace)) {
157
+ setDebounce(10);
158
+ intersected = false;
159
+ }
160
+ }
161
+ });
162
+ if (!intersected && highlightedRef.current) {
163
+ setObsHighlight(null);
164
+ setHighlighted(false);
165
+ }
166
+ }
167
+ });
168
+ const handlePointerDown = (e) => {
169
+ if (!isPresenting)
170
+ return;
171
+ e.stopPropagation();
172
+ e.target.setPointerCapture(e.pointerId);
173
+ if (grabControllerRef.current === null) {
174
+ grabControllerRef.current = e.pointerId;
175
+ lastPointerPositions.current.set(e.pointerId, e.point.clone());
176
+ if (rayGrabGroup.current) {
177
+ initialScale.current = rayGrabGroup.current.scale.clone();
178
+ }
179
+ } else if (secondPointerId.current === null && e.pointerId !== grabControllerRef.current) {
180
+ secondPointerId.current = e.pointerId;
181
+ lastPointerPositions.current.set(e.pointerId, e.point.clone());
182
+ const p1 = lastPointerPositions.current.get(grabControllerRef.current);
183
+ const p2 = e.point;
184
+ if (p1) {
185
+ initialDistance.current = p1.distanceTo(p2);
186
+ }
187
+ if (rayGrabGroup.current) {
188
+ initialScale.current = rayGrabGroup.current.scale.clone();
189
+ }
190
+ }
191
+ };
192
+ const handlePointerUp = (e) => {
193
+ e.target.releasePointerCapture(e.pointerId);
194
+ lastPointerPositions.current.delete(e.pointerId);
195
+ if (grabControllerRef.current === e.pointerId) {
196
+ grabControllerRef.current = null;
197
+ initialScale.current = null;
198
+ }
199
+ if (secondPointerId.current === e.pointerId) {
200
+ secondPointerId.current = null;
201
+ initialDistance.current = 0;
202
+ }
203
+ };
204
+ const handlePointerMove = (e) => {
205
+ if (!rayGrabGroup.current || !e.point)
206
+ return;
207
+ const isFirstPointer = grabControllerRef.current === e.pointerId;
208
+ const isSecondPointer = secondPointerId.current === e.pointerId;
209
+ if (!isFirstPointer && !isSecondPointer)
210
+ return;
211
+ const prevPos = lastPointerPositions.current.get(e.pointerId);
212
+ lastPointerPositions.current.set(e.pointerId, e.point.clone());
213
+ if (secondPointerId.current !== null && initialDistance.current > 0 && initialScale.current) {
214
+ const p1 = lastPointerPositions.current.get(grabControllerRef.current);
215
+ const p2 = lastPointerPositions.current.get(secondPointerId.current);
216
+ if (p1 && p2) {
217
+ const currentDistance = p1.distanceTo(p2);
218
+ const scaleFactor = currentDistance / initialDistance.current;
219
+ rayGrabGroup.current.scale.copy(initialScale.current).multiplyScalar(scaleFactor);
220
+ }
221
+ } else if (isFirstPointer && prevPos) {
222
+ const delta = e.point.clone().sub(prevPos);
223
+ rayGrabGroup.current.position.add(delta);
224
+ }
225
+ };
226
+ if (isPresenting) {
227
+ return jsxs("group", { children: [jsxs("group", { ref: rayGrabGroup, onPointerDown: handlePointerDown, onPointerUp: handlePointerUp, onPointerMove: handlePointerMove, children: [segmentationGroup?.visible ? jsxs("group", { children: [jsx("hemisphereLight", { color: 8421504, groundColor: 6316128 }), jsx("directionalLight", { color: 16777215, position: [0, -800, 0] }), jsx("primitive", { ref: model, object: segmentationGroup, position: [-0.18, 1.13, -1], scale: [
228
+ 2e-3 * segmentationSceneScale[0],
229
+ 2e-3 * segmentationSceneScale[1],
230
+ 2e-3 * segmentationSceneScale[2]
231
+ ] })] }) : null, renderingSettings.uniforms && renderingSettings.shader && renderingSettings.meshScale ? jsx("group", { children: jsxs("mesh", { name: "cube", position: [-0.18, 1.13, -1], rotation: [0, 0, 0], scale: [
232
+ 2e-3 * renderingSettings.meshScale[0],
233
+ 2e-3 * renderingSettings.meshScale[1],
234
+ 2e-3 * renderingSettings.meshScale[2]
235
+ ], ref: materialRef, children: [isValidGeometrySize(renderingSettings.geometrySize) && jsx("boxGeometry", { args: renderingSettings.geometrySize }), jsx("shaderMaterial", { customProgramCacheKey: () => "1", side: FrontSide, uniforms: renderingSettings.uniforms, needsUpdate: true, transparent: true, vertexShader: renderingSettings.shader.vertexShader, fragmentShader: renderingSettings.shader.fragmentShader })] }) }) : null] }), jsx("group", { name: "currentLine", ref: distanceRef, children: showLine ? jsx(MeasureLine, { currentLine, scale: 1 / 2e-3 * 0.4 }) : null }), jsx("group", { name: "lines", children: lines.map((object) => jsx(MeasureLine, { currentLine: object, scale: 1 / 2e-3 * 0.4 }, stringifyLineData(object))) })] });
236
+ }
237
+ return jsxs("group", { children: [jsxs("group", { children: [segmentationGroup?.visible ? jsxs("group", { children: [jsx("hemisphereLight", { color: 8421504, groundColor: 6316128 }), jsx("directionalLight", { color: 16777215, position: [0, -800, 0] }), jsx("directionalLight", { color: 16777215, position: [0, 800, 0] }), jsx(Bvh, { firstHitOnly: true, children: jsx("primitive", { ref: model, object: segmentationGroup, position: [0, 0, 0], onClick: (e) => {
238
+ if (e.object.parent?.userData.name === "finalPass") {
239
+ highlightEntity(e.object.name, e.object.userData.layerScope, e.object.userData.channelScope);
240
+ }
241
+ }, onPointerOver: (e) => {
242
+ setObsHighlight(e.object.name);
243
+ }, onPointerOut: () => setObsHighlight(null) }) })] }) : null, renderingSettings.uniforms && renderingSettings.shader && renderingSettings.meshScale && renderingSettings.geometrySize ? jsx("group", { children: jsxs("mesh", { scale: renderingSettings.meshScale, ref: materialRef, children: [jsx("boxGeometry", { args: renderingSettings.geometrySize }), jsx("shaderMaterial", { customProgramCacheKey: () => "1", side: FrontSide, uniforms: renderingSettings.uniforms, needsUpdate: true, transparent: true, vertexShader: renderingSettings.shader.vertexShader, fragmentShader: renderingSettings.shader.fragmentShader })] }) }) : null] }), jsx("group", { name: "lines", children: lines.map((object) => jsx(MeasureLine, { currentLine: object, scale: 1 }, stringifyLineData(object))) })] });
244
+ }
245
+ export {
246
+ GeometryAndMeshXR as default
247
+ };