hlfw.ca

binpack

Download patch

ref: 0ba3b3ea5128ab3d28b5951b1abfa5b4336079dc
parent: 671771e4799498d22262f134274e804461a90e40
author: Halfwit <michaelmisch1985@gmail.com>
date: Mon Nov 7 02:53:38 PST 2016

initial refactoring to new algorithm, but there is an issue with growing - not stable

--- a/binpack.c
+++ b/binpack.c
@@ -25,7 +25,7 @@
 	unsigned x, y, w, h;
 };
 
-size_t 
+size_t
 create_rect(struct input r[]) {
 	size_t length = 0;
 	char line[50] = "";
@@ -38,7 +38,7 @@
 }
 
 /* (max bin size - blob size) / 2 */
-void 
+void
 center(const size_t length, struct output r[], struct mbin mb) {
 	unsigned w = 0, h = 0;
 	for (size_t i = 0; i < length; i++) {
@@ -60,6 +60,19 @@
 
 	for (unsigned i = 1; i < *bin_count; i++) {
 		for (unsigned j = 0; j < *bin_count - i; j++) {
+			/* If two bins can be logically made in to one bin, do so */
+			if (b[j + 1].x == b[j].x + b[j].w && b[j + 1].y == b[j].y && b[j].h == b[j].h) {
+				b[j].w += b[j + 1].w;
+				b[j + 1].h = 0;
+				b[j + 1].w = 0;
+				continue;
+			}
+			if (b[j + 1].y == b[j].y + b[j].h && b[j + 1].x == b[j].x && b[j + 1].w == b[j].w) {
+				b[j].h += b[j + 1].h;
+				b[j + 1].h = 0;
+				b[j + 1].w = 0;
+				continue;
+			}
 			if ((b[j + 1].w * b[j + 1].h) > (b[j].w * b[j].h)) {
 				temp = b[j];
 				b[j] = b[j + 1];
@@ -123,7 +136,7 @@
 	}
 }
 
-void 
+void
 save_rect(struct bins bin[], struct output out[], struct input r[], size_t i, size_t j, struct mbin mb)
 {
 	/* Store rect x y w h wid */
@@ -130,9 +143,8 @@
 	out[i] = (struct output){bin[j].x + (mb.gaps / 2), bin[j].y + (mb.gaps / 2), r[i].min_w, r[i].min_h, r[i].wid};
 }
 
-/* Main algorithm */
-bool 
-pack_bin(struct output out[], struct input r[], const size_t length, unsigned *bin_width, unsigned *bin_height, struct mbin mb)
+bool
+pack_bin(const size_t length, struct output out[], struct mbin mb, struct input r[])
 {
 	/* initialize bins */
 	struct bins bin[100];
@@ -141,7 +153,7 @@
 	}
 
 	/* default bin */
-	bin[0] = (struct bins){ 0, 0, *bin_width + mb.gaps, *bin_height + mb.gaps};
+	bin[0] = (struct bins){ 0, 0, mb.x, mb.y};
 	size_t bin_count = 1;
 	bool rect_fits;
 
@@ -151,8 +163,7 @@
 
 		/* loop through each bin */
 		for (size_t j = 0; j < bin_count; j++) {
-			/* rect fits in current bin */
-			if (r[i].min_w + mb.gaps <= bin[j].w && r[i].min_h + mb.gaps <= bin[j].h) {
+			if ((r[i].min_w + r[i].max_w) / 2 <= bin[j].w && (r[i].min_h + r[i].max_h) / 2 <= bin[j].h) {
 				rect_fits = true;
 				save_rect(bin, out, r, i, j, mb);
 				create_bins(bin, out, i, j, &bin_count, mb);
@@ -161,45 +172,43 @@
 			}
 		}
 		if (rect_fits == false)
-		return true;
+			return true;
 	}
 	return false;
 }
 
 bool
-resize(struct output out[], struct input r[], const size_t length, unsigned *bin_width, unsigned *bin_height, struct mbin mb, size_t index)
+resize(const size_t length, struct output out[], struct mbin mb, struct input r[])
 {
-	for (size_t i = index; i < length; i++) {
-		unsigned limitcheck = 0;
+	size_t packed_bin = 0;
+	for (size_t i = 0; i < length; i++) {
 
-		while (pack_bin(out, r, length, bin_width, bin_height, mb)) {
-			if (limitcheck == mb.x)
-				return false;
-			limitcheck++;
+		/* If we're within 1, bin is fully packed */
+		if (r[i].max_h - r[i].min_h < 2 && r[i].max_w - r[i].min_w < 2) {
+			packed_bin++;
+			continue;
 		}
 
-		/* If rect can grow */
-		if (out[i].h < r[i].max_h)
-			r[i].min_h += 1;
-		if (out[i].w < r[i].max_w)
-			r[i].min_w += 1;
+		/* if binpack succeeds, we can grow --> set min as current, else set max as current */
+		if(pack_bin(length, out, mb, r) && r[i].max_w - r[i].min_w > 1) {
+			r[i].max_w = (r[i].min_w + r[i].max_w) / 2;
+		} else {
+			r[i].min_w = (r[i].min_w + r[i].max_w) / 2;
+		}
 
-		sort_input(r, length);
+		if(pack_bin(length, out, mb, r) && r[i].max_h - r[i].min_h > 1) {
+			r[i].max_h = (r[i].min_h + r[i].max_h) / 2;
+		} else{
+			r[i].min_h = (r[i].min_h + r[i].max_h) / 2;
+		}
 	}
 
-	/* max_h to handle cases of smaller windows */
-	unsigned w = 0, h = 0;
-
-	for (size_t i = index; i < length; i++) {
-		if (w < (out[i].w + out[i].x))
-			w = out[i].w + out[i].x + mb.gaps;
-		if (h < (out[i].h + out[i].y))
-			h = out[i].h + out[i].y + mb.gaps;
-	}
-
-	return ((h < mb.y + (mb.gaps / 2)) && (w < mb.x + (mb.gaps / 2)));
+	if (packed_bin == length)
+		return false;
+	return true;
 }
 
+
 int
 main(int argc, char *argv[])
 {
@@ -240,55 +249,16 @@
 
 	sort_input(r, length);
 
-	unsigned bin_width = mb.x;
-	unsigned bin_height = mb.y;
-	/* TODO: We're going to instead use a binary search approach
-	* to find a size for each bin, so the large windows optimization
-	* can be omitted 
-	*/
-	/* Test if we can use maximums on all windows */
-	bool no_large_windows = true;
-	for (size_t i = 0; i < length; i++) {
-		struct input temp = r[i];
-		r[i].min_w = r[i].max_w;
-		r[i].min_h = r[i].max_h;
+	/* Initial pack to establish out bins */
+	pack_bin(length, out, mb, r);
 
-		if (pack_bin(out, r, length, &bin_width, &bin_height, mb)) {
-			r[i] = temp;
-			no_large_windows = false;
-		}
-	}
+	while(resize(length, out, mb, r));
 
-	unsigned limitcheck = 0;
-
-	if (no_large_windows == false) {
-		bin_width = r[0].min_w;
-		bin_height = r[0].min_h;
-
-	while (pack_bin(out, r, length, &bin_width, &bin_height, mb)) {
-		/* if we've ran this long, something is up */
-		if (limitcheck == mb.x)
-			return EXIT_FAILURE;
-
-		limitcheck++;
-	}
-
-	limitcheck = 0;
-	for (size_t i = 0; i < length; i++) {
-		/* Square out the blob as best as we can */
-		while (resize(out, r, length, &bin_width, &bin_height, mb, i)) {
-			if (limitcheck == mb.x)
-				return EXIT_FAILURE;
-			limitcheck++;
-			}
-		}
-	}
-
 	center(length, out, mb);
 
 	for (size_t i = 0; i < length; i++) {
 		printf("%d %d %d %d %lx\n", out[i].x, out[i].y, out[i].w, out[i].h, out[i].wid);
 	}
-	
+
 	return EXIT_SUCCESS;
 }