@mark1russell7/packing 0.2.14 → 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/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.14",
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/index.ts CHANGED
@@ -79,7 +79,7 @@ export {
79
79
  type PushStrategyOptions,
80
80
  } from "./adapters.ts";
81
81
  export { fromRects, toRects } from "./convert.ts";
82
- export { aspectFitStrategy, composites, packWith, strategies, strategy, type AspectFitStrategyOptions } from "./registry.ts";
82
+ export { aspectFitStrategy, composites, DEFAULT_STRATEGY, packDefault, packWith, strategies, strategy, type AspectFitStrategyOptions } from "./registry.ts";
83
83
  export { ASPECT_FIT_FACTORS, ASPECT_FIT_LEVELS, ASPECT_FIT_STAGE, aspectFit, type AspectFitOptions } from "./aspect-fit.ts";
84
84
  export { hardBreaks, packPortfolio, PORTFOLIO_LEVELS, PORTFOLIO_STAGE, type PackPortfolioOptions, type PortfolioEntry } from "./portfolio.ts";
85
85
  export {
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>(rects: Rect<T>[], region: Rect<T>, offset: Vector, order: SortOrder): void {
44
- const unpacked = Rect.unpacked(rects);
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
- pack(unpacked, region, { sortOrder: order });
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>(rects: Rect<T>[], outer: Rect<T>, order: SortOrder): boolean {
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 byHeight) {
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(rects, outerLeft, outer.position, order);
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(rects);
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(rects, outerLeft, outer.position, order);
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
- for (const r of rects) if (r.locked) r.wasPacked = true;
125
- // A row that does not fit grows the height and starts again, thus the gap fills of the try before do not count
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
 
package/src/registry.ts CHANGED
@@ -72,3 +72,14 @@ export function packWith(id: string, input: PackInput, options?: unknown, seed =
72
72
  const merged: unknown = { ...(s.defaults as object), ...(options as object | undefined) };
73
73
  return s.pack(input, merged, createContext(seed));
74
74
  }
75
+
76
+ /**
77
+ * The id of the default strategy of an input: `select`. It passed two fresh-seed confirmations against `rows` (roadmap
78
+ * item k66). `pack` does not read it.
79
+ */
80
+ export const DEFAULT_STRATEGY = "select";
81
+
82
+ /** This function packs an input with `DEFAULT_STRATEGY` and its defaults. The default seed is 0. */
83
+ export function packDefault(input: PackInput, seed = 0): PackOutput {
84
+ return packWith(DEFAULT_STRATEGY, input, undefined, seed);
85
+ }