@mark1russell7/packing 0.2.15 → 0.2.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/index.d.ts.map +1 -1
- package/build/index.js +17 -11
- package/build/index.js.map +1 -1
- package/package.json +1 -1
- package/src/pack.ts +22 -13
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package",
|
|
3
3
|
"name": "@mark1russell7/packing",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.16",
|
|
5
5
|
"description": "Rectangle packing: shelf, guillotine and skyline strategies, push cascades and measures of a layout.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"rectangle-packing",
|
package/src/pack.ts
CHANGED
|
@@ -40,11 +40,13 @@ export interface PackLayoutOptions extends PackOptions {
|
|
|
40
40
|
/** The depth of the calls of `packInto`. Only the outer gap fill counts its rectangles as moves. */
|
|
41
41
|
let fillDepth = 0;
|
|
42
42
|
|
|
43
|
-
function packInto<T>(
|
|
44
|
-
|
|
43
|
+
function packInto<T>(byOrder: Rect<T>[], region: Rect<T>, offset: Vector, order: SortOrder): void {
|
|
44
|
+
// A filter keeps the order of the sort, thus the region needs no sort again
|
|
45
|
+
const unpacked = Rect.unpacked(byOrder);
|
|
45
46
|
fillDepth++;
|
|
46
47
|
try {
|
|
47
|
-
|
|
48
|
+
// The region has a fixed size, thus `pack` only calls the row packing
|
|
49
|
+
packSortedRows(unpacked, region, order);
|
|
48
50
|
} finally {
|
|
49
51
|
fillDepth--;
|
|
50
52
|
}
|
|
@@ -53,17 +55,15 @@ function packInto<T>(rects: Rect<T>[], region: Rect<T>, offset: Vector, order: S
|
|
|
53
55
|
for (const r of placed) r.translateBy(offset);
|
|
54
56
|
}
|
|
55
57
|
|
|
56
|
-
function packRow<T>(
|
|
58
|
+
function packRow<T>(byOrder: Rect<T>[], outer: Rect<T>, order: SortOrder): boolean {
|
|
57
59
|
const row: Rect<T>[] = [];
|
|
58
|
-
// toSorted gives a sorted copy, thus the order of the array of the caller stays
|
|
59
|
-
const byHeight = rects.toSorted(compareRects(order));
|
|
60
60
|
// A gap fill puts a later rect before an earlier one, thus the order `input` fills no gaps
|
|
61
61
|
const fillGaps = order !== "input";
|
|
62
62
|
|
|
63
63
|
const rowRect = new Rect<T>();
|
|
64
64
|
rowRect.size.set(outer.size.x, 0);
|
|
65
65
|
|
|
66
|
-
for (const rect of
|
|
66
|
+
for (const rect of byOrder) {
|
|
67
67
|
if (rect.wasPacked) continue;
|
|
68
68
|
|
|
69
69
|
if (rect.size.x > rowRect.size.x) {
|
|
@@ -73,7 +73,7 @@ function packRow<T>(rects: Rect<T>[], outer: Rect<T>, order: SortOrder): boolean
|
|
|
73
73
|
outerLeft.position.setTo(rowRect.position);
|
|
74
74
|
outerLeft.size.set(outer.size.x - rowRect.position.x, rowRect.size.y);
|
|
75
75
|
outerLeft.fixedSize = true;
|
|
76
|
-
if (fillGaps) packInto(
|
|
76
|
+
if (fillGaps) packInto(byOrder, outerLeft, outer.position, order);
|
|
77
77
|
|
|
78
78
|
rowRect.position.set(0, rowRect.bottom());
|
|
79
79
|
rowRect.size.set(outer.size.x, 0);
|
|
@@ -84,7 +84,7 @@ function packRow<T>(rects: Rect<T>[], outer: Rect<T>, order: SortOrder): boolean
|
|
|
84
84
|
if (outer.fixedSize) continue;
|
|
85
85
|
outer.size.y += rect.size.y;
|
|
86
86
|
if (!outer.fixedWidth && !outer.size.x) outer.size.x = rect.size.x;
|
|
87
|
-
Rect.resetPacked(
|
|
87
|
+
Rect.resetPacked(byOrder);
|
|
88
88
|
return false;
|
|
89
89
|
}
|
|
90
90
|
|
|
@@ -103,12 +103,22 @@ function packRow<T>(rects: Rect<T>[], outer: Rect<T>, order: SortOrder): boolean
|
|
|
103
103
|
outerLeft.size.set(rectInRow.size.x, rowRect.size.y - rectInRow.size.y);
|
|
104
104
|
outerLeft.fixedWidth = true;
|
|
105
105
|
outerLeft.fixedSize = true;
|
|
106
|
-
packInto(
|
|
106
|
+
packInto(byOrder, outerLeft, outer.position, order);
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
109
|
return true;
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
+
/**
|
|
113
|
+
* This function packs rows of rectangles that are in the order `order` already. A stable sort orders by the key and then
|
|
114
|
+
* by the position in the input, and a filter keeps that order. Thus a gap fill gives the layout of a sort again.
|
|
115
|
+
*/
|
|
116
|
+
function packSortedRows<T>(byOrder: Rect<T>[], outer: Rect<T>, order: SortOrder): void {
|
|
117
|
+
for (const r of byOrder) if (r.locked) r.wasPacked = true;
|
|
118
|
+
// A row that does not fit grows the height and starts again, thus the gap fills of the try before do not count
|
|
119
|
+
while (!packRow(byOrder, outer, order)) if (fillDepth === 0) clearMoves(MOVES.rows);
|
|
120
|
+
}
|
|
121
|
+
|
|
112
122
|
/**
|
|
113
123
|
* This function packs rectangles into an outer rectangle of a given width with a guillotine row packing. It does
|
|
114
124
|
* not change the width. Without `fixedSize`, the height grows until all rectangles fit. A `locked` rectangle keeps
|
|
@@ -121,9 +131,8 @@ export function packRows<T>(rects: Rect<T>[], outer: Rect<T>, options: PackOptio
|
|
|
121
131
|
const order = options.sortOrder ?? "height-desc";
|
|
122
132
|
const space = options.space;
|
|
123
133
|
if (space !== undefined && (!space.plain || rects.some((r) => r.locked))) return packRowsInSpace(rects, outer, order, space);
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
while (!packRow(rects, outer, order)) if (fillDepth === 0) clearMoves(MOVES.rows);
|
|
134
|
+
// toSorted gives a sorted copy, thus the order of the array of the caller stays. The sort happens once for each call.
|
|
135
|
+
packSortedRows(rects.toSorted(compareRects(order)), outer, order);
|
|
127
136
|
return outer;
|
|
128
137
|
}
|
|
129
138
|
|