@mark1russell7/packing 0.2.2 → 0.2.3
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 +4 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +101 -16
- package/build/index.js.map +1 -1
- package/package.json +1 -1
- package/src/adapters.ts +7 -4
- package/src/free.ts +3 -0
- package/src/measures.ts +24 -3
- package/src/moves.ts +33 -0
- package/src/pack.ts +15 -3
- package/src/shelf.ts +3 -0
- package/src/skyline.ts +34 -7
package/build/index.d.ts
CHANGED
|
@@ -351,7 +351,7 @@ export declare function packingMetrics(rects: readonly Rect[], options?: Metrics
|
|
|
351
351
|
/** The family of a measure. Each family has a section in `docs/MEASURES.md`. */
|
|
352
352
|
type MeasureFamily = "density" | "aspect" | "order" | "raggedness" | "overflow" | "stability" | "determinism" | "speed";
|
|
353
353
|
/** The id of a measure of the packer. The ids are those of `docs/FORMAT.md`, and `highways` uses the same ids. */
|
|
354
|
-
type MeasureId = "pack.area" | "pack.fill" | "pack.whitespace" | "pack.aspect" | "pack.aspectError" | "pack.order.inversions" | "pack.order.breaks" | "pack.raggedness" | "pack.overflow" | "pack.overflow.rate" | "pack.overflow.area" | "pack.overflow.forced" | "pack.overflow.forcedArea" | "pack.overflow.excess" | "pack.stability.moved" | "pack.stability.mean" | "pack.stability.q95" | "pack.deterministic" | "pack.search.widths" | "pack.search.ms";
|
|
354
|
+
type MeasureId = "pack.area" | "pack.fill" | "pack.whitespace" | "pack.aspect" | "pack.aspectError" | "pack.order.inversions" | "pack.order.breaks" | "pack.raggedness" | "pack.overflow" | "pack.overflow.rate" | "pack.overflow.area" | "pack.overflow.forced" | "pack.overflow.forcedArea" | "pack.overflow.excess" | "pack.overflow.forcedAreaMin" | "pack.overflow.excessArea" | "pack.stability.moved" | "pack.stability.mean" | "pack.stability.q95" | "pack.deterministic" | "pack.search.widths" | "pack.search.ms";
|
|
355
355
|
/**
|
|
356
356
|
* The facts of one measure: its family, its unit, its direction and its range.
|
|
357
357
|
* It is `MeasureSpec` of the contract for a packer measure id, with a family.
|
|
@@ -389,6 +389,8 @@ interface LayoutMeasures {
|
|
|
389
389
|
"pack.overflow.forced": number;
|
|
390
390
|
"pack.overflow.forcedArea": number;
|
|
391
391
|
"pack.overflow.excess": number;
|
|
392
|
+
"pack.overflow.forcedAreaMin": number;
|
|
393
|
+
"pack.overflow.excessArea": number;
|
|
392
394
|
"pack.search.widths": number;
|
|
393
395
|
"pack.search.ms": number;
|
|
394
396
|
}
|
|
@@ -425,6 +427,7 @@ export declare const MEASURE_SPECS: Readonly<Record<MeasureId, MeasureSpec>>;
|
|
|
425
427
|
* - The time `pack.search.ms` comes from the trace. It is not part of the determinism rule.
|
|
426
428
|
* - The overflow measures count each id once. `pack.overflow.forced` is the lower bound of `overflowBound`.
|
|
427
429
|
* - `pack.overflow.excess` is the overflow less the forced overflow. A container with no fixed side gives 0 for both.
|
|
430
|
+
* - `pack.overflow.forcedAreaMin` is a lower bound of the overflow area. `pack.overflow.excessArea` is the overflow area above it.
|
|
428
431
|
*
|
|
429
432
|
* @example
|
|
430
433
|
* ```ts
|
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":["Item","Sides","ContractMeasureSpec","Direction","ContainerTest","PackHard","LayoutContainer","LayoutEdge","LayoutInput"],"sources":["../src/vector.ts","../src/rect.ts","../src/order.ts","../src/contract.ts","../src/space.ts","../src/pack.ts","../src/skyline.ts","../src/shelf.ts","../src/free.ts","../src/push.ts","../src/metrics.ts","../src/measures.ts","../src/strategy.ts","../src/adapters.ts","../src/convert.ts","../src/registry.ts","../src/check.ts","../src/layout-input.ts","../src/generators.ts","../src/corpus.ts"],"mappings":";;qBACa;;EAIX,YAAY,YAAO;;MAMf;MACA,EAAE;;MAEF;MACA,EAAE;;EAGN,IAAI,WAAW;;EAMf,MAAM,GAAG;;EAMT,IAAI,OAAO,SAAS;;EAKpB;;EAKA,SAAS;;EAKT,MAAM,KAAK,QAAQ,KAAK,SAAS;;SAQ1B,GAAG,iBAAiB;;SAKpB,IAAI,SAAS,WAAW;;SASxB,IAAI,SAAS,WAAW;;aASpB,YAAY;;;qBCxEZ,KAAK;;;EAKhB,KAAK;;EAEL;;EAEA;;EAEA;;;;;EAKA;;MAGI,YAAY;;MAEZ,QAAQ;;EAGZ;;EAEA;;EAGA,WAAW;;EAOX,YAAY,QAAQ;;EAMpB;;SAGO,OAAO,GAAG,OAAO,KAAK,OAAO,KAAK;;SAKlC,SAAS,GAAG,OAAO,KAAK,OAAO,KAAK;;SAKpC,YAAY,GAAG,OAAO,KAAK;;SAK3B,SAAS,GAAG,OAAO,KAAK;;SAKxB,UAAU,GAAG,OAAO,KAAK;;;;;;KC/DtB;;qBAGC,sBAAsB;;wBAGnB,aAAa,OAAO,aAAa,GAAG,GAAG,KAAK,IAAI,GAAG,KAAK;;wBCiBxD,SAAS,MAAM,KAAKA,oBAAkBC;;;;;;;wBAWtC,SAAS,MAAMD,SAAOA;;UC/BrB;WACN;WACA;;;UAIM;WACN;WACA;WACA;WACA;;;;;;;;;;;UAYM;;WAEN;;WAEA;;;;;WAKA;;EAET,KAAK,YAAY,aAAa;;;;;EAK9B,OAAO,YAAY,YAAY,gBAAgB;;EAE/C,KAAK,MAAM;;EAEX,KAAK,WAAW,WAAW,YAAY;;;;;EAKvC,MAAM,YAAY,YAAY;;;;;;wBAgUhB,UAAU,OAAO,YAAY;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":["Item","Sides","ContractMeasureSpec","Direction","ContainerTest","PackHard","LayoutContainer","LayoutEdge","LayoutInput"],"sources":["../src/vector.ts","../src/rect.ts","../src/order.ts","../src/contract.ts","../src/space.ts","../src/pack.ts","../src/skyline.ts","../src/shelf.ts","../src/free.ts","../src/push.ts","../src/metrics.ts","../src/measures.ts","../src/strategy.ts","../src/adapters.ts","../src/convert.ts","../src/registry.ts","../src/check.ts","../src/layout-input.ts","../src/generators.ts","../src/corpus.ts"],"mappings":"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"}
|
package/build/index.js
CHANGED
|
@@ -137,6 +137,32 @@ var Rect = class {
|
|
|
137
137
|
return rects.reduce((acc, r) => Math.max(acc, r.bottom()), 0);
|
|
138
138
|
}
|
|
139
139
|
};
|
|
140
|
+
// src/moves.ts
|
|
141
|
+
/** The id of the characteristic move of each strategy. The trace of each strategy has its id, also with the count 0. */
|
|
142
|
+
const MOVES = Object.freeze({
|
|
143
|
+
/** A rectangle that the gap fill of `packRow` places in a gap of a row: under a shorter neighbor, or at the row break. */
|
|
144
|
+
rows: "move.gapFill",
|
|
145
|
+
/** A rectangle that `packShelf` puts on an open shelf with a taller rectangle. The strip above it stays empty. */
|
|
146
|
+
shelf: "move.stack",
|
|
147
|
+
/** A rectangle that the skyline puts in a lower window, not in the leftmost window where it fits. */
|
|
148
|
+
skyline: "move.lowerWindow",
|
|
149
|
+
/** A rectangle that a push cascade moves. */
|
|
150
|
+
push: "move.cascade"
|
|
151
|
+
});
|
|
152
|
+
const counts = /* @__PURE__ */ new Map();
|
|
153
|
+
/** This function adds `n` to the count of a move. */
|
|
154
|
+
function countMove(id, n = 1) {
|
|
155
|
+
if (n > 0) counts.set(id, (counts.get(id) ?? 0) + n);
|
|
156
|
+
}
|
|
157
|
+
/** This function sets the count of a move to 0. Without an id, it sets each count to 0. */
|
|
158
|
+
function clearMoves(id) {
|
|
159
|
+
if (id === void 0) counts.clear();
|
|
160
|
+
else counts.delete(id);
|
|
161
|
+
}
|
|
162
|
+
/** This function gives the count of a move since the last `clearMoves`. */
|
|
163
|
+
function moveCount(id) {
|
|
164
|
+
return counts.get(id) ?? 0;
|
|
165
|
+
}
|
|
140
166
|
// src/order.ts
|
|
141
167
|
/** This constant lists each sort order. The first one is the default. */
|
|
142
168
|
const SORT_ORDERS = [
|
|
@@ -832,6 +858,7 @@ function packShelf(rects, outer, options = {}) {
|
|
|
832
858
|
x = firstFreeX(obstacles, 0, w, rowTop, rowTop + h);
|
|
833
859
|
}
|
|
834
860
|
if (outer.fixedSize && rowTop + h > outer.size.y) continue;
|
|
861
|
+
if (!rowEmpty && rowTop + h < rowBottom) countMove(MOVES.shelf);
|
|
835
862
|
rect.position.set(x + outer.position.x, rowTop + outer.position.y);
|
|
836
863
|
rect.wasPacked = true;
|
|
837
864
|
rowEmpty = false;
|
|
@@ -956,6 +983,14 @@ function packRowsInSpace(rects, outer, order, space) {
|
|
|
956
983
|
* `limit[x, x + rw)`. A second deque keeps that smallest value. No valid window gives the height `Infinity`.
|
|
957
984
|
*/
|
|
958
985
|
function lowestWindow(skyline, width, rw, limit, rh = 0) {
|
|
986
|
+
const { x, y } = findWindow(skyline, width, rw, limit, rh);
|
|
987
|
+
return {
|
|
988
|
+
x,
|
|
989
|
+
y
|
|
990
|
+
};
|
|
991
|
+
}
|
|
992
|
+
/** This function is `lowestWindow`, and it also gives the x of the leftmost valid window. */
|
|
993
|
+
function findWindow(skyline, width, rw, limit, rh = 0) {
|
|
959
994
|
if (limit !== void 0) return lowestLimitedWindow(skyline, limit, width, rw, rh);
|
|
960
995
|
const deque = new Int32Array(width);
|
|
961
996
|
let head = 0;
|
|
@@ -976,9 +1011,14 @@ function lowestWindow(skyline, width, rw, limit, rh = 0) {
|
|
|
976
1011
|
}
|
|
977
1012
|
return {
|
|
978
1013
|
x: bestX,
|
|
979
|
-
y: bestY
|
|
1014
|
+
y: bestY,
|
|
1015
|
+
first: width >= rw ? 0 : -1
|
|
980
1016
|
};
|
|
981
1017
|
}
|
|
1018
|
+
/** This function counts the move of the skyline: a window that is lower than the leftmost valid window. */
|
|
1019
|
+
function countWindow(w) {
|
|
1020
|
+
if (Number.isFinite(w.y) && w.first >= 0 && w.x !== w.first) countMove(MOVES.skyline);
|
|
1021
|
+
}
|
|
982
1022
|
/** This function is `lowestWindow` with a limit for each cell. */
|
|
983
1023
|
function lowestLimitedWindow(skyline, limit, width, rw, rh) {
|
|
984
1024
|
const high = new Int32Array(width);
|
|
@@ -989,6 +1029,7 @@ function lowestLimitedWindow(skyline, limit, width, rw, rh) {
|
|
|
989
1029
|
let lt = 0;
|
|
990
1030
|
let bestX = 0;
|
|
991
1031
|
let bestY = Infinity;
|
|
1032
|
+
let first = -1;
|
|
992
1033
|
for (let i = 0; i < width; i++) {
|
|
993
1034
|
while (ht > hh && skyline[high[ht - 1]] <= skyline[i]) ht--;
|
|
994
1035
|
high[ht++] = i;
|
|
@@ -998,7 +1039,9 @@ function lowestLimitedWindow(skyline, limit, width, rw, rh) {
|
|
|
998
1039
|
if (low[lh] <= i - rw) lh++;
|
|
999
1040
|
if (i >= rw - 1) {
|
|
1000
1041
|
const max = skyline[high[hh]];
|
|
1001
|
-
|
|
1042
|
+
const valid = max + rh <= limit[low[lh]];
|
|
1043
|
+
if (valid && first < 0) first = i - rw + 1;
|
|
1044
|
+
if (max < bestY && valid) {
|
|
1002
1045
|
bestY = max;
|
|
1003
1046
|
bestX = i - rw + 1;
|
|
1004
1047
|
}
|
|
@@ -1006,7 +1049,8 @@ function lowestLimitedWindow(skyline, limit, width, rw, rh) {
|
|
|
1006
1049
|
}
|
|
1007
1050
|
return {
|
|
1008
1051
|
x: bestX,
|
|
1009
|
-
y: bestY
|
|
1052
|
+
y: bestY,
|
|
1053
|
+
first
|
|
1010
1054
|
};
|
|
1011
1055
|
}
|
|
1012
1056
|
/**
|
|
@@ -1050,8 +1094,10 @@ function packSkyline(rects, outer, options = {}) {
|
|
|
1050
1094
|
y = 0;
|
|
1051
1095
|
for (let i = 0; i < width; i++) if (skyline[i] > y) y = skyline[i];
|
|
1052
1096
|
} else {
|
|
1053
|
-
|
|
1097
|
+
const found = findWindow(skyline, width, rw);
|
|
1098
|
+
({x, y} = found);
|
|
1054
1099
|
if (outer.fixedSize && y + rh > outer.size.y) continue;
|
|
1100
|
+
countWindow(found);
|
|
1055
1101
|
}
|
|
1056
1102
|
rect.position.set(x + outer.position.x, y + outer.position.y);
|
|
1057
1103
|
rect.wasPacked = true;
|
|
@@ -1104,16 +1150,19 @@ function packSkylineInSpace(rects, outer, order, space) {
|
|
|
1104
1150
|
outer.size.y = Math.max(outer.size.y, y + rh);
|
|
1105
1151
|
continue;
|
|
1106
1152
|
}
|
|
1107
|
-
|
|
1153
|
+
let found = findWindow(skyline, width, rw, limit, rh);
|
|
1154
|
+
({x, y} = found);
|
|
1108
1155
|
let sky = skyline;
|
|
1109
1156
|
let lim = limit;
|
|
1110
1157
|
if (!Number.isFinite(y)) {
|
|
1111
1158
|
sky = skyline.slice();
|
|
1112
1159
|
lim = limit.slice();
|
|
1113
1160
|
for (let i = 0; i < width; i++) while (Number.isFinite(lim[i]) && lim[i] - sky[i] < rh && lim[i] < end) [sky[i], lim[i]] = rangeOf(i, lim[i]);
|
|
1114
|
-
|
|
1161
|
+
found = findWindow(sky, width, rw, lim, rh);
|
|
1162
|
+
({x, y} = found);
|
|
1115
1163
|
if (!Number.isFinite(y)) continue;
|
|
1116
1164
|
}
|
|
1165
|
+
countWindow(found);
|
|
1117
1166
|
rect.position.set(x + ox, y + oy);
|
|
1118
1167
|
rect.wasPacked = true;
|
|
1119
1168
|
const top = y + rh;
|
|
@@ -1126,10 +1175,19 @@ function packSkylineInSpace(rects, outer, order, space) {
|
|
|
1126
1175
|
return outer;
|
|
1127
1176
|
}
|
|
1128
1177
|
// src/pack.ts
|
|
1178
|
+
/** The depth of the calls of `packInto`. Only the outer gap fill counts its rectangles as moves. */
|
|
1179
|
+
let fillDepth = 0;
|
|
1129
1180
|
function packInto(rects, region, offset, order) {
|
|
1130
1181
|
const unpacked = Rect.unpacked(rects);
|
|
1131
|
-
|
|
1132
|
-
|
|
1182
|
+
fillDepth++;
|
|
1183
|
+
try {
|
|
1184
|
+
pack(unpacked, region, { sortOrder: order });
|
|
1185
|
+
} finally {
|
|
1186
|
+
fillDepth--;
|
|
1187
|
+
}
|
|
1188
|
+
const placed = Rect.packed(unpacked);
|
|
1189
|
+
if (fillDepth === 0) countMove(MOVES.rows, placed.length);
|
|
1190
|
+
for (const r of placed) r.translateBy(offset);
|
|
1133
1191
|
}
|
|
1134
1192
|
function packRow(rects, outer, order) {
|
|
1135
1193
|
const row = [];
|
|
@@ -1187,7 +1245,7 @@ function packRows(rects, outer, options = {}) {
|
|
|
1187
1245
|
const space = options.space;
|
|
1188
1246
|
if (space !== void 0 && (!space.plain || rects.some((r) => r.locked))) return packRowsInSpace(rects, outer, order, space);
|
|
1189
1247
|
for (const r of rects) if (r.locked) r.wasPacked = true;
|
|
1190
|
-
while (!packRow(rects, outer, order));
|
|
1248
|
+
while (!packRow(rects, outer, order)) if (fillDepth === 0) clearMoves(MOVES.rows);
|
|
1191
1249
|
return outer;
|
|
1192
1250
|
}
|
|
1193
1251
|
/**
|
|
@@ -1264,6 +1322,7 @@ function packFree(rects, outer = new Rect(), options = {}) {
|
|
|
1264
1322
|
const maxWidth = Math.max(minWidth, rowWidth);
|
|
1265
1323
|
const tried = [];
|
|
1266
1324
|
const run = (width) => {
|
|
1325
|
+
clearMoves();
|
|
1267
1326
|
Rect.resetPacked(rects);
|
|
1268
1327
|
const box = new Rect();
|
|
1269
1328
|
box.position.setTo(outer.position);
|
|
@@ -1959,6 +2018,8 @@ const MEASURE_SPECS = Object.freeze({
|
|
|
1959
2018
|
"pack.overflow.forced": spec("pack.overflow.forced", "overflow", "count", "lower", 0, Infinity, 0),
|
|
1960
2019
|
"pack.overflow.forcedArea": spec("pack.overflow.forcedArea", "overflow", "share", "lower", 0, 1, .005),
|
|
1961
2020
|
"pack.overflow.excess": spec("pack.overflow.excess", "overflow", "count", "lower", 0, Infinity, 0),
|
|
2021
|
+
"pack.overflow.forcedAreaMin": spec("pack.overflow.forcedAreaMin", "overflow", "share", "lower", 0, 1, .005),
|
|
2022
|
+
"pack.overflow.excessArea": spec("pack.overflow.excessArea", "overflow", "share", "lower", 0, 1, .005),
|
|
1962
2023
|
"pack.stability.moved": spec("pack.stability.moved", "stability", "share", "lower", 0, 1, .02, {
|
|
1963
2024
|
floor: 0,
|
|
1964
2025
|
tol: .02
|
|
@@ -2064,6 +2125,7 @@ function traceSum(output, id) {
|
|
|
2064
2125
|
* - The time `pack.search.ms` comes from the trace. It is not part of the determinism rule.
|
|
2065
2126
|
* - The overflow measures count each id once. `pack.overflow.forced` is the lower bound of `overflowBound`.
|
|
2066
2127
|
* - `pack.overflow.excess` is the overflow less the forced overflow. A container with no fixed side gives 0 for both.
|
|
2128
|
+
* - `pack.overflow.forcedAreaMin` is a lower bound of the overflow area. `pack.overflow.excessArea` is the overflow area above it.
|
|
2067
2129
|
*
|
|
2068
2130
|
* @example
|
|
2069
2131
|
* ```ts
|
|
@@ -2107,6 +2169,8 @@ function measure(input, output, options = {}) {
|
|
|
2107
2169
|
if (unplaced.has(item.id)) unplacedArea += a;
|
|
2108
2170
|
}
|
|
2109
2171
|
const bound = overflowBound(input);
|
|
2172
|
+
const overflowArea = itemArea > 0 ? unplacedArea / itemArea : 0;
|
|
2173
|
+
const forcedAreaMin = itemArea > 0 ? Math.min(1, bound.area / itemArea) : 0;
|
|
2110
2174
|
return {
|
|
2111
2175
|
"pack.area": hullArea,
|
|
2112
2176
|
"pack.fill": fill,
|
|
@@ -2118,15 +2182,25 @@ function measure(input, output, options = {}) {
|
|
|
2118
2182
|
"pack.raggedness": hull.w > 0 ? spread / hull.w : 0,
|
|
2119
2183
|
"pack.overflow": unplaced.size,
|
|
2120
2184
|
"pack.overflow.rate": input.items.length > 0 ? unplaced.size / input.items.length : 0,
|
|
2121
|
-
"pack.overflow.area":
|
|
2185
|
+
"pack.overflow.area": overflowArea,
|
|
2122
2186
|
"pack.overflow.forced": bound.forced,
|
|
2123
|
-
"pack.overflow.forcedArea":
|
|
2187
|
+
"pack.overflow.forcedArea": forcedAreaMin,
|
|
2124
2188
|
"pack.overflow.excess": Math.max(0, unplaced.size - bound.forced),
|
|
2189
|
+
"pack.overflow.forcedAreaMin": forcedAreaMin,
|
|
2190
|
+
"pack.overflow.excessArea": excessAreaOf(overflowArea, forcedAreaMin),
|
|
2125
2191
|
"pack.search.widths": traceSum(output, "pack.search.widths"),
|
|
2126
2192
|
"pack.search.ms": traceSum(output, "pack.search.ms")
|
|
2127
2193
|
};
|
|
2128
2194
|
}
|
|
2129
2195
|
/**
|
|
2196
|
+
* This function gives the overflow area above its lower bound. A value from `-AREA_NOISE` to 0 becomes 0. A value below
|
|
2197
|
+
* `-AREA_NOISE` stays, because it shows a bug of the bound or of the packer.
|
|
2198
|
+
*/
|
|
2199
|
+
function excessAreaOf(overflowArea, forcedAreaMin) {
|
|
2200
|
+
const excess = overflowArea - forcedAreaMin;
|
|
2201
|
+
return excess < 0 && excess >= -1e-9 ? 0 : excess;
|
|
2202
|
+
}
|
|
2203
|
+
/**
|
|
2130
2204
|
* This function gives the stability measures of a change pair: the run on the base input and the run on the changed
|
|
2131
2205
|
* input. The items match by id. The values are not rounded.
|
|
2132
2206
|
*
|
|
@@ -2475,6 +2549,7 @@ function packFixedWidth(id, input, options) {
|
|
|
2475
2549
|
const start = now();
|
|
2476
2550
|
const frame = buildFrame(input);
|
|
2477
2551
|
const rects = rectsOf(frame);
|
|
2552
|
+
clearMoves();
|
|
2478
2553
|
if (frame.w > 0) pack(rects, outerOf(frame), {
|
|
2479
2554
|
strategy: id,
|
|
2480
2555
|
sortOrder: options.sortOrder,
|
|
@@ -2486,7 +2561,10 @@ function packFixedWidth(id, input, options) {
|
|
|
2486
2561
|
trace: [{
|
|
2487
2562
|
id,
|
|
2488
2563
|
ms: now() - start,
|
|
2489
|
-
measures: {
|
|
2564
|
+
measures: {
|
|
2565
|
+
"pack.overflow": output.overflow.length,
|
|
2566
|
+
[MOVES[id]]: moveCount(MOVES[id])
|
|
2567
|
+
}
|
|
2490
2568
|
}]
|
|
2491
2569
|
};
|
|
2492
2570
|
}
|
|
@@ -2592,7 +2670,10 @@ const logSweep = {
|
|
|
2592
2670
|
}, {
|
|
2593
2671
|
id,
|
|
2594
2672
|
ms: ms / runs,
|
|
2595
|
-
measures: {
|
|
2673
|
+
measures: {
|
|
2674
|
+
"pack.overflow": output.overflow.length,
|
|
2675
|
+
[MOVES[id]]: moveCount(MOVES[id])
|
|
2676
|
+
}
|
|
2596
2677
|
}]
|
|
2597
2678
|
};
|
|
2598
2679
|
}
|
|
@@ -2628,11 +2709,12 @@ function pushFixedWidth(input, options, previous) {
|
|
|
2628
2709
|
}
|
|
2629
2710
|
const inPlay = frame.entries.filter((e) => !pending.includes(e)).map((e) => e.rect);
|
|
2630
2711
|
const maxShoves = options.maxShovesPerItem * Math.max(1, inPlay.length);
|
|
2712
|
+
let cascaded = 0;
|
|
2631
2713
|
for (const e of positioned) {
|
|
2632
|
-
pushCascade(e.rect, inPlay, {
|
|
2714
|
+
cascaded += pushCascade(e.rect, inPlay, {
|
|
2633
2715
|
gap: 0,
|
|
2634
2716
|
maxShoves
|
|
2635
|
-
});
|
|
2717
|
+
}).length;
|
|
2636
2718
|
e.rect.locked = true;
|
|
2637
2719
|
}
|
|
2638
2720
|
const { bounds } = frame;
|
|
@@ -2674,7 +2756,10 @@ function pushFixedWidth(input, options, previous) {
|
|
|
2674
2756
|
trace: [{
|
|
2675
2757
|
id: "push",
|
|
2676
2758
|
ms: pushMs,
|
|
2677
|
-
measures: {
|
|
2759
|
+
measures: {
|
|
2760
|
+
"pack.push.moved": moved.length,
|
|
2761
|
+
[MOVES.push]: cascaded
|
|
2762
|
+
}
|
|
2678
2763
|
}, {
|
|
2679
2764
|
id: "skyline",
|
|
2680
2765
|
ms: now() - skylineStart,
|