bin-pack
Version:
A packing algorithm for 2D bin packing. Largely based on code and a blog post by Jake Gordon.
153 lines (127 loc) • 4.56 kB
JavaScript
var assert = require('assert');
var pack = require('../index.js');
function intersect(item1, item2) {
var item1vertices = [
{ x: item1.x, y: item1.y }, // Top left
{ x: item1.x + item1.width, y: item1.y }, // Top right
{ x: item1.x + item1.width, y: item1.y + item1.height }, // Bottom right
{ x: item1.x, y: item1.y + item1.h } // Bottom left
];
for (var i = 0; i < item1vertices.length; i++) {
var vertex = item1vertices[i];
if (item2.x < vertex.x && vertex.x < item2.x + item2.width) {
if (item2.y < vertex.y && vertex.y < item2.y + item2.height) {
return true;
}
}
}
return false;
}
function verifyResult(result, items) {
assert.ok(result != null, "Result is defined");
assert.ok(items != null, "Items is defined");
assert.ok('width' in result, "Result has a width");
assert.ok('height' in result, "Result has a height");
for (var i = 0; i < items.length; i++) {
var item = items[i];
assert.ok('x' in item, "Item " + i + " has an x coordinate");
assert.ok('y' in item, "Item " + i + " has a y coordinate");
assert.ok('width' in item, "Item " + i + " has a width");
assert.ok('height' in item, "Item " + i + " has a height");
assert.ok(item.x >= 0, "Item is within the box (left)");
assert.ok(item.y >= 0, "Item is within the box (top)");
assert.ok(item.x + item.width <= result.width, "Item is within the box (right)");
assert.ok(item.y + item.height <= result.height, "Item is within the box (bottom)");
for (var j = 0; j < items.length; j++) {
var otheritem = items[j];
assert.ok(!intersect(item, otheritem), "Item " + i + " does not intersect with item " + j);
}
}
}
describe('bin-pack with no options', function() {
it('packs properly (basic)', function() {
var bins = [
{ width: 10, height: 10 },
{ width: 10, height: 10 },
{ width: 10, height: 10 },
{ width: 10, height: 10 }
];
var result = pack(bins);
assert.ok('items' in result, "Result has items");
assert.equal(result.items.length, bins.length, "Result has same amount of items as the source");
verifyResult(result, result.items);
});
it('packs properly when items are passed in in the wrong order', function() {
var bins = [
{ width: 10, height: 10 },
{ width: 100, height: 100 },
{ width: 1000, height: 1000 }
];
var result = pack(bins);
assert.ok('items' in result, "Result has items");
assert.equal(result.items.length, bins.length, "Result has same amount of items as the source");
verifyResult(result, result.items);
});
it('packs properly when items are irregular', function() {
var bins = [
{ width: 10, height: 110 },
{ width: 100, height: 10 },
{ width: 20, height: 1 },
{ width: 4, height: 48 }
];
var result = pack(bins);
assert.ok('items' in result, "Result has items");
assert.equal(result.items.length, bins.length, "Result has same amount of items as the source");
verifyResult(result, result.items);
});
it('does not affect original items', function() {
var bins = [
{ width: 10, height: 10 },
{ width: 10, height: 10 },
{ width: 10, height: 10 },
{ width: 10, height: 10 }
];
var result = pack(bins);
assert.ok(!('x' in bins[0]), "Original bin does not have x property");
assert.ok(!('y' in bins[0]), "Original bin does not have y property");
});
});
describe('bin-pack with in place option', function() {
it('packs properly (basic)', function() {
var bins = [
{ width: 10, height: 10 },
{ width: 10, height: 10 },
{ width: 10, height: 10 },
{ width: 10, height: 10 }
];
var result = pack(bins, { inPlace: true });
assert.ok(!('items' in result), "Result does not have items");
verifyResult(result, bins);
});
it('affects original items', function() {
var bins = [
{ width: 10, height: 10 },
{ width: 10, height: 10 },
{ width: 10, height: 10 },
{ width: 10, height: 10 }
];
var result = pack(bins, { inPlace: true });
assert.ok('x' in bins[0], "Original bin has an x property");
assert.ok('y' in bins[0], "Original bin has a y property");
});
it('does not sort original items', function() {
var bin0 = { width: 10, height: 10 };
var bin1 = { width: 100, height: 100 };
var bin2 = { width: 1000, height: 1000 };
var bins = [
bin0,
bin1,
bin2
];
var result = pack(bins, { inPlace: true });
assert.ok(bins[0] === bin0, "Bin 0 is still in place 0");
assert.ok(bins[1] === bin1, "Bin 1 is still in place 1");
assert.ok(bins[2] === bin2, "Bin 2 is still in place 2");
verifyResult(result, bins);
});
});