TurtleMobility.cc

00001 //
00002 // Copyright (C) 2005 Andras Varga
00003 //
00004 // This program is free software; you can redistribute it and/or
00005 // modify it under the terms of the GNU General Public License
00006 // as published by the Free Software Foundation; either version 2
00007 // of the License, or (at your option) any later version.
00008 //
00009 // This program is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU General Public License
00015 // along with this program; if not, write to the Free Software
00016 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00017 //
00018 
00019 #include "TurtleMobility.h"
00020 #include "FWMath.h"
00021 
00022 
00023 Define_Module(TurtleMobility);
00024 
00025 
00031 void TurtleMobility::initialize(int stage)
00032 {
00033     LineSegmentsMobilityBase::initialize(stage);
00034 
00035     debugEV << "initializing TurtleMobility stage " << stage << endl;
00036 
00037     if(stage == 0)
00038     {
00039         turtleScript = par("turtleScript");
00040         nextStatement = turtleScript->getFirstChild();
00041 
00042         move.setSpeed(1);
00043         angle = 0;
00044         borderPolicy = REFLECT;
00045 
00046         // a dirty trick to extract starting position out of the script
00047         // (start doing it, but then rewind to the beginning)
00048 
00049   // does not really work
00050   // we need to  set the startPos initially for which there is no option in
00051   // turtlemobility
00052   // -> always starting with random position... (Daniel)
00053         //resumeScript();
00054         //nextStatement = turtleScript->getFirstChild();
00055         //while (!loopVars.empty()) loopVars.pop();
00056 
00057         // WATCH for member 'speed' of the Move is disabled at the moment
00058         // because the member is not accessible directly anymore
00059         //WATCH(move.speed);
00060         WATCH(angle);
00061         WATCH(borderPolicy);
00062     }
00063     else if(stage == 1){
00064       if(!world->use2D()) {
00065       opp_warning("This mobility module does not yet support 3 dimensional movement."\
00066             "Movements will probably be incorrect.");
00067     }
00068 
00069     targetPos = move.getStartPos();
00070     stepTarget = move.getStartPos();
00071     targetTime = simTime();
00072     }
00073 }
00074 
00075 void TurtleMobility::setTargetPosition()
00076 {
00077     resumeScript();
00078 
00079     move.setStart(move.getStartPos(), simTime());
00080 }
00081 
00082 void TurtleMobility::fixIfHostGetsOutside()
00083 {
00084   debugEV << "stepTarget: " << stepTarget.info() << " targetPos: " << targetPos.info() << " stepSize: " << stepSize.info()
00085        << " angle: " << angle << endl;
00086 
00087     if( handleIfOutside(borderPolicy, stepTarget, targetPos, stepSize, angle) ){
00088 
00089       debugEV << "stepTarget: " << stepTarget.info() << " targetPos: " << targetPos.info() << " stepSize: " << stepSize.info()
00090      << " angle: " << angle << endl;
00091 
00092     }
00093 }
00094 
00098 void TurtleMobility::resumeScript()
00099 {
00100     if (!nextStatement)
00101     {
00102   move.setSpeed(0);
00103   debugEV << "no statement found -> not moving!\n";
00104         return;
00105     }
00106 
00107     simtime_t now = targetTime;
00108 
00109     // interpret statement
00110     while (nextStatement && targetTime==now)
00111     {
00112         executeStatement(nextStatement);
00113         gotoNextStatement();
00114     }
00115 }
00116 
00117 void TurtleMobility::executeStatement(cXMLElement *stmt)
00118 {
00119     const char *tag = stmt->getTagName();
00120 
00121     debugEV << "doing <" << tag << ">\n";
00122 
00123     if (!strcmp(tag,"repeat"))
00124     {
00125         const char *nAttr = stmt->getAttribute("n");
00126         long n = -1;  // infinity -- that's the default
00127         if (nAttr)
00128         {
00129             n = (long) getValue(nAttr);
00130             if (n<0)
00131                 error("<repeat>: negative repeat count at %s", stmt->getSourceLocation());
00132         }
00133         loopVars.push(n);
00134     }
00135 
00136 
00137     else if (!strcmp(tag,"set"))
00138     {
00139         const char *speedAttr = stmt->getAttribute("speed");
00140         const char *angleAttr = stmt->getAttribute("angle");
00141         const char *xAttr = stmt->getAttribute("x");
00142         const char *yAttr = stmt->getAttribute("y");
00143         const char *bpAttr = stmt->getAttribute("borderPolicy");
00144         if (speedAttr)
00145             move.setSpeed(getValue(speedAttr));
00146         if (angleAttr)
00147             angle = getValue(angleAttr);
00148         if (xAttr)
00149             targetPos.setX(getValue(xAttr));
00150         if (yAttr)
00151             targetPos.setY(getValue(yAttr));
00152         if (move.getSpeed()<=0)
00153             error("<set>: speed is negative or zero at %s", stmt->getSourceLocation());
00154         if (bpAttr)
00155         {
00156             if (!strcmp(bpAttr,"reflect"))
00157                 borderPolicy = REFLECT;
00158             else if (!strcmp(bpAttr,"wrap"))
00159                 borderPolicy = WRAP;
00160             else if (!strcmp(bpAttr,"placerandomly"))
00161                 borderPolicy = PLACERANDOMLY;
00162 
00163             else if (!strcmp(bpAttr,"error"))
00164                 borderPolicy = RAISEERROR;
00165             else
00166                 error("<set>: value for attribute borderPolicy is invalid, should be "
00167                       "'reflect', 'wrap', 'placerandomly' or 'error' at %s",
00168                       stmt->getSourceLocation());
00169         }
00170     }
00171     else if (!strcmp(tag,"forward"))
00172     {
00173         const char *dAttr = stmt->getAttribute("d");
00174         const char *tAttr = stmt->getAttribute("t");
00175         if (!dAttr && !tAttr)
00176             error("<forward>: must have at least attribute 't' or 'd' (or both) at %s", stmt->getSourceLocation());
00177         double d, t;
00178         if (tAttr && dAttr)
00179         {
00180             // cover distance d in time t (current speed is ignored)
00181             d = getValue(dAttr);
00182             t = getValue(tAttr);
00183         }
00184         else if (dAttr)
00185         {
00186             // travel distance d at current speed
00187             d = getValue(dAttr);
00188             t = d / move.getSpeed();
00189         }
00190         else // tAttr only
00191         {
00192             // travel for time t at current speed
00193             t = getValue(tAttr);
00194             d = move.getSpeed() * t;
00195         }
00196         if (t<0)
00197             error("<forward>: time (attribute t) is negative at %s", stmt->getSourceLocation());
00198         if (d<0)
00199             error("<forward>: distance (attribute d) is negative at %s", stmt->getSourceLocation());
00200         // FIXME handle zeros properly...
00201         targetPos.setX(targetPos.getX() + d * cos(PI * angle / 180));
00202         targetPos.setY(targetPos.getY() + d * sin(PI * angle / 180));
00203         targetTime += t;
00204     }
00205     else if (!strcmp(tag,"turn"))
00206     {
00207         const char *angleAttr = stmt->getAttribute("angle");
00208         if (!angleAttr)
00209             error("<turn>: required attribute 'angle' missing at %s", stmt->getSourceLocation());
00210         angle += getValue(angleAttr);
00211     }
00212     else if (!strcmp(tag,"wait"))
00213     {
00214         const char *tAttr = stmt->getAttribute("t");
00215         if (!tAttr)
00216             error("<wait>: required attribute 't' missing at %s", stmt->getSourceLocation());
00217         simtime_t t = getValue(tAttr);
00218         if (t<0)
00219             error("<wait>: time (attribute t) is negative (%s) at %s", SIMTIME_STR(t), stmt->getSourceLocation());
00220         targetTime += t;  // targetPos is unchanged
00221     }
00222     else if (!strcmp(tag,"moveto"))
00223     {
00224         const char *xAttr = stmt->getAttribute("x");
00225         const char *yAttr = stmt->getAttribute("y");
00226         const char *tAttr = stmt->getAttribute("t");
00227 
00228         if (xAttr)
00229             targetPos.setX(getValue(xAttr));
00230         if (yAttr)
00231             targetPos.setY(getValue(yAttr));
00232         // travel to targetPos at current speed, or get there in time t (ignoring current speed then)
00233         simtime_t t = tAttr ? getValue(tAttr) : move.getStartPos().distance(targetPos)/move.getSpeed();
00234         if (t<0)
00235             error("<wait>: time (attribute t) is negative at %s", stmt->getSourceLocation());
00236         targetTime += t;
00237     }
00238     else if (!strcmp(tag,"moveby"))
00239     {
00240         const char *xAttr = stmt->getAttribute("x");
00241         const char *yAttr = stmt->getAttribute("y");
00242         const char *tAttr = stmt->getAttribute("t");
00243         if (xAttr)
00244             targetPos.setX(targetPos.getX() + getValue(xAttr));
00245         if (yAttr)
00246             targetPos.setY(targetPos.getY() + getValue(yAttr));
00247         // travel to targetPos at current speed, or get there in time t (ignoring current speed then)
00248         simtime_t t = tAttr ? getValue(tAttr) : move.getStartPos().distance(targetPos)/move.getSpeed();
00249         if (t<0)
00250             error("<wait>: time (attribute t) is negative at %s", stmt->getSourceLocation());
00251         targetTime += t;
00252     }
00253 }
00254 
00255 double TurtleMobility::getValue(const char *s)
00256 {
00257     // first, textually replace $MAXX and $MAXY with their actual values
00258     std::string str;
00259     if (strchr(s,'$'))
00260     {
00261         char strMaxX[32], strMaxY[32];
00262         sprintf(strMaxX, "%g", playgroundSizeX()-1);
00263         sprintf(strMaxY, "%g", playgroundSizeY()-1);
00264 
00265         str = s;
00266         std::string::size_type pos;
00267         while ((pos = str.find("$MAXX")) != std::string::npos)
00268             str.replace(pos, sizeof("$MAXX")-1, strMaxX);
00269         while ((pos = str.find("$MAXY")) != std::string::npos)
00270             str.replace(pos, sizeof("$MAXY")-1, strMaxY);
00271         s = str.c_str();
00272     }
00273 
00274     // then use cMsgPar to evaluate the string
00275     cMsgPar tmp;
00276     if (!tmp.parse(s,'?'))
00277         error("wrong value '%s' around %s", s, nextStatement->getSourceLocation());
00278     return tmp.doubleValue();
00279 }
00280 
00281 void TurtleMobility::gotoNextStatement()
00282 {
00283     // "statement either doesn't have a child, or it's a <repeat> and loop count is already pushed on the stack"
00284     ASSERT(!nextStatement->getFirstChild() || (!strcmp(nextStatement->getTagName(),"repeat") && !loopVars.empty()));
00285 
00286     if (nextStatement->getFirstChild() && (loopVars.top()!=0 || (loopVars.pop(),false)))   // !=0: positive or -1
00287     {
00288         // statement must be a <repeat> if it has children; repeat count>0 must be
00289         // on the stack; let's start doing the body.
00290         nextStatement = nextStatement->getFirstChild();
00291     }
00292     else if (!nextStatement->getNextSibling())
00293     {
00294         // no sibling -- either end of <repeat> body, or end of script
00295         ASSERT(nextStatement->getParentNode()==turtleScript ? loopVars.empty() : !loopVars.empty());
00296         if (!loopVars.empty())
00297         {
00298             // decrement and check loop counter
00299             if (loopVars.top()!=-1)  // -1 means infinity
00300                 loopVars.top()--;
00301             if (loopVars.top()!=0)  // positive or -1
00302             {
00303                 // go to beginning of <repeat> block again
00304                 nextStatement = nextStatement->getParentNode()->getFirstChild();
00305             }
00306             else
00307             {
00308                 // end of loop -- locate next statement after the <repeat>
00309                 nextStatement = nextStatement->getParentNode();
00310                 gotoNextStatement();
00311             }
00312         }
00313         else
00314         {
00315             // end of script
00316             nextStatement = NULL;
00317         }
00318     }
00319     else
00320 
00321     {
00322         // go to next statement (must exist -- see "if" above)
00323         nextStatement = nextStatement->getNextSibling();
00324     }
00325 }
00326 
00327