2#include <Core/Utils/Color.hpp>
3#include <Engine/RadiumEngine.hpp>
4#include <Engine/Rendering/RenderObject.hpp>
5#include <Engine/Rendering/RenderObjectManager.hpp>
6#include <Engine/Rendering/Renderer.hpp>
7#include <Engine/Scene/Light.hpp>
9#include <Gui/Utils/KeyMappingManager.hpp>
10#include <Gui/Viewer/RotateAroundCameraManipulator.hpp>
11#include <Gui/Viewer/Viewer.hpp>
16using namespace Ra::Core::Utils;
18#define KMA_VALUE( XX ) KeyMappingManager::KeyMappingAction RotateAroundCameraManipulator::XX;
19KeyMappingRotateAroundCamera
22void RotateAroundCameraManipulator::configureKeyMapping_impl() {
23 auto keyMappingManager = Gui::KeyMappingManager::getInstance();
25 KeyMapping::setContext( KeyMappingManager::getInstance()->getContext(
"CameraContext" ) );
26 if ( KeyMapping::getContext().isInvalid() ) {
28 <<
"CameraContext not defined (maybe the configuration file do not contains it)";
29 LOG( logERROR ) <<
"CameraContext all keymapping invalid !";
33#define KMA_VALUE( XX ) XX = keyMappingManager->getAction( KeyMapping::getContext(), #XX );
34 KeyMappingRotateAroundCamera
38void RotateAroundCameraManipulator::setupKeyMappingCallbacks() {
41 TRACKBALLCAMERA_ROTATE, [=]( QEvent* event ) { rotateCallback( event ); } );
43 [=]( QEvent* event ) { panCallback( event ); } );
45 [=]( QEvent* event ) { zoomCallback( event ); } );
47 TRACKBALLCAMERA_MOVE_FORWARD, [=]( QEvent* event ) { moveForwardCallback( event ); } );
49 ROTATEAROUND_ALIGN_WITH_CLOSEST_AXIS,
50 [=]( QEvent* event ) { alignWithClosestAxisCallback( event ); } );
52 ROTATEAROUND_SET_PIVOT, [=]( QEvent* event ) { setPivotCallback( event ); } );
55void RotateAroundCameraManipulator::alignWithClosestAxisCallback( QEvent* event ) {
56 if ( event->type() == QEvent::KeyPress ) { alignOnClosestAxis(); }
59void RotateAroundCameraManipulator::moveForwardCallback( QEvent* event ) {
60 if ( event->type() == QEvent::MouseMove ) {
61 auto mouseEvent =
reinterpret_cast<QMouseEvent*
>( event );
62 auto [dx, dy] = computeDeltaMouseMove( mouseEvent );
63 handleCameraMoveForward( dx, dy );
66void RotateAroundCameraManipulator::panCallback( QEvent* event ) {
67 if ( event->type() == QEvent::MouseMove ) {
68 auto mouseEvent =
reinterpret_cast<QMouseEvent*
>( event );
69 auto [dx, dy] = computeDeltaMouseMove( mouseEvent );
70 handleCameraPan( dx, dy );
73void RotateAroundCameraManipulator::rotateCallback( QEvent* event ) {
74 if ( event->type() == QEvent::MouseMove ) {
75 auto mouseEvent =
reinterpret_cast<QMouseEvent*
>( event );
76 handleCameraRotate( mouseEvent->pos().x(), mouseEvent->pos().y() );
79void RotateAroundCameraManipulator::setPivotCallback( QEvent* event ) {
82void RotateAroundCameraManipulator::zoomCallback( QEvent* event ) {
83 if ( event->type() == QEvent::MouseMove ) {
84 auto mouseEvent =
reinterpret_cast<QMouseEvent*
>( event );
85 auto [dx, dy] = computeDeltaMouseMove( mouseEvent );
86 handleCameraZoom( dx, dy );
91 Ra::Core::Vector3& target,
92 Ra::Core::Quaternion& rotation,
93 const Ra::Core::Vector3& point ) {
95 Scalar l = ( target - t ).norm();
96 Ra::Core::Transform inverseCamRotateAround;
97 Ra::Core::AngleAxis aa0 { rotation };
98 Ra::Core::AngleAxis aa1 { aa0.angle(), ( cam->
getFrame().linear() * aa0.axis() ).normalized() };
99 inverseCamRotateAround.setIdentity();
100 inverseCamRotateAround.rotate( aa1 );
101 cam->applyTransform( inverseCamRotateAround );
103 Ra::Core::Vector3 trans = point + inverseCamRotateAround * ( t - point );
108RotateAroundCameraManipulator::RotateAroundCameraManipulator(
Ra::Gui::Viewer* viewer ) :
110 m_keyMappingCallbackManager { KeyMapping::getContext() },
112 setupKeyMappingCallbacks();
113 m_cameraSensitivity = 0.5_ra;
116RotateAroundCameraManipulator::RotateAroundCameraManipulator(
const CameraManipulator& cm,
119 m_keyMappingCallbackManager { KeyMapping::getContext() },
121 setupKeyMappingCallbacks();
122 m_cameraSensitivity = 0.5_ra;
125bool RotateAroundCameraManipulator::handleMouseMoveEvent(
127 const Qt::MouseButtons& ,
128 const Qt::KeyboardModifiers& ,
131 bool handled = m_keyMappingCallbackManager.triggerEventCallback( event, key );
133 m_lastMouseX =
event->pos().x();
134 m_lastMouseY =
event->pos().y();
136 if ( m_light !=
nullptr ) {
137 m_light->setPosition( m_camera->getPosition() );
138 m_light->setDirection( m_camera->getDirection() );
144bool RotateAroundCameraManipulator::handleKeyPressEvent(
147 return m_keyMappingCallbackManager.triggerEventCallback( action, event );
150void RotateAroundCameraManipulator::setPivot( Ra::Core::Vector3 pivot ) {
154void RotateAroundCameraManipulator::setPivotFromPixel( Scalar x, Scalar y ) {
155 using Ra::Core::Vector3;
158 auto dc = m_viewer->toDevice( { x, y } );
160 m_viewer->makeCurrent();
161 Scalar z = m_viewer->getDepthUnderMouse();
162 m_viewer->doneCurrent();
164 auto pivotPoint = m_camera->unProjectFromScreen( Vector3( dc[0], dc[1], z ) );
166 setPivot( pivotPoint );
169 auto dcs = m_viewer->toDevice( { x + 5, y } );
170 auto pivotShifted = m_camera->unProjectFromScreen( Vector3( dcs[0], dcs[1], z ) );
171 auto radius = ( pivotPoint - pivotShifted ).norm();
173 auto id = RA_DISPLAY_SPHERE( pivotPoint, radius, Color::Yellow() );
174 auto ro = Engine::RadiumEngine::getInstance()->getRenderObjectManager()->getRenderObject(
id );
175 ro->setLifetime( 100 );
178void RotateAroundCameraManipulator::alignOnClosestAxis() {
179 Ra::Core::Vector3 x( 1_ra, 0_ra, 0_ra );
180 Ra::Core::Vector3 y( 0_ra, 1_ra, 0_ra );
181 Ra::Core::Vector3 z( 0_ra, 0_ra, 1_ra );
182 Ra::Core::Vector3 oldDirection, newDirection = m_camera->getDirection();
183 Ra::Core::Vector3 newUpVector = m_camera->getUpVector();
185 Ra::Core::Vector3 pivotInCamSpace = m_camera->getFrame().inverse() * m_pivot;
187 auto updateMaxAndAxis =
188 []( Ra::Core::Vector3
ref, Ra::Core::Vector3 axis, Ra::Core::Vector3& out, Scalar&
max ) {
189 Scalar d =
ref.dot( axis );
197 Ra::Core::Vector3
ref = m_camera->getDirection();
199 updateMaxAndAxis( ref, axis, newDirection, max );
201 m_camera->setDirection( newDirection );
204 ref = m_camera->getUpVector();
206 updateMaxAndAxis( ref, axis, newUpVector, max );
208 m_camera->setUpVector( newUpVector );
210 Ra::Core::Vector3 newPivot = m_camera->getFrame() * pivotInCamSpace;
211 Ra::Core::Vector3 trans = m_pivot - newPivot;
212 m_camera->setPosition( m_camera->getPosition() + trans );
214 if ( m_light !=
nullptr ) {
215 m_light->setPosition( m_camera->getPosition() );
216 m_light->setDirection( m_camera->getDirection() );
221 return KeyMapping::getContext();
224void RotateAroundCameraManipulator::fitScene(
const Core::Aabb& aabb ) {
225 TrackballCameraManipulator::fitScene( aabb );
226 setPivot( aabb.center() );
229void RotateAroundCameraManipulator::handleCameraRotate( Scalar x, Scalar y ) {
230 Ra::Core::Vector3 trans = m_camera->projectToScreen( m_pivot );
231 Ra::Core::Quaternion rot = deformedBallQuaternion( x, y, trans[0], trans[1] );
232 Ra::Core::Vector3 pivot = m_pivot;
233 rotateAroundPoint( m_camera, m_target, rot, pivot );
236Scalar RotateAroundCameraManipulator::projectOnBall( Scalar x, Scalar y ) {
237 const Scalar size = 1.0;
238 const Scalar size2 = size * size;
239 const Scalar size_limit = size2 * 0.5;
241 const Scalar d = x * x + y * y;
242 return d < size_limit ?
std::sqrt( size2 - d ) : size_limit /
std::
sqrt( d );
246RotateAroundCameraManipulator::deformedBallQuaternion( Scalar x, Scalar y, Scalar cx, Scalar cy ) {
248 Scalar px = m_cameraSensitivity * ( m_lastMouseX - cx ) / m_camera->getWidth();
249 Scalar py = m_cameraSensitivity * ( cy - m_lastMouseY ) / m_camera->getHeight();
250 Scalar dx = m_cameraSensitivity * ( x - cx ) / m_camera->getWidth();
251 Scalar dy = m_cameraSensitivity * ( cy - y ) / m_camera->getHeight();
253 const Ra::Core::Vector3 p1( px, py, projectOnBall( px, py ) );
254 const Ra::Core::Vector3 p2( dx, dy, projectOnBall( dx, dy ) );
257 Ra::Core::Vector3 axis = p2.cross( p1 );
259 if ( axis.norm() > 10_ra * Ra::Core::Math::machineEps ) {
263 return Ra::Core::Quaternion( Ra::Core::AngleAxis( angle, axis.normalized() ) );
265 return Ra::Core::Quaternion {
266 Ra::Core::AngleAxis( 0_ra, Ra::Core::Vector3( 0_ra, 0_ra, 1_ra ) ) };
269void RotateAroundCameraManipulator::handleCameraForward( Scalar z ) {
270 Ra::Core::Vector3 trans = m_camera->getDirection() * z;
271 Ra::Core::Transform transfo( Ra::Core::Transform::Identity() );
272 transfo.translate( trans );
274 m_camera->applyTransform( transfo );
277void RotateAroundCameraManipulator::handleCameraPan( Scalar dx, Scalar dy ) {
278 Scalar x = dx * m_cameraSensitivity * m_quickCameraModifier * m_distFromCenter * 0.1_ra;
279 Scalar y = dy * m_cameraSensitivity * m_quickCameraModifier * m_distFromCenter * 0.1_ra;
281 Ra::Core::Vector3 R = -m_camera->getRightVector();
282 Ra::Core::Vector3 U = m_camera->getUpVector();
284 Ra::Core::Transform T( Ra::Core::Transform::Identity() );
285 Ra::Core::Vector3 t = x * R + y * U;
289 m_camera->applyTransform( T );
Camera class storing the Camera frame and the projection properties The view direction is -z in camer...
void setPosition(const Core::Vector3 &position)
Set the position of the camera to position.
Core::Vector3 getPosition() const
Return the position.
Core::Transform getFrame() const
Core::Vector3 getDirection() const
Return the direction the camera is looking at.
The CameraManipulator class is the generic class for camera manipulators.
Scalar m_lastMouseX
x-position of the mouse on the screen at the manipulation start.
Scalar m_lastMouseY
y-position of the mouse on the screen at the manipulation start.
void addEventCallback(KeyMappingAction action, Callback callback)
Ra::Core::Utils::Index KeyMappingAction
handle to an action
Ra::Core::Utils::Index Context
handle to a Context
A Trackball manipulator for Cameras.
Scalar angle(const Vector_ &v1, const Vector_ &v2)
hepler function to manage enum as underlying types in VariableSet