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=-1U;
00012 
00013 MotionSequenceEngine::MotionSequenceEngine()
00014 : LoadSave(), playtime(1), lasttime(0), endtime(0), playspeed(1.0),
00015 playing(true), hold(true), loadSaveMode(M_PI/180)
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) {
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=16, 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       setSaveDegrees();
00191     } else if(strcasecmp(command,"radians")==0) {
00192       setSaveRadians();
00193     } else {
00194       lastOutputIdx=getOutputIndex(command,lastOutputIdx+1);
00195       bool found = (lastOutputIdx!=NumOutputs);
00196       unsigned int lidx=lastOutputIdx,ridx=NumOutputs;
00197       if(!found) { // base name not found
00198         // try symmetric left/right versions
00199         char tname[cmdlen+1];
00200         strncpy(tname+1,command,cmdlen);
00201         tname[0]='L';
00202         lidx=getOutputIndex(tname,lastOutputIdx+1);
00203         if(lidx!=NumOutputs) {
00204           tname[0]='R';
00205           ridx=getOutputIndex(tname,lidx+1);
00206           if(ridx!=NumOutputs)
00207             found=true;
00208         }
00209       }
00210       if (!found) {
00211         cout << "*** WARNING " << command << " is not a valid joint on this model." << endl;
00212       } else {
00213         char* used;
00214         double value=strtod(arg1,&used), weight=1;
00215         if(*used!='\0')
00216           cout << "*** WARNING illegal value argument: " << arg1 << " - line " << linenum << endl;
00217         else {
00218           if(arg2[0]!='\0') {
00219             weight=strtod(arg2,&used);
00220             if(*used!='\0') {
00221                cout << "*** WARNING illegal weight argument: " << arg2 << " - line " << linenum << endl;
00222                weight=1;
00223             }
00224           }
00225           if(lastOutputIdx!=NumOutputs) {
00226             // found exact match earlier
00227             setOutputCmd(lastOutputIdx,OutputCmd(value*loadSaveMode,weight));
00228           } else {
00229             // found symmetric matches earlier
00230             setOutputCmd(lidx,OutputCmd(value*loadSaveMode,weight));
00231             setOutputCmd(ridx,OutputCmd(value*loadSaveMode,weight));
00232             lastOutputIdx=ridx;
00233           }
00234         }
00235       }
00236     }
00237 
00238     linenum++;
00239 
00240   }
00241   cout << "*** WARNING MotionSequenceEngine load missing #END" << endl;
00242   return origlen-len;
00243 }
00244 
00245 unsigned int MotionSequenceEngine::saveBuffer(char buf[], unsigned int len) const {
00246   //std::cout << "SAVEBUFFER..." << std::flush;
00247   unsigned int origlen=len;
00248   int written=snprintf(buf,len,"#MSq\n");
00249   if(!checkInc(written,buf,len,"*** ERROR MotionSequenceEngine save failed on header\n")) return 0; if(len==0 || len>origlen) {
00250     cout << "*** ERROR MotionSequenceEngine save overflow on header" << endl;
00251     return 0;
00252   }
00253   written=snprintf(buf,len,isSaveRadians()?"radians\n":"degrees\n");
00254   if(!checkInc(written,buf,len,"*** ERROR MotionSequenceEngine save failed on mode\n")) return 0; if(len==0 || len>origlen) {
00255     cout << "*** ERROR MotionSequenceEngine save overflow" << endl;
00256     return 0;
00257   }
00258   unsigned int t=0;
00259   Move_idx_t tprevs[NumOutputs];
00260   Move_idx_t tnexts[NumOutputs];
00261   bool hasInitialFrame=false;
00262   for(unsigned int i=0;i<NumOutputs;i++) {
00263     tnexts[i]=getKeyFrame(tprevs[i]=starts[i]).next;
00264     if(getKeyFrame(starts[i]).cmd.weight!=0)
00265       hasInitialFrame=true;
00266   }
00267   if(hasInitialFrame) {
00268     written=snprintf(buf,len,"setTime\t0\n");
00269     if(!checkInc(written,buf,len,"*** ERROR MotionSequenceEngine save failed on initial frame spec\n")) return 0;
00270   }
00271   while(t!=-1U) {
00272     //std::cout << "t="<<t<<"..."<<std::endl;
00273     for(unsigned int i=0; i<NumOutputs; i++) {
00274       //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;
00275       //first conditional is to skip 0 weighted values in first frame
00276       if((t!=0 || getKeyFrame(tprevs[i]).cmd.weight!=0) && getKeyFrame(tprevs[i]).starttime==t) {
00277         if(getKeyFrame(tprevs[i]).cmd.weight==1) {
00278           written=snprintf(buf,len,"%s\t%g\n",outputNames[i],getKeyFrame(tprevs[i]).cmd.value/loadSaveMode);
00279           if(!checkInc(written,buf,len,"*** ERROR MotionSequenceEngine save failed\n")) return 0;
00280         } else {
00281           written=snprintf(buf,len,"%s\t%g\t%g\n",outputNames[i],getKeyFrame(tprevs[i]).cmd.value/loadSaveMode,getKeyFrame(tprevs[i]).cmd.weight);
00282           if(!checkInc(written,buf,len,"*** ERROR MotionSequenceEngine save failed\n")) return 0;
00283         }
00284         if(len==0 || len>origlen) {
00285           cout << "*** ERROR MotionSequenceEngine save overflow" << endl;
00286           return 0;
00287         }
00288       }
00289     }
00290     unsigned int last=t;
00291     t=setNextFrameTime(tprevs,tnexts);
00292     if(t!=-1U) {
00293       written=snprintf(buf,len,"delay\t%d\n",t-last);
00294       if(!checkInc(written,buf,len,"*** ERROR MotionSequenceEngine save failed\n")) return 0;
00295       if(len==0 || len>origlen) {
00296         cout << "*** ERROR MotionSequenceEngine save overflow" << endl;
00297         return 0;
00298       }
00299     }
00300   }
00301   written=snprintf(buf,len,"#END\n");
00302   if(!checkInc(written,buf,len,"*** ERROR MotionSequenceEngine save failed on #END\n")) return 0;
00303   if(len==0 || len>origlen) {
00304     cout << "*** ERROR MotionSequenceEngine save overflow on #END" << endl;
00305     return 0;
00306   }
00307   return origlen-len;
00308   cout << "SAVE-done!" << endl;
00309 }
00310 
00311 unsigned int MotionSequenceEngine::loadFile(const char filename[]) {
00312   return LoadSave::loadFile(config->motion.makePath(filename).c_str());
00313 }
00314 unsigned int MotionSequenceEngine::saveFile(const char filename[]) const {
00315   return LoadSave::saveFile(config->motion.makePath(filename).c_str());
00316 }
00317 
00318 void MotionSequenceEngine::setTime(unsigned int x) {
00319   playtime=x;
00320   WorldState * st=WorldState::getCurrent();
00321   for(unsigned int i=0; i<NumOutputs; i++) {
00322     if(setRange(x,prevs[i],nexts[i])) {
00323       OutputCmd& cmd=getKeyFrame((playspeed<0)?nexts[i]:prevs[i]).cmd;
00324       if(cmd.weight<=0)
00325         cmd.value=st->outputs[i];
00326     }
00327   }
00328 }
00329 
00330 void MotionSequenceEngine::setOutputCmd(unsigned int i, const OutputCmd& cmd) {
00331   Move& p_m=getKeyFrame(prevs[i]);
00332   if(playtime==p_m.starttime) { //edit current keyframe
00333     p_m.cmd=cmd;
00334   } else { //add new keyframe
00335     Move_idx_t x = newKeyFrame();
00336     if(x==invalid_move) //ran out of memory - newKeyFrame should report error, we can silently die
00337       return;
00338     Move& cur=getKeyFrame(x);
00339     Move& prev_m=getKeyFrame(prevs[i]); //it's important to refresh this - newKeyFrame may have invalidated p_m reference
00340     cur.cmd=cmd;
00341     cur.starttime=playtime;
00342     cur.prev=prevs[i];
00343     cur.next=nexts[i];
00344     prev_m.next=x;
00345     if(nexts[i]!=invalid_move) //in middle
00346       getKeyFrame(nexts[i]).prev=x;
00347     else { //at end
00348       if(playtime>endtime)
00349         endtime=playtime;
00350     }
00351     prevs[i]=x;
00352 //    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;
00353   }
00354   curstamps[i]=-1U;
00355 }
00356 
00357 void MotionSequenceEngine::setPose(const PostureEngine& pose) {
00358   for(unsigned int i=0; i<NumOutputs; i++)
00359     if(pose.getOutputCmd(i).weight>0)
00360       setOutputCmd(i,pose.getOutputCmd(i));
00361 }
00362 
00363 void MotionSequenceEngine::setExplicitPose(const PostureEngine& pose) {
00364   for(unsigned int i=0; i<NumOutputs; i++)
00365     setOutputCmd(i,pose.getOutputCmd(i));
00366 }
00367 
00368 void MotionSequenceEngine::overlayPose(const PostureEngine& pose) {
00369   setPose(pose);
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=fabs(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   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     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   if(idx<NumOutputs) {
00573     unsigned int startidx=idx;
00574     for(;idx<NumOutputs;idx++)
00575       if(strcmp(name,outputNames[idx])==0)
00576         return idx;
00577     for(idx=0;idx<startidx;idx++)
00578       if(strcmp(name,outputNames[idx])==0)
00579         return idx;
00580     return NumOutputs;
00581   } else {
00582     for(idx=0;idx<NumOutputs;idx++)
00583       if(strcmp(name,outputNames[idx])==0)
00584         return idx;
00585     return idx;
00586   }
00587 }
00588 
00589 /*! @file
00590  * @brief Implements MotionSequenceEngine, abstract code for smoothly transitioning between a sequence of postures
00591  * @author ejt (Creator)
00592  *
00593  * $Author: ejt $
00594  * $Name: tekkotsu-3_0 $
00595  * $Revision: 1.15 $
00596  * $State: Exp $
00597  * $Date: 2006/09/23 19:51:11 $
00598  */
00599 

Tekkotsu v3.0
Generated Wed Oct 4 00:03:44 2006 by Doxygen 1.4.7