@giro3d/giro3d
Version:
A JS/WebGL framework for 3D geospatial data visualization
95 lines (82 loc) • 1.86 kB
text/typescript
/*
* Copyright (c) 2015-2018, IGN France.
* Copyright (c) 2018-2026, Giro3D team.
* SPDX-License-Identifier: MIT
*/
// original code from https://github.com/jakesgordon/bin-packing
// MIT License
export interface Node {
x: number;
y: number;
w: number;
h: number;
offset?: number;
right?: Node;
down?: Node;
used?: boolean;
}
export interface UsedNode extends Node {
used: true;
right: Node;
down: Node;
}
export interface Block {
w: number;
h: number;
fit: Node;
}
function findNode(root: Node, w: number, h: number): Node | null {
if (root.used === true) {
const used = root as UsedNode;
return findNode(used.right, w, h) || findNode(used.down, w, h);
}
if (w <= root.w && h <= root.h) {
return root;
}
return null;
}
function splitNode(node: Node, w: number, h: number): Node {
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,
};
return node;
}
// 2D Bin Packing algorithm (fit N random dimension blocks in a w * h rectangle) implementation
function fit(
blocks: Block[],
w: number,
h: number,
previousRoot: Node | null,
): {
maxX: number;
maxY: number;
} {
const root: Node = previousRoot || {
x: 0,
y: 0,
w,
h,
};
let maxX = 0;
let maxY = 0;
for (const block of blocks) {
const node = findNode(root, block.w, block.h);
if (node) {
block.fit = splitNode(node, block.w, block.h);
maxX = Math.max(maxX, node.x + block.w);
maxY = Math.max(maxY, node.y + block.h);
}
}
return { maxX, maxY };
}
export default fit;