We closed this forum 18 June 2010. It has served us well since 2005 as the ALPHA forum did before it from 2002 to 2005. New discussions are ongoing at the new URL http://forum.processing.org. You'll need to sign up and get a new user account. We're sorry about that inconvenience, but we think it's better in the long run. The content on this forum will remain online.
IndexProgramming Questions & HelpSyntax Questions › Pulling a spring with multiple points
Page Index Toggle Pages: 1
Pulling a spring with multiple points (Read 690 times)
Pulling a spring with multiple points
Aug 27th, 2009, 10:08am
 
I have a spring class that is pulled based on its distance to a point. It works fine with one point, but I cannot seem to make it work with two points.  I have multiple points affecting a non-spring object, but can't seem to get them to work on the spring.  Would anyone know how to add another point?  I am not sure what I am doing wrong.

This is the code for one spring (working):
Code:

Spring s;
Point p;

float mass = 3.;
float stiffness = .3;
float damping = .9;

float radius = 30.;
int falloff = 1;

float targetX;
float targetY;
float x = targetX;
float y = targetY;


void setup() {
 size (600,600);
 background(255);
 smooth();

 float px = 150.;
 float py = 150.;
 
 p = new Point (px, py);
 s = new Spring (100, 100);
}

void draw() {
 background(255);
 s.update(100, 100, p.vp.x, p.vp.y);
 s.display();
 p.display();
}

void mouseDragged() {
 if (mousePressed){
   if (mouseButton == RIGHT)
   {
     p.updateMaxDist();
   }
   else{
     p.update();
   }
 }
}
class Point {
 PVector vp;        // Vector holds point info
 PVector vMouse;    // Vector for mouse
 PVector vecMax;    // Vector for Max Distance
 float maxDist;

 float tempx =0;
 float tempy =0;


 Point (float x_, float y_ ) {
   vp = new PVector (x_, y_);
   maxDist = 100;
 }

 void display() {

   // Circle
   strokeWeight(2);
   stroke (255,0,0);
   fill (255, 150);
   ellipseMode (CENTER);
   ellipse (vp.x, vp.y, 17, 17);

   //Cross-hairs
   strokeWeight(1);
   stroke(0);
   line (vp.x - 15, vp.y, vp.x - 3, vp.y);
   line (vp.x + 3, vp.y, vp.x + 15, vp.y);
   line (vp.x, vp.y - 15, vp.x, vp.y - 3);
   line (vp.x, vp.y + 3, vp.x, vp.y + 15);

   // Radius for Max Distance
   float theta = PI/4;
   float mDx = (vp.x + (maxDist * cos(theta)));
   float mDy = (vp.y + (maxDist * sin(theta)));
   tempx = mDx;
   tempy = mDy;
   vecMax = new PVector (tempx, tempy);

   // Small grab circle
   stroke (150);
   ellipse (vecMax.x, vecMax.y, 10, 10);
   line (vp.x, vp.y, vecMax.x, vecMax.y);

   // Large distance cirlce
   ellipse (vp.x, vp.y, maxDist*2, maxDist*2);
 }

 void update() {
   if (dist(mouseX, mouseY, vp.x, vp.y) < 20) {
     vp.x += (mouseX - pmouseX);
     vp.y += (mouseY - pmouseY);
   }
 }

 void updateMaxDist() {
   if (dist(mouseX, mouseY, tempx, tempy) < 20) {
     tempx += (mouseX - pmouseX);
     tempy += (mouseY - pmouseY);
     maxDist = dist(tempx,tempy,vp.x,vp.y);
     //println(maxDist);
   }
 }
}
class Spring {
 PVector tVec;                  // Target Vector - pinned
 PVector pVec;                    // Pulling Vector
 PVector vPoint;
 float velocityX, velocityY;

 Spring (float x_, float y_) {
 }

 void update (float targetX, float targetY, float pullX, float pullY) {
   tVec = new PVector (targetX, targetY);
   pVec = new PVector (pullX, pullY);

   // Get distance from circle to the point
   vPoint = new PVector(pullX, pullY, 0);
   vPoint.sub (tVec);
   float m = vPoint.mag();

   // Scale with falloff
   float m1 = (pow(m/p.maxDist,falloff));
   println(p.maxDist);

   float forceX = stiffness * (tVec.x - pVec.x);
   float accelerationX = forceX / mass;
   velocityX = damping * (velocityX + accelerationX);

   float forceY = stiffness * (tVec.y - pVec.y);
   float accelerationY = forceY / mass;
   velocityY = damping * (velocityY + accelerationY);

   // If distance is less than max distance => apply scale
   if (m < p.maxDist) {
     pVec.x += velocityX * m1;
     pVec.y += velocityY * m1;
   }
   else {
     pVec.x = tVec.x;
     pVec.y = tVec.y;
   }    
 }

 void display() {
   // Colour based on distance from target
   float m = PVector.dist (tVec, pVec);
   float c = map (m, 0, 100, 0, 255);
   fill (c, 0, 0);
   // Size based on distance
   float sW = radius + abs(tVec.x-pVec.x);
   float sH = radius + abs(tVec.y-pVec.y);
   ellipse (pVec.x, pVec.y, sW, sH);
   line (tVec.x, tVec.y, pVec.x, pVec.y);
 }
}
Re: Pulling a spring with multiple points
Reply #1 - Aug 27th, 2009, 10:16am
 
Not sure if this helps, but this is how it should work (only with the spring rather than the ellipse.  Apologies for all the code.  Any pointers at all would be greatly appreciated.
Code:

float scaleMax = 10;      // Keep this high for high falloff
float falloff = 2;
float maxDistance = 100.;
float scaleX = 20;
float scaleY = 20;
Point p1, p2, p3;

Circle c1;

void setup() {
 size (800,800);
 background(255);
 smooth();

 float vpx = 200;          // Initial position for the point
 float vpy = 200;
 float vp2x = 300;
 float vp2y = 300;
 float vp3x = 400;
 float vp3y = 200;
 p1 = new Point (vpx, vpy);      // initialise the point object
 p2 = new Point (vp2x, vp2y);
 p3 = new Point (vp3x, vp3y);
 c1 = new Circle(400, 400, scaleX, scaleY);  // Initialise the circle

 //println(p.vecMax.x+","+ p.vecMax.y);
}

void draw() {

 background (255);
 c1.updateScale3(p1.vp.x, p1.vp.y, p2.vp.x, p2.vp.y, p3.vp.x, p3.vp.y);
 c1.display();
 
 p1.display();
 p2.display();
 p3.display();
 plotLine();
 //println(p.vp.x*p.maxDist/100);
}

void mouseDragged() {
 if (mousePressed){
   if (mouseButton == RIGHT)
   {
     p1.updateMaxDist();
     p2.updateMaxDist();
     p3.updateMaxDist();
   }
   else{
     p1.update();
     p2.update();
     p3.update();
   }
 }
}


 void plotLine() {
   line(p1.vp.x, p1.vp.y, p2.vp.x, p2.vp.y);
   line(p2.vp.x, p2.vp.y, p3.vp.x, p3.vp.y);
   line(p3.vp.x, p3.vp.y, p1.vp.x, p1.vp.y);
 }
class Circle {
 float sX, sY;          // Scale in x- and y-dir
 PVector center;
 PVector vPoint1, vPoint2, vPoint3;
 float red;
 float green;
 float blue;

 Circle (float x_, float y_, float sX_, float sY_) {
   center = new PVector (x_, y_);
   sX = sX_;
   sY = sY_;
 }

 void display() {
   fill (red, 0, 0, 255-blue);
   strokeWeight(1);
   stroke(150);
   ellipse (center.x, center.y, sX, sY);
 }
 
 void updateScale3 (float px1, float py1, float px2, float py2, float px3, float py3) {
   // Get distance from circle to the point
   vPoint1 = new PVector (px1, py1, 0);
   vPoint2 = new PVector (px2, py2, 0);
   vPoint3 = new PVector (px3, py3, 0);
   vPoint1.sub (center);
   vPoint2.sub (center);
   vPoint3.sub (center);
   float m1 = vPoint1.mag();
   float m2 = vPoint2.mag();
   float m3 = vPoint3.mag();
   //println(m);
   //println(dm-200);

   // Scale with falloff
   float mX1 =   (1/(pow(m1/p1.maxDist,3)));
   float mY1 =  (1/(pow(m1/p1.maxDist,3)));
   float mX2 =   (1/(pow(m2/p2.maxDist,3)));
   float mY2 =  (1/(pow(m2/p2.maxDist,3)));
   float mX3 =   (1/(pow(m3/p3.maxDist,3)));
   float mY3 =  (1/(pow(m3/p3.maxDist,3)));

   // Constrain scale to region
   float mX1c = constrain (mX1, 1, scaleMax);
   float mY1c = constrain (mY1, 1, scaleMax);
   float mX2c = constrain (mX2, 1, scaleMax);
   float mY2c = constrain (mY2, 1, scaleMax);
   float mX3c = constrain (mX3, 1, scaleMax);
   float mY3c = constrain (mY3, 1, scaleMax);

   // If distance is less than max distance => apply scale
   if ((m1 < p1.maxDist) && (m2 < p2.maxDist) && (m3 < p3.maxDist)) {    
     sX = scaleX*(mX1c + mX2c + mX3c);
     sY = scaleY*(mY1c + mY2c + mX3c);
     //red = map (mX, 0, 100, 0, 255);
     //blue = map (mY, 0, 100, 0, 255);
   }
   else if ((m1 < p1.maxDist) && (m2 < p2.maxDist)) {    
     sX = scaleX*(mX1c + mX2c);
     sY = scaleY*(mY1c + mY2c);
   }
   else if ((m2 < p2.maxDist) && (m3 < p3.maxDist)) {
     sX = scaleX*(mX2c + mX3c);
     sY = scaleY*(mY2c + mY3c);
   }
   else if ((m3 < p3.maxDist) && (m1 < p1.maxDist)) {
     sX = scaleX*(mX3c + mX1c);
     sY = scaleY*(mY3c + mY1c);
   }
   else if (m1 < p1.maxDist) {
     sX = scaleX*(mX1c);
     sY = scaleY*(mY1c);
   }
   else if (m2 < p2.maxDist) {
     sX = scaleX*(mX2c);
     sY = scaleY*(mY2c);
   }
   else if (m3 < p3.maxDist) {
     sX = scaleX*(mX3c);
     sY = scaleY*(mY3c);
   }
   else {
     sX = scaleX;
     sY = scaleY;
   }
 }
}
class Point {
 PVector vp;        // Vector holds point info
 PVector vMouse;    // Vector for mouse
 PVector vecMax;    // Vector for Max Distance
 float maxDist;

 float tempx =0;
 float tempy =0;


 Point (float x_, float y_ ) {
   vp = new PVector (x_, y_);
   maxDist = 100;
 }

 void display() {

   // Circle
   strokeWeight(2);
   stroke (255,0,0);
   fill (255, 150);
   ellipseMode (CENTER);
   ellipse (vp.x, vp.y, 17, 17);

   //Cross-hairs
   strokeWeight(1);
   stroke(0);
   line (vp.x - 15, vp.y, vp.x - 3, vp.y);
   line (vp.x + 3, vp.y, vp.x + 15, vp.y);
   line (vp.x, vp.y - 15, vp.x, vp.y - 3);
   line (vp.x, vp.y + 3, vp.x, vp.y + 15);

   // Radius for Max Distance
   float theta = PI/4;
   float mDx = (vp.x + (maxDist * cos(theta)));
   float mDy = (vp.y + (maxDist * sin(theta)));
   tempx = mDx;
   tempy = mDy;
   vecMax = new PVector (tempx, tempy);

   // Small grab circle
   stroke (150);
   ellipse (vecMax.x, vecMax.y, 10, 10);
   line (vp.x, vp.y, vecMax.x, vecMax.y);

   // Large distance cirlce
   ellipse (vp.x, vp.y, maxDist*2, maxDist*2);
 }

 void update() {
   if (dist(mouseX, mouseY, vp.x, vp.y) < 20) {
     vp.x += (mouseX - pmouseX);
     vp.y += (mouseY - pmouseY);
   }
 }

 void updateMaxDist() {
   if (dist(mouseX, mouseY, tempx, tempy) < 20) {
     tempx += (mouseX - pmouseX);
     tempy += (mouseY - pmouseY);
     maxDist = dist(tempx,tempy,vp.x,vp.y);
   }
 }
}

Re: Pulling a spring with multiple points
Reply #2 - Aug 27th, 2009, 12:28pm
 
I get the impression you're making things far more complicated than they need to be; though I must admit I haven't fully understood your goal.

Anyway - a fantastic resource on springing is Keith Peter's ActionScript animation.  You can download the example files from here. ch08_12.fla might be along the lines of what you're trying to achieve and it's done with surprisingly little code, even allowing for the fact that Flash makes some of the interaction more straightforward.  It's not too difficult to convert AS code to Processing so I'd definitely recommend the book...

Actually you're in luck.  The sample chapter is just the one you need Smiley
Re: Pulling a spring with multiple points
Reply #3 - Aug 28th, 2009, 2:39am
 
I haven't played with springing code for a while - it's fun!  Cheesy

I converted the 'attaching multiple objects with springs' example from 'ActionScript Animation' to Processing.  This example could be improved a little further, but it demonstrates the point.

Actually comparing it to your code I don't think it does exactly what you want.  It seems to me you're more interested in gravitational attraction than springing, or maybe you want to combine them both  Again there's an excellent example of this concept in action in the ActionScript Animation book.  I might have a go at converting that example too at some point, but am away for the weekend and may be fairly busy in the next couple of weeks...
multiple-springs (also questions about registerDra
Reply #4 - Aug 31st, 2009, 10:20am
 
I've made another example that looks closer to what you're trying to achieve...  

It also raises a couple of questions from me:  When using registerDraw (as suggested here) it would seem objects are drawn in the order they are registered.  Is there any way to alter this draw order on the fly  Is there a way to alter when Processing's draw loop is rendered (it appears to be drawn first and then objects drawn on top)
Page Index Toggle Pages: 1