static void findpack(struct pam * const imgs, unsigned int const imgCt, Coord ** const coordsP, unsigned int const quality, unsigned int const qfactor) { Coord * coords; /* malloc'ed array */ unsigned int minarea; unsigned int i; unsigned int rdiv; unsigned int cdiv; Rectangle * current; /* malloc'ed array */ unsigned int z; Coord c; MALLOCARRAY(coords, imgCt); if (!coords) pm_error("Out of memory allocating %u-element coords array", imgCt); z = UINT_MAX; /* initial value */ c.x = 0; c.y = 0; /* initial value */ if (quality > 1) { unsigned int realMinarea; for (realMinarea = i = 0; i < imgCt; ++i) realMinarea += imgs[i].height * imgs[i].width; minarea = realMinarea * qfactor / 100; } else minarea = UINT_MAX - 1; /* It's relatively easy to show that, if all the images * are multiples of a particular size, then a best * packing will always align the images on a grid of * that size. * * This speeds computation immensely. */ for (rdiv = imgs[0].height, i = 1; i < imgCt; ++i) rdiv = gcf(imgs[i].height, rdiv); for (cdiv = imgs[0].width, i = 1; i < imgCt; ++i) cdiv = gcf(imgs[i].width, cdiv); MALLOCARRAY(current, imgCt); for (i = 0; i < imgCt; ++i) { current[i].size.x = imgs[i].width; current[i].size.y = imgs[i].height; } recursefindpack(current, c, coords, minarea, &z, 0, imgCt, cdiv, rdiv, quality, qfactor); free(current); *coordsP = coords; }
static void recursefindpack(Rectangle * const current, Coord const currentsz, Coord * const best, unsigned int const minarea, unsigned int * const maxareaP, unsigned int const depth, unsigned int const n, unsigned int const xinc, unsigned int const yinc, unsigned int const quality, unsigned int const qfactor) { if (depth == n) { if (currentsz.x * currentsz.y < *maxareaP) { unsigned int i; for (i = 0; i < n; ++i) best[i] = current[i].ul; *maxareaP = currentsz.x * currentsz.y; } } else { unsigned int i; Rectangle * const newP = ¤t[depth]; for (i = 0; ; ++i) { for (newP->ul.x = 0, newP->ul.y = i * yinc; newP->ul.y <= i * yinc;) { Coord c; c.x = MAX(lr(*newP).x, currentsz.x); c.y = MAX(lr(*newP).y, currentsz.y); pm_message("current = (%u.%u, %u.%u) new = (%u.%u, %u.%u)", current[0].ul.x, current[0].size.x, current[0].ul.y, current[0].size.y, newP->ul.x, newP->size.x, newP->ul.y, newP->size.y); if (!collides(*newP, current, depth)) { pm_message("Depth %u: Doesn't collide at i=%u", depth,i); recursefindpack(current, c, best, minarea, maxareaP, depth + 1, n, xinc, yinc, quality, qfactor); if (*maxareaP <= minarea) return; } if (newP->ul.x == (i - 1) * xinc) newP->ul.y = 0; if (newP->ul.x < i * xinc) newP->ul.x += xinc; else newP->ul.y += yinc; } } } }
static void findpack(struct pam *imgs, int n, coord *coords) { int minarea; int i; int rdiv; int cdiv; int minx = -1; int miny = -1; coord *current; coord *set; int z = INT_MAX; coord c = { 0, 0 }; if (quality > 1) { for (minarea = i = 0; i < n; ++i) minarea += imgs[i].height * imgs[i].width, minx = imax(minx, imgs[i].width), miny = imax(miny, imgs[i].height); minarea = minarea * qfactor / 100; } else { minarea = INT_MAX - 1; } /* It's relatively easy to show that, if all the images * are multiples of a particular size, then a best * packing will always align the images on a grid of * that size. * * This speeds computation immensely. */ for (rdiv = imgs[0].height, i = 1; i < n; ++i) rdiv = gcd(imgs[i].height, rdiv); for (cdiv = imgs[0].width, i = 1; i < n; ++i) cdiv = gcd(imgs[i].width, cdiv); MALLOCARRAY(current, n); MALLOCARRAY(set, n); for (i = 0; i < n; ++i) set[i].x = imgs[i].width, set[i].y = imgs[i].height; recursefindpack(current, c, set, coords, minarea, &z, 0, n, cdiv, rdiv); }
static void recursefindpack(coord *current, coord currentsz, coord *set, coord *best, int minarea, int *maxarea, int depth, int n, int xinc, int yinc) { coord c; if (depth == n) { if (currentsz.x * currentsz.y < *maxarea) { memcpy(best, current, sizeof(coord) * n); *maxarea = currentsz.x * currentsz.y; } return; } for (current[depth].x = 0; imax(current[depth].x + set[depth].x, currentsz.x) * imax(currentsz.y, set[depth].y) < *maxarea; current[depth].x += xinc) { for (current[depth].y = 0; imax(current[depth].x + set[depth].x, currentsz.x) * imax(currentsz.y, current[depth].y + set[depth].y) < *maxarea; current[depth].y += yinc) { c.x = imax(current[depth].x + set[depth].x, currentsz.x); c.y = imax(current[depth].y + set[depth].y, currentsz.y); if (!checkcollision(current, set, ¤t[depth], &set[depth], depth)) { recursefindpack(current, c, set, best, minarea, maxarea, depth + 1, n, xinc, yinc); if (*maxarea <= minarea) return; } } } }