save loops

Dependencies:   mbed

Revision:
0:df6fdd9b99f0
diff -r 000000000000 -r df6fdd9b99f0 elasticLoop.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/elasticLoop.cpp	Tue Dec 02 04:39:15 2014 +0000
@@ -0,0 +1,1031 @@
+/*
+ *  elasticLoop.cpp
+ *  laserBlobPure
+ *
+ *  Created by CASSINELLI ALVARO on 5/20/11.
+ *  Copyright 2011 TOKYO UNIVERSITY. All rights reserved.
+ *
+ */
+
+#include "elasticLoop.h"
+
+// SHOULD NOT BE HERE: (only because I am using AD_MIRRIOR... max and min in the set region function that should not be here)
+#include "hardwareIO.h"
+
+elasticLoop::elasticLoop() {
+}
+
+elasticLoop::~elasticLoop() {
+    // no need to do clear, this is done by default when clearing the vector container?
+        massesLoop.clear();
+        loopSpringArray.clear();
+        hairVector.clear();
+        lightForce.clear();
+        centralSpringArray.clear();
+        displaySensingBuffer.lsdTrajectory.clear();
+}
+
+void elasticLoop::showChildParameters() {
+   // pc.printf("Mirror delay :%d\n", displaySensingBuffer.delayMirrorSamples);
+   // pc.printf("Angle correction force :%d\n", angleCorrectionForceLoop);
+    pc.printf("Integration Step Loop :%f\n", integrationStepLoop);
+    pc.printf("Integration Step Anchor :%f\n", integrationStepAnchor);
+    }
+
+void elasticLoop::createBlob(int _id, ElasticLoopMode _elasticBlobMode, vector2Df _initPos, vector2Df _initSpeed) {
+    // (1) set ID:
+    identifier=_id;
+
+    startCenter=_initPos;
+    startSpeed=_initSpeed;
+
+// (2) Initialize common variables of all blobs (base class):
+//   initCommonVariables();
+
+    // (3) initialize common variables for the elastic blob types:
+    integrationStepLoop=0.22;
+    integrationStepAnchor=0.4;
+    
+    slidingDirection=true; //  (will change when touching wall)
+    // Sending data:
+    periodSendingData=15; // in ms
+    sendingLoopPositions=false;
+    sendingBlobArea=true;
+    sendingKineticEnergy=true;
+    sendingBlobMaxMin=true;
+     // send ALWAYS, regardless of the fact the blob is being touched or not, in case of elastic loops:
+    sendingOnlyWhenTouch=false;
+
+// (3) Initialize secondary variables depending on the blob type and mode:
+
+// 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
+// actually be "condensed" in a mode...)
+
+    switch (_elasticBlobMode) {
+        case RELAX:
+
+            // Name of this kind of spot:
+            sprintf(spotName,"loop_relax"); //this is an relaxing elastic loop
+
+            // Color: (use parameter in the future):
+            //setColor(0x07);//0x04+0x02>>i);
+            setColor(0x04);
+            blueTouch=true;
+
+            // default (initial) shape (the scafold belongs to the base class):
+            startRadius=400;
+            bluePrint.buildCircularScafold(startRadius, vector2Dd(0,0), 40); //(float _radius, vector2Dd _pos, int _numScafoldPoints);
+
+            // Numeric parameters for the simulated mechanical system:
+            massLoopParticle=0.25;
+            dampMotionMassesLoop=0.025;//0.17;
+            massAnchor=2.0;
+            dampMotionAnchorMass=0.001;
+            // Springs:
+            centralSpringK=0.3;
+            centralSpringRelax=startRadius;// use the radius of the scafold
+            interSpringK=0.46;
+            interSpringRelax=20;
+            // for "zack-like" blob:
+            interParticleRange=100;
+            factorInterParticleForce=18.0;
+
+            searchActive=false;
+            pseudopodesMode=false; // this is for contour following.
+
+            // Active/inactive forces:
+            springForcesOnLoop=true;
+            lightForcesOnLoop=true;
+            forceBorderOnLoop=false;
+            nuclearForceOnLoop=false;//true;
+            interParticleForceOnLoop=false;
+            forceInternalPressureOnLoop=false; // (when true, either constant force or calculated area using Green function or approximation by bounding box)
+
+            // Recentering vector:
+            angleCorrectionForceLoop=0;// in deg
+            recenteringForceOnLoop=false;
+            angleCorrectionForceNucleus=0;// in deg
+            recenteringForceOnNucleus=false;//true;
+
+            factorLightForce=4.0;//3.0;//8.0;
+            factorRecenteringAnchorMass=20.0/bluePrint.scafold.size(); // use number of points in the scafold
+            factorRecenteringLoopMass=0.3;
+            factorPressureLoopMass=1.0;
+            factorForceBorder=4.5;
+
+            // per-blob mirror delay (if things were well adjusted - in particular mirror waiting times, then this could be 0.
+            //But in case of unique blobs, it may be interesting to accelerate display AND correct the delay by software):
+            displaySensingBuffer.setDelayMirrors(2);
+
+            break;
+
+        case CONTRACT:
+
+            sprintf(spotName,"loop_contract"); //this is an relaxing elastic loop
+
+            setColor(0x07);//0x04+0x02>>i);
+             blueTouch=true;
+             
+            // default (initial) shape:
+            startRadius =400;
+            bluePrint.buildCircularScafold(startRadius,  vector2Dd(0,0), 40); //(float _radius, vector2Dd _pos,vector2D _vel, int _numScafoldPoints);
+
+            // Numeric parameters for the simulated mechanical system:
+            massLoopParticle=0.25;
+            dampMotionMassesLoop=0.024;//0.17;
+            massAnchor=2.0;
+            dampMotionAnchorMass=0.001;
+            // Springs:
+            centralSpringK=0.5;
+            centralSpringRelax=startRadius;
+            interSpringK=0.4;//46;
+            interSpringRelax=30;
+            // for "zack-like" blob:
+            interParticleRange=100;
+            factorInterParticleForce=18.0;
+
+            searchActive=false;
+            pseudopodesMode=false; // this is for contour following.
+
+            // Active/Inactive Forces:
+            springForcesOnLoop=true;
+            lightForcesOnLoop=true;
+            forceBorderOnLoop=false;
+            nuclearForceOnLoop=true;//true;
+            interParticleForceOnLoop=false;
+            forceInternalPressureOnLoop=false; // (when true, either constant force or calculated area using Green function or approximation by bounding box)
+            // Recentering vector:
+            angleCorrectionForceLoop=0;// in deg
+            recenteringForceOnLoop=false;
+            angleCorrectionForceNucleus=0;// in deg
+            recenteringForceOnNucleus=false;//true;
+
+            factorLightForce=6.0;//3.0;//8.0;
+            factorRecenteringAnchorMass=20.0/bluePrint.scafold.size();
+            factorRecenteringLoopMass=0.3;
+            factorPressureLoopMass=1.0;
+            factorForceBorder=4.5;
+
+            // per-blob mirror delay (if things were well adjusted - in particular mirror waiting times, then this could be 0.
+            //But in case of unique blobs, it may be interesting to accelerate display AND correct the delay by software):
+            displaySensingBuffer.setDelayMirrors(2);    // per-blob mirror delay (if things were well adjusted - in particular mirror waiting times, then this could be 0.
+
+            break;
+        case CONTRACT_CENTRAL:  // this is the "big mouth"
+                      
+            integrationStepLoop=0.4;
+            integrationStepAnchor=0.4;
+    
+            sprintf(spotName,"contract_central");
+
+            //setColor(0x07);//0x04+0x02>>i);
+            setColor(0x04);
+             blueTouch=true;
+
+            // default (initial) shape:
+            startRadius=400;
+            bluePrint.buildCircularScafold(startRadius,  vector2Dd(0,0), 45); //(float _radius, vector2Dd _pos,vector2D _vel, int _numScafoldPoints);
+
+            // Numeric parameters for the simulated mechanical system:
+            massLoopParticle=0.3;
+            dampMotionMassesLoop=0.023;//0.17;
+            massAnchor=0.5;
+            dampMotionAnchorMass=0.001;
+            // Springs:
+            centralSpringK=0.3;
+            centralSpringRelax=startRadius;
+            interSpringK=0.54;//46;
+            interSpringRelax=25;//30;
+            // for "zack-like" blob:
+            interParticleRange=100;
+            factorInterParticleForce=18.0;
+
+            searchActive=false;
+            pseudopodesMode=false; // this is for contour following.
+
+            // Active/Inactive Forces:
+            springForcesOnLoop= true;
+            lightForcesOnLoop= true; 
+            forceBorderOnLoop=false;
+            nuclearForceOnLoop=false;//true;
+            interParticleForceOnLoop=false;
+            forceInternalPressureOnLoop=false; // (when true, either constant force or calculated area using Green function or approximation by bounding box)
+            // Recentering vector:
+            angleCorrectionForceLoop=0;// in deg
+            recenteringForceOnLoop=false ; //true; !!!!!!!!!!!!!!! 
+            angleCorrectionForceNucleus=0;// in deg
+            recenteringForceOnNucleus=false;//true;
+
+            factorLightForce=8.0;//4.3;
+            factorRecenteringAnchorMass= 20.0/bluePrint.scafold.size();
+            factorRecenteringLoopMass=0.045;
+            factorPressureLoopMass=1.5;
+            factorForceBorder=150;
+
+            // per-blob mirror delay (if things were well adjusted - in particular mirror waiting times, then this could be 0.
+            //But in case of unique blobs, it may be interesting to accelerate display AND correct the delay by software):
+            displaySensingBuffer.setDelayMirrors(1);
+
+            break;
+            
+        case CONTRACT_CENTRAL_FAST:
+        
+                      //setColor(0x07);//0x04+0x02>>i);
+                      setColor(0x04);
+                       blueTouch=true;
+
+                      // default (initial) shape:
+                      startRadius=150;
+                      bluePrint.buildCircularScafold(startRadius,  vector2Dd(0,0), 40); //(float _radius, vector2Dd _pos,vector2D _vel, int _numScafoldPoints);
+
+                      // Numeric parameters for the simulated mechanical system:
+                      massLoopParticle=0.06;
+                      dampMotionMassesLoop=0.021;//0.17;
+                      massAnchor=0.5;
+                      dampMotionAnchorMass=0.01;
+                      // Springs:
+                      centralSpringK=0.3;
+                      centralSpringRelax=startRadius;
+                      interSpringK=0.54;//46;
+                      interSpringRelax=40;
+                      // for "zack-like" blob:
+                      interParticleRange=150;
+                      factorInterParticleForce=160.0;
+
+                      searchActive=false;
+                      pseudopodesMode=false; // this is for contour following.
+
+                      // Active/Inactive Forces:
+                      springForcesOnLoop= true;
+                      lightForcesOnLoop= true;
+                      forceBorderOnLoop=false;
+                      nuclearForceOnLoop=false;
+                      interParticleForceOnLoop=true;  //!!!
+                      forceInternalPressureOnLoop=false; // (when true, either constant force or calculated area using Green function or approximation by bounding box)
+                      // Recentering vector:
+                      angleCorrectionForceLoop=90;// in deg
+                      recenteringForceOnLoop=true;
+                      angleCorrectionForceNucleus=0;// in deg
+                      recenteringForceOnNucleus=false;//true;
+
+                      factorLightForce=-4;//3.0;//8.0;
+                      factorRecenteringAnchorMass= 20.0/bluePrint.scafold.size();
+                      factorRecenteringLoopMass=0.06;
+                      factorPressureLoopMass=1.5;
+                      factorForceBorder=150;
+                      
+                     displaySensingBuffer.setDelayMirrors(1);
+            break;
+
+        case CONTOUR_FOLLOWING:
+            sprintf(spotName,"following"); //this is a contour-following loop
+
+            integrationStepLoop=0.22;
+            integrationStepAnchor=0.4;
+            
+            //setColor(0x07);//0x04+0x02>>i);
+            setColor(0x04);
+             blueTouch=true;
+
+            // default (initial) shape:
+            startRadius=100;
+            bluePrint.buildCircularScafold(startRadius, vector2Dd(0,0), 20); //(float _radius, vector2Dd _pos,vector2D _vel, int _numScafoldPoints);
+
+            // Numeric parameters for the simulated mechanical system:
+            massLoopParticle=0.05;
+            dampMotionMassesLoop=0.27;//0.17;
+            massAnchor=3.0;
+            dampMotionAnchorMass=0.03;
+            // Springs:
+            centralSpringK=0.4;
+            centralSpringRelax=100;//bluePrint.radius;
+            interSpringK=0.4;
+            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...
+            // for "zack-like" blob:
+            interParticleRange=70;
+            factorInterParticleForce=4.0;
+
+            searchActive=true;
+            pseudopodesMode=true; // this is for contour following.
+
+            // Active/Inactive Forces:
+            springForcesOnLoop=true;
+            lightForcesOnLoop=true;
+            forceBorderOnLoop=false;
+            nuclearForceOnLoop=false;//true;
+            interParticleForceOnLoop=true;
+            forceInternalPressureOnLoop=false; // (when true, either constant force or calculated area using Green function or approximation by bounding box)
+            // Recentering vector:
+            angleCorrectionForceLoop=0;// in deg
+            recenteringForceOnLoop=true;
+            angleCorrectionForceNucleus=180;// in deg
+            recenteringForceOnNucleus=false;//true;
+
+            factorLightForce=2.4;//3.0;//8.0;
+            factorRecenteringAnchorMass=1.0;//20.0/scafold.size();
+            factorRecenteringLoopMass=0.2;
+            factorPressureLoopMass=1.5;
+            factorForceBorder=150;
+            // per-blob mirror delay (if things were well adjusted - in particular mirror waiting times, then this could be 0.
+            //But in case of unique blobs, it may be interesting to accelerate display AND correct the delay by software):
+            displaySensingBuffer.setDelayMirrors(2);
+
+            break;
+        case CONTOUR_FOLLOWING_FAST:
+            sprintf(spotName,"following_fast");
+
+            setColor(0x07);//0x04+0x02>>i);
+            blueTouch=true;
+            
+            // default (initial) shape:
+            startRadius=100;
+            bluePrint.buildCircularScafold(startRadius,  vector2Dd(0,0), 30); //(float _radius, vector2Dd _pos,vector2D _vel, int _numScafoldPoints);
+
+            // Numeric parameters for the simulated mechanical system:
+            massLoopParticle=0.05;
+            dampMotionMassesLoop=0.27;//0.17;
+            massAnchor=3.0;
+            dampMotionAnchorMass=0.03;
+            // Springs:
+            centralSpringK=-200;
+            centralSpringRelax=100;//bluePrint.radius;
+            interSpringK=0.5;//46;
+            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...
+            // for "zack-like" blob:
+            interParticleRange=80;
+            factorInterParticleForce=4.0;
+
+            searchActive=false;
+            pseudopodesMode=true; // this is for contour following.
+
+            // Active/Inactive Forces:
+            springForcesOnLoop=true;
+            lightForcesOnLoop=true;
+            forceBorderOnLoop=false;
+            nuclearForceOnLoop=false;//true;
+            interParticleForceOnLoop=false;
+            forceInternalPressureOnLoop=false; // (when true, either constant force or calculated area using Green function or approximation by bounding box)
+            // Recentering vector:
+            angleCorrectionForceLoop=243;// in deg
+            recenteringForceOnLoop=true;
+            angleCorrectionForceNucleus=180;// in deg
+            recenteringForceOnNucleus=false;//true;
+
+            factorLightForce=2.3;//3.0;//8.0;
+            factorRecenteringAnchorMass=1.0;//20.0/bluePrint.scafold.size();
+            factorRecenteringLoopMass=0.09;
+            factorPressureLoopMass=1.5;
+            factorForceBorder=150;
+
+            // per-blob mirror delay (if things were well adjusted - in particular mirror waiting times, then this could be 0.
+            //But in case of unique blobs, it may be interesting to accelerate display AND correct the delay by software):
+            displaySensingBuffer.setDelayMirrors(2);
+            break;
+        case BOUNCING:
+            sprintf(spotName,"bouncing");
+
+            setColor(0x07);//0x04+0x02>>i);
+             blueTouch=true;
+             
+            // default (initial) shape:
+            startRadius=70;
+            bluePrint.buildCircularScafold(startRadius, vector2Dd(0,0), 20); //(float _radius, vector2Dd _pos,vector2D _vel, int _numScafoldPoints);
+
+            // Numeric parameters for the simulated mechanical system:
+            massLoopParticle=5.0;
+            dampMotionMassesLoop=0.001;//0.17;
+            massAnchor=1.0;
+            dampMotionAnchorMass=0.002;
+            // Springs:
+            centralSpringK=1.0;
+            centralSpringRelax=70;//bluePrint.radius;
+            interSpringK=0.4;//46;
+            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...
+            // for "zack-like" blob:
+            interParticleRange=100;
+            factorInterParticleForce=3.0;
+
+            searchActive=false;
+            pseudopodesMode=false; // this is for contour following.
+
+            // Active/Inactive Forces:
+            springForcesOnLoop=true;
+            lightForcesOnLoop=true;
+            forceBorderOnLoop=true;
+            nuclearForceOnLoop=true;//true;
+            interParticleForceOnLoop=false;
+            forceInternalPressureOnLoop=false; // (when true, either constant force or calculated area using Green function or approximation by bounding box)
+            // Recentering vector:
+            angleCorrectionForceLoop=0;// in deg
+            recenteringForceOnLoop=false;
+            angleCorrectionForceNucleus=0;// in deg
+            recenteringForceOnNucleus=false;//true;
+
+            factorLightForce=0.6;//3.0;//8.0;
+            factorRecenteringAnchorMass=100.0/bluePrint.scafold.size();
+            factorRecenteringLoopMass=5.0;
+            factorPressureLoopMass=2.0;
+            factorForceBorder=4.5;
+
+            // per-blob mirror delay (if things were well adjusted - in particular mirror waiting times, then this could be 0.
+            //But in case of unique blobs, it may be interesting to accelerate display AND correct the delay by software):
+            displaySensingBuffer.setDelayMirrors(2);
+            break;
+    }
+
+    // Finally, we can create the loop using these parameters, and the positions given in the scafold:
+    createLoopFromScafold(); // this sets the number of masses
+    
+    // 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...)
+    setRegionMotion(MIN_AD_MIRRORS, MIN_AD_MIRRORS, MAX_AD_MIRRORS, MAX_AD_MIRRORS);
+    
+    // draw it once on the display buffer for good initialization:
+    draw();
+}
+
+void elasticLoop::speedFactor(float speedfactor) {
+  // 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
+  // set in "contour following" mode. 
+  factorRecenteringLoopMass*=speedfactor;
+}
+
+void elasticLoop::initSizeBlob(int _numMasses) {
+    // Iinitialize blob size (number of points for the loop, as well as other structures such as lsdTrajectory)
+    numMasses=_numMasses;
+    // Since this is an elastic loop object, let's create an elastic loop of masses:
+    massesLoop.resize(numMasses);
+    loopSpringArray.resize(numMasses); // springs connecting consecutive masses
+    // NOTE: to save memory, we can drop hairVector (use lightForce instead)
+    hairVector.resize(numMasses); // the perpendiculars to the loop
+    lightForce.resize(numMasses); //  light force in each particle
+    //vector2D totalLightForce; // this belongs to the base class now
+    centralSpringArray.resize(numMasses); // springs connecting each mass to the anchorMass.
+
+    // Sensing and Display trajectory:
+    displaySensingBuffer.lsdTrajectory.resize(numMasses); // the lsdTrajectory and the elastic loop will have the same number of points (this could be different - decimation?).
+}
+
+// We will build the masses from the scafold shape (and maybe render it once on the lsdTrajectory to initialize this array?)
+void elasticLoop::createLoopFromScafold(void)  {
+    initSizeBlob(bluePrint.scafold.size()); // important: we will have here the same number of points in the scafold and the elastic loop (massLoop)
+
+    // Initial conditions for the loop masses:
+    for (int i = 0; i < numMasses; i++) {
+        massesLoop[i].setIntegrationStep(integrationStepLoop);//22);//19); // VERY IMPORTANT! in the case of verlet integration, we need to set dt BEFORE setting the initial speed.
+        massesLoop[i].setInitialCondition(startCenter.x+bluePrint.scafold[i].x,startCenter.y+bluePrint.scafold[i].y, startSpeed.x, startSpeed.y);
+        massesLoop[i].mass=massLoopParticle;
+        massesLoop[i].dampMotion=dampMotionMassesLoop;
+    }
+
+    // Springs for the loop:
+    for (int i = 0; i<numMasses; i++) {
+        loopSpringArray[i].distance        =interSpringRelax;
+        // if we want an perfect polygon: =startRadius*2*sin(1.0* PI/ numMasses);
+        // loopSpringArray[i].distance = startRadius*2*sin(1.0* PI/ numMasses);
+        loopSpringArray[i].springiness    = interSpringK;//*(i%5==0? .6 : 1);//0.4;//4f;
+        loopSpringArray[i].massA = & (massesLoop[i  ]);
+        loopSpringArray[i].massB = & (massesLoop[(i+1) % numMasses]);
+    }
+
+    // Central (anchor mass):
+    anchorMass.setIntegrationStep(0.3); // VERY IMPORTANT! in the case of verlet integration, we need to set dt BEFORE setting the initial speed.
+    anchorMass.setInitialCondition(startCenter, startSpeed);
+    anchorMass.mass=massAnchor;
+    anchorMass.dampMotion = dampMotionAnchorMass;
+
+
+    // Initial conditions for central springs:
+    for (int i = 0; i<numMasses; i++) {
+        centralSpringArray[i].distance       =centralSpringRelax;// + 60* cos ( (1.0*i / numMasses) * 7* 2 * PI);
+        centralSpringArray[i].springiness    =centralSpringK;// 0.4f;
+        centralSpringArray[i].massA = & (anchorMass);
+        centralSpringArray[i].massB = & (massesLoop[i]);
+    }
+}
+
+
+void elasticLoop::setRegionMotion(float mmix, float mmiy, float mmax, float mmay) { // Attention: the initial position should be INSIDE this...
+   /*
+    for (int i = 0; i<numMasses; i++) {
+        massesLoop[i].setWallLimits(mmix, mmiy, mmax, mmay);
+    }
+    anchorMass.setWallLimits(mmix+10, mmiy+10, mmax-10, mmay-10);
+    */
+    
+    // Use the static method of the class pointMass: 
+    // pointMass::setWallLimits(mmix+10, mmiy+10, mmax-10, mmay-10);
+     pointMass::setWallLimits(mmix+10, mmiy+10, mmax-10, mmay-10);
+}
+
+void elasticLoop::update(vector2Df referencePos) {
+
+    // (I) Process loop geometry (compute "hair vectors", area and first order moment):
+    processLoopData();
+
+    // (II) Process sensing buffer and compute light forces
+    // displaySensingBuffer.processSensedData();
+
+    // (III) Reset all forces:
+    for (int i = 0; i < numMasses; i++) {
+        massesLoop[i].resetForce();
+    }
+    anchorMass.resetForce();
+
+    // (IV) COMPUTE FORCES (motion is not update yet):
+    //== (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):
+    totalLightForce.set(0,0);
+    for (int i = 0; i < numMasses; i++) {
+        // NOTE: to save memory, we can drop hairVector...
+        lightForce[i]=hairVector[i]*factorLightForce*displaySensingBuffer.lsdTrajectory[i].lightZone;
+        lightForce[i].rotateDeg(angleCorrectionForceLoop); // correction by hand (interactive)
+        // lightForce[i]=lightForce[i]*factorLightForce*displaySensingBuffer.lsdTrajectory[i].lightZone;
+        //compute total light force, not only on lighted zones, because it will mean AWAY from black zones:
+        totalLightForce+=lightForce[i]; // note: bad value choice (negative means TOUCH, and equal to -1), TO CHANGE this in future implementations
+    }
+    recenteringVectorLoop=totalLightForce;//.getRotated(angleCorrectionForceLoop);
+    //== (2) Compute the "recentering vector" from the total light force:
+    // Compute redundant quantities:
+    normRecenteringVector=recenteringVectorLoop.length();
+    angleRecenteringVector=recenteringVectorLoop.angleDegHoriz();
+    recenteringVectorNucleus=totalLightForce.getRotatedDeg(angleCorrectionForceNucleus);
+    //== (3) Compute forces on the loop:
+    //----(a) Nearest neighbour inter-particle springs on the loop (always? we can have still another mode, following the center mass only, etc...)
+    if (springForcesOnLoop) {
+        for (int i = 0; i < numMasses; i++) { // if putting -1, the loop is broken
+            loopSpringArray[i].update();// this add forces to the particles
+        }
+    }
+    //----(b) Direct forces from light pressure (COULD BE MERGED WITH FORCE RECENTERING!!)
+    if (pseudopodesMode) {
+        // special "patches" on blob membrane, to "ATTACH" like a zip to the black drawing:
+        if (lightForcesOnLoop) {
+            int sign=1;
+            for (int i = 0; i < numMasses; i++) {
+                if ((i%2)==0) sign*=-1;
+                //sign=5*cos(6*2*PI*1.0*i/(numMasses-1))-2;
+                if (displaySensingBuffer.lsdTrajectory[i].lightZone>0) // this means touching something black: make SOME points attracted by it (pseudopodes!!) - but not all!
+                    massesLoop[i].addForce(lightForce[i]*(sign<0? -1.24 : 1.4)); // sign<0 means this is a pseudopode attracted by dark zones
+                else // this means something white: do nothing, all forces are towards the exterior
+                    massesLoop[i].addForce(lightForce[i]*2.3); // this force tends to make the blob "inflate", but is not "directional"
+            }
+        }
+        //----(c) Forces from the recentering vector on each particle (WITH PATCHES on the loop?): THIS IS RESPONSIBLE FOR THE "FOLLOWING" BEHAVIOUR
+        if (recenteringForceOnLoop) {
+
+            vector2Df auxForce= (slidingDirection? recenteringVectorLoop.getRotatedDeg(-145) : recenteringVectorLoop.getRotatedDeg(145))*factorRecenteringLoopMass*1;
+            //vector2Df auxForce2= (slidingDirection? totalLightForce.getRotatedDeg(-90) : totalLightForce.getRotatedDeg(90))*factorRecenteringLoopMass*1.5;
+            //vector2Df auxForce3= (slidingDirection? totalLightForce.getRotatedDeg(-90) : totalLightForce.getRotatedDeg(90))*factorRecenteringLoopMass*1.5;
+            vector2Df auxForce2= (slidingDirection? recenteringVectorLoop.getRotatedDeg(-50) : recenteringVectorLoop.getRotatedDeg(50))*factorRecenteringLoopMass*0.5;//*1.8;
+            vector2Df auxForce3= (slidingDirection? recenteringVectorLoop.getRotatedDeg(-30) : recenteringVectorLoop.getRotatedDeg(30))*factorRecenteringLoopMass*0.6;//1.2;
+            
+           
+            int sign=1;
+            for (int i = 0; i < numMasses; i++) {
+                if ((i%2)==0) sign*=-1;
+                if (displaySensingBuffer.lsdTrajectory[i].lightZone>0) {// this means touching something black: behaviour may depend on the pseudopode presence:
+                massesLoop[i].addForce((sign<0? auxForce2 : auxForce3)); // auxForce3: nothing, or sign, or corrected angle
+                } 
+                else massesLoop[i].addForce(auxForce); // this force is responsible for the behaviour (contour following or not)
+            }
+        }
+    } else { // no special zones in the "cell membrane":
+        if (lightForcesOnLoop) {
+            for (int i = 0; i < numMasses; i++) {
+                massesLoop[i].addForce(lightForce[i]);
+            }
+        }
+        //----(c') Forces from the recentering vector on each particle:
+        if (recenteringForceOnLoop) {
+            vector2Df auxForce= (slidingDirection? recenteringVectorLoop.getRotatedDeg(-90) : recenteringVectorLoop.getRotatedDeg(90))*factorRecenteringLoopMass;
+            for (int i = 0; i < numMasses; i++) massesLoop[i].addForce(auxForce);
+        }
+    }
+
+    //----(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)
+    if (nuclearForceOnLoop) {
+        // Springs:
+        for (int i = 0; i < numMasses; i++) centralSpringArray[i].update();//assymetricUpdate();
+        // note: if using centralSpringArray[i].update(), we will add forces to the particles AND to the anchor mass...
+        // Inverse square (attractive):
+        //for (int i = 0; i < numMasses; i++)  massesLoop[i].addInterInvSquareForce(anchorMass, 10, 300, centralSpringK);
+    }
+    //----(d) Inter loop-particles forces (Zach-Liebermann-like blob):
+    if (interParticleForceOnLoop) {
+        for (int i = 0; i < numMasses; i++) {
+            for (int j = 0; j < i-1; j++) massesLoop[i].addInterSpringForce(massesLoop[j], interParticleRange, factorInterParticleForce);
+        }
+    }
+    //----(e) Internal blob pressure force (my faster method to have a blob-like behaviour):
+    if (forceInternalPressureOnLoop) {
+        // 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):
+        // so: f= factor/area - cte, with cte=factor/area0, with area0 being the area at equilibrium.
+        // (And of course, to make it even more exact, we should do pressure*surface, but this will be considered constant)
+        // float area0=30000; // area in pixels when at equilibrium
+        //float factorPressureLoopMass=-0.1*(1.0/area-1.0/area0);
+        //float factorPressureLoopMass=500000.0*(1.0/(area*area)-1.0/(area0*area0));
+        //float factorPressureLoopMass=20000.0*(1.0/sqrt(area)-1.0/sqrt(area0));
+        // 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):
+        //float factorPressureLoopMass=2.5;//4.8;
+        // Now, add the pressure force proportional to the inverse of the area to all particles, or just a signed constant:
+        int auxsign=(area>=0? -1: 1);
+        auxsign=-1;
+        for (int i = 0; i < numMasses; i++) massesLoop[i].addForce( hairVector[i] * factorPressureLoopMass* auxsign);
+    }
+    //----(f) force from border:
+    if (forceBorderOnLoop) {
+        for (int i = 0; i < numMasses; i++) {
+            if (massesLoop[i].bWallCollision) massesLoop[i].addForce(massesLoop[i].innerCollitionDirection*factorForceBorder);
+        }
+    }
+
+    //== (4) Compute forces on the anchor mass:
+    //----(a) Force from data send by OSC? (ex: from mouse?)
+    // anchorMass.addSpringForce(mx, my, 500, -10.2f);
+    // or direct control:
+    // anchorMass.pos.x=mx;anchorMass.pos.y=my;
+    //----(b) Force from the total light force (aka, the "recentering vector"!):
+    if (recenteringForceOnNucleus) {
+        anchorMass.addForce(recenteringVectorNucleus*factorRecenteringAnchorMass);
+    }
+
+    // when nothing is touching it for a while:
+    if (searchActive) {
+        if (!displaySensingBuffer.lightTouched) {
+            if (firstTimeNoTouch) {
+                firstTimeNoTouch=false;
+                computeBoundingBox();
+                randomForce.set(2000-cx,2000-cy);
+                randomForce.normalize();
+                randomForce= randomForce.getRotatedDeg(rand()%50-25);
+            }
+            if (noTouchedCounter>0) {
+                // add random force, modulated:
+                float aux=1.0*noTouchedCounter/1150;
+                vector2Df randf=randomForce.getRotatedDeg(40.0*sin(aux*2*PI*2))*20.0;//*(1.0-aux)*0.3;
+                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!
+                    massesLoop[i].addForce(randf);
+                }
+                // and a special point?
+                //massesLoop[numMasses/2].addForce(randf);
+                // plus amoeba effect ?
+                // for (int i = 0; i < numMasses; i++) {
+                //   massesLoop[i].addForce(hairVector[i]*18*cos( (0.0*noTouchedCounter/1000 + 1.0*i/(numMasses-1)*2*PI*3)));
+                //}
+
+                if ((noTouchedCounter>1150)||(blobWallCollision)) {
+                    noTouchedCounter=0;
+                    // compute force towards the center, slightly rotated to make the blob wander about:
+                    computeBoundingBox();
+                    randomForce.set(2000-cx,2000-cy);
+                    randomForce.normalize();
+                    randomForce= randomForce.getRotatedDeg(rand()%50-25);
+                }
+            }
+        } else {
+            firstTimeNoTouch=true;
+            noTouchedCounter=0;
+        }
+        noTouchedCounter++;
+    }
+
+    // (V) UPDATE DYNAMICS
+    //== (1) particules on the loop:
+    for (int i = 0; i < numMasses; i++) {
+#ifndef VERLET_METHOD
+        massesLoop[i].addDampingForce(); // only in case of EULER method (damping in VERLET mode is done automatically when updating)
+#endif
+        massesLoop[i].update(); // unconstrained
+        massesLoop[i].bounceOffWalls(); // constrain position (and compute wall "hit")
+    }
+    //== (2) For the anchorMass:
+#ifndef VERLET_METHOD
+    anchorMass.addDampingForce();  // // only in case of EULER method (damping in VERLET mode is done automatically when updating)
+#endif
+    anchorMass.update();  // unconstrained
+    anchorMass.bounceOffWalls(); // constrain position (and compute wall "hit")
+
+    // OTHER PARTICULAR THINGS:
+    // (1) current color: change with touch? NO
+   // if (displaySensingBuffer.lightTouched)  
+   //     transientBlobColor=blobColor|0x02; // set green ON on the trajectory, regardless of the initial color
+   //  else 
+        transientBlobColor=blobColor; // just the original blob color
+    
+    // change sliding direction (for countour following):
+    if (blobWallCollision) {
+        if (wallCounter>10) {
+            slidingDirection=!slidingDirection;
+            wallCounter=0;
+        }
+    }
+    wallCounter++;
+}
+
+// Drawing the graphics - this will in fact use the graphic renderer - if any - and produce the trajectory to be displayed by the laser
+void elasticLoop::draw() {
+    // for the time being, there is no "opengl" like renderer, so we just copy the coordinates of the mass into the lsdTrajectory:
+    for (int i = 0; i < numMasses; i++) {
+        displaySensingBuffer.lsdTrajectory[i].x= (unsigned short)( massesLoop[i].pos.x ); // note: it should be an unsigned short
+        displaySensingBuffer.lsdTrajectory[i].y= (unsigned short)( massesLoop[i].pos.y );
+        
+        //displaySensingBuffer.lsdTrajectory[i]=  massesLoop[i].pos.y; // NOTE: doing this means converting from unsigned short to float (vector2Dd to vector2Df)
+        
+        //displaySensingBuffer.lsdTrajectory[i].color=blobColor; // perhaps per point color is not a good idea for the time being...
+    }
+    
+    // Global color for the whole loop:
+    displaySensingBuffer.displayColor=transientBlobColor;
+}
+
+void elasticLoop::processLoopData() {
+
+    // (0) Check if the blob touched the borders:
+    blobWallCollision=false;
+    for (int i = 0; i < numMasses; i++) blobWallCollision= (blobWallCollision || massesLoop[i].bWallCollision);
+
+    // (1) Compute all the "hairvectors" for the loop (this is, the normals to the particles, pointing outwards).
+    //     This will be approximated by taking the 90 deg rotated difference between contiguous particles positions.
+    for (int i = 0; i < numMasses; i++) {
+        vector2Df diff;
+        diff.set(massesLoop[(i+1)%numMasses].pos-massesLoop[i].pos);
+        // normalize and rotate 90 deg:
+        // NOTE: to save memory, we can drop hairVector...
+        hairVector[i]=diff.getPerpendicularNormed(CW);
+        //lightForce[i]=diff.getPerpendicularNormed(CW);
+    }
+
+    // (2) Compute area:
+    // (a) using Green method:
+    area=0;
+    float dx;
+    for (int i = 0; i < numMasses-1; i++){
+        dx=massesLoop[i].pos.x-massesLoop[i+1].pos.x;
+        area+=dx*massesLoop[i].pos.y;
+    }
+    // to avoid computation problems:
+    // if (area<=0) area=1; // or just norm: area CAN be negative! (a loop that is larger than the original blob...)
+
+    // (b) Compute approximate area from enclosing rectangle:
+    computeBoundingBox();
+    
+    // (c) Compute kinetic energy:
+    totalKineticEnergy=0;
+    for (int i = 0; i < numMasses; i++){
+        totalKineticEnergy+=massesLoop[i].getSpeed().squareLength();
+    }
+}
+
+
+void elasticLoop::computeBoundingBox() {
+    float minx=4096, maxx=-1, miny=4096, maxy=-1;
+    for (int i = 0; i < numMasses; i++) {
+        if (i == 0) {
+            minx = massesLoop[i].pos.x;
+            maxx = massesLoop[i].pos.x;
+            miny = massesLoop[i].pos.y;
+            maxy = massesLoop[i].pos.y;
+        } else {
+
+            minx = min(minx, massesLoop[i].pos.x);
+            maxx = max(maxx, massesLoop[i].pos.x);
+            miny = min(miny, massesLoop[i].pos.y);
+            maxy = max(maxy, massesLoop[i].pos.y);
+        }
+    }
+
+    // final results:
+    w = maxx - minx;
+    h = maxy - miny;
+    cx = minx+0.5*w; // note: center will be initialized with posX and posY when calling setInitialPos() of blobConfig
+    cy = miny+0.5*h;
+
+    // approx area:
+    approxArea=w*h;
+}
+
+void elasticLoop::sendDataSpecific() {
+    char auxstring[10];
+    myled2=1; // for tests...
+
+    // First, set the top address of the message to the ID of the blob (not the name):
+  //  sprintf(auxstring, "%d", identifier);
+  //  sendMes.setTopAddress("0");//auxstring);
+
+    // =====================   OSC  ======================
+    if (sendOSC) {
+
+        // (new) Total kinetic energy:
+         if (sendingKineticEnergy) {
+            sprintf(auxstring, "/k %d",identifier);
+            sendMes.setSubAddress(auxstring);
+            long x;    //ATTENTION: parameters to setArgs should be long or unsigned long only (not int!!)
+            x=(long)(totalKineticEnergy);
+            sendMes.setArgs( "i", &x);
+            osc.sendOsc( &sendMes );
+         }
+        // (a) Anchor mass:
+         if (sendingAnchorPosition) {
+           sprintf(auxstring, "/p %d",identifier);
+            sendMes.setSubAddress(auxstring);
+            long x, y;    //ATTENTION: parameters to setArgs should be long or unsigned long only (not int!!)
+            x=(long)(anchorMass.pos.x);
+            y=(long)(anchorMass.pos.y);
+            sendMes.setArgs( "ii", &x, &y);
+            osc.sendOsc( &sendMes );
+        }
+        if (sendingAnchorForce) {
+            sendMes.setSubAddress("/aforce");
+            long    x, y;    //ATTENTION: parameters to setArgs should be long or unsigned long only (not int!!)
+            x=(long)(anchorMass.totalForce.x);
+            y=(long)(anchorMass.totalForce.y);
+            sendMes.setArgs( "ii", &x, &y);
+            osc.sendOsc( &sendMes );
+        }
+        if (sendingAnchorTouchWall) {// note: not an else (we can send different data simultaneously)
+            sendMes.setSubAddress("/awall");
+            long wall=(long)(anchorMass.bWallCollision? 1 : 0);
+            sendMes.setArgs( "i", &wall);
+            osc.sendOsc( &sendMes );
+        }
+        // (b) data from blob points:
+        if (sendingLoopPositions) {
+#ifdef SEND_AS_POINTS
+            long    x, y;    //ATTENTION: parameters to setArgs should be long or unsigned long only (not int!!)
+            for (int i = 0; i < numMasses; i++) {
+                sprintf(auxstring, "/p %d", i); // auxstring read as "/p1", "/p2", ...
+                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...)
+                x=(long)(massesLoop[i].pos.x);
+                y=(long)(massesLoop[i].pos.y);
+                sendMes.setArgs( "ii", &x, &y);
+                osc.sendOsc( &sendMes );
+            }
+#endif
+#ifdef SEND_AS_BLOB
+            sendMes.clearArgs(); // no need, we won't use osc.sendOsc()...
+            uint8_t blobdata[4*numMasses]; // 2 bytes per coordinate, and 2 coordinates
+            for (int i = 0; i < numMasses; i++ ) {
+                // note: massesLoop[i].pos.x is a "float"
+                uint16_t x=(uint16_t)(massesLoop[i].pos.x);
+                blobdata[4*i]=(uint8_t)x>>8; // BIG ENDIAN (send FIRST the MOST SIGNIFICANT BYTE)
+                blobdata[4*i+1]=(uint8_t)x;
+
+                uint16_t y=(uint16_t)(massesLoop[i].pos.y);
+                blobdata[4*i+2]=(uint8_t)y>>8; // BIG ENDIAN (send FIRST the MOST SIGNIFICANT BYTE)
+                blobdata[4*i+3]=(uint8_t)y;
+            }
+            osc.sendOscBlob(&(blobdata[0]), 4*numMasses, &sendMes ); // second parameter is osc blob size in bytes
+#endif
+#ifdef SEND_AS_STRING
+            sendMes.clearArgs(); // no need, we won't use osc.sendOsc()...
+            uint8_t blobdata[4*numMasses]; // 2 bytes per coordinate, and 2 coordinates
+            for (int i = 0; i < numMasses; i++ ) {
+                // note: massesLoop[i].pos.x is a "float"
+                uint16_t x=(uint16_t)(massesLoop[i].pos.x);
+                blobdata[4*i]=(uint8_t)x>>8; // BIG ENDIAN (send FIRST the MOST SIGNIFICANT BYTE)
+                blobdata[4*i+1]=(uint8_t)x;
+
+                uint16_t y=(uint16_t)(massesLoop[i].pos.y);
+                blobdata[4*i+2]=(uint8_t)y>>8; // BIG ENDIAN (send FIRST the MOST SIGNIFICANT BYTE)
+                blobdata[4*i+3]=(uint8_t)y;
+            }
+            osc.sendOscString(blobdata, 4*numMasses, &sendMes ); // second parameter is osc blob size in bytes
+#endif
+        }
+        if (sendingLoopForces) { // ATTN: the force is the TOTAL force on the point (interesting perhaps for making sound...)
+            long    x, y;    //ATTENTION: parameters to setArgs should be long or unsigned long only (not int!!)
+            for (int i = 0; i < numMasses; i++) {
+                sprintf(auxstring, "/f%d", i); // auxstring read as "/f1", "/f2", ...
+                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...)
+                x=(long)(massesLoop[i].totalForce.x);
+                y=(long)(massesLoop[i].totalForce.y);
+                sendMes.setArgs( "ii", &x, &y);
+                osc.sendOsc( &sendMes );
+            }
+        }
+        if (sendingLoopForcesLight) { // ATTN: the force is the TOTAL force on the point (interesting perhaps for making sound...)
+            long    x, y;    //ATTENTION: parameters to setArgs should be long or unsigned long only (not int!!)
+            for (int i = 0; i < numMasses; i++) {
+                sprintf(auxstring, "/g%d", i); // auxstring read as "/f1", "/f2", ...
+                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...)
+                x=(long)(1000*lightForce[i].x);
+                y=(long)(1000*lightForce[i].y);
+                sendMes.setArgs( "ii", &x, &y);
+                osc.sendOsc( &sendMes );
+            }
+        }
+
+        if (sendingLoopRegions) {
+            long    x;   //ATTENTION: parameters to setArgs should be long or unsigned long only (not int!!)
+            for (int i = 0; i < numMasses; i++) {
+                sprintf(auxstring, "/r%d", i); // auxstring read as "/f1", "/f2", ...
+                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...)
+                x=(long)(displaySensingBuffer.lsdTrajectory[i].lightZone>0? 1 : 0);
+                sendMes.setArgs( "i", &x);
+                osc.sendOsc( &sendMes );
+            }
+        }
+        if (sendingLoopTouchWall) { // global touch wall for the loop (not per point)
+            long    wall;   //ATTENTION: parameters to setArgs should be long or unsigned long only (not int!!)
+            sprintf(auxstring, "/bWall");
+            sendMes.setSubAddress(auxstring);
+            wall=(long)(blobWallCollision? 1 : 0);
+            sendMes.setArgs( "i", &wall);
+            osc.sendOsc( &sendMes );
+        }
+        // (c) Blob geometry:
+        if (sendingBlobArea) {
+         /*  sendMes.setSubAddress("/a");
+            long    x;    //ATTENTION: parameters to setArgs should be long or unsigned long only (not int!!)
+           // x=(long)(area);//approxArea); // area or approxArea
+            x=(long)(area>0? approxArea : -approxArea);
+            sendMes.setArgs( "i", &x); // ATTENTION: AREA CAN BE NEGATIVE!!! (does MAX handles this well? test this!)
+         */   
+            // HACK for the time being (for Daito):
+            sendMes.setSubAddress("/a");
+            long    x, y;    //ATTENTION: parameters to setArgs should be long or unsigned long only (not int!!)
+           // x=(long)(area);//approxArea); // area or approxArea
+            x=(long)(w); y=(long)(h);
+            sendMes.setArgs( "ii", &x, &y); // ATTENTION: AREA CAN BE NEGATIVE!!! (does MAX handles this well? test this!)
+            
+            osc.sendOsc( &sendMes );
+        }
+        if (sendingBlobNormals) {
+            long    x, y;   //ATTENTION: parameters to setArgs should be long or unsigned long only (not int!!)
+            for (int i = 0; i < numMasses; i++) {
+                sprintf(auxstring, "nf%d", i); // auxstring read as "/f1", "/f2", ...
+                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...)
+                x=(long)(hairVector[i].x);
+                y=(long)(hairVector[i].y);
+                sendMes.setArgs( "ii", &x, &y);
+                osc.sendOsc( &sendMes );
+            }
+        }
+        if (sendingBlobAngles) {
+            long   x;   //ATTENTION: parameters to setArgs should be long or unsigned long only (not int!!)
+            for (int i = 0; i < numMasses; i++) {
+                sprintf(auxstring, "/a%d", i); // auxstring read as "/f1", "/f2", ...
+                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...)
+                x=(long)(hairVector[i].angleDegHoriz());
+                sendMes.setArgs( "i", &x);
+                osc.sendOsc( &sendMes );
+            }
+        }
+        // (d) Light sensing statistics:
+        if (sendingBlobMaxMin) {
+            sendMes.setSubAddress("/maxmin");
+            long    x, y;    //ATTENTION: parameters to setArgs should be long or unsigned long only (not int!!)
+            x=(long)(displaySensingBuffer.maxI);
+            y=(long)(displaySensingBuffer.minI);
+            sendMes.setArgs( "ii", &x, &y);
+            osc.sendOsc( &sendMes );
+        }
+        if (sendingLightForce) {
+            sendMes.setSubAddress("/lforce");
+            long    x, y;    //ATTENTION: parameters to setArgs should be long or unsigned long only (not int!!)
+            x=(long)(totalLightForce.x);
+            y=(long)(totalLightForce.y);
+            sendMes.setArgs( "ii", &x, &y);
+            osc.sendOsc( &sendMes );
+        }
+        // (e) Recentering vector: (note: redundant with sendingLightForce, IF the correction angle is known).
+        if (sendingRecenteringVector) {
+            sendMes.setSubAddress("/rvector");
+            long    x, y;    //ATTENTION: parameters to setArgs should be long or unsigned long only (not int!!)
+            x=(long)(recenteringVectorLoop.x);
+            y=(long)(recenteringVectorLoop.y);
+            sendMes.setArgs( "ii", &x, &y);
+            osc.sendOsc( &sendMes );
+        }
+        if (sendingRecenteringAngle) {
+            sendMes.setSubAddress("/rangle");
+            long    x;    //ATTENTION: parameters to setArgs should be long or unsigned long only (not int!!)
+            x=(long)(angleRecenteringVector);
+            sendMes.setArgs( "i", &x);
+            osc.sendOsc( &sendMes );
+        }
+        if (sendingRecenteringNorm) {
+            sendMes.setSubAddress("/rnorm");
+            long    x;    //ATTENTION: parameters to setArgs should be long or unsigned long only (not int!!)
+            x=(long)(normRecenteringVector);
+            sendMes.setArgs( "i", &x);
+            osc.sendOsc( &sendMes );
+        }
+
+        if (sendingTouched) {
+            if (displaySensingBuffer.lightTouched) {
+                sendMes.clearArgs(); // there are no arguments to send
+                sendMes.setSubAddress("/touched");
+                osc.sendOsc( &sendMes );
+            }
+        }
+
+    } // end of OSC sending per-spot
+
+    // =====================   SERIAL  ======================
+    if (sendSerial) {
+        //.. to do
+    }
+
+    myled2=0; // for tests...
+}
+