From 6e7741706e9bddd8a9305d82c1a51a5a212de539 Mon Sep 17 00:00:00 2001 From: Nick Fisher Date: Fri, 13 Sep 2024 13:46:41 +0800 Subject: [PATCH] add pan camera implementation and fix velocity timer --- .../v2/default_pan_camera_delegate.dart | 22 +++++- .../gestures/v2/delegate_gesture_handler.dart | 68 +++++++++++++++++-- 2 files changed, 83 insertions(+), 7 deletions(-) diff --git a/thermion_flutter/thermion_flutter/lib/thermion/widgets/camera/gestures/v2/default_pan_camera_delegate.dart b/thermion_flutter/thermion_flutter/lib/thermion/widgets/camera/gestures/v2/default_pan_camera_delegate.dart index 5c58f14a..a2c9eef0 100644 --- a/thermion_flutter/thermion_flutter/lib/thermion/widgets/camera/gestures/v2/default_pan_camera_delegate.dart +++ b/thermion_flutter/thermion_flutter/lib/thermion/widgets/camera/gestures/v2/default_pan_camera_delegate.dart @@ -7,12 +7,28 @@ import 'package:vector_math/vector_math_64.dart'; class DefaultPanCameraDelegate implements PanCameraDelegate { final ThermionViewer viewer; + static const double _panSensitivity = 0.005; + DefaultPanCameraDelegate(this.viewer); @override Future panCamera(Offset delta, Vector2? velocity) async { - // Implement panning logic here - // This is a placeholder implementation - print("Panning camera by $delta"); + double deltaX = delta.dx; + double deltaY = delta.dy; + deltaX *= _panSensitivity * viewer.pixelRatio; + deltaY *= _panSensitivity * viewer.pixelRatio; + + Matrix4 currentModelMatrix = await viewer.getCameraModelMatrix(); + Vector3 currentPosition = currentModelMatrix.getTranslation(); + Quaternion currentRotation = Quaternion.fromRotation(currentModelMatrix.getRotation()); + + Vector3 right = Vector3(1, 0, 0)..applyQuaternion(currentRotation); + Vector3 up = Vector3(0, 1, 0)..applyQuaternion(currentRotation); + + Vector3 panOffset = right * -deltaX + up * deltaY; + Vector3 newPosition = currentPosition + panOffset; + + Matrix4 newModelMatrix = Matrix4.compose(newPosition, currentRotation, Vector3(1, 1, 1)); + await viewer.setCameraModelMatrix4(newModelMatrix); } } \ No newline at end of file diff --git a/thermion_flutter/thermion_flutter/lib/thermion/widgets/camera/gestures/v2/delegate_gesture_handler.dart b/thermion_flutter/thermion_flutter/lib/thermion/widgets/camera/gestures/v2/delegate_gesture_handler.dart index 84fd329f..e384f737 100644 --- a/thermion_flutter/thermion_flutter/lib/thermion/widgets/camera/gestures/v2/delegate_gesture_handler.dart +++ b/thermion_flutter/thermion_flutter/lib/thermion/widgets/camera/gestures/v2/delegate_gesture_handler.dart @@ -1,7 +1,11 @@ import 'dart:async'; import 'package:flutter/gestures.dart'; import 'package:logging/logging.dart'; +import 'package:thermion_flutter/thermion/widgets/camera/gestures/v2/default_pan_camera_delegate.dart'; +import 'package:thermion_flutter/thermion/widgets/camera/gestures/v2/default_velocity_delegate.dart'; +import 'package:thermion_flutter/thermion/widgets/camera/gestures/v2/default_zoom_camera_delegate.dart'; import 'package:thermion_flutter/thermion/widgets/camera/gestures/v2/delegates.dart'; +import 'package:thermion_flutter/thermion/widgets/camera/gestures/v2/fixed_orbit_camera_rotation_delegate.dart'; import 'package:thermion_flutter/thermion_flutter.dart'; class DelegateGestureHandler implements ThermionGestureHandler { @@ -16,6 +20,10 @@ class DelegateGestureHandler implements ThermionGestureHandler { ZoomCameraDelegate? zoomCameraDelegate; VelocityDelegate? velocityDelegate; + // Timer for continuous movement + Timer? _velocityTimer; + static const _velocityUpdateInterval = Duration(milliseconds: 16); // ~60 FPS + DelegateGestureHandler({ required this.viewer, required this.rotateCameraDelegate, @@ -24,11 +32,22 @@ class DelegateGestureHandler implements ThermionGestureHandler { required this.velocityDelegate, }); + factory DelegateGestureHandler.withDefaults(ThermionViewer viewer) => + DelegateGestureHandler( + viewer: viewer, + rotateCameraDelegate: FixedOrbitRotateCameraDelegate(viewer), + panCameraDelegate: DefaultPanCameraDelegate(viewer), + zoomCameraDelegate: DefaultZoomCameraDelegate(viewer), + velocityDelegate: DefaultVelocityDelegate()); + @override Future onPointerDown(Offset localPosition, int buttons) async { velocityDelegate?.stopDeceleration(); + _stopVelocityTimer(); } + GestureType? _lastGestureType; + @override Future onPointerMove( Offset localPosition, Offset delta, int buttons) async { @@ -37,7 +56,7 @@ class DelegateGestureHandler implements ThermionGestureHandler { GestureType gestureType; if (buttons == kPrimaryMouseButton) { gestureType = GestureType.POINTER1_MOVE; - } else if (buttons == kSecondaryMouseButton) { + } else if (buttons == kMiddleMouseButton) { gestureType = GestureType.POINTER2_MOVE; } else { throw Exception("Unsupported button: $buttons"); @@ -51,19 +70,58 @@ class DelegateGestureHandler implements ThermionGestureHandler { await panCameraDelegate?.panCamera(delta, velocityDelegate?.velocity); case GestureAction.ROTATE_CAMERA: _currentState = ThermionGestureState.ROTATING; - await rotateCameraDelegate?.rotateCamera(delta, velocityDelegate?.velocity); + await rotateCameraDelegate?.rotateCamera( + delta, velocityDelegate?.velocity); case null: // ignore; break; default: throw Exception("Unsupported gesture type : $gestureType "); } + + _lastGestureType = gestureType; } @override Future onPointerUp(int buttons) async { _currentState = ThermionGestureState.NULL; velocityDelegate?.startDeceleration(); + _startVelocityTimer(); + } + + void _startVelocityTimer() { + _stopVelocityTimer(); // Ensure any existing timer is stopped + _velocityTimer = Timer.periodic(_velocityUpdateInterval, (timer) { + _applyVelocity(); + }); + } + + void _stopVelocityTimer() { + _velocityTimer?.cancel(); + _velocityTimer = null; + } + + Future _applyVelocity() async { + final velocity = velocityDelegate?.velocity; + if (velocity == null || velocity.length < 0.1) { + _stopVelocityTimer(); + return; + } + + final lastAction = _actions[_lastGestureType]; + switch (lastAction) { + case GestureAction.PAN_CAMERA: + await panCameraDelegate?.panCamera( + Offset(velocity.x, velocity.y), velocity); + case GestureAction.ROTATE_CAMERA: + await rotateCameraDelegate?.rotateCamera( + Offset(velocity.x, velocity.y), velocity); + default: + // Do nothing for other actions + break; + } + + velocityDelegate?.updateVelocity(Offset(velocity.x, velocity.y)); // Gradually reduce velocity } @override @@ -85,7 +143,8 @@ class DelegateGestureHandler implements ThermionGestureHandler { _currentState = ThermionGestureState.ZOOMING; try { - await zoomCameraDelegate?.zoomCamera(scrollDelta, velocityDelegate?.velocity); + await zoomCameraDelegate?.zoomCamera( + scrollDelta, velocityDelegate?.velocity); } catch (e) { _logger.warning("Error during camera zoom: $e"); } finally { @@ -95,7 +154,8 @@ class DelegateGestureHandler implements ThermionGestureHandler { @override void dispose() { - // Clean up any resources if needed + _stopVelocityTimer(); + velocityDelegate?.dispose(); } @override