-
Notifications
You must be signed in to change notification settings - Fork 22
Expand file tree
/
Copy pathXRVisualisationConnector.tsx
More file actions
155 lines (131 loc) · 5.89 KB
/
Copy pathXRVisualisationConnector.tsx
File metadata and controls
155 lines (131 loc) · 5.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import React, { useEffect, useState, useCallback, useRef } from 'react';
import { useFrame, useThree } from '@react-three/fiber';
import { useXR } from '@react-three/xr';
import { useXRCore } from '../providers/XRCoreProvider';
import { MetadataVisualizer, useTextLabelManager } from '../../visualisation/components/MetadataVisualizer';
import { useHandTracking } from '../systems/HandInteractionSystem';
import { useSettingsStore } from '../../../store/settingsStore';
import { useMultiUserStore, MultiUserConnection } from '../../../store/multiUserStore';
import { createLogger } from '../../../utils/logger';
import * as THREE from 'three';
const logger = createLogger('XRVisualisationConnector');
/**
* XRVisualisationConnector connects the Quest 3 AR hand interaction system
* with the visualisation system and platform manager.
*
* This component acts as the dependency injector between these systems.
* It uses the enhanced XRCoreProvider for robust session management.
*/
const XRVisualisationConnector: React.FC = () => {
const { isSessionActive: isXRMode, sessionType } = useXRCore();
const { isPresenting, player } = useXR();
const { camera } = useThree();
const settings = useSettingsStore(state => state.settings);
const handTracking = useHandTracking();
const labelManager = useTextLabelManager();
const [interactionEnabled, setInteractionEnabled] = useState(true);
const multiUserConnection = useRef<MultiUserConnection | null>(null);
const raycastRef = useRef<THREE.Raycaster>(new THREE.Raycaster());
const updateLocalPosition = useMultiUserStore(state => state.updateLocalPosition);
const updateLocalSelection = useMultiUserStore(state => state.updateLocalSelection);
const setLocalUserId = useMultiUserStore(state => state.setLocalUserId);
// Initialize multi-user connection when entering AR
useEffect(() => {
if (isPresenting && settings?.xr?.enableMultiUser !== false) {
// Generate or retrieve user ID
const userId = `user_${Math.random().toString(36).substr(2, 9)}`;
setLocalUserId(userId);
// Connect to multi-user server
const wsUrl = settings?.xr?.multiUserServerUrl || 'ws://localhost:8080';
multiUserConnection.current = new MultiUserConnection(wsUrl);
multiUserConnection.current.connect();
logger.info('Multi-user connection initialized', { userId, wsUrl });
}
return () => {
if (multiUserConnection.current) {
multiUserConnection.current.disconnect();
multiUserConnection.current = null;
}
};
}, [isPresenting, settings?.xr?.enableMultiUser, settings?.xr?.multiUserServerUrl, setLocalUserId]);
// Handle platform changes (Quest 3 AR focused)
useEffect(() => {
// Configure interactivity based on Quest 3 AR mode
const isQuest3AR = isXRMode && sessionType === 'immersive-ar';
setInteractionEnabled(isQuest3AR && settings?.xr?.enableHandTracking !== false);
// Debug logging
if (isQuest3AR) {
if (settings?.system?.debug?.enabled) {
logger.info('Quest 3 AR mode active, configuring visualisation for hand interaction');
}
}
}, [isXRMode, sessionType, settings?.xr?.enableHandTracking, settings?.system?.debug?.enabled]);
// Update user position and rotation in AR space
useFrame(() => {
if (!isPresenting || !player) return;
// Get head position and rotation from XR player
const position = player.position.toArray() as [number, number, number];
const rotation = [
player.rotation.x,
player.rotation.y,
player.rotation.z
] as [number, number, number];
updateLocalPosition(position, rotation);
});
// Handle hand gesture interactions with visualisations
useEffect(() => {
if (!interactionEnabled) return;
const { pinchState, handPositions, isLeftHandVisible, isRightHandVisible } = handTracking;
// Update selection state for multi-user
const isSelecting = pinchState.left || pinchState.right;
updateLocalSelection(isSelecting);
// Perform raycasting for node selection
if (isSelecting) {
const handPos = pinchState.left ? handPositions.left : handPositions.right;
if (handPos) {
// Create ray from hand position
const origin = new THREE.Vector3(...handPos);
const direction = new THREE.Vector3(0, 0, -1); // Forward direction
// Apply hand rotation if available
if (camera) {
direction.applyQuaternion(camera.quaternion);
}
raycastRef.current.set(origin, direction);
// Raycast against graph nodes (implementation would integrate with GraphManager)
// This is where you'd check for intersections with graph nodes
logger.debug(`Hand selection at [${handPos[0]}, ${handPos[1]}, ${handPos[2]}]`);
}
}
return () => {
// Cleanup if needed
};
}, [handTracking.pinchState, handTracking.handPositions, interactionEnabled, camera, updateLocalSelection]);
// Render the visualisation system with AR-specific enhancements
return (
<>
<MetadataVisualizer
renderLabels={settings?.visualisation?.labels?.enableLabels !== false}
/>
{/* AR-specific UI overlay */}
{isPresenting && (
<group>
{/* Connection status indicator */}
<mesh position={[0, 2.5, -2]}>
<planeGeometry args={[0.5, 0.1]} />
<meshBasicMaterial
color={useMultiUserStore.getState().connectionStatus === 'connected' ? '#00ff00' : '#ff0000'}
transparent
opacity={0.8}
/>
</mesh>
{/* User count display */}
<mesh position={[0.6, 2.5, -2]}>
<planeGeometry args={[0.3, 0.1]} />
<meshBasicMaterial color="#ffffff" transparent opacity={0.8} />
</mesh>
</group>
)}
</>
);
};
export default XRVisualisationConnector;