Random points on a spherical cap

Updated on Fri, 19 Aug 2016 04:59:34 GMT, tagged with ‘math’—‘tech’.

tl;dr JavaScript library (npm, and Matlab function) to draw random samples from arbitrary spherical caps.

Interactive 3D scatterplot of samples from three spherical caps. [Screenshot](screenshot.png)

@Pedro77 posted their approach to generating random points on the surface of a sphere contained in a cone emanating from the middle of the sphere—a cone pointing in a specified direction and with a specified angular extent.

In other words, they wanted a way to randomly sample points from the spherical cap (Mathworld, Wikipedia) parameterized by

@Pedro77’s technique used rejection sampling (generating random points on the sphere’s surface until one was found that met the criteria).

I was able to cobble together an implementation of a deterministic algorithm (in 😭Matlab😭) using the insights from @joriki and @Jim Belk—see these to learn some surprising facts about the surface areas of cuts of cylinders and spheres (they’re the same!).

In order to more easily visualize samples from spherical caps, and to get a feel for scijs and modern JavaScript as exemplified by d3 4.0 (“D3 is written using ES2015 modules … create a custom bundle using Rollup…”), I put together an ES2015 package to generate points on such directed spherical caps, sphere-cap-random, which can run in the browser or in Node.

Here’s a taste of what that looks like (here’s the rest):

export default function sampleSphericalCap(params) {
  params = params == null ? {N : 1, z : 0} : params;

  const π = Math.PI;
  const π2 = 2 * π;
  const radPerDeg = π / 180;

  const minZ =
      (params.z ? +params.z
                : (params.deg ? Math.cos(+params.deg * radPerDeg)
                              : (params.rad ? Math.cos(+params.rad) : 0)));
  const N = params.N ? +params.N : 1;
  return pack(Array.from({length : N}, _ => {
           const z = Math.random() * (1 - minZ) + minZ;
           const r = Math.sqrt(1 - z * z);
           const θ = Math.random() * π2;
           const x = r * Math.cos(θ);
           const y = r * Math.sin(θ);
           return [ x, y, z ];
         })).transpose(1, 0);
}

(N.B. These days, i.e., May 2017, I have converged to using Node-style modules, Browserify, and Google Closure Compiler’s JavaScript port. Node modules and Browserify are dead-simple. Google Closure Compiler brings the heavy magic, with proper dead-code elimination and whole-program optimization—and is also dead-simple to use!)

The 3D scatter plot above, courtesy of plotly.js, shows random samples from three spherical caps:

(Banner image: Hubble Space Telescope image of Juputer, dated 2016 June 29, NASA Goddard Space Flight Center, Greenbelt, Maryland, USA. Official Flickr. Wikimedia.)

Previous: Measure your code, or, Replicating columns in Matlab
Next: Track planes with a USB dongle