calculate-packing 0.0.56 → 0.0.58
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 +6 -6
- package/dist/index.js +71 -27
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -138,17 +138,17 @@ type Rect = {
|
|
|
138
138
|
|
|
139
139
|
type GlobalBounds = Bounds;
|
|
140
140
|
declare class LargestRectOutsideOutlineFromPointSolver extends BaseSolver$1 {
|
|
141
|
-
|
|
141
|
+
ccwFullOutline: Point$1[];
|
|
142
142
|
origin: Point$1;
|
|
143
143
|
globalBounds: Bounds;
|
|
144
144
|
largestRect: Rect | null;
|
|
145
145
|
constructor(params: {
|
|
146
|
-
|
|
146
|
+
ccwFullOutline: Point$1[];
|
|
147
147
|
origin: Point$1;
|
|
148
148
|
globalBounds: Bounds;
|
|
149
149
|
});
|
|
150
150
|
getConstructorParams(): {
|
|
151
|
-
|
|
151
|
+
ccwFullOutline: Point$1[];
|
|
152
152
|
origin: Point$1;
|
|
153
153
|
globalBounds: Bounds;
|
|
154
154
|
};
|
|
@@ -367,7 +367,7 @@ declare class TwoPhaseIrlsSolver extends BaseSolver {
|
|
|
367
367
|
declare class OutlineSegmentCandidatePointSolver extends BaseSolver$1 {
|
|
368
368
|
outlineSegment: [Point$2, Point$2];
|
|
369
369
|
viableOutlineSegment: [Point$2, Point$2] | null;
|
|
370
|
-
|
|
370
|
+
ccwFullOutline: [Point$2, Point$2][];
|
|
371
371
|
componentRotationDegrees: number;
|
|
372
372
|
packStrategy: PackPlacementStrategy;
|
|
373
373
|
minGap: number;
|
|
@@ -385,7 +385,7 @@ declare class OutlineSegmentCandidatePointSolver extends BaseSolver$1 {
|
|
|
385
385
|
twoPhaseIrlsSolver?: TwoPhaseIrlsSolver;
|
|
386
386
|
constructor(params: {
|
|
387
387
|
outlineSegment: [Point$2, Point$2];
|
|
388
|
-
|
|
388
|
+
ccwFullOutline: [Point$2, Point$2][];
|
|
389
389
|
componentRotationDegrees: number;
|
|
390
390
|
packStrategy: PackPlacementStrategy;
|
|
391
391
|
minGap: number;
|
|
@@ -434,7 +434,7 @@ interface QueuedOutlineSegment {
|
|
|
434
434
|
segment: Segment;
|
|
435
435
|
availableRotations: number[];
|
|
436
436
|
segmentIndex: number;
|
|
437
|
-
|
|
437
|
+
ccwFullOutline: Segment[];
|
|
438
438
|
}
|
|
439
439
|
interface CandidateResult {
|
|
440
440
|
segment: Segment;
|
package/dist/index.js
CHANGED
|
@@ -1014,7 +1014,7 @@ function pointInOutline(p, segments, rule = "even-odd") {
|
|
|
1014
1014
|
}
|
|
1015
1015
|
|
|
1016
1016
|
// lib/OutlineSegmentCandidatePointSolver/getOutwardNormal.ts
|
|
1017
|
-
function getOutwardNormal(outlineSegment,
|
|
1017
|
+
function getOutwardNormal(outlineSegment, ccwFullOutline) {
|
|
1018
1018
|
const [p1, p2] = outlineSegment;
|
|
1019
1019
|
const dx = p2.x - p1.x;
|
|
1020
1020
|
const dy = p2.y - p1.y;
|
|
@@ -1030,7 +1030,7 @@ function getOutwardNormal(outlineSegment, fullOutline) {
|
|
|
1030
1030
|
x: (p1.x + p2.x) / 2,
|
|
1031
1031
|
y: (p1.y + p2.y) / 2
|
|
1032
1032
|
};
|
|
1033
|
-
const bbox = getOutlineBoundsWithMargin(
|
|
1033
|
+
const bbox = getOutlineBoundsWithMargin(ccwFullOutline);
|
|
1034
1034
|
const scale = Math.max(bbox.maxX - bbox.minX, bbox.maxY - bbox.minY) || 1;
|
|
1035
1035
|
const testDistance = Math.max(1e-4, 1e-3 * scale);
|
|
1036
1036
|
const testLeft = {
|
|
@@ -1041,18 +1041,18 @@ function getOutwardNormal(outlineSegment, fullOutline) {
|
|
|
1041
1041
|
x: mid.x + right.x * testDistance,
|
|
1042
1042
|
y: mid.y + right.y * testDistance
|
|
1043
1043
|
};
|
|
1044
|
-
const locLeft = pointInOutline(testLeft,
|
|
1044
|
+
const locLeft = pointInOutline(testLeft, ccwFullOutline);
|
|
1045
1045
|
if (locLeft === "outside") {
|
|
1046
1046
|
return left;
|
|
1047
1047
|
}
|
|
1048
|
-
const locRight = pointInOutline(testRight,
|
|
1048
|
+
const locRight = pointInOutline(testRight, ccwFullOutline);
|
|
1049
1049
|
if (locRight === "outside") {
|
|
1050
1050
|
return right;
|
|
1051
1051
|
}
|
|
1052
1052
|
const verts = [];
|
|
1053
|
-
if (
|
|
1054
|
-
verts.push(
|
|
1055
|
-
for (const seg of
|
|
1053
|
+
if (ccwFullOutline.length > 0) {
|
|
1054
|
+
verts.push(ccwFullOutline[0][0]);
|
|
1055
|
+
for (const seg of ccwFullOutline) {
|
|
1056
1056
|
verts.push(seg[1]);
|
|
1057
1057
|
}
|
|
1058
1058
|
}
|
|
@@ -1077,12 +1077,12 @@ function getOutwardNormal(outlineSegment, fullOutline) {
|
|
|
1077
1077
|
const dotRight = right.x * away.x + right.y * away.y;
|
|
1078
1078
|
return dotRight >= dotLeft ? right : left;
|
|
1079
1079
|
}
|
|
1080
|
-
function getOutlineBoundsWithMargin(
|
|
1080
|
+
function getOutlineBoundsWithMargin(ccwFullOutline, margin = 0) {
|
|
1081
1081
|
let minX = Infinity;
|
|
1082
1082
|
let minY = Infinity;
|
|
1083
1083
|
let maxX = -Infinity;
|
|
1084
1084
|
let maxY = -Infinity;
|
|
1085
|
-
for (const [p1, p2] of
|
|
1085
|
+
for (const [p1, p2] of ccwFullOutline) {
|
|
1086
1086
|
minX = Math.min(minX, p1.x, p2.x);
|
|
1087
1087
|
minY = Math.min(minY, p1.y, p2.y);
|
|
1088
1088
|
maxX = Math.max(maxX, p1.x, p2.x);
|
|
@@ -1099,19 +1099,19 @@ function getOutlineBoundsWithMargin(fullOutline, margin = 0) {
|
|
|
1099
1099
|
// lib/LargestRectOutsideOutlineFromPointSolver.ts
|
|
1100
1100
|
import { BaseSolver as BaseSolver2 } from "@tscircuit/solver-utils";
|
|
1101
1101
|
var LargestRectOutsideOutlineFromPointSolver = class extends BaseSolver2 {
|
|
1102
|
-
|
|
1102
|
+
ccwFullOutline;
|
|
1103
1103
|
origin;
|
|
1104
1104
|
globalBounds;
|
|
1105
1105
|
largestRect = null;
|
|
1106
1106
|
constructor(params) {
|
|
1107
1107
|
super();
|
|
1108
|
-
this.
|
|
1108
|
+
this.ccwFullOutline = params.ccwFullOutline;
|
|
1109
1109
|
this.origin = params.origin;
|
|
1110
1110
|
this.globalBounds = params.globalBounds;
|
|
1111
1111
|
}
|
|
1112
1112
|
getConstructorParams() {
|
|
1113
1113
|
return {
|
|
1114
|
-
|
|
1114
|
+
ccwFullOutline: this.ccwFullOutline,
|
|
1115
1115
|
origin: this.origin,
|
|
1116
1116
|
globalBounds: this.globalBounds
|
|
1117
1117
|
};
|
|
@@ -1123,7 +1123,7 @@ var LargestRectOutsideOutlineFromPointSolver = class extends BaseSolver2 {
|
|
|
1123
1123
|
this.solved = true;
|
|
1124
1124
|
}
|
|
1125
1125
|
computeLargestRectOutside() {
|
|
1126
|
-
const edges = this.makeEdges(this.
|
|
1126
|
+
const edges = this.makeEdges(this.ccwFullOutline);
|
|
1127
1127
|
const bounds = {
|
|
1128
1128
|
x: this.globalBounds.minX,
|
|
1129
1129
|
y: this.globalBounds.minY,
|
|
@@ -1318,9 +1318,9 @@ var LargestRectOutsideOutlineFromPointSolver = class extends BaseSolver2 {
|
|
|
1318
1318
|
rects: [],
|
|
1319
1319
|
circles: []
|
|
1320
1320
|
};
|
|
1321
|
-
for (let i = 0; i < this.
|
|
1322
|
-
const p1 = this.
|
|
1323
|
-
const p2 = this.
|
|
1321
|
+
for (let i = 0; i < this.ccwFullOutline.length; i++) {
|
|
1322
|
+
const p1 = this.ccwFullOutline[i];
|
|
1323
|
+
const p2 = this.ccwFullOutline[(i + 1) % this.ccwFullOutline.length];
|
|
1324
1324
|
if (p1 && p2) {
|
|
1325
1325
|
graphics.lines.push({
|
|
1326
1326
|
points: [p1, p2],
|
|
@@ -1329,7 +1329,7 @@ var LargestRectOutsideOutlineFromPointSolver = class extends BaseSolver2 {
|
|
|
1329
1329
|
}
|
|
1330
1330
|
}
|
|
1331
1331
|
graphics.lines.push({
|
|
1332
|
-
points: [...this.
|
|
1332
|
+
points: [...this.ccwFullOutline, this.ccwFullOutline[0]],
|
|
1333
1333
|
strokeColor: "rgba(200, 200, 200, 0.5)",
|
|
1334
1334
|
strokeDash: [10, 5]
|
|
1335
1335
|
});
|
|
@@ -1446,7 +1446,7 @@ function isPointInPolygon(point, polygon) {
|
|
|
1446
1446
|
var OutlineSegmentCandidatePointSolver = class extends BaseSolver3 {
|
|
1447
1447
|
outlineSegment;
|
|
1448
1448
|
viableOutlineSegment = null;
|
|
1449
|
-
|
|
1449
|
+
ccwFullOutline;
|
|
1450
1450
|
// The entire outline containing the segment
|
|
1451
1451
|
componentRotationDegrees;
|
|
1452
1452
|
packStrategy;
|
|
@@ -1463,7 +1463,7 @@ var OutlineSegmentCandidatePointSolver = class extends BaseSolver3 {
|
|
|
1463
1463
|
constructor(params) {
|
|
1464
1464
|
super();
|
|
1465
1465
|
this.outlineSegment = params.outlineSegment;
|
|
1466
|
-
this.
|
|
1466
|
+
this.ccwFullOutline = params.ccwFullOutline;
|
|
1467
1467
|
this.componentRotationDegrees = params.componentRotationDegrees;
|
|
1468
1468
|
this.packStrategy = params.packStrategy;
|
|
1469
1469
|
this.minGap = params.minGap;
|
|
@@ -1476,7 +1476,7 @@ var OutlineSegmentCandidatePointSolver = class extends BaseSolver3 {
|
|
|
1476
1476
|
getConstructorParams() {
|
|
1477
1477
|
return {
|
|
1478
1478
|
outlineSegment: this.outlineSegment,
|
|
1479
|
-
|
|
1479
|
+
ccwFullOutline: this.ccwFullOutline,
|
|
1480
1480
|
componentRotationDegrees: this.componentRotationDegrees,
|
|
1481
1481
|
packStrategy: this.packStrategy,
|
|
1482
1482
|
minGap: this.minGap,
|
|
@@ -1492,7 +1492,7 @@ var OutlineSegmentCandidatePointSolver = class extends BaseSolver3 {
|
|
|
1492
1492
|
let minY = Infinity;
|
|
1493
1493
|
let maxX = -Infinity;
|
|
1494
1494
|
let maxY = -Infinity;
|
|
1495
|
-
for (const [p1, p2] of this.
|
|
1495
|
+
for (const [p1, p2] of this.ccwFullOutline) {
|
|
1496
1496
|
minX = Math.min(minX, p1.x, p2.x);
|
|
1497
1497
|
minY = Math.min(minY, p1.y, p2.y);
|
|
1498
1498
|
maxX = Math.max(maxX, p1.x, p2.x);
|
|
@@ -1518,7 +1518,7 @@ var OutlineSegmentCandidatePointSolver = class extends BaseSolver3 {
|
|
|
1518
1518
|
};
|
|
1519
1519
|
const outwardNormal = getOutwardNormal(
|
|
1520
1520
|
this.outlineSegment,
|
|
1521
|
-
this.
|
|
1521
|
+
this.ccwFullOutline
|
|
1522
1522
|
);
|
|
1523
1523
|
const componentBounds = getInputComponentBounds(this.componentToPack, {
|
|
1524
1524
|
rotationDegrees: this.componentRotationDegrees
|
|
@@ -1530,7 +1530,7 @@ var OutlineSegmentCandidatePointSolver = class extends BaseSolver3 {
|
|
|
1530
1530
|
) * 2 + this.minGap * 2
|
|
1531
1531
|
});
|
|
1532
1532
|
const largestRectSolverParams = {
|
|
1533
|
-
|
|
1533
|
+
ccwFullOutline: this.ccwFullOutline.flatMap(([p]) => p),
|
|
1534
1534
|
globalBounds: packedComponentBoundsWithMargin,
|
|
1535
1535
|
origin: {
|
|
1536
1536
|
x: (p1.x + p2.x) / 2 + outwardNormal.x * 1e-4,
|
|
@@ -1740,7 +1740,7 @@ var OutlineSegmentCandidatePointSolver = class extends BaseSolver3 {
|
|
|
1740
1740
|
const bounds = getComponentBounds(tempComponent, 0);
|
|
1741
1741
|
const outwardNormal = getOutwardNormal(
|
|
1742
1742
|
this.outlineSegment,
|
|
1743
|
-
this.
|
|
1743
|
+
this.ccwFullOutline
|
|
1744
1744
|
);
|
|
1745
1745
|
const isHorizontalNormal = Math.abs(outwardNormal.x) > Math.abs(outwardNormal.y);
|
|
1746
1746
|
const isVerticalNormal = !isHorizontalNormal;
|
|
@@ -1873,7 +1873,7 @@ var OutlineSegmentCandidatePointSolver = class extends BaseSolver3 {
|
|
|
1873
1873
|
strokeColor: "rgba(255,0,0,1)",
|
|
1874
1874
|
strokeDash: "3 3"
|
|
1875
1875
|
});
|
|
1876
|
-
for (const [p1, p2] of this.
|
|
1876
|
+
for (const [p1, p2] of this.ccwFullOutline) {
|
|
1877
1877
|
graphics.lines.push({
|
|
1878
1878
|
points: [p1, p2],
|
|
1879
1879
|
strokeColor: "rgba(0,0,0,0.5)",
|
|
@@ -2177,7 +2177,7 @@ var SingleComponentPackSolver = class extends BaseSolver4 {
|
|
|
2177
2177
|
availableRotations: [...availableRotations],
|
|
2178
2178
|
segmentIndex: segmentIndex * 1e3 + i,
|
|
2179
2179
|
// Unique index across all outlines
|
|
2180
|
-
|
|
2180
|
+
ccwFullOutline: outline
|
|
2181
2181
|
// Pass the entire outline containing this segment
|
|
2182
2182
|
});
|
|
2183
2183
|
}
|
|
@@ -2311,7 +2311,7 @@ var SingleComponentPackSolver = class extends BaseSolver4 {
|
|
|
2311
2311
|
const rotation = queuedSegment.availableRotations[this.currentRotationIndex];
|
|
2312
2312
|
this.activeSubSolver = new OutlineSegmentCandidatePointSolver({
|
|
2313
2313
|
outlineSegment: queuedSegment.segment,
|
|
2314
|
-
|
|
2314
|
+
ccwFullOutline: queuedSegment.ccwFullOutline,
|
|
2315
2315
|
componentRotationDegrees: rotation,
|
|
2316
2316
|
packStrategy: this.packPlacementStrategy,
|
|
2317
2317
|
minGap: this.minGap,
|
|
@@ -3110,12 +3110,30 @@ var convertCircuitJsonToPackOutput = (circuitJson, opts = {}) => {
|
|
|
3110
3110
|
return `unnamed${unnamedCounter++}`;
|
|
3111
3111
|
};
|
|
3112
3112
|
const topLevelNodes = tree.childNodes ?? [];
|
|
3113
|
+
const collectRelativeToGroupAnchorComponents = (node) => {
|
|
3114
|
+
const relativeComponents2 = [];
|
|
3115
|
+
if (node.nodeType === "component") {
|
|
3116
|
+
const pcbComponent = node.otherChildElements.find(
|
|
3117
|
+
(e) => e.type === "pcb_component"
|
|
3118
|
+
);
|
|
3119
|
+
if (pcbComponent && pcbComponent.position_mode === "relative_to_group_anchor") {
|
|
3120
|
+
relativeComponents2.push(pcbComponent);
|
|
3121
|
+
}
|
|
3122
|
+
}
|
|
3123
|
+
for (const child of node.childNodes ?? []) {
|
|
3124
|
+
relativeComponents2.push(...collectRelativeToGroupAnchorComponents(child));
|
|
3125
|
+
}
|
|
3126
|
+
return relativeComponents2;
|
|
3127
|
+
};
|
|
3113
3128
|
for (const node of topLevelNodes) {
|
|
3114
3129
|
if (node.nodeType === "component") {
|
|
3115
3130
|
const pcbComponent = node.otherChildElements.find(
|
|
3116
3131
|
(e) => e.type === "pcb_component"
|
|
3117
3132
|
);
|
|
3118
3133
|
if (!pcbComponent) continue;
|
|
3134
|
+
if (pcbComponent.position_mode === "relative_to_group_anchor") {
|
|
3135
|
+
continue;
|
|
3136
|
+
}
|
|
3119
3137
|
let shouldAddInnerObstaclesForComp = opts.shouldAddInnerObstacles;
|
|
3120
3138
|
if (pcbComponent.obstructs_within_bounds === false) {
|
|
3121
3139
|
shouldAddInnerObstaclesForComp = false;
|
|
@@ -3146,6 +3164,32 @@ var convertCircuitJsonToPackOutput = (circuitJson, opts = {}) => {
|
|
|
3146
3164
|
);
|
|
3147
3165
|
}
|
|
3148
3166
|
}
|
|
3167
|
+
const relativeComponents = topLevelNodes.flatMap(
|
|
3168
|
+
(node) => collectRelativeToGroupAnchorComponents(node)
|
|
3169
|
+
);
|
|
3170
|
+
for (const pcbComponent of relativeComponents) {
|
|
3171
|
+
const padInfos = extractPadInfos(pcbComponent, db, getNetworkId);
|
|
3172
|
+
if (padInfos.length === 0) continue;
|
|
3173
|
+
let minX = Infinity;
|
|
3174
|
+
let minY = Infinity;
|
|
3175
|
+
let maxX = -Infinity;
|
|
3176
|
+
let maxY = -Infinity;
|
|
3177
|
+
for (const pad of padInfos) {
|
|
3178
|
+
minX = Math.min(minX, pad.absoluteCenter.x - pad.size.x / 2);
|
|
3179
|
+
maxX = Math.max(maxX, pad.absoluteCenter.x + pad.size.x / 2);
|
|
3180
|
+
minY = Math.min(minY, pad.absoluteCenter.y - pad.size.y / 2);
|
|
3181
|
+
maxY = Math.max(maxY, pad.absoluteCenter.y + pad.size.y / 2);
|
|
3182
|
+
}
|
|
3183
|
+
const center = { x: (minX + maxX) / 2, y: (minY + maxY) / 2 };
|
|
3184
|
+
const width = maxX - minX;
|
|
3185
|
+
const height = maxY - minY;
|
|
3186
|
+
packOutput.obstacles.push({
|
|
3187
|
+
obstacleId: pcbComponent.pcb_component_id,
|
|
3188
|
+
absoluteCenter: center,
|
|
3189
|
+
width,
|
|
3190
|
+
height
|
|
3191
|
+
});
|
|
3192
|
+
}
|
|
3149
3193
|
for (const element of elementsOutsideTree) {
|
|
3150
3194
|
if (element.type === "pcb_plated_hole" && element.shape === "circular_hole_with_rect_pad") {
|
|
3151
3195
|
const { rect_pad_height, rect_pad_width, x, y } = element;
|
package/package.json
CHANGED