just a test

Dependencies:   mbed

Fork of scoreLight_Advanced by Alvaro Cassinelli

classPointMass.cpp

Committer:
mbedalvaro
Date:
2012-03-28
Revision:
0:345b3bc7a0ea
Child:
1:a4050fee11f7

File content as of revision 0:345b3bc7a0ea:

/*
 *  pointMass.cpp
 *  laserBlob
 *
 *  Created by CASSINELLI ALVARO on 5/19/11.
 *  Copyright 2011 TOKYO UNIVERSITY. All rights reserved.
 *
 */

#include "classPointMass.h"

//------------------------------------------------------------
pointMass::pointMass(){
    setIntegrationStep(.01); // default in case we don't call integration step setting
    // NOTE: it is important to set dt before inital conditions in case of VERLET integration, because we need the integration
    // step for properly setting the initial speed.
    setInitialCondition(0,0,0,0);// default in case we don't call to initial conditions.
    setWallLimits(100,100,4000,4000);
    mass=1.0; 
    dampMotion = 0.0175;//0.025 was good for bigger blobs;//2f;//0.07f;
    dampBorder = 0.013f; //0.07f
    bFixed = false;
    bWallCollision=false;
}

//------------------------------------------------------------
void pointMass::resetForce(){
    totalForce.set(0,0);
}

//------------------------------------------------------------
void pointMass::addForce(float x, float y){
    totalForce.x = totalForce.x + x;
    totalForce.y = totalForce.y + y;
}

//------------------------------------------------------------
void pointMass::addForce(vector2D forceToAdd){
    totalForce+=forceToAdd;
}

//------------------------------------------------------------
void pointMass::addInvSquareForce(float x, float y, float radiusMin, float radiusMax, float scale){
    
    vector2D posOfForce;
    posOfForce.set(x,y);
        
    vector2D diff    = pos - posOfForce; // note: we use the position AT TIME T, so this force is at time t
    float length    = diff.length();
    
    // check close enough and far enough (to avoid singularities for example):
    if ((length>radiusMin)&&(length<radiusMax)) {
        diff.normalize();
        totalForce += diff * scale * 1.0/(length*length+1);
    }
}

void pointMass::addInterInvSquareForce(pointMass &theOtherParticle, float radiusMin, float radiusMax, float scale){
    
    vector2D posOfForce;
    posOfForce.set(theOtherParticle.pos);
    
    vector2D diff    = pos - posOfForce; // note: we use the position AT TIME T, so this force is at time t
    float length    = diff.length();
    
    // check close enough and far enough (to avoid singularities for example):
    if ((length>radiusMin)&&(length<radiusMax)) {
        diff.normalize();
        totalForce += diff * scale * 1.0/(length*length+1);
        theOtherParticle.totalForce -= diff * scale * 1.0/(length*length+1);
    }
}


//------------------------------------------------------------
void pointMass::addSpringForce(float centerx, float centery, float radius, float scale){
    
    // ----------- (1) make a vector of where this particle p is: 
    vector2D posOfForce;
    posOfForce.set(centerx, centery);
    
    // ----------- (2) calculate the difference & length 
    
    vector2D diff    = pos - posOfForce;
    float length    = diff.length();
    
    // ----------- (3) check close enough
    
    bool bAmCloseEnough = true;
    if (radius > 0){
        if (length > radius){
            bAmCloseEnough = false;
        }
    }
    
    // ----------- (4) if so, update force
    
    if (bAmCloseEnough == true){
        float pct = 1 - (length / radius);  // stronger on the inside
        diff.normalize();
        totalForce += diff * scale * pct;
    }
}

void pointMass::addInterSpringForce(pointMass &theOtherParticle, float radius, float scale){
    
    // ----------- (1) make a vector of where this particle p is: 
    vector2D posOfForce;
    posOfForce.set(theOtherParticle.pos);
    
    // ----------- (2) calculate the difference & length 
    
    vector2D diff    = pos - posOfForce;
    float length    = diff.length();
    
    // ----------- (3) check close enough
    
    bool bAmCloseEnough = true;
    if (radius > 0){
        if (length > radius){
            bAmCloseEnough = false;
        }
    }
    
    // ----------- (4) if so, update REPULSIVE force
    
    if (bAmCloseEnough == true){
        float pct = 1 - (length / radius);  
        diff.normalize();
        totalForce += diff * scale * pct;
        theOtherParticle.totalForce -= diff * scale * pct;
        //theOtherParticle.frc.x = p.frc.x - diff.x * scale * pct;
        //theOtherParticle.frc.y = p.frc.y - diff.y * scale * pct;
    }
}



//------------------------------------------------------------
void pointMass::addDampingForce(){ // NOTE: use only in case of EULER intgration!
    totalForce-= speed* dampMotion;
}

//------------------------------------------------------------
void pointMass::setIntegrationStep(float _dt){
    dt=_dt;
}

//------------------------------------------------------------
void pointMass::setInitialCondition(float px, float py, float vx, float vy){
#ifndef VERLET_METHOD
    pos.set(px,py);
    speed.set(vx,vy);
#else
    // In case of Verlet method, setting the speed is a little more complicated. It involves in particular the integration step
    // through the approximation formula: 
    // speed = (posNew-posOld)/(2*dt), or speed=(pos-posOld)/dt. Hence:
    posOld.set(px, py); 
    setSpeed(vx, vy); // this assumes posOld known
#endif    
}

//-------------------------------------------------------
vector2D pointMass::getSpeed() {
    // this will give an estimate of the speed (not computed explicitly using the Verlet integration):
    //speed=(posNew-posOld)/(2*dt); // the variable speed is also updated (note: it is private)
    speed=(pos-posOld)/dt; // less approximate than the above, but we avoid having a global posNew variable 
    return(speed); 
}

void pointMass::setSpeed(const vector2D& vel) {
    speed.set(vel); // enough for EULER METHOD
    pos=speed*dt+posOld; // NECESSARY for VERLET METHOD (we assume posOld known). 
    // no need to compute newPos
}

void pointMass::setSpeed(float vx, float vy) {
    speed.set(vx, vy); // enough for EULER METHOD
    pos=speed*dt+posOld; // NECESSARY for VERLET METHOD (we assume posOld known). 
    // no need to compute newPos
}

void pointMass::setPos(float px, float py) { // assuming the speed is unchanged (must do some tweaking in case of Verlet integration)
    pos.set(px, py);
    posOld=pos-speed*dt;
}

//------------------------------------------------------------
void pointMass::update(){    
    if (bFixed == false){
        acc=totalForce/mass; // this is the acceleration at time t
    
#ifndef VERLET_METHOD
        
        // The following equations (Euler integration) assume acceleration constant during time dt:
        speed = speed + acc*dt;
        pos = pos + speed*dt ;//+acc*dt*dt*0.5;
#else
        // The following equations are for VERLET integration with pseudo-damping:
        vector2D posNew=pos*(2-dampMotion)-posOld*(1-dampMotion)+acc*dt*dt;
        // Without damping this is just: posNew=2*posOld-1*pos+acc*dt*dt; // i.e., dampMotion=0;
        
        posOld=pos;
        pos=posNew;
        
        // NOTE: we can also estimate the speed if we want. But this may be unnecessary (call getSpeed() for that). 
        
#endif

    }
}

void pointMass::setWallLimits(float Minx, float Miny, float Maxx, float Maxy) {
    maxWall.set(Maxx, Maxy);
    minWall.set(Minx, Miny);
}

//------------------------------------------------------------
void pointMass::bounceOffWalls(){
    // NOTE: bounce is easy in case of EULER method; in case of VERLET, we need to do some hack on the positions.
    //Note: the walls are in (vector2D) horizontalLimits and verticalLimits 
 
    bWallCollision=false;
    innerCollitionDirection.set(0,0);
#ifndef VERLET_METHOD // EULER METHOD!!
    
    if (pos.x > maxWall.x){
        pos.x = maxWall.x; 
        speed.x *= -1;
        bWallCollision = true;
        innerCollitionDirection.x=-1; 
    } else if (pos.x < minWall.x){
        pos.x = minWall.x; 
        speed.x *= -1;
        bWallCollision = true;
        innerCollitionDirection.x=1; 
    }
    
    if (pos.y > maxWall.y){
        pos.y = maxWall.y; 
        speed.y *= -1;
        bWallCollision = true;
        innerCollitionDirection.y=-1; 
    } else if (pos.y < minWall.y){
        pos.y = minWall.y; 
        speed.y *= -1;
        bWallCollision = true;
        innerCollitionDirection.y=1;
    }
    
    if (bWallCollision) {
        // damping:
        speed *=(1-dampBorder);
        // normalization of collision direction:
       innerCollitionDirection.normalize();
    }
    
#else // THIS IS FOR VERLET METHOD:
    // we need to estimate the inverted, damped vector for bumping::
    vector2D bumpVector=getSpeed()*dt*(dampBorder-1); // assuming dampBorder<1 of course
    if (pos.x > maxWall.x){
        //posOld.x=pos.x;
        //pos.x=pos.x+bumpVector.x;
        posOld.x=maxWall.x;
        pos.x=maxWall.x+bumpVector.x;
        bWallCollision = true; // this is just computed here to detect bumps
        innerCollitionDirection.x=-1; 
    } else if (pos.x < minWall.x){
        posOld.x=minWall.x;
        pos.x=minWall.x+bumpVector.x;
         innerCollitionDirection.x=1; 
        bWallCollision = true;
    }
    
    if (pos.y > maxWall.y){
        posOld.y=maxWall.y;
        pos.y=maxWall.y+bumpVector.y;    
         innerCollitionDirection.y=-1;     
        bWallCollision = true;
    } else if (pos.y < minWall.y){
        posOld.y=minWall.y;
        pos.y=minWall.y+bumpVector.y;
         innerCollitionDirection.y=1; 
        bWallCollision = true;
    }
#endif
    
}