BaseMobility.cc

00001 /* -*- mode:c++ -*- ********************************************************
00002  * file:        BaseMobility.cc
00003  *
00004  * author:      Daniel Willkomm, Andras Varga
00005  *
00006  * copyright:   (C) 2004 Telecommunication Networks Group (TKN) at
00007  *              Technische Universitaet Berlin, Germany.
00008  *
00009  *              (C) 2005 Andras Varga
00010  *
00011  *              This program is free software; you can redistribute it
00012  *              and/or modify it under the terms of the GNU General Public
00013  *              License as published by the Free Software Foundation; either
00014  *              version 2 of the License, or (at your option) any later
00015  *              version.
00016  *              For further information see file COPYING
00017  *              in the top level directory
00018  ***************************************************************************
00019  * part of:     framework implementation developed by tkn
00020  **************************************************************************/
00021 
00022 
00023 #include "BaseMobility.h"
00024 #include "FWMath.h"
00025 #include "BorderMsg_m.h"
00026 #include <sstream>
00027 
00028 Define_Module(BaseMobility);
00029 
00030 BaseMobility::BaseMobility():
00031     playgroundScaleX(1),
00032     playgroundScaleY(1),
00033     origDisplayWidth(0),
00034     origDisplayHeight(0),
00035     origIconSize(0)
00036 {}
00037 
00038 void BaseMobility::initialize(int stage)
00039 {
00040     BaseModule::initialize(stage);
00041 
00042     if (stage == 0){
00043         hasPar("coreDebug") ? coreDebug = par("coreDebug").boolValue() : coreDebug = false;
00044 
00045         coreEV << "initializing BaseMobility stage " << stage << endl;
00046 
00047         hasPar("scaleNodeByDepth") ? scaleNodeByDepth
00048             = par("scaleNodeByDepth").boolValue()
00049             : scaleNodeByDepth = true;
00050 
00051         // get utility pointers (world and host)
00052     world = FindModule<BaseWorldUtility*>::findGlobalModule();
00053         if (world == NULL)
00054             error("Could not find BaseWorldUtility module");
00055 
00056         coreEV << "initializing BaseUtility stage " << stage << endl; // for node position
00057 
00058         //get a pointer to the host
00059         hostPtr = findHost();
00060         hostId = hostPtr->getId();
00061 
00062 
00063         if (hasPar("updateInterval")) {
00064           updateInterval = par("updateInterval");
00065         } else {
00066             updateInterval = 0;
00067         }
00068 
00069     // initialize Move parameter
00070         bool use2D = world->use2D();
00071 
00072         //initalize position with random values
00073         Coord pos = world->getRandomPosition();
00074 
00075         //read coordinates from parameters if available
00076         double x = hasPar("x") ? par("x").doubleValue() : -1;
00077         double y = hasPar("y") ? par("y").doubleValue() : -1;
00078         double z = hasPar("z") ? par("z").doubleValue() : -1;
00079 
00080         //set position with values from parameters if available
00081         if(x > -1) pos.setX(x);
00082         if(y > -1) pos.setY(y);
00083         if(!use2D && z > -1) pos.setZ(z);
00084 
00085         // set start-position and start-time (i.e. current simulation-time) of the Move
00086         move.setStart(pos);
00087     coreEV << "start pos: " << move.getStartPos().info() << endl;
00088 
00089         //check whether position is within the playground
00090         if (!move.getStartPos().isInRectangle(Coord(use2D), world->getPgs())) {
00091             error("node position specified in omnetpp.ini exceeds playgroundsize");
00092         }
00093 
00094         // set speed and direction of the Move
00095         move.setSpeed(0);
00096         move.setDirectionByVector(Coord(use2D));
00097 
00098         //get BBItem category for Move
00099         moveCategory = utility->getCategory(&move);
00100 
00101     }
00102     else if (stage == 1){
00103         coreEV << "initializing BaseMobility stage " << stage << endl;
00104 
00105         //get playground scaling
00106         if (world->getParentModule() != NULL )
00107         {
00108           const cDisplayString& dispWorldOwner
00109           = world->getParentModule()->getDisplayString();
00110 
00111           if( dispWorldOwner.containsTag("bgb") )
00112       {
00113             double origPGWidth;
00114             double origPGHeight;
00115             // normally this should be equal to playground size
00116         std::istringstream(dispWorldOwner.getTagArg("bgb", 0))
00117             >> origPGWidth;
00118         std::istringstream(dispWorldOwner.getTagArg("bgb", 1))
00119             >> origPGHeight;
00120 
00121         //bgb of zero means size isn't set manually
00122         if(origPGWidth > 0) {
00123           playgroundScaleX = origPGWidth / playgroundSizeX();
00124         }
00125         if(origPGHeight > 0) {
00126           playgroundScaleY = origPGHeight / playgroundSizeY();
00127         }
00128       }
00129         }
00130 
00131         //get original display of host
00132     cDisplayString& disp = hostPtr->getDisplayString();
00133 
00134         //get host width and height
00135     if (disp.containsTag("b")) {
00136       std::istringstream(disp.getTagArg("b", 0)) >> origDisplayWidth;
00137       std::istringstream(disp.getTagArg("b", 1)) >> origDisplayHeight;
00138     }
00139     //get hosts icon size
00140     if (disp.containsTag("i")) {
00141       // choose a appropriate icon size (only if a icon is specified)
00142       origIconSize = iconSizeTagToSize(disp.getTagArg("is", 0));
00143     }
00144 
00145         // print new host position on the screen and update bb info
00146         updatePosition();
00147 
00148         if (move.getSpeed() > 0 && updateInterval > 0)
00149         {
00150           coreEV << "Host is moving, speed=" << move.getSpeed() << " updateInterval=" << updateInterval << endl;
00151           moveMsg = new cMessage("move", MOVE_HOST);
00152           //host moves the first time after some random delay to avoid synchronized movements
00153             scheduleAt(simTime() + uniform(0, updateInterval), moveMsg);
00154         }
00155     }
00156 }
00157 
00158 int BaseMobility::iconSizeTagToSize(const char* tag)
00159 {
00160   if(strcmp(tag, "vs") == 0) {
00161     return 16;
00162   } else if(strcmp(tag, "s") == 0) {
00163     return 24;
00164   } else if(strcmp(tag, "n") == 0 || strcmp(tag, "") == 0) {
00165     return 40;
00166   } else if(strcmp(tag, "l") == 0) {
00167     return 60;
00168   } else if(strcmp(tag, "vl") == 0) {
00169     return 100;
00170   }
00171 
00172   return -1;
00173 }
00174 
00175 const char* BaseMobility::iconSizeToTag(double size)
00176 {
00177   //returns the biggest icon smaller than the passed size (except sizes
00178   //smaller than the smallest icon
00179   if(size < 24) {
00180     return "vs";
00181   } else if(size < 40) {
00182     return "s";
00183   } else if(size < 60) {
00184     return "n";
00185   } else if(size < 100) {
00186     return "l";
00187   } else {
00188     return "vl";
00189   }
00190 }
00191 
00192 void BaseMobility::handleMessage(cMessage * msg)
00193 {
00194     if (!msg->isSelfMessage())
00195         error("mobility modules can only receive self messages");
00196 
00197     if(msg->getKind() == MOVE_TO_BORDER){
00198       handleBorderMsg(msg);
00199     } else {
00200       handleSelfMsg(msg);
00201     }
00202 }
00203 
00204 
00205 
00206 void BaseMobility::handleSelfMsg(cMessage * msg)
00207 {
00208     makeMove();
00209     updatePosition();
00210 
00211     if( !moveMsg->isScheduled() && move.getSpeed() > 0) {
00212       scheduleAt(simTime() + updateInterval, msg);
00213     } else {
00214       delete msg;
00215       moveMsg = NULL;
00216     }
00217 }
00218 
00219 
00220 
00221 void BaseMobility::handleBorderMsg(cMessage * msg)
00222 {
00223     coreEV << "start MOVE_TO_BORDER:" << move.info() << endl;
00224 
00225     BorderMsg* bMsg = static_cast<BorderMsg*>(msg);
00226 
00227     switch( bMsg->getPolicy() ){
00228     case REFLECT:
00229     move.setStart(bMsg->getStartPos());
00230     move.setDirectionByVector(bMsg->getDirection());
00231     break;
00232 
00233     case WRAP:
00234     move.setStart(bMsg->getStartPos());
00235     break;
00236 
00237     case PLACERANDOMLY:
00238     move.setStart(bMsg->getStartPos());
00239     coreEV << "new random position: " << move.getStartPos().info() << endl;
00240     break;
00241 
00242     case RAISEERROR:
00243     error("node moved outside the playground");
00244     break;
00245 
00246     default:
00247       error("Unknown BorderPolicy!");
00248     }
00249 
00250     fixIfHostGetsOutside();
00251 
00252     updatePosition();
00253 
00254     delete bMsg;
00255 
00256     coreEV << "end MOVE_TO_BORDER:" << move.info() << endl;
00257 }
00258 
00259 
00260 
00261 void BaseMobility::updatePosition() {
00262     EV << "updatePosition: " << move.info() << endl;
00263 
00264     //publish the the new move
00265     utility->publishBBItem(moveCategory, &move, hostId);
00266 
00267     if(ev.isGUI())
00268     {
00269       std::ostringstream osDisplayTag;
00270 
00271       const int          iPrecis        = 5;
00272       cDisplayString&    disp           = hostPtr->getDisplayString();
00273 
00274       // setup output stream
00275       osDisplayTag << std::fixed; osDisplayTag.precision(iPrecis);
00276 
00277       osDisplayTag << (move.getStartPos().getX() * playgroundScaleX);
00278       disp.setTagArg("p", 0, osDisplayTag.str().data());
00279 
00280       osDisplayTag.str(""); // reset
00281       osDisplayTag << (move.getStartPos().getY() * playgroundScaleY);
00282       disp.setTagArg("p", 1, osDisplayTag.str().data());
00283 
00284       if(!world->use2D() && scaleNodeByDepth)
00285       {
00286         const double minScale = 0.25;
00287         const double maxScale = 1.0;
00288 
00289         //scale host dependent on their z coordinate to simulate a depth
00290         //effect
00291       //z-coordinate of zero maps to a scale of maxScale (very close)
00292       //z-coordinate of playground size z maps to size of minScale (far away)
00293         double depthScale = minScale
00294                           + (maxScale - minScale)
00295                             * (1.0 - move.getStartPos().getZ()
00296                                      / playgroundSizeZ());
00297 
00298         if (origDisplayWidth > 0.0 && origDisplayHeight > 0.0)
00299         {
00300           osDisplayTag.str(""); // reset
00301         osDisplayTag << (origDisplayWidth * depthScale);
00302         disp.setTagArg("b", 0, osDisplayTag.str().data());
00303 
00304         osDisplayTag.str(""); // reset
00305         osDisplayTag << (origDisplayHeight * depthScale);
00306         disp.setTagArg("b", 1, osDisplayTag.str().data());
00307         }
00308 
00309         if (origIconSize > 0) {
00310           // choose a appropriate icon size (only if a icon is specified)
00311         disp.setTagArg("is", 0,
00312                        iconSizeToTag(origIconSize * depthScale));
00313         }
00314       }
00315     }
00316 }
00317 
00318 
00319 void BaseMobility::reflectCoordinate(BorderHandling border, Coord& c)
00320 {
00321     switch( border ) {
00322     case X_SMALLER:
00323         c.setX(-c.getX());
00324       break;
00325     case X_BIGGER:
00326         c.setX(2 * playgroundSizeX() - c.getX());
00327       break;
00328 
00329     case Y_SMALLER:
00330         c.setY(-c.getY());
00331       break;
00332     case Y_BIGGER:
00333         c.setY(2 * playgroundSizeY() - c.getY());
00334         break;
00335 
00336     case Z_SMALLER:
00337         c.setZ(-c.getZ());
00338         break;
00339     case Z_BIGGER:
00340         c.setZ(2 * playgroundSizeZ() - c.getZ());
00341       break;
00342 
00343     case NOWHERE:
00344     default:
00345       error("wrong border handling case!");
00346     }
00347 }
00348 
00349 
00350 void BaseMobility::reflectIfOutside(BorderHandling wo, Coord& stepTarget,
00351                   Coord& targetPos, Coord& step,
00352                   double& angle) {
00353 
00354     reflectCoordinate(wo, targetPos);
00355     reflectCoordinate(wo, stepTarget);
00356 
00357     switch( wo ) {
00358     case X_SMALLER:
00359     case X_BIGGER:
00360         step.setX(-step.getX());
00361       angle = 180 - angle;
00362       break;
00363 
00364     case Y_SMALLER:
00365     case Y_BIGGER:
00366         step.setY(-step.getY());
00367       angle = -angle;
00368       break;
00369 
00370     case Z_SMALLER:
00371     case Z_BIGGER:
00372         step.setZ(-step.getZ());
00373       angle = -angle;
00374       break;
00375 
00376     case NOWHERE:
00377     default:
00378       error("wrong border handling case!");
00379     }
00380 }
00381 
00382 
00383 
00384 void BaseMobility::wrapIfOutside(BorderHandling wo,
00385                  Coord& stepTarget, Coord& targetPos) {
00386     switch( wo ) {
00387     case X_SMALLER:
00388     case X_BIGGER:
00389         targetPos.setX(FWMath::modulo(targetPos.getX(), playgroundSizeX()));
00390         stepTarget.setX(FWMath::modulo(stepTarget.getX(), playgroundSizeX()));
00391       break;
00392 
00393     case Y_SMALLER:
00394     case Y_BIGGER:
00395         targetPos.setY(FWMath::modulo(targetPos.getY(), playgroundSizeY()));
00396         stepTarget.setY(FWMath::modulo(stepTarget.getY(), playgroundSizeY()));
00397       break;
00398 
00399     case Z_SMALLER:
00400     case Z_BIGGER:
00401         targetPos.setZ(FWMath::modulo(targetPos.getZ(), playgroundSizeZ()));
00402         stepTarget.setZ(FWMath::modulo(stepTarget.getZ(), playgroundSizeZ()));
00403       break;
00404 
00405     case NOWHERE:
00406     default:
00407       error("wrong border handling case!");
00408     }
00409 }
00410 
00411 
00412 void BaseMobility::placeRandomlyIfOutside( Coord& targetPos )
00413 {
00414     targetPos = world->getRandomPosition();
00415 }
00416 
00417 
00418 
00419 BaseMobility::BorderHandling BaseMobility::checkIfOutside( Coord targetPos,
00420                                Coord& borderStep )
00421 {
00422     BorderHandling outside = NOWHERE;
00423 
00424     // Testing x-value
00425     if (targetPos.getX() < 0){
00426     borderStep.setX(-move.getStartPos().getX());
00427     outside = X_SMALLER;
00428     }
00429     else if (targetPos.getX() >= playgroundSizeX()){
00430         borderStep.setX(playgroundSizeX() - move.getStartPos().getX());
00431         outside = X_BIGGER;
00432     }
00433 
00434     // Testing y-value
00435     if (targetPos.getY() < 0){
00436       borderStep.setY(-move.getStartPos().getY());
00437 
00438     if( outside == NOWHERE
00439       || fabs(borderStep.getX()/move.getDirection().getX())
00440          > fabs(borderStep.getY()/move.getDirection().getY()) )
00441     {
00442       outside = Y_SMALLER;
00443     }
00444     }
00445     else if (targetPos.getY() >= playgroundSizeY()){
00446         borderStep.setY(playgroundSizeY() - move.getStartPos().getY());
00447 
00448     if( outside == NOWHERE
00449       || fabs(borderStep.getX()/move.getDirection().getX())
00450          > fabs(borderStep.getY()/move.getDirection().getY()) )
00451     {
00452       outside = Y_BIGGER;
00453     }
00454     }
00455 
00456     // Testing z-value
00457     if (!world->use2D())
00458     {
00459       // going to reach the lower z-border
00460       if (targetPos.getZ() < 0)
00461       {
00462         borderStep.setZ(-move.getStartPos().getZ());
00463 
00464         // no border reached so far
00465         if( outside==NOWHERE )
00466         {
00467           outside = Z_SMALLER;
00468         }
00469         // an y-border is reached earliest so far, test whether z-border
00470         // is reached even earlier
00471         else if( (outside == Y_SMALLER || outside == Y_BIGGER)
00472              && fabs(borderStep.getY()/move.getDirection().getY())
00473                 > fabs(borderStep.getZ()/move.getDirection().getZ()) )
00474         {
00475           outside = Z_SMALLER;
00476         }
00477         // an x-border is reached earliest so far, test whether z-border
00478         // is reached even earlier
00479         else if( (outside == X_SMALLER || outside == X_BIGGER)
00480              && fabs(borderStep.getX()/move.getDirection().getX())
00481                 > fabs(borderStep.getZ()/move.getDirection().getZ()) )
00482         {
00483           outside = Z_SMALLER;
00484         }
00485 
00486       }
00487       // going to reach the upper z-border
00488       else if (targetPos.getZ() >= playgroundSizeZ())
00489       {
00490           borderStep.setZ(playgroundSizeZ() - move.getStartPos().getZ());
00491 
00492           // no border reached so far
00493           if( outside==NOWHERE )
00494           {
00495             outside = Z_BIGGER;
00496           }
00497           // an y-border is reached earliest so far, test whether z-border
00498           // is reached even earlier
00499           else if( (outside==Y_SMALLER || outside==Y_BIGGER)
00500                && fabs(borderStep.getY()/move.getDirection().getY())
00501                   > fabs(borderStep.getZ()/move.getDirection().getZ()) )
00502         {
00503           outside = Z_BIGGER;
00504         }
00505           // an x-border is reached earliest so far, test whether z-border
00506           // is reached even earlier
00507         else if( (outside==X_SMALLER || outside==X_BIGGER)
00508               && fabs(borderStep.getX()/move.getDirection().getX())
00509                  > fabs(borderStep.getZ()/move.getDirection().getZ()) )
00510         {
00511           outside = Z_BIGGER;
00512         }
00513 
00514 
00515       }
00516     }
00517 
00518     coreEV << "checkIfOutside, outside="<<outside<<" borderStep: " << borderStep.info() << endl;
00519 
00520     return outside;
00521 }
00522 
00523 
00524 
00525 void BaseMobility::goToBorder(BorderPolicy policy, BorderHandling wo,
00526                 Coord& borderStep, Coord& borderStart)
00527 {
00528     double factor;
00529 
00530     coreEV << "goToBorder: startPos: " << move.getStartPos().info()
00531          << " borderStep: " << borderStep.info()
00532          << " BorderPolicy: " << policy
00533          << " BorderHandling: " << wo << endl;
00534 
00535     switch( wo ) {
00536     case X_SMALLER:
00537     factor = borderStep.getX() / move.getDirection().getX();
00538     borderStep.setY(factor * move.getDirection().getY());
00539     if (!world->use2D())
00540     {
00541       borderStep.setZ(factor * move.getDirection().getZ()); // 3D case
00542     }
00543 
00544     if( policy == WRAP )
00545     {
00546       borderStart.setX(playgroundSizeX());
00547       borderStart.setY(move.getStartPos().getY() + borderStep.getY());
00548       if (!world->use2D())
00549       {
00550         borderStart.setZ(move.getStartPos().getZ()
00551                  + borderStep.getZ()); // 3D case
00552       }
00553     }
00554     break;
00555 
00556     case X_BIGGER:
00557     factor = borderStep.getX() / move.getDirection().getX();
00558     borderStep.setY(factor * move.getDirection().getY());
00559     if (!world->use2D())
00560     {
00561       borderStep.setZ(factor * move.getDirection().getZ()); // 3D case
00562     }
00563 
00564     if( policy == WRAP )
00565     {
00566       borderStart.setX(0);
00567       borderStart.setY(move.getStartPos().getY() + borderStep.getY());
00568       if (!world->use2D())
00569       {
00570         borderStart.setZ(move.getStartPos().getZ()
00571                  + borderStep.getZ()); // 3D case
00572       }
00573     }
00574     break;
00575 
00576     case Y_SMALLER:
00577     factor = borderStep.getY() / move.getDirection().getY();
00578     borderStep.setX(factor * move.getDirection().getX());
00579     if (!world->use2D())
00580     {
00581       borderStep.setZ(factor * move.getDirection().getZ()); // 3D case
00582     }
00583 
00584     if( policy == WRAP )
00585     {
00586       borderStart.setY(playgroundSizeY());
00587       borderStart.setX(move.getStartPos().getX() + borderStep.getX());
00588       if (!world->use2D())
00589       {
00590         borderStart.setZ(move.getStartPos().getZ()
00591                  + borderStep.getZ()); // 3D case
00592       }
00593     }
00594     break;
00595 
00596     case Y_BIGGER:
00597     factor = borderStep.getY() / move.getDirection().getY();
00598     borderStep.setX(factor * move.getDirection().getX());
00599     if (!world->use2D())
00600     {
00601       borderStep.setZ(factor * move.getDirection().getZ()); // 3D case
00602     }
00603 
00604     if( policy == WRAP )
00605     {
00606       borderStart.setY(0);
00607       borderStart.setX(move.getStartPos().getX() + borderStep.getX());
00608       if (!world->use2D())
00609       {
00610         borderStart.setZ(move.getStartPos().getZ()
00611                  + borderStep.getZ()); // 3D case
00612       }
00613     }
00614     break;
00615 
00616     case Z_SMALLER: // here we are definitely in 3D
00617     factor = borderStep.getZ() / move.getDirection().getZ();
00618     borderStep.setX(factor * move.getDirection().getX());
00619     borderStep.setY(factor * move.getDirection().getY());
00620 
00621     if( policy == WRAP )
00622     {
00623       borderStart.setZ(playgroundSizeZ());
00624       borderStart.setX(move.getStartPos().getX() + borderStep.getX());
00625       borderStart.setY(move.getStartPos().getY() + borderStep.getY());
00626     }
00627     break;
00628 
00629     case Z_BIGGER: // here we are definitely in 3D
00630     factor = borderStep.getZ() / move.getDirection().getZ();
00631     borderStep.setX(factor * move.getDirection().getX());
00632     borderStep.setY(factor * move.getDirection().getY());
00633 
00634     if( policy == WRAP )
00635     {
00636       borderStart.setZ(0);
00637       borderStart.setX(move.getStartPos().getX() + borderStep.getX());
00638       borderStart.setY(move.getStartPos().getY() + borderStep.getY());
00639     }
00640     break;
00641 
00642     default:
00643         factor = 0;
00644         error("invalid state in goToBorder switch!");
00645     }
00646 
00647     coreEV << "goToBorder: startPos: " << move.getStartPos().info()
00648          << " borderStep: " << borderStep.info()
00649          << " borderStart: " << borderStart.info()
00650          << " factor: " << factor << endl;
00651 }
00652 
00653 
00654 
00655 bool BaseMobility::handleIfOutside(BorderPolicy policy, Coord& stepTarget,
00656                    Coord& targetPos, Coord& step,
00657                    double& angle)
00658 {
00659     // where did the host leave the playground?
00660     BorderHandling wo;
00661 
00662     // step to reach the border
00663     Coord borderStep(world->use2D());
00664 
00665     wo = checkIfOutside(stepTarget, borderStep);
00666 
00667     // just return if the next step is not outside the playground
00668     if( wo == NOWHERE )
00669   return false;
00670 
00671     coreEV << "handleIfOutside:stepTarget = " << stepTarget.info() << endl;
00672 
00673     // new start position after the host reaches the border
00674     Coord borderStart(world->use2D());
00675     // new direction the host has to move to
00676     Coord borderDirection(world->use2D());
00677     // time to reach the border
00678     simtime_t borderInterval;
00679 
00680     coreEV << "old values: stepTarget: " << stepTarget.info()
00681          << " step: " << step.info()
00682          << " targetPos: " << targetPos.info()
00683          << " angle: " << angle << endl;
00684 
00685     // which border policy is to be followed
00686     switch (policy){
00687     case REFLECT:
00688     reflectIfOutside( wo, stepTarget, targetPos, step, angle );
00689     break;
00690     case WRAP:
00691     wrapIfOutside( wo, stepTarget, targetPos );
00692     break;
00693     case PLACERANDOMLY:
00694     placeRandomlyIfOutside( targetPos );
00695     break;
00696     case RAISEERROR:
00697       break;
00698     }
00699 
00700     coreEV << "new values: stepTarget: " << stepTarget.info()
00701          << " step: " << step.info()
00702          << " angle: " << angle << endl;
00703 
00704     // calculate the step to reach the border
00705     goToBorder(policy, wo, borderStep, borderStart);
00706 
00707     // calculate the time to reach the border
00708     borderInterval = (borderStep.length()) / move.getSpeed();
00709 
00710     // calculate new start position
00711     // NOTE: for WRAP this is done in goToBorder
00712     switch( policy ){
00713     case REFLECT:
00714     {
00715       borderStart = move.getStartPos() + borderStep;
00716       double d = stepTarget.distance( borderStart );
00717     borderDirection = (stepTarget - borderStart) / d;
00718     break;
00719     }
00720     case PLACERANDOMLY:
00721     borderStart = targetPos;
00722     stepTarget = targetPos;
00723     break;
00724 
00725     case WRAP:
00726     case RAISEERROR:
00727       break;
00728 
00729     default:
00730       error("unknown BorderPolicy");
00731     }
00732 
00733     coreEV << "border handled, borderStep: "<< borderStep.info()
00734          << "borderStart: " << borderStart.info()
00735          << " stepTarget " << stepTarget.info() << endl;
00736 
00737     // create a border self message and schedule it appropriately
00738     BorderMsg *bMsg = new BorderMsg("borderMove", MOVE_TO_BORDER);
00739     bMsg->setPolicy(policy);
00740     bMsg->setStartPos(borderStart);
00741     bMsg->setDirection(borderDirection);
00742 
00743     scheduleAt(simTime() + borderInterval, bMsg);
00744 
00745     return true;
00746 }
00747