Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p><strong>UPDATE</strong>: Upon closer review of the animation and the Wikipedia article, I've decided my algorithm is not Bouncing Bubble. From the animation it is clear that Bouncing Bubble moves the bounding sphere, while my algorithm only grows it in one direction at a time. Also, my understanding is that Bouncing Bubble uses an approximation and may not contain all the points; however, there seems to be a tolerance parameter that you can control.</p> <p>I think my algorithm still has some nice properties:</p> <ol> <li>It's O(n).</li> <li>It's incremental.</li> <li>It's guaranteed to contain all the points.</li> <li>It's dead simple. The only thing simpler would be to find the axis-aligned bounding box, and then put a sphere around that, but that's surely going to be a larger volume than this algorithm produces.</li> </ol> <hr> <p>I came up with a O(n) incremental algorithm on my own, which from the description on Wikipedia I believe must be the Bouncing Bubble algorithm. I have no idea how close it comes to the minimally bounding circle. First I'll try to explain my reasoning behind the algorithm. It may help to draw this on paper.</p> <p>Imagine you have a bounding circle with some center <em>C</em> and radius <em>r</em>. You want to extend the circle to contain a new point <em>P</em>. You compute the distance <em>d</em> from <em>C</em> to <em>P</em> and find that it is greater than <em>r</em>, so it must be outside the circle. Now if you cast a ray from <em>P</em> through <em>C</em>, it exits the back of the circle at <em>A</em>.</p> <p>Now imagine you pin the circle down at <em>A</em> and then expand it along the ray back toward <em>P</em>. It will continue to contain all the previous points, and now it contains <em>P</em>. The diameter of this new circle is <em>r + d</em>, thus its radius is <em>r' = (r + d) / 2</em>. Walk along the ray from <em>P</em> to <em>A</em> by the distance of the new radius, and you're at the center of the new circle.</p> <p>Here's a sketch of the algorithm:</p> <ol> <li>Initialize the bounding sphere to be centered on the first point <em>C</em> with a radius <em>r</em> of 0.</li> <li>For each remaining point <em>P</em>: <ol> <li>If the distance <em>d</em> from <em>P</em> to <em>C</em> is <em>&lt;= r</em>, skip it.</li> <li>If <em>d > r</em>: <ol> <li>The new radius <em>r' = (r + d) / 2</em>.</li> <li>The new center <em>C' = P + r' (C - P) / d</em>.</li> </ol></li> </ol></li> </ol> <p>And here's some Objective-C code I wrote just today:</p> <pre><code>- (void)updateBoundingVolume { self.boundingSphereCenter = GLKVector3Make(0, 0, 0); self.boundingSphereRadius = 0; GLfloat* vertex = self.vertices; GLfloat* endV = vertex + 3 * self.vertNum; if (vertex &lt; endV) { // initialize to zero radius sphere centered on the first point self.boundingSphereCenter = GLKVector3Make(vertex[0], vertex[1], vertex[2]); vertex += 3; } while (vertex &lt; endV) { GLKVector3 p = GLKVector3Make(vertex[0], vertex[1], vertex[2]); vertex += 3; float d = GLKVector3Distance(self.boundingSphereCenter, p); if (d &lt;= self.boundingSphereRadius) { // already inside the sphere continue; } // length of line from other side of sphere through the center to the new point // divide by 2 for radius self.boundingSphereRadius = (self.boundingSphereRadius + d) / 2; // unit vector from new point to old center GLKVector3 u = GLKVector3DivideScalar(GLKVector3Subtract(self.boundingSphereCenter, p), d); // step back from the new point by the new radius to get the new center self.boundingSphereCenter = GLKVector3Add(p, GLKVector3MultiplyScalar(u, self.boundingSphereRadius)); } } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload