private void bounceBall(int ball) {
    int ball4 = ball * 4;

    double rx = state[ball4];
    double vx = state[ball4 + 1];
    double ry = state[ball4 + 2];
    double vy = state[ball4 + 3];
    double vr;

    switch (getApproxSector(ball)) {
    case 1:
      // first sector: bounce off circle
      rx += l2;
      vr = -2 * (rx * vx + ry * vy) / (rx * rx + ry * ry);
      vx += rx * vr;
      vy += ry * vr;

      state[ball4 + 1] = vx;
      state[ball4 + 3] = vy;

      break;
    case 2:
      // second sector: invert the y movement
      state[ball4 + 3] = -vy;

      break;
    case 3:
      // third sector: bounce off circle

      rx -= l2;
      vr = -2 * (rx * vx + ry * vy) / (rx * rx + ry * ry);
      vx += rx * vr;
      vy += ry * vr;

      state[ball4 + 1] = vx;
      state[ball4 + 3] = vy;

      // remove ball if it enters the hole
      if (ry < h2 && ry > -h2) {
        double oldstate[] = state;
        state = new double[state.length - 4];
        int offset = 0;
        for (int i = 0; i < state.length; ++i) {
          if (i == ball4) {
            offset = 4;
          }
          state[i] = oldstate[i + offset];
        }

        break;
      }

      break;
    case 0:
      // outside: kill the program
      throw new RuntimeException("bounceBall: Ball left space");
    }

    return;
  }