/**
  * Calculates a minimum bounding sphere for the set of points. The algorithm was originally found
  * at
  * http://www.flipcode.com/cgi-bin/msg.cgi?showThread=COTD-SmallestEnclosingSpheres&forum=cotd&id=-1
  * in C++ and translated to java by Cep21
  *
  * @param points The points to calculate the minimum bounds from.
  */
 public void calcWelzl(FloatBuffer points) {
   if (center == null) {
     center = new Vector3f();
   }
   FloatBuffer buf = BufferUtils.createFloatBuffer(points.limit());
   points.rewind();
   buf.put(points);
   buf.flip();
   recurseMini(buf, buf.limit() / 3, 0, 0);
 }
  /**
   * Used from calcWelzl. This function recurses to calculate a minimum bounding sphere a few points
   * at a time.
   *
   * @param points The array of points to look through.
   * @param p The size of the list to be used.
   * @param b The number of points currently considering to include with the sphere.
   * @param ap A variable simulating pointer arithmatic from C++, and offset in <code>points</code>.
   */
  private void recurseMini(FloatBuffer points, int p, int b, int ap) {
    Vector3f tempA = Vector3f.newInstance();
    Vector3f tempB = Vector3f.newInstance();
    Vector3f tempC = Vector3f.newInstance();
    Vector3f tempD = Vector3f.newInstance();

    try {
      switch (b) {
        case 0:
          this.radius = 0;
          this.center.set(0, 0, 0);
          break;
        case 1:
          this.radius = 1f - RADIUS_EPSILON;
          BufferUtils.populateFromBuffer(center, points, ap - 1);
          break;
        case 2:
          BufferUtils.populateFromBuffer(tempA, points, ap - 1);
          BufferUtils.populateFromBuffer(tempB, points, ap - 2);
          setSphere(tempA, tempB);
          break;
        case 3:
          BufferUtils.populateFromBuffer(tempA, points, ap - 1);
          BufferUtils.populateFromBuffer(tempB, points, ap - 2);
          BufferUtils.populateFromBuffer(tempC, points, ap - 3);
          setSphere(tempA, tempB, tempC);
          break;
        case 4:
          BufferUtils.populateFromBuffer(tempA, points, ap - 1);
          BufferUtils.populateFromBuffer(tempB, points, ap - 2);
          BufferUtils.populateFromBuffer(tempC, points, ap - 3);
          BufferUtils.populateFromBuffer(tempD, points, ap - 4);
          setSphere(tempA, tempB, tempC, tempD);
          return;
      }
      for (int i = 0; i < p; i++) {
        BufferUtils.populateFromBuffer(tempA, points, i + ap);
        if (tempA.distanceSquared(center) - (radius * radius) > RADIUS_EPSILON - 1f) {
          for (int j = i; j > 0; j--) {
            BufferUtils.populateFromBuffer(tempB, points, j + ap);
            BufferUtils.populateFromBuffer(tempC, points, j - 1 + ap);
            BufferUtils.setInBuffer(tempC, points, j + ap);
            BufferUtils.setInBuffer(tempB, points, j - 1 + ap);
          }
          recurseMini(points, i, b + 1, ap + 1);
        }
      }
    } finally {
      Vector3f.recycle(tempA);
      Vector3f.recycle(tempB);
      Vector3f.recycle(tempC);
      Vector3f.recycle(tempD);
    }
  }