Alvaro Cassinelli / Mbed 2 deprecated skinGames_forktest

Dependencies:   mbed

Fork of scoreLight_Advanced by Alvaro Cassinelli

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers elasticLoop.cpp Source File

elasticLoop.cpp

00001 /*
00002  *  elasticLoop.cpp
00003  *  laserBlobPure
00004  *
00005  *  Created by CASSINELLI ALVARO on 5/20/11.
00006  *  Copyright 2011 TOKYO UNIVERSITY. All rights reserved.
00007  *
00008  */
00009 
00010 #include "elasticLoop.h"
00011 
00012 // SHOULD NOT BE HERE: (only because I am using AD_MIRRIOR... max and min in the set region function that should not be here)
00013 #include "hardwareIO.h"
00014 
00015 elasticLoop::elasticLoop() {
00016 }
00017 
00018 elasticLoop::~elasticLoop() {
00019     // no need to do clear, this is done by default when clearing the vector container?
00020         massesLoop.clear();
00021         loopSpringArray.clear();
00022         hairVector.clear();
00023         lightForce.clear();
00024         centralSpringArray.clear();
00025         displaySensingBuffer.lsdTrajectory.clear();
00026 }
00027 
00028 void elasticLoop::showChildParameters() {
00029    // pc.printf("Mirror delay :%d\n", displaySensingBuffer.delayMirrorSamples);
00030    // pc.printf("Angle correction force :%d\n", angleCorrectionForceLoop);
00031     pc.printf("Integration Step Loop :%f\n", integrationStepLoop);
00032     pc.printf("Integration Step Anchor :%f\n", integrationStepAnchor);
00033     }
00034 
00035 void elasticLoop::createBlob(int _id, ElasticLoopMode _elasticBlobMode, vector2Df _initPos, vector2Df _initSpeed) {
00036     // (1) set ID:
00037     identifier=_id;
00038 
00039     startCenter=_initPos;
00040     startSpeed=_initSpeed;
00041 
00042 // (2) Initialize common variables of all blobs (base class):
00043 //   initCommonVariables();
00044 
00045     // (3) initialize common variables for the elastic blob types:
00046     integrationStepLoop=0.22;
00047     integrationStepAnchor=0.4;
00048     
00049     slidingDirection=true; //  (will change when touching wall)
00050     // Sending data:
00051     periodSendingData=15; // in ms
00052     sendingLoopPositions=false;
00053     sendingBlobArea=true;
00054     sendingKineticEnergy=true;
00055     sendingBlobMaxMin=true;
00056      // send ALWAYS, regardless of the fact the blob is being touched or not, in case of elastic loops:
00057     sendingOnlyWhenTouch=false;
00058 
00059 // (3) Initialize secondary variables depending on the blob type and mode:
00060 
00061 // NOTE (!): the mode does not affect the update method; in fact, all these elastic loops have different behaviours because of different parameters (but the booleans modes could
00062 // actually be "condensed" in a mode...)
00063 
00064     switch (_elasticBlobMode) {
00065         case RELAX:
00066 
00067             // Name of this kind of spot:
00068             sprintf(spotName,"loop_relax"); //this is an relaxing elastic loop
00069 
00070             // Color: (use parameter in the future):
00071             //setColor(0x07);//0x04+0x02>>i);
00072             setColor(0x04);
00073             blueTouch=true;
00074 
00075             // default (initial) shape (the scafold belongs to the base class):
00076             startRadius=400;
00077             bluePrint.buildCircularScafold(startRadius, vector2Dd(0,0), 40); //(float _radius, vector2Dd _pos, int _numScafoldPoints);
00078 
00079             // Numeric parameters for the simulated mechanical system:
00080             massLoopParticle=0.25;
00081             dampMotionMassesLoop=0.025;//0.17;
00082             massAnchor=2.0;
00083             dampMotionAnchorMass=0.001;
00084             // Springs:
00085             centralSpringK=0.3;
00086             centralSpringRelax=startRadius;// use the radius of the scafold
00087             interSpringK=0.46;
00088             interSpringRelax=20;
00089             // for "zack-like" blob:
00090             interParticleRange=100;
00091             factorInterParticleForce=18.0;
00092 
00093             searchActive=false;
00094             pseudopodesMode=false; // this is for contour following.
00095 
00096             // Active/inactive forces:
00097             springForcesOnLoop=true;
00098             lightForcesOnLoop=true;
00099             forceBorderOnLoop=false;
00100             nuclearForceOnLoop=false;//true;
00101             interParticleForceOnLoop=false;
00102             forceInternalPressureOnLoop=false; // (when true, either constant force or calculated area using Green function or approximation by bounding box)
00103 
00104             // Recentering vector:
00105             angleCorrectionForceLoop=0;// in deg
00106             recenteringForceOnLoop=false;
00107             angleCorrectionForceNucleus=0;// in deg
00108             recenteringForceOnNucleus=false;//true;
00109 
00110             factorLightForce=4.0;//3.0;//8.0;
00111             factorRecenteringAnchorMass=20.0/bluePrint.scafold.size(); // use number of points in the scafold
00112             factorRecenteringLoopMass=0.3;
00113             factorPressureLoopMass=1.0;
00114             factorForceBorder=4.5;
00115 
00116             // per-blob mirror delay (if things were well adjusted - in particular mirror waiting times, then this could be 0.
00117             //But in case of unique blobs, it may be interesting to accelerate display AND correct the delay by software):
00118             displaySensingBuffer.setDelayMirrors(2);
00119 
00120             break;
00121 
00122         case CONTRACT:
00123 
00124             sprintf(spotName,"loop_contract"); //this is an relaxing elastic loop
00125 
00126             setColor(0x07);//0x04+0x02>>i);
00127              blueTouch=true;
00128              
00129             // default (initial) shape:
00130             startRadius =400;
00131             bluePrint.buildCircularScafold(startRadius,  vector2Dd(0,0), 40); //(float _radius, vector2Dd _pos,vector2D _vel, int _numScafoldPoints);
00132 
00133             // Numeric parameters for the simulated mechanical system:
00134             massLoopParticle=0.25;
00135             dampMotionMassesLoop=0.024;//0.17;
00136             massAnchor=2.0;
00137             dampMotionAnchorMass=0.001;
00138             // Springs:
00139             centralSpringK=0.5;
00140             centralSpringRelax=startRadius;
00141             interSpringK=0.4;//46;
00142             interSpringRelax=30;
00143             // for "zack-like" blob:
00144             interParticleRange=100;
00145             factorInterParticleForce=18.0;
00146 
00147             searchActive=false;
00148             pseudopodesMode=false; // this is for contour following.
00149 
00150             // Active/Inactive Forces:
00151             springForcesOnLoop=true;
00152             lightForcesOnLoop=true;
00153             forceBorderOnLoop=false;
00154             nuclearForceOnLoop=true;//true;
00155             interParticleForceOnLoop=false;
00156             forceInternalPressureOnLoop=false; // (when true, either constant force or calculated area using Green function or approximation by bounding box)
00157             // Recentering vector:
00158             angleCorrectionForceLoop=0;// in deg
00159             recenteringForceOnLoop=false;
00160             angleCorrectionForceNucleus=0;// in deg
00161             recenteringForceOnNucleus=false;//true;
00162 
00163             factorLightForce=6.0;//3.0;//8.0;
00164             factorRecenteringAnchorMass=20.0/bluePrint.scafold.size();
00165             factorRecenteringLoopMass=0.3;
00166             factorPressureLoopMass=1.0;
00167             factorForceBorder=4.5;
00168 
00169             // per-blob mirror delay (if things were well adjusted - in particular mirror waiting times, then this could be 0.
00170             //But in case of unique blobs, it may be interesting to accelerate display AND correct the delay by software):
00171             displaySensingBuffer.setDelayMirrors(2);    // per-blob mirror delay (if things were well adjusted - in particular mirror waiting times, then this could be 0.
00172 
00173             break;
00174         case CONTRACT_CENTRAL:  // this is the "big mouth"
00175                       
00176             integrationStepLoop=0.4;
00177             integrationStepAnchor=0.4;
00178     
00179             sprintf(spotName,"contract_central");
00180 
00181             //setColor(0x07);//0x04+0x02>>i);
00182             setColor(0x04);
00183              blueTouch=true;
00184 
00185             // default (initial) shape:
00186             startRadius=400;
00187             bluePrint.buildCircularScafold(startRadius,  vector2Dd(0,0), 45); //(float _radius, vector2Dd _pos,vector2D _vel, int _numScafoldPoints);
00188 
00189             // Numeric parameters for the simulated mechanical system:
00190             massLoopParticle=0.3;
00191             dampMotionMassesLoop=0.023;//0.17;
00192             massAnchor=0.5;
00193             dampMotionAnchorMass=0.001;
00194             // Springs:
00195             centralSpringK=0.3;
00196             centralSpringRelax=startRadius;
00197             interSpringK=0.54;//46;
00198             interSpringRelax=25;//30;
00199             // for "zack-like" blob:
00200             interParticleRange=100;
00201             factorInterParticleForce=18.0;
00202 
00203             searchActive=false;
00204             pseudopodesMode=false; // this is for contour following.
00205 
00206             // Active/Inactive Forces:
00207             springForcesOnLoop= true;
00208             lightForcesOnLoop= true; 
00209             forceBorderOnLoop=false;
00210             nuclearForceOnLoop=false;//true;
00211             interParticleForceOnLoop=false;
00212             forceInternalPressureOnLoop=false; // (when true, either constant force or calculated area using Green function or approximation by bounding box)
00213             // Recentering vector:
00214             angleCorrectionForceLoop=0;// in deg
00215             recenteringForceOnLoop=false ; //true; !!!!!!!!!!!!!!! 
00216             angleCorrectionForceNucleus=0;// in deg
00217             recenteringForceOnNucleus=false;//true;
00218 
00219             factorLightForce=8.0;//4.3;
00220             factorRecenteringAnchorMass= 20.0/bluePrint.scafold.size();
00221             factorRecenteringLoopMass=0.045;
00222             factorPressureLoopMass=1.5;
00223             factorForceBorder=150;
00224 
00225             // per-blob mirror delay (if things were well adjusted - in particular mirror waiting times, then this could be 0.
00226             //But in case of unique blobs, it may be interesting to accelerate display AND correct the delay by software):
00227             displaySensingBuffer.setDelayMirrors(1);
00228 
00229             break;
00230             
00231         case CONTRACT_CENTRAL_FAST:
00232         
00233                       //setColor(0x07);//0x04+0x02>>i);
00234                       setColor(0x04);
00235                        blueTouch=true;
00236 
00237                       // default (initial) shape:
00238                       startRadius=150;
00239                       bluePrint.buildCircularScafold(startRadius,  vector2Dd(0,0), 40); //(float _radius, vector2Dd _pos,vector2D _vel, int _numScafoldPoints);
00240 
00241                       // Numeric parameters for the simulated mechanical system:
00242                       massLoopParticle=0.06;
00243                       dampMotionMassesLoop=0.021;//0.17;
00244                       massAnchor=0.5;
00245                       dampMotionAnchorMass=0.01;
00246                       // Springs:
00247                       centralSpringK=0.3;
00248                       centralSpringRelax=startRadius;
00249                       interSpringK=0.54;//46;
00250                       interSpringRelax=40;
00251                       // for "zack-like" blob:
00252                       interParticleRange=150;
00253                       factorInterParticleForce=160.0;
00254 
00255                       searchActive=false;
00256                       pseudopodesMode=false; // this is for contour following.
00257 
00258                       // Active/Inactive Forces:
00259                       springForcesOnLoop= true;
00260                       lightForcesOnLoop= true;
00261                       forceBorderOnLoop=false;
00262                       nuclearForceOnLoop=false;
00263                       interParticleForceOnLoop=true;  //!!!
00264                       forceInternalPressureOnLoop=false; // (when true, either constant force or calculated area using Green function or approximation by bounding box)
00265                       // Recentering vector:
00266                       angleCorrectionForceLoop=90;// in deg
00267                       recenteringForceOnLoop=true;
00268                       angleCorrectionForceNucleus=0;// in deg
00269                       recenteringForceOnNucleus=false;//true;
00270 
00271                       factorLightForce=-4;//3.0;//8.0;
00272                       factorRecenteringAnchorMass= 20.0/bluePrint.scafold.size();
00273                       factorRecenteringLoopMass=0.06;
00274                       factorPressureLoopMass=1.5;
00275                       factorForceBorder=150;
00276                       
00277                      displaySensingBuffer.setDelayMirrors(1);
00278             break;
00279 
00280         case CONTOUR_FOLLOWING:
00281             sprintf(spotName,"following"); //this is a contour-following loop
00282 
00283             integrationStepLoop=0.22;
00284             integrationStepAnchor=0.4;
00285             
00286             //setColor(0x07);//0x04+0x02>>i);
00287             setColor(0x04);
00288              blueTouch=true;
00289 
00290             // default (initial) shape:
00291             startRadius=100;
00292             bluePrint.buildCircularScafold(startRadius, vector2Dd(0,0), 20); //(float _radius, vector2Dd _pos,vector2D _vel, int _numScafoldPoints);
00293 
00294             // Numeric parameters for the simulated mechanical system:
00295             massLoopParticle=0.05;
00296             dampMotionMassesLoop=0.27;//0.17;
00297             massAnchor=3.0;
00298             dampMotionAnchorMass=0.03;
00299             // Springs:
00300             centralSpringK=0.4;
00301             centralSpringRelax=100;//bluePrint.radius;
00302             interSpringK=0.4;
00303             interSpringRelax=0.7*startRadius*2*sin(1.0* PI/ bluePrint.scafold.size()); // if factor=1, this makes for a perfect polygon at relax for all springs...
00304             // for "zack-like" blob:
00305             interParticleRange=70;
00306             factorInterParticleForce=4.0;
00307 
00308             searchActive=true;
00309             pseudopodesMode=true; // this is for contour following.
00310 
00311             // Active/Inactive Forces:
00312             springForcesOnLoop=true;
00313             lightForcesOnLoop=true;
00314             forceBorderOnLoop=false;
00315             nuclearForceOnLoop=false;//true;
00316             interParticleForceOnLoop=true;
00317             forceInternalPressureOnLoop=false; // (when true, either constant force or calculated area using Green function or approximation by bounding box)
00318             // Recentering vector:
00319             angleCorrectionForceLoop=0;// in deg
00320             recenteringForceOnLoop=true;
00321             angleCorrectionForceNucleus=180;// in deg
00322             recenteringForceOnNucleus=false;//true;
00323 
00324             factorLightForce=2.4;//3.0;//8.0;
00325             factorRecenteringAnchorMass=1.0;//20.0/scafold.size();
00326             factorRecenteringLoopMass=0.2;
00327             factorPressureLoopMass=1.5;
00328             factorForceBorder=150;
00329             // per-blob mirror delay (if things were well adjusted - in particular mirror waiting times, then this could be 0.
00330             //But in case of unique blobs, it may be interesting to accelerate display AND correct the delay by software):
00331             displaySensingBuffer.setDelayMirrors(2);
00332 
00333             break;
00334         case CONTOUR_FOLLOWING_FAST:
00335             sprintf(spotName,"following_fast");
00336 
00337             setColor(0x07);//0x04+0x02>>i);
00338             blueTouch=true;
00339             
00340             // default (initial) shape:
00341             startRadius=100;
00342             bluePrint.buildCircularScafold(startRadius,  vector2Dd(0,0), 30); //(float _radius, vector2Dd _pos,vector2D _vel, int _numScafoldPoints);
00343 
00344             // Numeric parameters for the simulated mechanical system:
00345             massLoopParticle=0.05;
00346             dampMotionMassesLoop=0.27;//0.17;
00347             massAnchor=3.0;
00348             dampMotionAnchorMass=0.03;
00349             // Springs:
00350             centralSpringK=-200;
00351             centralSpringRelax=100;//bluePrint.radius;
00352             interSpringK=0.5;//46;
00353             interSpringRelax=0.7*startRadius*2*sin(1.0* PI/bluePrint.scafold.size()); // if factor=1, this makes for a perfect polygon at relax for all springs...
00354             // for "zack-like" blob:
00355             interParticleRange=80;
00356             factorInterParticleForce=4.0;
00357 
00358             searchActive=false;
00359             pseudopodesMode=true; // this is for contour following.
00360 
00361             // Active/Inactive Forces:
00362             springForcesOnLoop=true;
00363             lightForcesOnLoop=true;
00364             forceBorderOnLoop=false;
00365             nuclearForceOnLoop=false;//true;
00366             interParticleForceOnLoop=false;
00367             forceInternalPressureOnLoop=false; // (when true, either constant force or calculated area using Green function or approximation by bounding box)
00368             // Recentering vector:
00369             angleCorrectionForceLoop=243;// in deg
00370             recenteringForceOnLoop=true;
00371             angleCorrectionForceNucleus=180;// in deg
00372             recenteringForceOnNucleus=false;//true;
00373 
00374             factorLightForce=2.3;//3.0;//8.0;
00375             factorRecenteringAnchorMass=1.0;//20.0/bluePrint.scafold.size();
00376             factorRecenteringLoopMass=0.09;
00377             factorPressureLoopMass=1.5;
00378             factorForceBorder=150;
00379 
00380             // per-blob mirror delay (if things were well adjusted - in particular mirror waiting times, then this could be 0.
00381             //But in case of unique blobs, it may be interesting to accelerate display AND correct the delay by software):
00382             displaySensingBuffer.setDelayMirrors(2);
00383             break;
00384         case BOUNCING:
00385             sprintf(spotName,"bouncing");
00386 
00387             setColor(0x07);//0x04+0x02>>i);
00388              blueTouch=true;
00389              
00390             // default (initial) shape:
00391             startRadius=70;
00392             bluePrint.buildCircularScafold(startRadius, vector2Dd(0,0), 20); //(float _radius, vector2Dd _pos,vector2D _vel, int _numScafoldPoints);
00393 
00394             // Numeric parameters for the simulated mechanical system:
00395             massLoopParticle=5.0;
00396             dampMotionMassesLoop=0.001;//0.17;
00397             massAnchor=1.0;
00398             dampMotionAnchorMass=0.002;
00399             // Springs:
00400             centralSpringK=1.0;
00401             centralSpringRelax=70;//bluePrint.radius;
00402             interSpringK=0.4;//46;
00403             interSpringRelax==1.0*startRadius*2*sin(1.0* PI/bluePrint.scafold.size()); // if factor=1, this makes for a perfect polygon at relax for all springs...
00404             // for "zack-like" blob:
00405             interParticleRange=100;
00406             factorInterParticleForce=3.0;
00407 
00408             searchActive=false;
00409             pseudopodesMode=false; // this is for contour following.
00410 
00411             // Active/Inactive Forces:
00412             springForcesOnLoop=true;
00413             lightForcesOnLoop=true;
00414             forceBorderOnLoop=true;
00415             nuclearForceOnLoop=true;//true;
00416             interParticleForceOnLoop=false;
00417             forceInternalPressureOnLoop=false; // (when true, either constant force or calculated area using Green function or approximation by bounding box)
00418             // Recentering vector:
00419             angleCorrectionForceLoop=0;// in deg
00420             recenteringForceOnLoop=false;
00421             angleCorrectionForceNucleus=0;// in deg
00422             recenteringForceOnNucleus=false;//true;
00423 
00424             factorLightForce=0.6;//3.0;//8.0;
00425             factorRecenteringAnchorMass=100.0/bluePrint.scafold.size();
00426             factorRecenteringLoopMass=5.0;
00427             factorPressureLoopMass=2.0;
00428             factorForceBorder=4.5;
00429 
00430             // per-blob mirror delay (if things were well adjusted - in particular mirror waiting times, then this could be 0.
00431             //But in case of unique blobs, it may be interesting to accelerate display AND correct the delay by software):
00432             displaySensingBuffer.setDelayMirrors(2);
00433             break;
00434     }
00435 
00436     // Finally, we can create the loop using these parameters, and the positions given in the scafold:
00437     createLoopFromScafold(); // this sets the number of masses
00438     
00439     // Excursion limits (ATTN!!! this will set the limits for all the masses, so we need FIRT to call to createLoopFromScafold - NO NEEDED ANYMORE: now calling to static member method of pointMass...)
00440     setRegionMotion(MIN_AD_MIRRORS, MIN_AD_MIRRORS, MAX_AD_MIRRORS, MAX_AD_MIRRORS);
00441     
00442     // draw it once on the display buffer for good initialization:
00443     draw();
00444 }
00445 
00446 void elasticLoop::speedFactor(float speedfactor) {
00447   // This method is more appropiate for rigid loop, but we can "simulate" speed up in case of elastic loop by changing some parameters, even if the loop is not
00448   // set in "contour following" mode. 
00449   factorRecenteringLoopMass*=speedfactor;
00450 }
00451 
00452 void elasticLoop::initSizeBlob(int _numMasses) {
00453     // Iinitialize blob size (number of points for the loop, as well as other structures such as lsdTrajectory)
00454     numMasses=_numMasses;
00455     // Since this is an elastic loop object, let's create an elastic loop of masses:
00456     massesLoop.resize(numMasses);
00457     loopSpringArray.resize(numMasses); // springs connecting consecutive masses
00458     // NOTE: to save memory, we can drop hairVector (use lightForce instead)
00459     hairVector.resize(numMasses); // the perpendiculars to the loop
00460     lightForce.resize(numMasses); //  light force in each particle
00461     //vector2D totalLightForce; // this belongs to the base class now
00462     centralSpringArray.resize(numMasses); // springs connecting each mass to the anchorMass.
00463 
00464     // Sensing and Display trajectory:
00465     displaySensingBuffer.lsdTrajectory.resize(numMasses); // the lsdTrajectory and the elastic loop will have the same number of points (this could be different - decimation?).
00466 }
00467 
00468 // We will build the masses from the scafold shape (and maybe render it once on the lsdTrajectory to initialize this array?)
00469 void elasticLoop::createLoopFromScafold(void)  {
00470     initSizeBlob(bluePrint.scafold.size()); // important: we will have here the same number of points in the scafold and the elastic loop (massLoop)
00471 
00472     // Initial conditions for the loop masses:
00473     for (int i = 0; i < numMasses; i++) {
00474         massesLoop[i].setIntegrationStep(integrationStepLoop);//22);//19); // VERY IMPORTANT! in the case of verlet integration, we need to set dt BEFORE setting the initial speed.
00475         massesLoop[i].setInitialCondition(startCenter.x+bluePrint.scafold[i].x,startCenter.y+bluePrint.scafold[i].y, startSpeed.x, startSpeed.y);
00476         massesLoop[i].mass=massLoopParticle;
00477         massesLoop[i].dampMotion=dampMotionMassesLoop;
00478     }
00479 
00480     // Springs for the loop:
00481     for (int i = 0; i<numMasses; i++) {
00482         loopSpringArray[i].distance        =interSpringRelax;
00483         // if we want an perfect polygon: =startRadius*2*sin(1.0* PI/ numMasses);
00484         // loopSpringArray[i].distance = startRadius*2*sin(1.0* PI/ numMasses);
00485         loopSpringArray[i].springiness    = interSpringK;//*(i%5==0? .6 : 1);//0.4;//4f;
00486         loopSpringArray[i].massA = & (massesLoop[i  ]);
00487         loopSpringArray[i].massB = & (massesLoop[(i+1) % numMasses]);
00488     }
00489 
00490     // Central (anchor mass):
00491     anchorMass.setIntegrationStep(0.3); // VERY IMPORTANT! in the case of verlet integration, we need to set dt BEFORE setting the initial speed.
00492     anchorMass.setInitialCondition(startCenter, startSpeed);
00493     anchorMass.mass=massAnchor;
00494     anchorMass.dampMotion = dampMotionAnchorMass;
00495 
00496 
00497     // Initial conditions for central springs:
00498     for (int i = 0; i<numMasses; i++) {
00499         centralSpringArray[i].distance       =centralSpringRelax;// + 60* cos ( (1.0*i / numMasses) * 7* 2 * PI);
00500         centralSpringArray[i].springiness    =centralSpringK;// 0.4f;
00501         centralSpringArray[i].massA = & (anchorMass);
00502         centralSpringArray[i].massB = & (massesLoop[i]);
00503     }
00504 }
00505 
00506 
00507 void elasticLoop::setRegionMotion(float mmix, float mmiy, float mmax, float mmay) { // Attention: the initial position should be INSIDE this...
00508    /*
00509     for (int i = 0; i<numMasses; i++) {
00510         massesLoop[i].setWallLimits(mmix, mmiy, mmax, mmay);
00511     }
00512     anchorMass.setWallLimits(mmix+10, mmiy+10, mmax-10, mmay-10);
00513     */
00514     
00515     // Use the static method of the class pointMass: 
00516     // pointMass::setWallLimits(mmix+10, mmiy+10, mmax-10, mmay-10);
00517      pointMass::setWallLimits(mmix+10, mmiy+10, mmax-10, mmay-10);
00518 }
00519 
00520 void elasticLoop::update(vector2Df referencePos) {
00521 
00522     // (I) Process loop geometry (compute "hair vectors", area and first order moment):
00523     processLoopData();
00524 
00525     // (II) Process sensing buffer and compute light forces
00526     // displaySensingBuffer.processSensedData();
00527 
00528     // (III) Reset all forces:
00529     for (int i = 0; i < numMasses; i++) {
00530         massesLoop[i].resetForce();
00531     }
00532     anchorMass.resetForce();
00533 
00534     // (IV) COMPUTE FORCES (motion is not update yet):
00535     //== (1) Compute each particle light force as well as total light force (this will be stored separatedly from the final total particle force to send to OSC):
00536     totalLightForce.set(0,0);
00537     for (int i = 0; i < numMasses; i++) {
00538         // NOTE: to save memory, we can drop hairVector...
00539         lightForce[i]=hairVector[i]*factorLightForce*displaySensingBuffer.lsdTrajectory[i].lightZone;
00540         lightForce[i].rotateDeg(angleCorrectionForceLoop); // correction by hand (interactive)
00541         // lightForce[i]=lightForce[i]*factorLightForce*displaySensingBuffer.lsdTrajectory[i].lightZone;
00542         //compute total light force, not only on lighted zones, because it will mean AWAY from black zones:
00543         totalLightForce+=lightForce[i]; // note: bad value choice (negative means TOUCH, and equal to -1), TO CHANGE this in future implementations
00544     }
00545     recenteringVectorLoop=totalLightForce;//.getRotated(angleCorrectionForceLoop);
00546     //== (2) Compute the "recentering vector" from the total light force:
00547     // Compute redundant quantities:
00548     normRecenteringVector=recenteringVectorLoop.length();
00549     angleRecenteringVector=recenteringVectorLoop.angleDegHoriz();
00550     recenteringVectorNucleus=totalLightForce.getRotatedDeg(angleCorrectionForceNucleus);
00551     //== (3) Compute forces on the loop:
00552     //----(a) Nearest neighbour inter-particle springs on the loop (always? we can have still another mode, following the center mass only, etc...)
00553     if (springForcesOnLoop) {
00554         for (int i = 0; i < numMasses; i++) { // if putting -1, the loop is broken
00555             loopSpringArray[i].update();// this add forces to the particles
00556         }
00557     }
00558     //----(b) Direct forces from light pressure (COULD BE MERGED WITH FORCE RECENTERING!!)
00559     if (pseudopodesMode) {
00560         // special "patches" on blob membrane, to "ATTACH" like a zip to the black drawing:
00561         if (lightForcesOnLoop) {
00562             int sign=1;
00563             for (int i = 0; i < numMasses; i++) {
00564                 if ((i%2)==0) sign*=-1;
00565                 //sign=5*cos(6*2*PI*1.0*i/(numMasses-1))-2;
00566                 if (displaySensingBuffer.lsdTrajectory[i].lightZone>0) // this means touching something black: make SOME points attracted by it (pseudopodes!!) - but not all!
00567                     massesLoop[i].addForce(lightForce[i]*(sign<0? -1.24 : 1.4)); // sign<0 means this is a pseudopode attracted by dark zones
00568                 else // this means something white: do nothing, all forces are towards the exterior
00569                     massesLoop[i].addForce(lightForce[i]*2.3); // this force tends to make the blob "inflate", but is not "directional"
00570             }
00571         }
00572         //----(c) Forces from the recentering vector on each particle (WITH PATCHES on the loop?): THIS IS RESPONSIBLE FOR THE "FOLLOWING" BEHAVIOUR
00573         if (recenteringForceOnLoop) {
00574 
00575             vector2Df auxForce= (slidingDirection? recenteringVectorLoop.getRotatedDeg(-145) : recenteringVectorLoop.getRotatedDeg(145))*factorRecenteringLoopMass*1;
00576             //vector2Df auxForce2= (slidingDirection? totalLightForce.getRotatedDeg(-90) : totalLightForce.getRotatedDeg(90))*factorRecenteringLoopMass*1.5;
00577             //vector2Df auxForce3= (slidingDirection? totalLightForce.getRotatedDeg(-90) : totalLightForce.getRotatedDeg(90))*factorRecenteringLoopMass*1.5;
00578             vector2Df auxForce2= (slidingDirection? recenteringVectorLoop.getRotatedDeg(-50) : recenteringVectorLoop.getRotatedDeg(50))*factorRecenteringLoopMass*0.5;//*1.8;
00579             vector2Df auxForce3= (slidingDirection? recenteringVectorLoop.getRotatedDeg(-30) : recenteringVectorLoop.getRotatedDeg(30))*factorRecenteringLoopMass*0.6;//1.2;
00580             
00581            
00582             int sign=1;
00583             for (int i = 0; i < numMasses; i++) {
00584                 if ((i%2)==0) sign*=-1;
00585                 if (displaySensingBuffer.lsdTrajectory[i].lightZone>0) {// this means touching something black: behaviour may depend on the pseudopode presence:
00586                 massesLoop[i].addForce((sign<0? auxForce2 : auxForce3)); // auxForce3: nothing, or sign, or corrected angle
00587                 } 
00588                 else massesLoop[i].addForce(auxForce); // this force is responsible for the behaviour (contour following or not)
00589             }
00590         }
00591     } else { // no special zones in the "cell membrane":
00592         if (lightForcesOnLoop) {
00593             for (int i = 0; i < numMasses; i++) {
00594                 massesLoop[i].addForce(lightForce[i]);
00595             }
00596         }
00597         //----(c') Forces from the recentering vector on each particle:
00598         if (recenteringForceOnLoop) {
00599             vector2Df auxForce= (slidingDirection? recenteringVectorLoop.getRotatedDeg(-90) : recenteringVectorLoop.getRotatedDeg(90))*factorRecenteringLoopMass;
00600             for (int i = 0; i < numMasses; i++) massesLoop[i].addForce(auxForce);
00601         }
00602     }
00603 
00604     //----(d) Forces from the anchorMass (depending on how we set the equilibrium position for each central spring, we can have a nice blob shape at equilibrium... like a gear for instance)
00605     if (nuclearForceOnLoop) {
00606         // Springs:
00607         for (int i = 0; i < numMasses; i++) centralSpringArray[i].update();//assymetricUpdate();
00608         // note: if using centralSpringArray[i].update(), we will add forces to the particles AND to the anchor mass...
00609         // Inverse square (attractive):
00610         //for (int i = 0; i < numMasses; i++)  massesLoop[i].addInterInvSquareForce(anchorMass, 10, 300, centralSpringK);
00611     }
00612     //----(d) Inter loop-particles forces (Zach-Liebermann-like blob):
00613     if (interParticleForceOnLoop) {
00614         for (int i = 0; i < numMasses; i++) {
00615             for (int j = 0; j < i-1; j++) massesLoop[i].addInterSpringForce(massesLoop[j], interParticleRange, factorInterParticleForce);
00616         }
00617     }
00618     //----(e) Internal blob pressure force (my faster method to have a blob-like behaviour):
00619     if (forceInternalPressureOnLoop) {
00620         // NOTE on the Physics of the thing: the force on the membrane of a ballon is proportional to the DIFFERENCE of pressures (outside and inside):
00621         // so: f= factor/area - cte, with cte=factor/area0, with area0 being the area at equilibrium.
00622         // (And of course, to make it even more exact, we should do pressure*surface, but this will be considered constant)
00623         // float area0=30000; // area in pixels when at equilibrium
00624         //float factorPressureLoopMass=-0.1*(1.0/area-1.0/area0);
00625         //float factorPressureLoopMass=500000.0*(1.0/(area*area)-1.0/(area0*area0));
00626         //float factorPressureLoopMass=20000.0*(1.0/sqrt(area)-1.0/sqrt(area0));
00627         // Constant force seems to work well too... but produces an annoying blob reversal (probably solved by using negative light forces instead of internal blob pressure):
00628         //float factorPressureLoopMass=2.5;//4.8;
00629         // Now, add the pressure force proportional to the inverse of the area to all particles, or just a signed constant:
00630         int auxsign=(area>=0? -1: 1);
00631         auxsign=-1;
00632         for (int i = 0; i < numMasses; i++) massesLoop[i].addForce( hairVector[i] * factorPressureLoopMass* auxsign);
00633     }
00634     //----(f) force from border:
00635     if (forceBorderOnLoop) {
00636         for (int i = 0; i < numMasses; i++) {
00637             if (massesLoop[i].bWallCollision) massesLoop[i].addForce(massesLoop[i].innerCollitionDirection*factorForceBorder);
00638         }
00639     }
00640 
00641     //== (4) Compute forces on the anchor mass:
00642     //----(a) Force from data send by OSC? (ex: from mouse?)
00643     // anchorMass.addSpringForce(mx, my, 500, -10.2f);
00644     // or direct control:
00645     // anchorMass.pos.x=mx;anchorMass.pos.y=my;
00646     //----(b) Force from the total light force (aka, the "recentering vector"!):
00647     if (recenteringForceOnNucleus) {
00648         anchorMass.addForce(recenteringVectorNucleus*factorRecenteringAnchorMass);
00649     }
00650 
00651     // when nothing is touching it for a while:
00652     if (searchActive) {
00653         if (!displaySensingBuffer.lightTouched) {
00654             if (firstTimeNoTouch) {
00655                 firstTimeNoTouch=false;
00656                 computeBoundingBox();
00657                 randomForce.set(2000-cx,2000-cy);
00658                 randomForce.normalize();
00659                 randomForce= randomForce.getRotatedDeg(rand()%50-25);
00660             }
00661             if (noTouchedCounter>0) {
00662                 // add random force, modulated:
00663                 float aux=1.0*noTouchedCounter/1150;
00664                 vector2Df randf=randomForce.getRotatedDeg(40.0*sin(aux*2*PI*2))*20.0;//*(1.0-aux)*0.3;
00665                 for (int i = 0; i < 1; i=i+1) { // only on some of the particles (or only one...), and better if these are in the "black attractive" patch!
00666                     massesLoop[i].addForce(randf);
00667                 }
00668                 // and a special point?
00669                 //massesLoop[numMasses/2].addForce(randf);
00670                 // plus amoeba effect ?
00671                 // for (int i = 0; i < numMasses; i++) {
00672                 //   massesLoop[i].addForce(hairVector[i]*18*cos( (0.0*noTouchedCounter/1000 + 1.0*i/(numMasses-1)*2*PI*3)));
00673                 //}
00674 
00675                 if ((noTouchedCounter>1150)||(blobWallCollision)) {
00676                     noTouchedCounter=0;
00677                     // compute force towards the center, slightly rotated to make the blob wander about:
00678                     computeBoundingBox();
00679                     randomForce.set(2000-cx,2000-cy);
00680                     randomForce.normalize();
00681                     randomForce= randomForce.getRotatedDeg(rand()%50-25);
00682                 }
00683             }
00684         } else {
00685             firstTimeNoTouch=true;
00686             noTouchedCounter=0;
00687         }
00688         noTouchedCounter++;
00689     }
00690 
00691     // (V) UPDATE DYNAMICS
00692     //== (1) particules on the loop:
00693     for (int i = 0; i < numMasses; i++) {
00694 #ifndef VERLET_METHOD
00695         massesLoop[i].addDampingForce(); // only in case of EULER method (damping in VERLET mode is done automatically when updating)
00696 #endif
00697         massesLoop[i].update(); // unconstrained
00698         massesLoop[i].bounceOffWalls(); // constrain position (and compute wall "hit")
00699     }
00700     //== (2) For the anchorMass:
00701 #ifndef VERLET_METHOD
00702     anchorMass.addDampingForce();  // // only in case of EULER method (damping in VERLET mode is done automatically when updating)
00703 #endif
00704     anchorMass.update();  // unconstrained
00705     anchorMass.bounceOffWalls(); // constrain position (and compute wall "hit")
00706 
00707     // OTHER PARTICULAR THINGS:
00708     // (1) current color: change with touch? NO
00709    // if (displaySensingBuffer.lightTouched)  
00710    //     transientBlobColor=blobColor|0x02; // set green ON on the trajectory, regardless of the initial color
00711    //  else 
00712         transientBlobColor=blobColor; // just the original blob color
00713     
00714     // change sliding direction (for countour following):
00715     if (blobWallCollision) {
00716         if (wallCounter>10) {
00717             slidingDirection=!slidingDirection;
00718             wallCounter=0;
00719         }
00720     }
00721     wallCounter++;
00722 }
00723 
00724 // Drawing the graphics - this will in fact use the graphic renderer - if any - and produce the trajectory to be displayed by the laser
00725 void elasticLoop::draw() {
00726     // for the time being, there is no "opengl" like renderer, so we just copy the coordinates of the mass into the lsdTrajectory:
00727     for (int i = 0; i < numMasses; i++) {
00728         displaySensingBuffer.lsdTrajectory[i].x= (unsigned short)( massesLoop[i].pos.x ); // note: it should be an unsigned short
00729         displaySensingBuffer.lsdTrajectory[i].y= (unsigned short)( massesLoop[i].pos.y );
00730         
00731         //displaySensingBuffer.lsdTrajectory[i]=  massesLoop[i].pos.y; // NOTE: doing this means converting from unsigned short to float (vector2Dd to vector2Df)
00732         
00733         //displaySensingBuffer.lsdTrajectory[i].color=blobColor; // perhaps per point color is not a good idea for the time being...
00734     }
00735     
00736     // Global color for the whole loop:
00737     displaySensingBuffer.displayColor=transientBlobColor;
00738 }
00739 
00740 void elasticLoop::processLoopData() {
00741 
00742     // (0) Check if the blob touched the borders:
00743     blobWallCollision=false;
00744     for (int i = 0; i < numMasses; i++) blobWallCollision= (blobWallCollision || massesLoop[i].bWallCollision);
00745 
00746     // (1) Compute all the "hairvectors" for the loop (this is, the normals to the particles, pointing outwards).
00747     //     This will be approximated by taking the 90 deg rotated difference between contiguous particles positions.
00748     for (int i = 0; i < numMasses; i++) {
00749         vector2Df diff;
00750         diff.set(massesLoop[(i+1)%numMasses].pos-massesLoop[i].pos);
00751         // normalize and rotate 90 deg:
00752         // NOTE: to save memory, we can drop hairVector...
00753         hairVector[i]=diff.getPerpendicularNormed(CW);
00754         //lightForce[i]=diff.getPerpendicularNormed(CW);
00755     }
00756 
00757     // (2) Compute area:
00758     // (a) using Green method:
00759     area=0;
00760     float dx;
00761     for (int i = 0; i < numMasses-1; i++){
00762         dx=massesLoop[i].pos.x-massesLoop[i+1].pos.x;
00763         area+=dx*massesLoop[i].pos.y;
00764     }
00765     // to avoid computation problems:
00766     // if (area<=0) area=1; // or just norm: area CAN be negative! (a loop that is larger than the original blob...)
00767 
00768     // (b) Compute approximate area from enclosing rectangle:
00769     computeBoundingBox();
00770     
00771     // (c) Compute kinetic energy:
00772     totalKineticEnergy=0;
00773     for (int i = 0; i < numMasses; i++){
00774         totalKineticEnergy+=massesLoop[i].getSpeed().squareLength();
00775     }
00776 }
00777 
00778 
00779 void elasticLoop::computeBoundingBox() {
00780     float minx=4096, maxx=-1, miny=4096, maxy=-1;
00781     for (int i = 0; i < numMasses; i++) {
00782         if (i == 0) {
00783             minx = massesLoop[i].pos.x;
00784             maxx = massesLoop[i].pos.x;
00785             miny = massesLoop[i].pos.y;
00786             maxy = massesLoop[i].pos.y;
00787         } else {
00788 
00789             minx = min(minx, massesLoop[i].pos.x);
00790             maxx = max(maxx, massesLoop[i].pos.x);
00791             miny = min(miny, massesLoop[i].pos.y);
00792             maxy = max(maxy, massesLoop[i].pos.y);
00793         }
00794     }
00795 
00796     // final results:
00797     w = maxx - minx;
00798     h = maxy - miny;
00799     cx = minx+0.5*w; // note: center will be initialized with posX and posY when calling setInitialPos() of blobConfig
00800     cy = miny+0.5*h;
00801 
00802     // approx area:
00803     approxArea=w*h;
00804 }
00805 
00806 void elasticLoop::sendDataSpecific() {
00807     char auxstring[10];
00808     myled2=1; // for tests...
00809 
00810     // First, set the top address of the message to the ID of the blob (not the name):
00811   //  sprintf(auxstring, "%d", identifier);
00812   //  sendMes.setTopAddress("0");//auxstring);
00813 
00814     // =====================   OSC  ======================
00815     if (sendOSC) {
00816 
00817         // (new) Total kinetic energy:
00818          if (sendingKineticEnergy) {
00819             sprintf(auxstring, "/k %d",identifier);
00820             sendMes.setSubAddress(auxstring);
00821             long x;    //ATTENTION: parameters to setArgs should be long or unsigned long only (not int!!)
00822             x=(long)(totalKineticEnergy);
00823             sendMes.setArgs( "i", &x);
00824             osc.sendOsc( &sendMes );
00825          }
00826         // (a) Anchor mass:
00827          if (sendingAnchorPosition) {
00828            sprintf(auxstring, "/p %d",identifier);
00829             sendMes.setSubAddress(auxstring);
00830             long x, y;    //ATTENTION: parameters to setArgs should be long or unsigned long only (not int!!)
00831             x=(long)(anchorMass.pos.x);
00832             y=(long)(anchorMass.pos.y);
00833             sendMes.setArgs( "ii", &x, &y);
00834             osc.sendOsc( &sendMes );
00835         }
00836         if (sendingAnchorForce) {
00837             sendMes.setSubAddress("/aforce");
00838             long    x, y;    //ATTENTION: parameters to setArgs should be long or unsigned long only (not int!!)
00839             x=(long)(anchorMass.totalForce.x);
00840             y=(long)(anchorMass.totalForce.y);
00841             sendMes.setArgs( "ii", &x, &y);
00842             osc.sendOsc( &sendMes );
00843         }
00844         if (sendingAnchorTouchWall) {// note: not an else (we can send different data simultaneously)
00845             sendMes.setSubAddress("/awall");
00846             long wall=(long)(anchorMass.bWallCollision? 1 : 0);
00847             sendMes.setArgs( "i", &wall);
00848             osc.sendOsc( &sendMes );
00849         }
00850         // (b) data from blob points:
00851         if (sendingLoopPositions) {
00852 #ifdef SEND_AS_POINTS
00853             long    x, y;    //ATTENTION: parameters to setArgs should be long or unsigned long only (not int!!)
00854             for (int i = 0; i < numMasses; i++) {
00855                 sprintf(auxstring, "/p %d", i); // auxstring read as "/p1", "/p2", ...
00856                 sendMes.setSubAddress(auxstring);  // ATTENTION: the host computer needs to know in advance how many points are in the loop (I did not implement "bundle" messages yet...)
00857                 x=(long)(massesLoop[i].pos.x);
00858                 y=(long)(massesLoop[i].pos.y);
00859                 sendMes.setArgs( "ii", &x, &y);
00860                 osc.sendOsc( &sendMes );
00861             }
00862 #endif
00863 #ifdef SEND_AS_BLOB
00864             sendMes.clearArgs(); // no need, we won't use osc.sendOsc()...
00865             uint8_t blobdata[4*numMasses]; // 2 bytes per coordinate, and 2 coordinates
00866             for (int i = 0; i < numMasses; i++ ) {
00867                 // note: massesLoop[i].pos.x is a "float"
00868                 uint16_t x=(uint16_t)(massesLoop[i].pos.x);
00869                 blobdata[4*i]=(uint8_t)x>>8; // BIG ENDIAN (send FIRST the MOST SIGNIFICANT BYTE)
00870                 blobdata[4*i+1]=(uint8_t)x;
00871 
00872                 uint16_t y=(uint16_t)(massesLoop[i].pos.y);
00873                 blobdata[4*i+2]=(uint8_t)y>>8; // BIG ENDIAN (send FIRST the MOST SIGNIFICANT BYTE)
00874                 blobdata[4*i+3]=(uint8_t)y;
00875             }
00876             osc.sendOscBlob(&(blobdata[0]), 4*numMasses, &sendMes ); // second parameter is osc blob size in bytes
00877 #endif
00878 #ifdef SEND_AS_STRING
00879             sendMes.clearArgs(); // no need, we won't use osc.sendOsc()...
00880             uint8_t blobdata[4*numMasses]; // 2 bytes per coordinate, and 2 coordinates
00881             for (int i = 0; i < numMasses; i++ ) {
00882                 // note: massesLoop[i].pos.x is a "float"
00883                 uint16_t x=(uint16_t)(massesLoop[i].pos.x);
00884                 blobdata[4*i]=(uint8_t)x>>8; // BIG ENDIAN (send FIRST the MOST SIGNIFICANT BYTE)
00885                 blobdata[4*i+1]=(uint8_t)x;
00886 
00887                 uint16_t y=(uint16_t)(massesLoop[i].pos.y);
00888                 blobdata[4*i+2]=(uint8_t)y>>8; // BIG ENDIAN (send FIRST the MOST SIGNIFICANT BYTE)
00889                 blobdata[4*i+3]=(uint8_t)y;
00890             }
00891             osc.sendOscString(blobdata, 4*numMasses, &sendMes ); // second parameter is osc blob size in bytes
00892 #endif
00893         }
00894         if (sendingLoopForces) { // ATTN: the force is the TOTAL force on the point (interesting perhaps for making sound...)
00895             long    x, y;    //ATTENTION: parameters to setArgs should be long or unsigned long only (not int!!)
00896             for (int i = 0; i < numMasses; i++) {
00897                 sprintf(auxstring, "/f%d", i); // auxstring read as "/f1", "/f2", ...
00898                 sendMes.setSubAddress(auxstring);  // ATTENTION: the host computer needs to know in advance how many points are in the loop (I did not implement "bundle" messages yet...)
00899                 x=(long)(massesLoop[i].totalForce.x);
00900                 y=(long)(massesLoop[i].totalForce.y);
00901                 sendMes.setArgs( "ii", &x, &y);
00902                 osc.sendOsc( &sendMes );
00903             }
00904         }
00905         if (sendingLoopForcesLight) { // ATTN: the force is the TOTAL force on the point (interesting perhaps for making sound...)
00906             long    x, y;    //ATTENTION: parameters to setArgs should be long or unsigned long only (not int!!)
00907             for (int i = 0; i < numMasses; i++) {
00908                 sprintf(auxstring, "/g%d", i); // auxstring read as "/f1", "/f2", ...
00909                 sendMes.setSubAddress(auxstring);  // ATTENTION: the host computer needs to know in advance how many points are in the loop (I did not implement "bundle" messages yet...)
00910                 x=(long)(1000*lightForce[i].x);
00911                 y=(long)(1000*lightForce[i].y);
00912                 sendMes.setArgs( "ii", &x, &y);
00913                 osc.sendOsc( &sendMes );
00914             }
00915         }
00916 
00917         if (sendingLoopRegions) {
00918             long    x;   //ATTENTION: parameters to setArgs should be long or unsigned long only (not int!!)
00919             for (int i = 0; i < numMasses; i++) {
00920                 sprintf(auxstring, "/r%d", i); // auxstring read as "/f1", "/f2", ...
00921                 sendMes.setSubAddress(auxstring);  // ATTENTION: the host computer needs to know in advance how many points are in the loop (I did not implement "bundle" messages yet...)
00922                 x=(long)(displaySensingBuffer.lsdTrajectory[i].lightZone>0? 1 : 0);
00923                 sendMes.setArgs( "i", &x);
00924                 osc.sendOsc( &sendMes );
00925             }
00926         }
00927         if (sendingLoopTouchWall) { // global touch wall for the loop (not per point)
00928             long    wall;   //ATTENTION: parameters to setArgs should be long or unsigned long only (not int!!)
00929             sprintf(auxstring, "/bWall");
00930             sendMes.setSubAddress(auxstring);
00931             wall=(long)(blobWallCollision? 1 : 0);
00932             sendMes.setArgs( "i", &wall);
00933             osc.sendOsc( &sendMes );
00934         }
00935         // (c) Blob geometry:
00936         if (sendingBlobArea) {
00937          /*  sendMes.setSubAddress("/a");
00938             long    x;    //ATTENTION: parameters to setArgs should be long or unsigned long only (not int!!)
00939            // x=(long)(area);//approxArea); // area or approxArea
00940             x=(long)(area>0? approxArea : -approxArea);
00941             sendMes.setArgs( "i", &x); // ATTENTION: AREA CAN BE NEGATIVE!!! (does MAX handles this well? test this!)
00942          */   
00943             // HACK for the time being (for Daito):
00944             sendMes.setSubAddress("/a");
00945             long    x, y;    //ATTENTION: parameters to setArgs should be long or unsigned long only (not int!!)
00946            // x=(long)(area);//approxArea); // area or approxArea
00947             x=(long)(w); y=(long)(h);
00948             sendMes.setArgs( "ii", &x, &y); // ATTENTION: AREA CAN BE NEGATIVE!!! (does MAX handles this well? test this!)
00949             
00950             osc.sendOsc( &sendMes );
00951         }
00952         if (sendingBlobNormals) {
00953             long    x, y;   //ATTENTION: parameters to setArgs should be long or unsigned long only (not int!!)
00954             for (int i = 0; i < numMasses; i++) {
00955                 sprintf(auxstring, "nf%d", i); // auxstring read as "/f1", "/f2", ...
00956                 sendMes.setSubAddress(auxstring);  // ATTENTION: the host computer needs to know in advance how many points are in the loop (I did not implement "bundle" messages yet...)
00957                 x=(long)(hairVector[i].x);
00958                 y=(long)(hairVector[i].y);
00959                 sendMes.setArgs( "ii", &x, &y);
00960                 osc.sendOsc( &sendMes );
00961             }
00962         }
00963         if (sendingBlobAngles) {
00964             long   x;   //ATTENTION: parameters to setArgs should be long or unsigned long only (not int!!)
00965             for (int i = 0; i < numMasses; i++) {
00966                 sprintf(auxstring, "/a%d", i); // auxstring read as "/f1", "/f2", ...
00967                 sendMes.setSubAddress(auxstring);  // ATTENTION: the host computer needs to know in advance how many points are in the loop (I did not implement "bundle" messages yet...)
00968                 x=(long)(hairVector[i].angleDegHoriz());
00969                 sendMes.setArgs( "i", &x);
00970                 osc.sendOsc( &sendMes );
00971             }
00972         }
00973         // (d) Light sensing statistics:
00974         if (sendingBlobMaxMin) {
00975             sendMes.setSubAddress("/maxmin");
00976             long    x, y;    //ATTENTION: parameters to setArgs should be long or unsigned long only (not int!!)
00977             x=(long)(displaySensingBuffer.maxI);
00978             y=(long)(displaySensingBuffer.minI);
00979             sendMes.setArgs( "ii", &x, &y);
00980             osc.sendOsc( &sendMes );
00981         }
00982         if (sendingLightForce) {
00983             sendMes.setSubAddress("/lforce");
00984             long    x, y;    //ATTENTION: parameters to setArgs should be long or unsigned long only (not int!!)
00985             x=(long)(totalLightForce.x);
00986             y=(long)(totalLightForce.y);
00987             sendMes.setArgs( "ii", &x, &y);
00988             osc.sendOsc( &sendMes );
00989         }
00990         // (e) Recentering vector: (note: redundant with sendingLightForce, IF the correction angle is known).
00991         if (sendingRecenteringVector) {
00992             sendMes.setSubAddress("/rvector");
00993             long    x, y;    //ATTENTION: parameters to setArgs should be long or unsigned long only (not int!!)
00994             x=(long)(recenteringVectorLoop.x);
00995             y=(long)(recenteringVectorLoop.y);
00996             sendMes.setArgs( "ii", &x, &y);
00997             osc.sendOsc( &sendMes );
00998         }
00999         if (sendingRecenteringAngle) {
01000             sendMes.setSubAddress("/rangle");
01001             long    x;    //ATTENTION: parameters to setArgs should be long or unsigned long only (not int!!)
01002             x=(long)(angleRecenteringVector);
01003             sendMes.setArgs( "i", &x);
01004             osc.sendOsc( &sendMes );
01005         }
01006         if (sendingRecenteringNorm) {
01007             sendMes.setSubAddress("/rnorm");
01008             long    x;    //ATTENTION: parameters to setArgs should be long or unsigned long only (not int!!)
01009             x=(long)(normRecenteringVector);
01010             sendMes.setArgs( "i", &x);
01011             osc.sendOsc( &sendMes );
01012         }
01013 
01014         if (sendingTouched) {
01015             if (displaySensingBuffer.lightTouched) {
01016                 sendMes.clearArgs(); // there are no arguments to send
01017                 sendMes.setSubAddress("/touched");
01018                 osc.sendOsc( &sendMes );
01019             }
01020         }
01021 
01022     } // end of OSC sending per-spot
01023 
01024     // =====================   SERIAL  ======================
01025     if (sendSerial) {
01026         //.. to do
01027     }
01028 
01029     myled2=0; // for tests...
01030 }
01031