calculate-packing 0.0.7 → 0.0.9
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 +3 -1
- package/dist/index.js +196 -65
- package/package.json +3 -2
package/dist/index.d.ts
CHANGED
|
@@ -142,7 +142,9 @@ declare class PackSolver extends BaseSolver {
|
|
|
142
142
|
getResult(): PackedComponent[];
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
-
declare const convertCircuitJsonToPackOutput: (circuitJson: CircuitJson
|
|
145
|
+
declare const convertCircuitJsonToPackOutput: (circuitJson: CircuitJson, opts?: {
|
|
146
|
+
source_group_id?: string;
|
|
147
|
+
}) => PackOutput;
|
|
146
148
|
|
|
147
149
|
declare const getGraphicsFromPackOutput: (packOutput: PackOutput) => GraphicsObject;
|
|
148
150
|
|
package/dist/index.js
CHANGED
|
@@ -719,17 +719,187 @@ var pack = (input) => {
|
|
|
719
719
|
};
|
|
720
720
|
};
|
|
721
721
|
|
|
722
|
-
// lib/
|
|
723
|
-
import { cju } from "@tscircuit/circuit-json-util";
|
|
724
|
-
|
|
722
|
+
// lib/plumbing/convertCircuitJsonToPackOutput.ts
|
|
723
|
+
import { cju, getCircuitJsonTree } from "@tscircuit/circuit-json-util";
|
|
724
|
+
|
|
725
|
+
// lib/plumbing/extractPadInfos.ts
|
|
726
|
+
var extractPadInfos = (pcbComponent, db, getNetworkId) => {
|
|
727
|
+
const out = [];
|
|
728
|
+
const pushPad = ({
|
|
729
|
+
padId,
|
|
730
|
+
pcbPortId,
|
|
731
|
+
sx,
|
|
732
|
+
sy,
|
|
733
|
+
x,
|
|
734
|
+
y
|
|
735
|
+
}) => out.push({
|
|
736
|
+
padId,
|
|
737
|
+
networkId: getNetworkId(pcbPortId),
|
|
738
|
+
size: { x: sx, y: sy },
|
|
739
|
+
absoluteCenter: { x, y }
|
|
740
|
+
});
|
|
741
|
+
for (const ph of db.pcb_plated_hole.list({
|
|
742
|
+
pcb_component_id: pcbComponent.pcb_component_id
|
|
743
|
+
})) {
|
|
744
|
+
switch (ph.shape) {
|
|
745
|
+
case "circle": {
|
|
746
|
+
pushPad({
|
|
747
|
+
padId: ph.pcb_plated_hole_id,
|
|
748
|
+
pcbPortId: ph.pcb_port_id,
|
|
749
|
+
sx: ph.outer_diameter ?? ph.hole_diameter ?? 0,
|
|
750
|
+
sy: ph.outer_diameter ?? ph.hole_diameter ?? 0,
|
|
751
|
+
x: ph.x,
|
|
752
|
+
y: ph.y
|
|
753
|
+
});
|
|
754
|
+
break;
|
|
755
|
+
}
|
|
756
|
+
case "oval": {
|
|
757
|
+
pushPad({
|
|
758
|
+
padId: ph.pcb_plated_hole_id,
|
|
759
|
+
pcbPortId: ph.pcb_port_id,
|
|
760
|
+
sx: ph.outer_width,
|
|
761
|
+
sy: ph.outer_height,
|
|
762
|
+
x: ph.x,
|
|
763
|
+
y: ph.y
|
|
764
|
+
});
|
|
765
|
+
break;
|
|
766
|
+
}
|
|
767
|
+
case "circular_hole_with_rect_pad": {
|
|
768
|
+
pushPad({
|
|
769
|
+
padId: ph.pcb_plated_hole_id,
|
|
770
|
+
pcbPortId: ph.pcb_port_id,
|
|
771
|
+
sx: ph.rect_pad_width,
|
|
772
|
+
sy: ph.rect_pad_height,
|
|
773
|
+
x: ph.x,
|
|
774
|
+
y: ph.y
|
|
775
|
+
});
|
|
776
|
+
break;
|
|
777
|
+
}
|
|
778
|
+
case "pill": {
|
|
779
|
+
pushPad({
|
|
780
|
+
padId: ph.pcb_plated_hole_id,
|
|
781
|
+
pcbPortId: ph.pcb_port_id,
|
|
782
|
+
sx: ph.outer_width,
|
|
783
|
+
sy: ph.outer_height,
|
|
784
|
+
x: ph.x,
|
|
785
|
+
y: ph.y
|
|
786
|
+
});
|
|
787
|
+
break;
|
|
788
|
+
}
|
|
789
|
+
case "pill_hole_with_rect_pad": {
|
|
790
|
+
pushPad({
|
|
791
|
+
padId: ph.pcb_plated_hole_id,
|
|
792
|
+
pcbPortId: ph.pcb_port_id,
|
|
793
|
+
sx: ph.rect_pad_width,
|
|
794
|
+
sy: ph.rect_pad_height,
|
|
795
|
+
x: ph.x,
|
|
796
|
+
y: ph.y
|
|
797
|
+
});
|
|
798
|
+
break;
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
console.warn(`Unsupported plated hole shape ${ph.shape}`);
|
|
802
|
+
}
|
|
803
|
+
for (const sp of db.pcb_smtpad.list({
|
|
804
|
+
pcb_component_id: pcbComponent.pcb_component_id
|
|
805
|
+
})) {
|
|
806
|
+
switch (sp.shape) {
|
|
807
|
+
case "rect": {
|
|
808
|
+
pushPad({
|
|
809
|
+
padId: sp.pcb_smtpad_id,
|
|
810
|
+
pcbPortId: sp.pcb_port_id,
|
|
811
|
+
sx: sp.width ?? 0,
|
|
812
|
+
sy: sp.height ?? 0,
|
|
813
|
+
x: sp.x,
|
|
814
|
+
y: sp.y
|
|
815
|
+
});
|
|
816
|
+
break;
|
|
817
|
+
}
|
|
818
|
+
case "circle": {
|
|
819
|
+
pushPad({
|
|
820
|
+
padId: sp.pcb_smtpad_id,
|
|
821
|
+
pcbPortId: sp.pcb_port_id,
|
|
822
|
+
sx: sp.radius ?? 0,
|
|
823
|
+
sy: sp.radius ?? 0,
|
|
824
|
+
x: sp.x,
|
|
825
|
+
y: sp.y
|
|
826
|
+
});
|
|
827
|
+
break;
|
|
828
|
+
}
|
|
829
|
+
case "pill": {
|
|
830
|
+
pushPad({
|
|
831
|
+
padId: sp.pcb_smtpad_id,
|
|
832
|
+
pcbPortId: sp.pcb_port_id,
|
|
833
|
+
sx: sp.width ?? 0,
|
|
834
|
+
sy: sp.height ?? 0,
|
|
835
|
+
x: sp.x,
|
|
836
|
+
y: sp.y
|
|
837
|
+
});
|
|
838
|
+
break;
|
|
839
|
+
}
|
|
840
|
+
default: {
|
|
841
|
+
console.warn(
|
|
842
|
+
`smtpad shape ${sp.shape} pads are not supported in pack layout yet`
|
|
843
|
+
);
|
|
844
|
+
break;
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
return out;
|
|
849
|
+
};
|
|
850
|
+
|
|
851
|
+
// lib/plumbing/convertCircuitJsonToPackOutput.ts
|
|
852
|
+
var buildPackedComponent = (pcbComponents, componentId, db, getNetworkId) => {
|
|
853
|
+
const padInfos = pcbComponents.flatMap(
|
|
854
|
+
(pc) => extractPadInfos(pc, db, getNetworkId)
|
|
855
|
+
);
|
|
856
|
+
let minX = Infinity;
|
|
857
|
+
let minY = Infinity;
|
|
858
|
+
let maxX = -Infinity;
|
|
859
|
+
let maxY = -Infinity;
|
|
860
|
+
for (const p of padInfos) {
|
|
861
|
+
minX = Math.min(minX, p.absoluteCenter.x - p.size.x / 2);
|
|
862
|
+
maxX = Math.max(maxX, p.absoluteCenter.x + p.size.x / 2);
|
|
863
|
+
minY = Math.min(minY, p.absoluteCenter.y - p.size.y / 2);
|
|
864
|
+
maxY = Math.max(maxY, p.absoluteCenter.y + p.size.y / 2);
|
|
865
|
+
}
|
|
866
|
+
const center = { x: (minX + maxX) / 2, y: (minY + maxY) / 2 };
|
|
867
|
+
const pads = padInfos.map((p) => ({
|
|
868
|
+
padId: p.padId,
|
|
869
|
+
networkId: p.networkId,
|
|
870
|
+
type: "rect",
|
|
871
|
+
size: p.size,
|
|
872
|
+
absoluteCenter: p.absoluteCenter,
|
|
873
|
+
offset: {
|
|
874
|
+
x: p.absoluteCenter.x - center.x,
|
|
875
|
+
y: p.absoluteCenter.y - center.y
|
|
876
|
+
}
|
|
877
|
+
}));
|
|
878
|
+
return {
|
|
879
|
+
componentId,
|
|
880
|
+
center,
|
|
881
|
+
ccwRotationOffset: 0,
|
|
882
|
+
pads
|
|
883
|
+
};
|
|
884
|
+
};
|
|
885
|
+
var collectPcbComponents = (node, db) => {
|
|
886
|
+
if (node.nodeType === "component") {
|
|
887
|
+
const pcbId = node.otherChildElements[0]?.pcb_component_id;
|
|
888
|
+
return pcbId ? [db.pcb_component.get(pcbId)] : [];
|
|
889
|
+
}
|
|
890
|
+
return node.childNodes.flatMap((n) => collectPcbComponents(n, db));
|
|
891
|
+
};
|
|
892
|
+
var convertCircuitJsonToPackOutput = (circuitJson, opts = {}) => {
|
|
725
893
|
const packOutput = {
|
|
726
894
|
components: [],
|
|
727
895
|
minGap: 0,
|
|
728
896
|
packOrderStrategy: "largest_to_smallest",
|
|
729
897
|
packPlacementStrategy: "shortest_connection_along_outline"
|
|
730
898
|
};
|
|
899
|
+
const tree = getCircuitJsonTree(circuitJson, {
|
|
900
|
+
source_group_id: opts.source_group_id
|
|
901
|
+
});
|
|
731
902
|
const db = cju(circuitJson);
|
|
732
|
-
const pcbComponents = db.pcb_component.list();
|
|
733
903
|
let unnamedCounter = 0;
|
|
734
904
|
const getNetworkId = (pcbPortId) => {
|
|
735
905
|
if (pcbPortId) {
|
|
@@ -743,68 +913,29 @@ var convertCircuitJsonToPackOutput = (circuitJson) => {
|
|
|
743
913
|
}
|
|
744
914
|
return `unnamed${unnamedCounter++}`;
|
|
745
915
|
};
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
};
|
|
769
|
-
pads.push(pad);
|
|
770
|
-
}
|
|
771
|
-
const smtPads = db.pcb_smtpad.list({
|
|
772
|
-
pcb_component_id: pcbComponent.pcb_component_id
|
|
773
|
-
});
|
|
774
|
-
for (const smtPad of smtPads) {
|
|
775
|
-
if (smtPad.shape === "polygon") {
|
|
776
|
-
throw new Error("Polygon pads are not supported in pack layout yet");
|
|
777
|
-
}
|
|
778
|
-
const networkId = getNetworkId(smtPad.pcb_port_id);
|
|
779
|
-
const pad = {
|
|
780
|
-
padId: smtPad.pcb_smtpad_id,
|
|
781
|
-
networkId,
|
|
782
|
-
type: "rect",
|
|
783
|
-
offset: {
|
|
784
|
-
x: smtPad.x - pcbComponent.center.x,
|
|
785
|
-
y: smtPad.y - pcbComponent.center.y
|
|
786
|
-
},
|
|
787
|
-
size: {
|
|
788
|
-
x: smtPad.width ?? 0,
|
|
789
|
-
y: smtPad.height ?? 0
|
|
790
|
-
},
|
|
791
|
-
absoluteCenter: {
|
|
792
|
-
x: smtPad.x,
|
|
793
|
-
y: smtPad.y
|
|
794
|
-
}
|
|
795
|
-
};
|
|
796
|
-
pads.push(pad);
|
|
916
|
+
const topLevelNodes = tree.childNodes ?? [];
|
|
917
|
+
for (const node of topLevelNodes) {
|
|
918
|
+
if (node.nodeType === "component") {
|
|
919
|
+
const pcbComponent = node.otherChildElements.find(
|
|
920
|
+
(e) => e.type === "pcb_component"
|
|
921
|
+
);
|
|
922
|
+
if (!pcbComponent) continue;
|
|
923
|
+
packOutput.components.push(
|
|
924
|
+
buildPackedComponent(
|
|
925
|
+
[pcbComponent],
|
|
926
|
+
pcbComponent.pcb_component_id,
|
|
927
|
+
db,
|
|
928
|
+
getNetworkId
|
|
929
|
+
)
|
|
930
|
+
);
|
|
931
|
+
} else if (node.nodeType === "group") {
|
|
932
|
+
const pcbComps = collectPcbComponents(node, db);
|
|
933
|
+
if (!pcbComps.length) continue;
|
|
934
|
+
const compId = node.sourceGroup?.source_group_id ?? node.sourceGroup?.name ?? `group_${packOutput.components.length}`;
|
|
935
|
+
packOutput.components.push(
|
|
936
|
+
buildPackedComponent(pcbComps, compId, db, getNetworkId)
|
|
937
|
+
);
|
|
797
938
|
}
|
|
798
|
-
const packedComponent = {
|
|
799
|
-
componentId: pcbComponent.pcb_component_id,
|
|
800
|
-
pads,
|
|
801
|
-
center: {
|
|
802
|
-
x: pcbComponent.center.x,
|
|
803
|
-
y: pcbComponent.center.y
|
|
804
|
-
},
|
|
805
|
-
ccwRotationOffset: 0
|
|
806
|
-
};
|
|
807
|
-
packOutput.components.push(packedComponent);
|
|
808
939
|
}
|
|
809
940
|
return packOutput;
|
|
810
941
|
};
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "calculate-packing",
|
|
3
3
|
"main": "dist/index.js",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "0.0.
|
|
5
|
+
"version": "0.0.9",
|
|
6
6
|
"description": "Calculate a packing layout with support for different strategy configurations",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"start": "cosmos",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"@biomejs/biome": "^2.1.1",
|
|
19
19
|
"@flatten-js/core": "^1.6.2",
|
|
20
20
|
"@react-hook/resize-observer": "^2.0.2",
|
|
21
|
-
"@tscircuit/circuit-json-util": "^0.0.
|
|
21
|
+
"@tscircuit/circuit-json-util": "^0.0.57",
|
|
22
22
|
"@tscircuit/footprinter": "^0.0.203",
|
|
23
23
|
"@tscircuit/math-utils": "^0.0.19",
|
|
24
24
|
"@types/bun": "latest",
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"react-cosmos": "^7.0.0",
|
|
32
32
|
"react-cosmos-plugin-vite": "^7.0.0",
|
|
33
33
|
"react-dom": "^19.1.0",
|
|
34
|
+
"tscircuit": "^0.0.562",
|
|
34
35
|
"tsup": "^8.5.0",
|
|
35
36
|
"vite": "^7.0.5"
|
|
36
37
|
},
|