There are great circle packing algorithms and descriptions out there. Here is a nice video by Daniel Shiffman and here is a nice example from the book Generative Design.

I wanted to do something similar, but for non-cicular and image-based shapes. This post describes the method I came up with. Before I got started, I search around for an existing solution. I was pointed toward a 2D shape collsion detection library that looks nice for rectangles, ellipses, and even 2D polygons - basically any shape you can draw in a canvas. @sabrleRaph also pointed me towards a neat solution for for polygon packing. But neither of these covered image-based shapes, so that wasn’t going to work. So here’s the solution I came up with. It runs a little slow and isn’t great for real-time results, but works well enough and is good for final images or GIFs. If you’re reading this, and know a better way, please let me know!

Step 1 - Get a png image (something with transparency)

I used a peeled banana as an example.

Step 2 - Create a temporary graphics layer and place first banana

For the first banana, pick a random x/y location and rotation and draw a small banana in the temporary graphics layer. Read the pixels of the banana using loadPixels() and by checking the alpha channel. If any of the non-transparent pixels (the pixels of the banana) are at the edges of canvas, save the location info. If they’re not, make the banana a little bigger (using scale()) and check repeat until a max size is reached or until the edges of the canvas are hit. Once the first banana position is selected, draw it on the canvas.

Step 3 - Read pixel data of drawn bananas and draw another banana

For the next bananas, do the same as step 2 (create temporary graphics layer, pick random position, draw banana), but this time instead of just checking if the border is intersected, also check if the banana overlaps with existing bananas. To do this, the pixel information of the drawn bananas on the canvas can be used (loadPixels(), check if pixel is not transparent, save that pixel location to array to be used for comaprison). Now repeat

Here are what these steps look like:

And here it is in action:


This was a brief overview. There were a lot of details I skipped over. There is a template of the code at OpenProcessing that may be more helpful.