@mark1russell7/packing 0.2.1 → 0.2.2

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 CHANGED
@@ -1,4 +1,4 @@
1
- import { DEFAULT_TOLERANCE, Direction, Direction as Direction$1, EPS, Item, Item as Item$1, LayoutContainer, LayoutContainer as LayoutContainer$1, LayoutEdge, LayoutEdge as LayoutEdge$1, LayoutGenerator, LayoutInput, LayoutInput as LayoutInput$1, Margin, MeasureSpec as MeasureSpec$1, Obstacle, PackHard, PackHard as PackHard$1, PackInput, PackOutput, Placement, Port, RECORD_EPS, Region, Side, Sides, Sides as Sides$1, StageTrace, Tolerance, checkInput, turnPoint, turnPort, turnRegion } from "@mark1russell7/layout-contract";
1
+ import { ContainerTest, ContainerTest as ContainerTest$1, DEFAULT_TOLERANCE, Direction, Direction as Direction$1, EPS, Item, Item as Item$1, LayoutContainer, LayoutContainer as LayoutContainer$1, LayoutEdge, LayoutEdge as LayoutEdge$1, LayoutGenerator, LayoutInput, LayoutInput as LayoutInput$1, Margin, MeasureSpec as MeasureSpec$1, Obstacle, PackHard, PackHard as PackHard$1, PackInput, PackOutput, Placement, Port, RECORD_EPS, Region, Side, Sides, Sides as Sides$1, StageTrace, Tolerance, checkInput, turnPoint, turnPort, turnRegion } from "@mark1russell7/layout-contract";
2
2
  /** A mutable two-dimensional vector. */
3
3
  export declare class Vector {
4
4
  #private;
@@ -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.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.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.
@@ -384,6 +384,11 @@ interface LayoutMeasures {
384
384
  "pack.order.breaks": number;
385
385
  "pack.raggedness": number;
386
386
  "pack.overflow": number;
387
+ "pack.overflow.rate": number;
388
+ "pack.overflow.area": number;
389
+ "pack.overflow.forced": number;
390
+ "pack.overflow.forcedArea": number;
391
+ "pack.overflow.excess": number;
387
392
  "pack.search.widths": number;
388
393
  "pack.search.ms": number;
389
394
  }
@@ -403,7 +408,12 @@ interface MeasureOptions {
403
408
  }
404
409
  /**
405
410
  * The facts of each measure, by id. `docs/MEASURES.md` gives the full definitions. This record is the source of the floor
406
- * and the tolerance of each guard of the packer.
411
+ * and the tolerance of each guard of the packer, and of the minimum effect of each measure.
412
+ *
413
+ * - A count and a share of counts have the minimum effect 0. Thus each change of a count is an effect.
414
+ * - A share of an area from 0 to 1 has 0.005. A guard has its tolerance.
415
+ * - An area and a ratio of lengths have `{ rel: 0.01 }`: 1% of the larger value.
416
+ * - The time has no minimum effect, because the times of CI change each time.
407
417
  */
408
418
  export declare const MEASURE_SPECS: Readonly<Record<MeasureId, MeasureSpec>>;
409
419
  /**
@@ -413,6 +423,8 @@ export declare const MEASURE_SPECS: Readonly<Record<MeasureId, MeasureSpec>>;
413
423
  * - The boxes are the placed items with a width and a height above 0. The hull is the smallest rectangle around them.
414
424
  * - An empty layout gives the area 0, the aspect 1 and the aspect error 0. Its fill is 0 and its whitespace is 1.
415
425
  * - The time `pack.search.ms` comes from the trace. It is not part of the determinism rule.
426
+ * - The overflow measures count each id once. `pack.overflow.forced` is the lower bound of `overflowBound`.
427
+ * - `pack.overflow.excess` is the overflow less the forced overflow. A container with no fixed side gives 0 for both.
416
428
  *
417
429
  * @example
418
430
  * ```ts
@@ -644,8 +656,12 @@ export declare function packWith(id: string, input: PackInput, options?: unknown
644
656
  * The test of an obstacle is exact: a circle, an ellipse and a polygon with holes count only their insides, as in `packHard`.
645
657
  * The rules read a shape of the container or of an item as its bounding box (decision 5). The bounding box of an item
646
658
  * shape is relative to the position of the item. The result has no tolerance in it.
659
+ *
660
+ * With `options.exactContainer`, a shaped container with the size `fixed` also uses its true outline for `in-container`.
661
+ * A box then counts when `rectInRegion` of the contract tells that it is not in the shape, as in `packHard`.
662
+ * For that test, the box grows by the inset and becomes smaller by `tolerance.overlap` on each side. The default is `false`.
647
663
  */
648
- export declare function checkHard(input: PackInput, output: PackOutput, tolerance?: Pick<Tolerance, "overlap">): PackHard$1;
664
+ export declare function checkHard(input: PackInput, output: PackOutput, tolerance?: Pick<Tolerance, "overlap">, options?: ContainerTest$1): PackHard$1;
649
665
  /** The parameters of a generator: a name and a string or a number for each parameter. */
650
666
  type GeneratorParams = Record<string, string | number>;
651
667
  /**
@@ -818,5 +834,5 @@ interface Corpus {
818
834
  * `RangeError` for an unknown generator, a different version or 2 inputs with the same id.
819
835
  */
820
836
  export declare function corpus(name: string, specs: readonly CorpusSpec[]): Corpus;
821
- export { type Cell, type ChangeMeasures, type Corpus, type CorpusCell, type CorpusEntry, type CorpusGenerator, type CorpusManifest, type CorpusSpec, type CountScale, DEFAULT_TOLERANCE, type Dimension, type DimensionValue, type Direction, EPS, type EdgeCase, type EdgeCaseParams, type FreeSpace, type FreeSpan, type FreeWidthOptions, type FreeWidthResult, type FreeWidthTry, type GeneratedInput, type GeneratorParams, type GeneratorStamp, type Item, type LayoutContainer, type LayoutEdge, type LayoutInput, type LayoutMeasures, type LayoutStrategyOptions, type Margin, type MeasureFamily, type MeasureId, type MeasureOptions, type MeasureSpec, type MetricsOptions, type Obstacle, type ObstacleLayout, type PackContext, type PackHard, type PackInput, type PackLayoutOptions, type PackOptions, type PackOutput, type PackingMetrics, type Placement, type Port, type PushOptions, type PushStrategyOptions, RECORD_EPS, type RectGridParams, type RectScatteredParams, type Region, type ShelfOptions, type Side, type Sides, type SizeDistribution, type SizeSearch, type SkylineOptions, type SortOrder, type SpaceRect, type StageTrace, type Strategy, type Supports, type Tolerance, type UiParams, checkInput, turnPoint, turnPort, turnRegion };
837
+ export { type Cell, type ChangeMeasures, type ContainerTest, type Corpus, type CorpusCell, type CorpusEntry, type CorpusGenerator, type CorpusManifest, type CorpusSpec, type CountScale, DEFAULT_TOLERANCE, type Dimension, type DimensionValue, type Direction, EPS, type EdgeCase, type EdgeCaseParams, type FreeSpace, type FreeSpan, type FreeWidthOptions, type FreeWidthResult, type FreeWidthTry, type GeneratedInput, type GeneratorParams, type GeneratorStamp, type Item, type LayoutContainer, type LayoutEdge, type LayoutInput, type LayoutMeasures, type LayoutStrategyOptions, type Margin, type MeasureFamily, type MeasureId, type MeasureOptions, type MeasureSpec, type MetricsOptions, type Obstacle, type ObstacleLayout, type PackContext, type PackHard, type PackInput, type PackLayoutOptions, type PackOptions, type PackOutput, type PackingMetrics, type Placement, type Port, type PushOptions, type PushStrategyOptions, RECORD_EPS, type RectGridParams, type RectScatteredParams, type Region, type ShelfOptions, type Side, type Sides, type SizeDistribution, type SizeSearch, type SkylineOptions, type SortOrder, type SpaceRect, type StageTrace, type Strategy, type Supports, type Tolerance, type UiParams, checkInput, turnPoint, turnPort, turnRegion };
822
838
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":["Item","Sides","ContractMeasureSpec","Direction","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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"}
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
@@ -1,4 +1,4 @@
1
- import { DEFAULT_TOLERANCE, EPS, RECORD_EPS, boundsOf, boundsOf as boundsOf$1, checkInput, marginSides, regionHitsRect, translate, turnBox, turnPoint, turnPort, turnRegion } from "@mark1russell7/layout-contract";
1
+ import { DEFAULT_TOLERANCE, EPS, RECORD_EPS, boundsOf, boundsOf as boundsOf$1, checkInput, marginSides, rectInRegion, regionHitsRect, translate, turnBox, turnPoint, turnPort, turnRegion } from "@mark1russell7/layout-contract";
2
2
  // src/vector.ts
3
3
  /** A mutable two-dimensional vector. */
4
4
  var Vector = class Vector {
@@ -1398,6 +1398,323 @@ function pushCascade(placed, rects, options = {}) {
1398
1398
  }
1399
1399
  return [...moved];
1400
1400
  }
1401
+ // src/overflow.ts
1402
+ /** This function gives the area of a ring by the shoelace formula. The direction of the ring does not count. */
1403
+ function ringArea(ring) {
1404
+ let sum = 0;
1405
+ for (let i = 0; i < ring.length; i++) {
1406
+ const a = ring[i];
1407
+ const b = ring[(i + 1) % ring.length];
1408
+ sum += a[0] * b[1] - b[0] * a[1];
1409
+ }
1410
+ return Math.abs(sum) / 2;
1411
+ }
1412
+ /**
1413
+ * This function gives the area of a region that an item cannot use. A polygon loses the area of its holes. Thus a hole
1414
+ * that is out of the polygon makes the area too small, and the free area stays an upper bound.
1415
+ */
1416
+ function blockedArea(region) {
1417
+ switch (region.kind) {
1418
+ case "rect": return Math.max(0, region.w) * Math.max(0, region.h);
1419
+ case "circle": return Math.PI * region.r ** 2;
1420
+ case "ellipse": return Math.PI * region.rx * region.ry;
1421
+ case "polygon": {
1422
+ let area = ringArea(region.points);
1423
+ for (const hole of region.holes ?? []) area -= ringArea(hole);
1424
+ return Math.max(0, area);
1425
+ }
1426
+ }
1427
+ }
1428
+ /** This function tells if the insides of two rectangles have a common point. Two rectangles with a common edge do not. */
1429
+ function boxesOverlap(a, b) {
1430
+ return Math.min(a.x + a.w, b.x + b.w) - Math.max(a.x, b.x) > 0 && Math.min(a.y + a.h, b.y + b.h) - Math.max(a.y, b.y) > 0;
1431
+ }
1432
+ /** This function tells if rectangle `a` is in rectangle `b`. */
1433
+ function boxIn(a, b) {
1434
+ return a.x >= b.x && a.y >= b.y && a.x + a.w <= b.x + b.w && a.y + a.h <= b.y + b.h;
1435
+ }
1436
+ /** This function gives the rectangle made smaller by `d` on each side. */
1437
+ function shrink(b, d) {
1438
+ return {
1439
+ x: b.x + d,
1440
+ y: b.y + d,
1441
+ w: Math.max(0, b.w - 2 * d),
1442
+ h: Math.max(0, b.h - 2 * d)
1443
+ };
1444
+ }
1445
+ /** This function tells if a point is in a ring, by the even-odd rule. */
1446
+ function pointInRing(x, y, ring) {
1447
+ let inside = false;
1448
+ for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
1449
+ const [xi, yi] = ring[i];
1450
+ const [xj, yj] = ring[j];
1451
+ if (yi > y !== yj > y && x < (xj - xi) * (y - yi) / (yj - yi) + xi) inside = !inside;
1452
+ }
1453
+ return inside;
1454
+ }
1455
+ /** This function tells if a segment has a part of a length above 0 in the open rectangle. The Liang-Barsky clip gives it. */
1456
+ function segmentHitsBox(ax, ay, bx, by, r) {
1457
+ let t0 = 0;
1458
+ let t1 = 1;
1459
+ const dx = bx - ax;
1460
+ const dy = by - ay;
1461
+ const clip = (p, q) => {
1462
+ if (p === 0) return q > 0;
1463
+ const t = q / p;
1464
+ if (p < 0) {
1465
+ if (t > t1) return false;
1466
+ if (t > t0) t0 = t;
1467
+ } else {
1468
+ if (t < t0) return false;
1469
+ if (t < t1) t1 = t;
1470
+ }
1471
+ return true;
1472
+ };
1473
+ return clip(-dx, ax - r.x) && clip(dx, r.x + r.w - ax) && clip(-dy, ay - r.y) && clip(dy, r.y + r.h - ay) && t1 > t0;
1474
+ }
1475
+ /**
1476
+ * This function tells if a rectangle is in a polygon with holes. No edge of a ring crosses the inside of the rectangle.
1477
+ * No vertex is in it, and its center is in the polygon by the even-odd rule.
1478
+ */
1479
+ function boxInPolygon(b, rings) {
1480
+ for (const ring of rings) for (let i = 0; i < ring.length; i++) {
1481
+ const p = ring[i];
1482
+ const q = ring[(i + 1) % ring.length];
1483
+ if (p[0] > b.x && p[0] < b.x + b.w && p[1] > b.y && p[1] < b.y + b.h) return false;
1484
+ if (segmentHitsBox(p[0], p[1], q[0], q[1], b)) return false;
1485
+ }
1486
+ const cx = b.x + b.w / 2;
1487
+ const cy = b.y + b.h / 2;
1488
+ let inside = false;
1489
+ for (const ring of rings) if (pointInRing(cx, cy, ring)) inside = !inside;
1490
+ return inside;
1491
+ }
1492
+ /** This function tells if a rectangle is in a region of a container. A rectangle with no size is in no region. */
1493
+ function boxInShape(b, shape) {
1494
+ if (!(b.w > 0 && b.h > 0)) return false;
1495
+ const s = shrink(b, 1e-9 * Math.max(1, b.w, b.h));
1496
+ switch (shape.kind) {
1497
+ case "rect": return boxIn(b, {
1498
+ x: shape.x,
1499
+ y: shape.y,
1500
+ w: shape.w,
1501
+ h: shape.h
1502
+ });
1503
+ case "circle":
1504
+ case "ellipse": {
1505
+ const rx = shape.kind === "circle" ? shape.r : shape.rx;
1506
+ const ry = shape.kind === "circle" ? shape.r : shape.ry;
1507
+ const inside = (x, y) => ((x - shape.cx) / rx) ** 2 + ((y - shape.cy) / ry) ** 2 <= 1;
1508
+ return inside(s.x, s.y) && inside(s.x + s.w, s.y) && inside(s.x, s.y + s.h) && inside(s.x + s.w, s.y + s.h);
1509
+ }
1510
+ case "polygon": return boxInPolygon(s, [shape.points, ...shape.holes ?? []]);
1511
+ }
1512
+ }
1513
+ /**
1514
+ * This function gives the area of a container shape. A hole counts only when its bounding box is in the outer ring.
1515
+ * Also, that box has no common point with the box of a hole before it. Thus the area is not too small.
1516
+ */
1517
+ function shapeArea(shape) {
1518
+ if (shape.kind !== "polygon") return blockedArea(shape);
1519
+ let area = ringArea(shape.points);
1520
+ const kept = [];
1521
+ for (const hole of shape.holes ?? []) {
1522
+ const box = boundsOf({
1523
+ kind: "polygon",
1524
+ points: hole
1525
+ });
1526
+ if (!boxInPolygon(shrink(box, 1e-9 * Math.max(1, box.w, box.h)), [shape.points])) continue;
1527
+ if (kept.some((k) => boxesOverlap(k, box))) continue;
1528
+ kept.push(box);
1529
+ area -= ringArea(hole);
1530
+ }
1531
+ return Math.max(0, area);
1532
+ }
1533
+ /**
1534
+ * This function gives the area of the union of rectangles, each cut to the rectangle `clip`. A sweep over the x edges
1535
+ * adds the merged y intervals of each slab.
1536
+ */
1537
+ function unionArea(boxes, clip) {
1538
+ const cut = [];
1539
+ for (const b of boxes) {
1540
+ const x0 = Math.max(b.x, clip.x);
1541
+ const y0 = Math.max(b.y, clip.y);
1542
+ const x1 = Math.min(b.x + b.w, clip.x + clip.w);
1543
+ const y1 = Math.min(b.y + b.h, clip.y + clip.h);
1544
+ if (x1 > x0 && y1 > y0) cut.push({
1545
+ x: x0,
1546
+ y: y0,
1547
+ w: x1 - x0,
1548
+ h: y1 - y0
1549
+ });
1550
+ }
1551
+ const xs = [...new Set(cut.flatMap((b) => [b.x, b.x + b.w]))].toSorted((a, b) => a - b);
1552
+ let area = 0;
1553
+ for (let i = 0; i + 1 < xs.length; i++) {
1554
+ const left = xs[i];
1555
+ const right = xs[i + 1];
1556
+ const spans = cut.filter((b) => b.x <= left && b.x + b.w >= right).map((b) => [b.y, b.y + b.h]).toSorted((p, q) => p[0] - q[0]);
1557
+ let covered = 0;
1558
+ let top = -Infinity;
1559
+ let bottom = -Infinity;
1560
+ for (const [s, e] of spans) if (s > bottom) {
1561
+ covered += bottom - top > 0 ? bottom - top : 0;
1562
+ top = s;
1563
+ bottom = e;
1564
+ } else bottom = Math.max(bottom, e);
1565
+ covered += bottom - top > 0 ? bottom - top : 0;
1566
+ area += covered * (right - left);
1567
+ }
1568
+ return area;
1569
+ }
1570
+ /** This function gives the rectangle of the container: the bounding box of its shape, or 0, 0, `w`, `h`. */
1571
+ function containerBox(input) {
1572
+ const { container } = input;
1573
+ if (container.shape !== void 0) return boundsOf(container.shape);
1574
+ return {
1575
+ x: 0,
1576
+ y: 0,
1577
+ w: container.w ?? Infinity,
1578
+ h: container.h ?? Infinity
1579
+ };
1580
+ }
1581
+ /** This function tells if an item is locked at a position. Such an item is not a candidate of the overflow. */
1582
+ const lockedAt = (item) => item.locked === true && item.x !== void 0 && item.y !== void 0;
1583
+ /** This function gives the rectangle of an item at its position: the bounding box of its shape, or its size. */
1584
+ function itemBox(item) {
1585
+ const s = item.shape === void 0 ? {
1586
+ x: 0,
1587
+ y: 0,
1588
+ w: item.w,
1589
+ h: item.h
1590
+ } : boundsOf(item.shape);
1591
+ return {
1592
+ x: (item.x ?? 0) + s.x,
1593
+ y: (item.y ?? 0) + s.y,
1594
+ w: s.w,
1595
+ h: s.h
1596
+ };
1597
+ }
1598
+ /** This function gives the smallest area of an item: its rectangle, or the area of its shape when that is smaller. */
1599
+ function itemArea(item) {
1600
+ const rect = Math.max(0, item.w) * Math.max(0, item.h);
1601
+ return item.shape === void 0 ? rect : Math.min(rect, blockedArea(item.shape));
1602
+ }
1603
+ /**
1604
+ * This function gives an upper bound of the free area of a container with a fixed size. The bound ignores the gap and
1605
+ * the margins, thus it is not too small.
1606
+ *
1607
+ * - The container area is the inner rectangle (the container less the inset). A shape gives the smaller of that and its exact area.
1608
+ * - A rectangle container loses the exact union of the fixed rectangle obstacles and the locked items in the inner rectangle.
1609
+ * - A shape loses only the regions that are fully in it and in the inner rectangle, with no common point between their boxes.
1610
+ * - An obstacle with `move` can go out of the way. Thus the bound does not subtract it.
1611
+ */
1612
+ function freeAreaBound(input) {
1613
+ const inner = shrink(containerBox(input), input.container.inset ?? 0);
1614
+ if (!(inner.w > 0 && inner.h > 0)) return 0;
1615
+ const blocked = [];
1616
+ for (const o of input.obstacles ?? []) if (o.move === void 0) blocked.push({
1617
+ region: o.region,
1618
+ box: boundsOf(o.region)
1619
+ });
1620
+ for (const item of input.items) {
1621
+ if (!lockedAt(item)) continue;
1622
+ const box = itemBox(item);
1623
+ blocked.push({
1624
+ region: {
1625
+ kind: "rect",
1626
+ ...box
1627
+ },
1628
+ box
1629
+ });
1630
+ }
1631
+ const shape = input.container.shape;
1632
+ const innerArea = inner.w * inner.h;
1633
+ const inInner = (b) => b.w > 0 && b.h > 0 && boxIn(b, inner);
1634
+ if (shape === void 0 || shape.kind === "rect") {
1635
+ const rects = blocked.filter((b) => b.region.kind === "rect");
1636
+ let free = innerArea - unionArea(rects.map((b) => b.box), inner);
1637
+ const kept = [];
1638
+ for (const b of blocked) {
1639
+ if (b.region.kind === "rect" || !inInner(b.box)) continue;
1640
+ if (rects.some((r) => boxesOverlap(r.box, b.box)) || kept.some((k) => boxesOverlap(k, b.box))) continue;
1641
+ kept.push(b.box);
1642
+ free -= blockedArea(b.region);
1643
+ }
1644
+ return Math.max(0, free);
1645
+ }
1646
+ let free = Math.min(innerArea, shapeArea(shape));
1647
+ const kept = [];
1648
+ for (const b of blocked) {
1649
+ if (!inInner(b.box) || !boxInShape(b.box, shape) || kept.some((k) => boxesOverlap(k, b.box))) continue;
1650
+ kept.push(b.box);
1651
+ free -= blockedArea(b.region);
1652
+ }
1653
+ return Math.max(0, free);
1654
+ }
1655
+ /**
1656
+ * This function gives a lower bound of the overflow of an input: the items that no packer can place, and their area.
1657
+ *
1658
+ * - The candidates are the items that are not locked at a position.
1659
+ * - A fixed side forces each candidate that is longer than the side less the inset, in each turn that the item permits.
1660
+ * - A fixed size also forces the fewest other candidates that make the rest fit the free area of `freeAreaBound`. These are the largest ones.
1661
+ * - The area of the bound is the area of the long items, plus the part of the area of the rest above the free area.
1662
+ * - The margins and the gap do not count. A slack of the overlap tolerance along the edge of each candidate keeps the bound valid.
1663
+ * - A container with no fixed side gives 0.
1664
+ */
1665
+ function overflowBound(input) {
1666
+ const { container } = input;
1667
+ const fixedW = container.fixed === "size" || container.fixed === "width";
1668
+ const fixedH = container.fixed === "size" || container.fixed === "height";
1669
+ if (!fixedW && !fixedH) return {
1670
+ forced: 0,
1671
+ area: 0,
1672
+ free: Infinity
1673
+ };
1674
+ const tol = DEFAULT_TOLERANCE.overlap;
1675
+ const bounds = containerBox(input);
1676
+ const inset = container.inset ?? 0;
1677
+ const maxW = fixedW ? bounds.w - 2 * inset + 2 * tol : Infinity;
1678
+ const maxH = fixedH ? bounds.h - 2 * inset + 2 * tol : Infinity;
1679
+ let forced = 0;
1680
+ let area = 0;
1681
+ let slack = 0;
1682
+ const rest = [];
1683
+ for (const item of input.items) {
1684
+ if (lockedAt(item)) continue;
1685
+ const box = itemBox(item);
1686
+ const w = Math.min(item.w, box.w);
1687
+ const h = Math.min(item.h, box.h);
1688
+ const fits = w <= maxW && h <= maxH || item.turnable === true && h <= maxW && w <= maxH;
1689
+ const a = itemArea(item);
1690
+ if (!fits) {
1691
+ forced += 1;
1692
+ area += a;
1693
+ continue;
1694
+ }
1695
+ rest.push(a);
1696
+ slack += 2 * tol * (Math.max(0, w) + Math.max(0, h));
1697
+ }
1698
+ if (!(fixedW && fixedH)) return {
1699
+ forced,
1700
+ area,
1701
+ free: Infinity
1702
+ };
1703
+ const free = freeAreaBound(input);
1704
+ const room = free + slack + 2 * tol * (Math.max(0, bounds.w) + Math.max(0, bounds.h));
1705
+ let sum = rest.reduce((s, a) => s + a, 0);
1706
+ area += Math.max(0, sum - room);
1707
+ for (const a of rest.toSorted((p, q) => q - p)) {
1708
+ if (sum <= room || !(a > 0)) break;
1709
+ sum -= a;
1710
+ forced += 1;
1711
+ }
1712
+ return {
1713
+ forced,
1714
+ area,
1715
+ free
1716
+ };
1717
+ }
1401
1718
  // src/sha256.ts
1402
1719
  /** The round constants of SHA-256. */
1403
1720
  const K = new Uint32Array([
@@ -1597,53 +1914,66 @@ function toPackInput(file) {
1597
1914
  };
1598
1915
  }
1599
1916
  // src/measures.ts
1600
- const spec = (id, family, unit, direction, min, max, guard) => ({
1917
+ const spec = (id, family, unit, direction, min, max, minEffect, guard) => ({
1601
1918
  id,
1602
1919
  family,
1603
1920
  unit,
1604
1921
  direction,
1605
1922
  min,
1606
1923
  max,
1924
+ ...minEffect === void 0 ? {} : { minEffect },
1607
1925
  ...guard
1608
1926
  });
1927
+ /** The minimum effect of an area or a ratio of lengths: 1% of the larger value. */
1928
+ const REL = Object.freeze({ rel: .01 });
1609
1929
  /**
1610
1930
  * The facts of each measure, by id. `docs/MEASURES.md` gives the full definitions. This record is the source of the floor
1611
- * and the tolerance of each guard of the packer.
1931
+ * and the tolerance of each guard of the packer, and of the minimum effect of each measure.
1932
+ *
1933
+ * - A count and a share of counts have the minimum effect 0. Thus each change of a count is an effect.
1934
+ * - A share of an area from 0 to 1 has 0.005. A guard has its tolerance.
1935
+ * - An area and a ratio of lengths have `{ rel: 0.01 }`: 1% of the larger value.
1936
+ * - The time has no minimum effect, because the times of CI change each time.
1612
1937
  */
1613
1938
  const MEASURE_SPECS = Object.freeze({
1614
- "pack.area": spec("pack.area", "density", "square units", "lower", 0, Infinity),
1615
- "pack.fill": spec("pack.fill", "density", "share", "higher", 0, 1),
1616
- "pack.whitespace": spec("pack.whitespace", "density", "share", "lower", 0, 1),
1617
- "pack.aspect": spec("pack.aspect", "aspect", "ratio", "lower", 1, Infinity),
1618
- "pack.aspectError": spec("pack.aspectError", "aspect", "natural log", "lower", 0, Infinity, {
1939
+ "pack.area": spec("pack.area", "density", "square units", "lower", 0, Infinity, REL),
1940
+ "pack.fill": spec("pack.fill", "density", "share", "higher", 0, 1, .005),
1941
+ "pack.whitespace": spec("pack.whitespace", "density", "share", "lower", 0, 1, .005),
1942
+ "pack.aspect": spec("pack.aspect", "aspect", "ratio", "lower", 1, Infinity, REL),
1943
+ "pack.aspectError": spec("pack.aspectError", "aspect", "natural log", "lower", 0, Infinity, .01, {
1619
1944
  floor: 0,
1620
1945
  tol: .01
1621
1946
  }),
1622
- "pack.order.inversions": spec("pack.order.inversions", "order", "share", "lower", 0, 1, {
1947
+ "pack.order.inversions": spec("pack.order.inversions", "order", "share", "lower", 0, 1, 0, {
1623
1948
  floor: 0,
1624
1949
  tol: 0
1625
1950
  }),
1626
- "pack.order.breaks": spec("pack.order.breaks", "order", "count", "lower", 0, Infinity),
1627
- "pack.raggedness": spec("pack.raggedness", "raggedness", "share", "lower", 0, 1),
1628
- "pack.overflow": spec("pack.overflow", "overflow", "count", "lower", 0, Infinity, {
1951
+ "pack.order.breaks": spec("pack.order.breaks", "order", "count", "lower", 0, Infinity, 0),
1952
+ "pack.raggedness": spec("pack.raggedness", "raggedness", "share", "lower", 0, 1, .005),
1953
+ "pack.overflow": spec("pack.overflow", "overflow", "count", "lower", 0, Infinity, 0, {
1629
1954
  floor: 0,
1630
1955
  tol: 0
1631
1956
  }),
1632
- "pack.stability.moved": spec("pack.stability.moved", "stability", "share", "lower", 0, 1, {
1957
+ "pack.overflow.rate": spec("pack.overflow.rate", "overflow", "share", "lower", 0, 1, 0),
1958
+ "pack.overflow.area": spec("pack.overflow.area", "overflow", "share", "lower", 0, 1, .005),
1959
+ "pack.overflow.forced": spec("pack.overflow.forced", "overflow", "count", "lower", 0, Infinity, 0),
1960
+ "pack.overflow.forcedArea": spec("pack.overflow.forcedArea", "overflow", "share", "lower", 0, 1, .005),
1961
+ "pack.overflow.excess": spec("pack.overflow.excess", "overflow", "count", "lower", 0, Infinity, 0),
1962
+ "pack.stability.moved": spec("pack.stability.moved", "stability", "share", "lower", 0, 1, .02, {
1633
1963
  floor: 0,
1634
1964
  tol: .02
1635
1965
  }),
1636
- "pack.stability.mean": spec("pack.stability.mean", "stability", "container widths", "lower", 0, Infinity, {
1966
+ "pack.stability.mean": spec("pack.stability.mean", "stability", "container widths", "lower", 0, Infinity, .005, {
1637
1967
  floor: 0,
1638
1968
  tol: .005
1639
1969
  }),
1640
- "pack.stability.q95": spec("pack.stability.q95", "stability", "container widths", "lower", 0, Infinity, {
1970
+ "pack.stability.q95": spec("pack.stability.q95", "stability", "container widths", "lower", 0, Infinity, .01, {
1641
1971
  floor: 0,
1642
1972
  tol: .01
1643
1973
  }),
1644
- "pack.deterministic": spec("pack.deterministic", "determinism", "boolean", "higher", 0, 1),
1645
- "pack.search.widths": spec("pack.search.widths", "speed", "count", "lower", 0, Infinity),
1646
- "pack.search.ms": spec("pack.search.ms", "speed", "milliseconds", "lower", 0, Infinity)
1974
+ "pack.deterministic": spec("pack.deterministic", "determinism", "boolean", "higher", 0, 1, 0),
1975
+ "pack.search.widths": spec("pack.search.widths", "speed", "count", "lower", 0, Infinity, 0),
1976
+ "pack.search.ms": spec("pack.search.ms", "speed", "milliseconds", "lower", 0, Infinity, void 0)
1647
1977
  });
1648
1978
  /** This function gives the smallest rectangle around the boxes. No box gives a rectangle of size 0 at 0, 0. */
1649
1979
  function hullOf(boxes) {
@@ -1732,6 +2062,8 @@ function traceSum(output, id) {
1732
2062
  * - The boxes are the placed items with a width and a height above 0. The hull is the smallest rectangle around them.
1733
2063
  * - An empty layout gives the area 0, the aspect 1 and the aspect error 0. Its fill is 0 and its whitespace is 1.
1734
2064
  * - The time `pack.search.ms` comes from the trace. It is not part of the determinism rule.
2065
+ * - The overflow measures count each id once. `pack.overflow.forced` is the lower bound of `overflowBound`.
2066
+ * - `pack.overflow.excess` is the overflow less the forced overflow. A container with no fixed side gives 0 for both.
1735
2067
  *
1736
2068
  * @example
1737
2069
  * ```ts
@@ -1766,6 +2098,15 @@ function measure(input, output, options = {}) {
1766
2098
  }
1767
2099
  const rights = rowsOf$1(boxes, options.rowTolerance ?? quantileOrZero(boxes.map((b) => b.h), .5) / 2).map((r) => r.right);
1768
2100
  const spread = rights.length > 0 ? Math.max(...rights) - Math.min(...rights) : 0;
2101
+ const unplaced = new Set(output.overflow);
2102
+ let itemArea = 0;
2103
+ let unplacedArea = 0;
2104
+ for (const item of input.items) {
2105
+ const a = Math.max(0, item.w) * Math.max(0, item.h);
2106
+ itemArea += a;
2107
+ if (unplaced.has(item.id)) unplacedArea += a;
2108
+ }
2109
+ const bound = overflowBound(input);
1769
2110
  return {
1770
2111
  "pack.area": hullArea,
1771
2112
  "pack.fill": fill,
@@ -1775,7 +2116,12 @@ function measure(input, output, options = {}) {
1775
2116
  "pack.order.inversions": pairs > 0 ? inversions / pairs : 0,
1776
2117
  "pack.order.breaks": breaks,
1777
2118
  "pack.raggedness": hull.w > 0 ? spread / hull.w : 0,
1778
- "pack.overflow": new Set(output.overflow).size,
2119
+ "pack.overflow": unplaced.size,
2120
+ "pack.overflow.rate": input.items.length > 0 ? unplaced.size / input.items.length : 0,
2121
+ "pack.overflow.area": itemArea > 0 ? unplacedArea / itemArea : 0,
2122
+ "pack.overflow.forced": bound.forced,
2123
+ "pack.overflow.forcedArea": itemArea > 0 ? Math.min(1, bound.area / itemArea) : 0,
2124
+ "pack.overflow.excess": Math.max(0, unplaced.size - bound.forced),
1779
2125
  "pack.search.widths": traceSum(output, "pack.search.widths"),
1780
2126
  "pack.search.ms": traceSum(output, "pack.search.ms")
1781
2127
  };
@@ -2488,8 +2834,12 @@ function inner(box, tolerance) {
2488
2834
  * The test of an obstacle is exact: a circle, an ellipse and a polygon with holes count only their insides, as in `packHard`.
2489
2835
  * The rules read a shape of the container or of an item as its bounding box (decision 5). The bounding box of an item
2490
2836
  * shape is relative to the position of the item. The result has no tolerance in it.
2837
+ *
2838
+ * With `options.exactContainer`, a shaped container with the size `fixed` also uses its true outline for `in-container`.
2839
+ * A box then counts when `rectInRegion` of the contract tells that it is not in the shape, as in `packHard`.
2840
+ * For that test, the box grows by the inset and becomes smaller by `tolerance.overlap` on each side. The default is `false`.
2491
2841
  */
2492
- function checkHard(input, output, tolerance = DEFAULT_TOLERANCE) {
2842
+ function checkHard(input, output, tolerance = DEFAULT_TOLERANCE, options = {}) {
2493
2843
  const tol = tolerance.overlap;
2494
2844
  const placements = /* @__PURE__ */ new Map();
2495
2845
  for (const p of output.placements) if (!placements.has(p.id)) placements.set(p.id, p);
@@ -2554,11 +2904,18 @@ function checkHard(input, output, tolerance = DEFAULT_TOLERANCE) {
2554
2904
  const inset = container.inset ?? 0;
2555
2905
  const fixedW = container.fixed === "size" || container.fixed === "width";
2556
2906
  const fixedH = container.fixed === "size" || container.fixed === "height";
2907
+ const exact = options.exactContainer === true && container.fixed === "size" ? container.shape : void 0;
2557
2908
  let outside = 0;
2558
2909
  for (const box of boxes) {
2559
2910
  const outX = fixedW && (box.l < x + inset - tol || box.r > x + w - inset + tol);
2560
2911
  const outY = fixedH && (box.t < y + inset - tol || box.b > y + h - inset + tol);
2561
2912
  if (outX || outY) outside += 1;
2913
+ else if (exact !== void 0 && !rectInRegion(exact, inner({
2914
+ l: box.l - inset,
2915
+ t: box.t - inset,
2916
+ r: box.r + inset,
2917
+ b: box.b + inset
2918
+ }, tol))) outside += 1;
2562
2919
  }
2563
2920
  return {
2564
2921
  "no-overlap": overlaps,