camera.cpp
1 /****************************************************************************
2 
3  Copyright (C) 2002-2013 Gilles Debunne. All rights reserved.
4 
5  This file is part of the QGLViewer library version 2.5.2.
6 
7  http://www.libqglviewer.com - contact@libqglviewer.com
8 
9  This file may be used under the terms of the GNU General Public License
10  versions 2.0 or 3.0 as published by the Free Software Foundation and
11  appearing in the LICENSE file included in the packaging of this file.
12  In addition, as a special exception, Gilles Debunne gives you certain
13  additional rights, described in the file GPL_EXCEPTION in this package.
14 
15  libQGLViewer uses dual licensing. Commercial/proprietary software must
16  purchase a libQGLViewer Commercial License.
17 
18  This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
19  WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 
21 *****************************************************************************/
22 
23 #include "domUtils.h"
24 #include "camera.h"
25 #include "qglviewer.h"
26 #include "manipulatedCameraFrame.h"
27 
28 using namespace std;
29 using namespace qglviewer;
30 
38 Camera::Camera()
39  : frame_(NULL), fieldOfView_(M_PI/4.0f), modelViewMatrixIsUpToDate_(false), projectionMatrixIsUpToDate_(false)
40 {
41  // #CONNECTION# Camera copy constructor
42  interpolationKfi_ = new KeyFrameInterpolator;
43  // Requires the interpolationKfi_
45 
46  // #CONNECTION# All these default values identical in initFromDOMElement.
47 
48  // Requires fieldOfView() to define focusDistance()
49  setSceneRadius(1.0);
50 
51  // Initial value (only scaled after this)
52  orthoCoef_ = tan(fieldOfView()/2.0);
53 
54  // Also defines the pivotPoint(), which changes orthoCoef_. Requires a frame().
55  setSceneCenter(Vec(0.0, 0.0, 0.0));
56 
57  // Requires fieldOfView() when called with ORTHOGRAPHIC. Attention to projectionMatrix_ below.
58  setType(PERSPECTIVE);
59 
60  // #CONNECTION# initFromDOMElement default values
61  setZNearCoefficient(0.005f);
62  setZClippingCoefficient(sqrt(3.0));
63 
64  // Dummy values
65  setScreenWidthAndHeight(600, 400);
66 
67  // Stereo parameters
68  setIODistance(0.062f);
70  // focusDistance is set from setFieldOfView()
71 
72  // #CONNECTION# Camera copy constructor
73  for (unsigned short j=0; j<16; ++j)
74  {
75  modelViewMatrix_[j] = ((j%5 == 0) ? 1.0 : 0.0);
76  // #CONNECTION# computeProjectionMatrix() is lazy and assumes 0.0 almost everywhere.
77  projectionMatrix_[j] = 0.0;
78  }
80 }
81 
87 {
88  delete frame_;
89  delete interpolationKfi_;
90 }
91 
92 
94 Camera::Camera(const Camera& camera)
95  : QObject(), frame_(NULL)
96 {
97  // #CONNECTION# Camera constructor
98  interpolationKfi_ = new KeyFrameInterpolator;
99  // Requires the interpolationKfi_
100  setFrame(new ManipulatedCameraFrame(*camera.frame()));
101 
102  for (unsigned short j=0; j<16; ++j)
103  {
104  modelViewMatrix_[j] = ((j%5 == 0) ? 1.0 : 0.0);
105  // #CONNECTION# computeProjectionMatrix() is lazy and assumes 0.0 almost everywhere.
106  projectionMatrix_[j] = 0.0;
107  }
108 
109  (*this)=camera;
110 }
111 
125 {
127  setFieldOfView(camera.fieldOfView());
128  setSceneRadius(camera.sceneRadius());
129  setSceneCenter(camera.sceneCenter());
132  setType(camera.type());
133 
134  // Stereo parameters
135  setIODistance(camera.IODistance());
138 
139  orthoCoef_ = camera.orthoCoef_;
140  projectionMatrixIsUpToDate_ = false;
141 
142  // frame_ and interpolationKfi_ pointers are not shared.
143  frame_->setReferenceFrame(NULL);
144  frame_->setPosition(camera.position());
145  frame_->setOrientation(camera.orientation());
146 
147  interpolationKfi_->resetInterpolation();
148 
149  kfi_ = camera.kfi_;
150 
153 
154  return *this;
155 }
156 
166 void Camera::setScreenWidthAndHeight(int width, int height)
167 {
168  // Prevent negative and zero dimensions that would cause divisions by zero.
169  screenWidth_ = width > 0 ? width : 1;
170  screenHeight_ = height > 0 ? height : 1;
171  projectionMatrixIsUpToDate_ = false;
172 }
173 
211 float Camera::zNear() const
212 {
213  const float zNearScene = zClippingCoefficient() * sceneRadius();
214  float z = distanceToSceneCenter() - zNearScene;
215 
216  // Prevents negative or null zNear values.
217  const float zMin = zNearCoefficient() * zNearScene;
218  if (z < zMin)
219  switch (type())
220  {
221  case Camera::PERSPECTIVE : z = zMin; break;
222  case Camera::ORTHOGRAPHIC : z = 0.0; break;
223  }
224  return z;
225 }
226 
236 float Camera::zFar() const
237 {
239 }
240 
241 
245 void Camera::setFieldOfView(float fov) {
246  fieldOfView_ = fov;
247  setFocusDistance(sceneRadius() / tan(fov/2.0));
248  projectionMatrixIsUpToDate_ = false;
249 }
250 
262 {
263  // make ORTHOGRAPHIC frustum fit PERSPECTIVE (at least in plane normal to viewDirection(), passing
264  // through RAP). Done only when CHANGING type since orthoCoef_ may have been changed with a
265  // setPivotPoint() in the meantime.
266  if ( (type == Camera::ORTHOGRAPHIC) && (type_ == Camera::PERSPECTIVE) )
267  orthoCoef_ = tan(fieldOfView()/2.0);
268  type_ = type;
269  projectionMatrixIsUpToDate_ = false;
270 }
271 
286 {
287  if (!mcf)
288  return;
289 
290  if (frame_) {
291  disconnect(frame_, SIGNAL(modified()), this, SLOT(onFrameModified()));
292  }
293 
294  frame_ = mcf;
295  interpolationKfi_->setFrame(frame());
296 
297  connect(frame_, SIGNAL(modified()), this, SLOT(onFrameModified()));
298  onFrameModified();
299 }
300 
304 {
305  return fabs((frame()->coordinatesOf(sceneCenter())).z);
306 }
307 
308 
324 void Camera::getOrthoWidthHeight(GLdouble& halfWidth, GLdouble& halfHeight) const
325 {
326  const float dist = orthoCoef_ * fabs(cameraCoordinatesOf(pivotPoint()).z);
327  //#CONNECTION# fitScreenRegion
328  halfWidth = dist * ((aspectRatio() < 1.0) ? 1.0 : aspectRatio());
329  halfHeight = dist * ((aspectRatio() < 1.0) ? 1.0/aspectRatio() : 1.0);
330 }
331 
332 
351 {
352  if (projectionMatrixIsUpToDate_) return;
353 
354  const float ZNear = zNear();
355  const float ZFar = zFar();
356 
357  switch (type())
358  {
359  case Camera::PERSPECTIVE:
360  {
361  // #CONNECTION# all non null coefficients were set to 0.0 in constructor.
362  const float f = 1.0/tan(fieldOfView()/2.0);
363  projectionMatrix_[0] = f/aspectRatio();
364  projectionMatrix_[5] = f;
365  projectionMatrix_[10] = (ZNear + ZFar) / (ZNear - ZFar);
366  projectionMatrix_[11] = -1.0;
367  projectionMatrix_[14] = 2.0 * ZNear * ZFar / (ZNear - ZFar);
368  projectionMatrix_[15] = 0.0;
369  // same as gluPerspective( 180.0*fieldOfView()/M_PI, aspectRatio(), zNear(), zFar() );
370  break;
371  }
372  case Camera::ORTHOGRAPHIC:
373  {
374  GLdouble w, h;
375  getOrthoWidthHeight(w,h);
376  projectionMatrix_[0] = 1.0/w;
377  projectionMatrix_[5] = 1.0/h;
378  projectionMatrix_[10] = -2.0/(ZFar - ZNear);
379  projectionMatrix_[11] = 0.0;
380  projectionMatrix_[14] = -(ZFar + ZNear)/(ZFar - ZNear);
381  projectionMatrix_[15] = 1.0;
382  // same as glOrtho( -w, w, -h, h, zNear(), zFar() );
383  break;
384  }
385  }
386 
387  projectionMatrixIsUpToDate_ = true;
388 }
389 
401 {
402  if (modelViewMatrixIsUpToDate_) return;
403 
404  const Quaternion q = frame()->orientation();
405 
406  const double q00 = 2.0l * q[0] * q[0];
407  const double q11 = 2.0l * q[1] * q[1];
408  const double q22 = 2.0l * q[2] * q[2];
409 
410  const double q01 = 2.0l * q[0] * q[1];
411  const double q02 = 2.0l * q[0] * q[2];
412  const double q03 = 2.0l * q[0] * q[3];
413 
414  const double q12 = 2.0l * q[1] * q[2];
415  const double q13 = 2.0l * q[1] * q[3];
416 
417  const double q23 = 2.0l * q[2] * q[3];
418 
419  modelViewMatrix_[0] = 1.0l - q11 - q22;
420  modelViewMatrix_[1] = q01 - q23;
421  modelViewMatrix_[2] = q02 + q13;
422  modelViewMatrix_[3] = 0.0l;
423 
424  modelViewMatrix_[4] = q01 + q23;
425  modelViewMatrix_[5] = 1.0l - q22 - q00;
426  modelViewMatrix_[6] = q12 - q03;
427  modelViewMatrix_[7] = 0.0l;
428 
429  modelViewMatrix_[8] = q02 - q13;
430  modelViewMatrix_[9] = q12 + q03;
431  modelViewMatrix_[10] = 1.0l - q11 - q00;
432  modelViewMatrix_[11] = 0.0l;
433 
434  const Vec t = q.inverseRotate(frame()->position());
435 
436  modelViewMatrix_[12] = -t.x;
437  modelViewMatrix_[13] = -t.y;
438  modelViewMatrix_[14] = -t.z;
439  modelViewMatrix_[15] = 1.0l;
440 
441  modelViewMatrixIsUpToDate_ = true;
442 }
443 
444 
463 void Camera::loadProjectionMatrix(bool reset) const
464 {
465  // WARNING: makeCurrent must be called by every calling method
466  glMatrixMode(GL_PROJECTION);
467 
468  if (reset)
469  glLoadIdentity();
470 
472 
473  glMultMatrixd(projectionMatrix_);
474 }
475 
500 void Camera::loadModelViewMatrix(bool reset) const
501 {
502  // WARNING: makeCurrent must be called by every calling method
503  glMatrixMode(GL_MODELVIEW);
505  if (reset)
506  glLoadMatrixd(modelViewMatrix_);
507  else
508  glMultMatrixd(modelViewMatrix_);
509 }
510 
536 void Camera::loadProjectionMatrixStereo(bool leftBuffer) const
537 {
538  float left, right, bottom, top;
539  float screenHalfWidth, halfWidth, side, shift, delta;
540 
541  glMatrixMode(GL_PROJECTION);
542  glLoadIdentity();
543 
544  switch (type())
545  {
546  case Camera::PERSPECTIVE:
547  // compute half width of screen,
548  // corresponding to zero parallax plane to deduce decay of cameras
549  screenHalfWidth = focusDistance() * tan(horizontalFieldOfView() / 2.0);
550  shift = screenHalfWidth * IODistance() / physicalScreenWidth();
551  // should be * current y / y total
552  // to take into account that the window doesn't cover the entire screen
553 
554  // compute half width of "view" at znear and the delta corresponding to
555  // the shifted camera to deduce what to set for asymmetric frustums
556  halfWidth = zNear() * tan(horizontalFieldOfView() / 2.0);
557  delta = shift * zNear() / focusDistance();
558  side = leftBuffer ? -1.0 : 1.0;
559 
560  left = -halfWidth + side * delta;
561  right = halfWidth + side * delta;
562  top = halfWidth / aspectRatio();
563  bottom = -top;
564  glFrustum(left, right, bottom, top, zNear(), zFar() );
565  break;
566 
567  case Camera::ORTHOGRAPHIC:
568  qWarning("Camera::setProjectionMatrixStereo: Stereo not available with Ortho mode");
569  break;
570  }
571 }
572 
591 void Camera::loadModelViewMatrixStereo(bool leftBuffer) const
592 {
593  // WARNING: makeCurrent must be called by every calling method
594  glMatrixMode(GL_MODELVIEW);
595 
596  float halfWidth = focusDistance() * tan(horizontalFieldOfView() / 2.0);
597  float shift = halfWidth * IODistance() / physicalScreenWidth(); // * current window width / full screen width
598 
600  if (leftBuffer)
601  modelViewMatrix_[12] -= shift;
602  else
603  modelViewMatrix_[12] += shift;
604  glLoadMatrixd(modelViewMatrix_);
605 }
606 
621 void Camera::getProjectionMatrix(GLdouble m[16]) const
622 {
624  for (unsigned short i=0; i<16; ++i)
625  m[i] = projectionMatrix_[i];
626 }
627 
629 void Camera::getProjectionMatrix(GLfloat m[16]) const
630 {
631  static GLdouble mat[16];
632  getProjectionMatrix(mat);
633  for (unsigned short i=0; i<16; ++i)
634  m[i] = float(mat[i]);
635 }
636 
651 void Camera::getModelViewMatrix(GLdouble m[16]) const
652 {
653  // May not be needed, but easier like this.
654  // Prevents from retrieving matrix in stereo mode -> overwrites shifted value.
656  for (unsigned short i=0; i<16; ++i)
657  m[i] = modelViewMatrix_[i];
658 }
659 
660 
662 void Camera::getModelViewMatrix(GLfloat m[16]) const
663 {
664  static GLdouble mat[16];
665  getModelViewMatrix(mat);
666  for (unsigned short i=0; i<16; ++i)
667  m[i] = float(mat[i]);
668 }
669 
673 void Camera::getModelViewProjectionMatrix(GLdouble m[16]) const
674 {
675  GLdouble mv[16];
676  GLdouble proj[16];
677  getModelViewMatrix(mv);
678  getProjectionMatrix(proj);
679 
680  for (unsigned short i=0; i<4; ++i)
681  {
682  for (unsigned short j=0; j<4; ++j)
683  {
684  double sum = 0.0;
685  for (unsigned short k=0; k<4; ++k)
686  sum += proj[i+4*k]*mv[k+4*j];
687  m[i+4*j] = sum;
688  }
689  }
690 }
691 
693 void Camera::getModelViewProjectionMatrix(GLfloat m[16]) const
694 {
695  static GLdouble mat[16];
697  for (unsigned short i=0; i<16; ++i)
698  m[i] = float(mat[i]);
699 }
700 
705 void Camera::setSceneRadius(float radius)
706 {
707  if (radius <= 0.0)
708  {
709  qWarning("Scene radius must be positive - Ignoring value");
710  return;
711  }
712 
713  sceneRadius_ = radius;
714  projectionMatrixIsUpToDate_ = false;
715 
716  setFocusDistance(sceneRadius() / tan(fieldOfView()/2.0));
717 
718  frame()->setFlySpeed(0.01*sceneRadius());
719 }
720 
724 {
725  setSceneCenter((min+max)/2.0);
726  setSceneRadius(0.5*(max-min).norm());
727 }
728 
729 
733 void Camera::setSceneCenter(const Vec& center)
734 {
735  sceneCenter_ = center;
737  projectionMatrixIsUpToDate_ = false;
738 }
739 
745 bool Camera::setSceneCenterFromPixel(const QPoint& pixel)
746 {
747  bool found;
748  Vec point = pointUnderPixel(pixel, found);
749  if (found)
750  setSceneCenter(point);
751  return found;
752 }
753 
754 #ifndef DOXYGEN
755 void Camera::setRevolveAroundPoint(const Vec& point) {
756  qWarning("setRevolveAroundPoint() is deprecated, use setPivotPoint() instead");
757  setPivotPoint(point);
758 }
759 bool Camera::setRevolveAroundPointFromPixel(const QPoint& pixel) {
760  qWarning("setRevolveAroundPointFromPixel() is deprecated, use setPivotPointFromPixel() instead");
761  return setPivotPointFromPixel(pixel);
762 }
763 Vec Camera::revolveAroundPoint() const {
764  qWarning("revolveAroundPoint() is deprecated, use pivotPoint() instead");
765  return pivotPoint();
766 }
767 #endif
768 
770 void Camera::setPivotPoint(const Vec& point)
771 {
772  const float prevDist = fabs(cameraCoordinatesOf(pivotPoint()).z);
773 
774  // If frame's RAP is set directly, projectionMatrixIsUpToDate_ should also be
775  // set to false to ensure proper recomputation of the ORTHO projection matrix.
776  frame()->setPivotPoint(point);
777 
778  // orthoCoef_ is used to compensate for changes of the pivotPoint, so that the image does
779  // not change when the pivotPoint is changed in ORTHOGRAPHIC mode.
780  const float newDist = fabs(cameraCoordinatesOf(pivotPoint()).z);
781  // Prevents division by zero when rap is set to camera position
782  if ((prevDist > 1E-9) && (newDist > 1E-9))
783  orthoCoef_ *= prevDist / newDist;
784  projectionMatrixIsUpToDate_ = false;
785 }
786 
796 bool Camera::setPivotPointFromPixel(const QPoint& pixel)
797 {
798  bool found;
799  Vec point = pointUnderPixel(pixel, found);
800  if (found)
801  setPivotPoint(point);
802  return found;
803 }
804 
819 float Camera::pixelGLRatio(const Vec& position) const
820 {
821  switch (type())
822  {
823  case Camera::PERSPECTIVE :
824  return 2.0 * fabs((frame()->coordinatesOf(position)).z) * tan(fieldOfView()/2.0) / screenHeight();
825  case Camera::ORTHOGRAPHIC :
826  {
827  GLdouble w, h;
828  getOrthoWidthHeight(w,h);
829  return 2.0 * h / screenHeight();
830  }
831  }
832  // Bad compilers complain
833  return 1.0;
834 }
835 
862 {
863  if (distanceToSceneCenter() > sqrt(2.0)*sceneRadius())
865  else
866  setFieldOfView(M_PI / 2.0f);
867 }
868 
875 void Camera::interpolateToZoomOnPixel(const QPoint& pixel)
876 {
877  const float coef = 0.1f;
878 
879  bool found;
880  Vec target = pointUnderPixel(pixel, found);
881 
882  if (!found)
883  return;
884 
885  if (interpolationKfi_->interpolationIsStarted())
886  interpolationKfi_->stopInterpolation();
887 
888  interpolationKfi_->deletePath();
889  interpolationKfi_->addKeyFrame(*(frame()));
890 
891  interpolationKfi_->addKeyFrame(Frame(0.3f*frame()->position() + 0.7f*target, frame()->orientation()), 0.4f);
892 
893  // Small hack: attach a temporary frame to take advantage of lookAt without modifying frame
894  static ManipulatedCameraFrame* tempFrame = new ManipulatedCameraFrame();
895  ManipulatedCameraFrame* const originalFrame = frame();
896  tempFrame->setPosition(coef*frame()->position() + (1.0-coef)*target);
897  tempFrame->setOrientation(frame()->orientation());
898  setFrame(tempFrame);
899  lookAt(target);
900  setFrame(originalFrame);
901 
902  interpolationKfi_->addKeyFrame(*(tempFrame), 1.0);
903 
904  interpolationKfi_->startInterpolation();
905 }
906 
914 {
915  if (interpolationKfi_->interpolationIsStarted())
916  interpolationKfi_->stopInterpolation();
917 
918  interpolationKfi_->deletePath();
919  interpolationKfi_->addKeyFrame(*(frame()));
920 
921  // Small hack: attach a temporary frame to take advantage of lookAt without modifying frame
922  static ManipulatedCameraFrame* tempFrame = new ManipulatedCameraFrame();
923  ManipulatedCameraFrame* const originalFrame = frame();
924  tempFrame->setPosition(frame()->position());
925  tempFrame->setOrientation(frame()->orientation());
926  setFrame(tempFrame);
927  showEntireScene();
928  setFrame(originalFrame);
929 
930  interpolationKfi_->addKeyFrame(*(tempFrame));
931 
932  interpolationKfi_->startInterpolation();
933 }
934 
935 
942 void Camera::interpolateTo(const Frame& fr, float duration)
943 {
944  if (interpolationKfi_->interpolationIsStarted())
945  interpolationKfi_->stopInterpolation();
946 
947  interpolationKfi_->deletePath();
948  interpolationKfi_->addKeyFrame(*(frame()));
949  interpolationKfi_->addKeyFrame(fr, duration);
950 
951  interpolationKfi_->startInterpolation();
952 }
953 
954 
971 Vec Camera::pointUnderPixel(const QPoint& pixel, bool& found) const
972 {
973  float depth;
974  // Qt uses upper corner for its origin while GL uses the lower corner.
975  glReadPixels(pixel.x(), screenHeight()-1-pixel.y(), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
976  found = depth < 1.0;
977  Vec point(pixel.x(), pixel.y(), depth);
978  point = unprojectedCoordinatesOf(point);
979  return point;
980 }
981 
988 {
990 }
991 
998 {
1000 }
1001 
1008 void Camera::lookAt(const Vec& target)
1009 {
1010  setViewDirection(target - position());
1011 }
1012 
1020 void Camera::fitSphere(const Vec& center, float radius)
1021 {
1022  float distance = 0.0f;
1023  switch (type())
1024  {
1025  case Camera::PERSPECTIVE :
1026  {
1027  const float yview = radius / sin(fieldOfView() / 2.0);
1028  const float xview = radius / sin(horizontalFieldOfView() / 2.0);
1029  distance = qMax(xview, yview);
1030  break;
1031  }
1032  case Camera::ORTHOGRAPHIC :
1033  {
1034  distance = ((center-pivotPoint()) * viewDirection()) + (radius / orthoCoef_);
1035  break;
1036  }
1037  }
1038  Vec newPos(center - distance * viewDirection());
1039  frame()->setPositionWithConstraint(newPos);
1040 }
1041 
1044 void Camera::fitBoundingBox(const Vec& min, const Vec& max)
1045 {
1046  float diameter = qMax(fabs(max[1]-min[1]), fabs(max[0]-min[0]));
1047  diameter = qMax(fabsf(max[2]-min[2]), diameter);
1048  fitSphere(0.5*(min+max), 0.5*diameter);
1049 }
1050 
1058 void Camera::fitScreenRegion(const QRect& rectangle)
1059 {
1060  const Vec vd = viewDirection();
1061  const float distToPlane = distanceToSceneCenter();
1062  const QPoint center = rectangle.center();
1063 
1064  Vec orig, dir;
1065  convertClickToLine( center, orig, dir );
1066  Vec newCenter = orig + distToPlane / (dir*vd) * dir;
1067 
1068  convertClickToLine( QPoint(rectangle.x(), center.y()), orig, dir );
1069  const Vec pointX = orig + distToPlane / (dir*vd) * dir;
1070 
1071  convertClickToLine( QPoint(center.x(), rectangle.y()), orig, dir );
1072  const Vec pointY = orig + distToPlane / (dir*vd) * dir;
1073 
1074  float distance = 0.0f;
1075  switch (type())
1076  {
1077  case Camera::PERSPECTIVE :
1078  {
1079  const float distX = (pointX-newCenter).norm() / sin(horizontalFieldOfView()/2.0);
1080  const float distY = (pointY-newCenter).norm() / sin(fieldOfView()/2.0);
1081  distance = qMax(distX, distY);
1082  break;
1083  }
1084  case Camera::ORTHOGRAPHIC :
1085  {
1086  const float dist = ((newCenter-pivotPoint()) * vd);
1087  //#CONNECTION# getOrthoWidthHeight
1088  const float distX = (pointX-newCenter).norm() / orthoCoef_ / ((aspectRatio() < 1.0) ? 1.0 : aspectRatio());
1089  const float distY = (pointY-newCenter).norm() / orthoCoef_ / ((aspectRatio() < 1.0) ? 1.0/aspectRatio() : 1.0);
1090  distance = dist + qMax(distX, distY);
1091  break;
1092  }
1093  }
1094 
1095  Vec newPos(newCenter - distance * vd);
1096  frame()->setPositionWithConstraint(newPos);
1097 }
1098 
1116 void Camera::setUpVector(const Vec& up, bool noMove)
1117 {
1118  Quaternion q(Vec(0.0, 1.0, 0.0), frame()->transformOf(up));
1119 
1120  if (!noMove)
1121  frame()->setPosition(pivotPoint() - (frame()->orientation()*q).rotate(frame()->coordinatesOf(pivotPoint())));
1122 
1123  frame()->rotate(q);
1124 
1125  // Useful in fly mode to keep the horizontal direction.
1126  frame()->updateSceneUpVector();
1127 }
1128 
1140 void Camera::setOrientation(float theta, float phi)
1141 {
1142  Vec axis(0.0, 1.0, 0.0);
1143  const Quaternion rot1(axis, theta);
1144  axis = Vec(-cos(theta), 0., sin(theta));
1145  const Quaternion rot2(axis, phi);
1146  setOrientation(rot1 * rot2);
1147 }
1148 
1151 {
1152  frame()->setOrientation(q);
1153  frame()->updateSceneUpVector();
1154 }
1155 
1161 void Camera::setViewDirection(const Vec& direction)
1162 {
1163  if (direction.squaredNorm() < 1E-10)
1164  return;
1165 
1166  Vec xAxis = direction ^ upVector();
1167  if (xAxis.squaredNorm() < 1E-10)
1168  {
1169  // target is aligned with upVector, this means a rotation around X axis
1170  // X axis is then unchanged, let's keep it !
1171  xAxis = frame()->inverseTransformOf(Vec(1.0, 0.0, 0.0));
1172  }
1173 
1174  Quaternion q;
1175  q.setFromRotatedBasis(xAxis, xAxis^direction, -direction);
1177 }
1178 
1179 // Compute a 3 by 3 determinant.
1180 static float det(float m00,float m01,float m02,
1181  float m10,float m11,float m12,
1182  float m20,float m21,float m22)
1183 {
1184  return m00*m11*m22 + m01*m12*m20 + m02*m10*m21 - m20*m11*m02 - m10*m01*m22 - m00*m21*m12;
1185 }
1186 
1187 // Computes the index of element [i][j] in a \c float matrix[3][4].
1188 static inline unsigned int ind(unsigned int i, unsigned int j)
1189 {
1190  return (i*4+j);
1191 }
1192 
1200 Vec Camera::position() const { return frame()->position(); }
1201 
1210 {
1211  return frame()->inverseTransformOf(Vec(0.0, 1.0, 0.0));
1212 }
1220 Vec Camera::viewDirection() const { return frame()->inverseTransformOf(Vec(0.0, 0.0, -1.0)); }
1221 
1229 {
1230  return frame()->inverseTransformOf(Vec(1.0, 0.0, 0.0));
1231 }
1232 
1238 
1240 void Camera::setPosition(const Vec& pos) { frame()->setPosition(pos); }
1241 
1248 Vec Camera::cameraCoordinatesOf(const Vec& src) const { return frame()->coordinatesOf(src); }
1249 
1254 Vec Camera::worldCoordinatesOf(const Vec& src) const { return frame()->inverseCoordinatesOf(src); }
1255 
1263 float Camera::flySpeed() const { return frame()->flySpeed(); }
1264 
1268 void Camera::setFlySpeed(float speed) { frame()->setFlySpeed(speed); }
1269 
1275 Vec Camera::pivotPoint() const { return frame()->pivotPoint(); }
1276 
1294 void Camera::setFromModelViewMatrix(const GLdouble* const modelViewMatrix)
1295 {
1296  // Get upper left (rotation) matrix
1297  double upperLeft[3][3];
1298  for (int i=0; i<3; ++i)
1299  for (int j=0; j<3; ++j)
1300  upperLeft[i][j] = modelViewMatrix[i*4+j];
1301 
1302  // Transform upperLeft into the associated Quaternion
1303  Quaternion q;
1304  q.setFromRotationMatrix(upperLeft);
1305 
1306  setOrientation(q);
1307  setPosition(-q.rotate(Vec(modelViewMatrix[12], modelViewMatrix[13], modelViewMatrix[14])));
1308 }
1309 
1332 void Camera::setFromProjectionMatrix(const float matrix[12])
1333 {
1334  // The 3 lines of the matrix are the normals to the planes x=0, y=0, z=0
1335  // in the camera CS. As we normalize them, we do not need the 4th coordinate.
1336  Vec line_0(matrix[ind(0,0)],matrix[ind(0,1)],matrix[ind(0,2)]);
1337  Vec line_1(matrix[ind(1,0)],matrix[ind(1,1)],matrix[ind(1,2)]);
1338  Vec line_2(matrix[ind(2,0)],matrix[ind(2,1)],matrix[ind(2,2)]);
1339 
1340  line_0.normalize();
1341  line_1.normalize();
1342  line_2.normalize();
1343 
1344  // The camera position is at (0,0,0) in the camera CS so it is the
1345  // intersection of the 3 planes. It can be seen as the kernel
1346  // of the 3x4 projection matrix. We calculate it through 4 dimensional
1347  // vectorial product. We go directly into 3D that is to say we directly
1348  // divide the first 3 coordinates by the 4th one.
1349 
1350  // We derive the 4 dimensional vectorial product formula from the
1351  // computation of a 4x4 determinant that is developped according to
1352  // its 4th column. This implies some 3x3 determinants.
1353  const Vec cam_pos = Vec(det(matrix[ind(0,1)],matrix[ind(0,2)],matrix[ind(0,3)],
1354  matrix[ind(1,1)],matrix[ind(1,2)],matrix[ind(1,3)],
1355  matrix[ind(2,1)],matrix[ind(2,2)],matrix[ind(2,3)]),
1356 
1357  -det(matrix[ind(0,0)],matrix[ind(0,2)],matrix[ind(0,3)],
1358  matrix[ind(1,0)],matrix[ind(1,2)],matrix[ind(1,3)],
1359  matrix[ind(2,0)],matrix[ind(2,2)],matrix[ind(2,3)]),
1360 
1361  det(matrix[ind(0,0)],matrix[ind(0,1)],matrix[ind(0,3)],
1362  matrix[ind(1,0)],matrix[ind(1,1)],matrix[ind(1,3)],
1363  matrix[ind(2,0)],matrix[ind(2,1)],matrix[ind(2,3)])) /
1364 
1365  (-det(matrix[ind(0,0)],matrix[ind(0,1)],matrix[ind(0,2)],
1366  matrix[ind(1,0)],matrix[ind(1,1)],matrix[ind(1,2)],
1367  matrix[ind(2,0)],matrix[ind(2,1)],matrix[ind(2,2)]));
1368 
1369  // We compute the rotation matrix column by column.
1370 
1371  // GL Z axis is front facing.
1372  Vec column_2 = -line_2;
1373 
1374  // X-axis is almost like line_0 but should be orthogonal to the Z axis.
1375  Vec column_0 = ((column_2^line_0)^column_2);
1376  column_0.normalize();
1377 
1378  // Y-axis is almost like line_1 but should be orthogonal to the Z axis.
1379  // Moreover line_1 is downward oriented as the screen CS.
1380  Vec column_1 = -((column_2^line_1)^column_2);
1381  column_1.normalize();
1382 
1383  double rot[3][3];
1384  rot[0][0] = column_0[0];
1385  rot[1][0] = column_0[1];
1386  rot[2][0] = column_0[2];
1387 
1388  rot[0][1] = column_1[0];
1389  rot[1][1] = column_1[1];
1390  rot[2][1] = column_1[2];
1391 
1392  rot[0][2] = column_2[0];
1393  rot[1][2] = column_2[1];
1394  rot[2][2] = column_2[2];
1395 
1396  // We compute the field of view
1397 
1398  // line_1^column_0 -> vector of intersection line between
1399  // y_screen=0 and x_camera=0 plane.
1400  // column_2*(...) -> cos of the angle between Z vector et y_screen=0 plane
1401  // * 2 -> field of view = 2 * half angle
1402 
1403  // We need some intermediate values.
1404  Vec dummy = line_1^column_0;
1405  dummy.normalize();
1406  float fov = acos(column_2*dummy) * 2.0;
1407 
1408  // We set the camera.
1409  Quaternion q;
1410  q.setFromRotationMatrix(rot);
1411  setOrientation(q);
1412  setPosition(cam_pos);
1413  setFieldOfView(fov);
1414 }
1415 
1416 
1417 /*
1418  // persp : projectionMatrix_[0] = f/aspectRatio();
1419 void Camera::setFromProjectionMatrix(const GLdouble* projectionMatrix)
1420 {
1421  QString message;
1422  if ((fabs(projectionMatrix[1]) > 1E-3) ||
1423  (fabs(projectionMatrix[2]) > 1E-3) ||
1424  (fabs(projectionMatrix[3]) > 1E-3) ||
1425  (fabs(projectionMatrix[4]) > 1E-3) ||
1426  (fabs(projectionMatrix[6]) > 1E-3) ||
1427  (fabs(projectionMatrix[7]) > 1E-3) ||
1428  (fabs(projectionMatrix[8]) > 1E-3) ||
1429  (fabs(projectionMatrix[9]) > 1E-3))
1430  message = "Non null coefficient in projection matrix - Aborting";
1431  else
1432  if ((fabs(projectionMatrix[11]+1.0) < 1E-5) && (fabs(projectionMatrix[15]) < 1E-5))
1433  {
1434  if (projectionMatrix[5] < 1E-4)
1435  message="Negative field of view in Camera::setFromProjectionMatrix";
1436  else
1437  setType(Camera::PERSPECTIVE);
1438  }
1439  else
1440  if ((fabs(projectionMatrix[11]) < 1E-5) && (fabs(projectionMatrix[15]-1.0) < 1E-5))
1441  setType(Camera::ORTHOGRAPHIC);
1442  else
1443  message = "Unable to determine camera type in setFromProjectionMatrix - Aborting";
1444 
1445  if (!message.isEmpty())
1446  {
1447  qWarning(message);
1448  return;
1449  }
1450 
1451  switch (type())
1452  {
1453  case Camera::PERSPECTIVE:
1454  {
1455  setFieldOfView(2.0 * atan(1.0/projectionMatrix[5]));
1456  const float far = projectionMatrix[14] / (2.0 * (1.0 + projectionMatrix[10]));
1457  const float near = (projectionMatrix[10]+1.0) / (projectionMatrix[10]-1.0) * far;
1458  setSceneRadius((far-near)/2.0);
1459  setSceneCenter(position() + (near + sceneRadius())*viewDirection());
1460  break;
1461  }
1462  case Camera::ORTHOGRAPHIC:
1463  {
1464  GLdouble w, h;
1465  getOrthoWidthHeight(w,h);
1466  projectionMatrix_[0] = 1.0/w;
1467  projectionMatrix_[5] = 1.0/h;
1468  projectionMatrix_[10] = -2.0/(ZFar - ZNear);
1469  projectionMatrix_[11] = 0.0;
1470  projectionMatrix_[14] = -(ZFar + ZNear)/(ZFar - ZNear);
1471  projectionMatrix_[15] = 1.0;
1472  // same as glOrtho( -w, w, -h, h, zNear(), zFar() );
1473  break;
1474  }
1475  }
1476 }
1477 */
1478 
1480 
1482 void Camera::getCameraCoordinatesOf(const float src[3], float res[3]) const
1483 {
1484  Vec r = cameraCoordinatesOf(Vec(src));
1485  for (int i=0; i<3; ++i)
1486  res[i] = r[i];
1487 }
1488 
1490 void Camera::getWorldCoordinatesOf(const float src[3], float res[3]) const
1491 {
1492  Vec r = worldCoordinatesOf(Vec(src));
1493  for (int i=0; i<3; ++i)
1494  res[i] = r[i];
1495 }
1496 
1502 void Camera::getViewport(GLint viewport[4]) const
1503 {
1504  viewport[0] = 0;
1505  viewport[1] = screenHeight();
1506  viewport[2] = screenWidth();
1507  viewport[3] = -screenHeight();
1508 }
1509 
1584 Vec Camera::projectedCoordinatesOf(const Vec& src, const Frame* frame) const
1585 {
1586  GLdouble x,y,z;
1587  static GLint viewport[4];
1588  getViewport(viewport);
1589 
1590  if (frame)
1591  {
1592  const Vec tmp = frame->inverseCoordinatesOf(src);
1593  gluProject(tmp.x,tmp.y,tmp.z, modelViewMatrix_, projectionMatrix_, viewport, &x,&y,&z);
1594  }
1595  else
1596  gluProject(src.x,src.y,src.z, modelViewMatrix_, projectionMatrix_, viewport, &x,&y,&z);
1597 
1598  return Vec(x,y,z);
1599 }
1600 
1631 Vec Camera::unprojectedCoordinatesOf(const Vec& src, const Frame* frame) const
1632 {
1633  GLdouble x,y,z;
1634  static GLint viewport[4];
1635  getViewport(viewport);
1636  gluUnProject(src.x,src.y,src.z, modelViewMatrix_, projectionMatrix_, viewport, &x,&y,&z);
1637  if (frame)
1638  return frame->coordinatesOf(Vec(x,y,z));
1639  else
1640  return Vec(x,y,z);
1641 }
1642 
1644 void Camera::getProjectedCoordinatesOf(const float src[3], float res[3], const Frame* frame) const
1645 {
1646  Vec r = projectedCoordinatesOf(Vec(src), frame);
1647  for (int i=0; i<3; ++i)
1648  res[i] = r[i];
1649 }
1650 
1652 void Camera::getUnprojectedCoordinatesOf(const float src[3], float res[3], const Frame* frame) const
1653 {
1654  Vec r = unprojectedCoordinatesOf(Vec(src), frame);
1655  for (int i=0; i<3; ++i)
1656  res[i] = r[i];
1657 }
1658 
1660 
1665 {
1666  if (kfi_.contains(i))
1667  return kfi_[i];
1668  else
1669  return NULL;
1670 }
1671 
1691 {
1692  if (kfi)
1693  kfi_[i] = kfi;
1694  else
1695  kfi_.remove(i);
1696 }
1697 
1711 {
1712  if (!kfi_.contains(i))
1714 
1715  kfi_[i]->addKeyFrame(*(frame()));
1716 }
1717 
1726 void Camera::playPath(int i)
1727 {
1728  if (kfi_.contains(i)) {
1729  if (kfi_[i]->interpolationIsStarted())
1730  kfi_[i]->stopInterpolation();
1731  else
1732  kfi_[i]->startInterpolation();
1733  }
1734 }
1735 
1742 {
1743  if (kfi_.contains(i)) {
1744  if ((kfi_[i]->interpolationIsStarted()))
1745  kfi_[i]->stopInterpolation();
1746  else
1747  {
1748  kfi_[i]->resetInterpolation();
1749  kfi_[i]->interpolateAtTime(kfi_[i]->interpolationTime());
1750  }
1751  }
1752 }
1753 
1763 {
1764  if (kfi_.contains(i))
1765  {
1766  kfi_[i]->stopInterpolation();
1767  delete kfi_[i];
1768  kfi_.remove(i);
1769  }
1770 }
1771 
1779 {
1780  for (QMap<int, KeyFrameInterpolator*>::ConstIterator it = kfi_.begin(), end=kfi_.end(); it != end; ++it)
1781  (it.value())->drawPath(3, 5, sceneRadius());
1782 }
1783 
1785 
1811 QDomElement Camera::domElement(const QString& name, QDomDocument& document) const
1812 {
1813  QDomElement de = document.createElement(name);
1814  QDomElement paramNode = document.createElement("Parameters");
1815  paramNode.setAttribute("fieldOfView", QString::number(fieldOfView()));
1816  paramNode.setAttribute("zNearCoefficient", QString::number(zNearCoefficient()));
1817  paramNode.setAttribute("zClippingCoefficient", QString::number(zClippingCoefficient()));
1818  paramNode.setAttribute("orthoCoef", QString::number(orthoCoef_));
1819  paramNode.setAttribute("sceneRadius", QString::number(sceneRadius()));
1820  paramNode.appendChild(sceneCenter().domElement("SceneCenter", document));
1821 
1822  switch (type())
1823  {
1824  case Camera::PERSPECTIVE : paramNode.setAttribute("Type", "PERSPECTIVE"); break;
1825  case Camera::ORTHOGRAPHIC : paramNode.setAttribute("Type", "ORTHOGRAPHIC"); break;
1826  }
1827  de.appendChild(paramNode);
1828 
1829  QDomElement stereoNode = document.createElement("Stereo");
1830  stereoNode.setAttribute("IODist", QString::number(IODistance()));
1831  stereoNode.setAttribute("focusDistance", QString::number(focusDistance()));
1832  stereoNode.setAttribute("physScreenWidth", QString::number(physicalScreenWidth()));
1833  de.appendChild(stereoNode);
1834 
1835  de.appendChild(frame()->domElement("ManipulatedCameraFrame", document));
1836 
1837  // KeyFrame paths
1838  for (QMap<int, KeyFrameInterpolator*>::ConstIterator it = kfi_.begin(), end=kfi_.end(); it != end; ++it)
1839  {
1840  QDomElement kfNode = (it.value())->domElement("KeyFrameInterpolator", document);
1841  kfNode.setAttribute("index", QString::number(it.key()));
1842  de.appendChild(kfNode);
1843  }
1844 
1845  return de;
1846 }
1847 
1869 void Camera::initFromDOMElement(const QDomElement& element)
1870 {
1871  QDomElement child=element.firstChild().toElement();
1872 
1873  QMutableMapIterator<int, KeyFrameInterpolator*> it(kfi_);
1874  while (it.hasNext()) {
1875  it.next();
1876  deletePath(it.key());
1877  }
1878 
1879  while (!child.isNull())
1880  {
1881  if (child.tagName() == "Parameters")
1882  {
1883  // #CONNECTION# Default values set in constructor
1884  setFieldOfView(DomUtils::floatFromDom(child, "fieldOfView", M_PI/4.0f));
1885  setZNearCoefficient(DomUtils::floatFromDom(child, "zNearCoefficient", 0.005f));
1886  setZClippingCoefficient(DomUtils::floatFromDom(child, "zClippingCoefficient", sqrt(3.0)));
1887  orthoCoef_ = DomUtils::floatFromDom(child, "orthoCoef", tan(fieldOfView()/2.0));
1888  setSceneRadius(DomUtils::floatFromDom(child, "sceneRadius", sceneRadius()));
1889 
1890  setType(PERSPECTIVE);
1891  QString type = child.attribute("Type", "PERSPECTIVE");
1892  if (type == "PERSPECTIVE") setType(Camera::PERSPECTIVE);
1893  if (type == "ORTHOGRAPHIC") setType(Camera::ORTHOGRAPHIC);
1894 
1895  QDomElement child2=child.firstChild().toElement();
1896  while (!child2.isNull())
1897  {
1898  /* Although the scene does not change when a camera is loaded, restore the saved center and radius values.
1899  Mainly useful when a the viewer is restored on startup, with possible additional cameras. */
1900  if (child2.tagName() == "SceneCenter")
1901  setSceneCenter(Vec(child2));
1902 
1903  child2 = child2.nextSibling().toElement();
1904  }
1905  }
1906 
1907  if (child.tagName() == "ManipulatedCameraFrame")
1908  frame()->initFromDOMElement(child);
1909 
1910  if (child.tagName() == "Stereo")
1911  {
1912  setIODistance(DomUtils::floatFromDom(child, "IODist", 0.062f));
1913  setFocusDistance(DomUtils::floatFromDom(child, "focusDistance", focusDistance()));
1914  setPhysicalScreenWidth(DomUtils::floatFromDom(child, "physScreenWidth", 0.5f));
1915  }
1916 
1917  if (child.tagName() == "KeyFrameInterpolator")
1918  {
1919  int index = DomUtils::intFromDom(child, "index", 0);
1921  if (keyFrameInterpolator(index))
1923  }
1924 
1925  child = child.nextSibling().toElement();
1926  }
1927 }
1928 
1940 void Camera::convertClickToLine(const QPoint& pixel, Vec& orig, Vec& dir) const
1941 {
1942  switch (type())
1943  {
1944  case Camera::PERSPECTIVE:
1945  orig = position();
1946  dir = Vec( ((2.0 * pixel.x() / screenWidth()) - 1.0) * tan(fieldOfView()/2.0) * aspectRatio(),
1947  ((2.0 * (screenHeight()-pixel.y()) / screenHeight()) - 1.0) * tan(fieldOfView()/2.0),
1948  -1.0 );
1949  dir = worldCoordinatesOf(dir) - orig;
1950  dir.normalize();
1951  break;
1952 
1953  case Camera::ORTHOGRAPHIC:
1954  {
1955  GLdouble w,h;
1956  getOrthoWidthHeight(w,h);
1957  orig = Vec((2.0 * pixel.x() / screenWidth() - 1.0)*w, -(2.0 * pixel.y() / screenHeight() - 1.0)*h, 0.0);
1958  orig = worldCoordinatesOf(orig);
1959  dir = viewDirection();
1960  break;
1961  }
1962  }
1963 }
1964 
1965 #ifndef DOXYGEN
1966 
1967 void Camera::drawCamera(float, float, float)
1968 {
1969  qWarning("drawCamera is deprecated. Use Camera::draw() instead.");
1970 }
1971 #endif
1972 
1993 void Camera::draw(bool drawFarPlane, float scale) const
1994 {
1995  glPushMatrix();
1996  glMultMatrixd(frame()->worldMatrix());
1997 
1998  // 0 is the upper left coordinates of the near corner, 1 for the far one
1999  Vec points[2];
2000 
2001  points[0].z = scale * zNear();
2002  points[1].z = scale * zFar();
2003 
2004  switch (type())
2005  {
2006  case Camera::PERSPECTIVE:
2007  {
2008  points[0].y = points[0].z * tan(fieldOfView()/2.0);
2009  points[0].x = points[0].y * aspectRatio();
2010 
2011  const float ratio = points[1].z / points[0].z;
2012 
2013  points[1].y = ratio * points[0].y;
2014  points[1].x = ratio * points[0].x;
2015  break;
2016  }
2017  case Camera::ORTHOGRAPHIC:
2018  {
2019  GLdouble hw, hh;
2020  getOrthoWidthHeight(hw, hh);
2021  points[0].x = points[1].x = scale * float(hw);
2022  points[0].y = points[1].y = scale * float(hh);
2023  break;
2024  }
2025  }
2026 
2027  const int farIndex = drawFarPlane?1:0;
2028 
2029  // Near and (optionally) far plane(s)
2030  glBegin(GL_QUADS);
2031  for (int i=farIndex; i>=0; --i)
2032  {
2033  glNormal3f(0.0, 0.0, (i==0)?1.0:-1.0);
2034  glVertex3f( points[i].x, points[i].y, -points[i].z);
2035  glVertex3f(-points[i].x, points[i].y, -points[i].z);
2036  glVertex3f(-points[i].x, -points[i].y, -points[i].z);
2037  glVertex3f( points[i].x, -points[i].y, -points[i].z);
2038  }
2039  glEnd();
2040 
2041  // Up arrow
2042  const float arrowHeight = 1.5f * points[0].y;
2043  const float baseHeight = 1.2f * points[0].y;
2044  const float arrowHalfWidth = 0.5f * points[0].x;
2045  const float baseHalfWidth = 0.3f * points[0].x;
2046 
2047  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
2048  // Base
2049  glBegin(GL_QUADS);
2050  glVertex3f(-baseHalfWidth, points[0].y, -points[0].z);
2051  glVertex3f( baseHalfWidth, points[0].y, -points[0].z);
2052  glVertex3f( baseHalfWidth, baseHeight, -points[0].z);
2053  glVertex3f(-baseHalfWidth, baseHeight, -points[0].z);
2054  glEnd();
2055 
2056  // Arrow
2057  glBegin(GL_TRIANGLES);
2058  glVertex3f( 0.0f, arrowHeight, -points[0].z);
2059  glVertex3f(-arrowHalfWidth, baseHeight, -points[0].z);
2060  glVertex3f( arrowHalfWidth, baseHeight, -points[0].z);
2061  glEnd();
2062 
2063  // Frustum lines
2064  switch (type())
2065  {
2066  case Camera::PERSPECTIVE :
2067  glBegin(GL_LINES);
2068  glVertex3f(0.0f, 0.0f, 0.0f);
2069  glVertex3f( points[farIndex].x, points[farIndex].y, -points[farIndex].z);
2070  glVertex3f(0.0f, 0.0f, 0.0f);
2071  glVertex3f(-points[farIndex].x, points[farIndex].y, -points[farIndex].z);
2072  glVertex3f(0.0f, 0.0f, 0.0f);
2073  glVertex3f(-points[farIndex].x, -points[farIndex].y, -points[farIndex].z);
2074  glVertex3f(0.0f, 0.0f, 0.0f);
2075  glVertex3f( points[farIndex].x, -points[farIndex].y, -points[farIndex].z);
2076  glEnd();
2077  break;
2078  case Camera::ORTHOGRAPHIC :
2079  if (drawFarPlane)
2080  {
2081  glBegin(GL_LINES);
2082  glVertex3f( points[0].x, points[0].y, -points[0].z);
2083  glVertex3f( points[1].x, points[1].y, -points[1].z);
2084  glVertex3f(-points[0].x, points[0].y, -points[0].z);
2085  glVertex3f(-points[1].x, points[1].y, -points[1].z);
2086  glVertex3f(-points[0].x, -points[0].y, -points[0].z);
2087  glVertex3f(-points[1].x, -points[1].y, -points[1].z);
2088  glVertex3f( points[0].x, -points[0].y, -points[0].z);
2089  glVertex3f( points[1].x, -points[1].y, -points[1].z);
2090  glEnd();
2091  }
2092  }
2093 
2094  glPopMatrix();
2095 }
2096 
2097 
2121 void Camera::getFrustumPlanesCoefficients(GLdouble coef[6][4]) const
2122 {
2123  // Computed once and for all
2124  const Vec pos = position();
2125  const Vec viewDir = viewDirection();
2126  const Vec up = upVector();
2127  const Vec right = rightVector();
2128  const float posViewDir = pos * viewDir;
2129 
2130  static Vec normal[6];
2131  static GLdouble dist[6];
2132 
2133  switch (type())
2134  {
2135  case Camera::PERSPECTIVE :
2136  {
2137  const float hhfov = horizontalFieldOfView() / 2.0;
2138  const float chhfov = cos(hhfov);
2139  const float shhfov = sin(hhfov);
2140  normal[0] = - shhfov * viewDir;
2141  normal[1] = normal[0] + chhfov * right;
2142  normal[0] = normal[0] - chhfov * right;
2143 
2144  normal[2] = -viewDir;
2145  normal[3] = viewDir;
2146 
2147  const float hfov = fieldOfView() / 2.0;
2148  const float chfov = cos(hfov);
2149  const float shfov = sin(hfov);
2150  normal[4] = - shfov * viewDir;
2151  normal[5] = normal[4] - chfov * up;
2152  normal[4] = normal[4] + chfov * up;
2153 
2154  for (int i=0; i<2; ++i)
2155  dist[i] = pos * normal[i];
2156  for (int j=4; j<6; ++j)
2157  dist[j] = pos * normal[j];
2158 
2159  // Natural equations are:
2160  // dist[0,1,4,5] = pos * normal[0,1,4,5];
2161  // dist[2] = (pos + zNear() * viewDir) * normal[2];
2162  // dist[3] = (pos + zFar() * viewDir) * normal[3];
2163 
2164  // 2 times less computations using expanded/merged equations. Dir vectors are normalized.
2165  const float posRightCosHH = chhfov * pos * right;
2166  dist[0] = -shhfov * posViewDir;
2167  dist[1] = dist[0] + posRightCosHH;
2168  dist[0] = dist[0] - posRightCosHH;
2169  const float posUpCosH = chfov * pos * up;
2170  dist[4] = - shfov * posViewDir;
2171  dist[5] = dist[4] - posUpCosH;
2172  dist[4] = dist[4] + posUpCosH;
2173 
2174  break;
2175  }
2176  case Camera::ORTHOGRAPHIC :
2177  normal[0] = -right;
2178  normal[1] = right;
2179  normal[4] = up;
2180  normal[5] = -up;
2181 
2182  GLdouble hw, hh;
2183  getOrthoWidthHeight(hw, hh);
2184  dist[0] = (pos - hw * right) * normal[0];
2185  dist[1] = (pos + hw * right) * normal[1];
2186  dist[4] = (pos + hh * up) * normal[4];
2187  dist[5] = (pos - hh * up) * normal[5];
2188  break;
2189  }
2190 
2191  // Front and far planes are identical for both camera types.
2192  normal[2] = -viewDir;
2193  normal[3] = viewDir;
2194  dist[2] = -posViewDir - zNear();
2195  dist[3] = posViewDir + zFar();
2196 
2197  for (int i=0; i<6; ++i)
2198  {
2199  coef[i][0] = GLdouble(normal[i].x);
2200  coef[i][1] = GLdouble(normal[i].y);
2201  coef[i][2] = GLdouble(normal[i].z);
2202  coef[i][3] = dist[i];
2203  }
2204 }
2205 
2206 void Camera::onFrameModified() {
2207  projectionMatrixIsUpToDate_ = false;
2208  modelViewMatrixIsUpToDate_ = false;
2209 }
virtual ~Camera()
Virtual destructor.
Definition: camera.cpp:86
virtual float zNear() const
Returns the near clipping plane distance used by the Camera projection matrix.
Definition: camera.cpp:211
virtual QDomElement domElement(const QString &name, QDomDocument &document) const
Returns an XML QDomElement that represents the Camera.
Definition: camera.cpp:1811
void fitScreenRegion(const QRect &rectangle)
Moves the Camera so that the rectangular screen region defined by rectangle (pixel units...
Definition: camera.cpp:1058
float distanceToSceneCenter() const
Returns the distance from the Camera center to sceneCenter(), projected along the Camera Z axis...
Definition: camera.cpp:303
KeyFrameInterpolator * keyFrameInterpolator(int i) const
Returns the KeyFrameInterpolator that defines the Camera path number i.
Definition: camera.cpp:1664
A keyFrame Catmull-Rom Frame interpolator.
Vec projectedCoordinatesOf(const Vec &src, const Frame *frame=NULL) const
Returns the screen projected coordinates of a point src defined in the frame coordinate system...
Definition: camera.cpp:1584
void getCameraCoordinatesOf(const float src[3], float res[3]) const
Same as cameraCoordinatesOf(), but with float[3] parameters (src and res may be identical pointers)...
Definition: camera.cpp:1482
The ManipulatedCameraFrame class represents a ManipulatedFrame with Camera specific mouse bindings...
void setFromProjectionMatrix(const float matrix[12])
Defines the Camera position(), orientation() and fieldOfView() from a projection matrix.
Definition: camera.cpp:1332
float pixelGLRatio(const Vec &position) const
Returns the ratio between pixel and OpenGL units at position.
Definition: camera.cpp:819
void getWorldCoordinatesOf(const float src[3], float res[3]) const
Same as worldCoordinatesOf(), but with float[3] parameters (src and res may be identical pointers)...
Definition: camera.cpp:1490
Vec pivotPoint() const
The point the Camera pivots around with the QGLViewer::ROTATE mouse binding.
Definition: camera.cpp:1275
Camera & operator=(const Camera &camera)
Equal operator.
Definition: camera.cpp:124
Vec sceneCenter() const
Returns the position of the scene center, defined in the world coordinate system. ...
Definition: camera.h:297
void getModelViewProjectionMatrix(GLfloat m[16]) const
Overloaded getModelViewProjectionMatrix(GLdouble m[16]) method using a float array instead...
Definition: camera.cpp:693
float flySpeed() const
Returns the fly speed, expressed in OpenGL units.
double squaredNorm() const
Returns the squared norm of the Vec.
Definition: vec.h:332
void setSceneBoundingBox(const Vec &min, const Vec &max)
Similar to setSceneRadius() and setSceneCenter(), but the scene limits are defined by a (world axis a...
Definition: camera.cpp:723
void deletePath()
Removes all keyFrames from the path.
Vec worldCoordinatesOf(const Vec &src) const
Returns the world coordinates of the point whose position src is defined in the Camera coordinate sys...
Definition: camera.cpp:1254
Vec pointUnderPixel(const QPoint &pixel, bool &found) const
Returns the coordinates of the 3D point located at pixel (x,y) on screen.
Definition: camera.cpp:971
Vec unprojectedCoordinatesOf(const Vec &src, const Frame *frame=NULL) const
Returns the world unprojected coordinates of a point src defined in the screen coordinate system...
Definition: camera.cpp:1631
void stopInterpolation()
Stops an interpolation started with startInterpolation().
Quaternion orientation() const
Returns the Camera orientation, defined in the world coordinate system.
Definition: camera.cpp:1237
void setFrame(Frame *const frame)
Sets the frame() associated to the KeyFrameInterpolator.
virtual void drawAllPaths()
Draws all the Camera paths defined by the keyFrameInterpolator().
Definition: camera.cpp:1778
void startInterpolation(int period=-1)
Starts the interpolation process.
Vec pivotPoint() const
Returns the point the ManipulatedCameraFrame pivot point, around which the camera rotates...
void setFlySpeed(float speed)
Sets the Camera flySpeed().
Definition: camera.cpp:1268
Type
Enumerates the two possible types of Camera.
Definition: camera.h:105
void fitSphere(const Vec &center, float radius)
Moves the Camera so that the sphere defined by (center, radius) is visible and fits in the frustum...
Definition: camera.cpp:1020
void setOrientationWithConstraint(Quaternion &orientation)
Same as setOrientation(), but orientation is modified so that the potential constraint() of the Frame...
Definition: frame.cpp:631
float focusDistance() const
Returns the focus distance used by stereo display, expressed in OpenGL units.
Definition: camera.h:452
virtual void initFromDOMElement(const QDomElement &element)
Restores the Camera state from a QDomElement created by domElement().
Definition: camera.cpp:1869
Vec upVector() const
Returns the normalized up vector of the Camera, defined in the world coordinate system.
Definition: camera.cpp:1209
float flySpeed() const
Returns the fly speed of the Camera.
Definition: camera.cpp:1263
int screenWidth() const
Returns the width (in pixels) of the Camera screen.
Definition: camera.h:190
virtual void loadProjectionMatrixStereo(bool leftBuffer=true) const
Same as loadProjectionMatrix() but for a stereo setup.
Definition: camera.cpp:536
virtual void loadModelViewMatrix(bool reset=true) const
Loads the OpenGL GL_MODELVIEW matrix with the modelView matrix corresponding to the Camera...
Definition: camera.cpp:500
void setZClippingCoefficient(float coef)
Sets the zClippingCoefficient() value.
Definition: camera.h:268
Vec rightVector() const
Returns the normalized right vector of the Camera, defined in the world coordinate system...
Definition: camera.cpp:1228
void setKeyFrameInterpolator(int i, KeyFrameInterpolator *const kfi)
Sets the KeyFrameInterpolator that defines the Camera path of index i.
Definition: camera.cpp:1690
static void drawCamera(float scale=1.0, float aspectRatio=1.33, float fieldOfView=M_PI/4.0)
This method has been deprecated in libQGLViewer version 2.2.0.
Definition: camera.cpp:1967
FARSA_UTIL_TEMPLATE const T max(const T &t1, const U &t2)
bool setSceneCenterFromPixel(const QPoint &pixel)
setSceneCenter() to the result of pointUnderPixel(pixel).
Definition: camera.cpp:745
void setIODistance(float distance)
Sets the IODistance().
Definition: camera.h:455
Vec viewDirection() const
Returns the normalized view direction of the Camera, defined in the world coordinate system...
Definition: camera.cpp:1220
ManipulatedCameraFrame * frame() const
Returns the ManipulatedCameraFrame attached to the Camera.
Definition: camera.h:334
void setFieldOfView(float fov)
Sets the vertical fieldOfView() of the Camera (in radians).
Definition: camera.cpp:245
void setFocusDistance(float distance)
Sets the focusDistance(), in OpenGL scene units.
Definition: camera.h:466
void getProjectionMatrix(GLfloat m[16]) const
Overloaded getProjectionMatrix(GLdouble m[16]) method using a float array instead.
Definition: camera.cpp:629
virtual void loadModelViewMatrixStereo(bool leftBuffer=true) const
Same as loadModelViewMatrix() but for a stereo setup.
Definition: camera.cpp:591
void setType(Type type)
Defines the Camera type().
Definition: camera.cpp:261
void interpolateTo(const Frame &fr, float duration)
Smoothly interpolates the Camera on a KeyFrameInterpolator path so that it goes to fr...
Definition: camera.cpp:942
int screenHeight() const
Returns the height (in pixels) of the Camera screen.
Definition: camera.h:195
Vec coordinatesOf(const Vec &src) const
Returns the Frame coordinates of a point src defined in the world coordinate system (converts from wo...
Definition: frame.cpp:702
float fieldOfView() const
Returns the vertical field of view of the Camera (in radians).
Definition: camera.h:170
void setOrientation(const Quaternion &q)
Sets the Camera orientation(), defined in the world coordinate system.
Definition: camera.cpp:1150
void resetInterpolation()
Stops the interpolation and resets interpolationTime() to the firstTime().
void convertClickToLine(const QPoint &pixel, Vec &orig, Vec &dir) const
Gives the coefficients of a 3D half-line passing through the Camera eye and pixel (x...
Definition: camera.cpp:1940
The Vec class represents 3D positions and 3D vectors.
Definition: vec.h:65
void showEntireScene()
Moves the Camera so that the entire scene is visible.
Definition: camera.cpp:987
void rotate(Quaternion &q)
Same as rotate(const Quaternion&) but q may be modified to satisfy the rotation constraint().
Definition: frame.cpp:376
void addKeyFrame(const Frame &frame)
Appends a new keyFrame to the path.
virtual void getOrthoWidthHeight(GLdouble &halfWidth, GLdouble &halfHeight) const
Returns the halfWidth and halfHeight of the Camera orthographic frustum.
Definition: camera.cpp:324
Vec cameraCoordinatesOf(const Vec &src) const
Returns the Camera frame coordinates of a point src defined in world coordinates. ...
Definition: camera.cpp:1248
void setFromRotatedBasis(const Vec &X, const Vec &Y, const Vec &Z)
Sets the Quaternion from the three rotated vectors of an orthogonal basis.
Definition: quaternion.cpp:182
void setScreenWidthAndHeight(int width, int height)
Sets Camera screenWidth() and screenHeight() (expressed in pixels).
Definition: camera.cpp:166
void getProjectedCoordinatesOf(const float src[3], float res[3], const Frame *frame=NULL) const
Same as projectedCoordinatesOf(), but with float parameters (src and res can be identical pointers)...
Definition: camera.cpp:1644
Quaternion orientation() const
Returns the orientation of the Frame, defined in the world coordinate system.
Definition: frame.cpp:546
void setFlySpeed(float speed)
Sets the flySpeed(), defined in OpenGL units.
float aspectRatio() const
Returns the Camera aspect ratio defined by screenWidth() / screenHeight().
Definition: camera.h:185
void setPositionWithConstraint(Vec &position)
Same as setPosition(), but position is modified so that the potential constraint() of the Frame is sa...
Definition: frame.cpp:621
virtual void addKeyFrameToPath(int i)
Adds the current Camera position() and orientation() as a keyFrame to the path number i...
Definition: camera.cpp:1710
bool interpolationIsStarted() const
Returns true when the interpolation is being performed.
bool setPivotPointFromPixel(const QPoint &pixel)
The pivotPoint() is set to the point located under pixel on screen.
Definition: camera.cpp:796
virtual void loadProjectionMatrix(bool reset=true) const
Loads the OpenGL GL_PROJECTION matrix with the Camera projection matrix.
Definition: camera.cpp:463
virtual float zFar() const
Returns the far clipping plane distance used by the Camera projection matrix.
Definition: camera.cpp:236
void setPhysicalScreenWidth(float width)
Sets the physical screen (monitor or projected wall) width (in meters).
Definition: camera.h:463
void interpolateToFitScene()
Interpolates the Camera on a one second KeyFrameInterpolator path so that the entire scene fits the s...
Definition: camera.cpp:913
void projectOnLine(const Vec &origin, const Vec &direction)
Translates the Frame so that its position() lies on the line defined by origin and direction (defined...
Definition: frame.cpp:1133
void setSceneCenter(const Vec &center)
Sets the sceneCenter().
Definition: camera.cpp:733
void setFrame(ManipulatedCameraFrame *const mcf)
Sets the Camera frame().
Definition: camera.cpp:285
void getFrustumPlanesCoefficients(GLdouble coef[6][4]) const
Returns the 6 plane equations of the Camera frustum.
Definition: camera.cpp:2121
float zClippingCoefficient() const
Returns the coefficient used to position the near and far clipping planes.
Definition: camera.h:229
virtual void deletePath(int i)
Deletes the keyFrameInterpolator() of index i.
Definition: camera.cpp:1762
void computeProjectionMatrix() const
Computes the projection matrix associated with the Camera.
Definition: camera.cpp:350
A perspective or orthographic camera.
Definition: camera.h:84
virtual void initFromDOMElement(const QDomElement &element)
Restores the KeyFrameInterpolator state from a QDomElement created by domElement().
The Quaternion class represents 3D rotations and orientations.
Definition: quaternion.h:66
virtual void draw(bool drawFarPlane=true, float scale=1.0) const
Draws a representation of the Camera in the 3D world.
Definition: camera.cpp:1993
float physicalScreenWidth() const
Returns the physical screen width, in meters.
Definition: camera.h:440
void setReferenceFrame(const Frame *const refFrame)
Sets the referenceFrame() of the Frame.
Definition: frame.cpp:665
void setPivotPoint(const Vec &point)
Changes the pivotPoint() to point (defined in the world coordinate system).
Definition: camera.cpp:770
void setPosition(const Vec &position)
Sets the position() of the Frame, defined in the world coordinate system.
Definition: frame.cpp:443
Type type() const
Returns the Camera::Type of the Camera.
Definition: camera.h:158
void centerScene()
Moves the Camera so that its sceneCenter() is projected on the center of the window.
Definition: camera.cpp:997
void fitBoundingBox(const Vec &min, const Vec &max)
Moves the Camera so that the (world axis aligned) bounding box (min, max) is entirely visible...
Definition: camera.cpp:1044
virtual void playPath(int i)
Makes the Camera follow the path of keyFrameInterpolator() number i.
Definition: camera.cpp:1726
void setZNearCoefficient(float coef)
Sets the zNearCoefficient() value.
Definition: camera.h:266
void setViewDirection(const Vec &direction)
Rotates the Camera so that its viewDirection() is direction (defined in the world coordinate system)...
Definition: camera.cpp:1161
void lookAt(const Vec &target)
Sets the Camera orientation(), so that it looks at point target (defined in the world coordinate syst...
Definition: camera.cpp:1008
void setFromModelViewMatrix(const GLdouble *const modelViewMatrix)
Sets the Camera's position() and orientation() from an OpenGL ModelView matrix.
Definition: camera.cpp:1294
void setUpVector(const Vec &up, bool noMove=true)
Rotates the Camera so that its upVector() becomes up (defined in the world coordinate system)...
Definition: camera.cpp:1116
void setPosition(const Vec &pos)
Sets the Camera position() (the eye), defined in the world coordinate system.
Definition: camera.cpp:1240
float IODistance() const
Returns the user's inter-ocular distance (in meters).
Definition: camera.h:425
void getModelViewMatrix(GLfloat m[16]) const
Overloaded getModelViewMatrix(GLdouble m[16]) method using a float array instead. ...
Definition: camera.cpp:662
void getViewport(GLint viewport[4]) const
Fills viewport with the Camera OpenGL viewport.
Definition: camera.cpp:1502
void setFOVToFitScene()
Changes the Camera fieldOfView() so that the entire scene (defined by QGLViewer::sceneCenter() and QG...
Definition: camera.cpp:861
FARSA_UTIL_TEMPLATE const T min(const T &t1, const U &t2)
The Frame class represents a coordinate system, defined by a position and an orientation.
Definition: frame.h:121
double normalize()
Normalizes the Vec and returns its original norm.
Definition: vec.h:340
Vec position() const
Returns the Camera position (the eye), defined in the world coordinate system.
Definition: camera.cpp:1200
void setPivotPoint(const Vec &point)
Sets the pivotPoint(), defined in the world coordinate system.
Camera()
Default constructor.
Definition: camera.cpp:38
Vec rotate(const Vec &v) const
Returns the image of v by the Quaternion rotation.
Definition: quaternion.cpp:76
void setOrientation(const Quaternion &orientation)
Sets the orientation() of the Frame, defined in the world coordinate system.
Definition: frame.cpp:505
Vec inverseCoordinatesOf(const Vec &src) const
Returns the world coordinates of the point whose position in the Frame coordinate system is src (conv...
Definition: frame.cpp:715
Vec position() const
Returns the position of the Frame, defined in the world coordinate system.
Definition: frame.cpp:537
float sceneRadius() const
Returns the radius of the scene observed by the Camera.
Definition: camera.h:284
float horizontalFieldOfView() const
Returns the horizontal field of view of the Camera (in radians).
Definition: camera.h:179
void interpolateToZoomOnPixel(const QPoint &pixel)
Makes the Camera smoothly zoom on the pointUnderPixel() pixel.
Definition: camera.cpp:875
Vec inverseTransformOf(const Vec &src) const
Returns the world transform of the vector whose coordinates in the Frame coordinate system is src (co...
Definition: frame.cpp:856
virtual void resetPath(int i)
Resets the path of the keyFrameInterpolator() number i.
Definition: camera.cpp:1741
void setSceneRadius(float radius)
Sets the sceneRadius() value.
Definition: camera.cpp:705
void computeModelViewMatrix() const
Computes the modelView matrix associated with the Camera's position() and orientation().
Definition: camera.cpp:400
virtual void initFromDOMElement(const QDomElement &element)
Restores the ManipulatedCameraFrame state from a QDomElement created by domElement().
float zNearCoefficient() const
Returns the coefficient which is used to set zNear() when the Camera is inside the sphere defined by ...
Definition: camera.h:210
void getUnprojectedCoordinatesOf(const float src[3], float res[3], const Frame *frame=NULL) const
Same as unprojectedCoordinatesOf(), but with float parameters (src and res can be identical pointers)...
Definition: camera.cpp:1652