hlfw.ca

binpack

Download patch

ref: 83c86df5da916e0547c75327416fab18f9ac870d
parent: b294da37854705e27144afc0653030ff31d72525
author: Halfwit <michaelmisch1985@gmail.com>
date: Wed Nov 9 17:44:29 PST 2016

Strange behavior on single window, but works for now

--- a/binpack.c
+++ b/binpack.c
@@ -71,23 +71,33 @@
 
 void
 scrub_bins(struct bins b[], size_t *bin_count) {
-    
-    for (unsigned i = 1; i < *bin_count; i++) {
+	if (*bin_count == 1)
+		return;
+		
+	for (unsigned i = 1; i < *bin_count; i++) {
 		if(b[i].w == 0 || b[i].h == 0)
+			continue;
+		for (unsigned j = 0; j < *bin_count - 1; j++) {
+			
+			/* Skip if same bin */
+			if (i == j)
 				continue;
-		for (unsigned j = 0; j < *bin_count -i; j++) {
-
-				if (b[j].w == 0 || b[j].h == 0 || i == j)
-						continue;
 				
-				if (b[j].y == b[i].y && b[j].h == b[i].h) {
-						b[i].h += b[j].h;
-						b[j].h = 0;
-						b[j].w = 0;
-						continue;
-				}
+			/* Same row */
+			if (b[j].y == b[i].y && b[j].h == b[i].h) {
+				b[j].w += b[i].w;
+				b[i].h = 0;
+				b[i].w = 0;
+			}
+			
+			/* Same column */
+			if (b[j].x == b[i].x && b[j].w == b[i].w) {
+				b[j].h += b[i].h;
+				b[i].h = 0;
+				b[i].w = 0;
+			}
 		}
-    }
+	}	
 }
 
 /* arrange rectangles largest to smallest */
@@ -119,7 +129,7 @@
 	h = bin[j].h;
 
 	/* rect smaller, make two sub bins */
-	if (out[i].h + mb.gaps < h && out[i].w + mb.gaps < w) {
+	if (out[i].h <= h && out[i].w <= w) {
 		bin[*bin_count] = (struct bins){x + out[i].w + mb.gaps, y, w - out[i].w - mb.gaps, h};
 		bin[j].y += (out[i].h + mb.gaps);
 		bin[j].h -= (out[i].h - mb.gaps);
@@ -127,13 +137,13 @@
 	}
 	
 	/* rect same height */
-	else if (out[i].h + mb.gaps < h) {
+	else if (out[i].h == h) {
 		bin[j].y += (out[i].h + mb.gaps);
 		bin[j].h -= (out[i].h - mb.gaps);
 	}
 
 	/* rect same width */
-	else if (out[i].w + mb.gaps < w) {
+	else if (out[i].w == w) {
 		bin[j].x += (out[i].w + mb.gaps);
 		bin[j].w -= (out[i].w - mb.gaps);
 	}
@@ -164,49 +174,81 @@
 	/* default bin */
 	bin[0] = (struct bins){ 0, 0, mb.x, mb.y};
 	size_t bin_count = 1;
-	bool rect_fits;
+	size_t packed = 0;
 
 	/* loop through each rect */
 	for (size_t i = 0; i < length; i++) {
-		rect_fits = false;
 
 		/* loop through each bin */
 		for (size_t j = 0; j < bin_count; j++) {
 			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;
+				packed++;
 				save_rect(bin, out, r, i, j, mb);
 				create_bins(bin, out, i, j, &bin_count, mb);
-				sort_bins(bin, &bin_count);
 				scrub_bins(bin, &bin_count);
+				sort_bins(bin, &bin_count);
 				break;
 			}
 		}
-		if (rect_fits == false)
-			return true;
 	}
+	if (packed == length) {
+		return true;
+	}
 	return false;
 }
 
 bool
-resize(const size_t length, struct output out[], struct mbin mb, struct input r[])
+resizewidth(const size_t length, struct output out[], struct mbin mb, struct input r[])
 {
-	size_t packed_bin = 0;
+	size_t packed = 0;
 	for (size_t i = 0; i < length; i++) {
 
 		/* 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++;
+		if (r[i].max_w - r[i].min_w < 2) {
+			packed++;
 			continue;
 		}
+		
+		/* In case something goes wonky */
+		if (r[i].min_w > r[i].max_w) {
+			r[i].max_w = r[i].min_w;
+			r[i].min_w--;
+		}
 
 		/* 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) {
+		if(pack_bin(length, out, mb, r)) {
 			r[i].min_w = (r[i].min_w + r[i].max_w) / 2;
 		} else {
 			r[i].max_w = (r[i].min_w + r[i].max_w) / 2;
 		}
+	}
 
-		if(pack_bin(length, out, mb, r) && r[i].max_h - r[i].min_h > 1) {
+	if (packed == length) {
+		return false;
+	}
+	return true;
+}
+bool
+resizeheight(const size_t length, struct output out[], struct mbin mb, struct input r[])
+{
+	size_t packed_bin = 0;
+	for (size_t i = 0; i < length; i++) {
+
+		/* If we're within 1, bin is fully packed */
+		if (r[i].max_h - r[i].min_h < 2) {
+			packed_bin++;
+			continue;
+		}
+		
+
+		/* In case something goes wonky */
+		if (r[i].min_h > r[i].max_h) {
+			r[i].max_w = r[i].min_w;
+			r[i].min_w--;
+		}
+		
+		/* if binpack succeeds, we can grow --> set min as current, else set max as current */
+		if(pack_bin(length, out, mb, r)) {
 			r[i].min_h = (r[i].min_h + r[i].max_h) / 2;
 		} else {
 			r[i].max_h = (r[i].min_h + r[i].max_h) / 2;
@@ -213,12 +255,12 @@
 		}
 	}
 
-	if (packed_bin == length)
+	if (packed_bin == length) {
 		return false;
+	}
 	return true;
 }
 
-
 int
 main(int argc, char *argv[])
 {
@@ -253,13 +295,12 @@
 		return EXIT_SUCCESS;
 	}
 
-	/* If bin area is more than available area, exit */
 	sort_input(r, length);
 
 	/* Initial pack to establish out bins */
 	pack_bin(length, out, mb, r);
 
-	while(resize(length, out, mb, r));
+	while(resizeheight(length, out, mb, r) && resizewidth(length, out, mb, r));
 
 	unsigned area = 0;
 	for (size_t i = 0; i < length; i++) {