Skip to content

Instantly share code, notes, and snippets.

@lardratboy
Created January 31, 2025 05:35
Show Gist options
  • Save lardratboy/441f98a8f9aa484149c53eca90e97c87 to your computer and use it in GitHub Desktop.
Save lardratboy/441f98a8f9aa484149c53eca90e97c87 to your computer and use it in GitHub Desktop.
quick and dirty python->javascript version of repack.py
class Rect {
constructor(left, top, right, bottom) {
this.left = left;
this.top = top;
this.right = right;
this.bottom = bottom;
}
width() { return this.right - this.left; }
height() { return this.bottom - this.top; }
}
class Page {
constructor(width, height) {
this.width = width;
this.height = height;
this.free_rects = [new Rect(0, 0, width, height)];
this.occupied_rects = [];
}
static *external_clipped_rects(a, b) {
let top = a.top, bottom = a.bottom;
if (a.top < b.top) {
top = b.top;
yield new Rect(a.left, a.top, a.right, b.top);
}
if (a.bottom > b.bottom) {
bottom = b.bottom;
yield new Rect(a.left, b.bottom, a.right, a.bottom);
}
if (a.left < b.left) {
yield new Rect(a.left, top, b.left, bottom);
}
if (a.right > b.right) {
yield new Rect(b.right, top, a.right, b.bottom);
}
}
insert(width, height) {
for (let i = 0; i < this.free_rects.length; ++i) {
const free_rect = this.free_rects[i];
if (free_rect.width() < width || free_rect.height() < height) continue;
const rect = new Rect(free_rect.left, free_rect.top, free_rect.left + width, free_rect.top + height);
this.occupied_rects.push(rect);
this.free_rects.splice(i, 1); // Remove free_rect at index i
let free_count = this.free_rects.length;
for (const clipped_rect of Page.external_clipped_rects(free_rect, rect)) {
this.free_rects.push(clipped_rect);
}
if (free_count !== this.free_rects.length) {
this.free_rects.sort((x, y) => (x.height() - y.height()));
}
return rect;
}
return null;
}
calculate_efficency() {
const total_area = this.width * this.height;
let used_area = 0;
for (const rect of this.occupied_rects) {
used_area += rect.width() * rect.height();
}
return used_area / total_area;
}
}
class Packer {
constructor(width, height) {
this.pages = [new Page(width, height)];
this.page_width = width;
this.page_height = height;
}
insert(width, height) {
for (const page of this.pages) {
const rect = page.insert(width, height);
if (rect) return { page: page, rect: rect };
}
const new_page = new Page(this.page_width, this.page_height);
this.pages.push(new_page);
const rect = new_page.insert(width, height);
return { page: new_page, rect: rect };
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment