Skip to content

Commit 94b2b04

Browse files
Bugs in edgy rect placement in updateBinSize() (#56)
* fixes both bugs in #55 * Change default square option from true to false and remove outdated comment --------- Co-authored-by: Shen Yiming <soimy@163.com>
1 parent 1990f32 commit 94b2b04

2 files changed

Lines changed: 33 additions & 3 deletions

File tree

src/maxrects-bin.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export class MaxRectsBin<T extends IRectangle = Rectangle> extends Bin<T> {
1313
public options: IOption = {
1414
smart: true,
1515
pot: true,
16-
square: true,
16+
square: false,
1717
allowRotation: false,
1818
tag: false,
1919
exclusiveTag: true,
@@ -327,11 +327,19 @@ export class MaxRectsBin<T extends IRectangle = Rectangle> extends Bin<T> {
327327
if (this.stage.contain(node)) return false;
328328
let tmpWidth: number = Math.max(this.width, node.x + node.width - this.padding + this.border);
329329
let tmpHeight: number = Math.max(this.height, node.y + node.height - this.padding + this.border);
330+
let tmpFits: boolean = !(tmpWidth > this.maxWidth || tmpHeight > this.maxHeight);
330331
if (this.options.allowRotation) {
331332
// do extra test on rotated node whether it's a better choice
332333
const rotWidth: number = Math.max(this.width, node.x + node.height - this.padding + this.border);
333334
const rotHeight: number = Math.max(this.height, node.y + node.width - this.padding + this.border);
334-
if (rotWidth * rotHeight < tmpWidth * tmpHeight) {
335+
const rotFits: boolean = !(rotWidth > this.maxWidth || rotHeight > this.maxHeight);
336+
// only compare when both rects will fit into bin
337+
if (tmpFits && rotFits && rotWidth * rotHeight < tmpWidth * tmpHeight) {
338+
tmpWidth = rotWidth;
339+
tmpHeight = rotHeight;
340+
}
341+
// if rot fits and tmpFits not then do not compare area and set rot directly (some cases area of not rotated is smaller but will not fit)
342+
if (rotFits && !tmpFits) {
335343
tmpWidth = rotWidth;
336344
tmpHeight = rotHeight;
337345
}
@@ -343,7 +351,8 @@ export class MaxRectsBin<T extends IRectangle = Rectangle> extends Bin<T> {
343351
if (this.options.square) {
344352
tmpWidth = tmpHeight = Math.max(tmpWidth, tmpHeight);
345353
}
346-
if (tmpWidth > this.maxWidth + this.padding || tmpHeight > this.maxHeight + this.padding) {
354+
tmpFits = !(tmpWidth > this.maxWidth || tmpHeight > this.maxHeight);
355+
if (!tmpFits) {
347356
return false;
348357
}
349358
this.expandFreeRects(tmpWidth + this.padding, tmpHeight + this.padding);

test/maxrects-bin.spec.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,15 @@ describe("no padding", () => {
3333
expect(position.y).toBe(0);
3434
});
3535

36+
test("edge case: only rotated version fits and should be set", () => {
37+
const edgeCaseBin = new MaxRectsBin(256, 1024, 0, {allowRotation: true, pot: false});
38+
edgeCaseBin.add(260, 80);
39+
edgeCaseBin.add(260, 80);
40+
edgeCaseBin.add(260, 80);
41+
edgeCaseBin.add(260, 80);
42+
expect(edgeCaseBin.rects).toHaveLength(4);
43+
});
44+
3645
test("report/set bin dirty status", () => {
3746
bin.add(200, 100, {});
3847
expect(bin.dirty).toBe(true); // add element to bin will render bin dirty
@@ -219,6 +228,18 @@ describe("padding", () => {
219228
expect(bin.rects.length).toBe(1);
220229
});
221230

231+
test("edge case: multiple rects with slightly bigger size then maxWidth should be placed rotated", () => {
232+
const edgeCaseBin = new MaxRectsBin(256, 1024, padding, {allowRotation: true, pot: false, square: false, smart: true});
233+
edgeCaseBin.add(260, 80);
234+
edgeCaseBin.add(260, 80);
235+
edgeCaseBin.add(260, 80);
236+
edgeCaseBin.add(260, 80);
237+
238+
expect(edgeCaseBin.rects).toHaveLength(4);
239+
expect(edgeCaseBin.rects[3].rot).toBeTruthy();
240+
expect(edgeCaseBin.rects[3].width).toBe(80);
241+
});
242+
222243
test("monkey testing", () => {
223244
// bin = new MaxRectsBin(1024, 1024, 40);
224245
let rects = [];

0 commit comments

Comments
 (0)