public void draw(Graphics g) {
    animate();

    g.setColor(Color.black);
    g.fillRect(0, 0, dim.width, dim.height);
    g.setColor(Color.white);

    numpaint++;
    DebugPrinter dbg = new DebugPrinter(g, 50, 60);
    dbg.print(
        "Spring-mass demo by yigal irani, drag balls or create new ones by clicking inside box");
    dbg.print("frame", numpaint);
    dbg.print("fps", 1 / timer.time_diff);

    Point top_left = point_by_vec(new Vec(-1, 1));
    g.draw3DRect(top_left.x, top_left.y, screen_dist(2), screen_dist(2), true);
    for (int i = 0; i < springs.size(); i++) {
      Spring spring = springs.get2(i);
      Point p1 = point_by_vec(balls.get2(spring.start).pos);
      Point p2 = point_by_vec(balls.get2(spring.end).pos);
      g.drawLine(p1.x, p1.y, p2.x, p2.y);
    }
    for (int i = 0; i < balls.size(); i++) {
      Ball ball = balls.get2(i);
      Point p = point_by_vec(ball.pos);
      int screen_radius = screen_dist(RADIUS);
      g.setColor(Color.blue);
      g.fillOval(p.x - screen_radius, p.y - screen_radius, screen_radius * 2, screen_radius * 2);

      g.setColor(Color.white);
      g.drawOval(p.x - screen_radius, p.y - screen_radius, screen_radius * 2, screen_radius * 2);

      g.drawString("" + i, p.x, p.y);
    }
  }
  void the_derive(double time, double y[], double dy[]) {
    int i;
    BallVector balls = decode_balls(y); // new BallVector();//Ball[num_balls];
    BallVector dballs = new BallVector(); // new Ball[num_balls];

    for (i = 0; i < num_balls; i++) {
      Ball p = balls.get2(i);
      Ball d = new Ball();
      d.pos = p.speed;
      d.speed = wall_power(p);
      d.speed.y -= 1; // gravity
      dballs.add(d);
    }

    for (i = 0; i < num_balls; i++)
      for (int j = i + 1; j < num_balls; j++) {
        Ball p1 = balls.get2(i);
        Ball p2 = balls.get2(j);
        if (far_away_fast_calc(p1.pos, p2.pos, radius * 2)) continue;
        double dist = p1.pos.calc_dist(p2.pos);
        // if (dist>radius*2)
        //	continue;

        Vec collide_power = calc_collide_power(p1, p2, dist);
        dballs.get2(i).speed.add_to(collide_power);
        dballs.get2(j).speed.sub_to(collide_power);
      }
    for (i = 0; i < springs.size(); i++) {
      Spring s = springs.get2(i);
      Vec collide_power = calc_spring_power(balls.get2(s.start), balls.get2(s.end));
      dballs.get2(s.start).speed.add_to(collide_power);
      dballs.get2(s.end).speed.sub_to(collide_power);
    }
    encode_balls(dballs, dy);
  };
 BallVector decode_balls(double y[]) {
   BallVector ans = new BallVector();
   for (int i = 0; i < num_balls; i++) {
     Ball p = new Ball();
     p.pos.x = y[i * 4 + 1];
     p.pos.y = y[i * 4 + 2];
     p.speed.x = y[i * 4 + 3];
     p.speed.y = y[i * 4 + 4];
     ans.addElement(p);
   }
   return ans;
 }
 int find_ball(Vec v) {
   int num_balls = balls.size();
   for (int i = 0; i < num_balls; i++) {
     Ball p = balls.get2(i);
     double dist = v.calc_dist(p.pos);
     if (dist < RADIUS) {
       //		    printf("found ball %d\n",i);
       find_offset = p.pos.sub(dragged_vec);
       // last_dragged_vec=v;
       return i;
     }
   }
   return -1;
 }
  void encode_balls(BallVector balls, double y[]) {

    for (int i = 0; i < num_balls; i++) {
      Ball p = balls.get2(i);
      y[i * 4 + 1] = p.pos.x;
      y[i * 4 + 2] = p.pos.y;
      y[i * 4 + 3] = p.speed.x;
      y[i * 4 + 4] = p.speed.y;
    }
  }
  void animate() {
    dim = getSize();
    size = (int) (Math.min(dim.height, dim.width) / 2.2);
    timer.tell_time();
    if (timer.time_diff == 0) return; // not enought time has passed, dont animate-crach fix
    dragged_speed = dragged_vec.sub(last_dragged_vec).div(timer.time_diff);
    last_dragged_vec = dragged_vec;
    if (dragged_ball != -1) {
      balls.get2(dragged_ball).pos = dragged_vec.add(find_offset).trim(-1, 1);
      balls.get2(dragged_ball).speed = dragged_speed;
    }

    balls = new WorldAnimate().calc_new_frame(balls, springs, RADIUS, timer);
  }
 public BallVector calc_new_frame(
     BallVector _balls,
     SpringVector _springs,
     double _radius,
     Timer timer) { // return the the balls of the next frame
   balls = _balls;
   springs = _springs;
   radius = _radius;
   num_balls = balls.size();
   int i;
   for (i = 0; i < NUM_STEPS; i++)
     call_rk4(timer.cur_time, timer.time_diff / NUM_STEPS); // too: acum the time?
   return balls;
 }
 void call_rk4(double cur_time, double time_diff) {
   num_balls = balls.size();
   double[] y = new_vector(num_balls * 4); // double[num_balls*4];
   double[] dy = new_vector(num_balls * 4);
   encode_balls(balls, y);
   the_derive(
       cur_time, y,
       dy); // the current implementation of derive does not uses the time, but can envision an
            // implementation that might (gravity is off every second, perhaps?)
   rk4(y, dy, num_balls * 4, cur_time, time_diff, y);
   // balls=new BallVector();
   balls = decode_balls(y);
   // free_vector(y,1,num_balls*4);
   //	    free_vector(dy,1,num_balls*4);
 }
 void init_world() {
   springs = new SpringVector(); // [num_springs];
   add_spring(0, 1);
   add_spring(1, 2);
   add_spring(2, 0);
   add_spring(3, 4);
   add_spring(4, 5);
   add_spring(5, 3);
   add_spring(0, 4);
   balls = new BallVector(); // [num_balls];
   for (int i = 0; i < NUM_POINTS; i++) {
     Ball p = new Ball();
     init_rand(p);
     balls.addElement(p);
   }
 }
 void new_ball(Vec vec) {
   Ball b = new Ball();
   b.pos = vec;
   balls.add(b);
 }