2020-06-03 22:39:30 -04:00
|
|
|
/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
|
2017-04-18 22:22:29 -04:00
|
|
|
|
2017-04-18 17:09:33 -04:00
|
|
|
"use strict";
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* adapted from
|
|
|
|
|
* http://codeincomplete.com/posts/2011/5/7/bin_packing/
|
|
|
|
|
*/
|
|
|
|
|
|
2022-02-20 22:47:04 -05:00
|
|
|
gapp.register("kiri.pack", [], (root, exports) => {
|
2017-04-18 17:09:33 -04:00
|
|
|
|
2022-02-20 22:47:04 -05:00
|
|
|
const { kiri } = root;
|
2020-06-03 22:39:30 -04:00
|
|
|
|
2022-02-20 22:47:04 -05:00
|
|
|
class Packer {
|
2024-06-12 10:31:40 -07:00
|
|
|
constructor(w, h, spacing, opt = {}) {
|
2017-04-18 17:09:33 -04:00
|
|
|
this.root = { x: 0, y: 0, w: w, h: h };
|
|
|
|
|
this.max = { w: 0, h: 0 };
|
|
|
|
|
this.packed = false;
|
|
|
|
|
this.spacing = typeof(spacing) === 'number' ? spacing : 1;
|
2024-06-12 10:31:40 -07:00
|
|
|
this.opt = opt;
|
2017-04-18 17:09:33 -04:00
|
|
|
this.pad = this.spacing / 2;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-12 10:31:40 -07:00
|
|
|
// array of blocks/tiles with {w,h} properties
|
2022-02-20 22:47:04 -05:00
|
|
|
simple(blocks) {
|
2024-06-12 10:31:40 -07:00
|
|
|
let n = 0, block, x = 0, y = 0, mh = 0, maxx = 0, maxy = 0;
|
2024-06-11 20:18:09 -07:00
|
|
|
let spacing = blocks.length > 1 ? this.spacing : 0;
|
2022-02-20 22:47:04 -05:00
|
|
|
while (n < blocks.length) {
|
|
|
|
|
block = blocks[n++];
|
|
|
|
|
block.fit = { x, y };
|
|
|
|
|
this.max.w = Math.max(this.max.w, x + block.w);
|
|
|
|
|
this.max.h = Math.max(this.max.h, y + block.h);
|
2024-06-12 10:31:40 -07:00
|
|
|
maxx = Math.max(maxx, x);
|
|
|
|
|
maxy = Math.max(maxy, y);
|
2022-02-20 22:47:04 -05:00
|
|
|
mh = Math.max(mh, block.h);
|
2024-06-11 20:18:09 -07:00
|
|
|
x += block.w + spacing;
|
2022-02-20 22:47:04 -05:00
|
|
|
if (x > this.root.w) {
|
|
|
|
|
x = 0;
|
2024-06-12 10:31:40 -07:00
|
|
|
y = y + mh + spacing;
|
2022-02-20 22:47:04 -05:00
|
|
|
mh = 0;
|
2020-10-14 17:18:14 -04:00
|
|
|
}
|
2022-02-20 22:47:04 -05:00
|
|
|
if (y > this.root.h) {
|
|
|
|
|
return this;
|
2017-04-18 17:09:33 -04:00
|
|
|
}
|
2022-02-20 22:47:04 -05:00
|
|
|
}
|
2024-06-12 10:31:40 -07:00
|
|
|
if (this.opt.invx) {
|
|
|
|
|
for (let block of blocks) {
|
|
|
|
|
block.fit.x = maxx - block.fit.x;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (this.opt.invy) {
|
|
|
|
|
for (let block of blocks) {
|
|
|
|
|
block.fit.y = maxy - block.fit.y;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-02-20 22:47:04 -05:00
|
|
|
this.packed = true;
|
|
|
|
|
return this;
|
|
|
|
|
}
|
2017-04-18 17:09:33 -04:00
|
|
|
|
2022-02-20 22:47:04 -05:00
|
|
|
fit(blocks, simple) {
|
|
|
|
|
if (simple) {
|
|
|
|
|
return this.simple(blocks);
|
|
|
|
|
}
|
|
|
|
|
let n = 0, node, block, w, h;
|
2024-06-11 20:18:09 -07:00
|
|
|
let spacing = blocks.length > 1 ? this.spacing : 0;
|
2022-02-20 22:47:04 -05:00
|
|
|
while (n < blocks.length) {
|
|
|
|
|
block = blocks[n++];
|
2024-06-11 20:18:09 -07:00
|
|
|
w = block.w + spacing;
|
|
|
|
|
h = block.h + spacing;
|
2022-02-20 22:47:04 -05:00
|
|
|
if (node = this.findNode(this.root, w, h)) {
|
|
|
|
|
block.fit = this.splitNode(node, w, h);
|
2017-04-18 17:09:33 -04:00
|
|
|
} else {
|
2022-02-20 22:47:04 -05:00
|
|
|
return this;
|
2017-04-18 17:09:33 -04:00
|
|
|
}
|
2022-02-20 22:47:04 -05:00
|
|
|
}
|
|
|
|
|
this.packed = true;
|
|
|
|
|
return this;
|
|
|
|
|
}
|
2017-04-18 17:09:33 -04:00
|
|
|
|
2022-02-20 22:47:04 -05:00
|
|
|
findNode(root, w, h) {
|
|
|
|
|
if (root.used) {
|
|
|
|
|
return this.findNode(root.right, w, h) || this.findNode(root.down, w, h);
|
|
|
|
|
} else if (w <= root.w && h <= root.h) {
|
|
|
|
|
return root;
|
|
|
|
|
} else {
|
|
|
|
|
return null;
|
2017-04-18 17:09:33 -04:00
|
|
|
}
|
2022-02-20 22:47:04 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
splitNode(node, w, h) {
|
|
|
|
|
node.used = true;
|
|
|
|
|
node.down = { x: node.x, y: node.y + h, w: node.w, h: node.h - h };
|
|
|
|
|
node.right = { x: node.x + w, y: node.y, w: node.w - w, h: h };
|
|
|
|
|
this.max.w = Math.max(this.max.w, node.x + w);
|
|
|
|
|
this.max.h = Math.max(this.max.h, node.y + h);
|
|
|
|
|
return node;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
kiri.Pack = Packer;
|
2017-04-18 17:09:33 -04:00
|
|
|
|
2022-02-20 22:47:04 -05:00
|
|
|
});
|