Home

Awesome

pack-spheres

Brute force circle/sphere packing in 2D or 3D.

<img src="https://raw.githubusercontent.com/mattdesl/pack-spheres/master/demos/2d.png" width="20%" /><img src="https://raw.githubusercontent.com/mattdesl/pack-spheres/master/demos/2d-circle.png" width="20%" /><img src="https://raw.githubusercontent.com/mattdesl/pack-spheres/master/demos/3d.png" width="20%" />

See ./demos for examples.

const pack = require('pack-spheres');

const circles = pack({
  dimensions: 2,
  packAttempts: 500,
  maxCount: 1000,
  minRadius: 0.05,
  maxRadius: 0.5,
  padding: 0.0025
});

console.log('Got %d circles', circles.length);
console.log(circles[0].position, circles[0].radius);

Returns an array of objects with normalized values between -1.0 and 1.0, but the algorithm works on arbitrary units (for example, you could use pixels instead).

[ 
  {
    position: [ x, y, z ],
    radius: Number
  },
  ...
]

If you specify { dimensions: 2 }, the position will only contain [ x, y ].

The algorithm is roughly based on Tim Holman's Circle Packing tutorial, thanks Tim!

Install

Use npm to install.

npm install pack-spheres --save

Usage

spheres = pack([opt])

Packs 3D spheres (default) or 2D circles with the given options:

Override Functions

You can pass in override functions to change the behaviour:

// Some utility for randomness
const Random = require('canvas-sketch-util/random');

// Generate circles in a 2D unit circle
const bounds = 1;
const shapes = pack({
  bounds,
  // Generate a random point inside a 2D circle
  sample: () => Random.insideCircle(bounds),
  // See if mag(pos - center) >= bounds
  outside: (position, radius) => {
    const length = Math.sqrt(
      position[0] * position[0] + position[1] * position[1]
    );
    return length + radius >= bounds;
  }
});

Generator Functions

Instead of having all spheres start with, say, a fixed minRadius, you can pass a function that will get used for each new sphere being placed:

// Some utility for randomness
const Random = require('canvas-sketch-util/random');

const spheres = pack({
  minRadius: () => Random.range(0, 0.5)
});

Credits

Thanks to Tim Holman for his Circle Packing tutorial which this code is roughly based on.

License

MIT, see LICENSE.md for details.