Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

MotionSequenceEngine.cc

Go to the documentation of this file.
00001 #include "MotionSequenceEngine.h"
00002 #include "DynamicMotionSequence.h"
00003 #include "Shared/get_time.h"
00004 #include "Shared/WorldState.h"
00005 #include "Shared/Config.h"
00006 #include <iostream>
00007 
00008 using std::cout;
00009 using std::endl;
00010 
00011 MotionSequenceEngine::Move_idx_t MotionSequenceEngine::invalid_move=(MotionSequenceEngine::Move_idx_t)-1;
00012 
00013 MotionSequenceEngine::MotionSequenceEngine()
00014 : LoadSave(), playtime(1), lasttime(0), endtime(0), playspeed(1.0f),
00015 playing(true), hold(true), loadSaveMode(1)
00016 {
00017   for(unsigned int i=0; i<NumOutputs; i++)
00018     curstamps[i]=-1U;
00019 }
00020 
00021 
00022 int MotionSequenceEngine::updateOutputs() {
00023   if(isPlaying()) {
00024     if(lasttime==0)
00025       play();
00026     unsigned int curtime=get_time();
00027     float diff=(curtime-lasttime)*playspeed;
00028     if(playtime<-diff)
00029       setTime(0);
00030     else
00031       setTime(static_cast<unsigned int>(diff+playtime));
00032     lasttime=curtime;
00033     return 1;
00034   } else {
00035     lasttime=get_time();
00036     return 0;
00037   }
00038 }
00039 
00040 const OutputCmd& MotionSequenceEngine::getOutputCmd(unsigned int i) {
00041   if(curstamps[i]!=playtime) {
00042     if(nexts[i]!=invalid_move)
00043       calcOutput(curs[i],playtime,getKeyFrame(prevs[i]),getKeyFrame(nexts[i]));
00044     else if(hold)
00045       curs[i]=getKeyFrame(prevs[i]).cmd;
00046     else
00047       curs[i].unset();
00048     curstamps[i]=playtime;
00049   }
00050   return curs[i];
00051 }
00052 
00053 unsigned int MotionSequenceEngine::getBinSize() const {
00054   char buf[128];
00055   unsigned int len=128;
00056   unsigned int used=strlen("#MSq\n");
00057   used+=snprintf(buf,len,isSaveRadians()?"radians\n":"degrees\n");
00058   unsigned int t=0;
00059   Move_idx_t tprevs[NumOutputs];
00060   Move_idx_t tnexts[NumOutputs];
00061   bool hasInitialFrame=false;
00062   for(unsigned int i=0;i<NumOutputs;i++) {
00063     tnexts[i]=getKeyFrame(tprevs[i]=starts[i]).next;
00064     if(getKeyFrame(starts[i]).cmd.weight!=0)
00065       hasInitialFrame=true;
00066   }
00067   if(hasInitialFrame)
00068     used+=snprintf(buf,len,"setTime\t0\n");
00069   while(t!=-1U) {
00070     for(unsigned int i=0; i<NumOutputs; i++) {
00071       if((t!=0 || getKeyFrame(tprevs[i]).cmd.weight!=0) && getKeyFrame(tprevs[i]).starttime==t) {
00072         if(getKeyFrame(tprevs[i]).cmd.weight==1)
00073           used+=snprintf(buf,len,"%s\t%g\n",outputNames[i],getKeyFrame(tprevs[i]).cmd.value/loadSaveMode);
00074         else
00075           used+=snprintf(buf,len,"%s\t%g\t%g\n",outputNames[i],getKeyFrame(tprevs[i]).cmd.value/loadSaveMode,getKeyFrame(tprevs[i]).cmd.weight);
00076       }
00077     }
00078     unsigned int last=t;
00079     t=setNextFrameTime(tprevs,tnexts);
00080     if(t!=-1U)
00081       used+=snprintf(buf,len,"advanceTime\t%d\n",t-last);
00082   }
00083   used+=strlen("#END\n");
00084   return used+1;
00085 }
00086 
00087 unsigned int MotionSequenceEngine::loadBuffer(const char buf[], unsigned int len, const char* filename) {
00088   unsigned int origlen=len;
00089   if(strncmp("#POS",buf,4)==0) {
00090     // allow inlined loading of posture files
00091     PostureEngine pose;
00092     unsigned int used=pose.loadBuffer(buf,len);
00093     if(used!=0)
00094       setPose(pose);
00095     return used;
00096   }
00097   if(strncmp("#MSq",buf,4)!=0) {
00098     // we don't want to display an error here because we may be only testing file type,
00099     // so it's up to the caller to decide if it's necessarily an error if the file isn't
00100     // a motion sequence
00101     //cout << "ERROR MotionSequenceEngine load corrupted - expected #MSq header" << endl;
00102     return 0;
00103   }
00104   unsigned int linenum=1;
00105   unsigned int lastOutputIdx=0;
00106   while(len<=origlen && len>0) {
00107     int written;
00108     //printf("%d %.9s\n",linenum+1,buf);
00109     if(buf[0]=='\r') {
00110       buf++; len--;
00111       if(buf[0]=='\n') {
00112         buf++; len--;
00113       }
00114       linenum++;
00115       continue;
00116     }
00117     if(buf[0]=='\n') {
00118       buf++; len--;
00119       linenum++;
00120       continue;
00121     }
00122     if(buf[0]=='#') {
00123       if(strncmp("#END\n",buf,5)==0 || strncmp("#END\r",buf,5)==0) {
00124         return origlen-len+5;
00125       } else if(strncmp("#END\r\n",buf,6)==0) {
00126         return origlen-len+6;
00127       } else {
00128         while(len>0 && *buf!='\n' && *buf!='\r') {len--;buf++;}
00129         if(*buf=='\n') { //in case of \r\n
00130           buf++;
00131           len--;
00132         }
00133         linenum++;
00134         continue;
00135       }
00136     }
00137     written=-1;
00138     const unsigned int cmdlen=64, arglen=32;
00139     char command[cmdlen];
00140     char arg1[arglen];
00141     char arg2[arglen];
00142     written=readWord(buf,&buf[len],command,cmdlen);
00143     if(!checkInc(written,buf,len,"*** ERROR MotionSequenceEngine load corrupted - line %d\n",linenum)) return 0;
00144     written=readWord(buf,&buf[len],arg1,arglen);
00145     if(written>0)
00146       if(!checkInc(written,buf,len,"*** ERROR MotionSequenceEngine load corrupted - line %d\n",linenum)) return 0;
00147     written=readWord(buf,&buf[len],arg2,arglen);
00148     if(written!=0)
00149       if(!checkInc(written,buf,len,"*** ERROR MotionSequenceEngine load corrupted - line %d\n",linenum)) return 0;
00150     for(;len>0 && *buf!='\n' && *buf!='\r';buf++,len--) {}
00151     if(*buf=='\n') { //in case of \r\n
00152       buf++;
00153       len--;
00154     }
00155 
00156     if(strcasecmp(command,"delay")==0 || strcasecmp(command,"advanceTime")==0) {
00157       char* used;
00158       int delay = strtol(arg1,&used,0);
00159       if(*used!='\0') {
00160         cout << "*** WARNING illegal delay argument: " << arg1 << " - line " << linenum << endl;
00161       } else {
00162         setTime(playtime+delay);
00163       }
00164     } else if(strcasecmp(command,"settime")==0) {
00165       char* used;
00166       int newtime = strtol(arg1,&used,0);
00167       if(*used!='\0') {
00168         cout << "*** WARNING illegal settime argument: " << arg1 << " - line " << linenum << endl;
00169       } else {
00170         setTime(newtime);
00171       }
00172     } else if(strcasecmp(command,"load")==0 || strcasecmp(command,"overlay")==0) {
00173       PostureEngine pose;
00174       if(pose.loadFile(arg1)!=0) {
00175         // it's a posture file
00176         setPose(pose);
00177       } else if(overlayMotion(arg1)!=0) {
00178         // it's a motionsequence file (conditional test did the overlay)
00179       } else {
00180         // unknown file, give warning
00181         cout << "*** WARNING could not read file " << arg1 << " for overlay - line " << linenum << endl;
00182       }
00183     } else if(strcasecmp(command,"loadExplicit")==0) {
00184       PostureEngine pose;
00185       if(pose.loadFile(arg1)!=0) {
00186         setExplicitPose(pose);
00187       } else
00188         cout << "*** WARNING could not read file " << arg1 << " for load (loadExplicit only accepts posture files) - line " << linenum << endl;
00189     } else if(strcasecmp(command,"degrees")==0) {
00190       cout << "*** WARNING 'degrees' is deprecated, please specify all angles as radians" << endl;
00191       loadSaveMode=(float)M_PI/180; //setSaveDegrees();
00192     } else if(strcasecmp(command,"radians")==0) {
00193       setSaveRadians();
00194     } else {
00195       lastOutputIdx=getOutputIndex(command,lastOutputIdx+1);
00196       bool found = (lastOutputIdx!=NumOutputs);
00197       unsigned int lidx=lastOutputIdx,ridx=NumOutputs;
00198       if(!found) { // base name not found
00199         // try symmetric left/right versions
00200         char tname[cmdlen+1];
00201         strncpy(tname+1,command,cmdlen);
00202         tname[0]='L';
00203         lidx=getOutputIndex(tname,lastOutputIdx+1);
00204         if(lidx!=NumOutputs) {
00205           tname[0]='R';
00206           ridx=getOutputIndex(tname,lidx+1);
00207           if(ridx!=NumOutputs)
00208             found=true;
00209         }
00210       }
00211       if (!found) {
00212         cout << "*** WARNING " << command << " is not a valid joint on this model." << endl;
00213       } else {
00214         char* used;
00215         float value=(float)strtod(arg1,&used), weight=1;
00216         if(*used!='\0')
00217           cout << "*** WARNING illegal value argument: " << arg1 << " - line " << linenum << endl;
00218         else {
00219           if(arg2[0]!='\0') {
00220             weight=(float)strtod(arg2,&used);
00221             if(*used!='\0') {
00222                cout << "*** WARNING illegal weight argument: " << arg2 << " - line " << linenum << endl;
00223                weight=1;
00224             }
00225           }
00226           if(lastOutputIdx!=NumOutputs) {
00227             // found exact match earlier
00228             setOutputCmd(lastOutputIdx,OutputCmd(value*loadSaveMode,weight));
00229           } else {
00230             // found symmetric matches earlier
00231             setOutputCmd(lidx,OutputCmd(value*loadSaveMode,weight));
00232             setOutputCmd(ridx,OutputCmd(value*loadSaveMode,weight));
00233             lastOutputIdx=ridx;
00234           }
00235         }
00236       }
00237     }
00238 
00239     linenum++;
00240 
00241   }
00242   cout << "*** WARNING MotionSequenceEngine load missing #END" << endl;
00243   return origlen-len;
00244 }
00245 
00246 unsigned int MotionSequenceEngine::saveBuffer(char buf[], unsigned int len) const {
00247   //std::cout << "SAVEBUFFER..." << std::flush;
00248   unsigned int origlen=len;
00249   int written=snprintf(buf,len,"#MSq\n");
00250   if(!checkInc(written,buf,len,"*** ERROR MotionSequenceEngine save failed on header\n")) return 0; if(len==0 || len>origlen) {
00251     cout << "*** ERROR MotionSequenceEngine save overflow on header" << endl;
00252     return 0;
00253   }
00254   written=snprintf(buf,len,isSaveRadians()?"radians\n":"degrees\n");
00255   if(!checkInc(written,buf,len,"*** ERROR MotionSequenceEngine save failed on mode\n")) return 0; if(len==0 || len>origlen) {
00256     cout << "*** ERROR MotionSequenceEngine save overflow" << endl;
00257     return 0;
00258   }
00259   unsigned int t=0;
00260   Move_idx_t tprevs[NumOutputs];
00261   Move_idx_t tnexts[NumOutputs];
00262   bool hasInitialFrame=false;
00263   for(unsigned int i=0;i<NumOutputs;i++) {
00264     tnexts[i]=getKeyFrame(tprevs[i]=starts[i]).next;
00265     if(getKeyFrame(starts[i]).cmd.weight!=0)
00266       hasInitialFrame=true;
00267   }
00268   if(hasInitialFrame) {
00269     written=snprintf(buf,len,"setTime\t0\n");
00270     if(!checkInc(written,buf,len,"*** ERROR MotionSequenceEngine save failed on initial frame spec\n")) return 0;
00271   }
00272   while(t!=-1U) {
00273     //std::cout << "t="<<t<<"..."<<std::endl;
00274     for(unsigned int i=0; i<NumOutputs; i++) {
00275       //cout << i << ' ' << outputNames[i] << " (" << getKeyFrame(tprevs[i]).cmd.value << ',' << getKeyFrame(tprevs[i]).cmd.weight << ") " << getKeyFrame(tprevs[i]).starttime << " state: " << starts[i] <<' '<< prevs[i] <<' '<< nexts[i] << " cur: " << getKeyFrame(tprevs[i]).prev << ' ' << tprevs[i] << ' ' << getKeyFrame(tprevs[i]).next << endl;
00276       //first conditional is to skip 0 weighted values in first frame
00277       if((t!=0 || getKeyFrame(tprevs[i]).cmd.weight!=0) && getKeyFrame(tprevs[i]).starttime==t) {
00278         if(getKeyFrame(tprevs[i]).cmd.weight==1) {
00279           written=snprintf(buf,len,"%s\t%g\n",outputNames[i],getKeyFrame(tprevs[i]).cmd.value/loadSaveMode);
00280           if(!checkInc(written,buf,len,"*** ERROR MotionSequenceEngine save failed\n")) return 0;
00281         } else {
00282           written=snprintf(buf,len,"%s\t%g\t%g\n",outputNames[i],getKeyFrame(tprevs[i]).cmd.value/loadSaveMode,getKeyFrame(tprevs[i]).cmd.weight);
00283           if(!checkInc(written,buf,len,"*** ERROR MotionSequenceEngine save failed\n")) return 0;
00284         }
00285         if(len==0 || len>origlen) {
00286           cout << "*** ERROR MotionSequenceEngine save overflow" << endl;
00287           return 0;
00288         }
00289       }
00290     }
00291     unsigned int last=t;
00292     t=setNextFrameTime(tprevs,tnexts);
00293     if(t!=-1U) {
00294       written=snprintf(buf,len,"delay\t%d\n",t-last);
00295       if(!checkInc(written,buf,len,"*** ERROR MotionSequenceEngine save failed\n")) return 0;
00296       if(len==0 || len>origlen) {
00297         cout << "*** ERROR MotionSequenceEngine save overflow" << endl;
00298         return 0;
00299       }
00300     }
00301   }
00302   written=snprintf(buf,len,"#END\n");
00303   if(!checkInc(written,buf,len,"*** ERROR MotionSequenceEngine save failed on #END\n")) return 0;
00304   if(len==0 || len>origlen) {
00305     cout << "*** ERROR MotionSequenceEngine save overflow on #END" << endl;
00306     return 0;
00307   }
00308   return origlen-len;
00309   cout << "SAVE-done!" << endl;
00310 }
00311 
00312 unsigned int MotionSequenceEngine::loadFile(const char filename[]) {
00313   return LoadSave::loadFile(config->motion.makePath(filename).c_str());
00314 }
00315 unsigned int MotionSequenceEngine::saveFile(const char filename[]) const {
00316   return LoadSave::saveFile(config->motion.makePath(filename).c_str());
00317 }
00318 
00319 /*! @deprecated use radians instead (we don't have a good way to know which output values are angles, and which are 'other', e.g. wheel velocities or LED brightness...) */
00320 void MotionSequenceEngine::setSaveDegrees() { loadSaveMode=(float)M_PI/180; }
00321 
00322 void MotionSequenceEngine::setTime(unsigned int x) {
00323   playtime=x;
00324   const WorldState * st=WorldState::getCurrent();
00325   for(unsigned int i=0; i<NumOutputs; i++) {
00326     if(setRange(x,prevs[i],nexts[i])) {
00327       OutputCmd& cmd=getKeyFrame((playspeed<0)?nexts[i]:prevs[i]).cmd;
00328       if(cmd.weight<=0)
00329         cmd.value=st->outputs[i];
00330     }
00331   }
00332 }
00333 
00334 void MotionSequenceEngine::setOutputCmd(unsigned int i, const OutputCmd& cmd) {
00335   Move& p_m=getKeyFrame(prevs[i]);
00336   if(playtime==p_m.starttime) { //edit current keyframe
00337     p_m.cmd=cmd;
00338   } else { //add new keyframe
00339     Move_idx_t x = newKeyFrame();
00340     if(x==invalid_move) //ran out of memory - newKeyFrame should report error, we can silently die
00341       return;
00342     Move& cur=getKeyFrame(x);
00343     Move& prev_m=getKeyFrame(prevs[i]); //it's important to refresh this - newKeyFrame may have invalidated p_m reference
00344     cur.cmd=cmd;
00345     cur.starttime=playtime;
00346     cur.prev=prevs[i];
00347     cur.next=nexts[i];
00348     prev_m.next=x;
00349     if(nexts[i]!=invalid_move) //in middle
00350       getKeyFrame(nexts[i]).prev=x;
00351     else { //at end
00352       if(playtime>endtime)
00353         endtime=playtime;
00354     }
00355     prevs[i]=x;
00356 //    cout << "set " << i << ' ' << outputNames[i] << ' ' << cur.cmd.value << ' ' << cur.cmd.weight << ' ' << cur.starttime << " state: " << starts[i] <<' '<< prevs[i] <<' '<< prev_m.next <<' '<< nexts[i] << " new: " << cur.prev << ' ' << x << ' ' << cur.next << endl;
00357   }
00358   curstamps[i]=-1U;
00359 }
00360 
00361 void MotionSequenceEngine::setPose(const PostureEngine& pose) {
00362   for(unsigned int i=0; i<NumOutputs; i++)
00363     if(pose.getOutputCmd(i).weight>0)
00364       setOutputCmd(i,pose.getOutputCmd(i));
00365 }
00366 
00367 void MotionSequenceEngine::setExplicitPose(const PostureEngine& pose) {
00368   for(unsigned int i=0; i<NumOutputs; i++)
00369     setOutputCmd(i,pose.getOutputCmd(i));
00370 }
00371 
00372 PostureEngine MotionSequenceEngine::getPose() {
00373   PostureEngine pose;
00374   getPose(pose);
00375   return pose;
00376 }
00377 
00378 void MotionSequenceEngine::getPose(PostureEngine& pose) {
00379   for(unsigned int i=0; i<NumOutputs; i++)
00380     pose.setOutputCmd(i,getOutputCmd(i));
00381 }
00382 
00383 unsigned int MotionSequenceEngine::overlayMotion(const std::string& msFile) {
00384   DynamicMotionSequence ms;
00385   if(ms.loadFile(msFile.c_str())==0)
00386     return 0;
00387   overlayMotion(ms);
00388   return ms.getEndTime();
00389 }
00390 
00391 /*! @todo should better handle conflicts with keyframes in original motion
00392  *  
00393  *  This is not a particularly well implemented function -- it will interleave
00394  *  @a ms's keyframes with any pre-existing ones, but will clobber frames which
00395  *  coincide with @a ms's own.  Probably will not give the desired effect when
00396  *  the motion is actually overlaying something, but it will work for basic
00397  *  usage cases. */
00398 void MotionSequenceEngine::overlayMotion(const MotionSequenceEngine& ms) {
00399   //merge keyframes for each output, advance playhead by ms.endtime at the end
00400   for(unsigned int i=0; i<NumOutputs; i++) {
00401     //cout << "Processing " << outputNames[i] << ":" << endl;
00402     Move_idx_t myPrevIdx=prevs[i];
00403     unsigned int myPrevTime=getKeyFrame(prevs[i]).starttime;
00404     Move_idx_t myNextIdx=getKeyFrame(myPrevIdx).next;
00405     unsigned int myNextTime=-1U;
00406     if(myNextIdx!=invalid_move)
00407       myNextTime=getKeyFrame(myNextIdx).starttime;
00408     for(Move_idx_t curOtherIdx=ms.starts[i]; curOtherIdx!=invalid_move; curOtherIdx=ms.getKeyFrame(curOtherIdx).next) {
00409       const Move& curOther=ms.getKeyFrame(curOtherIdx);
00410       while(myNextTime <= curOther.starttime+getTime()) {
00411         //cout << "Advancing to " << myNextTime << endl;
00412         myPrevIdx=myNextIdx;
00413         myPrevTime=myNextTime;
00414         myNextIdx=getKeyFrame(myPrevIdx).next;
00415         myNextTime= (myNextIdx==invalid_move ? -1U : getKeyFrame(myNextIdx).starttime);
00416       }
00417       if(curOther.cmd.weight > 0) {
00418         if(curOther.starttime+getTime() == myPrevTime) {
00419           //replace current 'prev'
00420           //cout << "replacing frame " << myPrevIdx << " at " << myPrevTime << endl;
00421           getKeyFrame(myPrevIdx).cmd=curOther.cmd;
00422         } else {
00423           //insert new keyframe between 'prev' and 'next'
00424           Move_idx_t insIdx=newKeyFrame();
00425           //cout << "adding new frame at " << curOther.starttime+getTime() << " with index " << insIdx << endl;
00426           if(insIdx==invalid_move)
00427             return; //newKeyFrame should have reported error, we can silently return
00428           Move& ins=getKeyFrame(insIdx);
00429           ins.prev=myPrevIdx;
00430           ins.next=myNextIdx;
00431           ins.cmd=curOther.cmd;
00432           ins.starttime=curOther.starttime+getTime();
00433           getKeyFrame(myPrevIdx).next=insIdx;
00434           if(myNextIdx!=invalid_move)
00435             getKeyFrame(myNextIdx).prev=insIdx;
00436           if(myPrevIdx==prevs[i]) {
00437             nexts[i]=insIdx;
00438             curstamps[i]=-1U;
00439           }
00440           myPrevIdx=insIdx; //inserted frame is now 'prev'
00441           myPrevTime=ins.starttime;
00442           if(myPrevTime>endtime)
00443             endtime=myPrevTime;
00444         }
00445       }
00446     }
00447   }
00448   advanceTime(ms.getEndTime());
00449 }
00450 
00451 void MotionSequenceEngine::compress() {
00452   for(unsigned int i=0; i<NumOutputs; i++) {
00453     Move_idx_t prev=getKeyFrame(starts[i]).next;
00454     if(prev==invalid_move)
00455       break;
00456     Move_idx_t cur=getKeyFrame(prev).next;
00457     if(cur==invalid_move)
00458       break;
00459     Move_idx_t next=getKeyFrame(cur).next;
00460     while(next!=invalid_move) {
00461       OutputCmd tmp;
00462       Move& prev_m=getKeyFrame(prev);
00463       Move& cur_m=getKeyFrame(cur);
00464       Move& next_m=getKeyFrame(next);
00465       calcOutput(tmp,cur_m.starttime,prev_m,next_m);
00466       if(tmp==cur_m.cmd || (tmp.weight==0 && cur_m.cmd.weight==0) ) {
00467         prev_m.next=next;
00468         next_m.prev=prev;
00469         eraseKeyFrame(cur);
00470       } else
00471         prev=cur;
00472       cur=next;
00473       next=next_m.next;
00474     }
00475   }
00476 }
00477 
00478 void MotionSequenceEngine::makeSafe(const float vels[NumOutputs], float margin) {
00479   float comps[NumOutputs];
00480   for(unsigned int i=0;i<NumOutputs;i++)
00481     comps[i]=vels[i]*margin;
00482   unsigned int t=0;
00483   Move_idx_t tprevs[NumOutputs];
00484   Move_idx_t tnexts[NumOutputs];
00485   for(unsigned int i=0;i<NumOutputs;i++) {
00486     tnexts[i]=getKeyFrame(tprevs[i]=starts[i]).next;
00487     curstamps[i]=-1U;
00488   }
00489   while(t!=-1U) {
00490     for(unsigned int i=0; i<NumOutputs; i++) {
00491       //second and third conditionals are to skip transitions between 0 weighted frames
00492       if(tnexts[i]!=invalid_move && (getKeyFrame(tprevs[i]).cmd.weight!=0 || getKeyFrame(tnexts[i]).cmd.weight!=0) && getKeyFrame(tprevs[i]).starttime==t) {
00493         float dv=std::abs(getKeyFrame(tprevs[i]).cmd.value-getKeyFrame(tnexts[i]).cmd.value);
00494         unsigned int dt=getKeyFrame(tnexts[i]).starttime-getKeyFrame(tprevs[i]).starttime;
00495         if(dv/dt>comps[i]) {
00496           unsigned int delay=(unsigned int)(dv/comps[i])-dt;
00497           for(unsigned int j=0; j<NumOutputs; j++)
00498             for(Move_idx_t c=tnexts[j]; c!=invalid_move; c=getKeyFrame(c).next)
00499               getKeyFrame(c).starttime+=delay;
00500         }
00501       }
00502     }
00503     t=setNextFrameTime(tprevs,tnexts);
00504   }
00505   
00506 } 
00507 
00508 bool MotionSequenceEngine::isPlaying() {
00509   return playing && ((playspeed>0) ? (playtime<endtime) : (playtime>0)); 
00510 }
00511 
00512 
00513 void MotionSequenceEngine::play() {
00514   if(playspeed>0)
00515     setTime(0);
00516   else
00517     setTime(endtime);
00518   resume();
00519 }
00520 
00521 void MotionSequenceEngine::resume() {
00522   playing=true;
00523   lasttime=get_time();
00524   const WorldState * st=WorldState::getCurrent();
00525   for(unsigned int i=0; i<NumOutputs; i++) {
00526     Move_idx_t cur=starts[i];
00527     while(cur!=invalid_move) {
00528       if(getKeyFrame(cur).cmd.weight!=0) {
00529         getKeyFrame(starts[i]).cmd.value=st->outputs[i];
00530         break;
00531       }
00532       cur=getKeyFrame(cur).next;
00533     }
00534   }
00535 }
00536 
00537 unsigned int MotionSequenceEngine::setNextFrameTime(Move_idx_t p[NumOutputs], Move_idx_t n[NumOutputs]) const {
00538   unsigned int ans=-1U;
00539   for(unsigned int i=0; i<NumOutputs; i++)
00540     if(n[i]!=invalid_move && getKeyFrame(n[i]).starttime<ans)
00541       ans=getKeyFrame(n[i]).starttime;
00542   if(ans!=-1U) {
00543     const WorldState * st=WorldState::getCurrent();
00544     for(unsigned int i=0; i<NumOutputs; i++) {
00545       if(setRange(ans,p[i],n[i])) {
00546         const OutputCmd& cmd=getKeyFrame((playspeed<0)?n[i]:p[i]).cmd;
00547         if(cmd.weight<=0)
00548           const_cast<OutputCmd&>(cmd).value=st->outputs[i]; //it's ok to assign the value when weight is '0', still "const"... kinda
00549       }
00550     }
00551   }
00552   return ans;
00553 }
00554 
00555 unsigned int MotionSequenceEngine::readWord(const char buf[], const char * const bufend, char wrd[], const unsigned int wordlen) {
00556   const char* origbuf=buf;
00557   wrd[0]='\0';
00558   unsigned int i;
00559   //skip whitespace
00560   for(;buf<bufend && isspace(*buf) && *buf!='\n' && *buf!='\r';buf++) {}
00561   //store wrd
00562   for(i=0; buf<bufend && !isspace(*buf); buf++)
00563     if(i<wordlen-1)
00564       wrd[i++]=*buf;
00565   wrd[i]='\0';
00566   if(buf>=bufend)
00567     return -1U;
00568   return buf-origbuf;
00569 }
00570 
00571 unsigned int MotionSequenceEngine::getOutputIndex(const char name[], unsigned int idx) {
00572   unsigned int n=strlen(name);
00573   while(name[n-1]=='~')
00574     --n;
00575   if(idx<NumOutputs) {
00576     unsigned int startidx=idx;
00577     for(;idx<NumOutputs;idx++)
00578       if(strncmp(name,outputNames[idx],n)==0)
00579         return idx;
00580     for(idx=0;idx<startidx;idx++)
00581       if(strncmp(name,outputNames[idx],n)==0)
00582         return idx;
00583     return NumOutputs;
00584   } else {
00585     for(idx=0;idx<NumOutputs;idx++)
00586       if(strncmp(name,outputNames[idx],n)==0)
00587         return idx;
00588     return idx;
00589   }
00590 }
00591 
00592 /*! @file
00593  * @brief Implements MotionSequenceEngine, abstract code for smoothly transitioning between a sequence of postures
00594  * @author ejt (Creator)
00595  */
00596 

Tekkotsu v5.1CVS
Generated Mon May 9 04:58:45 2016 by Doxygen 1.6.3