@mark1russell7/packing 0.2.2 → 0.2.4

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/src/skyline.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { countMove, MOVES } from "./moves.ts";
1
2
  import { compareRects, type SortOrder } from "./order.ts";
2
3
  import type { Rect } from "./rect.ts";
3
4
  import type { FreeSpace } from "./space.ts";
@@ -11,6 +12,19 @@ import type { FreeSpace } from "./space.ts";
11
12
  * `limit[x, x + rw)`. A second deque keeps that smallest value. No valid window gives the height `Infinity`.
12
13
  */
13
14
  export function lowestWindow(skyline: ArrayLike<number>, width: number, rw: number, limit?: ArrayLike<number>, rh = 0): { x: number; y: number } {
15
+ const { x, y } = findWindow(skyline, width, rw, limit, rh);
16
+ return { x, y };
17
+ }
18
+
19
+ /** The lowest window of `findWindow`, and `first`: the x of the leftmost valid window, or `-1` */
20
+ interface Window {
21
+ x: number;
22
+ y: number;
23
+ first: number;
24
+ }
25
+
26
+ /** This function is `lowestWindow`, and it also gives the x of the leftmost valid window. */
27
+ function findWindow(skyline: ArrayLike<number>, width: number, rw: number, limit?: ArrayLike<number>, rh = 0): Window {
14
28
  if (limit !== undefined) return lowestLimitedWindow(skyline, limit, width, rw, rh);
15
29
  const deque = new Int32Array(width);
16
30
  let head = 0;
@@ -29,11 +43,16 @@ export function lowestWindow(skyline: ArrayLike<number>, width: number, rw: numb
29
43
  }
30
44
  }
31
45
  }
32
- return { x: bestX, y: bestY };
46
+ return { x: bestX, y: bestY, first: width >= rw ? 0 : -1 };
47
+ }
48
+
49
+ /** This function counts the move of the skyline: a window that is lower than the leftmost valid window. */
50
+ function countWindow(w: Window): void {
51
+ if (Number.isFinite(w.y) && w.first >= 0 && w.x !== w.first) countMove(MOVES.skyline);
33
52
  }
34
53
 
35
54
  /** This function is `lowestWindow` with a limit for each cell. */
36
- function lowestLimitedWindow(skyline: ArrayLike<number>, limit: ArrayLike<number>, width: number, rw: number, rh: number): { x: number; y: number } {
55
+ function lowestLimitedWindow(skyline: ArrayLike<number>, limit: ArrayLike<number>, width: number, rw: number, rh: number): Window {
37
56
  const high = new Int32Array(width);
38
57
  const low = new Int32Array(width);
39
58
  let hh = 0;
@@ -42,6 +61,7 @@ function lowestLimitedWindow(skyline: ArrayLike<number>, limit: ArrayLike<number
42
61
  let lt = 0;
43
62
  let bestX = 0;
44
63
  let bestY = Infinity;
64
+ let first = -1;
45
65
  for (let i = 0; i < width; i++) {
46
66
  while (ht > hh && skyline[high[ht - 1]!]! <= skyline[i]!) ht--;
47
67
  high[ht++] = i;
@@ -51,13 +71,15 @@ function lowestLimitedWindow(skyline: ArrayLike<number>, limit: ArrayLike<number
51
71
  if (low[lh]! <= i - rw) lh++;
52
72
  if (i >= rw - 1) {
53
73
  const max = skyline[high[hh]!]!;
54
- if (max < bestY && max + rh <= limit[low[lh]!]!) {
74
+ const valid = max + rh <= limit[low[lh]!]!;
75
+ if (valid && first < 0) first = i - rw + 1;
76
+ if (max < bestY && valid) {
55
77
  bestY = max;
56
78
  bestX = i - rw + 1;
57
79
  }
58
80
  }
59
81
  }
60
- return { x: bestX, y: bestY };
82
+ return { x: bestX, y: bestY, first };
61
83
  }
62
84
 
63
85
  /** The options of `packSkyline` */
@@ -116,8 +138,10 @@ export function packSkyline<T>(rects: Rect<T>[], outer: Rect<T>, options: Skylin
116
138
  y = 0;
117
139
  for (let i = 0; i < width; i++) if (skyline[i]! > y) y = skyline[i]!;
118
140
  } else {
119
- ({ x, y } = lowestWindow(skyline, width, rw));
141
+ const found = findWindow(skyline, width, rw);
142
+ ({ x, y } = found);
120
143
  if (outer.fixedSize && y + rh > outer.size.y) continue;
144
+ countWindow(found);
121
145
  }
122
146
 
123
147
  rect.position.set(x + outer.position.x, y + outer.position.y);
@@ -179,7 +203,8 @@ function packSkylineInSpace<T>(rects: Rect<T>[], outer: Rect<T>, order: SortOrde
179
203
  outer.size.y = Math.max(outer.size.y, y + rh);
180
204
  continue;
181
205
  }
182
- ({ x, y } = lowestWindow(skyline, width, rw, limit, rh));
206
+ let found = findWindow(skyline, width, rw, limit, rh);
207
+ ({ x, y } = found);
183
208
  let sky: Float64Array = skyline;
184
209
  let lim: Float64Array = limit;
185
210
  if (!Number.isFinite(y)) {
@@ -189,10 +214,12 @@ function packSkylineInSpace<T>(rects: Rect<T>[], outer: Rect<T>, order: SortOrde
189
214
  for (let i = 0; i < width; i++) {
190
215
  while (Number.isFinite(lim[i]!) && lim[i]! - sky[i]! < rh && lim[i]! < end) [sky[i], lim[i]] = rangeOf(i, lim[i]!);
191
216
  }
192
- ({ x, y } = lowestWindow(sky, width, rw, lim, rh));
217
+ found = findWindow(sky, width, rw, lim, rh);
218
+ ({ x, y } = found);
193
219
  if (!Number.isFinite(y)) continue;
194
220
  }
195
221
 
222
+ countWindow(found);
196
223
  rect.position.set(x + ox, y + oy);
197
224
  rect.wasPacked = true;
198
225
  const top = y + rh;