|
INET Framework for OMNeT++/OMNEST
|
LOGO-style movement model, with the script coming from XML. See NED file for more info. More...
#include <TurtleMobility.h>
Protected Member Functions | |
| virtual void | initialize (int) |
| Initializes mobility model parameters. | |
| virtual void | setTargetPosition () |
| Overridden from LineSegmentsMobilityBase. Invokes resumeScript(). | |
| virtual void | fixIfHostGetsOutside () |
| Overridden from LineSegmentsMobilityBase. | |
| virtual void | resumeScript () |
| Process next statements from script. | |
| virtual void | executeStatement (cXMLElement *nextStatement) |
| Execute the given statement. | |
| virtual double | getValue (const char *s) |
| Parse attrs in the script -- accepts things like "uniform(10,50) as well. | |
| virtual void | gotoNextStatement () |
| Advance nextStatement pointer. | |
Protected Attributes | |
| cXMLElement * | turtleScript |
| cXMLElement * | nextStatement |
| double | speed |
| double | angle |
| BorderPolicy | borderPolicy |
| std::stack< long > | loopVars |
LOGO-style movement model, with the script coming from XML. See NED file for more info.
| void TurtleMobility::executeStatement | ( | cXMLElement * | nextStatement | ) | [protected, virtual] |
Execute the given statement.
Referenced by resumeScript().
{
const char *tag = stmt->getTagName();
EV << "doing <" << tag << ">\n";
if (!strcmp(tag,"repeat"))
{
const char *nAttr = stmt->getAttribute("n");
long n = -1; // infinity -- that's the default
if (nAttr)
{
n = (long) getValue(nAttr);
if (n<0)
error("<repeat>: negative repeat count at %s", stmt->getSourceLocation());
}
loopVars.push(n);
}
else if (!strcmp(tag,"set"))
{
const char *speedAttr = stmt->getAttribute("speed");
const char *angleAttr = stmt->getAttribute("angle");
const char *xAttr = stmt->getAttribute("x");
const char *yAttr = stmt->getAttribute("y");
const char *bpAttr = stmt->getAttribute("borderPolicy");
if (speedAttr)
speed = getValue(speedAttr);
if (angleAttr)
angle = getValue(angleAttr);
if (xAttr)
targetPos.x = pos.x = getValue(xAttr);
if (yAttr)
targetPos.y = pos.y = getValue(yAttr);
if (speed<=0)
error("<set>: speed is negative or zero at %s", stmt->getSourceLocation());
if (bpAttr)
{
if (!strcmp(bpAttr,"reflect"))
borderPolicy = REFLECT;
else if (!strcmp(bpAttr,"wrap"))
borderPolicy = WRAP;
else if (!strcmp(bpAttr,"placerandomly"))
borderPolicy = PLACERANDOMLY;
else if (!strcmp(bpAttr,"error"))
borderPolicy = RAISEERROR;
else
error("<set>: value for attribute borderPolicy is invalid, should be "
"'reflect', 'wrap', 'placerandomly' or 'error' at %s",
stmt->getSourceLocation());
}
}
else if (!strcmp(tag,"forward"))
{
const char *dAttr = stmt->getAttribute("d");
const char *tAttr = stmt->getAttribute("t");
if (!dAttr && !tAttr)
error("<forward>: must have at least attribute 't' or 'd' (or both) at %s", stmt->getSourceLocation());
double d, t;
if (tAttr && dAttr)
{
// cover distance d in time t (current speed is ignored)
d = getValue(dAttr);
t = getValue(tAttr);
}
else if (dAttr)
{
// travel distance d at current speed
d = getValue(dAttr);
t = d / speed;
}
else // tAttr only
{
// travel for time t at current speed
t = getValue(tAttr);
d = speed * t;
}
if (t<0)
error("<forward>: time (attribute t) is negative at %s", stmt->getSourceLocation());
if (d<0)
error("<forward>: distance (attribute d) is negative at %s", stmt->getSourceLocation());
// FIXME handle zeros properly...
targetPos.x += d * cos(PI * angle / 180);
targetPos.y += d * sin(PI * angle / 180);
targetTime += t;
}
else if (!strcmp(tag,"turn"))
{
const char *angleAttr = stmt->getAttribute("angle");
if (!angleAttr)
error("<turn>: required attribute 'angle' missing at %s", stmt->getSourceLocation());
angle += getValue(angleAttr);
}
else if (!strcmp(tag,"wait"))
{
const char *tAttr = stmt->getAttribute("t");
if (!tAttr)
error("<wait>: required attribute 't' missing at %s", stmt->getSourceLocation());
double t = getValue(tAttr);
if (t<0)
error("<wait>: time (attribute t) is negative (%g) at %s", t, stmt->getSourceLocation());
targetTime += t; // targetPos is unchanged
}
else if (!strcmp(tag,"moveto"))
{
const char *xAttr = stmt->getAttribute("x");
const char *yAttr = stmt->getAttribute("y");
const char *tAttr = stmt->getAttribute("t");
if (xAttr)
targetPos.x = getValue(xAttr);
if (yAttr)
targetPos.y = getValue(yAttr);
// travel to targetPos at current speed, or get there in time t (ignoring current speed then)
double t = tAttr ? getValue(tAttr) : pos.distance(targetPos)/speed;
if (t<0)
error("<wait>: time (attribute t) is negative at %s", stmt->getSourceLocation());
targetTime += t;
}
else if (!strcmp(tag,"moveby"))
{
const char *xAttr = stmt->getAttribute("x");
const char *yAttr = stmt->getAttribute("y");
const char *tAttr = stmt->getAttribute("t");
if (xAttr)
targetPos.x += getValue(xAttr);
if (yAttr)
targetPos.y += getValue(yAttr);
// travel to targetPos at current speed, or get there in time t (ignoring current speed then)
double t = tAttr ? getValue(tAttr) : pos.distance(targetPos)/speed;
if (t<0)
error("<wait>: time (attribute t) is negative at %s", stmt->getSourceLocation());
targetTime += t;
}
}
| void TurtleMobility::fixIfHostGetsOutside | ( | ) | [protected, virtual] |
Overridden from LineSegmentsMobilityBase.
Implements LineSegmentsMobilityBase.
{
handleIfOutside(borderPolicy, targetPos, step, angle);
}
| double TurtleMobility::getValue | ( | const char * | s | ) | [protected, virtual] |
Parse attrs in the script -- accepts things like "uniform(10,50) as well.
Referenced by executeStatement().
{
// first, textually replace $MAXX and $MAXY with their actual values
std::string str;
if (strchr(s,'$'))
{
char strMaxX[32], strMaxY[32];
sprintf(strMaxX, "%g", getPlaygroundSizeX()-1);
sprintf(strMaxY, "%g", getPlaygroundSizeY()-1);
str = s;
std::string::size_type pos;
while ((pos = str.find("$MAXX")) != std::string::npos)
str.replace(pos, sizeof("$MAXX")-1, strMaxX);
while ((pos = str.find("$MAXY")) != std::string::npos)
str.replace(pos, sizeof("$MAXY")-1, strMaxY);
s = str.c_str();
}
// then use cDynamicExpression to evaluate the string
try {
cDynamicExpression expr;
expr.parse(s);
return expr.doubleValue(this);
}
catch (std::exception& e) {
throw cRuntimeError(this, "wrong value '%s' around %s: %s", s, nextStatement->getSourceLocation(), e.what());
}
}
| void TurtleMobility::gotoNextStatement | ( | ) | [protected, virtual] |
Advance nextStatement pointer.
Referenced by resumeScript().
{
// "statement either doesn't have a child, or it's a <repeat> and loop count is already pushed on the stack"
ASSERT(!nextStatement->getFirstChild() || (!strcmp(nextStatement->getTagName(),"repeat") && !loopVars.empty()));
if (nextStatement->getFirstChild() && (loopVars.top()!=0 || (loopVars.pop(),false))) // !=0: positive or -1
{
// statement must be a <repeat> if it has children; repeat count>0 must be
// on the stack; let's start doing the body.
nextStatement = nextStatement->getFirstChild();
}
else if (!nextStatement->getNextSibling())
{
// no sibling -- either end of <repeat> body, or end of script
ASSERT(nextStatement->getParentNode()==turtleScript ? loopVars.empty() : !loopVars.empty());
if (!loopVars.empty())
{
// decrement and check loop counter
if (loopVars.top()!=-1) // -1 means infinity
loopVars.top()--;
if (loopVars.top()!=0) // positive or -1
{
// go to beginning of <repeat> block again
nextStatement = nextStatement->getParentNode()->getFirstChild();
}
else
{
// end of loop -- locate next statement after the <repeat>
nextStatement = nextStatement->getParentNode();
gotoNextStatement();
}
}
else
{
// end of script
nextStatement = NULL;
}
}
else
{
// go to next statement (must exist -- see "if" above)
nextStatement = nextStatement->getNextSibling();
}
}
| void TurtleMobility::initialize | ( | int | stage | ) | [protected, virtual] |
Initializes mobility model parameters.
Reads the parameters. If the host is not stationary it calculates a random position and schedules a timer to trigger the first movement
Reimplemented from LineSegmentsMobilityBase.
{
LineSegmentsMobilityBase::initialize(stage);
EV << "initializing TurtleMobility stage " << stage << endl;
if (stage == 1)
{
turtleScript = par("turtleScript");
nextStatement = turtleScript->getFirstChild();
speed = 1;
angle = 0;
borderPolicy = REFLECT;
// a dirty trick to extract starting position out of the script
// (start doing it, but then rewind to the beginning)
resumeScript();
targetPos = pos;
targetTime = simTime();
nextStatement = turtleScript->getFirstChild();
while (!loopVars.empty()) loopVars.pop();
updatePosition();
WATCH(speed);
WATCH(angle);
//WATCH(borderPolicy);
}
}
| void TurtleMobility::resumeScript | ( | ) | [protected, virtual] |
Process next statements from script.
Will set a new targetTime and targetPos
Referenced by initialize(), and setTargetPosition().
{
if (!nextStatement)
{
stationary = true;
return;
}
simtime_t now = targetTime;
// interpret statement
while (nextStatement && targetTime==now)
{
executeStatement(nextStatement);
gotoNextStatement();
}
}
| void TurtleMobility::setTargetPosition | ( | ) | [protected, virtual] |
Overridden from LineSegmentsMobilityBase. Invokes resumeScript().
Implements LineSegmentsMobilityBase.
{
resumeScript();
}
double TurtleMobility::angle [protected] |
Referenced by executeStatement(), fixIfHostGetsOutside(), and initialize().
BorderPolicy TurtleMobility::borderPolicy [protected] |
Referenced by executeStatement(), fixIfHostGetsOutside(), and initialize().
std::stack<long> TurtleMobility::loopVars [protected] |
Referenced by executeStatement(), gotoNextStatement(), and initialize().
cXMLElement* TurtleMobility::nextStatement [protected] |
Referenced by getValue(), gotoNextStatement(), initialize(), and resumeScript().
double TurtleMobility::speed [protected] |
Referenced by executeStatement(), and initialize().
cXMLElement* TurtleMobility::turtleScript [protected] |
Referenced by gotoNextStatement(), and initialize().