calculate-packing 0.0.49 → 0.0.51
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/README.md +2 -0
- package/dist/index.js +54 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
**calculate-packing** is a small TypeScript library that ships the placement /
|
|
4
4
|
packing algorithm used by the [tscircuit tool-chain](https://github.com/tscircuit/tscircuit) for automatically laying out PCB components.
|
|
5
5
|
|
|
6
|
+
[Paste PackInput and Debug Online](https://calculate-packing.tscircuit.com/?fixture=%7B%22path%22%3A%22site%2Fpack%2Fpack-debugger-from-input.page.tsx%22%7D)
|
|
7
|
+
|
|
6
8
|
The solver turns a user-supplied `PackInput` (components, pads & strategy
|
|
7
9
|
settings) into a collision-free `PackOutput` while
|
|
8
10
|
|
package/dist/index.js
CHANGED
|
@@ -2519,6 +2519,38 @@ gap_distance=${candidate.gapDistance}`,
|
|
|
2519
2519
|
|
|
2520
2520
|
// lib/PackSolver2/PackSolver2.ts
|
|
2521
2521
|
import { computeDistanceBetweenBoxes as computeDistanceBetweenBoxes3 } from "@tscircuit/math-utils";
|
|
2522
|
+
|
|
2523
|
+
// lib/math/getPolygonCentroid.ts
|
|
2524
|
+
function getPolygonCentroid(points) {
|
|
2525
|
+
if (points.length < 3) {
|
|
2526
|
+
const sumX = points.reduce((sum, p) => sum + p.x, 0);
|
|
2527
|
+
const sumY = points.reduce((sum, p) => sum + p.y, 0);
|
|
2528
|
+
return { x: sumX / points.length, y: sumY / points.length };
|
|
2529
|
+
}
|
|
2530
|
+
let signedArea = 0;
|
|
2531
|
+
let cx = 0;
|
|
2532
|
+
let cy = 0;
|
|
2533
|
+
for (let i = 0; i < points.length; i++) {
|
|
2534
|
+
const p1 = points[i];
|
|
2535
|
+
const p2 = points[(i + 1) % points.length];
|
|
2536
|
+
const crossProduct = p1.x * p2.y - p2.x * p1.y;
|
|
2537
|
+
signedArea += crossProduct;
|
|
2538
|
+
cx += (p1.x + p2.x) * crossProduct;
|
|
2539
|
+
cy += (p1.y + p2.y) * crossProduct;
|
|
2540
|
+
}
|
|
2541
|
+
signedArea *= 0.5;
|
|
2542
|
+
const area = Math.abs(signedArea);
|
|
2543
|
+
if (area < 1e-10) {
|
|
2544
|
+
const sumX = points.reduce((sum, p) => sum + p.x, 0);
|
|
2545
|
+
const sumY = points.reduce((sum, p) => sum + p.y, 0);
|
|
2546
|
+
return { x: sumX / points.length, y: sumY / points.length };
|
|
2547
|
+
}
|
|
2548
|
+
cx /= 6 * signedArea;
|
|
2549
|
+
cy /= 6 * signedArea;
|
|
2550
|
+
return { x: cx, y: cy };
|
|
2551
|
+
}
|
|
2552
|
+
|
|
2553
|
+
// lib/PackSolver2/PackSolver2.ts
|
|
2522
2554
|
var PackSolver2 = class extends BaseSolver {
|
|
2523
2555
|
packInput;
|
|
2524
2556
|
unpackedComponentQueue = [];
|
|
@@ -2542,9 +2574,13 @@ var PackSolver2 = class extends BaseSolver {
|
|
|
2542
2574
|
}
|
|
2543
2575
|
packFirstComponent() {
|
|
2544
2576
|
const firstComponentToPack = this.unpackedComponentQueue.shift();
|
|
2577
|
+
let initialPosition = { x: 0, y: 0 };
|
|
2578
|
+
if (this.packInput.boundaryOutline && this.packInput.boundaryOutline.length >= 3) {
|
|
2579
|
+
initialPosition = getPolygonCentroid(this.packInput.boundaryOutline);
|
|
2580
|
+
}
|
|
2545
2581
|
const newPackedComponent = {
|
|
2546
2582
|
...firstComponentToPack,
|
|
2547
|
-
center:
|
|
2583
|
+
center: initialPosition,
|
|
2548
2584
|
ccwRotationOffset: 0,
|
|
2549
2585
|
pads: firstComponentToPack.pads.map((p) => ({
|
|
2550
2586
|
...p,
|
|
@@ -2569,7 +2605,23 @@ var PackSolver2 = class extends BaseSolver {
|
|
|
2569
2605
|
return distance + 1e-6 < this.packInput.minGap;
|
|
2570
2606
|
});
|
|
2571
2607
|
});
|
|
2572
|
-
|
|
2608
|
+
let outsideBoundaryOutline = false;
|
|
2609
|
+
if (this.packInput.boundaryOutline && this.packInput.boundaryOutline.length >= 3) {
|
|
2610
|
+
const componentBounds = getComponentBounds(newPackedComponent, 0);
|
|
2611
|
+
const allPadsInside = newPackedComponent.pads.every(
|
|
2612
|
+
(pad) => isPointInPolygon(pad.absoluteCenter, this.packInput.boundaryOutline)
|
|
2613
|
+
);
|
|
2614
|
+
const cornersInside = [
|
|
2615
|
+
{ x: componentBounds.minX, y: componentBounds.minY },
|
|
2616
|
+
{ x: componentBounds.minX, y: componentBounds.maxY },
|
|
2617
|
+
{ x: componentBounds.maxX, y: componentBounds.minY },
|
|
2618
|
+
{ x: componentBounds.maxX, y: componentBounds.maxY }
|
|
2619
|
+
].every(
|
|
2620
|
+
(corner) => isPointInPolygon(corner, this.packInput.boundaryOutline)
|
|
2621
|
+
);
|
|
2622
|
+
outsideBoundaryOutline = !allPadsInside || !cornersInside;
|
|
2623
|
+
}
|
|
2624
|
+
if (!tooCloseToObstacles && !outsideBoundaryOutline) {
|
|
2573
2625
|
this.packedComponents.push(newPackedComponent);
|
|
2574
2626
|
return;
|
|
2575
2627
|
}
|
package/package.json
CHANGED