/** * 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); } }