rt300@0: /* rt300@0: * lump.cpp rt300@0: * simplespring rt300@0: * rt300@0: * Created by Robert Tubb on 01/06/2011. rt300@0: * Copyright 2011 __MyCompanyName__. All rights reserved. rt300@0: * rt300@0: */ rt300@0: #include "lump.h" rt300@0: #include "testApp.h" rt300@0: #include rt300@0: #include "globalForces.h" rt300@0: #include "globalUI.h" rt300@0: extern GlobalForces globalForces; rt300@0: extern GlobalUI globalUI; rt300@0: //int Lump::numLumps = 0; rt300@0: //-------------------------------------------------------------- rt300@0: // default constr rt300@4: Lump::Lump(){ rt300@0: //cout << "constructing a default lump" << endl; rt300@8: // myIndexInMesh = index; HOW TO GET THIS?? rt300@0: mass = 10.0; rt300@0: inverseMass = 1.0/mass; // not needed - used csquared for force rt300@0: friction = 0.996; rt300@0: position.x = 0.5; rt300@0: position.y = 0.5; rt300@0: velocity.x = 0.0; rt300@0: velocity.y = 0.0; rt300@0: accel.x = 0.0; rt300@0: accel.y = 0.0; rt300@0: numAttachedSprings = 0; rt300@0: grabbed = false; rt300@0: highlighted = false; rt300@0: constrained = false; rt300@0: totalForceMag = 0.0; rt300@8: //size = 3; //sqrt(mass/3.0); rt300@0: isInScanPath = false; rt300@4: isScanPathStart = false; rt300@4: isScanPathEnd = false; rt300@4: rt300@0: previousPosition.setCoord(0.5,0.5); rt300@0: zeroRefPos.setCoord(0.0,0.0); rt300@0: constrainMode = NOT_CONSTRAINED; rt300@5: radialDisplacement = 0.0; rt300@0: grabID = -1; rt300@0: rt300@0: } rt300@0: //-------------------------------------------------------------- rt300@0: // arg constructor rt300@4: Lump::Lump(double aMass,double aFriction, double positionX, double positionY){ rt300@0: // set members rt300@0: rt300@0: } rt300@0: rt300@0: //-------------------------------------------------------------- rt300@0: Lump::~Lump(){ rt300@4: rt300@0: } rt300@0: //-------------------------------------------------------------- rt300@0: void Lump::attachSpring(Spring* aSpring){ rt300@0: rt300@4: rt300@4: attachedSprings.push_back(aSpring); rt300@4: numAttachedSprings++; rt300@4: rt300@0: } rt300@0: //-------------------------------------------------------------- rt300@0: Spring * Lump::checkConnectedTo(Lump * otherLump){ rt300@0: // loop thru all attached springs looking at other end rt300@4: for(int i = 0; igetLumpOnOtherEnd(this) == otherLump){ rt300@0: return attachedSprings[i]; rt300@0: } rt300@0: } rt300@0: return NULL; rt300@0: } rt300@0: //-------------------------------------------------------------- rt300@0: void Lump::constrain(){ rt300@0: // TODO1 different constrain modes rt300@0: constrained = true; rt300@0: constrainMode = CONSTRAIN_XY; rt300@0: setZeroRefPos(); rt300@0: //cout << "constraining lump "<< endl; rt300@0: rt300@0: } rt300@6: rt300@0: //-------------------------------------------------------------- rt300@0: void Lump::constrain(ConstrainMode aconstrainMode){ rt300@6: if(aconstrainMode == CONSTRAIN_XY){ rt300@6: constrained = true; rt300@6: } rt300@0: constrainMode = aconstrainMode; rt300@0: setZeroRefPos(); rt300@0: //cout << "constraining lump "<< endl; rt300@0: rt300@0: } rt300@0: void Lump::setInvMass(double aInvMass){ rt300@0: // use csquared rt300@0: inverseMass = aInvMass; rt300@0: } rt300@0: //-------------------------------------------------------------- rt300@0: rt300@0: void Lump::draw(){ rt300@0: /* rt300@0: rt300@0: rt300@0: */ rt300@0: rt300@0: if(grabbed){ rt300@0: rt300@0: int xpos = position.x * ofGetHeight() + globalUI.borderSize; rt300@0: int ypos = position.y * ofGetHeight(); rt300@0: // draw a circle round it rt300@0: ofSetColor(255, 0, 0); rt300@0: ofNoFill(); rt300@0: ofCircle(xpos, ypos, 35.0); rt300@0: ofFill(); rt300@0: }else if(isInScanPath){ rt300@12: /* rt300@0: ofSetColor(0, 200, 20); rt300@0: int xpos = position.x * ofGetHeight() + globalUI.borderSize; rt300@0: int ypos = position.y * ofGetHeight(); rt300@0: ofEllipse(xpos,ypos, 6, 6); rt300@4: if(isScanPathEnd){ rt300@4: ofSetColor(255, 255, 0); rt300@4: ofNoFill(); rt300@4: ofCircle(xpos, ypos, 6.0); rt300@4: ofFill(); rt300@4: } rt300@4: if(isScanPathStart){ rt300@4: ofSetColor(0, 255, 255); rt300@4: ofNoFill(); rt300@4: ofCircle(xpos, ypos, 7.0); rt300@4: ofFill(); rt300@4: } rt300@0: // code to display restpos and displacement rt300@12: rt300@0: ofSetColor(0, 0, 0); rt300@0: int rxpos = zeroRefPos.x * ofGetHeight() + 128; rt300@0: int rypos = zeroRefPos.y * ofGetHeight(); rt300@0: ofEllipse(rxpos,rypos, 6, 6); rt300@0: rt300@0: ofSetColor(100, 100, 100); rt300@0: rt300@0: ofLine(rxpos,rypos,xpos,ypos); rt300@0: */ rt300@0: rt300@0: }else if(highlighted){ rt300@0: ofSetColor(200, 0, 0); rt300@0: int xpos = position.x * ofGetHeight() + globalUI.borderSize; rt300@0: int ypos = position.y * ofGetHeight(); rt300@0: ofEllipse(xpos,ypos, 2, 2); rt300@0: }else if (constrained){ rt300@4: ofSetColor(200,5,5); rt300@4: int xpos = position.x * ofGetHeight() + globalUI.borderSize; rt300@4: int ypos = position.y * ofGetHeight(); rt300@4: ofEllipse(xpos,ypos, 2, 2); rt300@0: }else{ rt300@0: // dont draw 'normal ' lumps rt300@0: return; rt300@0: //ofSetColor(23, 23, 200); rt300@0: } rt300@0: } rt300@0: rt300@0: //-------------------------------------------------------------- rt300@0: rt300@0: TwoVector Lump::applyForce(){ rt300@0: rt300@0: rt300@0: if(grabbed || constrainMode == CONSTRAIN_XY){ rt300@0: rt300@0: // don't bother rt300@0: return position; rt300@0: } rt300@0: // called LOTS so optimise rt300@0: // use spring force to calc accel - vel - pos rt300@0: rt300@0: TwoVector springForce(0.0,0.0); rt300@0: TwoVector totalForce(0.0,0.0); rt300@0: rt300@0: // sum up force from each attached spring rt300@4: for(int i = 0;igetForce(this); rt300@0: rt300@0: //cout << "spring number " << i << " force x " << springForce.x << endl; rt300@0: totalForce.x += springForce.x; rt300@0: totalForce.y += springForce.y; rt300@0: } rt300@0: rt300@0: // get the global forces, gravity and so on rt300@0: totalForce.x += globalForces.getAllForceAt(position.x,position.y).x; rt300@0: totalForce.y += globalForces.getAllForceAt(position.x,position.y).y; rt300@0: rt300@0: if (constrainMode != CONSTRAIN_X){ rt300@0: accel.x = totalForce.x*inverseMass; rt300@0: }else{ rt300@0: accel.x = 0.0; rt300@0: } rt300@0: if(constrainMode != CONSTRAIN_Y){ rt300@0: accel.y = totalForce.y*inverseMass; rt300@0: }else{ rt300@0: accel.y = 0.0; rt300@0: } rt300@0: rt300@0: // DIFFERENCE EQUATIONS HERE. This is the bit that controls the movement! rt300@0: rt300@0: // Heun rt300@0: rt300@0: double pvx = velocity.x*friction + accel.x*2/3; rt300@0: double pvy = velocity.y*friction + accel.y*2/3; rt300@0: rt300@0: rt300@0: velocity.x = 0.75*pvx + 0.25*velocity.x; rt300@0: velocity.y = 0.75*pvy + 0.25*velocity.y; rt300@0: rt300@0: double px = position.x + velocity.x*2/3; rt300@0: double py = position.y + velocity.y*2/3; rt300@0: rt300@0: rt300@0: position.x = 0.75*px + 0.25*position.x; rt300@0: position.y = 0.75*py + 0.25*position.y; rt300@0: rt300@0: rt300@0: // Newton's 2nd law rt300@0: /* rt300@0: velocity.x += accel.x; rt300@0: velocity.x *= friction; rt300@0: position.x += velocity.x; rt300@0: rt300@0: velocity.y += accel.y; rt300@0: velocity.y *= friction; rt300@0: position.y += velocity.y; rt300@0: */ rt300@0: rt300@0: rt300@0: // WALLS rt300@0: if (position.x < 0.0){ rt300@0: position.x = -position.x; rt300@0: velocity.x = -velocity.x * globalForces.wallBounce; rt300@0: rt300@0: } else if (position.x > 1.0){ rt300@0: position.x = 2.0 - position.x; rt300@0: velocity.x = -velocity.x * globalForces.wallBounce; rt300@0: rt300@0: } rt300@0: if (position.y < 0.0){ rt300@0: position.y = -position.y; rt300@0: velocity.y = -velocity.y * globalForces.wallBounce; rt300@0: rt300@0: } else if (position.y > 1.0){ rt300@0: position.y = 2.0 - position.y; rt300@0: velocity.y = -velocity.y * globalForces.wallBounce; rt300@0: rt300@5: } rt300@5: radialDisplacement = position.distanceTo(zeroRefPos); rt300@0: return position; rt300@0: rt300@0: } rt300@0: //--------------------------------------------- rt300@0: void Lump::homingFilter(double amt){ rt300@0: // includes a little bit of the zero pos in the position, so sound will exponentially decay rt300@0: rt300@0: if (constrained || grabbed) return; rt300@0: rt300@0: position.x = (1 - amt)*position.x + amt*zeroRefPos.x; rt300@0: position.y = (1 - amt)*position.y + amt*zeroRefPos.y; rt300@0: rt300@0: } rt300@0: //--------------------------------------------- rt300@0: void Lump::averagingFilter(double amt){ rt300@0: // NOT USED AVERAGING FILTER NOW IN MESH rt300@0: // amt is between 0 and 1 rt300@0: if (constrained || grabbed) return; rt300@0: double avx = 0.0, avy = 0.0; rt300@0: // average the position of all the attached lumps rt300@4: for(int i = 0;igetLumpOnOtherEnd(this); rt300@0: avx += otherLump->position.x; rt300@0: avy += otherLump->position.y; rt300@0: } rt300@4: avx /= attachedSprings.size(); rt300@4: avy /= attachedSprings.size(); rt300@0: rt300@0: // mix in the average with the 'real' rt300@0: position.x = (1 - amt)*position.x + amt*avx; rt300@0: position.y = (1 - amt)*position.y + amt*avy; rt300@0: rt300@0: } rt300@0: //--------------------------------------------- rt300@0: TwoVector Lump::averageOfConnected(){ rt300@0: TwoVector av; rt300@0: if (constrained || grabbed) return position; // don't want constrained ones moving rt300@0: //TODO what if edges unconstrained? this is why filtered unconstrained just ends up as a line... rt300@0: rt300@0: // average the position of all the attached lumps rt300@4: for(int i = 0;igetLumpOnOtherEnd(this); rt300@0: av.x += otherLump->position.x; rt300@0: av.y += otherLump->position.y; rt300@0: } rt300@4: av.x /= attachedSprings.size(); rt300@4: av.y /= attachedSprings.size(); rt300@0: rt300@0: return av; rt300@0: rt300@0: } rt300@0: //-------------------------------------------------------------- rt300@0: void Lump::setPosition(double ax, double ay){ rt300@0: // set INITIAL position rt300@0: // Called from mesh set up. not used for updates rt300@0: rt300@0: position.x = ax; rt300@0: position.y = ay; rt300@0: zeroRefPos.x = ax; rt300@0: zeroRefPos.y = ay; rt300@0: } rt300@0: //-------------------------------------------------------------- rt300@0: void Lump::setVelocity(double ax, double ay){ rt300@0: rt300@0: velocity.x = ax; rt300@0: velocity.y = ay; rt300@0: rt300@0: } rt300@0: //-------------------------------------------------------------- rt300@0: rt300@0: void Lump::setFriction(double aF){ rt300@0: friction = aF; rt300@0: } rt300@0: //-------------------------------------------------------------- rt300@0: rt300@0: void Lump::setZeroRefPos(){ rt300@0: // sets the reference point from which displacement is measured for scan amplitudes rt300@0: zeroRefPos = position; rt300@0: } rt300@0: //-------------------------------------------------------------- rt300@0: double Lump::getTotalForceMag(){ rt300@0: return totalForceMag; rt300@0: } rt300@0: //-------------------------------------------------------------- rt300@0: double Lump::scanDisplacement(){ rt300@0: // returns the absolute distance from 'home' rt300@0: return position.distanceTo(zeroRefPos); rt300@0: } rt300@0: //-------------------------------------------------------------- rt300@0: double Lump::scanLumpSpeed(){ rt300@0: // returns the absolute magnitude of the lumps velocity rt300@0: return velocity.norm(); rt300@0: } rt300@0: //-------------------------------------------------------------- rt300@0: double Lump::scanYPos(){ rt300@0: // returns the y displ rt300@0: return position.y - zeroRefPos.y; rt300@0: } rt300@0: //-------------------------------------------------------------- rt300@0: double Lump::scanXPos(){ rt300@0: // returns the x displ rt300@0: return position.x - zeroRefPos.x; rt300@0: } rt300@0: // ------------------- rt300@0: double Lump::scanRadialDisplacement(){ rt300@0: // returns the distance from circle zero line rt300@0: // need to know where the centre point of the circle is and default radius rt300@0: rt300@0: //return position.y - 0.5; rt300@5: return radialDisplacement; rt300@0: rt300@0: } rt300@0: //-------------------------------------------------------------- rt300@0: void Lump::addToScanPath(){ rt300@0: isInScanPath = true; rt300@0: setZeroRefPos(); rt300@0: } rt300@0: //-------------------------------------------------------------- rt300@0: void Lump::removeFromScanPath(){ rt300@0: isInScanPath = false; rt300@0: rt300@0: } rt300@0: //-------------------------------------------------------------- rt300@0: void Lump::grab(int aGrabID){ rt300@0: // hover hilight doesn't work on touchscreens if(highlighted) grabbed = true; rt300@0: grabbed = true; rt300@0: grabID = aGrabID; rt300@0: velocity.x = 0.0; rt300@0: velocity.y = 0.0; rt300@0: } rt300@0: //-------------------------------------------------------------- rt300@0: void Lump::drag(double ax, double ay, int aGrabID){ rt300@0: if(aGrabID == grabID){ rt300@0: //cout << "dragging lump ID: " << grabID << endl; rt300@0: position.x = ax; rt300@0: position.y = ay; rt300@0: velocity.x = previousPosition.x - position.x; rt300@0: velocity.y = previousPosition.y - position.y; rt300@0: previousPosition = position; // sets velocity too rt300@0: } rt300@0: } rt300@0: //-------------------------------------------------------------- rt300@0: void Lump::unGrab(){ rt300@0: cout << "ungrabbed something\n"; rt300@0: grabbed = false; rt300@0: grabID = -1; rt300@0: velocity.x = 0.0; rt300@0: velocity.y = 0.0; rt300@0: } rt300@0: //-------------------------------------------------------------- rt300@0: void Lump::unconstrain(){ rt300@0: constrained = false; rt300@0: constrainMode = NOT_CONSTRAINED; rt300@0: } rt300@0: rt300@0: rt300@0: //-------------------------------------------------------------- rt300@0: rt300@0: bool Lump::isGrabbed(){ rt300@0: return grabbed; rt300@0: } rt300@0: rt300@0: //-------------------------------------------------------------- rt300@0: rt300@0: void Lump::highlight(){ rt300@0: highlighted = true; rt300@0: } rt300@0: rt300@0: //-------------------------------------------------------------- rt300@0: rt300@0: void Lump::unhighlight(){ rt300@0: highlighted = false; rt300@0: } rt300@0: //--------------------------------------------------------------