00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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
00052 world = FindModule<BaseWorldUtility*>::findGlobalModule();
00053 if (world == NULL)
00054 error("Could not find BaseWorldUtility module");
00055
00056 coreEV << "initializing BaseUtility stage " << stage << endl;
00057
00058
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
00070 bool use2D = world->use2D();
00071
00072
00073 Coord pos = world->getRandomPosition();
00074
00075
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
00081 if(x > -1) pos.setX(x);
00082 if(y > -1) pos.setY(y);
00083 if(!use2D && z > -1) pos.setZ(z);
00084
00085
00086 move.setStart(pos);
00087 coreEV << "start pos: " << move.getStartPos().info() << endl;
00088
00089
00090 if (!move.getStartPos().isInRectangle(Coord(use2D), world->getPgs())) {
00091 error("node position specified in omnetpp.ini exceeds playgroundsize");
00092 }
00093
00094
00095 move.setSpeed(0);
00096 move.setDirectionByVector(Coord(use2D));
00097
00098
00099 moveCategory = utility->getCategory(&move);
00100
00101 }
00102 else if (stage == 1){
00103 coreEV << "initializing BaseMobility stage " << stage << endl;
00104
00105
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
00116 std::istringstream(dispWorldOwner.getTagArg("bgb", 0))
00117 >> origPGWidth;
00118 std::istringstream(dispWorldOwner.getTagArg("bgb", 1))
00119 >> origPGHeight;
00120
00121
00122 if(origPGWidth > 0) {
00123 playgroundScaleX = origPGWidth / playgroundSizeX();
00124 }
00125 if(origPGHeight > 0) {
00126 playgroundScaleY = origPGHeight / playgroundSizeY();
00127 }
00128 }
00129 }
00130
00131
00132 cDisplayString& disp = hostPtr->getDisplayString();
00133
00134
00135 if (disp.containsTag("b")) {
00136 std::istringstream(disp.getTagArg("b", 0)) >> origDisplayWidth;
00137 std::istringstream(disp.getTagArg("b", 1)) >> origDisplayHeight;
00138 }
00139
00140 if (disp.containsTag("i")) {
00141
00142 origIconSize = iconSizeTagToSize(disp.getTagArg("is", 0));
00143 }
00144
00145
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
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
00178
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
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
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("");
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
00290
00291
00292
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("");
00301 osDisplayTag << (origDisplayWidth * depthScale);
00302 disp.setTagArg("b", 0, osDisplayTag.str().data());
00303
00304 osDisplayTag.str("");
00305 osDisplayTag << (origDisplayHeight * depthScale);
00306 disp.setTagArg("b", 1, osDisplayTag.str().data());
00307 }
00308
00309 if (origIconSize > 0) {
00310
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
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
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
00457 if (!world->use2D())
00458 {
00459
00460 if (targetPos.getZ() < 0)
00461 {
00462 borderStep.setZ(-move.getStartPos().getZ());
00463
00464
00465 if( outside==NOWHERE )
00466 {
00467 outside = Z_SMALLER;
00468 }
00469
00470
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
00478
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
00488 else if (targetPos.getZ() >= playgroundSizeZ())
00489 {
00490 borderStep.setZ(playgroundSizeZ() - move.getStartPos().getZ());
00491
00492
00493 if( outside==NOWHERE )
00494 {
00495 outside = Z_BIGGER;
00496 }
00497
00498
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
00506
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());
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());
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());
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());
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());
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());
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());
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());
00612 }
00613 }
00614 break;
00615
00616 case Z_SMALLER:
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:
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
00660 BorderHandling wo;
00661
00662
00663 Coord borderStep(world->use2D());
00664
00665 wo = checkIfOutside(stepTarget, borderStep);
00666
00667
00668 if( wo == NOWHERE )
00669 return false;
00670
00671 coreEV << "handleIfOutside:stepTarget = " << stepTarget.info() << endl;
00672
00673
00674 Coord borderStart(world->use2D());
00675
00676 Coord borderDirection(world->use2D());
00677
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
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
00705 goToBorder(policy, wo, borderStep, borderStart);
00706
00707
00708 borderInterval = (borderStep.length()) / move.getSpeed();
00709
00710
00711
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
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