Loading [MathJax]/extensions/TeX/AMSmath.js
Radium Engine  1.5.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Modules Pages
RotateAroundCameraManipulator.cpp
1 #include <Core/Types.hpp>
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>
8 #include <Engine/Scene/SystemDisplay.hpp>
9 #include <Gui/Utils/KeyMappingManager.hpp>
10 #include <Gui/Viewer/RotateAroundCameraManipulator.hpp>
11 #include <Gui/Viewer/Viewer.hpp>
12 
13 namespace Ra {
14 namespace Gui {
15 
16 using namespace Ra::Core::Utils;
17 
18 #define KMA_VALUE( XX ) KeyMappingManager::KeyMappingAction RotateAroundCameraManipulator::XX;
19 KeyMappingRotateAroundCamera
20 #undef KMA_VALUE
21 
22 void RotateAroundCameraManipulator::configureKeyMapping_impl() {
23  auto keyMappingManager = Gui::KeyMappingManager::getInstance();
24 
25  KeyMapping::setContext( KeyMappingManager::getInstance()->getContext( "CameraContext" ) );
26  if ( KeyMapping::getContext().isInvalid() ) {
27  LOG( logINFO )
28  << "CameraContext not defined (maybe the configuration file do not contains it)";
29  LOG( logERROR ) << "CameraContext all keymapping invalid !";
30  return;
31  }
32 
33 #define KMA_VALUE( XX ) XX = keyMappingManager->getAction( KeyMapping::getContext(), #XX );
34  KeyMappingRotateAroundCamera
35 #undef KMA_VALUE
36 }
37 
38 void RotateAroundCameraManipulator::setupKeyMappingCallbacks() {
39 
40  m_keyMappingCallbackManager.addEventCallback(
41  TRACKBALLCAMERA_ROTATE, [=]( QEvent* event ) { rotateCallback( event ); } );
42  m_keyMappingCallbackManager.addEventCallback( TRACKBALLCAMERA_PAN,
43  [=]( QEvent* event ) { panCallback( event ); } );
44  m_keyMappingCallbackManager.addEventCallback( TRACKBALLCAMERA_ZOOM,
45  [=]( QEvent* event ) { zoomCallback( event ); } );
46  m_keyMappingCallbackManager.addEventCallback(
47  TRACKBALLCAMERA_MOVE_FORWARD, [=]( QEvent* event ) { moveForwardCallback( event ); } );
48  m_keyMappingCallbackManager.addEventCallback(
49  ROTATEAROUND_ALIGN_WITH_CLOSEST_AXIS,
50  [=]( QEvent* event ) { alignWithClosestAxisCallback( event ); } );
51  m_keyMappingCallbackManager.addEventCallback(
52  ROTATEAROUND_SET_PIVOT, [=]( QEvent* event ) { setPivotCallback( event ); } );
53 }
54 
55 void RotateAroundCameraManipulator::alignWithClosestAxisCallback( QEvent* event ) {
56  if ( event->type() == QEvent::KeyPress ) { alignOnClosestAxis(); }
57 }
58 
59 void 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 );
64  }
65 }
66 void 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 );
71  }
72 }
73 void 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() );
77  }
78 }
79 void RotateAroundCameraManipulator::setPivotCallback( QEvent* event ) {
80  if ( event->type() == QEvent::KeyPress ) { setPivotFromPixel( m_lastMouseX, m_lastMouseY ); }
81 }
82 void 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 );
87  }
88 }
89 
90 void rotateAroundPoint( Ra::Core::Asset::Camera* cam,
91  Ra::Core::Vector3& target,
92  Ra::Core::Quaternion& rotation,
93  const Ra::Core::Vector3& point ) {
94  Ra::Core::Vector3 t = cam->getPosition();
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 );
102 
103  Ra::Core::Vector3 trans = point + inverseCamRotateAround * ( t - point );
104  cam->setPosition( trans );
105  target = cam->getPosition() + l * cam->getDirection();
106 }
107 
108 RotateAroundCameraManipulator::RotateAroundCameraManipulator( Ra::Gui::Viewer* viewer ) :
109  TrackballCameraManipulator(),
110  m_keyMappingCallbackManager { KeyMapping::getContext() },
111  m_viewer( viewer ) {
112  setupKeyMappingCallbacks();
113  m_cameraSensitivity = 0.5_ra;
114 }
115 
116 RotateAroundCameraManipulator::RotateAroundCameraManipulator( const CameraManipulator& cm,
117  Ra::Gui::Viewer* viewer ) :
118  TrackballCameraManipulator( cm ),
119  m_keyMappingCallbackManager { KeyMapping::getContext() },
120  m_viewer( viewer ) {
121  setupKeyMappingCallbacks();
122  m_cameraSensitivity = 0.5_ra;
123 }
124 
125 bool RotateAroundCameraManipulator::handleMouseMoveEvent(
126  QMouseEvent* event,
127  const Qt::MouseButtons& /*buttons*/,
128  const Qt::KeyboardModifiers& /* modifiers*/,
129  int key ) {
130 
131  bool handled = m_keyMappingCallbackManager.triggerEventCallback( event, key );
132 
133  m_lastMouseX = event->pos().x();
134  m_lastMouseY = event->pos().y();
135 
136  if ( m_light != nullptr ) {
137  m_light->setPosition( m_camera->getPosition() );
138  m_light->setDirection( m_camera->getDirection() );
139  }
140 
141  return handled;
142 }
143 
144 bool RotateAroundCameraManipulator::handleKeyPressEvent(
145  QKeyEvent* event,
147  return m_keyMappingCallbackManager.triggerEventCallback( action, event );
148 }
149 
150 void RotateAroundCameraManipulator::setPivot( Ra::Core::Vector3 pivot ) {
151  m_pivot = pivot;
152 }
153 
154 void RotateAroundCameraManipulator::setPivotFromPixel( Scalar x, Scalar y ) {
155  using Ra::Core::Vector3;
157 
158  auto dc = m_viewer->toDevice( { x, y } );
159 
160  m_viewer->makeCurrent();
161  Scalar z = m_viewer->getDepthUnderMouse();
162  m_viewer->doneCurrent();
163 
164  auto pivotPoint = m_camera->unProjectFromScreen( Vector3( dc[0], dc[1], z ) );
165 
166  setPivot( pivotPoint );
167 
168  // draw a 5 logical pixel sphere, shift lc by 5 pixels
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();
172 
173  auto id = RA_DISPLAY_SPHERE( pivotPoint, radius, Color::Yellow() );
174  auto ro = Engine::RadiumEngine::getInstance()->getRenderObjectManager()->getRenderObject( id );
175  ro->setLifetime( 100 );
176 }
177 
178 void 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();
184  // getFrame().inverse() is a transform we can apply on Vector3
185  Ra::Core::Vector3 pivotInCamSpace = m_camera->getFrame().inverse() * m_pivot;
186 
187  auto updateMaxAndAxis =
188  []( Ra::Core::Vector3 ref, Ra::Core::Vector3 axis, Ra::Core::Vector3& out, Scalar& max ) {
189  Scalar d = ref.dot( axis );
190  if ( d > max ) {
191  max = d;
192  out = axis;
193  }
194  };
195 
196  Scalar max = 0_ra;
197  Ra::Core::Vector3 ref = m_camera->getDirection();
198  for ( auto axis : std::vector<Ra::Core::Vector3> { -x, x, -y, y, -z, z } ) {
199  updateMaxAndAxis( ref, axis, newDirection, max );
200  }
201  m_camera->setDirection( newDirection );
202 
203  max = 0_ra;
204  ref = m_camera->getUpVector();
205  for ( auto axis : std::vector<Ra::Core::Vector3> { -x, x, -y, y, -z, z } ) {
206  updateMaxAndAxis( ref, axis, newUpVector, max );
207  }
208  m_camera->setUpVector( newUpVector );
209 
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 );
213 
214  if ( m_light != nullptr ) {
215  m_light->setPosition( m_camera->getPosition() );
216  m_light->setDirection( m_camera->getDirection() );
217  }
218 }
219 
220 KeyMappingManager::Context RotateAroundCameraManipulator::mappingContext() {
221  return KeyMapping::getContext();
222 }
223 
224 void RotateAroundCameraManipulator::fitScene( const Core::Aabb& aabb ) {
225  TrackballCameraManipulator::fitScene( aabb );
226  setPivot( aabb.center() );
227 }
228 
229 void 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 );
234 }
235 
236 Scalar 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;
240 
241  const Scalar d = x * x + y * y;
242  return d < size_limit ? std::sqrt( size2 - d ) : size_limit / std::sqrt( d );
243 }
244 
245 Ra::Core::Quaternion
246 RotateAroundCameraManipulator::deformedBallQuaternion( Scalar x, Scalar y, Scalar cx, Scalar cy ) {
247  // Points on the deformed ball
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();
252 
253  const Ra::Core::Vector3 p1( px, py, projectOnBall( px, py ) );
254  const Ra::Core::Vector3 p2( dx, dy, projectOnBall( dx, dy ) );
255  // Approximation of rotation angle
256  // Should be divided by the projectOnBall size, but it is 1.0
257  Ra::Core::Vector3 axis = p2.cross( p1 );
258 
259  if ( axis.norm() > 10_ra * Ra::Core::Math::machineEps ) {
260  const Scalar angle =
261  5.0_ra *
262  std::asin( std::sqrt( axis.squaredNorm() / p1.squaredNorm() / p2.squaredNorm() ) );
263  return Ra::Core::Quaternion( Ra::Core::AngleAxis( angle, axis.normalized() ) );
264  }
265  return Ra::Core::Quaternion {
266  Ra::Core::AngleAxis( 0_ra, Ra::Core::Vector3( 0_ra, 0_ra, 1_ra ) ) };
267 }
268 
269 void 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 );
273 
274  m_camera->applyTransform( transfo );
275 }
276 
277 void 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;
280  // Move camera and trackball center, keep the distance to the center
281  Ra::Core::Vector3 R = -m_camera->getRightVector();
282  Ra::Core::Vector3 U = m_camera->getUpVector();
283 
284  Ra::Core::Transform T( Ra::Core::Transform::Identity() );
285  Ra::Core::Vector3 t = x * R + y * U;
286  T.translate( t );
287  m_target += t;
288 
289  m_camera->applyTransform( T );
290 }
291 
292 } // namespace Gui
293 } // namespace Ra
Camera class storing the Camera frame and the projection properties The view direction is -z in camer...
Definition: Camera.hpp:16
void setPosition(const Core::Vector3 &position)
Set the position of the camera to position.
Definition: Camera.hpp:248
Core::Vector3 getPosition() const
Return the position.
Definition: Camera.hpp:244
Core::Transform getFrame() const
Definition: Camera.hpp:236
Core::Vector3 getDirection() const
Return the direction the camera is looking at.
Definition: Camera.hpp:254
Ra::Core::Utils::Index KeyMappingAction
handle to an action
Scalar angle(const Vector_ &v1, const Vector_ &v2)
Definition: Cage.cpp:3