It finally took some time to answer this question, so here is my bin package code:
using:
binpack_rec bp_rec; bp_rec.genere_random(N,x0,x1,y0,y1); // genere N random rectangles with sizes (x0..x1),(y0..y1) bp_rec.binpack(x0,y0,xs,w,acc); // compute positions for rectangles where: x0,y0-page start, xs-page size, w-space between rectangles, acc-acuracy for same Y-size bp_rec.rec[0..(bp_rec.N-1)] ... rectangle access (members: x0,y0 is position and xs,ys is size)
OK, now the binpack algorithm explains:
prepare data
- sort rectangles in descending order of size Y (sort index to array
ix[] ) - find all rectangles with the same size Y (+/- acc)
- sort them in descending order of size X (sort the index to the
ix[] array) - and remember their start / end index in
ix[] ... to lin[].i0,lin[].i1 - also computes the cumulative width of these rectangles in
lin[].xs
use whole lines (red part of the image)
Search for all lin[] with greater width than line size. If it is found, fill it with a line and mark the used rectangles as used (also delete the used width) and go to the next line
try to fill the line break (not the whole page) (green part of the image)
calculate the minimum non-zero line division height and use it as a limit to fill the height and split the stack next to each other so that they fill the entire line. I am using div line/2 + line/4 + line/8 + line/16 ... = ~ line
snap all unused rectangles to page size (blue part of the image)
[Note]
This approach is far from optimal, and the code is not optimized, but still quite effective. For 450 boxes with linear randomness in size (0.5 .. 10.0) average ~2.8ms time is ~2.8ms , which I think. You can improve this by dividing and winning, not my linear division. Fill in all the rows, and then use the rest to recursively fill the areas.

Hope this helps ... if there is something obscure, comment on me ...
source share