INET Framework for OMNeT++/OMNEST
TurtleMobility.cc
Go to the documentation of this file.
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 Lesser 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 Lesser General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU Lesser General Public License
00015 // along with this program; if not, see <http://www.gnu.org/licenses/>.
00016 //
00017 
00018 #include "TurtleMobility.h"
00019 #include "FWMath.h"
00020 
00021 
00022 Define_Module(TurtleMobility);
00023 
00024 
00030 void TurtleMobility::initialize(int stage)
00031 {
00032     LineSegmentsMobilityBase::initialize(stage);
00033 
00034     EV << "initializing TurtleMobility stage " << stage << endl;
00035 
00036     if (stage == 1)
00037     {
00038         turtleScript = par("turtleScript");
00039         nextStatement = turtleScript->getFirstChild();
00040 
00041         speed = 1;
00042         angle = 0;
00043         borderPolicy = REFLECT;
00044 
00045         // a dirty trick to extract starting position out of the script
00046         // (start doing it, but then rewind to the beginning)
00047         resumeScript();
00048         targetPos = pos;
00049         targetTime = simTime();
00050         nextStatement = turtleScript->getFirstChild();
00051         while (!loopVars.empty()) loopVars.pop();
00052 
00053         updatePosition();
00054 
00055         WATCH(speed);
00056         WATCH(angle);
00057         //WATCH(borderPolicy);
00058     }
00059 }
00060 
00061 void TurtleMobility::setTargetPosition()
00062 {
00063     resumeScript();
00064 }
00065 
00066 void TurtleMobility::fixIfHostGetsOutside()
00067 {
00068     handleIfOutside(borderPolicy, targetPos, step, angle);
00069 }
00070 
00074 void TurtleMobility::resumeScript()
00075 {
00076     if (!nextStatement)
00077     {
00078         stationary = true;
00079         return;
00080     }
00081 
00082     simtime_t now = targetTime;
00083 
00084     // interpret statement
00085     while (nextStatement && targetTime==now)
00086     {
00087         executeStatement(nextStatement);
00088         gotoNextStatement();
00089     }
00090 }
00091 
00092 void TurtleMobility::executeStatement(cXMLElement *stmt)
00093 {
00094     const char *tag = stmt->getTagName();
00095 
00096     EV << "doing <" << tag << ">\n";
00097 
00098     if (!strcmp(tag,"repeat"))
00099     {
00100         const char *nAttr = stmt->getAttribute("n");
00101         long n = -1;  // infinity -- that's the default
00102         if (nAttr)
00103         {
00104             n = (long) getValue(nAttr);
00105             if (n<0)
00106                 error("<repeat>: negative repeat count at %s", stmt->getSourceLocation());
00107         }
00108         loopVars.push(n);
00109     }
00110     else if (!strcmp(tag,"set"))
00111     {
00112         const char *speedAttr = stmt->getAttribute("speed");
00113         const char *angleAttr = stmt->getAttribute("angle");
00114         const char *xAttr = stmt->getAttribute("x");
00115         const char *yAttr = stmt->getAttribute("y");
00116         const char *bpAttr = stmt->getAttribute("borderPolicy");
00117         if (speedAttr)
00118             speed = getValue(speedAttr);
00119         if (angleAttr)
00120             angle = getValue(angleAttr);
00121         if (xAttr)
00122             targetPos.x = pos.x = getValue(xAttr);
00123         if (yAttr)
00124             targetPos.y = pos.y = getValue(yAttr);
00125         if (speed<=0)
00126             error("<set>: speed is negative or zero at %s", stmt->getSourceLocation());
00127         if (bpAttr)
00128         {
00129             if (!strcmp(bpAttr,"reflect"))
00130                 borderPolicy = REFLECT;
00131             else if (!strcmp(bpAttr,"wrap"))
00132                 borderPolicy = WRAP;
00133             else if (!strcmp(bpAttr,"placerandomly"))
00134                 borderPolicy = PLACERANDOMLY;
00135             else if (!strcmp(bpAttr,"error"))
00136                 borderPolicy = RAISEERROR;
00137             else
00138                 error("<set>: value for attribute borderPolicy is invalid, should be "
00139                       "'reflect', 'wrap', 'placerandomly' or 'error' at %s",
00140                       stmt->getSourceLocation());
00141         }
00142     }
00143     else if (!strcmp(tag,"forward"))
00144     {
00145         const char *dAttr = stmt->getAttribute("d");
00146         const char *tAttr = stmt->getAttribute("t");
00147         if (!dAttr && !tAttr)
00148             error("<forward>: must have at least attribute 't' or 'd' (or both) at %s", stmt->getSourceLocation());
00149         double d, t;
00150         if (tAttr && dAttr)
00151         {
00152             // cover distance d in time t (current speed is ignored)
00153             d = getValue(dAttr);
00154             t = getValue(tAttr);
00155         }
00156         else if (dAttr)
00157         {
00158             // travel distance d at current speed
00159             d = getValue(dAttr);
00160             t = d / speed;
00161         }
00162         else // tAttr only
00163         {
00164             // travel for time t at current speed
00165             t = getValue(tAttr);
00166             d = speed * t;
00167         }
00168         if (t<0)
00169             error("<forward>: time (attribute t) is negative at %s", stmt->getSourceLocation());
00170         if (d<0)
00171             error("<forward>: distance (attribute d) is negative at %s", stmt->getSourceLocation());
00172         // FIXME handle zeros properly...
00173         targetPos.x += d * cos(PI * angle / 180);
00174         targetPos.y += d * sin(PI * angle / 180);
00175         targetTime += t;
00176     }
00177     else if (!strcmp(tag,"turn"))
00178     {
00179         const char *angleAttr = stmt->getAttribute("angle");
00180         if (!angleAttr)
00181             error("<turn>: required attribute 'angle' missing at %s", stmt->getSourceLocation());
00182         angle += getValue(angleAttr);
00183     }
00184     else if (!strcmp(tag,"wait"))
00185     {
00186         const char *tAttr = stmt->getAttribute("t");
00187         if (!tAttr)
00188             error("<wait>: required attribute 't' missing at %s", stmt->getSourceLocation());
00189         double t = getValue(tAttr);
00190         if (t<0)
00191             error("<wait>: time (attribute t) is negative (%g) at %s", t, stmt->getSourceLocation());
00192         targetTime += t;  // targetPos is unchanged
00193     }
00194     else if (!strcmp(tag,"moveto"))
00195     {
00196         const char *xAttr = stmt->getAttribute("x");
00197         const char *yAttr = stmt->getAttribute("y");
00198         const char *tAttr = stmt->getAttribute("t");
00199         if (xAttr)
00200             targetPos.x = getValue(xAttr);
00201         if (yAttr)
00202             targetPos.y = getValue(yAttr);
00203         // travel to targetPos at current speed, or get there in time t (ignoring current speed then)
00204         double t = tAttr ? getValue(tAttr) : pos.distance(targetPos)/speed;
00205         if (t<0)
00206             error("<wait>: time (attribute t) is negative at %s", stmt->getSourceLocation());
00207         targetTime += t;
00208     }
00209     else if (!strcmp(tag,"moveby"))
00210     {
00211         const char *xAttr = stmt->getAttribute("x");
00212         const char *yAttr = stmt->getAttribute("y");
00213         const char *tAttr = stmt->getAttribute("t");
00214         if (xAttr)
00215             targetPos.x += getValue(xAttr);
00216         if (yAttr)
00217             targetPos.y += getValue(yAttr);
00218         // travel to targetPos at current speed, or get there in time t (ignoring current speed then)
00219         double t = tAttr ? getValue(tAttr) : pos.distance(targetPos)/speed;
00220         if (t<0)
00221             error("<wait>: time (attribute t) is negative at %s", stmt->getSourceLocation());
00222         targetTime += t;
00223     }
00224 }
00225 
00226 double TurtleMobility::getValue(const char *s)
00227 {
00228     // first, textually replace $MAXX and $MAXY with their actual values
00229     std::string str;
00230     if (strchr(s,'$'))
00231     {
00232         char strMaxX[32], strMaxY[32];
00233         sprintf(strMaxX, "%g", getPlaygroundSizeX()-1);
00234         sprintf(strMaxY, "%g", getPlaygroundSizeY()-1);
00235 
00236         str = s;
00237         std::string::size_type pos;
00238         while ((pos = str.find("$MAXX")) != std::string::npos)
00239             str.replace(pos, sizeof("$MAXX")-1, strMaxX);
00240         while ((pos = str.find("$MAXY")) != std::string::npos)
00241             str.replace(pos, sizeof("$MAXY")-1, strMaxY);
00242         s = str.c_str();
00243     }
00244 
00245     // then use cDynamicExpression to evaluate the string
00246     try {
00247         cDynamicExpression expr;
00248         expr.parse(s);
00249         return expr.doubleValue(this);
00250     }
00251     catch (std::exception& e) {
00252         throw cRuntimeError(this, "wrong value '%s' around %s: %s", s, nextStatement->getSourceLocation(), e.what());
00253     }
00254 }
00255 
00256 void TurtleMobility::gotoNextStatement()
00257 {
00258     // "statement either doesn't have a child, or it's a <repeat> and loop count is already pushed on the stack"
00259     ASSERT(!nextStatement->getFirstChild() || (!strcmp(nextStatement->getTagName(),"repeat") && !loopVars.empty()));
00260 
00261     if (nextStatement->getFirstChild() && (loopVars.top()!=0 || (loopVars.pop(),false)))   // !=0: positive or -1
00262     {
00263         // statement must be a <repeat> if it has children; repeat count>0 must be
00264         // on the stack; let's start doing the body.
00265         nextStatement = nextStatement->getFirstChild();
00266     }
00267     else if (!nextStatement->getNextSibling())
00268     {
00269         // no sibling -- either end of <repeat> body, or end of script
00270         ASSERT(nextStatement->getParentNode()==turtleScript ? loopVars.empty() : !loopVars.empty());
00271         if (!loopVars.empty())
00272         {
00273             // decrement and check loop counter
00274             if (loopVars.top()!=-1)  // -1 means infinity
00275                 loopVars.top()--;
00276             if (loopVars.top()!=0)  // positive or -1
00277             {
00278                 // go to beginning of <repeat> block again
00279                 nextStatement = nextStatement->getParentNode()->getFirstChild();
00280             }
00281             else
00282             {
00283                 // end of loop -- locate next statement after the <repeat>
00284                 nextStatement = nextStatement->getParentNode();
00285                 gotoNextStatement();
00286             }
00287         }
00288         else
00289         {
00290             // end of script
00291             nextStatement = NULL;
00292         }
00293     }
00294     else
00295     {
00296         // go to next statement (must exist -- see "if" above)
00297         nextStatement = nextStatement->getNextSibling();
00298     }
00299 }
00300 
00301