ObjectAnimation.qt.C

00001 #ifndef OBJECTANIMATION_QT_C
00002 #define OBJECTANIMATION_QT_C
00003 
00004 #include "NeovisionII/NeoAnnotate/ObjectAnimation.qt.H"
00005 #include "rutz/trace.h"
00006 
00007 //######################################################################
00008 ObjectAnimation::ObjectAnimation(int frameNum, FrameRange masterFrameRange, QPointF initialPos) :
00009   itsMasterFrameRange(masterFrameRange)
00010 {
00011   itsKeyFrames.clear();
00012 
00013   //Insert a single keyframe at the current frame number at the given initial position
00014   FrameState defaultKey;
00015   defaultKey.pos     = initialPos;
00016   defaultKey.visible = true;
00017 //  itsKeyFrames[masterFrameRange.getFirst()] = defaultKey;
00018   itsKeyFrames[frameNum] = defaultKey;
00019 }
00020 
00021 //######################################################################
00022 std::pair<QMap<int, ObjectAnimation::FrameState>::const_iterator,
00023           QMap<int, ObjectAnimation::FrameState>::const_iterator>
00024 ObjectAnimation::getBoundingKeyframes(int fnum)
00025 {
00026 
00027   GVX_TRACE(__PRETTY_FUNCTION__);
00028 
00029   //Create our bounding keyframes container, and fill it with bogus
00030   //values, in case we're asked to find unreasonable bounding frames
00031   std::pair<QMap<int, ObjectAnimation::FrameState>::const_iterator,
00032             QMap<int, ObjectAnimation::FrameState>::const_iterator> ret;
00033   ret.first  = itsKeyFrames.end();
00034   ret.second = itsKeyFrames.end();
00035 
00036   //If we're asked for unreasonable bounding frames, then just return the
00037   //bogus container
00038   if(fnum < itsKeyFrames.begin().key())
00039     return ret;
00040   if(fnum > (itsKeyFrames.end()-1).key())
00041     return ret;
00042 
00043   //Find the first keyframe which has a larger or equal value
00044   //to the frame number
00045   ret.second = itsKeyFrames.lowerBound(fnum);
00046 
00047   //Try to find the previous keyframe as long as our frameNum isn't a keyframe, or
00048   //the first frame in the animation.
00049   ret.first = ret.second;
00050   if(ret.second != itsKeyFrames.begin() && ret.second.key() != fnum)
00051     ret.first--;
00052 
00053   return ret;
00054 }
00055 
00056 //######################################################################
00057 ObjectAnimation::FrameState ObjectAnimation::getFrameState(int frameNum)
00058 {
00059   GVX_TRACE(__PRETTY_FUNCTION__);
00060 
00061 
00062   //If the requested frame is before the first keyframe, just return an invisible
00063   //framestate
00064   if(frameNum < itsKeyFrames.begin().key())
00065   {
00066     FrameState ret;
00067     ret.visible  = false;
00068     ret.is_keyframe = false;
00069     return ret;
00070   }
00071 
00072   //If we are beyond the final keyframe, then just return the position of the last known one
00073   //Note that this means that all frames after the last keyframe will inherit that last keyframe's
00074   //visibility state
00075   if(frameNum > (itsKeyFrames.end()-1).key())
00076   {
00077     FrameState ret  = (itsKeyFrames.end()-1).value();
00078     ret.is_keyframe = false;
00079     return ret;
00080   }
00081 
00082   //Find the bounding keyframes for the given frame
00083   std::pair<QMap<int, ObjectAnimation::FrameState>::const_iterator,
00084             QMap<int, ObjectAnimation::FrameState>::const_iterator> bounds =
00085               getBoundingKeyframes(frameNum);
00086 
00087   //If the bounding keyframes are the same, then no need to interpolate - we
00088   //already have a keyframe
00089   if(bounds.first == bounds.second) 
00090   {
00091     return bounds.first.value();
00092   }
00093 
00094   FrameState upperKey = bounds.second.value();
00095   FrameState lowerKey = bounds.first.value();
00096   QPointF lowerPos = lowerKey.pos;
00097   QPointF upperPos = upperKey.pos;
00098 
00099   //Interpolate between the two neighboring keyframes
00100   float alpha = 1.0;
00101   if(bounds.second.key() != bounds.first.key())
00102   {
00103     alpha = float(frameNum - bounds.first.key()) /
00104             float(bounds.second.key() - bounds.first.key());
00105   }
00106   QPointF intPos = upperPos*alpha + lowerPos*(1.0-alpha);
00107 
00108   FrameState ret;
00109   ret.pos         = intPos;
00110   ret.visible     = lowerKey.visible;
00111   ret.is_keyframe = false;
00112 
00113   return ret;
00114 }
00115 
00116 //######################################################################
00117 AnimationDelegate::FrameType ObjectAnimation::getFrameType(int fnum)
00118 {
00119   GVX_TRACE(__PRETTY_FUNCTION__);
00120 
00121   //If the requested frame is before the first keyframe, just return an invisible frametype
00122   if(fnum < itsKeyFrames.begin().key())
00123     return AnimationDelegate::Invisible;
00124 
00125   //If we are beyond the final keyframe, then look to our previous keyframe to see if we are invisible or not
00126   if(fnum > (itsKeyFrames.end()-1).key())
00127   {
00128     FrameState ret  = (itsKeyFrames.end()-1).value();
00129     if(ret.visible)
00130       return AnimationDelegate::Tween;
00131     else
00132       return AnimationDelegate::Invisible;
00133   }
00134 
00135   //Find the bounding keyframes for the given frame
00136   std::pair<QMap<int, ObjectAnimation::FrameState>::const_iterator,
00137             QMap<int, ObjectAnimation::FrameState>::const_iterator> bounds =
00138               getBoundingKeyframes(fnum);
00139 
00140   //If we have an actual keyframe:
00141   if(bounds.first.key() == bounds.second.key())
00142   {
00143     if(bounds.first.value().visible)
00144       return AnimationDelegate::VisibleKeyframe;
00145     else
00146       return AnimationDelegate::InvisibleKeyframe;
00147   }
00148 
00149   if(bounds.first.value().visible)
00150     return AnimationDelegate::Tween;
00151 
00152   return AnimationDelegate::Invisible;
00153 }
00154 
00155 //######################################################################
00156 bool ObjectAnimation::moveKeyframe(int from_fnum, int to_fnum)
00157 {
00158   if(itsKeyFrames.contains(from_fnum) && !itsKeyFrames.contains(to_fnum))
00159   {
00160     if(to_fnum >= itsMasterFrameRange.getFirst() && to_fnum <= itsMasterFrameRange.getLast())
00161     {
00162       itsKeyFrames[to_fnum] = itsKeyFrames[from_fnum];
00163       itsKeyFrames.remove(from_fnum);
00164       emit(animationChanged());
00165       return true;
00166     }
00167   }
00168 
00169   return false;
00170 }
00171 
00172 //######################################################################
00173 void ObjectAnimation::setPosition(int frameNum, QPointF pos, bool visible)
00174 {
00175   //Construct a new keyframe at the given framenumber with the given position
00176   FrameState key;
00177   key.pos         = pos;
00178   key.visible     = visible;
00179   key.is_keyframe = true;
00180   //Insert the keyframe into the data store
00181   itsKeyFrames[frameNum] = key;
00182 
00183   emit(animationChanged());
00184 }
00185 
00186 //######################################################################
00187 void ObjectAnimation::constructContextMenu(QPoint pos, int column)
00188 {
00189   //Compute the absolute frame number
00190   int frameNum = column + itsMasterFrameRange.getFirst();
00191 
00192   //Create a new drop down menu
00193   QMenu menu;
00194 
00195   QAction *createKeyframe = NULL;
00196   QAction *removeKeyframe = NULL;
00197   QAction *makeVisible    = NULL;
00198   QAction *makeInvisible  = NULL;
00199 
00200   //Find the relevant frame number
00201   QMap<int, FrameState>::iterator frameIt = itsKeyFrames.find(frameNum);
00202 
00203   if(frameIt != itsKeyFrames.end())
00204   {
00205     //Create some actions if the active frame is a keyframe
00206 
00207     FrameState state = frameIt.value();
00208 
00209     //Allow the user to make the current keyframe visible or invisible
00210     if(state.visible == true)
00211     {
00212       makeInvisible = new QAction(tr("Make &Invisible"), this);
00213       menu.addAction(makeInvisible);
00214     }
00215     else if(state.visible == false)
00216     {
00217       makeVisible = new QAction(tr("Make &Visible"), this);
00218       menu.addAction(makeVisible);
00219     }
00220 
00221     //Allow the user to delete the current keyframe
00222     removeKeyframe = new QAction(tr("&Delete Keyframe"), this);
00223     menu.addAction(removeKeyframe);
00224   }
00225   else
00226   {
00227     //If the active frame is not a keyframe, allow the user to make it one
00228     createKeyframe = new QAction(tr("&Create Keyframe"), this);
00229     menu.addAction(createKeyframe);
00230   }
00231 
00232   //Show the menu and retrieve the selected action
00233   QAction* menuAction = menu.exec(pos);
00234 
00235   if(menuAction != NULL)
00236   {
00237     //Perform the requested action
00238 
00239     if(menuAction == createKeyframe)
00240     {
00241       FrameState newState  = getFrameState(frameNum);
00242       newState.visible     = true;
00243       newState.is_keyframe = true;
00244       itsKeyFrames[frameNum] = newState;
00245       emit(animationChanged());
00246     }
00247     else if(menuAction == removeKeyframe)
00248     {
00249       itsKeyFrames.erase(frameIt);
00250       emit(animationChanged());
00251     }
00252     else if(menuAction == makeVisible)
00253     {
00254       frameIt->visible = true;
00255       emit(animationChanged());
00256     }
00257     else if(menuAction == makeInvisible)
00258     {
00259       frameIt->visible = false;
00260       emit(animationChanged());
00261     }
00262   }
00263 
00264   //Clean up the menu items
00265   if(createKeyframe != NULL) delete createKeyframe;
00266   if(removeKeyframe != NULL) delete removeKeyframe;
00267   if(makeVisible    != NULL) delete makeVisible;
00268   if(makeInvisible  != NULL) delete makeInvisible;
00269 }
00270 
00271 void ObjectAnimation::clear()
00272 {
00273   itsKeyFrames.clear();
00274   emit(animationChanged());
00275 }
00276 
00277 #endif //OBJECTANIMATION_QT_C
Generated on Sun May 8 08:41:02 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3