just a test

Dependencies:   mbed

Fork of scoreLight_Advanced by Alvaro Cassinelli

Revision:
30:d8af03f01cd4
Parent:
27:1ce994629ffc
Child:
31:5f039cbddee8
--- a/elasticLoop.cpp	Wed Jun 20 03:25:49 2012 +0000
+++ b/elasticLoop.cpp	Fri Sep 21 10:02:35 2012 +0000
@@ -1,1000 +1,1001 @@
-/*
- *  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::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:
-    slidingDirection=true; //  (will change when touching wall)
-    // Sending data:
-    periodSendingData=15; // in ms
-    sendingLoopPositions=false;
-    sendingBlobArea=true;
-    sendingKineticEnergy=true;
-    sendingOnlyWhenTouch=false; // send ALWAYS, regardless of the fact the blob is being touched or not. 
-
-// (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);
-
-            // 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);
-
-            // 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:  
-                      
-            sprintf(spotName,"contract_central");
-
-            //setColor(0x07);//0x04+0x02>>i);
-            setColor(0x04);
-
-            // 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=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=6.3;//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(4);
-
-            break;
-            
-        case CONTRACT_CENTRAL_FAST:
-        
-                      //setColor(0x07);//0x04+0x02>>i);
-                      setColor(0x04);
-
-                      // 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(70);
-            break;
-
-        case CONTOUR_FOLLOWING:
-            sprintf(spotName,"following"); //this is a contour-following loop
-
-            //setColor(0x07);//0x04+0x02>>i);
-            setColor(0x04);
-
-            // 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;//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=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=240;//239;// in deg
-            recenteringForceOnLoop=true;
-            angleCorrectionForceNucleus=180;// in deg
-            recenteringForceOnNucleus=false;//true;
-
-            factorLightForce=2.23;//3.0;//8.0;
-            factorRecenteringAnchorMass=1.0;//20.0/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(4);
-
-            break;
-        case CONTOUR_FOLLOWING_FAST:
-            sprintf(spotName,"following_fast");
-
-            setColor(0x07);//0x04+0x02>>i);
-
-            // 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);
-
-            // 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(0.23);//18); // 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);
-}
-
-void elasticLoop::update() {
-
-    // (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]=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
-    }
-    //== (2) Compute the "recentering vector" from the total light force, by rotating by the angleCorrection (this will give different behaviours):
-    recenteringVectorLoop= totalLightForce.getRotatedDeg(slidingDirection? angleCorrectionForceLoop : 140); // the hard coded value is a hack for the time being...
-    // 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:
-        if (lightForcesOnLoop) {
-            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: 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]*1.6); // 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?):
-        if (recenteringForceOnLoop) {
-
-            vector2Df auxForce= recenteringVectorLoop*factorRecenteringLoopMass*1.0;
-            vector2Df auxForce2= totalLightForce.getRotatedDeg(80)*factorRecenteringLoopMass*(slidingDirection? 0 : 1)*1.8;
-            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 : auxForce2)); // 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= recenteringVectorLoop*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, 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...
-}
-
+/*
+ *  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::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:
+    slidingDirection=true; //  (will change when touching wall)
+    // Sending data:
+    periodSendingData=15; // in ms
+    sendingLoopPositions=false;
+    sendingBlobArea=true;
+    sendingKineticEnergy=true;
+    sendingOnlyWhenTouch=false; // send ALWAYS, regardless of the fact the blob is being touched or not. 
+
+// (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);
+
+            // 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);
+
+            // 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:  
+                      
+            sprintf(spotName,"contract_central");
+
+            //setColor(0x07);//0x04+0x02>>i);
+            setColor(0x04);
+
+            // 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=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=6.3;//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(4);
+
+            break;
+            
+        case CONTRACT_CENTRAL_FAST:
+        
+                      //setColor(0x07);//0x04+0x02>>i);
+                      setColor(0x04);
+
+                      // 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(70);
+            break;
+
+        case CONTOUR_FOLLOWING:
+            sprintf(spotName,"following"); //this is a contour-following loop
+
+            //setColor(0x07);//0x04+0x02>>i);
+            setColor(0x04);
+
+            // 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;//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=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=240;//239;// in deg
+            recenteringForceOnLoop=true;
+            angleCorrectionForceNucleus=180;// in deg
+            recenteringForceOnNucleus=false;//true;
+
+            factorLightForce=2.23;//3.0;//8.0;
+            factorRecenteringAnchorMass=1.0;//20.0/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(4);
+
+            break;
+        case CONTOUR_FOLLOWING_FAST:
+            sprintf(spotName,"following_fast");
+
+            setColor(0x07);//0x04+0x02>>i);
+
+            // 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);
+
+            // 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(0.23);//18); // 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() {
+
+    // (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]=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
+    }
+    //== (2) Compute the "recentering vector" from the total light force, by rotating by the angleCorrection (this will give different behaviours):
+    recenteringVectorLoop= totalLightForce.getRotatedDeg(slidingDirection? angleCorrectionForceLoop : 140); // the hard coded value is a hack for the time being...
+    // 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:
+        if (lightForcesOnLoop) {
+            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: 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]*1.6); // 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?):
+        if (recenteringForceOnLoop) {
+
+            vector2Df auxForce= recenteringVectorLoop*factorRecenteringLoopMass*1.0;
+            vector2Df auxForce2= totalLightForce.getRotatedDeg(80)*factorRecenteringLoopMass*(slidingDirection? 0 : 1)*1.8;
+            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 : auxForce2)); // 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= recenteringVectorLoop*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, 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...
+}
+