1 /****************************************************************************
2 
3  Copyright (c) 2018  GeometryFactory Sarl (France).
4  Copyright (C) 2002-2014 Gilles Debunne. All rights reserved.
5 
6  This file is part of a fork of the QGLViewer library version 2.7.0.
7 
8 *****************************************************************************/
9 // $URL: https://github.com/CGAL/cgal/blob/v5.3/GraphicsView/include/CGAL/Qt/camera_impl.h $
10 // $Id: camera_impl.h db338aa 2021-02-18T15:19:06+01:00 Laurent Rineau
11 // SPDX-License-Identifier: GPL-3.0-only
12 
13 #ifdef CGAL_HEADER_ONLY
14 #define CGAL_INLINE_FUNCTION inline
15 
16 #include <CGAL/license/GraphicsView.h>
17 
18 #else
19 #define CGAL_INLINE_FUNCTION
20 #endif
21 
22 #include <CGAL/Qt/camera.h>
23 #include <CGAL/Qt/manipulatedCameraFrame.h>
24 #include <CGAL/Qt/keyFrameInterpolator.h>
25 
26 namespace CGAL{
27 namespace qglviewer{
28 
29 /*! Default constructor.
30 
31  sceneCenter() is set to (0,0,0) and sceneRadius() is set to 1.0. type() is
32  Camera::PERSPECTIVE, with a \c M_PI/4 fieldOfView().
33 
34  See IODistance(), physicalDistanceToScreen(), physicalScreenWidth() and
35  focusDistance(). */
36 CGAL_INLINE_FUNCTION
Camera(QObject * parent)37 Camera::Camera(QObject *parent)
38     : frame_(nullptr), fieldOfView_(CGAL_PI / 4.0), modelViewMatrixIsUpToDate_(false),
39       projectionMatrixIsUpToDate_(false) {
40   m_zMin = 0;
41   setParent(parent);
42   // #CONNECTION# Camera copy constructor
43   interpolationKfi_ = new KeyFrameInterpolator;
44   // Requires the interpolationKfi_
45   setFrame(new ManipulatedCameraFrame());
46 
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
55   // frame().
56   setSceneCenter(Vec(0.0, 0.0, 0.0));
57 
58   // Requires fieldOfView() when called with ORTHOGRAPHIC. Attention to
59   // projectionMatrix_ below.
60   setType(PERSPECTIVE);
61 
62   setZNearCoefficient(0.005);
63   setZClippingCoefficient(sqrt(3.0));
64 
65   // Dummy values
66   setScreenWidthAndHeight(600, 400);
67 
68 
69   // focusDistance is set from setFieldOfView()
70 
71   // #CONNECTION# Camera copy constructor
72   for (unsigned short j = 0; j < 16; ++j) {
73     modelViewMatrix_[j] = ((j % 5 == 0) ? 1.0 : 0.0);
74     // #CONNECTION# computeProjectionMatrix() is lazy and assumes 0.0 almost
75     // everywhere.
76     projectionMatrix_[j] = 0.0;
77   }
78   computeProjectionMatrix();
79 }
80 
81 /*! Virtual destructor.
82 
83  The frame() is deleted, but the different keyFrameInterpolator() are \e not
84  deleted (in case they are shared). */
85 
86 CGAL_INLINE_FUNCTION
~Camera()87 Camera::~Camera() {
88   delete frame_;
89   delete interpolationKfi_;
90 }
91 
92 /*! Copy constructor. Performs a deep copy using operator=(). */
93 CGAL_INLINE_FUNCTION
Camera(const Camera & camera)94 Camera::Camera(const Camera &camera) : QObject(), frame_(nullptr) {
95   // #CONNECTION# Camera constructor
96   interpolationKfi_ = new KeyFrameInterpolator;
97   // Requires the interpolationKfi_
98   setFrame(new ManipulatedCameraFrame(*camera.frame()));
99 
100   for (unsigned short j = 0; j < 16; ++j) {
101     modelViewMatrix_[j] = ((j % 5 == 0) ? 1.0 : 0.0);
102     // #CONNECTION# computeProjectionMatrix() is lazy and assumes 0.0 almost
103     // everywhere.
104     projectionMatrix_[j] = 0.0;
105   }
106 
107   (*this) = camera;
108 }
109 
110 /*! Equal operator.
111 
112  All the parameters of \p camera are copied. The frame() pointer is not
113  modified, but its Frame::position() and Frame::orientation() are set to those
114  of \p camera.
115 
116  \attention The Camera screenWidth() and screenHeight() are set to those of \p
117  camera. If your Camera is associated with a CGAL::QGLViewer, you should update these
118  value after the call to this method: \code
119  *(camera()) = otherCamera;
120  camera()->setScreenWidthAndHeight(width(), height());
121  \endcode
122  The same applies to sceneCenter() and sceneRadius(), if needed. */
123 CGAL_INLINE_FUNCTION
124 Camera &Camera::operator=(const Camera &camera) {
125   setScreenWidthAndHeight(camera.screenWidth(), camera.screenHeight());
126   setFieldOfView(camera.fieldOfView());
127   setSceneRadius(camera.sceneRadius());
128   setSceneCenter(camera.sceneCenter());
129   setZNearCoefficient(camera.zNearCoefficient());
130   setZClippingCoefficient(camera.zClippingCoefficient());
131   setType(camera.type());
132 
133   orthoCoef_ = camera.orthoCoef_;
134   projectionMatrixIsUpToDate_ = false;
135 
136   // frame_ and interpolationKfi_ pointers are not shared.
137   frame_->setReferenceFrame(nullptr);
138   frame_->setPosition(camera.position());
139   frame_->setOrientation(camera.orientation());
140 
141   interpolationKfi_->resetInterpolation();
142 
143   kfi_ = camera.kfi_;
144 
145   computeProjectionMatrix();
146   computeModelViewMatrix();
147 
148   return *this;
149 }
150 
151 /*! Sets Camera screenWidth() and screenHeight() (expressed in pixels).
152 
153 You should not call this method when the Camera is associated with a CGAL::QGLViewer,
154 since the latter automatically updates these values when it is resized (hence
155 overwriting your values).
156 
157 Non-positive dimension are silently replaced by a 1 pixel value to ensure
158 frustrum coherence.
159 
160 If your Camera is used without a CGAL::QGLViewer (offscreen rendering, shadow maps),
161 use setAspectRatio() instead to define the projection matrix. */
162 CGAL_INLINE_FUNCTION
setScreenWidthAndHeight(int width,int height)163 void Camera::setScreenWidthAndHeight(int width, int height) {
164   // Prevent negative and zero dimensions that would cause divisions by zero.
165   screenWidth_ = width > 0 ? width : 1;
166   screenHeight_ = height > 0 ? height : 1;
167   projectionMatrixIsUpToDate_ = false;
168 }
169 
170 /*! Returns the near clipping plane distance used by the Camera projection
171  matrix.
172 
173  The clipping planes' positions depend on the sceneRadius() and sceneCenter()
174  rather than being fixed small-enough and large-enough values. A good scene
175  dimension approximation will hence result in an optimal precision of the
176  z-buffer.
177 
178  The near clipping plane is positioned at a distance equal to
179  zClippingCoefficient() * sceneRadius() in front of the sceneCenter(): \code
180  zNear = distanceToSceneCenter() - zClippingCoefficient()*sceneRadius();
181  \endcode
182 
183  In order to prevent negative or too small zNear() values (which would degrade
184  the z precision), zNearCoefficient() is used when the Camera is inside the
185  sceneRadius() sphere: \code const qreal zMin = zNearCoefficient() *
186  zClippingCoefficient() * sceneRadius(); if (zNear < zMin) zNear = zMin;
187  // With an ORTHOGRAPHIC type, the value is simply clamped to 0.0
188  \endcode
189 
190  See also the zFar(), zClippingCoefficient() and zNearCoefficient()
191  documentations.
192 
193  If you need a completely different zNear computation, overload the zNear() and
194  zFar() methods in a new class that publicly inherits from Camera and use
195  CGAL::QGLViewer::setCamera(): \code class myCamera :: public CGAL::qglviewer::Camera
196  {
197    virtual qreal Camera::zNear() const { return 0.001; };
198    virtual qreal Camera::zFar() const { return 100.0; };
199  }
200  \endcode
201 
202  See the <a href="../examples/standardCamera.html">standardCamera example</a>
203  for an application.
204 
205  \attention The value is always positive although the clipping plane is
206  positioned at a negative z value in the Camera coordinate system. This follows
207  the \c gluPerspective standard. */
208 CGAL_INLINE_FUNCTION
zNear()209 qreal Camera::zNear() const {
210   const qreal zNearScene = zClippingCoefficient() * sceneRadius();
211   qreal z = distanceToSceneCenter() - zNearScene;
212 
213   // Prevents negative or null zNear values.
214   const qreal zMin = zNearCoefficient() * zNearScene;
215   if (z < zMin)
216     switch (type()) {
217     case Camera::PERSPECTIVE:
218       z = zMin;
219       break;
220     case Camera::ORTHOGRAPHIC:
221       z = m_zMin;
222       break;
223     }
224   return z;
225 }
226 
227 /*! Returns the far clipping plane distance used by the Camera projection
228 matrix.
229 
230 The far clipping plane is positioned at a distance equal to
231 zClippingCoefficient() * sceneRadius() behind the sceneCenter(): \code zFar =
232 distanceToSceneCenter() + zClippingCoefficient()*sceneRadius(); \endcode
233 
234 See the zNear() documentation for details. */
235 CGAL_INLINE_FUNCTION
zFar()236 qreal Camera::zFar() const {
237   return distanceToSceneCenter() + zClippingCoefficient() * sceneRadius();
238 }
239 
240 /*! Sets the vertical fieldOfView() of the Camera (in radians).
241 
242 Note that focusDistance() is set to sceneRadius() / tan(fieldOfView()/2) by this
243 method. */
244 CGAL_INLINE_FUNCTION
setFieldOfView(qreal fov)245 void Camera::setFieldOfView(qreal fov) {
246   fieldOfView_ = fov;
247   projectionMatrixIsUpToDate_ = false;
248 }
249 
250 /*! Defines the Camera type().
251 
252 Changing the camera Type alters the viewport and the objects' sizes can be
253 changed. This method guarantees that the two frustum match in a plane normal to
254 viewDirection(), passing through the pivotPoint().
255 
256 Prefix the type with \c Camera if needed, as in:
257 \code
258 camera()->setType(Camera::ORTHOGRAPHIC);
259 // or even CGAL::qglviewer::Camera::ORTHOGRAPHIC if you do not use namespace
260 \endcode */
261 CGAL_INLINE_FUNCTION
setType(Type type)262 void Camera::setType(Type type) {
263   // make ORTHOGRAPHIC frustum fit PERSPECTIVE (at least in plane normal to
264   // viewDirection(), passing through RAP). Done only when CHANGING type since
265   // orthoCoef_ may have been changed with a 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 
272 /*! Sets the Camera frame().
273 
274 If you want to move the Camera, use setPosition() and setOrientation() or one of
275 the Camera positioning methods (lookAt(), fitSphere(), showEntireScene()...)
276 instead.
277 
278 If you want to save the Camera position(), there's no need to call this method
279 either. Use addKeyFrameToPath() and playPath() instead.
280 
281 This method is actually mainly useful if you derive the ManipulatedCameraFrame
282 class and want to use an instance of your new class to move the Camera.
283 
284 A \c nullptr \p mcf pointer will silently be ignored. The calling method is
285 responsible for deleting the previous frame() pointer if needed in order to
286 prevent memory leaks. */
287 CGAL_INLINE_FUNCTION
setFrame(ManipulatedCameraFrame * const mcf)288 void Camera::setFrame(ManipulatedCameraFrame *const mcf) {
289   if (!mcf)
290     return;
291 
292   if (frame_) {
293     disconnect(frame_, SIGNAL(modified()), this, SLOT(onFrameModified()));
294   }
295 
296   frame_ = mcf;
297   interpolationKfi_->setFrame(frame());
298 
299   connect(frame_, SIGNAL(modified()), this, SLOT(onFrameModified()));
300   onFrameModified();
301 }
302 
303 /*! Returns the distance from the Camera center to sceneCenter(), projected
304   along the Camera Z axis. Used by zNear() and zFar() to optimize the Z range.
305 */
306 CGAL_INLINE_FUNCTION
distanceToSceneCenter()307 qreal Camera::distanceToSceneCenter() const {
308   return fabs((frame()->coordinatesOf(sceneCenter())).z);
309 }
310 
311 /*! Returns the \p halfWidth and \p halfHeight of the Camera orthographic
312  frustum.
313 
314  These values are only valid and used when the Camera is of type()
315  Camera::ORTHOGRAPHIC. They are expressed in OpenGL units and are used by
316  loadProjectionMatrix() to define the projection matrix using: \code glOrtho(
317  -halfWidth, halfWidth, -halfHeight, halfHeight, zNear(), zFar() ) \endcode
318 
319  These values are proportional to the Camera (z projected) distance to the
320  pivotPoint(). When zooming on the object, the Camera is translated forward \e
321  and its frustum is narrowed, making the object appear bigger on screen, as
322  intuitively expected.
323 
324  Overload this method to change this behavior if desired, as is done in the
325  <a href="../examples/standardCamera.html">standardCamera example</a>. */
326 CGAL_INLINE_FUNCTION
getOrthoWidthHeight(GLdouble & halfWidth,GLdouble & halfHeight)327 void Camera::getOrthoWidthHeight(GLdouble &halfWidth,
328                                  GLdouble &halfHeight) const {
329   const qreal dist = orthoCoef_ * fabs(cameraCoordinatesOf(pivotPoint()).z);
330   //#CONNECTION# fitScreenRegion
331   halfWidth = dist * ((aspectRatio() < 1.0) ? 1.0 : aspectRatio());
332   halfHeight = dist * ((aspectRatio() < 1.0) ? 1.0 / aspectRatio() : 1.0);
333 }
334 
335 /*! Computes the projection matrix associated with the Camera.
336 
337  If type() is Camera::PERSPECTIVE, defines a \c GL_PROJECTION matrix similar to
338  what would \c gluPerspective() do using the fieldOfView(), window
339  aspectRatio(), zNear() and zFar() parameters.
340 
341  If type() is Camera::ORTHOGRAPHIC, the projection matrix is as what \c
342  glOrtho() would do. Frustum's width and height are set using
343  getOrthoWidthHeight().
344 
345  Both types use zNear() and zFar() to place clipping planes. These values are
346  determined from sceneRadius() and sceneCenter() so that they best fit the scene
347  size.
348 
349  Use getProjectionMatrix() to retrieve this matrix. Overload
350  loadProjectionMatrix() if you want your Camera to use an exotic projection
351  matrix.
352 
353  \note You must call this method if your Camera is not associated with a
354  CGAL::QGLViewer and is used for offscreen computations (using
355  (un)projectedCoordinatesOf() for instance). loadProjectionMatrix() does it
356  otherwise. */
357 CGAL_INLINE_FUNCTION
computeProjectionMatrix()358 void Camera::computeProjectionMatrix() const {
359   if (projectionMatrixIsUpToDate_)
360     return;
361 
362   const qreal ZNear = zNear();
363   const qreal ZFar = zFar();
364 
365   switch (type()) {
366   case Camera::PERSPECTIVE: {
367     // #CONNECTION# all non null coefficients were set to 0.0 in constructor.
368     const qreal f = 1.0 / tan(fieldOfView() / 2.0);
369     projectionMatrix_[0] = f / aspectRatio();
370     projectionMatrix_[5] = f;
371     projectionMatrix_[10] = (ZNear + ZFar) / (ZNear - ZFar);
372     projectionMatrix_[11] = -1.0;
373     projectionMatrix_[14] = 2.0 * ZNear * ZFar / (ZNear - ZFar);
374     projectionMatrix_[15] = 0.0;
375     // same as gluPerspective( 180.0*fieldOfView()/CGAL_PI, aspectRatio(), zNear(),
376     // zFar() );
377     break;
378   }
379   case Camera::ORTHOGRAPHIC: {
380     GLdouble w, h;
381     getOrthoWidthHeight(w, h);
382     projectionMatrix_[0] = 1.0 / w;
383     projectionMatrix_[5] = 1.0 / h;
384     projectionMatrix_[10] = -2.0 / (ZFar - ZNear);
385     projectionMatrix_[11] = 0.0;
386     projectionMatrix_[14] = -(ZFar + ZNear) / (ZFar - ZNear);
387     projectionMatrix_[15] = 1.0;
388     // same as glOrtho( -w, w, -h, h, zNear(), zFar() );
389     break;
390   }
391   }
392 
393   projectionMatrixIsUpToDate_ = true;
394 }
395 
396 /*! Computes the modelView matrix associated with the Camera's position() and
397  orientation().
398 
399  This matrix converts from the world coordinates system to the Camera
400  coordinates system, so that coordinates can then be projected on screen using
401  the projection matrix (see computeProjectionMatrix()).
402 
403  Use getModelViewMatrix() to retrieve this matrix.
404 
405  \note You must call this method if your Camera is not associated with a
406  CGAL::QGLViewer and is used for offscreen computations (using
407  (un)projectedCoordinatesOf() for instance). loadModelViewMatrix() does it
408  otherwise. */
409 CGAL_INLINE_FUNCTION
computeModelViewMatrix()410 void Camera::computeModelViewMatrix() const {
411   if (modelViewMatrixIsUpToDate_)
412     return;
413 
414   const Quaternion q = frame()->orientation();
415 
416   const qreal q00 = 2.0 * q[0] * q[0];
417   const qreal q11 = 2.0 * q[1] * q[1];
418   const qreal q22 = 2.0 * q[2] * q[2];
419 
420   const qreal q01 = 2.0 * q[0] * q[1];
421   const qreal q02 = 2.0 * q[0] * q[2];
422   const qreal q03 = 2.0 * q[0] * q[3];
423 
424   const qreal q12 = 2.0 * q[1] * q[2];
425   const qreal q13 = 2.0 * q[1] * q[3];
426 
427   const qreal q23 = 2.0 * q[2] * q[3];
428 
429   modelViewMatrix_[0] = 1.0 - q11 - q22;
430   modelViewMatrix_[1] = q01 - q23;
431   modelViewMatrix_[2] = q02 + q13;
432   modelViewMatrix_[3] = 0.0;
433 
434   modelViewMatrix_[4] = q01 + q23;
435   modelViewMatrix_[5] = 1.0 - q22 - q00;
436   modelViewMatrix_[6] = q12 - q03;
437   modelViewMatrix_[7] = 0.0;
438 
439   modelViewMatrix_[8] = q02 - q13;
440   modelViewMatrix_[9] = q12 + q03;
441   modelViewMatrix_[10] = 1.0 - q11 - q00;
442   modelViewMatrix_[11] = 0.0;
443 
444   const Vec t = q.inverseRotate(frame()->position());
445 
446   modelViewMatrix_[12] = -t.x;
447   modelViewMatrix_[13] = -t.y;
448   modelViewMatrix_[14] = -t.z;
449   modelViewMatrix_[15] = 1.0;
450 
451   modelViewMatrixIsUpToDate_ = true;
452 }
453 
454 /*! Loads the OpenGL \c GL_PROJECTION matrix with the Camera projection matrix.
455 
456  The Camera projection matrix is computed using computeProjectionMatrix().
457 
458  When \p reset is \c true (default), the method clears the previous projection
459  matrix by calling \c glLoadIdentity before setting the matrix. Setting \p reset
460  to \c false is useful for \c GL_SELECT mode, to combine the pushed matrix with
461  a picking matrix. See CGAL::QGLViewer::beginSelection() for details.
462 
463  This method is used by CGAL::QGLViewer::preDraw() (called before user's
464  CGAL::QGLViewer::draw() method) to set the \c GL_PROJECTION matrix according to the
465  viewer's CGAL::QGLViewer::camera() settings.
466 
467  Use getProjectionMatrix() to retrieve this matrix. Overload this method if you
468  want your Camera to use an exotic projection matrix. See also
469  loadModelViewMatrix().
470 
471  \attention \c glMatrixMode is set to \c GL_PROJECTION.
472 
473  \attention If you use several OpenGL contexts and bypass the Qt main refresh
474  loop, you should call QOpenGLWidget::makeCurrent() before this method in order
475  to activate the right OpenGL context. */
476 CGAL_INLINE_FUNCTION
loadProjectionMatrix(bool)477 void Camera::loadProjectionMatrix(bool ) const {
478   // WARNING: makeCurrent must be called by every calling method
479   computeProjectionMatrix();
480 }
481 
482 /*! Loads the OpenGL \c GL_MODELVIEW matrix with the modelView matrix
483  corresponding to the Camera.
484 
485  Calls computeModelViewMatrix() to compute the Camera's modelView matrix.
486 
487  This method is used by CGAL::QGLViewer::preDraw() (called before user's
488  CGAL::QGLViewer::draw() method) to set the \c GL_MODELVIEW matrix according to the
489  viewer's CGAL::QGLViewer::camera() position() and orientation().
490 
491  As a result, the vertices used in CGAL::QGLViewer::draw() can be defined in the so
492  called world coordinate system. They are multiplied by this matrix to get
493  converted to the Camera coordinate system, before getting projected using the
494  \c GL_PROJECTION matrix (see loadProjectionMatrix()).
495 
496  When \p reset is \c true (default), the method loads (overwrites) the \c
497  GL_MODELVIEW matrix. Setting \p reset to \c false simply calls \c glMultMatrixd
498  (might be useful for some applications).
499 
500  Overload this method or simply call glLoadMatrixd() at the beginning of
501  CGAL::QGLViewer::draw() if you want your Camera to use an exotic modelView matrix.
502  See also loadProjectionMatrix().
503 
504  getModelViewMatrix() returns the 4x4 modelView matrix.
505 
506  \attention glMatrixMode is set to \c GL_MODELVIEW
507 
508  \attention If you use several OpenGL contexts and bypass the Qt main refresh
509  loop, you should call QOpenGLWidget::makeCurrent() before this method in order
510  to activate the right OpenGL context. */
511 CGAL_INLINE_FUNCTION
loadModelViewMatrix(bool)512 void Camera::loadModelViewMatrix(bool ) const {
513   // WARNING: makeCurrent must be called by every calling method
514   computeModelViewMatrix();
515 }
516 
517 
518 
519 
520 /*! Fills \p m with the Camera projection matrix values.
521 
522  Based on computeProjectionMatrix() to make sure the Camera projection matrix is
523  up to date.
524 
525  This matrix only reflects the Camera's internal parameters and it may differ
526  from the \c GL_PROJECTION matrix retrieved using \c
527  glGetDoublev(GL_PROJECTION_MATRIX, m). It actually represents the state of the
528  \c GL_PROJECTION after CGAL::QGLViewer::preDraw(), at the beginning of
529  CGAL::QGLViewer::draw(). If you modified the \c GL_PROJECTION matrix (for instance
530  using CGAL::QGLViewer::startScreenCoordinatesSystem()), the two results differ.
531 
532  The result is an OpenGL 4x4 matrix, which is given in \e column-major order
533  (see \c glMultMatrix man page for details).
534 
535  See also getModelViewMatrix() and setFromProjectionMatrix(). */
536 CGAL_INLINE_FUNCTION
getProjectionMatrix(GLdouble m[16])537 void Camera::getProjectionMatrix(GLdouble m[16]) const {
538   computeProjectionMatrix();
539   for (unsigned short i = 0; i < 16; ++i)
540     m[i] = projectionMatrix_[i];
541 }
542 
543 /*! Overloaded getProjectionMatrix(GLdouble m[16]) method using a \c GLfloat
544  * array instead. */
545 CGAL_INLINE_FUNCTION
getProjectionMatrix(GLfloat m[16])546 void Camera::getProjectionMatrix(GLfloat m[16]) const {
547   static GLdouble mat[16];
548   getProjectionMatrix(mat);
549   for (unsigned short i = 0; i < 16; ++i)
550     m[i] = float(mat[i]);
551 }
552 
553 /*! Fills \p m with the Camera modelView matrix values.
554 
555  First calls computeModelViewMatrix() to define the Camera modelView matrix.
556 
557  Note that this matrix may \e not be the one you would get from a \c
558  glGetDoublev(GL_MODELVIEW_MATRIX, m). It actually represents the state of the
559  \c GL_MODELVIEW after CGAL::QGLViewer::preDraw(), at the \e beginning of
560  CGAL::QGLViewer::draw(). It converts from the world to the Camera coordinate system.
561  As soon as you modify the \c GL_MODELVIEW in your CGAL::QGLViewer::draw() method
562  (using glTranslate, glRotate... or similar methods), the two matrices differ.
563 
564  The result is an OpenGL 4x4 matrix, which is given in \e column-major order
565  (see \c glMultMatrix man page for details).
566 
567  See also getProjectionMatrix() and setFromModelViewMatrix(). */
568 CGAL_INLINE_FUNCTION
getModelViewMatrix(GLdouble m[16])569 void Camera::getModelViewMatrix(GLdouble m[16]) const {
570   // May not be needed, but easier like this.
571   computeModelViewMatrix();
572   for (unsigned short i = 0; i < 16; ++i)
573     m[i] = modelViewMatrix_[i];
574 }
575 
576 /*! Overloaded getModelViewMatrix(GLdouble m[16]) method using a \c GLfloat
577  * array instead. */
578 CGAL_INLINE_FUNCTION
getModelViewMatrix(GLfloat m[16])579 void Camera::getModelViewMatrix(GLfloat m[16]) const {
580   static GLdouble mat[16];
581   getModelViewMatrix(mat);
582   for (unsigned short i = 0; i < 16; ++i)
583     m[i] = float(mat[i]);
584 }
585 
586 /*! Fills \p m with the product of the ModelView and Projection matrices.
587 
588   Calls getModelViewMatrix() and getProjectionMatrix() and then fills \p m with
589   the product of these two matrices. */
590 CGAL_INLINE_FUNCTION
getModelViewProjectionMatrix(GLdouble m[16])591 void Camera::getModelViewProjectionMatrix(GLdouble m[16]) const {
592   GLdouble mv[16];
593   GLdouble proj[16];
594   getModelViewMatrix(mv);
595   getProjectionMatrix(proj);
596 
597   for (unsigned short i = 0; i < 4; ++i) {
598     for (unsigned short j = 0; j < 4; ++j) {
599       qreal sum = 0.0;
600       for (unsigned short k = 0; k < 4; ++k)
601         sum += proj[i + 4 * k] * mv[k + 4 * j];
602       m[i + 4 * j] = sum;
603     }
604   }
605 }
606 
607 /*! Overloaded getModelViewProjectionMatrix(GLdouble m[16]) method using a \c
608  * GLfloat array instead. */
609 CGAL_INLINE_FUNCTION
getModelViewProjectionMatrix(GLfloat m[16])610 void Camera::getModelViewProjectionMatrix(GLfloat m[16]) const {
611   static GLdouble mat[16];
612   getModelViewProjectionMatrix(mat);
613   for (unsigned short i = 0; i < 16; ++i)
614     m[i] = float(mat[i]);
615 }
616 
617 /*! Sets the sceneRadius() value. Negative values are ignored.
618 
619 \attention This methods also sets focusDistance() to sceneRadius() /
620 tan(fieldOfView()/2) and flySpeed() to 1% of sceneRadius(). */
621 CGAL_INLINE_FUNCTION
setSceneRadius(qreal radius)622 void Camera::setSceneRadius(qreal radius) {
623   if (radius <= 0.0) {
624     qWarning("Scene radius must be positive - Ignoring value");
625     return;
626   }
627 
628   sceneRadius_ = radius;
629   projectionMatrixIsUpToDate_ = false;
630 
631   frame()->setFlySpeed(0.01 * sceneRadius());
632 }
633 
634 /*! Similar to setSceneRadius() and setSceneCenter(), but the scene limits are
635   defined by a (world axis aligned) bounding box. */
636 CGAL_INLINE_FUNCTION
setSceneBoundingBox(const Vec & min,const Vec & max)637 void Camera::setSceneBoundingBox(const Vec &min, const Vec &max) {
638   setSceneCenter((min + max) / 2.0);
639   setSceneRadius(0.5 * (max - min).norm());
640 }
641 
642 /*! Sets the sceneCenter().
643 
644  \attention This method also sets the pivotPoint() to sceneCenter(). */
645 CGAL_INLINE_FUNCTION
setSceneCenter(const Vec & center)646 void Camera::setSceneCenter(const Vec &center) {
647   sceneCenter_ = center;
648   setPivotPoint(sceneCenter());
649   projectionMatrixIsUpToDate_ = false;
650 }
651 
652 /*! setSceneCenter() to the result of pointUnderPixel(\p pixel).
653 
654   Returns \c true if a pointUnderPixel() was found and sceneCenter() was
655   actually changed.
656 
657   See also setPivotPointFromPixel(). See the pointUnderPixel() documentation. */
658 CGAL_INLINE_FUNCTION
setSceneCenterFromPixel(const QPoint & pixel)659 bool Camera::setSceneCenterFromPixel(const QPoint &pixel) {
660   bool found;
661   Vec point = pointUnderPixel(pixel, found);
662   if (found)
663     setSceneCenter(point);
664   return found;
665 }
666 
667 /*! Changes the pivotPoint() to \p point (defined in the world coordinate
668  * system). */
669 CGAL_INLINE_FUNCTION
setPivotPoint(const Vec & point)670 void Camera::setPivotPoint(const Vec &point) {
671   const qreal prevDist = fabs(cameraCoordinatesOf(pivotPoint()).z);
672 
673   // If frame's RAP is set directly, projectionMatrixIsUpToDate_ should also be
674   // set to false to ensure proper recomputation of the ORTHO projection matrix.
675   frame()->setPivotPoint(point);
676 
677   // orthoCoef_ is used to compensate for changes of the pivotPoint, so that the
678   // image does not change when the pivotPoint is changed in ORTHOGRAPHIC mode.
679   const qreal newDist = fabs(cameraCoordinatesOf(pivotPoint()).z);
680   // Prevents division by zero when rap is set to camera position
681   if ((prevDist > 1E-9) && (newDist > 1E-9))
682     orthoCoef_ *= prevDist / newDist;
683   projectionMatrixIsUpToDate_ = false;
684 }
685 
686 /*! The pivotPoint() is set to the point located under \p pixel on screen.
687 
688 Returns \c true if a pointUnderPixel() was found. If no point was found under \p
689 pixel, the pivotPoint() is left unchanged.
690 
691 \p pixel is expressed in Qt format (origin in the upper left corner of the
692 window). See pointUnderPixel().
693 
694 See also setSceneCenterFromPixel(). */
695 CGAL_INLINE_FUNCTION
setPivotPointFromPixel(const QPoint & pixel)696 bool Camera::setPivotPointFromPixel(const QPoint &pixel) {
697   bool found;
698   Vec point = pointUnderPixel(pixel, found);
699   if (found)
700     setPivotPoint(point);
701   return found;
702 }
703 
704 /*! Returns the ratio between pixel and OpenGL units at \p position.
705 
706  A line of \c n * pixelGLRatio() OpenGL units, located at \p position in the
707  world coordinates system, will be projected with a length of \c n pixels on
708  screen.
709 
710  Use this method to scale objects so that they have a constant pixel size on
711  screen. The following code will draw a 20 pixel line, starting at sceneCenter()
712  and always directed along the screen vertical direction: \code
713  glBegin(GL_LINES);
714  glVertex3fv(sceneCenter());
715  glVertex3fv(sceneCenter() + 20 * pixelGLRatio(sceneCenter()) *
716  camera()->upVector()); glEnd(); \endcode */
717 CGAL_INLINE_FUNCTION
pixelGLRatio(const Vec & position)718 qreal Camera::pixelGLRatio(const Vec &position) const {
719   switch (type()) {
720   case Camera::PERSPECTIVE:
721     return 2.0 * fabs((frame()->coordinatesOf(position)).z) *
722            tan(fieldOfView() / 2.0) / screenHeight();
723   case Camera::ORTHOGRAPHIC: {
724     GLdouble w, h;
725     getOrthoWidthHeight(w, h);
726     return 2.0 * h / screenHeight();
727   }
728   }
729   // Bad compilers complain
730   return 1.0;
731 }
732 
733 /*! Changes the Camera fieldOfView() so that the entire scene (defined by
734  CGAL::QGLViewer::sceneCenter() and CGAL::QGLViewer::sceneRadius()) is visible from the
735  Camera position().
736 
737  The position() and orientation() of the Camera are not modified and you first
738  have to orientate the Camera in order to actually see the scene (see lookAt(),
739  showEntireScene() or fitSphere()).
740 
741  This method is especially useful for \e shadow \e maps computation. Use the
742  Camera positioning tools (setPosition(), lookAt()) to position a Camera at the
743  light position. Then use this method to define the fieldOfView() so that the
744  shadow map resolution is optimally used: \code
745  // The light camera needs size hints in order to optimize its fieldOfView
746  lightCamera->setSceneRadius(sceneRadius());
747  lightCamera->setSceneCenter(sceneCenter());
748 
749  // Place the light camera.
750  lightCamera->setPosition(lightFrame->position());
751  lightCamera->lookAt(sceneCenter());
752  lightCamera->setFOVToFitScene();
753  \endcode
754 
755  See the (soon available) shadowMap contribution example for a practical
756  implementation.
757 
758  \attention The fieldOfView() is clamped to CGAL_PI/2.0. This happens when the
759  Camera is at a distance lower than sqrt(2.0) * sceneRadius() from the
760  sceneCenter(). It optimizes the shadow map resolution, although it may miss
761  some parts of the scene. */
762 CGAL_INLINE_FUNCTION
setFOVToFitScene()763 void Camera::setFOVToFitScene() {
764   if (distanceToSceneCenter() > sqrt(2.0) * sceneRadius())
765     setFieldOfView(2.0 * asin(sceneRadius() / distanceToSceneCenter()));
766   else
767     setFieldOfView(CGAL_PI / 2.0);
768 }
769 
770 /*! Makes the Camera smoothly zoom on the pointUnderPixel() \p pixel.
771 
772  Nothing happens if no pointUnderPixel() is found. Otherwise a
773  KeyFrameInterpolator is created that animates the Camera on a one second path
774  that brings the Camera closer to the point under \p pixel.
775 
776  See also interpolateToFitScene(). */
777 CGAL_INLINE_FUNCTION
interpolateToZoomOnPixel(const QPoint & pixel)778 void Camera::interpolateToZoomOnPixel(const QPoint &pixel) {
779   const qreal coef = 0.1;
780 
781   bool found;
782   Vec target = pointUnderPixel(pixel, found);
783 
784   if (!found)
785     return;
786 
787   if (interpolationKfi_->interpolationIsStarted())
788     interpolationKfi_->stopInterpolation();
789 
790   interpolationKfi_->deletePath();
791   interpolationKfi_->addKeyFrame(*(frame()));
792 
793   interpolationKfi_->addKeyFrame(
794       Frame(0.3 * frame()->position() + 0.7 * target, frame()->orientation()),
795       0.4);
796 
797   // Small hack: attach a temporary frame to take advantage of lookAt without
798   // modifying frame
799   static ManipulatedCameraFrame *tempFrame = new ManipulatedCameraFrame();
800   ManipulatedCameraFrame *const originalFrame = frame();
801   tempFrame->setPosition(coef * frame()->position() + (1.0 - coef) * target);
802   tempFrame->setOrientation(frame()->orientation());
803   setFrame(tempFrame);
804   lookAt(target);
805   setFrame(originalFrame);
806 
807   interpolationKfi_->addKeyFrame(*(tempFrame), 1.0);
808 
809   interpolationKfi_->startInterpolation();
810 }
811 
812 /*! Interpolates the Camera on a one second KeyFrameInterpolator path so that
813  the entire scene fits the screen at the end.
814 
815  The scene is defined by its sceneCenter() and its sceneRadius(). See
816  showEntireScene().
817 
818  The orientation() of the Camera is not modified. See also
819  interpolateToZoomOnPixel(). */
820 CGAL_INLINE_FUNCTION
interpolateToFitScene()821 void Camera::interpolateToFitScene() {
822   if (interpolationKfi_->interpolationIsStarted())
823     interpolationKfi_->stopInterpolation();
824 
825   interpolationKfi_->deletePath();
826   interpolationKfi_->addKeyFrame(*(frame()));
827 
828   // Small hack:  attach a temporary frame to take advantage of lookAt without
829   // modifying frame
830   static ManipulatedCameraFrame *tempFrame = new ManipulatedCameraFrame();
831   ManipulatedCameraFrame *const originalFrame = frame();
832   tempFrame->setPosition(frame()->position());
833   tempFrame->setOrientation(frame()->orientation());
834   setFrame(tempFrame);
835   showEntireScene();
836   setFrame(originalFrame);
837 
838   interpolationKfi_->addKeyFrame(*(tempFrame));
839 
840   interpolationKfi_->startInterpolation();
841 }
842 
843 /*! Smoothly interpolates the Camera on a KeyFrameInterpolator path so that it
844   goes to \p fr.
845 
846   \p fr is expressed in world coordinates. \p duration tunes the interpolation
847   speed (default is 1 second).
848 
849   See also interpolateToFitScene() and interpolateToZoomOnPixel(). */
850 CGAL_INLINE_FUNCTION
interpolateTo(const Frame & fr,qreal duration)851 void Camera::interpolateTo(const Frame &fr, qreal duration) {
852   if (interpolationKfi_->interpolationIsStarted())
853     interpolationKfi_->stopInterpolation();
854 
855   interpolationKfi_->deletePath();
856   interpolationKfi_->addKeyFrame(*(frame()));
857   interpolationKfi_->addKeyFrame(fr, duration);
858 
859   interpolationKfi_->startInterpolation();
860 }
861 
862 /*! Returns the coordinates of the 3D point located at pixel (x,y) on screen.
863 
864  Calls a \c glReadPixel to get the pixel depth and applies an
865  unprojectedCoordinatesOf() to the result. \p found indicates whether a point
866  was found or not (i.e. background pixel, result's depth is zFar() in that
867  case).
868 
869  \p x and \p y are expressed in pixel units with an origin in the upper left
870  corner. Use screenHeight() - y to convert to OpenGL standard.
871 
872  \attention This method assumes that a GL context is available, and that its
873  content was drawn using the Camera (i.e. using its projection and modelview
874  matrices). This method hence cannot be used for offscreen Camera computations.
875  Use cameraCoordinatesOf() and worldCoordinatesOf() to perform similar
876  operations in that case.
877 
878  \note The precision of the z-Buffer highly depends on how the zNear() and
879  zFar() values are fitted to your scene. Loose boundaries will result in
880  imprecision along the viewing direction. */
881 CGAL_INLINE_FUNCTION
pointUnderPixel(const QPoint & pixel,bool & found)882 Vec Camera::pointUnderPixel(const QPoint &pixel, bool &found) const {
883   float depth = 2.0;
884   // Qt uses upper corner for its origin while GL uses the lower corner.
885   if(auto p = dynamic_cast<QOpenGLFunctions*>(parent()))
886   {
887     p->glReadPixels(pixel.x(), screenHeight() - 1 - pixel.y(), 1, 1,
888                     GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
889   }
890   found = depth < 1.0;
891   Vec point(pixel.x(), pixel.y(), depth);
892   point = unprojectedCoordinatesOf(point);
893   return point;
894 }
895 
896 /*! Moves the Camera so that the entire scene is visible.
897 
898  Calls fitSphere() on a sphere defined by sceneCenter() and
899  sceneRadius(), and resets the default FOV.
900 
901  You will typically use this method in CGAL::QGLViewer::init() after you defined a new
902  sceneRadius(). */
903 CGAL_INLINE_FUNCTION
showEntireScene()904 void Camera::showEntireScene()
905 {
906   setFieldOfView(CGAL_PI/4.0);
907   fitSphere(sceneCenter(), sceneRadius());
908 }
909 
910 /*! Moves the Camera so that its sceneCenter() is projected on the center of the
911  window. The orientation() and fieldOfView() are unchanged.
912 
913  Simply projects the current position on a line passing through sceneCenter().
914  See also showEntireScene().*/
915 CGAL_INLINE_FUNCTION
centerScene()916 void Camera::centerScene() {
917   frame()->projectOnLine(sceneCenter(), viewDirection());
918 }
919 
920 /*! Sets the Camera orientation(), so that it looks at point \p target (defined
921  in the world coordinate system).
922 
923  The Camera position() is not modified. Simply setViewDirection().
924 
925  See also setUpVector(), setOrientation(), showEntireScene(), fitSphere() and
926  fitBoundingBox(). */
927 CGAL_INLINE_FUNCTION
lookAt(const Vec & target)928 void Camera::lookAt(const Vec &target) {
929   setViewDirection(target - position());
930 }
931 
932 /*! Moves the Camera so that the sphere defined by (\p center, \p radius) is
933  visible and fits in the frustum.
934 
935  The Camera is simply translated to center the sphere in the screen and make it
936  fit the frustum. Its orientation() and its fieldOfView() are unchanged.
937 
938  You should therefore orientate the Camera before you call this method. See
939  lookAt(), setOrientation() and setUpVector(). */
940 CGAL_INLINE_FUNCTION
fitSphere(const Vec & center,qreal radius)941 void Camera::fitSphere(const Vec &center, qreal radius) {
942   qreal distance = 0.0;
943   switch (type()) {
944   case Camera::PERSPECTIVE: {
945     const qreal yview = radius / sin(fieldOfView() / 2.0);
946     const qreal xview = radius / sin(horizontalFieldOfView() / 2.0);
947     distance = qMax(xview, yview);
948     break;
949   }
950   case Camera::ORTHOGRAPHIC: {
951     distance =
952         ((center - pivotPoint()) * viewDirection()) + (radius / orthoCoef_);
953     break;
954   }
955   }
956   Vec newPos(center - distance * viewDirection());
957   frame()->setPositionWithConstraint(newPos);
958 }
959 
960 /*! Moves the Camera so that the (world axis aligned) bounding box (\p min, \p
961   max) is entirely visible, using fitSphere(). */
962 CGAL_INLINE_FUNCTION
fitBoundingBox(const Vec & min,const Vec & max)963 void Camera::fitBoundingBox(const Vec &min, const Vec &max) {
964   qreal diameter = qMax(fabs(max[1] - min[1]), fabs(max[0] - min[0]));
965   diameter = qMax(fabs(max[2] - min[2]), diameter);
966   fitSphere(0.5 * (min + max), 0.5 * diameter);
967 }
968 
969 /*! Moves the Camera so that the rectangular screen region defined by \p
970   rectangle (pixel units, with origin in the upper left corner) fits the screen.
971 
972   The Camera is translated (its orientation() is unchanged) so that \p rectangle
973   is entirely visible. Since the pixel coordinates only define a \e frustum in
974   3D, it's the intersection of this frustum with a plane (orthogonal to the
975   viewDirection() and passing through the sceneCenter()) that is used to define
976   the 3D rectangle that is eventually fitted. */
977 CGAL_INLINE_FUNCTION
fitScreenRegion(const QRect & rectangle)978 void Camera::fitScreenRegion(const QRect &rectangle) {
979   const Vec vd = viewDirection();
980   const qreal distToPlane = distanceToSceneCenter();
981   const QPoint center = rectangle.center();
982 
983   Vec orig, dir;
984   convertClickToLine(center, orig, dir);
985   Vec newCenter = orig + distToPlane / (dir * vd) * dir;
986 
987   convertClickToLine(QPoint(rectangle.x(), center.y()), orig, dir);
988   const Vec pointX = orig + distToPlane / (dir * vd) * dir;
989 
990   convertClickToLine(QPoint(center.x(), rectangle.y()), orig, dir);
991   const Vec pointY = orig + distToPlane / (dir * vd) * dir;
992 
993   qreal distance = 0.0;
994   switch (type()) {
995   case Camera::PERSPECTIVE: {
996     const qreal distX =
997         (pointX - newCenter).norm() / sin(horizontalFieldOfView() / 2.0);
998     const qreal distY = (pointY - newCenter).norm() / sin(fieldOfView() / 2.0);
999     distance = qMax(distX, distY);
1000     break;
1001   }
1002   case Camera::ORTHOGRAPHIC: {
1003     const qreal dist = ((newCenter - pivotPoint()) * vd);
1004     //#CONNECTION# getOrthoWidthHeight
1005     const qreal distX = (pointX - newCenter).norm() / orthoCoef_ /
1006                         ((aspectRatio() < 1.0) ? 1.0 : aspectRatio());
1007     const qreal distY = (pointY - newCenter).norm() / orthoCoef_ /
1008                         ((aspectRatio() < 1.0) ? 1.0 / aspectRatio() : 1.0);
1009     distance = dist + qMax(distX, distY);
1010     break;
1011   }
1012   }
1013 
1014   Vec newPos(newCenter - distance * vd);
1015   frame()->setPositionWithConstraint(newPos);
1016 }
1017 
1018 /*! Rotates the Camera so that its upVector() becomes \p up (defined in the
1019  world coordinate system).
1020 
1021  The Camera is rotated around an axis orthogonal to \p up and to the current
1022  upVector() direction. Use this method in order to define the Camera horizontal
1023  plane.
1024 
1025  When \p noMove is set to \c false, the orientation modification is compensated
1026  by a translation, so that the pivotPoint() stays projected at the same position
1027  on screen. This is especially useful when the Camera is used as an observer of
1028  the scene (default mouse binding).
1029 
1030  When \p noMove is \c true (default), the Camera position() is left unchanged,
1031  which is an intuitive behavior when the Camera is in a walkthrough fly mode
1032  (see the CGAL::QGLViewer::MOVE_FORWARD and CGAL::QGLViewer::MOVE_BACKWARD
1033  CGAL::QGLViewer::MouseAction).
1034 
1035  The frame()'s ManipulatedCameraFrame::sceneUpVector() is set accordingly.
1036 
1037  See also setViewDirection(), lookAt() and setOrientation(). */
1038 CGAL_INLINE_FUNCTION
setUpVector(const Vec & up,bool noMove)1039 void Camera::setUpVector(const Vec &up, bool noMove) {
1040   Quaternion q(Vec(0.0, 1.0, 0.0), frame()->transformOf(up));
1041 
1042   if (!noMove)
1043     frame()->setPosition(pivotPoint() -
1044                          (frame()->orientation() * q)
1045                              .rotate(frame()->coordinatesOf(pivotPoint())));
1046 
1047   frame()->rotate(q);
1048 
1049   // Useful in fly mode to keep the horizontal direction.
1050   frame()->updateSceneUpVector();
1051 }
1052 
1053 /*! Sets the orientation() of the Camera using polar coordinates.
1054 
1055  \p theta rotates the Camera around its Y axis, and \e then \p phi rotates it
1056  around its X axis. The polar coordinates are defined in the world coordinates
1057  system: \p theta = \p phi = 0 means that the Camera is directed towards the
1058  world Z axis. Both angles are expressed in radians.
1059 
1060  See also setUpVector(). The position() of the Camera is unchanged, you may want
1061  to call showEntireScene() after this method to move the Camera.
1062 
1063  This method can be useful to create Quicktime VR panoramic sequences, see the
1064  CGAL::QGLViewer::saveSnapshot() documentation for details. */
1065 CGAL_INLINE_FUNCTION
setOrientation(qreal theta,qreal phi)1066 void Camera::setOrientation(qreal theta, qreal phi) {
1067   Vec axis(0.0, 1.0, 0.0);
1068   const Quaternion rot1(axis, theta);
1069   axis = Vec(-cos(theta), 0.0, sin(theta));
1070   const Quaternion rot2(axis, phi);
1071   setOrientation(rot1 * rot2);
1072 }
1073 
1074 /*! Sets the Camera orientation(), defined in the world coordinate system. */
1075 CGAL_INLINE_FUNCTION
setOrientation(const Quaternion & q)1076 void Camera::setOrientation(const Quaternion &q) {
1077   frame()->setOrientation(q);
1078   frame()->updateSceneUpVector();
1079 }
1080 
1081 /*! Rotates the Camera so that its viewDirection() is \p direction (defined in
1082  the world coordinate system).
1083 
1084  The Camera position() is not modified. The Camera is rotated so that the
1085  horizon (defined by its upVector()) is preserved. See also lookAt() and
1086  setUpVector(). */
1087 CGAL_INLINE_FUNCTION
setViewDirection(const Vec & direction)1088 void Camera::setViewDirection(const Vec &direction) {
1089   if (direction.squaredNorm() < 1E-10)
1090     return;
1091 
1092   Vec xAxis = direction ^ upVector();
1093   if (xAxis.squaredNorm() < 1E-10) {
1094     // target is aligned with upVector, this means a rotation around X axis
1095     // X axis is then unchanged, let's keep it !
1096     xAxis = frame()->inverseTransformOf(Vec(1.0, 0.0, 0.0));
1097   }
1098 
1099   Quaternion q;
1100   q.setFromRotatedBasis(xAxis, xAxis ^ direction, -direction);
1101   frame()->setOrientationWithConstraint(q);
1102 }
1103 
1104 // Compute a 3 by 3 determinant.
det(qreal m00,qreal m01,qreal m02,qreal m10,qreal m11,qreal m12,qreal m20,qreal m21,qreal m22)1105 static qreal det(qreal m00, qreal m01, qreal m02, qreal m10, qreal m11,
1106                  qreal m12, qreal m20, qreal m21, qreal m22) {
1107   return m00 * m11 * m22 + m01 * m12 * m20 + m02 * m10 * m21 - m20 * m11 * m02 -
1108          m10 * m01 * m22 - m00 * m21 * m12;
1109 }
1110 
1111 // Computes the index of element [i][j] in a \c qreal matrix[3][4].
ind(unsigned int i,unsigned int j)1112 static inline unsigned int ind(unsigned int i, unsigned int j) {
1113   return (i * 4 + j);
1114 }
1115 
1116 /*! Returns the Camera position (the eye), defined in the world coordinate
1117 system.
1118 
1119 Use setPosition() to set the Camera position. Other convenient methods are
1120 showEntireScene() or fitSphere(). Actually returns \c frame()->position().
1121 
1122 This position corresponds to the projection center of a Camera::PERSPECTIVE
1123 Camera. It is not located in the image plane, which is at a zNear() distance
1124 ahead. */
1125 CGAL_INLINE_FUNCTION
position()1126 Vec Camera::position() const { return frame()->position(); }
1127 
1128 /*! Returns the normalized up vector of the Camera, defined in the world
1129 coordinate system.
1130 
1131 Set using setUpVector() or setOrientation(). It is orthogonal to viewDirection()
1132 and to rightVector().
1133 
1134 It corresponds to the Y axis of the associated frame() (actually returns
1135 frame()->inverseTransformOf(Vec(0.0, 1.0, 0.0)) ). */
1136 CGAL_INLINE_FUNCTION
upVector()1137 Vec Camera::upVector() const {
1138   return frame()->inverseTransformOf(Vec(0.0, 1.0, 0.0));
1139 }
1140 /*! Returns the normalized view direction of the Camera, defined in the world
1141 coordinate system.
1142 
1143 Change this value using setViewDirection(), lookAt() or setOrientation(). It is
1144 orthogonal to upVector() and to rightVector().
1145 
1146 This corresponds to the negative Z axis of the frame() (
1147 frame()->inverseTransformOf(Vec(0.0, 0.0, -1.0)) ). */
1148 CGAL_INLINE_FUNCTION
viewDirection()1149 Vec Camera::viewDirection() const {
1150   return frame()->inverseTransformOf(Vec(0.0, 0.0, -1.0));
1151 }
1152 
1153 /*! Returns the normalized right vector of the Camera, defined in the world
1154 coordinate system.
1155 
1156 This vector lies in the Camera horizontal plane, directed along the X axis
1157 (orthogonal to upVector() and to viewDirection()). Set using setUpVector(),
1158 lookAt() or setOrientation().
1159 
1160 Simply returns frame()->inverseTransformOf(Vec(1.0, 0.0, 0.0)). */
1161 CGAL_INLINE_FUNCTION
rightVector()1162 Vec Camera::rightVector() const {
1163   return frame()->inverseTransformOf(Vec(1.0, 0.0, 0.0));
1164 }
1165 
1166 /*! Returns the Camera orientation, defined in the world coordinate system.
1167 
1168 Actually returns \c frame()->orientation(). Use setOrientation(), setUpVector()
1169 or lookAt() to set the Camera orientation. */
1170 CGAL_INLINE_FUNCTION
orientation()1171 Quaternion Camera::orientation() const { return frame()->orientation(); }
1172 
1173 /*! Sets the Camera position() (the eye), defined in the world coordinate
1174  * system. */
1175 CGAL_INLINE_FUNCTION
setPosition(const Vec & pos)1176 void Camera::setPosition(const Vec &pos) { frame()->setPosition(pos); }
1177 
1178 /*! Returns the Camera frame coordinates of a point \p src defined in world
1179 coordinates.
1180 
1181 worldCoordinatesOf() performs the inverse transformation.
1182 
1183 Note that the point coordinates are simply converted in a different coordinate
1184 system. They are not projected on screen. Use projectedCoordinatesOf() for that.
1185 */
1186 CGAL_INLINE_FUNCTION
cameraCoordinatesOf(const Vec & src)1187 Vec Camera::cameraCoordinatesOf(const Vec &src) const {
1188   return frame()->coordinatesOf(src);
1189 }
1190 
1191 /*! Returns the world coordinates of the point whose position \p src is defined
1192 in the Camera coordinate system.
1193 
1194 cameraCoordinatesOf() performs the inverse transformation. */
1195 CGAL_INLINE_FUNCTION
worldCoordinatesOf(const Vec & src)1196 Vec Camera::worldCoordinatesOf(const Vec &src) const {
1197   return frame()->inverseCoordinatesOf(src);
1198 }
1199 
1200 /*! Returns the fly speed of the Camera.
1201 
1202 Simply returns frame()->flySpeed(). See the ManipulatedCameraFrame::flySpeed()
1203 documentation. This value is only meaningful when the MouseAction bindings is
1204 CGAL::QGLViewer::MOVE_FORWARD or CGAL::QGLViewer::MOVE_BACKWARD.
1205 
1206 Set to 1% of the sceneRadius() by setSceneRadius(). See also setFlySpeed(). */
1207 CGAL_INLINE_FUNCTION
flySpeed()1208 qreal Camera::flySpeed() const { return frame()->flySpeed(); }
1209 
1210 /*! Sets the Camera flySpeed().
1211 
1212 \attention This value is modified by setSceneRadius(). */
1213 CGAL_INLINE_FUNCTION
setFlySpeed(qreal speed)1214 void Camera::setFlySpeed(qreal speed) { frame()->setFlySpeed(speed); }
1215 
1216 /*! The point the Camera pivots around with the CGAL::QGLViewer::ROTATE mouse binding.
1217 Defined in world coordinate system.
1218 
1219 Default value is the sceneCenter().
1220 
1221 \attention setSceneCenter() changes this value. */
1222 CGAL_INLINE_FUNCTION
pivotPoint()1223 Vec Camera::pivotPoint() const { return frame()->pivotPoint(); }
1224 
1225 /*! Sets the Camera's position() and orientation() from an OpenGL ModelView
1226 matrix.
1227 
1228 This enables a Camera initialisation from an other OpenGL application. \p
1229 modelView is a 16 GLdouble vector representing a valid OpenGL ModelView matrix,
1230 such as one can get using: \code GLdouble mvm[16];
1231 glGetDoublev(GL_MODELVIEW_MATRIX, mvm);
1232 myCamera->setFromModelViewMatrix(mvm);
1233 \endcode
1234 
1235 After this method has been called, getModelViewMatrix() returns a matrix
1236 equivalent to \p modelView.
1237 
1238 Only the orientation() and position() of the Camera are modified.
1239 
1240 \note If you defined your matrix as \c GLdouble \c mvm[4][4], pass \c
1241 &(mvm[0][0]) as a parameter. */
1242 CGAL_INLINE_FUNCTION
setFromModelViewMatrix(const GLdouble * const modelViewMatrix)1243 void Camera::setFromModelViewMatrix(const GLdouble *const modelViewMatrix) {
1244   // Get upper left (rotation) matrix
1245   qreal upperLeft[3][3];
1246   for (int i = 0; i < 3; ++i)
1247     for (int j = 0; j < 3; ++j)
1248       upperLeft[i][j] = modelViewMatrix[i * 4 + j];
1249 
1250   // Transform upperLeft into the associated Quaternion
1251   Quaternion q;
1252   q.setFromRotationMatrix(upperLeft);
1253 
1254   setOrientation(q);
1255   setPosition(-q.rotate(
1256       Vec(modelViewMatrix[12], modelViewMatrix[13], modelViewMatrix[14])));
1257 }
1258 
1259 /*! Defines the Camera position(), orientation() and fieldOfView() from a
1260  projection matrix.
1261 
1262  \p matrix has to be given in the format used by vision algorithm. It has 3
1263  lines and 4 columns. It transforms a point from the world homogeneous
1264  coordinate system (4 coordinates: \c sx, \c sy, \c sz and \c s) into a point in
1265  the screen homogeneous coordinate system (3 coordinates: \c sx, \c sy, and \c
1266  s, where \c x and \c y are the pixel coordinates on the screen).
1267 
1268  Its three lines correspond to the homogeneous coordinates of the normals to the
1269  planes x=0, y=0 and z=0, defined in the Camera coordinate system.
1270 
1271  The elements of the matrix are ordered in line major order: you can call \c
1272  setFromProjectionMatrix(&(matrix[0][0])) if you defined your matrix as a \c
1273  qreal \c matrix[3][4].
1274 
1275  \attention Passing the result of getProjectionMatrix() or getModelViewMatrix()
1276  to this method is not possible (purposefully incompatible matrix dimensions).
1277  \p matrix is more likely to be the product of these two matrices, without the
1278  last line.
1279 
1280  Use setFromModelViewMatrix() to set position() and orientation() from a \c
1281  GL_MODELVIEW matrix. fieldOfView() can also be retrieved from a \e perspective
1282  \c GL_PROJECTION matrix using 2.0 * atan(1.0/projectionMatrix[5]).
1283 
1284  This code was written by Sylvain Paris. */
1285 CGAL_INLINE_FUNCTION
setFromProjectionMatrix(const qreal matrix[12])1286 void Camera::setFromProjectionMatrix(const qreal matrix[12]) {
1287   // The 3 lines of the matrix are the normals to the planes x=0, y=0, z=0
1288   // in the camera CS. As we normalize them, we do not need the 4th coordinate.
1289   Vec line_0(matrix[ind(0, 0)], matrix[ind(0, 1)], matrix[ind(0, 2)]);
1290   Vec line_1(matrix[ind(1, 0)], matrix[ind(1, 1)], matrix[ind(1, 2)]);
1291   Vec line_2(matrix[ind(2, 0)], matrix[ind(2, 1)], matrix[ind(2, 2)]);
1292 
1293   line_0.normalize();
1294   line_1.normalize();
1295   line_2.normalize();
1296 
1297   // The camera position is at (0,0,0) in the camera CS so it is the
1298   // intersection of the 3 planes. It can be seen as the kernel
1299   // of the 3x4 projection matrix. We calculate it through 4 dimensional
1300   // vectorial product. We go directly into 3D that is to say we directly
1301   // divide the first 3 coordinates by the 4th one.
1302 
1303   // We derive the 4 dimensional vectorial product formula from the
1304   // computation of a 4x4 determinant that is developped according to
1305   // its 4th column. This implies some 3x3 determinants.
1306   const Vec cam_pos =
1307       Vec(det(matrix[ind(0, 1)], matrix[ind(0, 2)], matrix[ind(0, 3)],
1308               matrix[ind(1, 1)], matrix[ind(1, 2)], matrix[ind(1, 3)],
1309               matrix[ind(2, 1)], matrix[ind(2, 2)], matrix[ind(2, 3)]),
1310 
1311           -det(matrix[ind(0, 0)], matrix[ind(0, 2)], matrix[ind(0, 3)],
1312                matrix[ind(1, 0)], matrix[ind(1, 2)], matrix[ind(1, 3)],
1313                matrix[ind(2, 0)], matrix[ind(2, 2)], matrix[ind(2, 3)]),
1314 
1315           det(matrix[ind(0, 0)], matrix[ind(0, 1)], matrix[ind(0, 3)],
1316               matrix[ind(1, 0)], matrix[ind(1, 1)], matrix[ind(1, 3)],
1317               matrix[ind(2, 0)], matrix[ind(2, 1)], matrix[ind(2, 3)])) /
1318 
1319       (-det(matrix[ind(0, 0)], matrix[ind(0, 1)], matrix[ind(0, 2)],
1320             matrix[ind(1, 0)], matrix[ind(1, 1)], matrix[ind(1, 2)],
1321             matrix[ind(2, 0)], matrix[ind(2, 1)], matrix[ind(2, 2)]));
1322 
1323   // We compute the rotation matrix column by column.
1324 
1325   // GL Z axis is front facing.
1326   Vec column_2 = -line_2;
1327 
1328   // X-axis is almost like line_0 but should be orthogonal to the Z axis.
1329   Vec column_0 = ((column_2 ^ line_0) ^ column_2);
1330   column_0.normalize();
1331 
1332   // Y-axis is almost like line_1 but should be orthogonal to the Z axis.
1333   // Moreover line_1 is downward oriented as the screen CS.
1334   Vec column_1 = -((column_2 ^ line_1) ^ column_2);
1335   column_1.normalize();
1336 
1337   qreal rot[3][3];
1338   rot[0][0] = column_0[0];
1339   rot[1][0] = column_0[1];
1340   rot[2][0] = column_0[2];
1341 
1342   rot[0][1] = column_1[0];
1343   rot[1][1] = column_1[1];
1344   rot[2][1] = column_1[2];
1345 
1346   rot[0][2] = column_2[0];
1347   rot[1][2] = column_2[1];
1348   rot[2][2] = column_2[2];
1349 
1350   // We compute the field of view
1351 
1352   // line_1^column_0 -> vector of intersection line between
1353   // y_screen=0 and x_camera=0 plane.
1354   // column_2*(...)  -> cos of the angle between Z vector et y_screen=0 plane
1355   // * 2 -> field of view = 2 * half angle
1356 
1357   // We need some intermediate values.
1358   Vec dummy = line_1 ^ column_0;
1359   dummy.normalize();
1360   qreal fov = acos(column_2 * dummy) * 2.0;
1361 
1362   // We set the camera.
1363   Quaternion q;
1364   q.setFromRotationMatrix(rot);
1365   setOrientation(q);
1366   setPosition(cam_pos);
1367   setFieldOfView(fov);
1368 }
1369 
1370 /*
1371   // persp : projectionMatrix_[0]  = f/aspectRatio();
1372 CGAL_INLINE_FUNCTION
1373 void Camera::setFromProjectionMatrix(const GLdouble* projectionMatrix)
1374 {
1375   QString message;
1376   if ((fabs(projectionMatrix[1]) > 1E-3) ||
1377     (fabs(projectionMatrix[2]) > 1E-3) ||
1378     (fabs(projectionMatrix[3]) > 1E-3) ||
1379     (fabs(projectionMatrix[4]) > 1E-3) ||
1380     (fabs(projectionMatrix[6]) > 1E-3) ||
1381     (fabs(projectionMatrix[7]) > 1E-3) ||
1382     (fabs(projectionMatrix[8]) > 1E-3) ||
1383     (fabs(projectionMatrix[9]) > 1E-3))
1384   message = "Non null coefficient in projection matrix - Aborting";
1385   else
1386   if ((fabs(projectionMatrix[11]+1.0) < 1E-5) && (fabs(projectionMatrix[15]) <
1387 1E-5))
1388     {
1389   if (projectionMatrix[5] < 1E-4)
1390     message="Negative field of view in Camera::setFromProjectionMatrix";
1391   else
1392     setType(Camera::PERSPECTIVE);
1393     }
1394   else
1395     if ((fabs(projectionMatrix[11]) < 1E-5) && (fabs(projectionMatrix[15]-1.0) <
1396 1E-5)) setType(Camera::ORTHOGRAPHIC); else message = "Unable to determine camera
1397 type in setFromProjectionMatrix - Aborting";
1398 
1399   if (!message.isEmpty())
1400   {
1401     qWarning(message);
1402     return;
1403   }
1404 
1405   switch (type())
1406   {
1407   case Camera::PERSPECTIVE:
1408     {
1409   setFieldOfView(2.0 * atan(1.0/projectionMatrix[5]));
1410   const qreal far = projectionMatrix[14] / (2.0 * (1.0 + projectionMatrix[10]));
1411   const qreal near = (projectionMatrix[10]+1.0) / (projectionMatrix[10]-1.0) *
1412 far; setSceneRadius((far-near)/2.0); setSceneCenter(position() + (near +
1413 sceneRadius())*viewDirection()); break;
1414     }
1415   case Camera::ORTHOGRAPHIC:
1416     {
1417   GLdouble w, h;
1418   getOrthoWidthHeight(w,h);
1419   projectionMatrix_[0]  = 1.0/w;
1420   projectionMatrix_[5]  = 1.0/h;
1421   projectionMatrix_[10] = -2.0/(ZFar - ZNear);
1422   projectionMatrix_[11] = 0.0;
1423   projectionMatrix_[14] = -(ZFar + ZNear)/(ZFar - ZNear);
1424   projectionMatrix_[15] = 1.0;
1425   // same as glOrtho( -w, w, -h, h, zNear(), zFar() );
1426   break;
1427     }
1428   }
1429 }
1430 */
1431 
1432 ///////////////////////// Camera to world transform ///////////////////////
1433 
1434 /*! Same as cameraCoordinatesOf(), but with \c qreal[3] parameters (\p src and
1435  * \p res may be identical pointers). */
1436 CGAL_INLINE_FUNCTION
getCameraCoordinatesOf(const qreal src[3],qreal res[3])1437 void Camera::getCameraCoordinatesOf(const qreal src[3], qreal res[3]) const {
1438   Vec r = cameraCoordinatesOf(Vec(src));
1439   for (int i = 0; i < 3; ++i)
1440     res[i] = r[i];
1441 }
1442 
1443 /*! Same as worldCoordinatesOf(), but with \c qreal[3] parameters (\p src and \p
1444  * res may be identical pointers). */
1445 CGAL_INLINE_FUNCTION
getWorldCoordinatesOf(const qreal src[3],qreal res[3])1446 void Camera::getWorldCoordinatesOf(const qreal src[3], qreal res[3]) const {
1447   Vec r = worldCoordinatesOf(Vec(src));
1448   for (int i = 0; i < 3; ++i)
1449     res[i] = r[i];
1450 }
1451 
1452 /*! Fills \p viewport with the Camera OpenGL viewport.
1453 
1454 This method is mainly used in conjunction with \c gluProject, which requires
1455 such a viewport. Returned values are (0, screenHeight(), screenWidth(), -
1456 screenHeight()), so that the origin is located in the \e upper left corner of
1457 the window (Qt style coordinate system). */
1458 CGAL_INLINE_FUNCTION
getViewport(GLint viewport[4])1459 void Camera::getViewport(GLint viewport[4]) const {
1460   viewport[0] = 0;
1461   viewport[1] = screenHeight();
1462   viewport[2] = screenWidth();
1463   viewport[3] = -screenHeight();
1464 }
1465 
1466 //source code of GluProject and GluUnproject, imported here to avoid the dependency to Glu
1467 CGAL_INLINE_FUNCTION
project(qreal objx,qreal objy,qreal objz,GLdouble * modelview,GLdouble * projection,int * viewport,GLdouble * winX,GLdouble * winY,GLdouble * winZ)1468 int project(qreal objx, qreal objy, qreal objz, GLdouble *modelview,
1469             GLdouble *projection, int *viewport, GLdouble*winX, GLdouble *winY,GLdouble *winZ)
1470   {
1471       //Transformation vectors
1472       GLdouble fTempo[8];
1473       //Modelview transform
1474       fTempo[0]=modelview[0]*objx+modelview[4]*objy+modelview[8]*objz+modelview[12];  //w is always 1
1475       fTempo[1]=modelview[1]*objx+modelview[5]*objy+modelview[9]*objz+modelview[13];
1476       fTempo[2]=modelview[2]*objx+modelview[6]*objy+modelview[10]*objz+modelview[14];
1477       fTempo[3]=modelview[3]*objx+modelview[7]*objy+modelview[11]*objz+modelview[15];
1478       fTempo[4]=projection[0]*fTempo[0]+projection[4]*fTempo[1]+projection[8]*fTempo[2]+projection[12]*fTempo[3];
1479       fTempo[5]=projection[1]*fTempo[0]+projection[5]*fTempo[1]+projection[9]*fTempo[2]+projection[13]*fTempo[3];
1480       fTempo[6]=projection[2]*fTempo[0]+projection[6]*fTempo[1]+projection[10]*fTempo[2]+projection[14]*fTempo[3];
1481       fTempo[7]=projection[3]*fTempo[0]+projection[7]*fTempo[1]+projection[11]*fTempo[2]+projection[15]*fTempo[3];
1482       //The result normalizes between -1 and 1
1483       if(fTempo[7]==0.0)        //The w value
1484          return 0;
1485       fTempo[7]=1.0/fTempo[7];
1486       //Perspective division
1487       fTempo[4]*=fTempo[7];
1488       fTempo[5]*=fTempo[7];
1489       fTempo[6]*=fTempo[7];
1490       //Window coordinates
1491       //Map x, y to range 0-1
1492       *winX=(fTempo[4]*0.5+0.5)*viewport[2]+viewport[0];
1493       *winY=(fTempo[5]*0.5+0.5)*viewport[3]+viewport[1];
1494       //This is only correct when glDepthRange(0.0, 1.0)
1495       *winZ=(1.0+fTempo[6])*0.5;        //Between 0 and 1
1496       return 1;
1497 }
1498 
1499 CGAL_INLINE_FUNCTION
MultiplyMatrices4by4OpenGL_GLdouble(GLdouble * result,GLdouble * matrix1,GLdouble * matrix2)1500 void MultiplyMatrices4by4OpenGL_GLdouble(GLdouble *result, GLdouble *matrix1, GLdouble *matrix2)
1501  {
1502    result[0]=matrix1[0]*matrix2[0]+
1503      matrix1[4]*matrix2[1]+
1504      matrix1[8]*matrix2[2]+
1505      matrix1[12]*matrix2[3];
1506    result[4]=matrix1[0]*matrix2[4]+
1507      matrix1[4]*matrix2[5]+
1508      matrix1[8]*matrix2[6]+
1509      matrix1[12]*matrix2[7];
1510    result[8]=matrix1[0]*matrix2[8]+
1511      matrix1[4]*matrix2[9]+
1512      matrix1[8]*matrix2[10]+
1513      matrix1[12]*matrix2[11];
1514    result[12]=matrix1[0]*matrix2[12]+
1515      matrix1[4]*matrix2[13]+
1516      matrix1[8]*matrix2[14]+
1517      matrix1[12]*matrix2[15];
1518    result[1]=matrix1[1]*matrix2[0]+
1519      matrix1[5]*matrix2[1]+
1520      matrix1[9]*matrix2[2]+
1521      matrix1[13]*matrix2[3];
1522    result[5]=matrix1[1]*matrix2[4]+
1523      matrix1[5]*matrix2[5]+
1524      matrix1[9]*matrix2[6]+
1525      matrix1[13]*matrix2[7];
1526    result[9]=matrix1[1]*matrix2[8]+
1527      matrix1[5]*matrix2[9]+
1528      matrix1[9]*matrix2[10]+
1529      matrix1[13]*matrix2[11];
1530    result[13]=matrix1[1]*matrix2[12]+
1531      matrix1[5]*matrix2[13]+
1532      matrix1[9]*matrix2[14]+
1533      matrix1[13]*matrix2[15];
1534    result[2]=matrix1[2]*matrix2[0]+
1535      matrix1[6]*matrix2[1]+
1536      matrix1[10]*matrix2[2]+
1537      matrix1[14]*matrix2[3];
1538    result[6]=matrix1[2]*matrix2[4]+
1539      matrix1[6]*matrix2[5]+
1540      matrix1[10]*matrix2[6]+
1541      matrix1[14]*matrix2[7];
1542    result[10]=matrix1[2]*matrix2[8]+
1543      matrix1[6]*matrix2[9]+
1544      matrix1[10]*matrix2[10]+
1545      matrix1[14]*matrix2[11];
1546    result[14]=matrix1[2]*matrix2[12]+
1547      matrix1[6]*matrix2[13]+
1548      matrix1[10]*matrix2[14]+
1549      matrix1[14]*matrix2[15];
1550    result[3]=matrix1[3]*matrix2[0]+
1551      matrix1[7]*matrix2[1]+
1552      matrix1[11]*matrix2[2]+
1553      matrix1[15]*matrix2[3];
1554    result[7]=matrix1[3]*matrix2[4]+
1555      matrix1[7]*matrix2[5]+
1556      matrix1[11]*matrix2[6]+
1557      matrix1[15]*matrix2[7];
1558    result[11]=matrix1[3]*matrix2[8]+
1559      matrix1[7]*matrix2[9]+
1560      matrix1[11]*matrix2[10]+
1561      matrix1[15]*matrix2[11];
1562    result[15]=matrix1[3]*matrix2[12]+
1563      matrix1[7]*matrix2[13]+
1564      matrix1[11]*matrix2[14]+
1565      matrix1[15]*matrix2[15];
1566  }
1567 
1568 CGAL_INLINE_FUNCTION
MultiplyMatrixByVector4by4OpenGL_GLdouble(GLdouble * resultvector,const GLdouble * matrix,const GLdouble * pvector)1569  void MultiplyMatrixByVector4by4OpenGL_GLdouble(GLdouble *resultvector, const GLdouble *matrix, const GLdouble *pvector)
1570  {
1571    resultvector[0]=matrix[0]*pvector[0]+matrix[4]*pvector[1]+matrix[8]*pvector[2]+matrix[12]*pvector[3];
1572    resultvector[1]=matrix[1]*pvector[0]+matrix[5]*pvector[1]+matrix[9]*pvector[2]+matrix[13]*pvector[3];
1573    resultvector[2]=matrix[2]*pvector[0]+matrix[6]*pvector[1]+matrix[10]*pvector[2]+matrix[14]*pvector[3];
1574    resultvector[3]=matrix[3]*pvector[0]+matrix[7]*pvector[1]+matrix[11]*pvector[2]+matrix[15]*pvector[3];
1575  }
1576 
1577    #define SWAP_ROWS_DOUBLE(a, b) { double *_tmp = a; (a)=(b); (b)=_tmp; }
1578    #define SWAP_ROWS_GLdouble(a, b) { GLdouble *_tmp = a; (a)=(b); (b)=_tmp; }
1579    #define MAT(m,r,c) (m)[(c)*4+(r)]
1580    //This code comes directly from GLU except that it is for GLdouble
1581  CGAL_INLINE_FUNCTION
glhInvertMatrixf2(GLdouble * m,GLdouble * out)1582  int glhInvertMatrixf2(GLdouble *m, GLdouble *out)
1583   {
1584    GLdouble wtmp[4][8];
1585    GLdouble m0, m1, m2, m3, s;
1586    GLdouble *r0, *r1, *r2, *r3;
1587    r0 = wtmp[0], r1 = wtmp[1], r2 = wtmp[2], r3 = wtmp[3];
1588    r0[0] = MAT(m, 0, 0), r0[1] = MAT(m, 0, 1),
1589       r0[2] = MAT(m, 0, 2), r0[3] = MAT(m, 0, 3),
1590       r0[4] = 1.0, r0[5] = r0[6] = r0[7] = 0.0,
1591       r1[0] = MAT(m, 1, 0), r1[1] = MAT(m, 1, 1),
1592       r1[2] = MAT(m, 1, 2), r1[3] = MAT(m, 1, 3),
1593       r1[5] = 1.0, r1[4] = r1[6] = r1[7] = 0.0,
1594       r2[0] = MAT(m, 2, 0), r2[1] = MAT(m, 2, 1),
1595       r2[2] = MAT(m, 2, 2), r2[3] = MAT(m, 2, 3),
1596       r2[6] = 1.0, r2[4] = r2[5] = r2[7] = 0.0,
1597       r3[0] = MAT(m, 3, 0), r3[1] = MAT(m, 3, 1),
1598       r3[2] = MAT(m, 3, 2), r3[3] = MAT(m, 3, 3),
1599       r3[7] = 1.0, r3[4] = r3[5] = r3[6] = 0.0;
1600    /* choose pivot - or die */
1601    if (fabs(r3[0]) > fabs(r2[0]))
1602       SWAP_ROWS_GLdouble(r3, r2);
1603    if (fabs(r2[0]) > fabs(r1[0]))
1604       SWAP_ROWS_GLdouble(r2, r1);
1605    if (fabs(r1[0]) > fabs(r0[0]))
1606       SWAP_ROWS_GLdouble(r1, r0);
1607    if (0.0 == r0[0])
1608       return 0;
1609    /* eliminate first variable     */
1610    m1 = r1[0] / r0[0];
1611    m2 = r2[0] / r0[0];
1612    m3 = r3[0] / r0[0];
1613    s = r0[1];
1614    r1[1] -= m1 * s;
1615    r2[1] -= m2 * s;
1616    r3[1] -= m3 * s;
1617    s = r0[2];
1618    r1[2] -= m1 * s;
1619    r2[2] -= m2 * s;
1620    r3[2] -= m3 * s;
1621    s = r0[3];
1622    r1[3] -= m1 * s;
1623    r2[3] -= m2 * s;
1624    r3[3] -= m3 * s;
1625    s = r0[4];
1626    if (s != 0.0) {
1627       r1[4] -= m1 * s;
1628       r2[4] -= m2 * s;
1629       r3[4] -= m3 * s;
1630    }
1631    s = r0[5];
1632    if (s != 0.0) {
1633       r1[5] -= m1 * s;
1634       r2[5] -= m2 * s;
1635       r3[5] -= m3 * s;
1636    }
1637    s = r0[6];
1638    if (s != 0.0) {
1639       r1[6] -= m1 * s;
1640       r2[6] -= m2 * s;
1641       r3[6] -= m3 * s;
1642    }
1643    s = r0[7];
1644    if (s != 0.0) {
1645       r1[7] -= m1 * s;
1646       r2[7] -= m2 * s;
1647       r3[7] -= m3 * s;
1648    }
1649    /* choose pivot - or die */
1650    if (fabs(r3[1]) > fabs(r2[1]))
1651       SWAP_ROWS_GLdouble(r3, r2);
1652    if (fabs(r2[1]) > fabs(r1[1]))
1653       SWAP_ROWS_GLdouble(r2, r1);
1654    if (0.0 == r1[1])
1655       return 0;
1656    /* eliminate second variable */
1657    m2 = r2[1] / r1[1];
1658    m3 = r3[1] / r1[1];
1659    r2[2] -= m2 * r1[2];
1660    r3[2] -= m3 * r1[2];
1661    r2[3] -= m2 * r1[3];
1662    r3[3] -= m3 * r1[3];
1663    s = r1[4];
1664    if (0.0 != s) {
1665       r2[4] -= m2 * s;
1666       r3[4] -= m3 * s;
1667    }
1668    s = r1[5];
1669    if (0.0 != s) {
1670       r2[5] -= m2 * s;
1671       r3[5] -= m3 * s;
1672    }
1673    s = r1[6];
1674    if (0.0 != s) {
1675       r2[6] -= m2 * s;
1676       r3[6] -= m3 * s;
1677    }
1678    s = r1[7];
1679    if (0.0 != s) {
1680       r2[7] -= m2 * s;
1681       r3[7] -= m3 * s;
1682    }
1683    /* choose pivot - or die */
1684    if (fabs(r3[2]) > fabs(r2[2]))
1685       SWAP_ROWS_GLdouble(r3, r2);
1686    if (0.0 == r2[2])
1687       return 0;
1688    /* eliminate third variable */
1689    m3 = r3[2] / r2[2];
1690    r3[3] -= m3 * r2[3], r3[4] -= m3 * r2[4],
1691       r3[5] -= m3 * r2[5], r3[6] -= m3 * r2[6], r3[7] -= m3 * r2[7];
1692    /* last check */
1693    if (0.0 == r3[3])
1694       return 0;
1695    s = 1.0 / r3[3];                /* now back substitute row 3 */
1696    r3[4] *= s;
1697    r3[5] *= s;
1698    r3[6] *= s;
1699    r3[7] *= s;
1700    m2 = r2[3];                        /* now back substitute row 2 */
1701    s = 1.0 / r2[2];
1702    r2[4] = s * (r2[4] - r3[4] * m2), r2[5] = s * (r2[5] - r3[5] * m2),
1703       r2[6] = s * (r2[6] - r3[6] * m2), r2[7] = s * (r2[7] - r3[7] * m2);
1704    m1 = r1[3];
1705    r1[4] -= r3[4] * m1, r1[5] -= r3[5] * m1,
1706       r1[6] -= r3[6] * m1, r1[7] -= r3[7] * m1;
1707    m0 = r0[3];
1708    r0[4] -= r3[4] * m0, r0[5] -= r3[5] * m0,
1709       r0[6] -= r3[6] * m0, r0[7] -= r3[7] * m0;
1710    m1 = r1[2];                        /* now back substitute row 1 */
1711    s = 1.0 / r1[1];
1712    r1[4] = s * (r1[4] - r2[4] * m1), r1[5] = s * (r1[5] - r2[5] * m1),
1713       r1[6] = s * (r1[6] - r2[6] * m1), r1[7] = s * (r1[7] - r2[7] * m1);
1714    m0 = r0[2];
1715    r0[4] -= r2[4] * m0, r0[5] -= r2[5] * m0,
1716       r0[6] -= r2[6] * m0, r0[7] -= r2[7] * m0;
1717    m0 = r0[1];                        /* now back substitute row 0 */
1718    s = 1.0 / r0[0];
1719    r0[4] = s * (r0[4] - r1[4] * m0), r0[5] = s * (r0[5] - r1[5] * m0),
1720       r0[6] = s * (r0[6] - r1[6] * m0), r0[7] = s * (r0[7] - r1[7] * m0);
1721    MAT(out, 0, 0) = r0[4];
1722    MAT(out, 0, 1) = r0[5], MAT(out, 0, 2) = r0[6];
1723    MAT(out, 0, 3) = r0[7], MAT(out, 1, 0) = r1[4];
1724    MAT(out, 1, 1) = r1[5], MAT(out, 1, 2) = r1[6];
1725    MAT(out, 1, 3) = r1[7], MAT(out, 2, 0) = r2[4];
1726    MAT(out, 2, 1) = r2[5], MAT(out, 2, 2) = r2[6];
1727    MAT(out, 2, 3) = r2[7], MAT(out, 3, 0) = r3[4];
1728    MAT(out, 3, 1) = r3[5], MAT(out, 3, 2) = r3[6];
1729    MAT(out, 3, 3) = r3[7];
1730    return 1;
1731   }
1732 
1733 #undef MAT
1734 #undef SWAP_ROWS_GLdouble
1735 #undef SWAP_ROWS_DOUBLE
1736 
1737 CGAL_INLINE_FUNCTION
unProject(GLdouble winx,GLdouble winy,GLdouble winz,GLdouble * modelview,GLdouble * projection,int * viewport,GLdouble * objX,GLdouble * objY,GLdouble * objZ)1738 int unProject(GLdouble winx, GLdouble winy, GLdouble winz, GLdouble *modelview, GLdouble *projection, int *viewport,
1739               GLdouble *objX,GLdouble *objY,GLdouble *objZ)
1740  {
1741      //Transformation matrices
1742      GLdouble m[16], A[16];
1743      GLdouble in[4], out[4];
1744      //Calculation for inverting a matrix, compute projection x modelview
1745      //and store in A[16]
1746      MultiplyMatrices4by4OpenGL_GLdouble(A, projection, modelview);
1747      //Now compute the inverse of matrix A
1748      if(glhInvertMatrixf2(A, m)==0)
1749         return 0;
1750      //Transformation of normalized coordinates between -1 and 1
1751      in[0]=(winx-(GLdouble)viewport[0])/(GLdouble)viewport[2]*2.0-1.0;
1752      in[1]=(winy-(GLdouble)viewport[1])/(GLdouble)viewport[3]*2.0-1.0;
1753      in[2]=2.0*winz-1.0;
1754      in[3]=1.0;
1755      //Objects coordinates
1756      MultiplyMatrixByVector4by4OpenGL_GLdouble(out, m, in);
1757      if(out[3]==0.0)
1758         return 0;
1759      out[3]=1.0/out[3];
1760      *objX=out[0]*out[3];
1761      *objY=out[1]*out[3];
1762      *objZ=out[2]*out[3];
1763      return 1;
1764  }
1765 
1766 /*! Returns the screen projected coordinates of a point \p src defined in the \p frame coordinate
1767  system.
1768  When \p frame in \c nullptr (default), \p src is expressed in the world coordinate system.
1769  The x and y coordinates of the returned Vec are expressed in pixel, (0,0) being the \e upper left
1770  corner of the window. The z coordinate ranges between 0.0 (near plane) and 1.0 (excluded, far
1771  plane). See the \c gluProject man page for details.
1772  unprojectedCoordinatesOf() performs the inverse transformation.
1773  See the <a href="../examples/screenCoordSystem.html">screenCoordSystem example</a>.
1774  This method only uses the intrinsic Camera parameters (see getModelViewMatrix(),
1775  getProjectionMatrix() and getViewport()) and is completely independent of the OpenGL \c
1776  GL_MODELVIEW, \c GL_PROJECTION and viewport matrices. You can hence define a virtual Camera and use
1777  this method to compute projections out of a classical rendering context.
1778  \attention However, if your Camera is not attached to a CGAL::QGLViewer (used for offscreen computations
1779  for instance), make sure the Camera matrices are updated before calling this method. Call
1780  computeModelViewMatrix() and computeProjectionMatrix() to do so.
1781  If you call this method several times with no change in the matrices, consider precomputing the
1782  projection times modelview matrix to save computation time if required (\c P x \c M in the \c
1783  gluProject man page).
1784  Here is the code corresponding to what this method does (kindly submitted by Robert W. Kuhn) :
1785  \code
1786  Vec project(Vec point)
1787  {
1788     GLint    Viewport[4];
1789     GLdouble Projection[16], Modelview[16];
1790     GLdouble matrix[16];
1791     // Precomputation begin
1792     glGetIntegerv(GL_VIEWPORT         , Viewport);
1793     glGetDoublev (GL_MODELVIEW_MATRIX , Modelview);
1794     glGetDoublev (GL_PROJECTION_MATRIX, Projection);
1795     for (unsigned short m=0; m<4; ++m)
1796     {
1797         for (unsigned short l=0; l<4; ++l)
1798         {
1799             qreal sum = 0.0;
1800             for (unsigned short k=0; k<4; ++k)
1801                 sum += Projection[l+4*k]*Modelview[k+4*m];
1802             matrix[l+4*m] = sum;
1803         }
1804     }
1805     // Precomputation end
1806     GLdouble v[4], vs[4];
1807     v[0]=point[0]; v[1]=point[1]; v[2]=point[2]; v[3]=1.0;
1808     vs[0]=matrix[0 ]*v[0] + matrix[4 ]*v[1] + matrix[8 ]*v[2] + matrix[12 ]*v[3];
1809     vs[1]=matrix[1 ]*v[0] + matrix[5 ]*v[1] + matrix[9 ]*v[2] + matrix[13 ]*v[3];
1810     vs[2]=matrix[2 ]*v[0] + matrix[6 ]*v[1] + matrix[10]*v[2] + matrix[14 ]*v[3];
1811     vs[3]=matrix[3 ]*v[0] + matrix[7 ]*v[1] + matrix[11]*v[2] + matrix[15 ]*v[3];
1812     vs[0] /= vs[3];
1813     vs[1] /= vs[3];
1814     vs[2] /= vs[3];
1815     vs[0] = vs[0] * 0.5 + 0.5;
1816     vs[1] = vs[1] * 0.5 + 0.5;
1817     vs[2] = vs[2] * 0.5 + 0.5;
1818     vs[0] = vs[0] * Viewport[2] + Viewport[0];
1819     vs[1] = vs[1] * Viewport[3] + Viewport[1];
1820     return Vec(vs[0], Viewport[3]-vs[1], vs[2]);
1821   }
1822  \endcode
1823  */
1824 CGAL_INLINE_FUNCTION
projectedCoordinatesOf(const Vec & src,const Frame * frame)1825 Vec Camera::projectedCoordinatesOf(const Vec& src, const Frame* frame) const
1826 {
1827     GLdouble x = 0.f, y = 0.f, z = 0.f;
1828     static GLint viewport[4];
1829     getViewport(viewport);
1830 
1831     if (frame)
1832     {
1833         const Vec tmp = frame->inverseCoordinatesOf(src);
1834         project(tmp.x,tmp.y,tmp.z, modelViewMatrix_, projectionMatrix_, viewport,  &x,&y,&z);
1835     }
1836     else
1837         project(src.x,src.y,src.z, modelViewMatrix_, projectionMatrix_, viewport,  &x,&y,&z);
1838 
1839     return Vec(x,y,z);
1840 }
1841 
1842 /*! Returns the world unprojected coordinates of a point \p src defined in the screen coordinate
1843  system.
1844  The \p src.x and \p src.y input values are expressed in pixels, (0,0) being the \e upper left corner
1845  of the window. \p src.z is a depth value ranging in [0..1[ (respectively corresponding to the near
1846  and far planes). Note that src.z is \e not a linear interpolation between zNear and zFar.
1847  /code
1848  src.z = zFar() / (zFar() - zNear()) * (1.0 - zNear() / z);
1849  /endcode
1850  Where z is the distance from the point you project to the camera, along the viewDirection().
1851  See the \c gluUnProject man page for details.
1852  The result is expressed in the \p frame coordinate system. When \p frame is \c nullptr (default), the
1853  result is expressed in the world coordinates system. The possible \p frame Frame::referenceFrame()
1854  are taken into account.
1855  projectedCoordinatesOf() performs the inverse transformation.
1856  This method only uses the intrinsic Camera parameters (see getModelViewMatrix(),
1857  getProjectionMatrix() and getViewport()) and is completely independent of the OpenGL \c
1858  GL_MODELVIEW, \c GL_PROJECTION and viewport matrices. You can hence define a virtual Camera and use
1859  this method to compute un-projections out of a classical rendering context.
1860  \attention However, if your Camera is not attached to a CGAL::QGLViewer (used for offscreen computations
1861  for instance), make sure the Camera matrices are updated before calling this method (use
1862  computeModelViewMatrix(), computeProjectionMatrix()). See also setScreenWidthAndHeight().
1863  This method is not computationally optimized. If you call it several times with no change in the
1864  matrices, you should buffer the entire inverse projection matrix (modelview, projection and then
1865  viewport) to speed-up the queries. See the \c gluUnProject man page for details. */
1866 CGAL_INLINE_FUNCTION
unprojectedCoordinatesOf(const Vec & src,const Frame * frame)1867 Vec Camera::unprojectedCoordinatesOf(const Vec& src, const Frame* frame) const
1868 {
1869     GLdouble x = 0.f, y = 0.f, z = 0.f;
1870     static GLint viewport[4];
1871     getViewport(viewport);
1872     unProject(src.x,src.y,src.z, modelViewMatrix_,  projectionMatrix_,  viewport,  &x,&y,&z);
1873     if (frame)
1874         return frame->coordinatesOf(Vec(x,y,z));
1875     else
1876         return Vec(x,y,z);
1877 }
1878 
1879 /*! Same as projectedCoordinatesOf(), but with \c qreal parameters (\p src and
1880  * \p res can be identical pointers). */
1881 CGAL_INLINE_FUNCTION
getProjectedCoordinatesOf(const qreal src[3],qreal res[3],const Frame * frame)1882 void Camera::getProjectedCoordinatesOf(const qreal src[3], qreal res[3],
1883                                        const Frame *frame) const {
1884   Vec r = projectedCoordinatesOf(Vec(src), frame);
1885   for (int i = 0; i < 3; ++i)
1886     res[i] = r[i];
1887 }
1888 
1889 /*! Same as unprojectedCoordinatesOf(), but with \c qreal parameters (\p src and
1890  * \p res can be identical pointers). */
1891 CGAL_INLINE_FUNCTION
getUnprojectedCoordinatesOf(const qreal src[3],qreal res[3],const Frame * frame)1892 void Camera::getUnprojectedCoordinatesOf(const qreal src[3], qreal res[3],
1893                                          const Frame *frame) const {
1894   Vec r = unprojectedCoordinatesOf(Vec(src), frame);
1895   for (int i = 0; i < 3; ++i)
1896     res[i] = r[i];
1897 }
1898 
1899 /////////////////////////////////////  KFI
1900 ////////////////////////////////////////////
1901 
1902 /*! Returns the KeyFrameInterpolator that defines the Camera path number \p i.
1903 
1904 If path \p i is not defined for this index, the method returns a \c nullptr
1905 pointer. */
1906 CGAL_INLINE_FUNCTION
keyFrameInterpolator(unsigned int i)1907 KeyFrameInterpolator *Camera::keyFrameInterpolator(unsigned int i) const {
1908   if (kfi_.contains(i))
1909     return kfi_[i];
1910   else
1911     return nullptr;
1912 }
1913 
1914 /*! Sets the KeyFrameInterpolator that defines the Camera path of index \p i.
1915 
1916  The previous keyFrameInterpolator() is lost and should be deleted by the
1917  calling method if needed.
1918 
1919  The KeyFrameInterpolator::interpolated() signal of \p kfi probably needs to be
1920  connected to the Camera's associated CGAL::QGLViewer::update() slot, so that when the
1921  Camera position is interpolated using \p kfi, every interpolation step updates
1922  the display: \code myViewer.camera()->deletePath(3);
1923  myViewer.camera()->setKeyFrameInterpolator(3, myKeyFrameInterpolator);
1924  connect(myKeyFrameInterpolator, SIGNAL(interpolated()), myViewer,
1925  SLOT(update()); \endcode
1926 
1927  \note These connections are done automatically when a Camera is attached to a
1928  CGAL::QGLViewer, or when a new KeyFrameInterpolator is defined using the
1929  CGAL::QGLViewer::addKeyFrameKeyboardModifiers() and CGAL::QGLViewer::pathKey() (default is
1930  Alt+F[1-12]). See the <a href="../keyboard.html">keyboard page</a> for details.
1931  */
1932 CGAL_INLINE_FUNCTION
setKeyFrameInterpolator(unsigned int i,KeyFrameInterpolator * const kfi)1933 void Camera::setKeyFrameInterpolator(unsigned int i,
1934                                      KeyFrameInterpolator *const kfi) {
1935   if (kfi)
1936     kfi_[i] = kfi;
1937   else
1938     kfi_.remove(i);
1939 }
1940 
1941 /*! Adds the current Camera position() and orientation() as a keyFrame to the
1942 path number \p i.
1943 
1944 This method can also be used if you simply want to save a Camera point of view
1945 (a path made of a single keyFrame). Use playPath() to make the Camera play the
1946 keyFrame path (resp. restore the point of view). Use deletePath() to clear the
1947 path.
1948 
1949 The default keyboard shortcut for this method is Alt+F[1-12]. Set
1950 CGAL::QGLViewer::pathKey() and CGAL::QGLViewer::addKeyFrameKeyboardModifiers().
1951 
1952 If you use directly this method and the keyFrameInterpolator(i) does not exist,
1953 a new one is created. Its KeyFrameInterpolator::interpolated() signal should
1954 then be connected to the CGAL::QGLViewer::update() slot (see
1955 setKeyFrameInterpolator()). */
1956 CGAL_INLINE_FUNCTION
addKeyFrameToPath(unsigned int i)1957 void Camera::addKeyFrameToPath(unsigned int i) {
1958   if (!kfi_.contains(i))
1959     setKeyFrameInterpolator(i, new KeyFrameInterpolator(frame()));
1960 
1961   kfi_[i]->addKeyFrame(*(frame()));
1962 }
1963 
1964 /*! Makes the Camera follow the path of keyFrameInterpolator() number \p i.
1965 
1966  If the interpolation is started, it stops it instead.
1967 
1968  This method silently ignores undefined (empty) paths (see
1969  keyFrameInterpolator()).
1970 
1971  The default keyboard shortcut for this method is F[1-12]. Set
1972  CGAL::QGLViewer::pathKey() and CGAL::QGLViewer::playPathKeyboardModifiers(). */
1973 CGAL_INLINE_FUNCTION
playPath(unsigned int i)1974 void Camera::playPath(unsigned int i) {
1975   if (kfi_.contains(i)) {
1976     if (kfi_[i]->interpolationIsStarted())
1977       kfi_[i]->stopInterpolation();
1978     else
1979       kfi_[i]->startInterpolation();
1980   }
1981 }
1982 
1983 /*! Resets the path of the keyFrameInterpolator() number \p i.
1984 
1985 If this path is \e not being played (see playPath() and
1986 KeyFrameInterpolator::interpolationIsStarted()), resets it to its starting
1987 position (see KeyFrameInterpolator::resetInterpolation()). If the path is
1988 played, simply stops interpolation. */
1989 CGAL_INLINE_FUNCTION
resetPath(unsigned int i)1990 void Camera::resetPath(unsigned int i) {
1991   if (kfi_.contains(i)) {
1992     if ((kfi_[i]->interpolationIsStarted()))
1993       kfi_[i]->stopInterpolation();
1994     else {
1995       kfi_[i]->resetInterpolation();
1996       kfi_[i]->interpolateAtTime(kfi_[i]->interpolationTime());
1997     }
1998   }
1999 }
2000 
2001 /*! Deletes the keyFrameInterpolator() of index \p i.
2002 
2003 Disconnect the keyFrameInterpolator() KeyFrameInterpolator::interpolated()
2004 signal before deleting the keyFrameInterpolator() if needed: \code
2005 disconnect(camera()->keyFrameInterpolator(i), SIGNAL(interpolated()), this,
2006 SLOT(update())); camera()->deletePath(i); \endcode */
2007 CGAL_INLINE_FUNCTION
deletePath(unsigned int i)2008 void Camera::deletePath(unsigned int i) {
2009   if (kfi_.contains(i)) {
2010     kfi_[i]->stopInterpolation();
2011     delete kfi_[i];
2012     kfi_.remove(i);
2013   }
2014 }
2015 
2016 
2017 ////////////////////////////////////////////////////////////////////////////////
2018 
2019 /*! Gives the coefficients of a 3D half-line passing through the Camera eye and
2020  pixel (x,y).
2021 
2022  The origin of the half line (eye position) is stored in \p orig, while \p dir
2023  contains the properly oriented and normalized direction of the half line.
2024 
2025  \p x and \p y are expressed in Qt format (origin in the upper left corner). Use
2026  screenHeight() - y to convert to OpenGL units.
2027 
2028  This method is useful for analytical intersection in a selection method.
2029 
2030  See the <a href="../examples/select.html">select example</a> for an
2031  illustration. */
2032 CGAL_INLINE_FUNCTION
convertClickToLine(const QPoint & pixel,Vec & orig,Vec & dir)2033 void Camera::convertClickToLine(const QPoint &pixel, Vec &orig,
2034                                 Vec &dir) const {
2035   switch (type()) {
2036   case Camera::PERSPECTIVE:
2037     orig = position();
2038     dir = Vec(((2.0 * pixel.x() / screenWidth()) - 1.0) *
2039                   tan(fieldOfView() / 2.0) * aspectRatio(),
2040               ((2.0 * (screenHeight() - pixel.y()) / screenHeight()) - 1.0) *
2041                   tan(fieldOfView() / 2.0),
2042               -1.0);
2043     dir = worldCoordinatesOf(dir) - orig;
2044     dir.normalize();
2045     break;
2046 
2047   case Camera::ORTHOGRAPHIC: {
2048     GLdouble w, h;
2049     getOrthoWidthHeight(w, h);
2050     orig = Vec((2.0 * pixel.x() / screenWidth() - 1.0) * w,
2051                -(2.0 * pixel.y() / screenHeight() - 1.0) * h, 0.0);
2052     orig = worldCoordinatesOf(orig);
2053     dir = viewDirection();
2054     break;
2055   }
2056   }
2057 }
2058 
2059 
2060 /*! Returns the 6 plane equations of the Camera frustum.
2061 
2062 The six 4-component vectors of \p coef respectively correspond to the left,
2063 right, near, far, top and bottom Camera frustum planes. Each vector holds a
2064 plane equation of the form: \code a*x + b*y + c*z + d = 0 \endcode where \c a,
2065 \c b, \c c and \c d are the 4 components of each vector, in that order.
2066 
2067 See the <a href="../examples/frustumCulling.html">frustumCulling example</a> for
2068 an application.
2069 
2070 This format is compatible with the \c glClipPlane() function. One camera frustum
2071 plane can hence be applied in an other viewer to visualize the culling results:
2072 \code
2073  // Retrieve plane equations
2074  GLdouble coef[6][4];
2075  mainViewer->camera()->getFrustumPlanesCoefficients(coef);
2076 
2077  // These two additional clipping planes (which must have been enabled)
2078  // will reproduce the mainViewer's near and far clipping.
2079  glClipPlane(GL_CLIP_PLANE0, coef[2]);
2080  glClipPlane(GL_CLIP_PLANE1, coef[3]);
2081 \endcode */
2082 CGAL_INLINE_FUNCTION
getFrustumPlanesCoefficients(GLdouble coef[6][4])2083 void Camera::getFrustumPlanesCoefficients(GLdouble coef[6][4]) const {
2084   // Computed once and for all
2085   const Vec pos = position();
2086   const Vec viewDir = viewDirection();
2087   const Vec up = upVector();
2088   const Vec right = rightVector();
2089   const qreal posViewDir = pos * viewDir;
2090 
2091   static Vec normal[6];
2092   static GLdouble dist[6];
2093 
2094   switch (type()) {
2095   case Camera::PERSPECTIVE: {
2096     const qreal hhfov = horizontalFieldOfView() / 2.0;
2097     const qreal chhfov = cos(hhfov);
2098     const qreal shhfov = sin(hhfov);
2099     normal[0] = -shhfov * viewDir;
2100     normal[1] = normal[0] + chhfov * right;
2101     normal[0] = normal[0] - chhfov * right;
2102 
2103     normal[2] = -viewDir;
2104     normal[3] = viewDir;
2105 
2106     const qreal hfov = fieldOfView() / 2.0;
2107     const qreal chfov = cos(hfov);
2108     const qreal shfov = sin(hfov);
2109     normal[4] = -shfov * viewDir;
2110     normal[5] = normal[4] - chfov * up;
2111     normal[4] = normal[4] + chfov * up;
2112 
2113     for (int i = 0; i < 2; ++i)
2114       dist[i] = pos * normal[i];
2115     for (int j = 4; j < 6; ++j)
2116       dist[j] = pos * normal[j];
2117 
2118     // Natural equations are:
2119     // dist[0,1,4,5] = pos * normal[0,1,4,5];
2120     // dist[2] = (pos + zNear() * viewDir) * normal[2];
2121     // dist[3] = (pos + zFar()  * viewDir) * normal[3];
2122 
2123     // 2 times less computations using expanded/merged equations. Dir vectors
2124     // are normalized.
2125     const qreal posRightCosHH = chhfov * pos * right;
2126     dist[0] = -shhfov * posViewDir;
2127     dist[1] = dist[0] + posRightCosHH;
2128     dist[0] = dist[0] - posRightCosHH;
2129     const qreal posUpCosH = chfov * pos * up;
2130     dist[4] = -shfov * posViewDir;
2131     dist[5] = dist[4] - posUpCosH;
2132     dist[4] = dist[4] + posUpCosH;
2133 
2134     break;
2135   }
2136   case Camera::ORTHOGRAPHIC:
2137     normal[0] = -right;
2138     normal[1] = right;
2139     normal[4] = up;
2140     normal[5] = -up;
2141 
2142     GLdouble hw, hh;
2143     getOrthoWidthHeight(hw, hh);
2144     dist[0] = (pos - hw * right) * normal[0];
2145     dist[1] = (pos + hw * right) * normal[1];
2146     dist[4] = (pos + hh * up) * normal[4];
2147     dist[5] = (pos - hh * up) * normal[5];
2148     break;
2149   }
2150 
2151   // Front and far planes are identical for both camera types.
2152   normal[2] = -viewDir;
2153   normal[3] = viewDir;
2154   dist[2] = -posViewDir - zNear();
2155   dist[3] = posViewDir + zFar();
2156 
2157   for (int i = 0; i < 6; ++i) {
2158     coef[i][0] = GLdouble(normal[i].x);
2159     coef[i][1] = GLdouble(normal[i].y);
2160     coef[i][2] = GLdouble(normal[i].z);
2161     coef[i][3] = dist[i];
2162   }
2163 }
2164 
2165 CGAL_INLINE_FUNCTION
onFrameModified()2166 void Camera::onFrameModified() {
2167   projectionMatrixIsUpToDate_ = false;
2168   modelViewMatrixIsUpToDate_ = false;
2169 }
2170 
2171 CGAL_INLINE_FUNCTION
setHorizontalFieldOfView(qreal hfov)2172 void Camera::setHorizontalFieldOfView(qreal hfov) {
2173   setFieldOfView(2.0 * atan(tan(hfov / 2.0) / aspectRatio()));
2174 }
2175 
2176 CGAL_INLINE_FUNCTION
horizontalFieldOfView()2177 qreal Camera::horizontalFieldOfView() const {
2178   return 2.0 * atan(tan(fieldOfView() / 2.0) * aspectRatio());
2179 }
2180 
2181 
2182 
2183 CGAL_INLINE_FUNCTION
setFrustum(double frustum[6])2184 void Camera::setFrustum(double frustum[6])
2185 {
2186   double l(frustum[0]),r(frustum[1]),t(frustum[2]),
2187       b(frustum[3]),n(frustum[4]),f(frustum[5]);
2188   if(type() == PERSPECTIVE)
2189   {
2190     double A = 2*n/(r-l);
2191     double B = (r+l)/(r-l);
2192     double C = 2*n/(t-b);
2193     double D = (t+b)/(t-b);
2194     double E = -(f+n)/(f-n);
2195     double F = -2*(f*n)/(f-n);
2196     projectionMatrix_[0] = A; projectionMatrix_[4] = 0; projectionMatrix_[8] = B ; projectionMatrix_[12] = 0;
2197     projectionMatrix_[1] = 0; projectionMatrix_[5] = C; projectionMatrix_[9] = D ; projectionMatrix_[13] = 0;
2198     projectionMatrix_[2] = 0; projectionMatrix_[6] = 0; projectionMatrix_[10] = E ; projectionMatrix_[14] = F;
2199     projectionMatrix_[3] =0; projectionMatrix_[7] =0; projectionMatrix_[11] =-1; projectionMatrix_[15] =0;
2200   }
2201   else
2202   {
2203     double A = 2/(r-l);
2204     double B = -(r+l)/(r-l);
2205     double C = 2/(t-b);
2206     double D = -(t+b)/(t-b);
2207     double E = -(f+n)/(f-n);
2208     double F = -2/(f-n);
2209     projectionMatrix_[0] = A; projectionMatrix_[1] = 0; projectionMatrix_[2] = 0 ; projectionMatrix_[3] = 0;
2210     projectionMatrix_[4] = 0; projectionMatrix_[5] = C; projectionMatrix_[6] = 0 ; projectionMatrix_[7] = 0;
2211     projectionMatrix_[8] = 0; projectionMatrix_[9] = 0; projectionMatrix_[10] = F ; projectionMatrix_[11] = 0;
2212     projectionMatrix_[12] = B; projectionMatrix_[13] = D; projectionMatrix_[14] = E; projectionMatrix_[15] = 1;
2213   }
2214   projectionMatrixIsUpToDate_ = true;
2215 }
2216 
2217 CGAL_INLINE_FUNCTION
getFrustum(double frustum[6])2218 void Camera::getFrustum(double frustum[6])
2219 {
2220   double l,r,t,b,n,f;
2221   if(type() == PERSPECTIVE)
2222   {
2223   n = projectionMatrix_[14]/2*((projectionMatrix_[10]+1)/(projectionMatrix_[10]-1)-1);
2224   f = n*(projectionMatrix_[10]-1)/(projectionMatrix_[10]+1);
2225   l = ((2*n/projectionMatrix_[0])*(projectionMatrix_[8]-1)/(projectionMatrix_[8]+1))/(1-(projectionMatrix_[8]-1)/(projectionMatrix_[8]+1));
2226   r = 2*n/projectionMatrix_[0]+l;
2227   b=(-2*n/projectionMatrix_[5]*(1-projectionMatrix_[9])/(1+projectionMatrix_[9]))/(1+(1-projectionMatrix_[9])/(1+projectionMatrix_[9]));
2228   t = 2*n/projectionMatrix_[5]+b;
2229   }
2230   else
2231   {
2232     double A(projectionMatrix_[0]),B(projectionMatrix_[12]),
2233         C(projectionMatrix_[5]),D(projectionMatrix_[13]),
2234         E(projectionMatrix_[14]),F(projectionMatrix_[10]);
2235     double B1 = (B+1)/(1-B), D1 = (1-D)/(D+1),
2236         E1=(E+1)/(1-E);
2237 
2238     l = -2*B1/(1+B1*A);
2239     r = 2+A*l;
2240     t = 2*D1/(C*(1+D1));
2241     b =t -2/C;
2242     n = -2/(F*(1+E1));
2243     f=n-2/F;
2244 
2245   }
2246   frustum[0] = l;
2247   frustum[1] = r;
2248   frustum[2] = t;
2249   frustum[3] = b;
2250   frustum[4] = n;
2251   frustum[5] = f;
2252 }
2253 }}//end of namespace
2254