[Solved] Returning NaN, why ?

edited April 2014 in Questions about Code

Hello,

I am trying to create a charge particle system where when you click left mouse it creates negative charge and right click creates positive charge. You can add as many as positive and negative charges.

The problem in my code is when I try to calculate the ditance between the two charges it returns NaN and when I check for NaN as in line number 63 it returns some float values so I figured out that when I try calculating the force and accl it returns NaN but when float.NaN(d) is ture the d returns some value.

ArrayList<Charge> poop = new ArrayList();
void setup() {
  size(300, 200);
}

float k =  1; // 8.98E+9; //  8.9875517873681764×10^9
void draw() {
  background(0);
  for (int i=0;i<poop.size();i++) {
    Charge q = (Charge)poop.get(i);
    q.show();
    q.update();
    q.applyForce(q);
  }
}

void mousePressed() {
  int t=1;
  if (mouseButton == RIGHT) t = 1;
  if (mouseButton == LEFT) t = -1;
  Charge C = new Charge(t, mouseX, mouseY);
  poop.add(C);
}

class Charge {
  PVector loc;
  PVector vel;
  PVector acc;
  float k =  1;
  float state = 1;//1.60E-19; //  1.602176487×10−19
  color c;

  Charge(int t, int x, int y) {
    loc = new PVector(x, y);
    vel = new PVector(0, 0);
    acc = new PVector(0, 0);
    //acc = new PVector(random(-0.05, 0.05), random(-0.05, 0.05));
    state*=t;
    c = (color) random(#000000);
  }

  void show() {
    noFill();
    strokeWeight(2);
    stroke(c);
    ellipse(loc.x, loc.y, 20, 20);
    setCharge();
  }

  void update() {
    vel.add(acc);
    vel.limit(1);
    loc.add(vel);
  }

  void applyForce(Charge C) {

    for (int i=0;i<poop.size();i++) {
      Charge Q = (Charge)poop.get(i);
      PVector dir = PVector.sub(Q.loc, C.loc);
      float d = dir.mag();
      println(" d: " + d);
      if (!Float.isNaN(d)) {
        float force = (k*Q.state*C.state)/d*d;
        dir.mult(force);
        acc.add(dir);
      }
    }

  }

  void setCharge() {
    pushMatrix();
    translate(loc.x, loc.y);
    if (state<0)line(-5, 0, 5, 0);
    else {
      line(0, -5, 0, 5); 
      line(-5, 0, 5, 0);
    }
    popMatrix();
  }
}

boolean flag=false;
void keyPressed() {
  flag = !flag;
}
Tagged:

Answers

  • The problem is caused because in applyForce you end up testing a charge against itself which creates the NaNs. Change this method to

      void applyForce(Charge C) {
        for (int i=0;i<poop.size();i++) {
          Charge Q = (Charge)poop.get(i);
          if (Q != C) {
            PVector dir = PVector.sub(Q.loc, C.loc);
            float d = dir.mag();
            float force = (k*Q.state*C.state)/d*d;
            dir.mult(force);
            acc.add(dir);
          }
        }
      }
    

    There is now need to to check for NaNs because they will not be created.

  • @Quark once again you saved me :) :) :) Thank you sooooo much :) Actually I had the same thought it might be returning NaN becuase charge is checking against itself. I should believe myself before posting silly question :P .............

    So now I did the changes but something strange happening ..now same charges are attracting and opposite charges are repling :/ ...

  • edited April 2014 Answer ✓

    Tip: No need for (Charge) casting if you had already declared the Collection type variable is for Charge references only! *-:)

    ArrayList<Charge> poop = new ArrayList();

    Charge Q = poop.get(i);

  • Answer ✓

    So now I did the changes but something strange happening ..now same charges are attracting and opposite charges are repling

    The applyForce method is part of the Charge class but is testing every charge against every other charge. Then you repeat this for each Charge in draw.

    Anyway I have made the corrections to the code see below

    ArrayList<Charge> poop = new ArrayList<Charge>();
    void setup() {
      size(300, 200);
    }
    
    float k =  1; // 8.98E+9; //  8.9875517873681764×10^9
    void draw() {
      background(0);
      for (int i=0;i<poop.size();i++) {
        Charge q = poop.get(i);
        q.show();
        q.update();
        q.applyForce(poop);
      }
    }
    
    void mousePressed() {
      int t=1;
      if (mouseButton == RIGHT) t = 1;
      if (mouseButton == LEFT) t = -1;
      Charge C = new Charge(t, mouseX, mouseY);
      poop.add(C);
    }
    
    boolean flag=false;
    void keyPressed() {
      flag = !flag;
    }
    
    class Charge {
      PVector loc;
      PVector vel;
      PVector acc;
      float k =  1;
      float state = 1;//1.60E-19; //  1.602176487×10−19
      color c;
    
      Charge(int t, int x, int y) {
        loc = new PVector(x, y);
        vel = new PVector(0, 0);
        acc = new PVector(0, 0);
        //acc = new PVector(random(-0.05, 0.05), random(-0.05, 0.05));
        state*=t;
        c = (color) random(#000000);
      }
    
      void show() {
        noFill();
        strokeWeight(2);
        stroke(c);
        ellipse(loc.x, loc.y, 20, 20);
        setCharge();
      }
    
      void update() {
        vel.add(acc);
        vel.limit(1);
        loc.add(vel);
      }
    
      void applyForce(ArrayList<Charge> allCharges) {  
        for (int i=0;i<allCharges.size();i++) {
          Charge c = poop.get(i);
          if (this != c) {
            PVector dir = PVector.sub(loc, c.loc);
            float d = dir.mag();
            float force = (k*state*c.state)/d*d;
            dir.mult(force);
            acc.add(dir);
          }
        }
      }
    
      void setCharge() {
        pushMatrix();
        translate(loc.x, loc.y);
        if (state<0)line(-5, 0, 5, 0);
        else {
          line(0, -5, 0, 5);
          line(-5, 0, 5, 0);
        }
        popMatrix();
      }
    }
    
  • edited April 2014

    @Quark I dont know if I am correct but I think in the line 64 where you have made correction for checking if this!=C is correct because when you think "this" object has default positive charge (since charge of the object is set by the mouse pressed) so it has created another problem now charges are randomly attracting and reppelling smilar and opposite charges.

  • Answer ✓

    I think you will find the problem is that acc is not being zeroed each update try

      void applyForce(ArrayList<Charge> allCharges) { 
        acc.x = acc.y = 0;
        for (int i=0;i<allCharges.size();i++) {
          Charge c = poop.get(i);
          if (this != c) {
            PVector dir = PVector.sub(loc, c.loc);
            float d = dir.mag();
            float force = (k*state*c.state)/d*d;
            dir.mult(force);
            acc.add(dir);
          }
        }
      }
    
  • @Quark, I tried it but still after some click same charges are starting to attract each other and repelling to opposite charge. I think my code is buggy :( I'll try to write fresh code.

  • Answer ✓

    I can't see anything wrong with the code logic, but once you have more than 2 charges you have a more complex system so seeing cause-and-effect relationships will be difficult.

    In the update method you limit the velocity to 1 (line 57) but this might cause too much distortion of the system if the magnitude of acc is much larger than 1

  • edited April 2014

    Oh ! I got the error. I was not normalizing the dir vector so I have normalized the dir vector before multiplying it with the force :D Now it is working fine :D Thanks Quark :)

  • edited April 2014

    Just a last question, when I am drawing a resultant vector with line(dir.x,dir.y,C.loc.x,c.loc.y); , the line is drawing from the origin. why not line is pointing towads the net force direction ? It is also not working in js mode?

    ArrayList<Charge> poop = new ArrayList<Charge>();
    void setup() {
      size(600, 200);
    }
    
    float k =  1; // 8.98E+9; //  8.9875517873681764×10^9
    void draw() {
      background(0);
      for (int i=0;i<poop.size();i++) {
        Charge q = poop.get(i);
        q.show();
        q.update();
        q.applyForce(poop);
        q.bounce();
      }
    }
    
    void mousePressed() {
      int t=1;
      if (mouseButton == RIGHT) t = 1;
      if (mouseButton == LEFT) t = -1;
      Charge C = new Charge(t, mouseX, mouseY);
      poop.add(C);
    }
    
    boolean flag=false;
    void keyPressed() {
      flag = !flag;
    }
    
    class Charge {
      PVector loc;
      PVector vel;
      PVector acc;
      float k =  1;
      float state = 1;//1.60E-19; //  1.602176487×10−19
      color c;
    
      Charge(int t, int x, int y) {
        loc = new PVector(x, y);
        vel = new PVector(0, 0);
        acc = new PVector(0, 0);
        //acc = new PVector(random(-0.05, 0.05), random(-0.05, 0.05));
        state*=t;
        c = (color) random(#000000);
      }
    
      void show() {
        noFill();
        strokeWeight(2);
        stroke(c);
        ellipse(loc.x, loc.y, 20, 20);
        setCharge();
      }
    
      void update() {
        vel.add(acc);
        vel.limit(4);
        loc.add(vel);
      }
    
      void applyForce(ArrayList<Charge> allCharges) {  
        acc.mult(0);
        for (int i=0;i<allCharges.size();i++) {
          Charge c = poop.get(i);
          if (this != c) {
            PVector dir = PVector.sub(loc, c.loc);
            float d = dir.mag();
            float force = (k*state*c.state)/d*d;
            dir.normalize();
            dir.mult(force);
            acc.add(dir);
            stroke(-1);
            strokeWeight(0.5);
            line(dir.x, dir.y, c.loc.x, c.loc.y);
          }
        }
      }
    
      void setCharge() {
        pushMatrix();
        translate(loc.x, loc.y);
        if (state<0)line(-5, 0, 5, 0);
        else {
          line(0, -5, 0, 5);
          line(-5, 0, 5, 0);
        }
        popMatrix();
      }
    
      void bounce() {
        if (loc.x < 0 || loc.x >width ) vel.x = vel.x*-1;
        if (loc.y < 0 || loc.y >height) vel.y = vel.y*-1;
      }
    }
    
  • Answer ✓

    dir is a PVector relative to the charge location so

    line(c.loc.x, c.loc.y, c.loc.x + dir.x, c.loc.y + dir.y);

    The only problem is that the magnitude of dir is very small so you won't see it. Try

    line(c.loc.x, c.loc.y, c.loc.x + dir.x *10, c.loc.y + dir.y * 10);

  • Thanks that worked :)

  • blyk, remember to choose a category when posting... Thanks.

Sign In or Register to comment.