calculate-packing 0.0.46 → 0.0.48
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/dist/index.d.ts +1 -0
- package/dist/index.js +107 -8
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -409,6 +409,7 @@ declare class OutlineSegmentCandidatePointSolver extends BaseSolver {
|
|
|
409
409
|
private createTemporaryPackedComponent;
|
|
410
410
|
/**
|
|
411
411
|
* Adjust position to avoid component bounds crossing to the inside of the outline
|
|
412
|
+
* and ensure the component stays within the boundary outline
|
|
412
413
|
*/
|
|
413
414
|
private adjustPositionForOutlineCollision;
|
|
414
415
|
visualize(): GraphicsObject;
|
package/dist/index.js
CHANGED
|
@@ -1403,6 +1403,26 @@ function normalizeVector(direction) {
|
|
|
1403
1403
|
};
|
|
1404
1404
|
}
|
|
1405
1405
|
|
|
1406
|
+
// lib/math/isPointInPolygon.ts
|
|
1407
|
+
function isPointInPolygon(point, polygon) {
|
|
1408
|
+
if (polygon.length < 3) return false;
|
|
1409
|
+
let inside = false;
|
|
1410
|
+
const n = polygon.length;
|
|
1411
|
+
const poly = [...polygon];
|
|
1412
|
+
if (poly[0].x !== poly[n - 1].x || poly[0].y !== poly[n - 1].y) {
|
|
1413
|
+
poly.push({ ...poly[0] });
|
|
1414
|
+
}
|
|
1415
|
+
for (let i = 0, j = poly.length - 1; i < poly.length; j = i++) {
|
|
1416
|
+
const xi = poly[i].x;
|
|
1417
|
+
const yi = poly[i].y;
|
|
1418
|
+
const xj = poly[j].x;
|
|
1419
|
+
const yj = poly[j].y;
|
|
1420
|
+
const intersect = yi > point.y !== yj > point.y && point.x < (xj - xi) * (point.y - yi) / (yj - yi) + xi;
|
|
1421
|
+
if (intersect) inside = !inside;
|
|
1422
|
+
}
|
|
1423
|
+
return inside;
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1406
1426
|
// lib/OutlineSegmentCandidatePointSolver/OutlineSegmentCandidatePointSolver.ts
|
|
1407
1427
|
var OutlineSegmentCandidatePointSolver = class extends BaseSolver {
|
|
1408
1428
|
outlineSegment;
|
|
@@ -1511,12 +1531,30 @@ var OutlineSegmentCandidatePointSolver = class extends BaseSolver {
|
|
|
1511
1531
|
Math.sign(this.outlineSegment[1].y - this.outlineSegment[0].y)
|
|
1512
1532
|
)
|
|
1513
1533
|
};
|
|
1514
|
-
|
|
1534
|
+
let viableBounds = {
|
|
1515
1535
|
minX: largestRectBounds.minX - componentBounds.minX * segmentNormAbs.x,
|
|
1516
1536
|
minY: largestRectBounds.minY - componentBounds.minY * segmentNormAbs.y,
|
|
1517
1537
|
maxX: largestRectBounds.maxX - componentBounds.maxX * segmentNormAbs.x,
|
|
1518
1538
|
maxY: largestRectBounds.maxY - componentBounds.maxY * segmentNormAbs.y
|
|
1519
1539
|
};
|
|
1540
|
+
if (this.boundaryOutline && this.boundaryOutline.length >= 3) {
|
|
1541
|
+
let boundaryMinX = Infinity;
|
|
1542
|
+
let boundaryMinY = Infinity;
|
|
1543
|
+
let boundaryMaxX = -Infinity;
|
|
1544
|
+
let boundaryMaxY = -Infinity;
|
|
1545
|
+
for (const point of this.boundaryOutline) {
|
|
1546
|
+
boundaryMinX = Math.min(boundaryMinX, point.x);
|
|
1547
|
+
boundaryMinY = Math.min(boundaryMinY, point.y);
|
|
1548
|
+
boundaryMaxX = Math.max(boundaryMaxX, point.x);
|
|
1549
|
+
boundaryMaxY = Math.max(boundaryMaxY, point.y);
|
|
1550
|
+
}
|
|
1551
|
+
viableBounds = {
|
|
1552
|
+
minX: Math.max(viableBounds.minX, boundaryMinX - componentBounds.minX),
|
|
1553
|
+
minY: Math.max(viableBounds.minY, boundaryMinY - componentBounds.minY),
|
|
1554
|
+
maxX: Math.min(viableBounds.maxX, boundaryMaxX - componentBounds.maxX),
|
|
1555
|
+
maxY: Math.min(viableBounds.maxY, boundaryMaxY - componentBounds.maxY)
|
|
1556
|
+
};
|
|
1557
|
+
}
|
|
1520
1558
|
this.viableBounds = viableBounds;
|
|
1521
1559
|
const viableBoundsWidth = viableBounds.maxX - viableBounds.minX;
|
|
1522
1560
|
const viableBoundsHeight = viableBounds.maxY - viableBounds.minY;
|
|
@@ -1676,6 +1714,7 @@ var OutlineSegmentCandidatePointSolver = class extends BaseSolver {
|
|
|
1676
1714
|
}
|
|
1677
1715
|
/**
|
|
1678
1716
|
* Adjust position to avoid component bounds crossing to the inside of the outline
|
|
1717
|
+
* and ensure the component stays within the boundary outline
|
|
1679
1718
|
*/
|
|
1680
1719
|
adjustPositionForOutlineCollision(center) {
|
|
1681
1720
|
const tempComponent = this.createTemporaryPackedComponent(center);
|
|
@@ -1686,37 +1725,66 @@ var OutlineSegmentCandidatePointSolver = class extends BaseSolver {
|
|
|
1686
1725
|
);
|
|
1687
1726
|
const isHorizontalNormal = Math.abs(outwardNormal.x) > Math.abs(outwardNormal.y);
|
|
1688
1727
|
const isVerticalNormal = !isHorizontalNormal;
|
|
1728
|
+
let adjustedCenter = center;
|
|
1689
1729
|
if (isHorizontalNormal) {
|
|
1690
1730
|
const isXPlusFacing = outwardNormal.x > 0;
|
|
1691
1731
|
const isXMinusFacing = !isXPlusFacing;
|
|
1692
1732
|
if (isXPlusFacing) {
|
|
1693
|
-
|
|
1733
|
+
adjustedCenter = {
|
|
1694
1734
|
x: bounds.maxX,
|
|
1695
1735
|
y: center.y
|
|
1696
1736
|
};
|
|
1697
1737
|
} else if (isXMinusFacing) {
|
|
1698
|
-
|
|
1738
|
+
adjustedCenter = {
|
|
1699
1739
|
x: bounds.minX,
|
|
1700
1740
|
y: center.y
|
|
1701
1741
|
};
|
|
1702
1742
|
}
|
|
1703
|
-
}
|
|
1704
|
-
if (isVerticalNormal) {
|
|
1743
|
+
} else if (isVerticalNormal) {
|
|
1705
1744
|
const isYPlusFacing = outwardNormal.y > 0;
|
|
1706
1745
|
const isYMinusFacing = !isYPlusFacing;
|
|
1707
1746
|
if (isYPlusFacing) {
|
|
1708
|
-
|
|
1747
|
+
adjustedCenter = {
|
|
1709
1748
|
x: center.x,
|
|
1710
1749
|
y: bounds.maxY
|
|
1711
1750
|
};
|
|
1712
1751
|
} else if (isYMinusFacing) {
|
|
1713
|
-
|
|
1752
|
+
adjustedCenter = {
|
|
1714
1753
|
x: center.x,
|
|
1715
1754
|
y: bounds.minY
|
|
1716
1755
|
};
|
|
1717
1756
|
}
|
|
1718
1757
|
}
|
|
1719
|
-
|
|
1758
|
+
if (this.boundaryOutline && this.boundaryOutline.length >= 3) {
|
|
1759
|
+
const adjustedComponent = this.createTemporaryPackedComponent(adjustedCenter);
|
|
1760
|
+
const adjustedBounds = getComponentBounds(adjustedComponent, 0);
|
|
1761
|
+
const allPadsInside = adjustedComponent.pads.every(
|
|
1762
|
+
(pad) => isPointInPolygon(pad.absoluteCenter, this.boundaryOutline)
|
|
1763
|
+
);
|
|
1764
|
+
const cornersInside = [
|
|
1765
|
+
{ x: adjustedBounds.minX, y: adjustedBounds.minY },
|
|
1766
|
+
{ x: adjustedBounds.minX, y: adjustedBounds.maxY },
|
|
1767
|
+
{ x: adjustedBounds.maxX, y: adjustedBounds.minY },
|
|
1768
|
+
{ x: adjustedBounds.maxX, y: adjustedBounds.maxY }
|
|
1769
|
+
].every((corner) => isPointInPolygon(corner, this.boundaryOutline));
|
|
1770
|
+
if (!allPadsInside || !cornersInside) {
|
|
1771
|
+
if (this.viableBounds) {
|
|
1772
|
+
adjustedCenter = {
|
|
1773
|
+
x: clamp(
|
|
1774
|
+
adjustedCenter.x,
|
|
1775
|
+
this.viableBounds.minX,
|
|
1776
|
+
this.viableBounds.maxX
|
|
1777
|
+
),
|
|
1778
|
+
y: clamp(
|
|
1779
|
+
adjustedCenter.y,
|
|
1780
|
+
this.viableBounds.minY,
|
|
1781
|
+
this.viableBounds.maxY
|
|
1782
|
+
)
|
|
1783
|
+
};
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
return adjustedCenter;
|
|
1720
1788
|
}
|
|
1721
1789
|
visualize() {
|
|
1722
1790
|
const graphics = {
|
|
@@ -2128,6 +2196,20 @@ var SingleComponentPackSolver = class extends BaseSolver {
|
|
|
2128
2196
|
return distance2 + 1e-6 < this.minGap;
|
|
2129
2197
|
});
|
|
2130
2198
|
});
|
|
2199
|
+
let outsideBoundaryOutline = false;
|
|
2200
|
+
if (this.boundaryOutline && this.boundaryOutline.length >= 3) {
|
|
2201
|
+
const componentBounds = getComponentBounds(candidateComponent, 0);
|
|
2202
|
+
const allPadsInside = candidateComponent.pads.every(
|
|
2203
|
+
(pad) => isPointInPolygon(pad.absoluteCenter, this.boundaryOutline)
|
|
2204
|
+
);
|
|
2205
|
+
const cornersInside = [
|
|
2206
|
+
{ x: componentBounds.minX, y: componentBounds.minY },
|
|
2207
|
+
{ x: componentBounds.minX, y: componentBounds.maxY },
|
|
2208
|
+
{ x: componentBounds.maxX, y: componentBounds.minY },
|
|
2209
|
+
{ x: componentBounds.maxX, y: componentBounds.maxY }
|
|
2210
|
+
].every((corner) => isPointInPolygon(corner, this.boundaryOutline));
|
|
2211
|
+
outsideBoundaryOutline = !allPadsInside || !cornersInside;
|
|
2212
|
+
}
|
|
2131
2213
|
distance = this.calculateDistance(optimalPosition, rotation);
|
|
2132
2214
|
if (hasOverlap) {
|
|
2133
2215
|
this.rejectedCandidates.push({
|
|
@@ -2149,6 +2231,17 @@ var SingleComponentPackSolver = class extends BaseSolver {
|
|
|
2149
2231
|
rotationIndex: this.currentRotationIndex,
|
|
2150
2232
|
gapDistance: minObstacleGapDistance
|
|
2151
2233
|
});
|
|
2234
|
+
} else if (outsideBoundaryOutline) {
|
|
2235
|
+
this.rejectedCandidates.push({
|
|
2236
|
+
segment: queuedSegment.segment,
|
|
2237
|
+
rotation,
|
|
2238
|
+
optimalPosition,
|
|
2239
|
+
distance,
|
|
2240
|
+
segmentIndex: queuedSegment.segmentIndex,
|
|
2241
|
+
rotationIndex: this.currentRotationIndex,
|
|
2242
|
+
gapDistance: -1
|
|
2243
|
+
// Special marker for boundary violation
|
|
2244
|
+
});
|
|
2152
2245
|
} else {
|
|
2153
2246
|
this.candidateResults.push({
|
|
2154
2247
|
segment: queuedSegment.segment,
|
|
@@ -2853,6 +2946,12 @@ var convertCircuitJsonToPackOutput = (circuitJson, opts = {}) => {
|
|
|
2853
2946
|
});
|
|
2854
2947
|
const db = cju(circuitJson);
|
|
2855
2948
|
let unnamedCounter = 0;
|
|
2949
|
+
const pcbBoard = circuitJson.find(
|
|
2950
|
+
(item) => item.type === "pcb_board"
|
|
2951
|
+
);
|
|
2952
|
+
if (pcbBoard && pcbBoard.outline) {
|
|
2953
|
+
packOutput.boundaryOutline = pcbBoard.outline;
|
|
2954
|
+
}
|
|
2856
2955
|
const getNetworkId = (pcbPortId) => {
|
|
2857
2956
|
if (pcbPortId) {
|
|
2858
2957
|
const pcbPort = db.pcb_port.get(pcbPortId);
|
package/package.json
CHANGED