Loading...
Logo
Processing Forum
Hello everyone,

I'm trying to port a simple example of Node+Spring from Generative Gestaltung to processing js with no luck.

I've got rid of libraries and stuff that could cause pbs, it runs in plain java so it should work but I get an :

Uncaught TypeError: Object #<Node> has no method 'get'

So it seems that the error comes from the class Node, and as a matter of fact the class extends PVector, so I guess the issue would come from there. It's a weird error and I really don't know were to start digging to resolve this.

I already used extended class in pjs and it didn't seem to cause trouble, does anybody have an idea how to solve this ?
Copy code

  1. Node nodeA, nodeB;
  2. Spring spring;


  3. void setup() {
  4.   size(600, 600);
  5.   smooth();
  6.   fill(0);
  7.     
  8.   PVector vecA = new PVector(  width/2+random(-50, 50), height/2+random(-50, 50));
  9.   PVector vecB = new PVector(  width/2+random(-50, 50), height/2+random(-50, 50));
  10.     
  11.   nodeA = new Node(vecA);
  12.   nodeB = new Node(vecB);

  13.   nodeA.setDamping(0.1);
  14.   nodeB.setDamping(0.1);

  15.   spring = new Spring(nodeA, nodeB);
  16.   spring.setLength(100);
  17.   spring.setStiffness(0.6);
  18.   spring.setDamping(0.3);
  19. }


  20. void draw() {
  21.   background(255);

  22.   if (mousePressed == true) {
  23.     nodeA.x = mouseX;
  24.     nodeA.y = mouseY;
  25.   }

  26.   // update spring
  27.   spring.update();

  28.   // update node positions
  29.   nodeA.update();
  30.   nodeB.update();


  31.   // draw spring
  32.   stroke(0, 130, 164);
  33.   strokeWeight(4);
  34.   line(nodeA.x, nodeA.y, nodeB.x, nodeB.y);

  35.   // draw nodes
  36.   noStroke();
  37.   fill(0);
  38.   ellipse(nodeA.x, nodeA.y, 20, 20);
  39.   ellipse(nodeB.x, nodeB.y, 20, 20);
  40. }



  41. // M_6_1_01.pde
  42. // Node.pde
  43. // 
  44. // Generative Gestaltung, ISBN: 978-3-87439-759-9
  45. // First Edition, Hermann Schmidt, Mainz, 2009
  46. // Hartmut Bohnacker, Benedikt Gross, Julia Laub, Claudius Lazzeroni
  47. // Copyright 2009 Hartmut Bohnacker, Benedikt Gross, Julia Laub, Claudius Lazzeroni
  48. //
  49. // http://www.generative-gestaltung.de
  50. //
  51. // Licensed under the Apache License, Version 2.0 (the "License");
  52. // you may not use this file except in compliance with the License.
  53. // You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
  54. // Unless required by applicable law or agreed to in writing, software
  55. // distributed under the License is distributed on an "AS IS" BASIS,
  56. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  57. // See the License for the specific language governing permissions and
  58. // limitations under the License.

  59. class Node extends PVector{

  60.   // ------   properties ------
  61.   // if needed, an ID for the node
  62.   String id = "";
  63.   float diameter = 0;

  64.   float minX = -60000; // those were Float.MAX_VALUE before being 6000 because pjs complained about not knowing Float with a capital F
  65.   float maxX = 60000;
  66.   float minY = -60000;
  67.   float maxY = 60000;
  68.   float minZ = -60000;
  69.   float maxZ = 60000;

  70.   PVector velocity = new PVector();
  71.   PVector pVelocity = new PVector();
  72.   float maxVelocity = 10;

  73.   float damping = 0.5f;
  74.   // radius of impact
  75.   float radius = 200;
  76.   // strength: positive for attraction, negative for repulsion (default for Nodes)
  77.   float strength = -1;
  78.   // parameter that influences the form of the function
  79.   float ramp = 1.0f;


  80.   // ------ constructors ------
  81.   Node() {
  82.   }

  83.   Node(float theX, float theY) {
  84.     x = theX;
  85.     y = theY;
  86.   }

  87.   Node(float theX, float theY, float theZ) {
  88.     x = theX;
  89.     y = theY;
  90.     z = theZ;
  91.   }

  92.   Node(PVector theVector) {

  93.     x = theVector.x;
  94.     y = theVector.y;
  95.     z = theVector.z;
  96.   }

  97.   // ------ rotate position around origin ------
  98.   void rotateX(float theAngle) {
  99.     float newy = y * cos(theAngle) - z * sin(theAngle);
  100.     float newz = y * sin(theAngle) + z * cos(theAngle);
  101.     y = newy;
  102.     z = newz;
  103.   }

  104.   void rotateY(float theAngle) {
  105.     float newx = x * cos(-theAngle) - z * sin(-theAngle);
  106.     float newz = x * sin(-theAngle) + z * cos(-theAngle);
  107.     x = newx;
  108.     z = newz;
  109.   }

  110.   void rotateZ(float theAngle) {
  111.     float newx = x * cos(theAngle) - y * sin(theAngle);
  112.     float newy = x * sin(theAngle) + y * cos(theAngle);
  113.     x = newx;
  114.     y = newy;
  115.   }

  116.   // ------ calculate attraction ------
  117.   void attract(Node[] theNodes) {
  118.     // attraction or repulsion part
  119.     for (int i = 0; i < theNodes.length; i++) {
  120.       Node otherNode = theNodes[i];
  121.       // stop when empty
  122.       if (otherNode == null) break;
  123.       // not with itself
  124.       if (otherNode == this) continue;

  125.       this.attract(otherNode);
  126.     }
  127.   }

  128.   void attract(Node theNode) {
  129.     float d = PVector.dist(this, theNode);

  130.     if (d > 0 && d < radius) {
  131.       float s = pow(d / radius, 1 / ramp);
  132.       float f = s * 9 * strength * (1 / (s + 1) + ((s - 3) / 4)) / d;
  133.       PVector df = PVector.sub(this, theNode);
  134.       df.mult(f);

  135.       theNode.velocity.x += df.x;
  136.       theNode.velocity.y += df.y;
  137.       theNode.velocity.z += df.z;
  138.     }
  139.   }

  140.   // ------ update positions ------
  141.   void update() {
  142.     update(false, false, false);
  143.   }

  144.   void update(boolean theLockX, boolean theLockY, boolean theLockZ) {

  145.     velocity.limit(maxVelocity);

  146.     pVelocity = velocity.get();

  147.     if (!theLockX) x += velocity.x;
  148.     if (!theLockY) y += velocity.y;
  149.     if (!theLockZ) z += velocity.z;

  150.     if (x < minX) {
  151.       x = minX - (x - minX);
  152.       velocity.x = -velocity.x;
  153.     }
  154.     if (x > maxX) {
  155.       x = maxX - (x - maxX);
  156.       velocity.x = -velocity.x;
  157.     }

  158.     if (y < minY) {
  159.       y = minY - (y - minY);
  160.       velocity.y = -velocity.y;
  161.     }
  162.     if (y > maxY) {
  163.       y = maxY - (y - maxY);
  164.       velocity.y = -velocity.y;
  165.     }

  166.     if (z < minZ) {
  167.       z = minZ - (z - minZ);
  168.       velocity.z = -velocity.z;
  169.     }
  170.     if (z > maxZ) {
  171.       z = maxZ - (z - maxZ);
  172.       velocity.z = -velocity.z;
  173.     }

  174.     velocity.mult(1 - damping);
  175.   }

  176.   // ------ getters and setters ------
  177.  
  178.  
  179.   String getID() {
  180.     return id;
  181.   }

  182.   void setID(String theID) {
  183.     this.id = theID;
  184.   }

  185.   float getDiameter() {
  186.     return diameter;
  187.   }

  188.   void setDiameter(float theDiameter) {
  189.     this.diameter = theDiameter;
  190.   }

  191.   void setBoundary(float theMinX, float theMinY, float theMinZ,
  192.   float theMaxX, float theMaxY, float theMaxZ) {
  193.     this.minX = theMinX;
  194.     this.maxX = theMaxX;
  195.     this.minY = theMinY;
  196.     this.maxY = theMaxY;
  197.     this.minZ = theMinZ;
  198.     this.maxZ = theMaxZ;
  199.   }

  200.   void setBoundary(float theMinX, float theMinY, float theMaxX,
  201.   float theMaxY) {
  202.     this.minX = theMinX;
  203.     this.maxX = theMaxX;
  204.     this.minY = theMinY;
  205.     this.maxY = theMaxY;
  206.   }

  207.   float getMinX() {
  208.     return minX;
  209.   }

  210.   void setMinX(float theMinX) {
  211.     this.minX = theMinX;
  212.   }

  213.   float getMaxX() {
  214.     return maxX;
  215.   }

  216.   void setMaxX(float theMaxX) {
  217.     this.maxX = theMaxX;
  218.   }

  219.   float getMinY() {
  220.     return minY;
  221.   }

  222.   void setMinY(float theMinY) {
  223.     this.minY = theMinY;
  224.   }

  225.   float getMaxY() {
  226.     return maxY;
  227.   }

  228.   void setMaxY(float theMaxY) {
  229.     this.maxY = theMaxY;
  230.   }

  231.   float getMinZ() {
  232.     return minZ;
  233.   }

  234.   void setMinZ(float theMinZ) {
  235.     this.minZ = theMinZ;
  236.   }

  237.   float getMaxZ() {
  238.     return maxZ;
  239.   }

  240.   void setMaxZ(float theMaxZ) {
  241.     this.maxZ = theMaxZ;
  242.   }

  243.   PVector getVelocity() {
  244.     return velocity;
  245.   }

  246.   void setVelocity(PVector theVelocity) {
  247.     this.velocity = theVelocity;
  248.   }

  249.   float getMaxVelocity() {
  250.     return maxVelocity;
  251.   }

  252.   void setMaxVelocity(float theMaxVelocity) {
  253.     this.maxVelocity = theMaxVelocity;
  254.   }

  255.   float getDamping() {
  256.     return damping;
  257.   }

  258.   void setDamping(float theDamping) {
  259.     this.damping = theDamping;
  260.   }

  261.   float getRadius() {
  262.     return radius;
  263.   }

  264.   void setRadius(float theRadius) {
  265.     this.radius = theRadius;
  266.   }

  267.   float getStrength() {
  268.     return strength;
  269.   }

  270.   void setStrength(float theStrength) {
  271.     this.strength = theStrength;
  272.   }

  273.   float getRamp() {
  274.     return ramp;
  275.   }

  276.   void setRamp(float theRamp) {
  277.     this.ramp = theRamp;
  278.   }
  279. }



  280. // M_6_1_02.pde
  281. // Spring.pde
  282. // 
  283. // Generative Gestaltung, ISBN: 978-3-87439-759-9
  284. // First Edition, Hermann Schmidt, Mainz, 2009
  285. // Hartmut Bohnacker, Benedikt Gross, Julia Laub, Claudius Lazzeroni
  286. // Copyright 2009 Hartmut Bohnacker, Benedikt Gross, Julia Laub, Claudius Lazzeroni
  287. //
  288. // http://www.generative-gestaltung.de
  289. //
  290. // Licensed under the Apache License, Version 2.0 (the "License");
  291. // you may not use this file except in compliance with the License.
  292. // You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
  293. // Unless required by applicable law or agreed to in writing, software
  294. // distributed under the License is distributed on an "AS IS" BASIS,
  295. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  296. // See the License for the specific language governing permissions and
  297. // limitations under the License.

  298. class Spring {
  299.   Node fromNode;
  300.   Node toNode;

  301.   float length = 100;
  302.   float stiffness = 0.6;
  303.   float damping = 0.9;

  304.   // ------ constructors ------
  305.   Spring(Node theFromNode, Node theToNode) {
  306.     fromNode = theFromNode;
  307.     toNode = theToNode;
  308.   }

  309.   Spring(Node theFromNode, Node theToNode, float theLength, float theStiffness, float theDamping) {
  310.     fromNode = theFromNode;
  311.     toNode = theToNode;

  312.     length = theLength;
  313.     stiffness = theStiffness;
  314.     damping = theDamping;
  315.   }

  316.   // ------ apply forces on spring and attached nodes ------
  317.   void update() {
  318.     // calculate the target position
  319.     // target = normalize(to - from) * length + from
  320.     PVector diff = PVector.sub(toNode, fromNode);
  321.     diff.normalize();
  322.     diff.mult(length);
  323.     PVector target = PVector.add(fromNode, diff);

  324.     PVector force = PVector.sub(target, toNode);
  325.     force.mult(0.5);
  326.     force.mult(stiffness);
  327.     force.mult(1 - damping);

  328.     toNode.velocity.add(force);
  329.     fromNode.velocity.add(PVector.mult(force, -1));
  330.   }

  331.   // ------ getters and setters ------
  332.   Node getFromNode() {
  333.     return fromNode;
  334.   }

  335.   void setFromNode(Node theFromNode) {
  336.     fromNode = theFromNode;
  337.   }

  338.   Node getToNode() {
  339.     return toNode;
  340.   }

  341.   void setToNode(Node theToNode) {
  342.     toNode = theToNode;
  343.   }

  344.   float getLength() {
  345.     return length;
  346.   }

  347.   void setLength(float theLength) {
  348.     this.length = theLength;
  349.   }

  350.   float getStiffness() {
  351.     return stiffness;
  352.   }

  353.   void setStiffness(float theStiffness) {
  354.     this.stiffness = theStiffness;
  355.   }

  356.   float getDamping() {
  357.     return damping;
  358.   }

  359.   void setDamping(float theDamping) {
  360.     this.damping = theDamping;
  361.   }
  362. }


Replies(9)

I just deleted my other comments.  I wasn't using Javascript mode.

That's the second time I've done that today.

Grrrrrrrrr.
@ line 77, we can see that class Node is a subclass of PVector:
class Node extends PVector {

It means that it inherits everything from PVector, both its methods & fields!
While, at the same time, overshadowing many Processing's own functions 
that happen to have the same name as the 1s  PVector offers!  For example:
  • set()
  • get()
  • dist()
  • rotate()
  • lerp()
I dunno where the problem is, since I haven't perused the code yet.
But it's not for the lack of get()!  
Benj! Seems like you're deleting many posts in which my replies make some reference to it.
And it makes mine seem outta context w/o them!  

Your advice of using  pVelocity = this.getVelocity(); in place of  pVelocity = velocity.get(); 
would add another bug! 

That would assign velocity's reference pointer to pVelocity!
That is, both variables would point to the same PVector object instance!  

Also, prefixing this wouldn't make any difference, since there ain't local variables w/ same name as a field!

And an alternative to line #186 would be ->  pVelocity.set(velocity);
It avoids creating a temporary instance of PVector as get() would! 
Sorry.

The only alternative is to write "[EDIT] this does not work", but I don't see the point in having suggestions that do not work lingering on the site.

I'm just really trigger happy today.  If I chill out I won't have to do either.

(PS:  by many i think you mean two  )


well I'm aware of that :) but the issue stays still since the javascript console says that the class Node as no method get()

FIY i tried to build a fake get method :

void get(){

}

if I do that I get a new error : a null pointer on the next operation using velocity - quite normal I guess. So for some reason it seems that inheritence is broken somehow translating to js ?

i'd cross post to the pjs googlegroup or the lighthouse bug tracker because it seems like its due to the way the pjs source is working with your code (that's where the console says your error is from at least).  and since it works in Java and doesn't use any extra libraries, there's a good shot that the issue is not with your code but something inherent to PJS and the way it converts it.  lots of the folks who maintain the source hangout there.

having said that, the last person i sent there did not get a response.  still, it's worth shot.

http://groups.google.com/group/processingjs
http://processing-js.lighthouseapp.com/

I guess I know what the problem is!  

I had a tweaked program which used a class extending PVector too.
Check it out the middle of this post for it:

I always wanted to make it work in PJS too.
But before that, I had to remove extends PVector from class  Bullet!
Now it can be played online as well:

It seems like JS has some problems w/ overridden methods and methods w/ same name in general!

The only advantage of extending PVector in a class is that it grants 3 float field variables -> x, y, z.
And it can directly use PVector's methods w/o typing anything extra when referring to those fields!

P.S.: As I mentioned in my previous post above, use set() rather than  get() if possible.
It's 1 instance less for both Java & JavaScript's GC to take care of.  
ok got it :)

so basically i remove the extends and declare a new PVector location and replace every occurence of x by location.x etc... right ?

good tip for using the set() method :)


yeah ! it worked :D

Here's the updated code, changes are in bold, the Spring class has had to be updated aswell


Thanks you guys ! and may it be helpful to others ;)

Cheers

Copy code



  1. Node nodeA, nodeB;
  2. Spring spring;


  3. void setup() {
  4.   size(600, 600);
  5.   smooth();
  6.   fill(0);
  7.     
  8.   PVector vecA = new PVector(  width/2+random(-50, 50), height/2+random(-50, 50));
  9.   PVector vecB = new PVector(  width/2+random(-50, 50), height/2+random(-50, 50));
  10.     
  11.   nodeA = new Node(vecA);
  12.   nodeB = new Node(vecB);

  13.   nodeA.setDamping(0.1);
  14.   nodeB.setDamping(0.1);

  15.   spring = new Spring(nodeA, nodeB);
  16.   spring.setLength(100);
  17.   spring.setStiffness(0.6);
  18.   spring.setDamping(0.3);
  19. }


  20. void draw() {
  21.   background(255);

  22.   if (mousePressed == true) {
  23.   nodeA.location.x = mouseX;
  24.    nodeA.location.y = mouseY;
  25.   }

  26.   // update spring
  27.   spring.update();

  28.   // update node positions
  29.   nodeA.update();
  30.   nodeB.update();


  31.   // draw spring
  32.   stroke(0, 130, 164);
  33.   strokeWeight(4);
  34.   line(nodeA.location.x, nodeA.location.y, nodeB.location.x, nodeB.location.y);

  35.   // draw nodes
  36.   noStroke();
  37.   fill(0);
  38.   ellipse(nodeA.location.x, nodeA.location.y, 20, 20);
  39.   ellipse(nodeB.location.x, nodeB.location.y, 20, 20);
  40. }



  41. // M_6_1_01.pde
  42. // Node.pde
  43. // 
  44. // Generative Gestaltung, ISBN: 978-3-87439-759-9
  45. // First Edition, Hermann Schmidt, Mainz, 2009
  46. // Hartmut Bohnacker, Benedikt Gross, Julia Laub, Claudius Lazzeroni
  47. // Copyright 2009 Hartmut Bohnacker, Benedikt Gross, Julia Laub, Claudius Lazzeroni
  48. //
  49. // http://www.generative-gestaltung.de
  50. //
  51. // Licensed under the Apache License, Version 2.0 (the "License");
  52. // you may not use this file except in compliance with the License.
  53. // You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
  54. // Unless required by applicable law or agreed to in writing, software
  55. // distributed under the License is distributed on an "AS IS" BASIS,
  56. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  57. // See the License for the specific language governing permissions and
  58. // limitations under the License.

  59. class Node { // remmoving extends statement

  60.   // ------   properties ------
  61.   // if needed, an ID for the node
  62.   String id = "";
  63.   float diameter = 0;

  64.   float minX = -60000;
  65.   float maxX = 60000;
  66.   float minY = -60000;
  67.   float maxY = 60000;
  68.   float minZ = -60000;
  69.   float maxZ = 60000;

  70.   PVector velocity = new PVector();
  71.   PVector pVelocity = new PVector();
  72.   float maxVelocity = 10;

  73.   float damping = 0.5f;
  74.   // radius of impact
  75.   float radius = 200;
  76.   // strength: positive for attraction, negative for repulsion (default for Nodes)
  77.   float strength = -1;
  78.   // parameter that influences the form of the function
  79.   float ramp = 1.0f;
  80.   
  81.   PVector location = new PVector();



  82.   // ------ constructors ------
  83.   Node() {
  84.    
  85.   }

  86.   Node(float theX, float theY) {
  87.     
  88.    location.x = theX;
  89.     location.y = theY;
  90.   }

  91.   Node(float theX, float theY, float theZ) {
  92.     
  93.     location.x = theX;
  94.     location.y = theY;
  95.    location.z = theZ;
  96.   }

  97.   Node(PVector theVector) {
  98.     
  99.     location.x = theVector.x;
  100.     location.y = theVector.y; 
  101.     location.z = theVector.z;
  102.   }

  103.   // ------ rotate position around origin ------
  104.   void rotateX(float theAngle) {
  105.     float newy = location.y * cos(theAngle) - location.z * sin(theAngle);
  106.     float newz = location.y * sin(theAngle) + location.z * cos(theAngle);
  107.     location.y = newy;
  108.     location.z = newz;
  109.   }

  110.   void rotateY(float theAngle) {
  111.     float newx = location.x * cos(-theAngle) - location.z * sin(-theAngle);
  112.     float newz = location.x * sin(-theAngle) + location.z * cos(-theAngle);
  113.     location.x = newx;
  114.     location.z = newz;
  115.   }

  116.   void rotateZ(float theAngle) {
  117.     float newx = location.x * cos(theAngle) - location.y * sin(theAngle);
  118.     float newy = location.x * sin(theAngle) + location.y * cos(theAngle);
  119.     location.x = newx;
  120.     location.y = newy;
  121.   }

  122.   // ------ calculate attraction ------
  123.   void attract(Node[] theNodes) {
  124.     // attraction or repulsion part
  125.     for (int i = 0; i < theNodes.length; i++) {
  126.       Node otherNode = theNodes[i];
  127.       // stop when empty
  128.       if (otherNode == null) break;
  129.       // not with itself
  130.       if (otherNode == this) continue;

  131.       this.attract(otherNode);
  132.     }
  133.   }

  134.   void attract(Node theNode) {
  135.     float d = PVector.dist(location, theNode.location);

  136.     if (d > 0 && d < radius) {
  137.       float s = pow(d / radius, 1 / ramp);
  138.       float f = s * 9 * strength * (1 / (s + 1) + ((s - 3) / 4)) / d;
  139.       PVector df = PVector.sub(this.location, theNode.location);
  140.       df.mult(f);

  141.       theNode.velocity.x += df.x;
  142.       theNode.velocity.y += df.y;
  143.       theNode.velocity.z += df.z;
  144.     }
  145.   }

  146.   // ------ update positions ------
  147.   void update() {
  148.     update(false, false, false);
  149.   }

  150.   void update(boolean theLockX, boolean theLockY, boolean theLockZ) {

  151.     velocity.limit(maxVelocity);

  152.     pVelocity.set(velocity); // GoToLoop tip to avoid new instance of PVector

  153.     if (!theLockX) location.x += velocity.x;
  154.     if (!theLockY) location.y += velocity.y;
  155.     if (!theLockZ) location.z += velocity.z;

  156.     if (location.x < minX) {
  157.       location.x = minX - (location.x - minX);
  158.       velocity.x = -velocity.x;
  159.     }
  160.     if (location.x > maxX) {
  161.       location.x = maxX - (location.x - maxX);
  162.       velocity.x = -velocity.x;
  163.     }

  164.     if (location.y < minY) {
  165.       location.y = minY - (location.y - minY);
  166.       velocity.y = -velocity.y;
  167.     }
  168.     if (location.y > maxY) {
  169.       location.y = maxY - (location.y - maxY);
  170.       velocity.y = -velocity.y;
  171.     }

  172.     if (location.z < minZ) {
  173.       location.z = minZ - (location.z - minZ);
  174.       velocity.z = -velocity.z;
  175.     }
  176.     if (location.z > maxZ) {
  177.       location.z = maxZ - (location.z - maxZ);
  178.       velocity.z = -velocity.z;
  179.     }

  180.     velocity.mult(1 - damping);
  181.   }

  182.   // ------ getters and setters ------
  183.  
  184.   
  185.   String getID() {
  186.     return id;
  187.   }

  188.   void setID(String theID) {
  189.     this.id = theID;
  190.   }

  191.   float getDiameter() {
  192.     return diameter;
  193.   }

  194.   void setDiameter(float theDiameter) {
  195.     this.diameter = theDiameter;
  196.   }

  197.   void setBoundary(float theMinX, float theMinY, float theMinZ,
  198.   float theMaxX, float theMaxY, float theMaxZ) {
  199.     this.minX = theMinX;
  200.     this.maxX = theMaxX;
  201.     this.minY = theMinY;
  202.     this.maxY = theMaxY;
  203.     this.minZ = theMinZ;
  204.     this.maxZ = theMaxZ;
  205.   }

  206.   void setBoundary(float theMinX, float theMinY, float theMaxX,
  207.   float theMaxY) {
  208.     this.minX = theMinX;
  209.     this.maxX = theMaxX;
  210.     this.minY = theMinY;
  211.     this.maxY = theMaxY;
  212.   }

  213.   float getMinX() {
  214.     return minX;
  215.   }

  216.   void setMinX(float theMinX) {
  217.     this.minX = theMinX;
  218.   }

  219.   float getMaxX() {
  220.     return maxX;
  221.   }

  222.   void setMaxX(float theMaxX) {
  223.     this.maxX = theMaxX;
  224.   }

  225.   float getMinY() {
  226.     return minY;
  227.   }

  228.   void setMinY(float theMinY) {
  229.     this.minY = theMinY;
  230.   }

  231.   float getMaxY() {
  232.     return maxY;
  233.   }

  234.   void setMaxY(float theMaxY) {
  235.     this.maxY = theMaxY;
  236.   }

  237.   float getMinZ() {
  238.     return minZ;
  239.   }

  240.   void setMinZ(float theMinZ) {
  241.     this.minZ = theMinZ;
  242.   }

  243.   float getMaxZ() {
  244.     return maxZ;
  245.   }

  246.   void setMaxZ(float theMaxZ) {
  247.     this.maxZ = theMaxZ;
  248.   }

  249.   PVector getVelocity() {
  250.     return velocity;
  251.   }

  252.   void setVelocity(PVector theVelocity) {
  253.     this.velocity = theVelocity;
  254.   }

  255.   float getMaxVelocity() {
  256.     return maxVelocity;
  257.   }

  258.   void setMaxVelocity(float theMaxVelocity) {
  259.     this.maxVelocity = theMaxVelocity;
  260.   }

  261.   float getDamping() {
  262.     return damping;
  263.   }

  264.   void setDamping(float theDamping) {
  265.     this.damping = theDamping;
  266.   }

  267.   float getRadius() {
  268.     return radius;
  269.   }

  270.   void setRadius(float theRadius) {
  271.     this.radius = theRadius;
  272.   }

  273.   float getStrength() {
  274.     return strength;
  275.   }

  276.   void setStrength(float theStrength) {
  277.     this.strength = theStrength;
  278.   }


  279.   float getRamp() {
  280.     return ramp;
  281.   }

  282.   void setRamp(float theRamp) {
  283.     this.ramp = theRamp;
  284.   }

  285. }



  286. // M_6_1_02.pde
  287. // Spring.pde
  288. // 
  289. // Generative Gestaltung, ISBN: 978-3-87439-759-9
  290. // First Edition, Hermann Schmidt, Mainz, 2009
  291. // Hartmut Bohnacker, Benedikt Gross, Julia Laub, Claudius Lazzeroni
  292. // Copyright 2009 Hartmut Bohnacker, Benedikt Gross, Julia Laub, Claudius Lazzeroni
  293. //
  294. // http://www.generative-gestaltung.de
  295. //
  296. // Licensed under the Apache License, Version 2.0 (the "License");
  297. // you may not use this file except in compliance with the License.
  298. // You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
  299. // Unless required by applicable law or agreed to in writing, software
  300. // distributed under the License is distributed on an "AS IS" BASIS,
  301. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  302. // See the License for the specific language governing permissions and
  303. // limitations under the License.

  304. class Spring {
  305.   Node fromNode;
  306.   Node toNode;

  307.   float length = 100;
  308.   float stiffness = 0.6;
  309.   float damping = 0.9;

  310.   // ------ constructors ------
  311.   Spring(Node theFromNode, Node theToNode) {
  312.     fromNode = theFromNode;
  313.     toNode = theToNode;
  314.   }

  315.   Spring(Node theFromNode, Node theToNode, float theLength, float theStiffness, float theDamping) {
  316.     fromNode = theFromNode;
  317.     toNode = theToNode;

  318.     length = theLength;
  319.     stiffness = theStiffness;
  320.     damping = theDamping;
  321.   }

  322.   // ------ apply forces on spring and attached nodes ------
  323.   void update() {
  324.     // calculate the target position
  325.     // target = normalize(to - from) * length + from
  326.     PVector diff = PVector.sub(toNode.location, fromNode.location);
  327.     diff.normalize();
  328.     diff.mult(length);
  329.     PVector target = PVector.add(fromNode.location, diff);

  330.     PVector force = PVector.sub(target, toNode.location);
  331.     force.mult(0.5);
  332.     force.mult(stiffness);
  333.     force.mult(1 - damping);

  334.     toNode.velocity.add(force);
  335.     fromNode.velocity.add(PVector.mult(force, -1));
  336.   }

  337.   // ------ getters and setters ------
  338.   Node getFromNode() {
  339.     return fromNode;
  340.   }

  341.   void setFromNode(Node theFromNode) {
  342.     fromNode = theFromNode;
  343.   }

  344.   Node getToNode() {
  345.     return toNode;
  346.   }

  347.   void setToNode(Node theToNode) {
  348.     toNode = theToNode;
  349.   }

  350.   float getLength() {
  351.     return length;
  352.   }

  353.   void setLength(float theLength) {
  354.     this.length = theLength;
  355.   }

  356.   float getStiffness() {
  357.     return stiffness;
  358.   }

  359.   void setStiffness(float theStiffness) {
  360.     this.stiffness = theStiffness;
  361.   }

  362.   float getDamping() {
  363.     return damping;
  364.   }

  365.   void setDamping(float theDamping) {
  366.     this.damping = theDamping;
  367.   }

  368. }