KiCad PCB EDA Suite
ccamera.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
5  * Copyright (C) 1992-2017 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
30 #include "ccamera.h"
31 #include <wx/log.h>
32 
33 
34 // A helper function to normalize aAngle between -2PI and +2PI
35 inline void normalise2PI( float& aAngle )
36 {
37  while( aAngle > 0.0 )
38  aAngle -= M_PI*2;
39 
40  while( aAngle < 0.0 )
41  aAngle += M_PI*2;
42 }
43 
44 
51 const wxChar *CCAMERA::m_logTrace = wxT( "KI_TRACE_CCAMERA" );
52 
53 #define MIN_ZOOM 0.10f
54 #define MAX_ZOOM 1.25f
55 
56 CCAMERA::CCAMERA( float aRangeScale )
57 {
58  wxLogTrace( m_logTrace, wxT( "CCAMERA::CCAMERA" ) );
59 
60  m_range_scale = aRangeScale;
61  m_camera_pos_init = SFVEC3F( 0.0f, 0.0f, -(aRangeScale * 2.0f ) );
63  m_windowSize = SFVEC2I( 0, 0 );
66 
67  Reset();
68 }
69 
70 
72 {
73  m_parametersChanged = true;
74  m_projectionMatrix = glm::mat4( 1.0f );
75  m_projectionMatrixInv = glm::mat4( 1.0f );
76  m_rotationMatrix = glm::mat4( 1.0f );
77  m_rotationMatrixAux = glm::mat4( 1.0f );
78  m_lastPosition = wxPoint( 0, 0 );
79 
80  m_zoom = 1.0f;
81  m_zoom_t0 = 1.0f;
82  m_zoom_t1 = 1.0f;
89 
90  m_rotate_aux = SFVEC3F( 0.0f );
91  m_rotate_aux_t0 = SFVEC3F( 0.0f );
92  m_rotate_aux_t1 = SFVEC3F( 0.0f );
93 
96  m_viewMatrixInverse = glm::inverse( m_viewMatrix );
97  m_scr_nX.clear();
98  m_scr_nY.clear();
100 }
101 
102 
104 {
106  m_zoom_t1 = 1.0f;
107  m_rotate_aux_t1 = SFVEC3F( 0.0f );
109 
110 
111  // Since 0 = 2pi, we want to reset the angle to be the closest
112  // one to where we currently are. That ensures that we rotate
113  // the board around the smallest distance getting there.
114  if( m_rotate_aux_t0.x > M_PI )
115  m_rotate_aux_t1.x = 2*M_PI;
116 
117  if( m_rotate_aux_t0.y > M_PI )
118  m_rotate_aux_t1.y = 2*M_PI;
119 
120  if( m_rotate_aux_t0.z > M_PI )
121  m_rotate_aux_t1.z = 2*M_PI;
122 
123 }
124 
125 
127 {
128  m_viewMatrix = glm::translate( glm::mat4( 1.0f ), m_camera_pos ) *
130  glm::translate( glm::mat4( 1.0f ), -m_lookat_pos );
131 }
132 
133 
135 {
136  m_rotationMatrixAux = glm::rotate( glm::mat4( 1.0f ),
137  m_rotate_aux.x,
138  SFVEC3F( 1.0f, 0.0f, 0.0f ) );
140 
142  m_rotate_aux.y,
143  SFVEC3F( 0.0f, 1.0f, 0.0f ) );
145 
147  m_rotate_aux.z,
148  SFVEC3F( 0.0f, 0.0f, 1.0f ) );
150 
151  m_parametersChanged = true;
152 
154  updateFrustum();
155 }
156 
157 
158 const glm::mat4 CCAMERA::GetRotationMatrix() const
159 {
161 }
162 
163 
165 {
166  if( (m_windowSize.x == 0) ||
167  (m_windowSize.y == 0) )
168  return;
169 
170  m_frustum.ratio = (float) m_windowSize.x / (float)m_windowSize.y;
171 
172  // Consider that we can render double the length multiplied by the 2/sqrt(2)
173  //
174  m_frustum.farD = glm::length( m_camera_pos_init ) * 2.0f * ( 2.0f * sqrtf( 2.0f ) );
175 
176  switch( m_projectionType )
177  {
178  default:
180 
181  m_frustum.nearD = 0.10f;
182 
183  // Ratio width / height of the window display
184  m_frustum.angle = 45.0f * m_zoom;
185 
186 
187  m_projectionMatrix = glm::perspective( glm::radians( m_frustum.angle ),
190  m_frustum.farD );
191 
192  m_projectionMatrixInv = glm::inverse( m_projectionMatrix );
193 
194  m_frustum.tang = glm::tan( glm::radians( m_frustum.angle ) * 0.5f );
195 
196  m_focalLen.x = ( (float)m_windowSize.y / (float)m_windowSize.x ) / m_frustum.tang;
197  m_focalLen.y = 1.0f / m_frustum.tang;
198 
203  break;
204 
206 
207  m_frustum.nearD = -m_frustum.farD; // Use a symmetrical clip plane for ortho projection
208 
209  // This formula was found by trial and error
210  const float orthoReductionFactor = glm::length( m_camera_pos_init ) *
211  m_zoom * m_zoom * 0.5f;
212 
213  // Initialize Projection Matrix for Ortographic View
214  m_projectionMatrix = glm::ortho( -m_frustum.ratio * orthoReductionFactor,
215  m_frustum.ratio * orthoReductionFactor,
216  -orthoReductionFactor,
217  orthoReductionFactor,
219 
220  m_projectionMatrixInv = glm::inverse( m_projectionMatrix );
221 
222  m_frustum.nw = orthoReductionFactor * 2.0f * m_frustum.ratio;
223  m_frustum.nh = orthoReductionFactor * 2.0f;
226 
227  break;
228  }
229 
230  if ( (m_windowSize.x > 0) &&
231  (m_windowSize.y > 0) )
232  {
233  m_scr_nX.resize( m_windowSize.x + 1 );
234  m_scr_nY.resize( m_windowSize.y + 1 );
235 
236  // Precalc X values for camera -> ray generation
237  for( unsigned int x = 0; x < (unsigned int)m_windowSize.x + 1; ++x )
238  {
239  // Converts 0.0 .. 1.0
240  const float xNormalizedDeviceCoordinates = ( ( (float)x + 0.5f ) /
241  (m_windowSize.x - 0.0f) );
242 
243  // Converts -1.0 .. 1.0
244  m_scr_nX[x] = 2.0f * xNormalizedDeviceCoordinates - 1.0f;
245  }
246 
247  // Precalc Y values for camera -> ray generation
248  for( unsigned int y = 0; y < (unsigned int)m_windowSize.y + 1 ; ++y )
249  {
250  // Converts 0.0 .. 1.0
251  const float yNormalizedDeviceCoordinates = ( ( (float)y + 0.5f ) /
252  (m_windowSize.y - 0.0f) );
253 
254  // Converts -1.0 .. 1.0
255  m_scr_nY[y] = 2.0f * yNormalizedDeviceCoordinates - 1.0f;
256  }
257 
258  updateFrustum();
259  }
260 }
261 
262 
264 {
265  // Update matrix and vectors
266  m_viewMatrixInverse = glm::inverse( m_viewMatrix );
267 
268  m_right = glm::normalize( SFVEC3F( m_viewMatrixInverse *
269  glm::vec4( SFVEC3F( 1.0, 0.0, 0.0 ), 0.0 ) ) );
270 
271  m_up = glm::normalize( SFVEC3F( m_viewMatrixInverse *
272  glm::vec4( SFVEC3F( 0.0, 1.0, 0.0 ), 0.0 ) ) );
273 
274  m_dir = glm::normalize( SFVEC3F( m_viewMatrixInverse *
275  glm::vec4( SFVEC3F( 0.0, 0.0, 1.0 ), 0.0 ) ) );
276 
277  m_pos = SFVEC3F( m_viewMatrixInverse * glm::vec4( SFVEC3F( 0.0, 0.0, 0.0 ), 1.0 ) );
278 
279 
280  /*
281  * Frustum is a implementation based on a tutorial by
282  * http://www.lighthouse3d.com/tutorials/view-frustum-culling/
283  */
284 
285  // compute the centers of the near and far planes
288 
289  // compute the 4 corners of the frustum on the near plane
294 
295  // compute the 4 corners of the frustum on the far plane
300 
301  if ( (m_windowSize.x > 0) &&
302  (m_windowSize.y > 0) )
303  {
304  // Reserve size for precalc values
305  m_right_nX.resize( m_windowSize.x + 1 );
306  m_up_nY.resize( m_windowSize.y + 1 );
307 
308  // Precalc X values for camera -> ray generation
309  const SFVEC3F right_nw = m_right * m_frustum.nw;
310 
311  for( unsigned int x = 0; x < ((unsigned int)m_windowSize.x + 1); ++x )
312  m_right_nX[x] = right_nw * m_scr_nX[x];
313 
314  // Precalc Y values for camera -> ray generation
315  const SFVEC3F up_nh = m_up * m_frustum.nh;
316 
317  for( unsigned int y = 0; y < ((unsigned int)m_windowSize.y + 1); ++y )
318  m_up_nY[y] = up_nh * m_scr_nY[y];
319  }
320 }
321 
322 
323 void CCAMERA::MakeRay( const SFVEC2I &aWindowPos,
324  SFVEC3F &aOutOrigin,
325  SFVEC3F &aOutDirection ) const
326 {
327  wxASSERT( aWindowPos.x < m_windowSize.x );
328  wxASSERT( aWindowPos.y < m_windowSize.y );
329 
330  const SFVEC3F up_plus_right = m_up_nY[aWindowPos.y] +
331  m_right_nX[aWindowPos.x];
332 
333  switch( m_projectionType )
334  {
335  default:
337  aOutOrigin = up_plus_right + m_frustum.nc;
338  aOutDirection = glm::normalize( aOutOrigin - m_pos );
339  break;
340 
342  aOutOrigin = up_plus_right * 0.5f + m_frustum.nc;
343  aOutDirection = -m_dir + SFVEC3F( FLT_EPSILON );
344  break;
345  }
346 }
347 
348 
349 void CCAMERA::MakeRay( const SFVEC2F &aWindowPos, SFVEC3F &aOutOrigin, SFVEC3F &aOutDirection ) const
350 {
351  wxASSERT( aWindowPos.x < (float)m_windowSize.x );
352  wxASSERT( aWindowPos.y < (float)m_windowSize.y );
353 
354  const SFVEC2F floorWinPos_f = glm::floor( aWindowPos );
355  const SFVEC2I floorWinPos_i = (SFVEC2I)floorWinPos_f;
356  const SFVEC2F relativeWinPos = aWindowPos - floorWinPos_f;
357 
358  // Note: size of vectors m_up and m_right are m_windowSize + 1
359  const SFVEC3F up_plus_right = m_up_nY[floorWinPos_i.y] * (1.0f - relativeWinPos.y) +
360  m_up_nY[floorWinPos_i.y + 1] * relativeWinPos.y +
361  m_right_nX[floorWinPos_i.x] * (1.0f - relativeWinPos.x) +
362  m_right_nX[floorWinPos_i.x + 1] * relativeWinPos.x;
363 
364  switch( m_projectionType )
365  {
366  default:
368  aOutOrigin = up_plus_right + m_frustum.nc;
369  aOutDirection = glm::normalize( aOutOrigin - m_pos );
370  break;
371 
373  aOutOrigin = up_plus_right * 0.5f + m_frustum.nc;
374  aOutDirection = -m_dir + SFVEC3F( FLT_EPSILON );
375  break;
376  }
377 }
378 
379 
381  SFVEC3F &aOutDirection ) const
382 {
385  aOutOrigin, aOutDirection );
386 }
387 
388 
389 const glm::mat4 &CCAMERA::GetProjectionMatrix() const
390 {
391  return m_projectionMatrix;
392 }
393 
394 
395 const glm::mat4 &CCAMERA::GetProjectionMatrixInv() const
396 {
397  return m_projectionMatrixInv;
398 }
399 
400 
402 {
403  m_parametersChanged = true;
404  m_camera_pos.x = 0.0f;
405  m_camera_pos.y = 0.0f;
406 
408  updateFrustum();
409 }
410 
411 
413 {
414  m_camera_pos_t1.x = 0.0f;
415  m_camera_pos_t1.y = 0.0f;
416 }
417 
418 
419 const glm::mat4 &CCAMERA::GetViewMatrix() const
420 {
421  return m_viewMatrix;
422 }
423 
424 
425 const glm::mat4 &CCAMERA::GetViewMatrix_Inv() const
426 {
427  return m_viewMatrixInverse;
428 }
429 
430 
431 void CCAMERA::SetCurMousePosition( const wxPoint &aNewMousePosition )
432 {
433  m_lastPosition = aNewMousePosition;
434 }
435 
436 
438 {
441  else
443 
445 }
446 
447 
448 bool CCAMERA::SetCurWindowSize( const wxSize &aSize )
449 {
450  const SFVEC2I newSize = SFVEC2I( aSize.x, aSize.y );
451 
452  if( m_windowSize != newSize )
453  {
454  m_windowSize = newSize;
456 
457  return true;
458  }
459 
460  return false;
461 }
462 
463 
465 {
466  m_zoom = 1.0f;
467 
469 
472 }
473 
474 bool CCAMERA::Zoom( float aFactor )
475 {
476  if ( ( m_zoom == MIN_ZOOM && aFactor > 1 ) || ( m_zoom == MAX_ZOOM && aFactor < 1 ) || aFactor == 1 )
477  return false;
478 
479  m_zoom /= aFactor;
480  if( m_zoom <= MIN_ZOOM )
481  m_zoom = MIN_ZOOM;
482  if( m_zoom >= MAX_ZOOM )
483  m_zoom = MAX_ZOOM;
484 
486 
489 
490  return true;
491 }
492 
493 bool CCAMERA::Zoom_T1( float aFactor )
494 {
495  if( ( m_zoom == MIN_ZOOM && aFactor > 1 ) || ( m_zoom == MAX_ZOOM && aFactor < 1 ) || aFactor == 1 )
496  return false;
497 
498  m_zoom_t1 = m_zoom / aFactor;
499  if (m_zoom_t1 < MIN_ZOOM )
501  if (m_zoom_t1 > MAX_ZOOM )
503 
505 
506  return true;
507 }
508 
509 
510 float CCAMERA::ZoomGet() const
511 {
512  return m_zoom;
513 }
514 
515 
516 void CCAMERA::RotateX( float aAngleInRadians )
517 {
518  m_rotate_aux.x += aAngleInRadians;
520 }
521 
522 
523 void CCAMERA::RotateY( float aAngleInRadians )
524 {
525  m_rotate_aux.y += aAngleInRadians;
527 }
528 
529 
530 void CCAMERA::RotateZ( float aAngleInRadians )
531 {
532  m_rotate_aux.z += aAngleInRadians;
534 }
535 
536 
537 void CCAMERA::RotateX_T1( float aAngleInRadians )
538 {
539  m_rotate_aux_t1.x += aAngleInRadians;
540 }
541 
542 
543 void CCAMERA::RotateY_T1( float aAngleInRadians )
544 {
545  m_rotate_aux_t1.y += aAngleInRadians;
546 }
547 
548 
549 void CCAMERA::RotateZ_T1( float aAngleInRadians )
550 {
551  m_rotate_aux_t1.z += aAngleInRadians;
552 }
553 
554 
556 {
560  m_zoom_t0 = m_zoom;
561 
565  m_zoom_t1 = m_zoom;
566 }
567 
568 
569 void CCAMERA::Interpolate( float t )
570 {
571  wxASSERT( t >= 0.0f );
572 
573  const float t0 = 1.0f - t;
574 
578  m_zoom = m_zoom_t0 * t0 + m_zoom_t1 * t;
579 
580  m_parametersChanged = true;
581 
584 }
585 
586 
588 {
589  const bool parametersChanged = m_parametersChanged;
590 
591  m_parametersChanged = false;
592 
593  return parametersChanged;
594 }
#define MAX_ZOOM
Definition: ccamera.cpp:54
SFVEC3F fc
Definition: ccamera.h:51
void ResetXYpos()
Definition: ccamera.cpp:401
bool m_parametersChanged
Set to true if any of the parameters in the camera was changed.
Definition: ccamera.h:324
SFVEC3F m_dir
Definition: ccamera.h:285
virtual void SetT0_and_T1_current_T()
SetT0_and_T1_current_T - This will set T0 and T1 with the current values.
Definition: ccamera.cpp:555
SFVEC3F ftl
Far Top Left.
Definition: ccamera.h:56
void ResetXYpos_T1()
Definition: ccamera.cpp:412
SFVEC3F ntl
Near Top Left.
Definition: ccamera.h:52
virtual void Reset()
Reset the camera to initial state.
Definition: ccamera.cpp:71
float farD
Definition: ccamera.h:60
static const wxChar * m_logTrace
Trace mask used to enable or disable the trace output of this class.
Definition: ccamera.h:332
SFVEC3F m_board_lookat_pos_init
Default boardlookat position (the board center)
Definition: ccamera.h:298
SFVEC3F m_rotate_aux
Stores the rotation angle auxiliar.
Definition: ccamera.h:300
void ZoomReset()
Definition: ccamera.cpp:464
void RotateY(float aAngleInRadians)
Definition: ccamera.cpp:523
CCAMERA(float aRangeScale)
CCAMERA initialize a camera.
Definition: ccamera.cpp:56
void updateFrustum()
Definition: ccamera.cpp:263
std::vector< SFVEC3F > m_up_nY
Definition: ccamera.h:318
float nearD
Definition: ccamera.h:60
glm::mat4 m_viewMatrixInverse
Definition: ccamera.h:276
float nw
Definition: ccamera.h:61
std::vector< float > m_scr_nY
Definition: ccamera.h:311
std::vector< float > m_scr_nX
Precalc values array used to calc ray for each pixel (constant for the same window size)
Definition: ccamera.h:310
SFVEC3F fbr
Far Bottom Right.
Definition: ccamera.h:59
Define an abstract camera.
glm::ivec2 SFVEC2I
Definition: xv3d_types.h:42
float tang
Definition: ccamera.h:60
void updateViewMatrix()
Definition: ccamera.cpp:126
wxPoint m_lastPosition
The last mouse position in the screen.
Definition: ccamera.h:271
void SetCurMousePosition(const wxPoint &aPosition)
It updates the current mouse position without make any new recalculations on camera.
Definition: ccamera.cpp:431
bool Zoom(float aFactor)
Definition: ccamera.cpp:474
const glm::mat4 GetRotationMatrix() const
Function GetRotationMatrix Get the rotation matrix to be applied in a transformation camera.
Definition: ccamera.cpp:158
float fw
Definition: ccamera.h:61
void RotateZ(float aAngleInRadians)
Definition: ccamera.cpp:530
void RotateX(float aAngleInRadians)
Definition: ccamera.cpp:516
SFVEC2F m_focalLen
Definition: ccamera.h:288
SFVEC3F nbr
Near Bottom Right.
Definition: ccamera.h:55
SFVEC3F m_camera_pos_t1
Definition: ccamera.h:293
SFVEC3F fbl
Far Bottom Left.
Definition: ccamera.h:58
float m_zoom_t0
Definition: ccamera.h:260
float ZoomGet() const
Definition: ccamera.cpp:510
glm::vec2 SFVEC2F
Definition: xv3d_types.h:45
SFVEC3F m_right
Definition: ccamera.h:283
SFVEC3F m_pos
Definition: ccamera.h:286
void ToggleProjection()
Definition: ccamera.cpp:437
float angle
Definition: ccamera.h:60
SFVEC3F m_up
Definition: ccamera.h:284
SFVEC3F m_lookat_pos_t1
Definition: ccamera.h:297
virtual void Interpolate(float t)
Interpolate - It will update the matrix to interpolate between T0 and T1 values.
Definition: ccamera.cpp:569
SFVEC3F nbl
Near Bottom Left.
Definition: ccamera.h:54
float m_range_scale
m_range_scale - the nominal range expected to be used in the camera.
Definition: ccamera.h:254
SFVEC3F m_lookat_pos_t0
Definition: ccamera.h:296
bool SetCurWindowSize(const wxSize &aSize)
SetCurWindowSize - update the windows size of the camera.
Definition: ccamera.cpp:448
glm::mat4 m_rotationMatrix
Definition: ccamera.h:273
SFVEC3F ntr
Near Top Right.
Definition: ccamera.h:53
FRUSTUM m_frustum
Definition: ccamera.h:281
glm::mat4 m_projectionMatrix
Definition: ccamera.h:277
bool Zoom_T1(float aFactor)
Definition: ccamera.cpp:493
void RotateX_T1(float aAngleInRadians)
Definition: ccamera.cpp:537
virtual void Reset_T1()
Definition: ccamera.cpp:103
float m_zoom
3D zoom value (Min 0.0 ...
Definition: ccamera.h:259
SFVEC3F m_rotate_aux_t1
Definition: ccamera.h:302
void updateRotationMatrix()
Definition: ccamera.cpp:134
SFVEC3F m_camera_pos_init
Definition: ccamera.h:290
SFVEC3F m_camera_pos
Definition: ccamera.h:291
SFVEC3F m_camera_pos_t0
Definition: ccamera.h:292
std::vector< SFVEC3F > m_right_nX
Precalc values array used to calc ray for each pixel, for X and Y axis of each new camera position.
Definition: ccamera.h:317
SFVEC3F nc
Definition: ccamera.h:50
void RotateY_T1(float aAngleInRadians)
Definition: ccamera.cpp:543
void MakeRayAtCurrrentMousePosition(SFVEC3F &aOutOrigin, SFVEC3F &aOutDirection) const
MakeRayAtCurrrentMousePosition - Make a ray based on the latest mouse position.
Definition: ccamera.cpp:380
const glm::mat4 & GetViewMatrix() const
Definition: ccamera.cpp:419
void rebuildProjection()
Definition: ccamera.cpp:164
#define MIN_ZOOM
Definition: ccamera.cpp:53
glm::vec3 SFVEC3F
Definition: xv3d_types.h:47
void normalise2PI(float &aAngle)
Definition: ccamera.cpp:35
SFVEC2I m_windowSize
The window size that this camera is working.
Definition: ccamera.h:266
SFVEC3F ftr
Far Top Right.
Definition: ccamera.h:57
const glm::mat4 & GetProjectionMatrix() const
Definition: ccamera.cpp:389
float m_zoom_t1
Definition: ccamera.h:261
CAMERA_INTERPOLATION m_interpolation_mode
Definition: ccamera.h:304
void MakeRay(const SFVEC2I &aWindowPos, SFVEC3F &aOutOrigin, SFVEC3F &aOutDirection) const
MakeRay - Make a ray based on a windows screen position.
Definition: ccamera.cpp:323
const glm::mat4 & GetProjectionMatrixInv() const
Definition: ccamera.cpp:395
SFVEC3F m_rotate_aux_t0
Definition: ccamera.h:301
glm::mat4 m_rotationMatrixAux
Definition: ccamera.h:274
const glm::mat4 & GetViewMatrix_Inv() const
Definition: ccamera.cpp:425
void RotateZ_T1(float aAngleInRadians)
Definition: ccamera.cpp:549
float fh
Definition: ccamera.h:61
float nh
Definition: ccamera.h:61
float ratio
Definition: ccamera.h:60
glm::mat4 m_viewMatrix
Definition: ccamera.h:275
glm::mat4 m_projectionMatrixInv
Definition: ccamera.h:278
bool ParametersChanged()
Function ParametersChanged.
Definition: ccamera.cpp:587
SFVEC3F m_lookat_pos
Definition: ccamera.h:295
PROJECTION_TYPE m_projectionType
Definition: ccamera.h:279