keyFrameInterpolator.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 
3  Copyright (C) 2002-2014 Gilles Debunne. All rights reserved.
4 
5  This file is part of the QGLViewer library version 2.6.3.
6 
7  http://www.libqglviewer.com - contact@libqglviewer.com
8 
9  This file may be used under the terms of the GNU General Public License
10  versions 2.0 or 3.0 as published by the Free Software Foundation and
11  appearing in the LICENSE file included in the packaging of this file.
12  In addition, as a special exception, Gilles Debunne gives you certain
13  additional rights, described in the file GPL_EXCEPTION in this package.
14 
15  libQGLViewer uses dual licensing. Commercial/proprietary software must
16  purchase a libQGLViewer Commercial License.
17 
18  This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
19  WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 
21 *****************************************************************************/
22 
23 #include "domUtils.h"
24 #include "qglviewer.h" // for QGLViewer::drawAxis and Camera::drawCamera
25 
26 using namespace qglviewer;
27 using namespace std;
28 
36  : frame_(NULL), period_(40), interpolationTime_(0.0), interpolationSpeed_(1.0), interpolationStarted_(false),
37  closedPath_(false), loopInterpolation_(false), pathIsValid_(false), valuesAreValid_(true), currentFrameValid_(false)
38  // #CONNECTION# Values cut pasted initFromDOMElement()
39 {
40  setFrame(frame);
41  for (int i=0; i<4; ++i)
42  currentFrame_[i] = new QMutableListIterator<KeyFrame*>(keyFrame_);
43  connect(&timer_, SIGNAL(timeout()), SLOT(update()));
44 }
45 
48 {
49  deletePath();
50  for (int i=0; i<4; ++i)
51  delete currentFrame_[i];
52 }
53 
56 {
57  if (this->frame())
58  disconnect(this, SIGNAL( interpolated() ), this->frame(), SIGNAL( interpolated() ));
59 
60  frame_ = frame;
61 
62  if (this->frame())
63  connect(this, SIGNAL( interpolated() ), this->frame(), SIGNAL( interpolated() ));
64 }
65 
73 {
75 
77 
78  if (interpolationTime() > keyFrame_.last()->time())
79  {
80  if (loopInterpolation())
81  setInterpolationTime(keyFrame_.first()->time() + interpolationTime_ - keyFrame_.last()->time());
82  else
83  {
84  // Make sure last KeyFrame is reached and displayed
85  interpolateAtTime(keyFrame_.last()->time());
87  }
88  Q_EMIT endReached();
89  }
90  else
91  if (interpolationTime() < keyFrame_.first()->time())
92  {
93  if (loopInterpolation())
94  setInterpolationTime(keyFrame_.last()->time() - keyFrame_.first()->time() + interpolationTime_);
95  else
96  {
97  // Make sure first KeyFrame is reached and displayed
98  interpolateAtTime(keyFrame_.first()->time());
100  }
101  Q_EMIT endReached();
102  }
103 }
104 
105 
127 {
128  if (period >= 0)
129  setInterpolationPeriod(period);
130 
131  if (!keyFrame_.isEmpty())
132  {
133  if ((interpolationSpeed() > 0.0) && (interpolationTime() >= keyFrame_.last()->time()))
134  setInterpolationTime(keyFrame_.first()->time());
135  if ((interpolationSpeed() < 0.0) && (interpolationTime() <= keyFrame_.first()->time()))
136  setInterpolationTime(keyFrame_.last()->time());
137  timer_.start(interpolationPeriod());
138  interpolationStarted_ = true;
139  update();
140  }
141 }
142 
143 
146 {
147  timer_.stop();
148  interpolationStarted_ = false;
149 }
150 
151 
157 {
160 }
161 
174 void KeyFrameInterpolator::addKeyFrame(const Frame* const frame, qreal time)
175 {
176  if (!frame)
177  return;
178 
179  if (keyFrame_.isEmpty())
180  interpolationTime_ = time;
181 
182  if ( (!keyFrame_.isEmpty()) && (keyFrame_.last()->time() > time) )
183  qWarning("Error in KeyFrameInterpolator::addKeyFrame: time is not monotone");
184  else
185  keyFrame_.append(new KeyFrame(frame, time));
186  connect(frame, SIGNAL(modified()), SLOT(invalidateValues()));
187  valuesAreValid_ = false;
188  pathIsValid_ = false;
189  currentFrameValid_ = false;
191 }
192 
201 {
202  if (keyFrame_.isEmpty())
203  interpolationTime_ = time;
204 
205  if ( (!keyFrame_.isEmpty()) && (keyFrame_.last()->time() > time) )
206  qWarning("Error in KeyFrameInterpolator::addKeyFrame: time is not monotone");
207  else
208  keyFrame_.append(new KeyFrame(frame, time));
209 
210  valuesAreValid_ = false;
211  pathIsValid_ = false;
212  currentFrameValid_ = false;
214 }
215 
216 
222 {
223  qreal time;
224  if (keyFrame_.isEmpty())
225  time = 0.0;
226  else
227  time = lastTime() + 1.0;
228 
229  addKeyFrame(frame, time);
230 }
231 
237 {
238  qreal time;
239  if (keyFrame_.isEmpty())
240  time = 0.0;
241  else
242  time = keyFrame_.last()->time() + 1.0;
243 
244  addKeyFrame(frame, time);
245 }
246 
249 {
251  qDeleteAll(keyFrame_);
252  keyFrame_.clear();
253  pathIsValid_ = false;
254  valuesAreValid_ = false;
255  currentFrameValid_ = false;
256 }
257 
258 static void drawCamera(qreal scale)
259 {
260  glDisable(GL_LIGHTING);
261 
262  const qreal halfHeight = scale * 0.07;
263  const qreal halfWidth = halfHeight * 1.3;
264  const qreal dist = halfHeight / tan(qreal(M_PI)/8.0);
265 
266  const qreal arrowHeight = 1.5 * halfHeight;
267  const qreal baseHeight = 1.2 * halfHeight;
268  const qreal arrowHalfWidth = 0.5 * halfWidth;
269  const qreal baseHalfWidth = 0.3 * halfWidth;
270 
271  // Frustum outline
272  glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
273  glBegin(GL_LINE_STRIP);
274  glVertex3d(-halfWidth, halfHeight,-dist);
275  glVertex3d(-halfWidth,-halfHeight,-dist);
276  glVertex3d( 0.0, 0.0, 0.0);
277  glVertex3d( halfWidth,-halfHeight,-dist);
278  glVertex3d(-halfWidth,-halfHeight,-dist);
279  glEnd();
280  glBegin(GL_LINE_STRIP);
281  glVertex3d( halfWidth,-halfHeight,-dist);
282  glVertex3d( halfWidth, halfHeight,-dist);
283  glVertex3d( 0.0, 0.0, 0.0);
284  glVertex3d(-halfWidth, halfHeight,-dist);
285  glVertex3d( halfWidth, halfHeight,-dist);
286  glEnd();
287 
288  // Up arrow
289  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
290  // Base
291  glBegin(GL_QUADS);
292  glVertex3d(-baseHalfWidth, halfHeight,-dist);
293  glVertex3d( baseHalfWidth, halfHeight,-dist);
294  glVertex3d( baseHalfWidth, baseHeight,-dist);
295  glVertex3d(-baseHalfWidth, baseHeight,-dist);
296  glEnd();
297 
298  // Arrow
299  glBegin(GL_TRIANGLES);
300  glVertex3d( 0.0, arrowHeight,-dist);
301  glVertex3d(-arrowHalfWidth, baseHeight, -dist);
302  glVertex3d( arrowHalfWidth, baseHeight, -dist);
303  glEnd();
304 }
305 
337 void KeyFrameInterpolator::drawPath(int mask, int nbFrames, qreal scale)
338 {
339  const int nbSteps = 30;
340  if (!pathIsValid_)
341  {
342  path_.clear();
343 
344  if (keyFrame_.isEmpty())
345  return;
346 
347  if (!valuesAreValid_)
349 
350  if (keyFrame_.first() == keyFrame_.last())
351  path_.push_back(Frame(keyFrame_.first()->position(), keyFrame_.first()->orientation()));
352  else
353  {
354  static Frame fr;
355  KeyFrame* kf_[4];
356  kf_[0] = keyFrame_.first();
357  kf_[1] = kf_[0];
358  int index = 1;
359  kf_[2] = (index < keyFrame_.size()) ? keyFrame_.at(index) : NULL;
360  index++;
361  kf_[3] = (index < keyFrame_.size()) ? keyFrame_.at(index) : NULL;
362 
363  while (kf_[2])
364  {
365  Vec diff = kf_[2]->position() - kf_[1]->position();
366  Vec v1 = 3.0 * diff - 2.0 * kf_[1]->tgP() - kf_[2]->tgP();
367  Vec v2 = -2.0 * diff + kf_[1]->tgP() + kf_[2]->tgP();
368 
369  // cout << kf_[0]->time() << " , " << kf_[1]->time() << " , " << kf_[2]->time() << " , " << kf_[3]->time() << endl;
370  for (int step=0; step<nbSteps; ++step)
371  {
372  qreal alpha = step / static_cast<qreal>(nbSteps);
373  fr.setPosition(kf_[1]->position() + alpha * (kf_[1]->tgP() + alpha * (v1+alpha*v2)));
374  fr.setOrientation(Quaternion::squad(kf_[1]->orientation(), kf_[1]->tgQ(), kf_[2]->tgQ(), kf_[2]->orientation(), alpha));
375  path_.push_back(fr);
376  }
377 
378  // Shift
379  kf_[0] = kf_[1];
380  kf_[1] = kf_[2];
381  kf_[2] = kf_[3];
382  index++;
383  kf_[3] = (index < keyFrame_.size()) ? keyFrame_.at(index) : NULL;
384  }
385  // Add last KeyFrame
386  path_.push_back(Frame(kf_[1]->position(), kf_[1]->orientation()));
387  }
388  pathIsValid_ = true;
389  }
390 
391  if (mask)
392  {
393  glDisable(GL_LIGHTING);
394  glLineWidth(2);
395 
396  if (mask & 1)
397  {
398  glBegin(GL_LINE_STRIP);
399  Q_FOREACH (Frame fr, path_)
400  glVertex3fv(fr.position());
401  glEnd();
402  }
403  if (mask & 6)
404  {
405  int count = 0;
406  if (nbFrames > nbSteps)
407  nbFrames = nbSteps;
408  qreal goal = 0.0;
409  Q_FOREACH (Frame fr, path_)
410  if ((count++) >= goal)
411  {
412  goal += nbSteps / static_cast<qreal>(nbFrames);
413  glPushMatrix();
414  glMultMatrixd(fr.matrix());
415  if (mask & 2) drawCamera(scale);
416  if (mask & 4) QGLViewer::drawAxis(scale/10.0);
417  glPopMatrix();
418  }
419  }
420  }
421 }
422 
424 {
425  Quaternion prevQ = keyFrame_.first()->orientation();
426  KeyFrame* kf;
427  for (int i=0; i<keyFrame_.size(); ++i)
428  {
429  kf = keyFrame_.at(i);
430  if (kf->frame())
432  kf->flipOrientationIfNeeded(prevQ);
433  prevQ = kf->orientation();
434  }
435 
436  KeyFrame* prev = keyFrame_.first();
437  kf = keyFrame_.first();
438  int index = 1;
439  while (kf)
440  {
441  KeyFrame* next = (index < keyFrame_.size()) ? keyFrame_.at(index) : NULL;
442  index++;
443  if (next)
444  kf->computeTangent(prev, next);
445  else
446  kf->computeTangent(prev, kf);
447  prev = kf;
448  kf = next;
449  }
450  valuesAreValid_ = true;
451 }
452 
460 {
461  const KeyFrame* const kf = keyFrame_.at(index);
462  return Frame(kf->position(), kf->orientation());
463 }
464 
469 {
470  return keyFrame_.at(index)->time();
471 }
472 
478 {
479  return lastTime() - firstTime();
480 }
481 
486 {
487  if (keyFrame_.isEmpty())
488  return 0.0;
489  else
490  return keyFrame_.first()->time();
491 }
492 
497 {
498  if (keyFrame_.isEmpty())
499  return 0.0;
500  else
501  return keyFrame_.last()->time();
502 }
503 
505 {
506  // Assertion: times are sorted in monotone order.
507  // Assertion: keyFrame_ is not empty
508 
509  // TODO: Special case for loops when closed path is implemented !!
510  if (!currentFrameValid_)
511  // Recompute everything from scrach
512  currentFrame_[1]->toFront();
513 
514  while (currentFrame_[1]->peekNext()->time() > time)
515  {
516  currentFrameValid_ = false;
517  if (!currentFrame_[1]->hasPrevious())
518  break;
519  currentFrame_[1]->previous();
520  }
521 
522  if (!currentFrameValid_)
523  *currentFrame_[2] = *currentFrame_[1];
524 
525  while (currentFrame_[2]->peekNext()->time() < time)
526  {
527  currentFrameValid_ = false;
528  if (!currentFrame_[2]->hasNext())
529  break;
530  currentFrame_[2]->next();
531  }
532 
533  if (!currentFrameValid_)
534  {
535  *currentFrame_[1] = *currentFrame_[2];
536  if ((currentFrame_[1]->hasPrevious()) && (time < currentFrame_[2]->peekNext()->time()))
537  currentFrame_[1]->previous();
538 
539  *currentFrame_[0] = *currentFrame_[1];
540  if (currentFrame_[0]->hasPrevious())
541  currentFrame_[0]->previous();
542 
543  *currentFrame_[3] = *currentFrame_[2];
544  if (currentFrame_[3]->hasNext())
545  currentFrame_[3]->next();
546 
547  currentFrameValid_ = true;
548  splineCacheIsValid_ = false;
549  }
550 
551  // cout << "Time = " << time << " : " << currentFrame_[0]->peekNext()->time() << " , " <<
552  // currentFrame_[1]->peekNext()->time() << " , " << currentFrame_[2]->peekNext()->time() << " , " << currentFrame_[3]->peekNext()->time() << endl;
553 }
554 
556 {
557  Vec delta = currentFrame_[2]->peekNext()->position() - currentFrame_[1]->peekNext()->position();
558  v1 = 3.0 * delta - 2.0 * currentFrame_[1]->peekNext()->tgP() - currentFrame_[2]->peekNext()->tgP();
559  v2 = -2.0 * delta + currentFrame_[1]->peekNext()->tgP() + currentFrame_[2]->peekNext()->tgP();
560  splineCacheIsValid_ = true;
561 }
562 
571 {
572  setInterpolationTime(time);
573 
574  if ((keyFrame_.isEmpty()) || (!frame()))
575  return;
576 
577  if (!valuesAreValid_)
579 
581 
582  if (!splineCacheIsValid_)
584 
585  qreal alpha;
586  qreal dt = currentFrame_[2]->peekNext()->time() - currentFrame_[1]->peekNext()->time();
587  if (dt == 0.0)
588  alpha = 0.0;
589  else
590  alpha = (time - currentFrame_[1]->peekNext()->time()) / dt;
591 
592  // Linear interpolation - debug
593  // Vec pos = alpha*(currentFrame_[2]->peekNext()->position()) + (1.0-alpha)*(currentFrame_[1]->peekNext()->position());
594  Vec pos = currentFrame_[1]->peekNext()->position() + alpha * (currentFrame_[1]->peekNext()->tgP() + alpha * (v1+alpha*v2));
595  Quaternion q = Quaternion::squad(currentFrame_[1]->peekNext()->orientation(), currentFrame_[1]->peekNext()->tgQ(),
596  currentFrame_[2]->peekNext()->tgQ(), currentFrame_[2]->peekNext()->orientation(), alpha);
598 
599  Q_EMIT interpolated();
600 }
601 
617 QDomElement KeyFrameInterpolator::domElement(const QString& name, QDomDocument& document) const
618 {
619  QDomElement de = document.createElement(name);
620  int count = 0;
621  Q_FOREACH (KeyFrame* kf, keyFrame_)
622  {
623  Frame fr(kf->position(), kf->orientation());
624  QDomElement kfNode = fr.domElement("KeyFrame", document);
625  kfNode.setAttribute("index", QString::number(count));
626  kfNode.setAttribute("time", QString::number(kf->time()));
627  de.appendChild(kfNode);
628  ++count;
629  }
630  de.setAttribute("nbKF", QString::number(keyFrame_.count()));
631  de.setAttribute("time", QString::number(interpolationTime()));
632  de.setAttribute("speed", QString::number(interpolationSpeed()));
633  de.setAttribute("period", QString::number(interpolationPeriod()));
634  DomUtils::setBoolAttribute(de, "closedPath", closedPath());
636  return de;
637 }
638 
647 void KeyFrameInterpolator::initFromDOMElement(const QDomElement& element)
648 {
649  qDeleteAll(keyFrame_);
650  keyFrame_.clear();
651  QDomElement child=element.firstChild().toElement();
652  while (!child.isNull())
653  {
654  if (child.tagName() == "KeyFrame")
655  {
656  Frame fr;
657  fr.initFromDOMElement(child);
658  qreal time = DomUtils::qrealFromDom(child, "time", 0.0);
659  addKeyFrame(fr, time);
660  }
661 
662  child = child.nextSibling().toElement();
663  }
664 
665  // #CONNECTION# Values cut pasted from constructor
666  setInterpolationTime(DomUtils::qrealFromDom(element, "time", 0.0));
667  setInterpolationSpeed(DomUtils::qrealFromDom(element, "speed", 1.0));
668  setInterpolationPeriod(DomUtils::intFromDom(element, "period", 40));
669  setClosedPath(DomUtils::boolFromDom(element, "closedPath", false));
670  setLoopInterpolation(DomUtils::boolFromDom(element, "loop", false));
671 
672  // setFrame(NULL);
673  pathIsValid_ = false;
674  valuesAreValid_ = false;
675  currentFrameValid_ = false;
676 
678 }
679 
680 #ifndef DOXYGEN
681 
684  : time_(t), frame_(NULL)
685 {
686  p_ = fr.position();
687  q_ = fr.orientation();
688 }
689 
691  : time_(t), frame_(fr)
692 {
694 }
695 
697 {
698  p_ = frame()->position();
699  q_ = frame()->orientation();
700 }
701 
702 void KeyFrameInterpolator::KeyFrame::computeTangent(const KeyFrame* const prev, const KeyFrame* const next)
703 {
704  tgP_ = 0.5 * (next->position() - prev->position());
706 }
707 
709 {
710  if (Quaternion::dot(prev, q_) < 0.0)
711  q_.negate();
712 }
713 
714 #endif //DOXYGEN
Vec position() const
Definition: frame.cpp:537
void addKeyFrame(const Frame &frame)
QMutableListIterator< KeyFrame * > * currentFrame_[4]
void setClosedPath(bool closed=true)
static Quaternion squad(const Quaternion &a, const Quaternion &tgA, const Quaternion &tgB, const Quaternion &b, qreal t)
Definition: quaternion.cpp:467
void computeTangent(const KeyFrame *const prev, const KeyFrame *const next)
virtual QDomElement domElement(const QString &name, QDomDocument &document) const
Definition: frame.cpp:994
virtual void interpolateAtTime(qreal time)
virtual void drawPath(int mask=1, int nbFrames=6, qreal scale=1.0)
#define M_PI
static Quaternion squadTangent(const Quaternion &before, const Quaternion &center, const Quaternion &after)
Definition: quaternion.cpp:513
static void drawAxis(qreal length=1.0)
Definition: qglviewer.cpp:3255
The Vec class represents 3D positions and 3D vectors.
Definition: vec.h:65
const GLdouble * matrix() const
Definition: frame.cpp:123
static qreal dot(const Quaternion &a, const Quaternion &b)
Definition: quaternion.h:270
void flipOrientationIfNeeded(const Quaternion &prev)
static void setBoolAttribute(QDomElement &element, const QString &attribute, bool value)
Definition: domUtils.h:137
static qreal qrealFromDom(const QDomElement &e, const QString &attribute, qreal defValue)
Definition: domUtils.h:44
void setLoopInterpolation(bool loop=true)
The Quaternion class represents 3D rotations and orientations.
Definition: quaternion.h:66
Quaternion orientation() const
Definition: frame.cpp:546
void setPosition(const Vec &position)
Definition: frame.cpp:443
static bool boolFromDom(const QDomElement &e, const QString &attribute, bool defValue)
Definition: domUtils.h:114
virtual void initFromDOMElement(const QDomElement &element)
The Frame class represents a coordinate system, defined by a position and an orientation.
Definition: frame.h:121
static int intFromDom(const QDomElement &e, const QString &attribute, int defValue)
Definition: domUtils.h:72
void setOrientation(const Quaternion &orientation)
Definition: frame.cpp:505
virtual QDomElement domElement(const QString &name, QDomDocument &document) const
void setPositionAndOrientationWithConstraint(Vec &position, Quaternion &orientation)
Definition: frame.cpp:641
static void drawCamera(qreal scale)
virtual void initFromDOMElement(const QDomElement &element)
Definition: frame.cpp:1011


octovis
Author(s): Kai M. Wurm , Armin Hornung
autogenerated on Wed Jun 5 2019 19:26:39