circuit-json-to-tscircuit 0.0.91 → 0.0.92
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/{chunk-TYZGD7TY.js → chunk-GAMHGAGS.js} +1114 -198
- package/dist/cli/main.js +9 -2
- package/dist/lib/index.js +1 -1
- package/lib/board-conversion-context.ts +21 -6
- package/lib/board-conversion-types.ts +2 -0
- package/lib/board-converter/BoardConverterContext.ts +18 -0
- package/lib/board-converter/convert-board-circuit-json.ts +80 -0
- package/lib/board-converter/create-component-preserving-board-conversion-context.ts +98 -0
- package/lib/board-converter/get-board-child-runtime-names.ts +129 -0
- package/lib/board-converter/get-pcb-component-render-placement.ts +102 -0
- package/lib/board-converter/get-pin-labels.ts +99 -0
- package/lib/board-converter/get-schematic-components-for-pcb-component.ts +50 -0
- package/lib/board-converter/localize-pcb-component-elements.ts +270 -0
- package/lib/board-converter/stages/convert-board-cad-models.ts +36 -0
- package/lib/board-converter/stages/convert-board-nets.ts +19 -0
- package/lib/board-converter/stages/convert-board-properties.ts +49 -0
- package/lib/board-converter/stages/convert-board-schematic.ts +16 -0
- package/lib/board-converter/stages/convert-board-traces.ts +12 -0
- package/lib/board-converter/stages/convert-copper-pours.ts +12 -0
- package/lib/board-converter/stages/convert-pcb-components.ts +171 -0
- package/lib/board-converter/stages/convert-standalone-pcb-primitives.ts +46 -0
- package/lib/format-jsx-string-attribute.ts +9 -0
- package/lib/generate-board-cad-models-tsx/generate-cad-model-group-model-tsx.ts +41 -0
- package/lib/generate-board-cad-models-tsx/generate-cad-model-group-tsx.ts +8 -18
- package/lib/generate-board-cad-models-tsx/generate-cad-model-tsx.ts +6 -33
- package/lib/generate-board-cad-models-tsx/generate-jscad-cad-model-tsx.ts +26 -0
- package/lib/generate-board-cad-models-tsx/get-cad-model-groups.ts +3 -2
- package/lib/generate-board-cad-models-tsx/get-cad-model-placement-attributes.ts +50 -0
- package/lib/generate-board-cad-models-tsx/has-cad-model-source.ts +9 -0
- package/lib/generate-board-cad-models-tsx.ts +13 -2
- package/lib/generate-board-nets-tsx.ts +32 -2
- package/lib/generate-board-traces-tsx.ts +28 -0
- package/lib/generate-footprint-tsx/get-imported-port-hints.ts +10 -1
- package/lib/get-board-using-template.ts +3 -95
- package/lib/get-runtime-net-names.ts +93 -5
- package/package.json +8 -1
- package/tests/board-autorouted-pad-connectivity.test.tsx +153 -0
- package/tests/board-bottom-cad-model-rotation.test.ts +5 -5
- package/tests/board-bottom-jscad-cad-model.test.ts +67 -0
- package/tests/board-component-cad-models-on-multiple-layers.test.ts +81 -0
- package/tests/board-connected-net-aliases.test.ts +56 -0
- package/tests/board-duplicate-component-names.test.tsx +60 -0
- package/tests/board-grouped-jscad-cad-model.test.ts +135 -0
- package/tests/board-imported-board-name-collision.test.ts +74 -0
- package/tests/board-imported-cad-model-name-collision.test.ts +86 -0
- package/tests/board-jscad-cad-model.test.ts +83 -0
- package/tests/board-mixed-url-and-jscad-cad-models.test.ts +110 -0
- package/tests/board-near-zero-local-coordinates.test.ts +65 -0
- package/tests/board-net-endpoint-order.test.ts +135 -0
- package/tests/board-net-name-collision.test.ts +1 -1
- package/tests/board-net-routing-order.test.ts +50 -0
- package/tests/board-nonnumeric-port-placement.test.ts +130 -0
- package/tests/board-off-center-footprint-cad-model.test.ts +82 -0
- package/tests/board-rotated-pad-orientation.test.ts +120 -0
- package/tests/board-rotated-pill-cad-model-placement.test.ts +93 -0
- package/tests/board-standalone-primitives-do-not-obstruct.test.ts +34 -0
- package/tests/test20-board-conversion-drops-children.test.tsx +31 -30
- package/tests/ti-evms/__snapshots__/ti-drv8307evm-roundtrip-pcb-comparison.snap.svg +1 -1
- package/tests/ti-evms/__snapshots__/ti-drv8307evm-roundtrip.test.tsx.snap +4361 -4109
- package/tests/ti-evms/__snapshots__/ti-lm251772evm-pd-roundtrip-pcb-comparison.snap.svg +1 -1
- package/tests/ti-evms/__snapshots__/ti-lm251772evm-pd-roundtrip.test.tsx.snap +5557 -5171
- package/tests/ti-evms/__snapshots__/ti-lm5155evm-fly-roundtrip-pcb-comparison.snap.svg +1 -1
- package/tests/ti-evms/__snapshots__/ti-lmg342x-bb-evm-roundtrip-pcb-comparison.snap.svg +1 -1
- package/tests/ti-evms/__snapshots__/ti-lmg342x-bb-evm-roundtrip.test.tsx.snap +4592 -4226
- package/tests/ti-evms/ti-lm5155evm-fly-roundtrip.test.tsx +2823 -2608
|
@@ -1,19 +1,26 @@
|
|
|
1
|
-
// lib/get-board-using-template.ts
|
|
2
|
-
import { mmStr as mmStr9 } from "@tscircuit/mm";
|
|
3
|
-
import { su as su21 } from "@tscircuit/soup-util";
|
|
4
|
-
|
|
5
1
|
// lib/get-runtime-net-names.ts
|
|
6
2
|
var getRuntimeNetNames = (circuitJson, sourceNetIdsRequiringSelector) => {
|
|
7
3
|
const sourceNets = circuitJson.filter(
|
|
8
4
|
(element) => element.type === "source_net"
|
|
9
5
|
);
|
|
6
|
+
const canonicalSourceNetIdBySourceNetId = getCanonicalSourceNetIdBySourceNetId(circuitJson);
|
|
7
|
+
const sourceNetById = new Map(
|
|
8
|
+
sourceNets.map((sourceNet) => [sourceNet.source_net_id, sourceNet])
|
|
9
|
+
);
|
|
10
|
+
const canonicalSourceNets = sourceNets.filter(
|
|
11
|
+
(sourceNet) => canonicalSourceNetIdBySourceNetId.get(sourceNet.source_net_id) === sourceNet.source_net_id
|
|
12
|
+
);
|
|
10
13
|
const sourceNetNamesRequiringSelector = /* @__PURE__ */ new Set();
|
|
11
|
-
for (const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
for (const sourceNetId of sourceNetIdsRequiringSelector) {
|
|
15
|
+
const canonicalSourceNetId = canonicalSourceNetIdBySourceNetId.get(sourceNetId) ?? sourceNetId;
|
|
16
|
+
const canonicalSourceNet = sourceNetById.get(canonicalSourceNetId);
|
|
17
|
+
if (canonicalSourceNet) {
|
|
18
|
+
sourceNetNamesRequiringSelector.add(canonicalSourceNet.name);
|
|
14
19
|
}
|
|
15
20
|
}
|
|
16
|
-
const sourceNetNames = [
|
|
21
|
+
const sourceNetNames = [
|
|
22
|
+
...new Set(canonicalSourceNets.map(({ name }) => name))
|
|
23
|
+
];
|
|
17
24
|
const runtimeNameByOriginalName = /* @__PURE__ */ new Map();
|
|
18
25
|
const usedRuntimeNetNames = /* @__PURE__ */ new Set();
|
|
19
26
|
const namesThatRemainUnchanged = sourceNetNames.filter(
|
|
@@ -36,13 +43,74 @@ var getRuntimeNetNames = (circuitJson, sourceNetIdsRequiringSelector) => {
|
|
|
36
43
|
}
|
|
37
44
|
const runtimeNetNameBySourceNetId = /* @__PURE__ */ new Map();
|
|
38
45
|
for (const sourceNet of sourceNets) {
|
|
46
|
+
const canonicalSourceNetId = canonicalSourceNetIdBySourceNetId.get(sourceNet.source_net_id) ?? sourceNet.source_net_id;
|
|
47
|
+
const canonicalSourceNet = sourceNetById.get(canonicalSourceNetId);
|
|
48
|
+
if (!canonicalSourceNet) continue;
|
|
39
49
|
runtimeNetNameBySourceNetId.set(
|
|
40
50
|
sourceNet.source_net_id,
|
|
41
|
-
runtimeNameByOriginalName.get(
|
|
51
|
+
runtimeNameByOriginalName.get(canonicalSourceNet.name)
|
|
42
52
|
);
|
|
43
53
|
}
|
|
44
54
|
return runtimeNetNameBySourceNetId;
|
|
45
55
|
};
|
|
56
|
+
var getCanonicalSourceNetIdBySourceNetId = (circuitJson) => {
|
|
57
|
+
const parentSourceNetIdBySourceNetId = /* @__PURE__ */ new Map();
|
|
58
|
+
for (const element of circuitJson) {
|
|
59
|
+
if (element.type !== "source_net") continue;
|
|
60
|
+
parentSourceNetIdBySourceNetId.set(
|
|
61
|
+
element.source_net_id,
|
|
62
|
+
element.source_net_id
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
for (const element of circuitJson) {
|
|
66
|
+
if (element.type !== "source_trace") continue;
|
|
67
|
+
const sourceNetIds = element.connected_source_net_ids.filter(
|
|
68
|
+
(sourceNetId) => parentSourceNetIdBySourceNetId.has(sourceNetId)
|
|
69
|
+
);
|
|
70
|
+
const firstSourceNetId = sourceNetIds[0];
|
|
71
|
+
if (!firstSourceNetId) continue;
|
|
72
|
+
const canonicalSourceNetId = findCanonicalSourceNetId({
|
|
73
|
+
parentSourceNetIdBySourceNetId,
|
|
74
|
+
sourceNetId: firstSourceNetId
|
|
75
|
+
});
|
|
76
|
+
for (const sourceNetId of sourceNetIds.slice(1)) {
|
|
77
|
+
const aliasCanonicalSourceNetId = findCanonicalSourceNetId({
|
|
78
|
+
parentSourceNetIdBySourceNetId,
|
|
79
|
+
sourceNetId
|
|
80
|
+
});
|
|
81
|
+
if (aliasCanonicalSourceNetId === canonicalSourceNetId) continue;
|
|
82
|
+
parentSourceNetIdBySourceNetId.set(
|
|
83
|
+
aliasCanonicalSourceNetId,
|
|
84
|
+
canonicalSourceNetId
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return new Map(
|
|
89
|
+
[...parentSourceNetIdBySourceNetId.keys()].map((sourceNetId) => [
|
|
90
|
+
sourceNetId,
|
|
91
|
+
findCanonicalSourceNetId({
|
|
92
|
+
parentSourceNetIdBySourceNetId,
|
|
93
|
+
sourceNetId
|
|
94
|
+
})
|
|
95
|
+
])
|
|
96
|
+
);
|
|
97
|
+
};
|
|
98
|
+
var findCanonicalSourceNetId = ({
|
|
99
|
+
parentSourceNetIdBySourceNetId,
|
|
100
|
+
sourceNetId
|
|
101
|
+
}) => {
|
|
102
|
+
let currentSourceNetId = sourceNetId;
|
|
103
|
+
const visitedSourceNetIds = /* @__PURE__ */ new Set();
|
|
104
|
+
while (!visitedSourceNetIds.has(currentSourceNetId)) {
|
|
105
|
+
visitedSourceNetIds.add(currentSourceNetId);
|
|
106
|
+
const parentSourceNetId = parentSourceNetIdBySourceNetId.get(currentSourceNetId);
|
|
107
|
+
if (!parentSourceNetId || parentSourceNetId === currentSourceNetId) {
|
|
108
|
+
return currentSourceNetId;
|
|
109
|
+
}
|
|
110
|
+
currentSourceNetId = parentSourceNetId;
|
|
111
|
+
}
|
|
112
|
+
return currentSourceNetId;
|
|
113
|
+
};
|
|
46
114
|
var getUniqueRuntimeNetName = (sourceNetName, usedRuntimeNetNames) => {
|
|
47
115
|
const baseName = getRuntimeNetNameBase(sourceNetName);
|
|
48
116
|
let candidate = baseName;
|
|
@@ -59,8 +127,11 @@ var getRuntimeNetNameBase = (sourceNetName) => {
|
|
|
59
127
|
};
|
|
60
128
|
|
|
61
129
|
// lib/board-conversion-context.ts
|
|
62
|
-
var
|
|
63
|
-
var createBoardConversionContext = (
|
|
130
|
+
var DEFAULT_PCB_CHIP_NAME = "ImportedBoard";
|
|
131
|
+
var createBoardConversionContext = ({
|
|
132
|
+
circuitJson,
|
|
133
|
+
pcbChipName = DEFAULT_PCB_CHIP_NAME
|
|
134
|
+
}) => {
|
|
64
135
|
const sourceNetIdsRequiringSelector = getSourceNetIdsRequiringSelector(circuitJson);
|
|
65
136
|
const runtimeNetNameBySourceNetId = getRuntimeNetNames(
|
|
66
137
|
circuitJson,
|
|
@@ -78,22 +149,29 @@ var createBoardConversionContext = (circuitJson) => {
|
|
|
78
149
|
circuitJson,
|
|
79
150
|
runtimeNetNameBySourceNetId
|
|
80
151
|
});
|
|
152
|
+
const pcbPortSelectorsBySourcePortId = /* @__PURE__ */ new Map();
|
|
81
153
|
const pcbPortSelectorsByRuntimeNetName = /* @__PURE__ */ new Map();
|
|
82
154
|
for (const [pcbPortId, sourcePortId] of sourcePortIdByPcbPortId) {
|
|
83
155
|
const portHint = portHintByPcbPortId.get(pcbPortId);
|
|
84
156
|
if (!portHint) continue;
|
|
157
|
+
const selector = `.${pcbChipName} > .${portHint}`;
|
|
158
|
+
const sourcePortSelectors = pcbPortSelectorsBySourcePortId.get(sourcePortId) ?? [];
|
|
159
|
+
sourcePortSelectors.push(selector);
|
|
160
|
+
pcbPortSelectorsBySourcePortId.set(sourcePortId, sourcePortSelectors);
|
|
85
161
|
for (const runtimeNetName of runtimeNetNamesBySourcePortId.get(
|
|
86
162
|
sourcePortId
|
|
87
163
|
) ?? []) {
|
|
88
164
|
const selectors = pcbPortSelectorsByRuntimeNetName.get(runtimeNetName) ?? [];
|
|
89
|
-
selectors.push(
|
|
165
|
+
selectors.push(selector);
|
|
90
166
|
pcbPortSelectorsByRuntimeNetName.set(runtimeNetName, selectors);
|
|
91
167
|
}
|
|
92
168
|
}
|
|
93
169
|
return {
|
|
94
|
-
pcbChipName
|
|
170
|
+
pcbChipName,
|
|
171
|
+
pcbPortIdsWithUnambiguousComponentSelectors: /* @__PURE__ */ new Set(),
|
|
95
172
|
portHintByPcbPortId,
|
|
96
173
|
runtimeNetNameBySourceNetId,
|
|
174
|
+
pcbPortSelectorsBySourcePortId,
|
|
97
175
|
pcbPortSelectorsByRuntimeNetName
|
|
98
176
|
};
|
|
99
177
|
};
|
|
@@ -140,6 +218,206 @@ var getRuntimeNetNamesBySourcePortId = ({
|
|
|
140
218
|
return result;
|
|
141
219
|
};
|
|
142
220
|
|
|
221
|
+
// lib/board-converter/create-component-preserving-board-conversion-context.ts
|
|
222
|
+
function createComponentPreservingBoardConversionContext({
|
|
223
|
+
circuitJson,
|
|
224
|
+
pcbChipName,
|
|
225
|
+
pcbComponentRuntimeNameByPcbComponentId
|
|
226
|
+
}) {
|
|
227
|
+
const context = createBoardConversionContext({ circuitJson, pcbChipName });
|
|
228
|
+
const pcbComponentsById = /* @__PURE__ */ new Map();
|
|
229
|
+
for (const element of circuitJson) {
|
|
230
|
+
if (element.type === "pcb_component") {
|
|
231
|
+
pcbComponentsById.set(element.pcb_component_id, element);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
const pcbPortSelectorsBySourcePortId = /* @__PURE__ */ new Map();
|
|
235
|
+
const pcbPortIdsWithUnambiguousComponentSelectors = new Set(
|
|
236
|
+
circuitJson.flatMap((element) => {
|
|
237
|
+
if (element.type !== "pcb_port") return [];
|
|
238
|
+
const pcbComponent = element.pcb_component_id ? pcbComponentsById.get(element.pcb_component_id) : void 0;
|
|
239
|
+
return pcbComponent && pcbComponentRuntimeNameByPcbComponentId.has(
|
|
240
|
+
pcbComponent.pcb_component_id
|
|
241
|
+
) ? [element.pcb_port_id] : [];
|
|
242
|
+
})
|
|
243
|
+
);
|
|
244
|
+
for (const element of circuitJson) {
|
|
245
|
+
if (element.type !== "pcb_port") continue;
|
|
246
|
+
const pcbComponent = element.pcb_component_id ? pcbComponentsById.get(element.pcb_component_id) : void 0;
|
|
247
|
+
const portHint = context.portHintByPcbPortId.get(element.pcb_port_id);
|
|
248
|
+
if (!portHint) continue;
|
|
249
|
+
const componentName = pcbComponent ? pcbComponentRuntimeNameByPcbComponentId.get(
|
|
250
|
+
pcbComponent.pcb_component_id
|
|
251
|
+
) : void 0;
|
|
252
|
+
const selectors = pcbPortSelectorsBySourcePortId.get(element.source_port_id) ?? [];
|
|
253
|
+
selectors.push(`.${componentName ?? context.pcbChipName} > .${portHint}`);
|
|
254
|
+
pcbPortSelectorsBySourcePortId.set(element.source_port_id, selectors);
|
|
255
|
+
}
|
|
256
|
+
const pcbPortSelectorsByRuntimeNetName = /* @__PURE__ */ new Map();
|
|
257
|
+
for (const element of circuitJson) {
|
|
258
|
+
if (element.type !== "source_trace") continue;
|
|
259
|
+
for (const sourceNetId of element.connected_source_net_ids) {
|
|
260
|
+
const runtimeNetName = context.runtimeNetNameBySourceNetId.get(sourceNetId);
|
|
261
|
+
if (!runtimeNetName) continue;
|
|
262
|
+
const selectors = pcbPortSelectorsByRuntimeNetName.get(runtimeNetName) ?? [];
|
|
263
|
+
for (const sourcePortId of element.connected_source_port_ids) {
|
|
264
|
+
for (const selector of pcbPortSelectorsBySourcePortId.get(
|
|
265
|
+
sourcePortId
|
|
266
|
+
) ?? []) {
|
|
267
|
+
if (!selectors.includes(selector)) selectors.push(selector);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
pcbPortSelectorsByRuntimeNetName.set(runtimeNetName, selectors);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return {
|
|
274
|
+
...context,
|
|
275
|
+
pcbPortIdsWithUnambiguousComponentSelectors,
|
|
276
|
+
pcbPortSelectorsBySourcePortId,
|
|
277
|
+
pcbPortSelectorsByRuntimeNetName
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// lib/generate-board-cad-models-tsx/get-cad-model-url.ts
|
|
282
|
+
function getCadModelUrl(cadComponent) {
|
|
283
|
+
if (cadComponent.model_glb_url) {
|
|
284
|
+
return { format: "glb", url: cadComponent.model_glb_url };
|
|
285
|
+
}
|
|
286
|
+
if (cadComponent.model_gltf_url) {
|
|
287
|
+
return { format: "gltf", url: cadComponent.model_gltf_url };
|
|
288
|
+
}
|
|
289
|
+
if (cadComponent.model_obj_url) {
|
|
290
|
+
return { format: "obj", url: cadComponent.model_obj_url };
|
|
291
|
+
}
|
|
292
|
+
if (cadComponent.model_step_url) {
|
|
293
|
+
return { format: "step", url: cadComponent.model_step_url };
|
|
294
|
+
}
|
|
295
|
+
if (cadComponent.model_stl_url) {
|
|
296
|
+
return { format: "stl", url: cadComponent.model_stl_url };
|
|
297
|
+
}
|
|
298
|
+
if (cadComponent.model_wrl_url) {
|
|
299
|
+
return { format: "wrl", url: cadComponent.model_wrl_url };
|
|
300
|
+
}
|
|
301
|
+
return void 0;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// lib/generate-board-cad-models-tsx/has-cad-model-source.ts
|
|
305
|
+
function hasCadModelSource(cadComponent) {
|
|
306
|
+
return cadComponent.model_jscad !== void 0 || getCadModelUrl(cadComponent) !== void 0;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// lib/generate-board-cad-models-tsx/get-cad-model-groups.ts
|
|
310
|
+
function getCadModelGroups(circuitJson) {
|
|
311
|
+
const pcbComponentById = /* @__PURE__ */ new Map();
|
|
312
|
+
for (const element of circuitJson) {
|
|
313
|
+
if (element.type === "pcb_component") {
|
|
314
|
+
pcbComponentById.set(element.pcb_component_id, element);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
const cadModelGroupByKey = /* @__PURE__ */ new Map();
|
|
318
|
+
for (const element of circuitJson) {
|
|
319
|
+
if (element.type !== "cad_component" || !hasCadModelSource(element))
|
|
320
|
+
continue;
|
|
321
|
+
const pcbComponent = element.pcb_component_id ? pcbComponentById.get(element.pcb_component_id) : void 0;
|
|
322
|
+
const layer = (element.layer ?? pcbComponent?.layer) === "bottom" ? "bottom" : "top";
|
|
323
|
+
let parentPlacement = {
|
|
324
|
+
center: element.position,
|
|
325
|
+
ccwRotationDegrees: 0,
|
|
326
|
+
layer
|
|
327
|
+
};
|
|
328
|
+
let cadModelGroupKey = element.cad_component_id;
|
|
329
|
+
if (pcbComponent !== void 0) {
|
|
330
|
+
parentPlacement = {
|
|
331
|
+
center: pcbComponent.center,
|
|
332
|
+
ccwRotationDegrees: pcbComponent.rotation,
|
|
333
|
+
layer
|
|
334
|
+
};
|
|
335
|
+
cadModelGroupKey = `${pcbComponent.pcb_component_id}:${layer}`;
|
|
336
|
+
}
|
|
337
|
+
const cadModelGroup = cadModelGroupByKey.get(cadModelGroupKey) ?? {
|
|
338
|
+
cadComponents: [],
|
|
339
|
+
parentPlacement
|
|
340
|
+
};
|
|
341
|
+
cadModelGroup.cadComponents.push(element);
|
|
342
|
+
cadModelGroupByKey.set(cadModelGroupKey, cadModelGroup);
|
|
343
|
+
}
|
|
344
|
+
return [...cadModelGroupByKey.values()];
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// lib/board-converter/get-board-child-runtime-names.ts
|
|
348
|
+
var getUnusedRuntimeName = ({
|
|
349
|
+
preferredRuntimeName,
|
|
350
|
+
usedRuntimeNames
|
|
351
|
+
}) => {
|
|
352
|
+
if (!usedRuntimeNames.has(preferredRuntimeName)) return preferredRuntimeName;
|
|
353
|
+
let duplicateNumber = 2;
|
|
354
|
+
while (usedRuntimeNames.has(`${preferredRuntimeName}_${duplicateNumber}`)) {
|
|
355
|
+
duplicateNumber += 1;
|
|
356
|
+
}
|
|
357
|
+
return `${preferredRuntimeName}_${duplicateNumber}`;
|
|
358
|
+
};
|
|
359
|
+
var getBoardChildRuntimeNames = (circuitJson) => {
|
|
360
|
+
const sourceComponentBySourceComponentId = /* @__PURE__ */ new Map();
|
|
361
|
+
for (const element of circuitJson) {
|
|
362
|
+
if (element.type === "source_component" && !sourceComponentBySourceComponentId.has(element.source_component_id)) {
|
|
363
|
+
sourceComponentBySourceComponentId.set(
|
|
364
|
+
element.source_component_id,
|
|
365
|
+
element
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
const usedRuntimeNames = /* @__PURE__ */ new Set();
|
|
370
|
+
const pcbComponentRuntimeNameByPcbComponentId = /* @__PURE__ */ new Map();
|
|
371
|
+
const pcbComponents = circuitJson.filter(
|
|
372
|
+
(element) => element.type === "pcb_component"
|
|
373
|
+
);
|
|
374
|
+
for (const [pcbComponentIndex, pcbComponent] of pcbComponents.entries()) {
|
|
375
|
+
const sourceComponent = pcbComponent.source_component_id ? sourceComponentBySourceComponentId.get(pcbComponent.source_component_id) : void 0;
|
|
376
|
+
const preferredRuntimeName = sourceComponent?.name ?? `imported_component_${pcbComponentIndex + 1}`;
|
|
377
|
+
const runtimeName = getUnusedRuntimeName({
|
|
378
|
+
preferredRuntimeName,
|
|
379
|
+
usedRuntimeNames
|
|
380
|
+
});
|
|
381
|
+
usedRuntimeNames.add(runtimeName);
|
|
382
|
+
pcbComponentRuntimeNameByPcbComponentId.set(
|
|
383
|
+
pcbComponent.pcb_component_id,
|
|
384
|
+
runtimeName
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
const pcbChipName = getUnusedRuntimeName({
|
|
388
|
+
preferredRuntimeName: DEFAULT_PCB_CHIP_NAME,
|
|
389
|
+
usedRuntimeNames
|
|
390
|
+
});
|
|
391
|
+
usedRuntimeNames.add(pcbChipName);
|
|
392
|
+
const standaloneCadModelRuntimeNameByCadComponentId = /* @__PURE__ */ new Map();
|
|
393
|
+
const standaloneCadModelGroups = getCadModelGroups(circuitJson).filter(
|
|
394
|
+
(cadModelGroup) => cadModelGroup.cadComponents.every(
|
|
395
|
+
(cadComponent) => cadComponent.pcb_component_id === void 0
|
|
396
|
+
)
|
|
397
|
+
);
|
|
398
|
+
for (const [
|
|
399
|
+
groupIndex,
|
|
400
|
+
cadModelGroup
|
|
401
|
+
] of standaloneCadModelGroups.entries()) {
|
|
402
|
+
const firstCadComponent = cadModelGroup.cadComponents[0];
|
|
403
|
+
if (!firstCadComponent) continue;
|
|
404
|
+
const runtimeName = getUnusedRuntimeName({
|
|
405
|
+
preferredRuntimeName: `ImportedCadModel${groupIndex + 1}`,
|
|
406
|
+
usedRuntimeNames
|
|
407
|
+
});
|
|
408
|
+
usedRuntimeNames.add(runtimeName);
|
|
409
|
+
standaloneCadModelRuntimeNameByCadComponentId.set(
|
|
410
|
+
firstCadComponent.cad_component_id,
|
|
411
|
+
runtimeName
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
return {
|
|
415
|
+
pcbChipName,
|
|
416
|
+
pcbComponentRuntimeNameByPcbComponentId,
|
|
417
|
+
standaloneCadModelRuntimeNameByCadComponentId
|
|
418
|
+
};
|
|
419
|
+
};
|
|
420
|
+
|
|
143
421
|
// lib/generate-board-cad-models-tsx/format-point-prop.ts
|
|
144
422
|
function formatPointProp(point) {
|
|
145
423
|
return `{ x: ${point.x}, y: ${point.y}, z: ${point.z} }`;
|
|
@@ -192,54 +470,18 @@ function getCadModelPlacement({
|
|
|
192
470
|
};
|
|
193
471
|
}
|
|
194
472
|
|
|
195
|
-
// lib/generate-board-cad-models-tsx/get-cad-model-
|
|
196
|
-
function
|
|
197
|
-
if (cadComponent.model_glb_url) {
|
|
198
|
-
return { format: "glb", url: cadComponent.model_glb_url };
|
|
199
|
-
}
|
|
200
|
-
if (cadComponent.model_gltf_url) {
|
|
201
|
-
return { format: "gltf", url: cadComponent.model_gltf_url };
|
|
202
|
-
}
|
|
203
|
-
if (cadComponent.model_obj_url) {
|
|
204
|
-
return { format: "obj", url: cadComponent.model_obj_url };
|
|
205
|
-
}
|
|
206
|
-
if (cadComponent.model_step_url) {
|
|
207
|
-
return { format: "step", url: cadComponent.model_step_url };
|
|
208
|
-
}
|
|
209
|
-
if (cadComponent.model_stl_url) {
|
|
210
|
-
return { format: "stl", url: cadComponent.model_stl_url };
|
|
211
|
-
}
|
|
212
|
-
if (cadComponent.model_wrl_url) {
|
|
213
|
-
return { format: "wrl", url: cadComponent.model_wrl_url };
|
|
214
|
-
}
|
|
215
|
-
return void 0;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
// lib/generate-board-cad-models-tsx/get-model-url-with-format-hint.ts
|
|
219
|
-
function getModelUrlWithFormatHint({
|
|
220
|
-
format,
|
|
221
|
-
url
|
|
222
|
-
}) {
|
|
223
|
-
const pathWithoutQuery = url.split(/[?#]/u)[0] ?? "";
|
|
224
|
-
if (pathWithoutQuery.toLowerCase().endsWith(`.${format}`)) return url;
|
|
225
|
-
return `${url}#ext=${format}`;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
// lib/generate-board-cad-models-tsx/generate-cad-model-tsx.ts
|
|
229
|
-
function generateCadModelTsx({
|
|
473
|
+
// lib/generate-board-cad-models-tsx/get-cad-model-placement-attributes.ts
|
|
474
|
+
function getCadModelPlacementAttributes({
|
|
230
475
|
cadComponent,
|
|
231
476
|
parentPlacement,
|
|
232
477
|
pcbBoard
|
|
233
478
|
}) {
|
|
234
|
-
const modelUrl = getCadModelUrl(cadComponent);
|
|
235
|
-
if (!modelUrl) return void 0;
|
|
236
479
|
const placement = getCadModelPlacement({
|
|
237
480
|
cadComponent,
|
|
238
481
|
parentPlacement,
|
|
239
482
|
pcbBoard
|
|
240
483
|
});
|
|
241
484
|
const attributes = [
|
|
242
|
-
`modelUrl={${JSON.stringify(getModelUrlWithFormatHint(modelUrl))}}`,
|
|
243
485
|
`positionOffset={${formatPointProp(placement.positionOffset)}}`,
|
|
244
486
|
`rotationOffset={${formatPointProp(placement.ccwRotationOffsetDegrees)}}`
|
|
245
487
|
];
|
|
@@ -265,32 +507,96 @@ function generateCadModelTsx({
|
|
|
265
507
|
if (cadComponent.show_as_translucent_model === true) {
|
|
266
508
|
attributes.push("showAsTranslucentModel");
|
|
267
509
|
}
|
|
510
|
+
return attributes;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// lib/generate-board-cad-models-tsx/get-model-url-with-format-hint.ts
|
|
514
|
+
function getModelUrlWithFormatHint({
|
|
515
|
+
format,
|
|
516
|
+
url
|
|
517
|
+
}) {
|
|
518
|
+
const pathWithoutQuery = url.split(/[?#]/u)[0] ?? "";
|
|
519
|
+
if (pathWithoutQuery.toLowerCase().endsWith(`.${format}`)) return url;
|
|
520
|
+
return `${url}#ext=${format}`;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
// lib/generate-board-cad-models-tsx/generate-cad-model-tsx.ts
|
|
524
|
+
function generateCadModelTsx({
|
|
525
|
+
cadComponent,
|
|
526
|
+
parentPlacement,
|
|
527
|
+
pcbBoard
|
|
528
|
+
}) {
|
|
529
|
+
const modelUrl = getCadModelUrl(cadComponent);
|
|
530
|
+
if (!modelUrl) return void 0;
|
|
531
|
+
const attributes = [
|
|
532
|
+
`modelUrl={${JSON.stringify(getModelUrlWithFormatHint(modelUrl))}}`,
|
|
533
|
+
...getCadModelPlacementAttributes({
|
|
534
|
+
cadComponent,
|
|
535
|
+
parentPlacement,
|
|
536
|
+
pcbBoard
|
|
537
|
+
})
|
|
538
|
+
];
|
|
268
539
|
return `<cadmodel ${attributes.join(" ")} />`;
|
|
269
540
|
}
|
|
270
541
|
|
|
271
|
-
// lib/generate-board-cad-models-tsx/generate-cad-model-
|
|
272
|
-
function
|
|
273
|
-
|
|
274
|
-
|
|
542
|
+
// lib/generate-board-cad-models-tsx/generate-jscad-cad-model-tsx.ts
|
|
543
|
+
function generateJscadCadModelTsx({
|
|
544
|
+
cadComponent,
|
|
545
|
+
parentPlacement,
|
|
275
546
|
pcbBoard
|
|
276
547
|
}) {
|
|
277
|
-
|
|
278
|
-
const
|
|
279
|
-
|
|
548
|
+
if (cadComponent.model_jscad === void 0) return void 0;
|
|
549
|
+
const attributes = [
|
|
550
|
+
`jscad={${JSON.stringify(cadComponent.model_jscad)}}`,
|
|
551
|
+
...getCadModelPlacementAttributes({
|
|
280
552
|
cadComponent,
|
|
281
553
|
parentPlacement,
|
|
282
554
|
pcbBoard
|
|
283
|
-
})
|
|
284
|
-
|
|
555
|
+
})
|
|
556
|
+
];
|
|
557
|
+
return `<cadmodel ${attributes.join(" ")} />`;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
// lib/generate-board-cad-models-tsx/generate-cad-model-group-model-tsx.ts
|
|
561
|
+
var generateCadModelElementsTsx = ({
|
|
562
|
+
cadModelGroup,
|
|
563
|
+
pcbBoard
|
|
564
|
+
}) => cadModelGroup.cadComponents.flatMap((cadComponent) => {
|
|
565
|
+
const modelElementGenerator = cadComponent.model_jscad === void 0 ? generateCadModelTsx : generateJscadCadModelTsx;
|
|
566
|
+
const modelElement = modelElementGenerator({
|
|
567
|
+
cadComponent,
|
|
568
|
+
parentPlacement: cadModelGroup.parentPlacement,
|
|
569
|
+
pcbBoard
|
|
570
|
+
});
|
|
571
|
+
return modelElement ? [modelElement] : [];
|
|
572
|
+
});
|
|
573
|
+
function generateCadModelGroupModelTsx({
|
|
574
|
+
cadModelGroup,
|
|
575
|
+
pcbBoard
|
|
576
|
+
}) {
|
|
577
|
+
const modelElements = generateCadModelElementsTsx({
|
|
578
|
+
cadModelGroup,
|
|
579
|
+
pcbBoard
|
|
285
580
|
});
|
|
286
581
|
if (modelElements.length === 0) return void 0;
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
582
|
+
if (modelElements.length === 1) return modelElements[0];
|
|
583
|
+
return `<cadassembly>${modelElements.join("\n")}</cadassembly>`;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
// lib/generate-board-cad-models-tsx/generate-cad-model-group-tsx.ts
|
|
587
|
+
function generateCadModelGroupTsx({
|
|
588
|
+
cadModelGroup,
|
|
589
|
+
pcbBoard,
|
|
590
|
+
runtimeName
|
|
591
|
+
}) {
|
|
592
|
+
const { parentPlacement } = cadModelGroup;
|
|
593
|
+
const cadModelTsx = generateCadModelGroupModelTsx({
|
|
594
|
+
cadModelGroup,
|
|
595
|
+
pcbBoard
|
|
596
|
+
});
|
|
291
597
|
if (!cadModelTsx) return void 0;
|
|
292
598
|
const attributes = [
|
|
293
|
-
`name={${JSON.stringify(
|
|
599
|
+
`name={${JSON.stringify(runtimeName)}}`,
|
|
294
600
|
`pcbX={${parentPlacement.center.x}}`,
|
|
295
601
|
`pcbY={${parentPlacement.center.y}}`,
|
|
296
602
|
`pcbRotation="${parentPlacement.ccwRotationDegrees}deg"`,
|
|
@@ -303,71 +609,131 @@ function generateCadModelGroupTsx({
|
|
|
303
609
|
return `<chip ${attributes.join(" ")} />`;
|
|
304
610
|
}
|
|
305
611
|
|
|
306
|
-
// lib/
|
|
307
|
-
|
|
308
|
-
const pcbComponentById = /* @__PURE__ */ new Map();
|
|
309
|
-
for (const element of circuitJson) {
|
|
310
|
-
if (element.type === "pcb_component") {
|
|
311
|
-
pcbComponentById.set(element.pcb_component_id, element);
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
const cadModelGroupByKey = /* @__PURE__ */ new Map();
|
|
315
|
-
for (const element of circuitJson) {
|
|
316
|
-
if (element.type !== "cad_component" || !getCadModelUrl(element)) continue;
|
|
317
|
-
const pcbComponent = element.pcb_component_id ? pcbComponentById.get(element.pcb_component_id) : void 0;
|
|
318
|
-
const layer = (element.layer ?? pcbComponent?.layer) === "bottom" ? "bottom" : "top";
|
|
319
|
-
let parentPlacement = {
|
|
320
|
-
center: element.position,
|
|
321
|
-
ccwRotationDegrees: 0,
|
|
322
|
-
layer
|
|
323
|
-
};
|
|
324
|
-
let cadModelGroupKey = element.cad_component_id;
|
|
325
|
-
if (pcbComponent !== void 0) {
|
|
326
|
-
parentPlacement = {
|
|
327
|
-
center: pcbComponent.center,
|
|
328
|
-
ccwRotationDegrees: pcbComponent.rotation,
|
|
329
|
-
layer
|
|
330
|
-
};
|
|
331
|
-
cadModelGroupKey = `${pcbComponent.pcb_component_id}:${layer}`;
|
|
332
|
-
}
|
|
333
|
-
const cadModelGroup = cadModelGroupByKey.get(cadModelGroupKey) ?? {
|
|
334
|
-
cadComponents: [],
|
|
335
|
-
parentPlacement
|
|
336
|
-
};
|
|
337
|
-
cadModelGroup.cadComponents.push(element);
|
|
338
|
-
cadModelGroupByKey.set(cadModelGroupKey, cadModelGroup);
|
|
339
|
-
}
|
|
340
|
-
return [...cadModelGroupByKey.values()];
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
// lib/generate-board-cad-models-tsx.ts
|
|
344
|
-
function generateBoardCadModelsTsx({
|
|
612
|
+
// lib/board-converter/stages/convert-board-cad-models.ts
|
|
613
|
+
var convertBoardCadModels = ({
|
|
345
614
|
circuitJson,
|
|
346
|
-
pcbBoard
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
615
|
+
pcbBoard,
|
|
616
|
+
boardChildren,
|
|
617
|
+
standaloneCadModelRuntimeNameByCadComponentId
|
|
618
|
+
}) => {
|
|
619
|
+
const standaloneCadModelGroups = getCadModelGroups(circuitJson).filter(
|
|
620
|
+
(cadModelGroup) => cadModelGroup.cadComponents.every(
|
|
621
|
+
(cadComponent) => cadComponent.pcb_component_id === void 0
|
|
622
|
+
)
|
|
623
|
+
);
|
|
624
|
+
for (const cadModelGroup of standaloneCadModelGroups) {
|
|
625
|
+
const firstCadComponent = cadModelGroup.cadComponents[0];
|
|
626
|
+
if (!firstCadComponent) continue;
|
|
627
|
+
const runtimeName = standaloneCadModelRuntimeNameByCadComponentId.get(
|
|
628
|
+
firstCadComponent.cad_component_id
|
|
629
|
+
);
|
|
630
|
+
if (!runtimeName) {
|
|
631
|
+
throw new Error(
|
|
632
|
+
`Missing runtime name for standalone CAD model ${firstCadComponent.cad_component_id}`
|
|
633
|
+
);
|
|
634
|
+
}
|
|
350
635
|
const cadModelGroupTsx = generateCadModelGroupTsx({
|
|
351
636
|
cadModelGroup,
|
|
352
|
-
|
|
353
|
-
|
|
637
|
+
pcbBoard,
|
|
638
|
+
runtimeName
|
|
354
639
|
});
|
|
355
|
-
|
|
356
|
-
}
|
|
357
|
-
}
|
|
640
|
+
if (cadModelGroupTsx) boardChildren.push(cadModelGroupTsx);
|
|
641
|
+
}
|
|
642
|
+
};
|
|
358
643
|
|
|
359
644
|
// lib/generate-board-nets-tsx.ts
|
|
360
|
-
var generateBoardNetsTsx = (context) => {
|
|
361
|
-
const runtimeNetNames =
|
|
362
|
-
return
|
|
645
|
+
var generateBoardNetsTsx = (circuitJson, context) => {
|
|
646
|
+
const runtimeNetNames = getRuntimeNetNamesInTraceOrder(circuitJson, context);
|
|
647
|
+
return runtimeNetNames.map((runtimeNetName) => {
|
|
363
648
|
const selectors = context.pcbPortSelectorsByRuntimeNetName.get(runtimeNetName) ?? [];
|
|
364
649
|
const connectsTo = selectors.length ? ` connectsTo={${JSON.stringify(selectors)}}` : "";
|
|
365
650
|
return `<net name={${JSON.stringify(runtimeNetName)}}${connectsTo} />`;
|
|
366
651
|
});
|
|
367
652
|
};
|
|
653
|
+
var getRuntimeNetNamesInTraceOrder = (circuitJson, context) => {
|
|
654
|
+
const orderedNames = [];
|
|
655
|
+
const addedNames = /* @__PURE__ */ new Set();
|
|
656
|
+
for (const element of circuitJson) {
|
|
657
|
+
if (element.type !== "source_trace") continue;
|
|
658
|
+
for (const sourceNetId of element.connected_source_net_ids) {
|
|
659
|
+
const runtimeNetName = context.runtimeNetNameBySourceNetId.get(sourceNetId);
|
|
660
|
+
if (!runtimeNetName || addedNames.has(runtimeNetName)) continue;
|
|
661
|
+
orderedNames.push(runtimeNetName);
|
|
662
|
+
addedNames.add(runtimeNetName);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
for (const runtimeNetName of context.runtimeNetNameBySourceNetId.values()) {
|
|
666
|
+
if (addedNames.has(runtimeNetName)) continue;
|
|
667
|
+
orderedNames.push(runtimeNetName);
|
|
668
|
+
addedNames.add(runtimeNetName);
|
|
669
|
+
}
|
|
670
|
+
return orderedNames;
|
|
671
|
+
};
|
|
368
672
|
|
|
369
|
-
// lib/
|
|
673
|
+
// lib/board-converter/stages/convert-board-nets.ts
|
|
674
|
+
var convertBoardNets = ({
|
|
675
|
+
boardChildren,
|
|
676
|
+
boardProps,
|
|
677
|
+
circuitJson,
|
|
678
|
+
footprintConversionContext
|
|
679
|
+
}) => {
|
|
680
|
+
boardChildren.push(
|
|
681
|
+
...generateBoardNetsTsx(circuitJson, footprintConversionContext)
|
|
682
|
+
);
|
|
683
|
+
if (circuitJson.some((element) => element.type === "pcb_trace") && !boardProps.includes("routingDisabled")) {
|
|
684
|
+
boardProps.push("routingDisabled");
|
|
685
|
+
}
|
|
686
|
+
};
|
|
687
|
+
|
|
688
|
+
// lib/board-converter/stages/convert-board-properties.ts
|
|
370
689
|
import { mmStr } from "@tscircuit/mm";
|
|
690
|
+
var convertBoardProperties = ({
|
|
691
|
+
pcbBoard,
|
|
692
|
+
boardProps
|
|
693
|
+
}) => {
|
|
694
|
+
if (pcbBoard.center.x !== 0) {
|
|
695
|
+
boardProps.push(`pcbX={${pcbBoard.center.x}}`);
|
|
696
|
+
}
|
|
697
|
+
if (pcbBoard.center.y !== 0) {
|
|
698
|
+
boardProps.push(`pcbY={${pcbBoard.center.y}}`);
|
|
699
|
+
}
|
|
700
|
+
if (pcbBoard.width !== void 0) {
|
|
701
|
+
boardProps.push(`width="${mmStr(pcbBoard.width)}"`);
|
|
702
|
+
}
|
|
703
|
+
if (pcbBoard.height !== void 0) {
|
|
704
|
+
boardProps.push(`height="${mmStr(pcbBoard.height)}"`);
|
|
705
|
+
}
|
|
706
|
+
if (pcbBoard.outline && pcbBoard.outline.length > 0) {
|
|
707
|
+
const points = pcbBoard.outline.map((point) => `{ x: ${point.x}, y: ${point.y} }`).join(", ");
|
|
708
|
+
boardProps.push(`outline={[${points}]}`);
|
|
709
|
+
}
|
|
710
|
+
if (pcbBoard.thickness !== void 0) {
|
|
711
|
+
boardProps.push(`thickness="${mmStr(pcbBoard.thickness)}"`);
|
|
712
|
+
}
|
|
713
|
+
if (pcbBoard.num_layers !== void 0) {
|
|
714
|
+
boardProps.push(`layers={${pcbBoard.num_layers}}`);
|
|
715
|
+
}
|
|
716
|
+
if (pcbBoard.material !== void 0) {
|
|
717
|
+
boardProps.push(`material="${pcbBoard.material}"`);
|
|
718
|
+
}
|
|
719
|
+
if (pcbBoard.solder_mask_color !== void 0) {
|
|
720
|
+
boardProps.push(`solderMaskColor="${pcbBoard.solder_mask_color}"`);
|
|
721
|
+
}
|
|
722
|
+
if (pcbBoard.silkscreen_color !== void 0) {
|
|
723
|
+
boardProps.push(`silkscreenColor="${pcbBoard.silkscreen_color}"`);
|
|
724
|
+
}
|
|
725
|
+
if (pcbBoard.anchor_position !== void 0) {
|
|
726
|
+
boardProps.push(
|
|
727
|
+
`boardAnchorPosition={{ x: ${pcbBoard.anchor_position.x}, y: ${pcbBoard.anchor_position.y} }}`
|
|
728
|
+
);
|
|
729
|
+
}
|
|
730
|
+
if (pcbBoard.anchor_alignment !== void 0) {
|
|
731
|
+
boardProps.push(`boardAnchorAlignment="${pcbBoard.anchor_alignment}"`);
|
|
732
|
+
}
|
|
733
|
+
};
|
|
734
|
+
|
|
735
|
+
// lib/generate-board-schematic-sheet-tsx.ts
|
|
736
|
+
import { mmStr as mmStr2 } from "@tscircuit/mm";
|
|
371
737
|
var DEFAULT_SHEET_DIMENSIONS_MM = {
|
|
372
738
|
a4: { width: 297, height: 210 },
|
|
373
739
|
ansi_b: { width: 431.8, height: 279.4 }
|
|
@@ -391,8 +757,8 @@ var generateBoardSchematicSheetTsx = ({
|
|
|
391
757
|
const defaultDimensions = DEFAULT_SHEET_DIMENSIONS_MM[sheet.sheet_size ?? "a4"];
|
|
392
758
|
const sheetWidth = sheet.sheet_width ?? defaultDimensions.width;
|
|
393
759
|
const sheetHeight = sheet.sheet_height ?? defaultDimensions.height;
|
|
394
|
-
attrs.push(`sheetWidth="${
|
|
395
|
-
attrs.push(`sheetHeight="${
|
|
760
|
+
attrs.push(`sheetWidth="${mmStr2(sheetWidth)}"`);
|
|
761
|
+
attrs.push(`sheetHeight="${mmStr2(sheetHeight)}"`);
|
|
396
762
|
return `<schematicsheet ${attrs.join(" ")}>
|
|
397
763
|
${schematicElements.join("\n")}
|
|
398
764
|
</schematicsheet>`;
|
|
@@ -1589,6 +1955,51 @@ var generateBoardSchematicElements = (circuitJson) => {
|
|
|
1589
1955
|
];
|
|
1590
1956
|
};
|
|
1591
1957
|
|
|
1958
|
+
// lib/board-converter/stages/convert-board-schematic.ts
|
|
1959
|
+
var convertBoardSchematic = ({
|
|
1960
|
+
boardChildren,
|
|
1961
|
+
circuitJson
|
|
1962
|
+
}) => {
|
|
1963
|
+
const schematicElements = generateBoardSchematicElements(circuitJson);
|
|
1964
|
+
boardChildren.push(
|
|
1965
|
+
generateBoardSchematicSheetTsx({
|
|
1966
|
+
circuitJson,
|
|
1967
|
+
schematicElements
|
|
1968
|
+
})
|
|
1969
|
+
);
|
|
1970
|
+
};
|
|
1971
|
+
|
|
1972
|
+
// lib/generate-board-traces-tsx.ts
|
|
1973
|
+
function generateBoardTracesTsx(circuitJson, context) {
|
|
1974
|
+
return circuitJson.flatMap((element) => {
|
|
1975
|
+
if (element.type !== "source_trace") return [];
|
|
1976
|
+
const portSelectors = element.connected_source_port_ids.flatMap(
|
|
1977
|
+
(sourcePortId) => context.pcbPortSelectorsBySourcePortId.get(sourcePortId) ?? []
|
|
1978
|
+
);
|
|
1979
|
+
const netSelectors = [
|
|
1980
|
+
...new Set(
|
|
1981
|
+
element.connected_source_net_ids.flatMap((sourceNetId) => {
|
|
1982
|
+
const runtimeNetName = context.runtimeNetNameBySourceNetId.get(sourceNetId);
|
|
1983
|
+
return runtimeNetName ? [`net.${runtimeNetName}`] : [];
|
|
1984
|
+
})
|
|
1985
|
+
)
|
|
1986
|
+
];
|
|
1987
|
+
const path = [...portSelectors, ...netSelectors];
|
|
1988
|
+
return path.length >= 2 ? [`<trace path={${JSON.stringify(path)}} />`] : [];
|
|
1989
|
+
});
|
|
1990
|
+
}
|
|
1991
|
+
|
|
1992
|
+
// lib/board-converter/stages/convert-board-traces.ts
|
|
1993
|
+
var convertBoardTraces = ({
|
|
1994
|
+
boardChildren,
|
|
1995
|
+
circuitJson,
|
|
1996
|
+
footprintConversionContext
|
|
1997
|
+
}) => {
|
|
1998
|
+
boardChildren.push(
|
|
1999
|
+
...generateBoardTracesTsx(circuitJson, footprintConversionContext)
|
|
2000
|
+
);
|
|
2001
|
+
};
|
|
2002
|
+
|
|
1592
2003
|
// lib/generate-copper-pours-tsx.ts
|
|
1593
2004
|
import { su as su6 } from "@tscircuit/soup-util";
|
|
1594
2005
|
|
|
@@ -1798,6 +2209,26 @@ var getUnassignedCopperPourNetName = ({
|
|
|
1798
2209
|
return name;
|
|
1799
2210
|
};
|
|
1800
2211
|
|
|
2212
|
+
// lib/board-converter/stages/convert-copper-pours.ts
|
|
2213
|
+
var convertCopperPours = ({
|
|
2214
|
+
boardChildren,
|
|
2215
|
+
circuitJson,
|
|
2216
|
+
footprintConversionContext
|
|
2217
|
+
}) => {
|
|
2218
|
+
boardChildren.push(
|
|
2219
|
+
...generateCopperPoursTsx(circuitJson, footprintConversionContext)
|
|
2220
|
+
);
|
|
2221
|
+
};
|
|
2222
|
+
|
|
2223
|
+
// lib/format-jsx-string-attribute.ts
|
|
2224
|
+
var formatJsxStringAttribute = (text) => {
|
|
2225
|
+
const stringText = String(text ?? "");
|
|
2226
|
+
if (!/["\\\r\n\t{}<&>]/.test(stringText)) {
|
|
2227
|
+
return `"${stringText}"`;
|
|
2228
|
+
}
|
|
2229
|
+
return `{${JSON.stringify(stringText)}}`;
|
|
2230
|
+
};
|
|
2231
|
+
|
|
1801
2232
|
// lib/generate-footprint-tsx/convert-copper-text.ts
|
|
1802
2233
|
import { su as su7 } from "@tscircuit/soup-util";
|
|
1803
2234
|
|
|
@@ -1897,8 +2328,8 @@ var convertCourtyard = (circuitJson) => {
|
|
|
1897
2328
|
import { su as su9 } from "@tscircuit/soup-util";
|
|
1898
2329
|
|
|
1899
2330
|
// lib/generate-footprint-tsx/footprint-tsx-attribute-formatters/format-mm.ts
|
|
1900
|
-
import { mmStr as
|
|
1901
|
-
var formatMm = (value) =>
|
|
2331
|
+
import { mmStr as mmStr3 } from "@tscircuit/mm";
|
|
2332
|
+
var formatMm = (value) => mmStr3(value ?? 0);
|
|
1902
2333
|
|
|
1903
2334
|
// lib/generate-footprint-tsx/convert-cutouts.ts
|
|
1904
2335
|
var convertCutouts = (circuitJson) => {
|
|
@@ -2043,26 +2474,26 @@ var convertFabrication = (circuitJson) => {
|
|
|
2043
2474
|
|
|
2044
2475
|
// lib/generate-footprint-tsx/convert-holes.ts
|
|
2045
2476
|
import { su as su11 } from "@tscircuit/soup-util";
|
|
2046
|
-
import { mmStr as
|
|
2477
|
+
import { mmStr as mmStr4 } from "@tscircuit/mm";
|
|
2047
2478
|
var convertHoles = (circuitJson) => {
|
|
2048
2479
|
const holes = su11(circuitJson).pcb_hole.list();
|
|
2049
2480
|
const elementStrings = [];
|
|
2050
2481
|
for (const hole of holes) {
|
|
2051
2482
|
if (hole.hole_shape === "circle") {
|
|
2052
2483
|
elementStrings.push(
|
|
2053
|
-
`<hole pcbX="${
|
|
2484
|
+
`<hole pcbX="${mmStr4(hole.x)}" pcbY="${mmStr4(hole.y)}" diameter="${mmStr4(hole.hole_diameter)}" />`
|
|
2054
2485
|
);
|
|
2055
2486
|
} else if (hole.hole_shape === "rect") {
|
|
2056
2487
|
elementStrings.push(
|
|
2057
|
-
`<hole pcbX="${
|
|
2488
|
+
`<hole pcbX="${mmStr4(hole.x)}" pcbY="${mmStr4(hole.y)}" width="${mmStr4(hole.hole_width)}" height="${mmStr4(hole.hole_height)}" shape="rect" />`
|
|
2058
2489
|
);
|
|
2059
2490
|
} else if (hole.hole_shape === "oval") {
|
|
2060
2491
|
elementStrings.push(
|
|
2061
|
-
`<hole pcbX="${
|
|
2492
|
+
`<hole pcbX="${mmStr4(hole.x)}" pcbY="${mmStr4(hole.y)}" width="${mmStr4(hole.hole_width)}" height="${mmStr4(hole.hole_height)}" shape="oval" />`
|
|
2062
2493
|
);
|
|
2063
2494
|
} else if (hole.hole_shape === "pill" || hole.hole_shape === "rotated_pill") {
|
|
2064
2495
|
elementStrings.push(
|
|
2065
|
-
`<hole pcbX="${
|
|
2496
|
+
`<hole pcbX="${mmStr4(hole.x)}" pcbY="${mmStr4(hole.y)}" width="${mmStr4(hole.hole_width)}" height="${mmStr4(hole.hole_height)}" shape="pill"${formatPcbRotationAttr("ccw_rotation" in hole ? hole.ccw_rotation : void 0)} />`
|
|
2066
2497
|
);
|
|
2067
2498
|
}
|
|
2068
2499
|
}
|
|
@@ -2276,13 +2707,13 @@ var convertPcbTraces = (circuitJson) => su14(circuitJson).pcb_trace.list().map((
|
|
|
2276
2707
|
|
|
2277
2708
|
// lib/generate-footprint-tsx/convert-plated-holes.ts
|
|
2278
2709
|
import { su as su15 } from "@tscircuit/soup-util";
|
|
2279
|
-
import { mmStr as
|
|
2710
|
+
import { mmStr as mmStr6 } from "@tscircuit/mm";
|
|
2280
2711
|
|
|
2281
2712
|
// lib/generate-footprint-tsx/footprint-tsx-attribute-formatters/format-optional-mm-attr.ts
|
|
2282
|
-
import { mmStr as
|
|
2713
|
+
import { mmStr as mmStr5 } from "@tscircuit/mm";
|
|
2283
2714
|
var formatOptionalMmAttr = (attrName, value) => {
|
|
2284
2715
|
if (value === void 0) return "";
|
|
2285
|
-
return ` ${attrName}="${
|
|
2716
|
+
return ` ${attrName}="${mmStr5(value)}"`;
|
|
2286
2717
|
};
|
|
2287
2718
|
|
|
2288
2719
|
// lib/generate-footprint-tsx/footprint-tsx-attribute-formatters/format-solder-mask-attrs.ts
|
|
@@ -2298,7 +2729,13 @@ var formatSolderMaskAttrs = (platedHole) => {
|
|
|
2298
2729
|
var getImportedPortHints = (primitive, context) => {
|
|
2299
2730
|
if (!primitive.pcb_port_id || !context) return primitive.port_hints;
|
|
2300
2731
|
const importedHint = context.portHintByPcbPortId.get(primitive.pcb_port_id);
|
|
2301
|
-
|
|
2732
|
+
if (!importedHint) return primitive.port_hints;
|
|
2733
|
+
if (!context.pcbPortIdsWithUnambiguousComponentSelectors.has(
|
|
2734
|
+
primitive.pcb_port_id
|
|
2735
|
+
)) {
|
|
2736
|
+
return [importedHint];
|
|
2737
|
+
}
|
|
2738
|
+
return [.../* @__PURE__ */ new Set([importedHint, ...primitive.port_hints ?? []])];
|
|
2302
2739
|
};
|
|
2303
2740
|
|
|
2304
2741
|
// lib/generate-footprint-tsx/convert-plated-holes.ts
|
|
@@ -2311,26 +2748,26 @@ var convertPlatedHoles = (circuitJson, context) => {
|
|
|
2311
2748
|
const tagSpacing = context ? " " : " ";
|
|
2312
2749
|
if (platedHole.shape === "oval" || platedHole.shape === "pill") {
|
|
2313
2750
|
elementStrings.push(
|
|
2314
|
-
`<platedhole${tagSpacing}${portHintsAttr} pcbX="${
|
|
2751
|
+
`<platedhole${tagSpacing}${portHintsAttr} pcbX="${mmStr6(platedHole.x)}" pcbY="${mmStr6(platedHole.y)}"${formatSolderMaskAttrs(platedHole)} outerHeight="${mmStr6(platedHole.outer_height)}" outerWidth="${mmStr6(platedHole.outer_width)}" holeHeight="${mmStr6(platedHole.hole_height)}" holeWidth="${mmStr6(platedHole.hole_width)}" height="${mmStr6(platedHole.hole_height)}" shape="${platedHole.shape}"${formatPcbRotationAttr("ccw_rotation" in platedHole ? platedHole.ccw_rotation : void 0)} />`
|
|
2315
2752
|
);
|
|
2316
2753
|
} else if (platedHole.shape === "circle") {
|
|
2317
2754
|
elementStrings.push(
|
|
2318
|
-
`<platedhole${tagSpacing}${portHintsAttr} pcbX="${
|
|
2755
|
+
`<platedhole${tagSpacing}${portHintsAttr} pcbX="${mmStr6(platedHole.x)}" pcbY="${mmStr6(platedHole.y)}"${formatSolderMaskAttrs(platedHole)} outerDiameter="${mmStr6(platedHole.outer_diameter)}" holeDiameter="${mmStr6(platedHole.hole_diameter)}" shape="circle" />`
|
|
2319
2756
|
);
|
|
2320
2757
|
} else if (platedHole.shape === "circular_hole_with_rect_pad") {
|
|
2321
2758
|
elementStrings.push(
|
|
2322
|
-
`<platedhole${tagSpacing}${portHintsAttr} pcbX="${
|
|
2759
|
+
`<platedhole${tagSpacing}${portHintsAttr} pcbX="${mmStr6(platedHole.x)}" pcbY="${mmStr6(platedHole.y)}"${platedHole.hole_shape === void 0 ? "" : ` holeShape="${platedHole.hole_shape}"`}${platedHole.pad_shape === void 0 ? "" : ` padShape="${platedHole.pad_shape}"`}${formatSolderMaskAttrs(platedHole)} holeDiameter="${mmStr6(platedHole.hole_diameter)}" rectPadWidth="${mmStr6(platedHole.rect_pad_width)}" rectPadHeight="${mmStr6(platedHole.rect_pad_height)}"${formatOptionalMmAttr("rectBorderRadius", platedHole.rect_border_radius)}${formatOptionalMmAttr("holeOffsetX", platedHole.hole_offset_x)}${formatOptionalMmAttr("holeOffsetY", platedHole.hole_offset_y)}${formatPcbRotationAttr(platedHole.rect_ccw_rotation)} shape="circular_hole_with_rect_pad" />`
|
|
2323
2760
|
);
|
|
2324
2761
|
} else if (platedHole.shape === "pill_hole_with_rect_pad" || platedHole.shape === "rotated_pill_hole_with_rect_pad") {
|
|
2325
2762
|
const holeShape = platedHole.shape === "rotated_pill_hole_with_rect_pad" ? "pill" : platedHole.hole_shape;
|
|
2326
2763
|
const rotation = platedHole.shape === "rotated_pill_hole_with_rect_pad" ? platedHole.hole_ccw_rotation : void 0;
|
|
2327
2764
|
elementStrings.push(
|
|
2328
|
-
`<platedhole${tagSpacing}${portHintsAttr} pcbX="${
|
|
2765
|
+
`<platedhole${tagSpacing}${portHintsAttr} pcbX="${mmStr6(platedHole.x)}" pcbY="${mmStr6(platedHole.y)}"${holeShape === void 0 ? "" : ` holeShape="${holeShape}"`}${platedHole.pad_shape === void 0 ? "" : ` padShape="${platedHole.pad_shape}"`}${formatSolderMaskAttrs(platedHole)} holeWidth="${mmStr6(platedHole.hole_width)}" holeHeight="${mmStr6(platedHole.hole_height)}" rectPadWidth="${mmStr6(platedHole.rect_pad_width)}" rectPadHeight="${mmStr6(platedHole.rect_pad_height)}"${formatOptionalMmAttr("rectBorderRadius", platedHole.rect_border_radius)}${formatOptionalMmAttr("holeOffsetX", platedHole.hole_offset_x)}${formatOptionalMmAttr("holeOffsetY", platedHole.hole_offset_y)}${formatPcbRotationAttr(rotation)} shape="pill_hole_with_rect_pad" />`
|
|
2329
2766
|
);
|
|
2330
2767
|
} else if (platedHole.shape === "hole_with_polygon_pad") {
|
|
2331
|
-
const holeSizeAttrs = platedHole.hole_shape === "circle" ? ` holeDiameter="${
|
|
2768
|
+
const holeSizeAttrs = platedHole.hole_shape === "circle" ? ` holeDiameter="${mmStr6(platedHole.hole_diameter ?? 0)}"` : `${formatOptionalMmAttr("holeWidth", platedHole.hole_width)}${formatOptionalMmAttr("holeHeight", platedHole.hole_height)}`;
|
|
2332
2769
|
elementStrings.push(
|
|
2333
|
-
`<platedhole${tagSpacing}${portHintsAttr} pcbX="${
|
|
2770
|
+
`<platedhole${tagSpacing}${portHintsAttr} pcbX="${mmStr6(platedHole.x)}" pcbY="${mmStr6(platedHole.y)}"${platedHole.hole_shape === void 0 ? "" : ` holeShape="${platedHole.hole_shape}"`}${formatSolderMaskAttrs(platedHole)}${holeSizeAttrs} padOutline={${JSON.stringify(platedHole.pad_outline)}} holeOffsetX="${mmStr6(platedHole.hole_offset_x ?? 0)}" holeOffsetY="${mmStr6(platedHole.hole_offset_y ?? 0)}" shape="hole_with_polygon_pad" />`
|
|
2334
2771
|
);
|
|
2335
2772
|
}
|
|
2336
2773
|
}
|
|
@@ -2535,7 +2972,7 @@ var convertSilkscreenGraphics = (circuitJson) => {
|
|
|
2535
2972
|
|
|
2536
2973
|
// lib/generate-footprint-tsx/convert-silkscreen-text.ts
|
|
2537
2974
|
import { su as su18 } from "@tscircuit/soup-util";
|
|
2538
|
-
import { mmStr as
|
|
2975
|
+
import { mmStr as mmStr7 } from "@tscircuit/mm";
|
|
2539
2976
|
var convertSilkscreenText = (circuitJson) => {
|
|
2540
2977
|
const silkscreenTexts = su18(circuitJson).pcb_silkscreen_text.list();
|
|
2541
2978
|
const elementStrings = [];
|
|
@@ -2545,7 +2982,7 @@ var convertSilkscreenText = (circuitJson) => {
|
|
|
2545
2982
|
const knockoutPadding = silkscreenText.knockout_padding;
|
|
2546
2983
|
const hasUniformKnockoutPadding = knockoutPadding && knockoutPadding.left === knockoutPadding.top && knockoutPadding.top === knockoutPadding.right && knockoutPadding.right === knockoutPadding.bottom;
|
|
2547
2984
|
elementStrings.push(
|
|
2548
|
-
`<silkscreentext pcbX={${pcbX}} pcbY={${pcbY}} anchorAlignment="${silkscreenText.anchor_alignment}" fontSize={${silkscreenText.font_size}}${silkscreenText.font !== void 0 ? ` font="${silkscreenText.font}"` : ""}${silkscreenText.ccw_rotation !== void 0 ? ` pcbRotation="${typeof silkscreenText.ccw_rotation === "number" ? `${silkscreenText.ccw_rotation}deg` : silkscreenText.ccw_rotation}"` : ""}${silkscreenText.is_knockout !== void 0 ? ` isKnockout={${silkscreenText.is_knockout}}` : ""}${knockoutPadding ? hasUniformKnockoutPadding ? ` knockoutPadding="${
|
|
2985
|
+
`<silkscreentext pcbX={${pcbX}} pcbY={${pcbY}} anchorAlignment="${silkscreenText.anchor_alignment}" fontSize={${silkscreenText.font_size}}${silkscreenText.font !== void 0 ? ` font="${silkscreenText.font}"` : ""}${silkscreenText.ccw_rotation !== void 0 ? ` pcbRotation="${typeof silkscreenText.ccw_rotation === "number" ? `${silkscreenText.ccw_rotation}deg` : silkscreenText.ccw_rotation}"` : ""}${silkscreenText.is_knockout !== void 0 ? ` isKnockout={${silkscreenText.is_knockout}}` : ""}${knockoutPadding ? hasUniformKnockoutPadding ? ` knockoutPadding="${mmStr7(knockoutPadding.left)}"` : ` knockoutPaddingLeft="${mmStr7(knockoutPadding.left)}" knockoutPaddingTop="${mmStr7(knockoutPadding.top)}" knockoutPaddingRight="${mmStr7(knockoutPadding.right)}" knockoutPaddingBottom="${mmStr7(knockoutPadding.bottom)}"` : ""}${silkscreenText.is_mirrored !== void 0 ? ` mirrored={${silkscreenText.is_mirrored}}` : ""}${silkscreenText.layer !== void 0 ? ` layer="${silkscreenText.layer}"` : ""} text="${escapeJsxText2(silkscreenText.text)}" />`
|
|
2549
2986
|
);
|
|
2550
2987
|
}
|
|
2551
2988
|
return elementStrings;
|
|
@@ -2553,7 +2990,7 @@ var convertSilkscreenText = (circuitJson) => {
|
|
|
2553
2990
|
|
|
2554
2991
|
// lib/generate-footprint-tsx/convert-smt-pads.ts
|
|
2555
2992
|
import { su as su19 } from "@tscircuit/soup-util";
|
|
2556
|
-
import { mmStr as
|
|
2993
|
+
import { mmStr as mmStr8 } from "@tscircuit/mm";
|
|
2557
2994
|
var convertSmtPads = (circuitJson, context) => {
|
|
2558
2995
|
const smtPads = su19(circuitJson).pcb_smtpad.list();
|
|
2559
2996
|
const elementStrings = [];
|
|
@@ -2565,29 +3002,29 @@ var convertSmtPads = (circuitJson, context) => {
|
|
|
2565
3002
|
commonAttrs.push(`portHints={${JSON.stringify(portHints)}}`);
|
|
2566
3003
|
}
|
|
2567
3004
|
if ("x" in smtPad && smtPad.x !== void 0) {
|
|
2568
|
-
commonAttrs.push(`pcbX="${
|
|
3005
|
+
commonAttrs.push(`pcbX="${mmStr8(smtPad.x)}"`);
|
|
2569
3006
|
}
|
|
2570
3007
|
if ("y" in smtPad && smtPad.y !== void 0) {
|
|
2571
|
-
commonAttrs.push(`pcbY="${
|
|
3008
|
+
commonAttrs.push(`pcbY="${mmStr8(smtPad.y)}"`);
|
|
2572
3009
|
}
|
|
2573
3010
|
if (smtPad.layer !== void 0) {
|
|
2574
3011
|
commonAttrs.push(`layer="${smtPad.layer}"`);
|
|
2575
3012
|
}
|
|
2576
3013
|
if (smtPad.shape === "circle") {
|
|
2577
3014
|
elementStrings.push(
|
|
2578
|
-
`<smtpad ${commonAttrs.join(" ")}${solderMaskAttrs} radius="${
|
|
3015
|
+
`<smtpad ${commonAttrs.join(" ")}${solderMaskAttrs} radius="${mmStr8(smtPad.radius ?? 0)}" shape="circle" />`
|
|
2579
3016
|
);
|
|
2580
3017
|
} else if (smtPad.shape === "rect") {
|
|
2581
3018
|
elementStrings.push(
|
|
2582
|
-
`<smtpad ${commonAttrs.join(" ")}${solderMaskAttrs}${formatOptionalMmAttr("rectBorderRadius", smtPad.rect_border_radius)}${formatOptionalMmAttr("cornerRadius", smtPad.corner_radius)}${formatOptionalMmAttr("solderMaskMarginLeft", smtPad.soldermask_margin_left)}${formatOptionalMmAttr("solderMaskMarginTop", smtPad.soldermask_margin_top)}${formatOptionalMmAttr("solderMaskMarginRight", smtPad.soldermask_margin_right)}${formatOptionalMmAttr("solderMaskMarginBottom", smtPad.soldermask_margin_bottom)} width="${
|
|
3019
|
+
`<smtpad ${commonAttrs.join(" ")}${solderMaskAttrs}${formatOptionalMmAttr("rectBorderRadius", smtPad.rect_border_radius)}${formatOptionalMmAttr("cornerRadius", smtPad.corner_radius)}${formatOptionalMmAttr("solderMaskMarginLeft", smtPad.soldermask_margin_left)}${formatOptionalMmAttr("solderMaskMarginTop", smtPad.soldermask_margin_top)}${formatOptionalMmAttr("solderMaskMarginRight", smtPad.soldermask_margin_right)}${formatOptionalMmAttr("solderMaskMarginBottom", smtPad.soldermask_margin_bottom)} width="${mmStr8(smtPad.width ?? 0)}" height="${mmStr8(smtPad.height ?? 0)}" shape="rect" />`
|
|
2583
3020
|
);
|
|
2584
3021
|
} else if (smtPad.shape === "pill") {
|
|
2585
3022
|
elementStrings.push(
|
|
2586
|
-
`<smtpad ${commonAttrs.join(" ")}${solderMaskAttrs} width="${
|
|
3023
|
+
`<smtpad ${commonAttrs.join(" ")}${solderMaskAttrs} width="${mmStr8(smtPad.width ?? 0)}" height="${mmStr8(smtPad.height ?? 0)}" radius="${mmStr8(smtPad.radius ?? 0)}" shape="pill" />`
|
|
2587
3024
|
);
|
|
2588
3025
|
} else if (smtPad.shape === "rotated_pill") {
|
|
2589
3026
|
elementStrings.push(
|
|
2590
|
-
`<smtpad ${commonAttrs.join(" ")}${solderMaskAttrs} width="${
|
|
3027
|
+
`<smtpad ${commonAttrs.join(" ")}${solderMaskAttrs} width="${mmStr8(smtPad.width ?? 0)}" height="${mmStr8(smtPad.height ?? 0)}" radius="${mmStr8(smtPad.radius ?? 0)}"${formatPcbRotationAttr(smtPad.ccw_rotation)} shape="pill" />`
|
|
2591
3028
|
);
|
|
2592
3029
|
} else if (smtPad.shape === "polygon") {
|
|
2593
3030
|
elementStrings.push(
|
|
@@ -2596,7 +3033,7 @@ var convertSmtPads = (circuitJson, context) => {
|
|
|
2596
3033
|
} else if (smtPad.shape === "rotated_rect") {
|
|
2597
3034
|
const cornerRadius = smtPad.corner_radius ?? smtPad.rect_border_radius ?? void 0;
|
|
2598
3035
|
elementStrings.push(
|
|
2599
|
-
`<smtpad ${commonAttrs.join(" ")}${solderMaskAttrs}${formatOptionalMmAttr("cornerRadius", cornerRadius)}${formatOptionalMmAttr("solderMaskMarginLeft", smtPad.soldermask_margin_left)}${formatOptionalMmAttr("solderMaskMarginTop", smtPad.soldermask_margin_top)}${formatOptionalMmAttr("solderMaskMarginRight", smtPad.soldermask_margin_right)}${formatOptionalMmAttr("solderMaskMarginBottom", smtPad.soldermask_margin_bottom)} width="${
|
|
3036
|
+
`<smtpad ${commonAttrs.join(" ")}${solderMaskAttrs}${formatOptionalMmAttr("cornerRadius", cornerRadius)}${formatOptionalMmAttr("solderMaskMarginLeft", smtPad.soldermask_margin_left)}${formatOptionalMmAttr("solderMaskMarginTop", smtPad.soldermask_margin_top)}${formatOptionalMmAttr("solderMaskMarginRight", smtPad.soldermask_margin_right)}${formatOptionalMmAttr("solderMaskMarginBottom", smtPad.soldermask_margin_bottom)} width="${mmStr8(smtPad.width ?? 0)}" height="${mmStr8(smtPad.height ?? 0)}" ccwRotation={${smtPad.ccw_rotation ?? 0}} shape="rotated_rect" />`
|
|
2600
3037
|
);
|
|
2601
3038
|
}
|
|
2602
3039
|
}
|
|
@@ -2604,7 +3041,7 @@ var convertSmtPads = (circuitJson, context) => {
|
|
|
2604
3041
|
};
|
|
2605
3042
|
|
|
2606
3043
|
// lib/generate-footprint-tsx/convert-vias.ts
|
|
2607
|
-
import { mmStr as
|
|
3044
|
+
import { mmStr as mmStr9 } from "@tscircuit/mm";
|
|
2608
3045
|
import { su as su20 } from "@tscircuit/soup-util";
|
|
2609
3046
|
var convertVias = (circuitJson, context) => {
|
|
2610
3047
|
return su20(circuitJson).pcb_via.list().map((via) => {
|
|
@@ -2620,7 +3057,7 @@ var convertVias = (circuitJson, context) => {
|
|
|
2620
3057
|
const tentedAttr = tentedOnTop !== void 0 || tentedOnBottom !== void 0 ? ` tented="${tented}"` : "";
|
|
2621
3058
|
const runtimeNetName = via.source_net_id ? context?.runtimeNetNameBySourceNetId.get(via.source_net_id) : void 0;
|
|
2622
3059
|
const connectsToAttr = runtimeNetName ? ` connectsTo={${JSON.stringify(`net.${runtimeNetName}`)}}` : "";
|
|
2623
|
-
return `<via pcbX="${
|
|
3060
|
+
return `<via pcbX="${mmStr9(via.x)}" pcbY="${mmStr9(via.y)}" holeDiameter="${mmStr9(via.hole_diameter)}" outerDiameter="${mmStr9(via.outer_diameter)}" fromLayer="${fromLayer}" toLayer="${toLayer}"${tentedAttr}${connectsToAttr} />`;
|
|
2624
3061
|
});
|
|
2625
3062
|
};
|
|
2626
3063
|
|
|
@@ -2655,80 +3092,559 @@ var generateFootprintTsx = (circuitJson, context) => {
|
|
|
2655
3092
|
`.trim();
|
|
2656
3093
|
};
|
|
2657
3094
|
|
|
2658
|
-
// lib/get-
|
|
2659
|
-
|
|
3095
|
+
// lib/board-converter/get-pcb-component-render-placement.ts
|
|
3096
|
+
import { getBoundsOfPcbElements } from "@tscircuit/circuit-json-util";
|
|
3097
|
+
import { applyToPoint as applyToPoint5, inverse, translate as translate5 } from "transformation-matrix";
|
|
3098
|
+
var physicalPcbElementTypes = /* @__PURE__ */ new Set([
|
|
3099
|
+
"pcb_copper_text",
|
|
3100
|
+
"pcb_cutout",
|
|
3101
|
+
"pcb_hole",
|
|
3102
|
+
"pcb_keepout",
|
|
3103
|
+
"pcb_plated_hole",
|
|
3104
|
+
"pcb_smtpad",
|
|
3105
|
+
"pcb_trace",
|
|
3106
|
+
"pcb_via"
|
|
3107
|
+
]);
|
|
3108
|
+
var isPhysicalPcbElement = (element) => physicalPcbElementTypes.has(element.type);
|
|
3109
|
+
var getElementsAsRenderedByGeneratedTsx = (elements) => elements.map((element) => {
|
|
3110
|
+
if (element.type !== "pcb_plated_hole" || element.shape !== "rotated_pill_hole_with_rect_pad") {
|
|
3111
|
+
return element;
|
|
3112
|
+
}
|
|
3113
|
+
return {
|
|
3114
|
+
...element,
|
|
3115
|
+
rect_ccw_rotation: element.hole_ccw_rotation
|
|
3116
|
+
};
|
|
3117
|
+
});
|
|
3118
|
+
var getPcbComponentRenderPlacement = ({
|
|
2660
3119
|
circuitJson,
|
|
2661
|
-
|
|
3120
|
+
pcbBoard,
|
|
3121
|
+
pcbComponent
|
|
2662
3122
|
}) => {
|
|
2663
|
-
const
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
3123
|
+
const componentPosition = applyToPoint5(
|
|
3124
|
+
inverse(translate5(pcbBoard.center.x, pcbBoard.center.y)),
|
|
3125
|
+
pcbComponent.center
|
|
3126
|
+
);
|
|
3127
|
+
const physicalElements = circuitJson.filter(
|
|
3128
|
+
(element) => isPhysicalPcbElement(element) && "pcb_component_id" in element && element.pcb_component_id === pcbComponent.pcb_component_id
|
|
3129
|
+
);
|
|
3130
|
+
const physicalBounds = getBoundsOfPcbElements(
|
|
3131
|
+
getElementsAsRenderedByGeneratedTsx(physicalElements)
|
|
3132
|
+
);
|
|
3133
|
+
const physicalWidth = physicalBounds.maxX - physicalBounds.minX;
|
|
3134
|
+
const physicalHeight = physicalBounds.maxY - physicalBounds.minY;
|
|
3135
|
+
if (Number.isFinite(physicalWidth) && Number.isFinite(physicalHeight) && physicalWidth > 0 && physicalHeight > 0) {
|
|
3136
|
+
return {
|
|
3137
|
+
cadModelParentCenter: {
|
|
3138
|
+
x: (physicalBounds.minX + physicalBounds.maxX) / 2,
|
|
3139
|
+
y: (physicalBounds.minY + physicalBounds.maxY) / 2
|
|
3140
|
+
},
|
|
3141
|
+
componentPosition
|
|
3142
|
+
};
|
|
3143
|
+
}
|
|
3144
|
+
return {
|
|
3145
|
+
cadModelParentCenter: componentPosition,
|
|
3146
|
+
componentPosition
|
|
3147
|
+
};
|
|
3148
|
+
};
|
|
3149
|
+
|
|
3150
|
+
// lib/board-converter/get-pin-labels.ts
|
|
3151
|
+
var getCompoundPinNumber = (sourcePort) => {
|
|
3152
|
+
if (sourcePort.pin_number !== void 0) return sourcePort.pin_number;
|
|
3153
|
+
const firstPinNumber = /^\d+/u.exec(sourcePort.name)?.[0];
|
|
3154
|
+
return firstPinNumber ? Number.parseInt(firstPinNumber, 10) : void 0;
|
|
3155
|
+
};
|
|
3156
|
+
var getPinLabels = ({
|
|
3157
|
+
circuitJson,
|
|
3158
|
+
footprintConversionContext,
|
|
3159
|
+
pcbComponent,
|
|
3160
|
+
sourceComponents
|
|
3161
|
+
}) => {
|
|
3162
|
+
if (sourceComponents.length === 0) return void 0;
|
|
3163
|
+
const pinLabels = {};
|
|
3164
|
+
const sourceComponentIds = new Set(
|
|
3165
|
+
sourceComponents.map((sourceComponent) => sourceComponent.source_component_id).filter(
|
|
3166
|
+
(sourceComponentId) => sourceComponentId !== void 0
|
|
3167
|
+
)
|
|
3168
|
+
);
|
|
3169
|
+
const sourcePorts = circuitJson.filter(
|
|
3170
|
+
(element) => element.type === "source_port" && element.source_component_id !== void 0 && sourceComponentIds.has(element.source_component_id) && (element.pin_number !== void 0 || element.source_component_id === pcbComponent.source_component_id)
|
|
3171
|
+
);
|
|
3172
|
+
const usedPinNumbers = new Set(
|
|
3173
|
+
sourcePorts.map(getCompoundPinNumber).filter((pinNumber) => pinNumber !== void 0)
|
|
3174
|
+
);
|
|
3175
|
+
let nextSyntheticPinNumber = Math.max(0, ...usedPinNumbers) + 1;
|
|
3176
|
+
for (const sourcePort of sourcePorts) {
|
|
3177
|
+
const importedPortHints = circuitJson.flatMap((element) => {
|
|
3178
|
+
if (sourcePort.source_component_id !== pcbComponent.source_component_id || element.type !== "pcb_port" || element.source_port_id !== sourcePort.source_port_id) {
|
|
3179
|
+
return [];
|
|
3180
|
+
}
|
|
3181
|
+
const importedPortHint = footprintConversionContext.portHintByPcbPortId.get(element.pcb_port_id);
|
|
3182
|
+
return importedPortHint ? [importedPortHint] : [];
|
|
3183
|
+
});
|
|
3184
|
+
const aliases = [
|
|
3185
|
+
sourcePort.name,
|
|
3186
|
+
...sourcePort.port_hints ?? [],
|
|
3187
|
+
...importedPortHints
|
|
3188
|
+
].filter(
|
|
3189
|
+
(alias, aliasIndex, allAliases) => alias.length > 0 && allAliases.indexOf(alias) === aliasIndex
|
|
3190
|
+
);
|
|
3191
|
+
let pinNumber = getCompoundPinNumber(sourcePort);
|
|
3192
|
+
if (pinNumber === void 0) {
|
|
3193
|
+
while (usedPinNumbers.has(nextSyntheticPinNumber)) {
|
|
3194
|
+
nextSyntheticPinNumber += 1;
|
|
3195
|
+
}
|
|
3196
|
+
pinNumber = nextSyntheticPinNumber;
|
|
3197
|
+
usedPinNumbers.add(pinNumber);
|
|
3198
|
+
nextSyntheticPinNumber += 1;
|
|
3199
|
+
}
|
|
3200
|
+
const pinLabelKey = `pin${pinNumber}`;
|
|
3201
|
+
pinLabels[pinLabelKey] = [
|
|
3202
|
+
...pinLabels[pinLabelKey] ?? [],
|
|
3203
|
+
...aliases
|
|
3204
|
+
].filter(
|
|
3205
|
+
(alias, aliasIndex, allAliases) => allAliases.indexOf(alias) === aliasIndex
|
|
3206
|
+
);
|
|
3207
|
+
}
|
|
3208
|
+
return Object.keys(pinLabels).length > 0 ? pinLabels : void 0;
|
|
3209
|
+
};
|
|
3210
|
+
|
|
3211
|
+
// lib/board-converter/get-schematic-components-for-pcb-component.ts
|
|
3212
|
+
var getSchematicComponentsForPcbComponent = ({
|
|
3213
|
+
circuitJson,
|
|
3214
|
+
pcbComponent
|
|
3215
|
+
}) => {
|
|
3216
|
+
const sourceComponents = circuitJson.filter(
|
|
3217
|
+
(element) => element.type === "source_component"
|
|
3218
|
+
);
|
|
3219
|
+
const pcbSourceComponent = sourceComponents.find(
|
|
3220
|
+
(sourceComponent) => sourceComponent.source_component_id === pcbComponent.source_component_id
|
|
3221
|
+
);
|
|
3222
|
+
if (!pcbSourceComponent) return [];
|
|
3223
|
+
const matchingSourceComponentIds = new Set(
|
|
3224
|
+
sourceComponents.filter(
|
|
3225
|
+
(sourceComponent) => sourceComponent.source_component_id === pcbSourceComponent.source_component_id || pcbSourceComponent.name !== void 0 && sourceComponent.name === pcbSourceComponent.name
|
|
3226
|
+
).map((sourceComponent) => sourceComponent.source_component_id).filter(
|
|
3227
|
+
(sourceComponentId) => sourceComponentId !== void 0
|
|
3228
|
+
)
|
|
3229
|
+
);
|
|
3230
|
+
return circuitJson.filter(
|
|
3231
|
+
(element) => element.type === "schematic_component" && element.source_component_id !== void 0 && matchingSourceComponentIds.has(element.source_component_id)
|
|
3232
|
+
);
|
|
3233
|
+
};
|
|
3234
|
+
|
|
3235
|
+
// lib/board-converter/localize-pcb-component-elements.ts
|
|
3236
|
+
import { transformPCBElements } from "@tscircuit/circuit-json-util";
|
|
3237
|
+
import {
|
|
3238
|
+
applyToPoint as applyToPoint6,
|
|
3239
|
+
compose as compose4,
|
|
3240
|
+
decomposeTSR,
|
|
3241
|
+
flipY,
|
|
3242
|
+
inverse as inverse2,
|
|
3243
|
+
rotateDEG as rotateDEG3,
|
|
3244
|
+
translate as translate6
|
|
3245
|
+
} from "transformation-matrix";
|
|
3246
|
+
var FLOATING_POINT_NOISE_THRESHOLD = 1e-12;
|
|
3247
|
+
var LOCAL_COORDINATE_DECIMAL_PLACES = 12;
|
|
3248
|
+
var normalizeFloatingPointNoise = (elementPropertyValue) => {
|
|
3249
|
+
if (Array.isArray(elementPropertyValue)) {
|
|
3250
|
+
for (const item of elementPropertyValue) normalizeFloatingPointNoise(item);
|
|
3251
|
+
return;
|
|
3252
|
+
}
|
|
3253
|
+
if (typeof elementPropertyValue !== "object" || elementPropertyValue === null)
|
|
3254
|
+
return;
|
|
3255
|
+
const record = elementPropertyValue;
|
|
3256
|
+
for (const [key, property] of Object.entries(record)) {
|
|
3257
|
+
if (typeof property === "number" && Math.abs(property) < FLOATING_POINT_NOISE_THRESHOLD) {
|
|
3258
|
+
record[key] = 0;
|
|
3259
|
+
} else {
|
|
3260
|
+
normalizeFloatingPointNoise(property);
|
|
2671
3261
|
}
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
3262
|
+
}
|
|
3263
|
+
};
|
|
3264
|
+
var normalizeRoutableElementCoordinates = (localComponentElements) => {
|
|
3265
|
+
for (const element of localComponentElements) {
|
|
3266
|
+
if (element.type !== "pcb_smtpad" && element.type !== "pcb_plated_hole") {
|
|
3267
|
+
continue;
|
|
2675
3268
|
}
|
|
2676
|
-
if (
|
|
2677
|
-
|
|
3269
|
+
if (!("x" in element) || !("y" in element)) continue;
|
|
3270
|
+
element.x = Number(element.x.toFixed(LOCAL_COORDINATE_DECIMAL_PLACES));
|
|
3271
|
+
element.y = Number(element.y.toFixed(LOCAL_COORDINATE_DECIMAL_PLACES));
|
|
3272
|
+
}
|
|
3273
|
+
};
|
|
3274
|
+
var transformSilkscreenGraphic = ({
|
|
3275
|
+
absoluteToComponentLocalTransform,
|
|
3276
|
+
graphic
|
|
3277
|
+
}) => {
|
|
3278
|
+
if (graphic.shape !== "brep") return;
|
|
3279
|
+
graphic.brep_shape.outer_ring.vertices = graphic.brep_shape.outer_ring.vertices.map(
|
|
3280
|
+
(vertex) => applyToPoint6(absoluteToComponentLocalTransform, vertex)
|
|
3281
|
+
);
|
|
3282
|
+
graphic.brep_shape.inner_rings = graphic.brep_shape.inner_rings.map(
|
|
3283
|
+
(ring) => ({
|
|
3284
|
+
...ring,
|
|
3285
|
+
vertices: ring.vertices.map(
|
|
3286
|
+
(vertex) => applyToPoint6(absoluteToComponentLocalTransform, vertex)
|
|
3287
|
+
)
|
|
3288
|
+
})
|
|
3289
|
+
);
|
|
3290
|
+
};
|
|
3291
|
+
var normalizeDegrees = (degrees) => (degrees % 360 + 360) % 360;
|
|
3292
|
+
var getTransformedCcwRotationDegrees = ({
|
|
3293
|
+
absoluteCcwRotationDegrees,
|
|
3294
|
+
absoluteToComponentLocalRotationTransform
|
|
3295
|
+
}) => {
|
|
3296
|
+
const transformedRotation = decomposeTSR(
|
|
3297
|
+
compose4(
|
|
3298
|
+
absoluteToComponentLocalRotationTransform,
|
|
3299
|
+
rotateDEG3(absoluteCcwRotationDegrees)
|
|
3300
|
+
)
|
|
3301
|
+
).rotation.angle;
|
|
3302
|
+
return normalizeDegrees(transformedRotation * 180 / Math.PI);
|
|
3303
|
+
};
|
|
3304
|
+
var localizePrimitiveRotations = ({
|
|
3305
|
+
absoluteComponentElements,
|
|
3306
|
+
absoluteToComponentLocalRotationTransform,
|
|
3307
|
+
localComponentElements
|
|
3308
|
+
}) => {
|
|
3309
|
+
const rotationPropertyNames = [
|
|
3310
|
+
"ccw_rotation",
|
|
3311
|
+
"hole_ccw_rotation",
|
|
3312
|
+
"rect_ccw_rotation"
|
|
3313
|
+
];
|
|
3314
|
+
for (const [elementIndex, localElement] of localComponentElements.entries()) {
|
|
3315
|
+
if (localElement.type === "pcb_silkscreen_text" || localElement.type === "pcb_copper_text" || localElement.type === "pcb_fabrication_note_text") {
|
|
3316
|
+
continue;
|
|
2678
3317
|
}
|
|
2679
|
-
|
|
2680
|
-
|
|
3318
|
+
const absoluteElement = absoluteComponentElements[elementIndex];
|
|
3319
|
+
if (absoluteElement?.type !== localElement.type) continue;
|
|
3320
|
+
const absoluteRotations = absoluteElement;
|
|
3321
|
+
const localRotations = localElement;
|
|
3322
|
+
for (const rotationPropertyName of rotationPropertyNames) {
|
|
3323
|
+
const absoluteCcwRotationDegrees = absoluteRotations[rotationPropertyName];
|
|
3324
|
+
if (typeof absoluteCcwRotationDegrees !== "number") continue;
|
|
3325
|
+
localRotations[rotationPropertyName] = getTransformedCcwRotationDegrees({
|
|
3326
|
+
absoluteCcwRotationDegrees,
|
|
3327
|
+
absoluteToComponentLocalRotationTransform
|
|
3328
|
+
});
|
|
2681
3329
|
}
|
|
2682
|
-
|
|
2683
|
-
|
|
3330
|
+
}
|
|
3331
|
+
};
|
|
3332
|
+
var getOppositeOuterLayer = (layer) => {
|
|
3333
|
+
if (layer === "top") return "bottom";
|
|
3334
|
+
if (layer === "bottom") return "top";
|
|
3335
|
+
return layer;
|
|
3336
|
+
};
|
|
3337
|
+
var localizeBottomComponentLayers = (localComponentElements) => {
|
|
3338
|
+
for (const localElement of localComponentElements) {
|
|
3339
|
+
if ("layer" in localElement && (localElement.layer === "top" || localElement.layer === "bottom")) {
|
|
3340
|
+
localElement.layer = getOppositeOuterLayer(localElement.layer);
|
|
2684
3341
|
}
|
|
2685
|
-
if (
|
|
2686
|
-
|
|
3342
|
+
if ("layers" in localElement && Array.isArray(localElement.layers)) {
|
|
3343
|
+
localElement.layers = localElement.layers.map(
|
|
3344
|
+
(layer) => layer === "top" || layer === "bottom" ? getOppositeOuterLayer(layer) : layer
|
|
3345
|
+
);
|
|
2687
3346
|
}
|
|
2688
|
-
|
|
2689
|
-
|
|
3347
|
+
}
|
|
3348
|
+
};
|
|
3349
|
+
var localizeTextRotations = ({
|
|
3350
|
+
absoluteComponentElements,
|
|
3351
|
+
componentCcwRotationDegrees,
|
|
3352
|
+
localComponentElements
|
|
3353
|
+
}) => {
|
|
3354
|
+
for (const [elementIndex, localElement] of localComponentElements.entries()) {
|
|
3355
|
+
if (localElement.type !== "pcb_silkscreen_text" && localElement.type !== "pcb_copper_text" && localElement.type !== "pcb_fabrication_note_text") {
|
|
3356
|
+
continue;
|
|
2690
3357
|
}
|
|
2691
|
-
const
|
|
2692
|
-
if (
|
|
2693
|
-
|
|
2694
|
-
|
|
3358
|
+
const absoluteElement = absoluteComponentElements[elementIndex];
|
|
3359
|
+
if (absoluteElement?.type !== localElement.type) continue;
|
|
3360
|
+
const absoluteRotation = normalizeDegrees(absoluteElement.ccw_rotation ?? 0);
|
|
3361
|
+
if (localElement.type === "pcb_silkscreen_text") {
|
|
3362
|
+
localElement.ccw_rotation = absoluteRotation || 360;
|
|
3363
|
+
} else if (localElement.type === "pcb_copper_text") {
|
|
3364
|
+
localElement.ccw_rotation = absoluteRotation;
|
|
3365
|
+
} else {
|
|
3366
|
+
localElement.ccw_rotation = normalizeDegrees(
|
|
3367
|
+
absoluteRotation - componentCcwRotationDegrees
|
|
2695
3368
|
);
|
|
2696
3369
|
}
|
|
2697
|
-
|
|
2698
|
-
|
|
3370
|
+
}
|
|
3371
|
+
};
|
|
3372
|
+
var localizePcbComponentElements = ({
|
|
3373
|
+
circuitJson,
|
|
3374
|
+
pcbComponent
|
|
3375
|
+
}) => {
|
|
3376
|
+
const absoluteComponentElements = circuitJson.filter(
|
|
3377
|
+
(element) => "pcb_component_id" in element && element.pcb_component_id === pcbComponent.pcb_component_id
|
|
3378
|
+
);
|
|
3379
|
+
const localComponentElements = structuredClone(absoluteComponentElements);
|
|
3380
|
+
const componentLocalToAbsoluteTransform = compose4(
|
|
3381
|
+
translate6(pcbComponent.center.x, pcbComponent.center.y),
|
|
3382
|
+
rotateDEG3(pcbComponent.rotation)
|
|
3383
|
+
);
|
|
3384
|
+
let absoluteToComponentLocalTransform = inverse2(
|
|
3385
|
+
componentLocalToAbsoluteTransform
|
|
3386
|
+
);
|
|
3387
|
+
if (pcbComponent.layer === "bottom") {
|
|
3388
|
+
absoluteToComponentLocalTransform = compose4(
|
|
3389
|
+
flipY(),
|
|
3390
|
+
absoluteToComponentLocalTransform
|
|
3391
|
+
);
|
|
3392
|
+
}
|
|
3393
|
+
transformPCBElements(
|
|
3394
|
+
localComponentElements,
|
|
3395
|
+
absoluteToComponentLocalTransform
|
|
3396
|
+
);
|
|
3397
|
+
for (const localElement of localComponentElements) {
|
|
3398
|
+
if (localElement.type === "pcb_silkscreen_graphic") {
|
|
3399
|
+
transformSilkscreenGraphic({
|
|
3400
|
+
absoluteToComponentLocalTransform,
|
|
3401
|
+
graphic: localElement
|
|
3402
|
+
});
|
|
2699
3403
|
}
|
|
2700
3404
|
}
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
const boardNetsTsx = generateBoardNetsTsx(context);
|
|
2706
|
-
const boardCadModelsTsx = generateBoardCadModelsTsx({
|
|
2707
|
-
circuitJson,
|
|
2708
|
-
pcbBoard
|
|
3405
|
+
localizeTextRotations({
|
|
3406
|
+
absoluteComponentElements,
|
|
3407
|
+
componentCcwRotationDegrees: pcbComponent.rotation,
|
|
3408
|
+
localComponentElements
|
|
2709
3409
|
});
|
|
2710
|
-
|
|
2711
|
-
|
|
3410
|
+
localizePrimitiveRotations({
|
|
3411
|
+
absoluteComponentElements,
|
|
3412
|
+
absoluteToComponentLocalRotationTransform: inverse2(
|
|
3413
|
+
componentLocalToAbsoluteTransform
|
|
3414
|
+
),
|
|
3415
|
+
localComponentElements
|
|
3416
|
+
});
|
|
3417
|
+
if (pcbComponent.layer === "bottom") {
|
|
3418
|
+
localizeBottomComponentLayers(localComponentElements);
|
|
3419
|
+
}
|
|
3420
|
+
normalizeRoutableElementCoordinates(localComponentElements);
|
|
3421
|
+
normalizeFloatingPointNoise(localComponentElements);
|
|
3422
|
+
return localComponentElements;
|
|
3423
|
+
};
|
|
3424
|
+
|
|
3425
|
+
// lib/board-converter/stages/convert-pcb-components.ts
|
|
3426
|
+
var getComponentFootprintTsx = ({
|
|
3427
|
+
circuitJson,
|
|
3428
|
+
footprintConversionContext,
|
|
3429
|
+
pcbComponent
|
|
3430
|
+
}) => {
|
|
3431
|
+
const componentElements = localizePcbComponentElements({
|
|
2712
3432
|
circuitJson,
|
|
2713
|
-
|
|
3433
|
+
pcbComponent
|
|
2714
3434
|
});
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
3435
|
+
return generateFootprintTsx(componentElements, footprintConversionContext);
|
|
3436
|
+
};
|
|
3437
|
+
var convertPcbComponents = ({
|
|
3438
|
+
circuitJson,
|
|
3439
|
+
footprintConversionContext,
|
|
3440
|
+
pcbComponentRuntimeNameByPcbComponentId,
|
|
3441
|
+
pcbBoard,
|
|
3442
|
+
boardChildren
|
|
3443
|
+
}) => {
|
|
3444
|
+
const pcbComponents = circuitJson.filter(
|
|
3445
|
+
(element) => element.type === "pcb_component"
|
|
3446
|
+
);
|
|
3447
|
+
const cadModelGroupByPcbComponentId = /* @__PURE__ */ new Map();
|
|
3448
|
+
for (const cadModelGroup of getCadModelGroups(circuitJson)) {
|
|
3449
|
+
const pcbComponentId = cadModelGroup.cadComponents[0]?.pcb_component_id;
|
|
3450
|
+
if (pcbComponentId === void 0) continue;
|
|
3451
|
+
const existingCadModelGroup = cadModelGroupByPcbComponentId.get(pcbComponentId);
|
|
3452
|
+
cadModelGroupByPcbComponentId.set(
|
|
3453
|
+
pcbComponentId,
|
|
3454
|
+
existingCadModelGroup ? {
|
|
3455
|
+
...existingCadModelGroup,
|
|
3456
|
+
cadComponents: [
|
|
3457
|
+
...existingCadModelGroup.cadComponents,
|
|
3458
|
+
...cadModelGroup.cadComponents
|
|
3459
|
+
]
|
|
3460
|
+
} : cadModelGroup
|
|
3461
|
+
);
|
|
3462
|
+
}
|
|
3463
|
+
for (const pcbComponent of pcbComponents) {
|
|
3464
|
+
const sourceComponent = circuitJson.find(
|
|
3465
|
+
(element) => element.type === "source_component" && element.source_component_id === pcbComponent.source_component_id
|
|
3466
|
+
);
|
|
3467
|
+
const schematicComponents = getSchematicComponentsForPcbComponent({
|
|
3468
|
+
circuitJson,
|
|
3469
|
+
pcbComponent
|
|
3470
|
+
});
|
|
3471
|
+
const schematicSourceComponentIds = new Set(
|
|
3472
|
+
schematicComponents.map((schematicComponent) => schematicComponent.source_component_id).filter(
|
|
3473
|
+
(sourceComponentId) => sourceComponentId !== void 0
|
|
3474
|
+
)
|
|
3475
|
+
);
|
|
3476
|
+
const sourceComponents = circuitJson.filter(
|
|
3477
|
+
(element) => element.type === "source_component" && (element.source_component_id === pcbComponent.source_component_id || element.source_component_id !== void 0 && schematicSourceComponentIds.has(element.source_component_id))
|
|
3478
|
+
);
|
|
3479
|
+
const { cadModelParentCenter, componentPosition } = getPcbComponentRenderPlacement({
|
|
3480
|
+
circuitJson,
|
|
3481
|
+
pcbBoard,
|
|
3482
|
+
pcbComponent
|
|
3483
|
+
});
|
|
3484
|
+
const footprintTsx = getComponentFootprintTsx({
|
|
3485
|
+
circuitJson,
|
|
3486
|
+
footprintConversionContext,
|
|
3487
|
+
pcbComponent
|
|
3488
|
+
});
|
|
3489
|
+
const pinLabels = getPinLabels({
|
|
3490
|
+
circuitJson,
|
|
3491
|
+
footprintConversionContext,
|
|
3492
|
+
pcbComponent,
|
|
3493
|
+
sourceComponents
|
|
3494
|
+
});
|
|
3495
|
+
const componentName = pcbComponentRuntimeNameByPcbComponentId.get(
|
|
3496
|
+
pcbComponent.pcb_component_id
|
|
3497
|
+
);
|
|
3498
|
+
if (!componentName) {
|
|
3499
|
+
throw new Error("Expected every PCB component to have a runtime name");
|
|
3500
|
+
}
|
|
3501
|
+
const cadModelGroup = cadModelGroupByPcbComponentId.get(
|
|
3502
|
+
pcbComponent.pcb_component_id
|
|
3503
|
+
);
|
|
3504
|
+
const localizedCadModelGroup = cadModelGroup ? {
|
|
3505
|
+
...cadModelGroup,
|
|
3506
|
+
parentPlacement: {
|
|
3507
|
+
center: cadModelParentCenter,
|
|
3508
|
+
ccwRotationDegrees: pcbComponent.rotation,
|
|
3509
|
+
layer: pcbComponent.layer === "bottom" ? "bottom" : "top"
|
|
3510
|
+
}
|
|
3511
|
+
} : void 0;
|
|
3512
|
+
const cadModelTsx = localizedCadModelGroup ? generateCadModelGroupModelTsx({
|
|
3513
|
+
cadModelGroup: localizedCadModelGroup,
|
|
3514
|
+
pcbBoard
|
|
3515
|
+
}) : void 0;
|
|
3516
|
+
const componentProps = [
|
|
3517
|
+
`name=${formatJsxStringAttribute(componentName)}`,
|
|
3518
|
+
`pcbX={${componentPosition.x}}`,
|
|
3519
|
+
`pcbY={${componentPosition.y}}`,
|
|
3520
|
+
`pcbRotation="${pcbComponent.rotation}deg"`,
|
|
3521
|
+
`layer="${pcbComponent.layer}"`,
|
|
3522
|
+
"noSchematicRepresentation"
|
|
3523
|
+
];
|
|
3524
|
+
if (cadModelTsx) {
|
|
3525
|
+
componentProps.push(`cadModel={${cadModelTsx}}`);
|
|
3526
|
+
}
|
|
3527
|
+
if (pinLabels) {
|
|
3528
|
+
componentProps.push(`pinLabels={${JSON.stringify(pinLabels)}}`);
|
|
3529
|
+
}
|
|
3530
|
+
if (sourceComponent?.manufacturer_part_number) {
|
|
3531
|
+
componentProps.push(
|
|
3532
|
+
`manufacturerPartNumber=${formatJsxStringAttribute(sourceComponent.manufacturer_part_number)}`
|
|
3533
|
+
);
|
|
3534
|
+
}
|
|
3535
|
+
if (sourceComponent?.supplier_part_numbers && Object.keys(sourceComponent.supplier_part_numbers).length > 0) {
|
|
3536
|
+
componentProps.push(
|
|
3537
|
+
`supplierPartNumbers={${JSON.stringify(sourceComponent.supplier_part_numbers)}}`
|
|
3538
|
+
);
|
|
3539
|
+
}
|
|
3540
|
+
if (pcbComponent.do_not_place === true) {
|
|
3541
|
+
componentProps.push("doNotPlace");
|
|
3542
|
+
}
|
|
3543
|
+
if (pcbComponent.obstructs_within_bounds === false) {
|
|
3544
|
+
componentProps.push("obstructsWithinBounds={false}");
|
|
3545
|
+
}
|
|
3546
|
+
boardChildren.push(
|
|
3547
|
+
`<chip ${componentProps.join(" ")} footprint={${footprintTsx ?? "<footprint />"}} />`
|
|
3548
|
+
);
|
|
3549
|
+
}
|
|
3550
|
+
};
|
|
3551
|
+
|
|
3552
|
+
// lib/board-converter/stages/convert-standalone-pcb-primitives.ts
|
|
3553
|
+
var convertStandalonePcbPrimitives = ({
|
|
3554
|
+
circuitJson,
|
|
3555
|
+
footprintConversionContext,
|
|
3556
|
+
pcbBoard,
|
|
3557
|
+
boardChildren
|
|
3558
|
+
}) => {
|
|
3559
|
+
const existingPcbComponentIds = new Set(
|
|
3560
|
+
circuitJson.flatMap(
|
|
3561
|
+
(element) => element.type === "pcb_component" ? [element.pcb_component_id] : []
|
|
3562
|
+
)
|
|
3563
|
+
);
|
|
3564
|
+
const standaloneElements = circuitJson.filter(
|
|
3565
|
+
(element) => !("pcb_component_id" in element) || !element.pcb_component_id || !existingPcbComponentIds.has(element.pcb_component_id)
|
|
3566
|
+
);
|
|
3567
|
+
const footprintTsx = generateFootprintTsx(
|
|
3568
|
+
standaloneElements,
|
|
3569
|
+
footprintConversionContext
|
|
3570
|
+
);
|
|
3571
|
+
if (!footprintTsx) return;
|
|
3572
|
+
const footprintContainerProps = [
|
|
3573
|
+
`name="${footprintConversionContext.pcbChipName}"`,
|
|
3574
|
+
"noSchematicRepresentation",
|
|
3575
|
+
"obstructsWithinBounds={false}"
|
|
3576
|
+
];
|
|
3577
|
+
if (pcbBoard.center.x !== 0) {
|
|
3578
|
+
footprintContainerProps.push(`pcbX={${-pcbBoard.center.x}}`);
|
|
3579
|
+
}
|
|
3580
|
+
if (pcbBoard.center.y !== 0) {
|
|
3581
|
+
footprintContainerProps.push(`pcbY={${-pcbBoard.center.y}}`);
|
|
3582
|
+
}
|
|
3583
|
+
boardChildren.push(
|
|
3584
|
+
`<chip${footprintContainerProps.length > 0 ? ` ${footprintContainerProps.join(" ")}` : ""} footprint={${footprintTsx}} />`
|
|
3585
|
+
);
|
|
3586
|
+
};
|
|
3587
|
+
|
|
3588
|
+
// lib/board-converter/convert-board-circuit-json.ts
|
|
3589
|
+
var conversionStages = [
|
|
3590
|
+
convertBoardProperties,
|
|
3591
|
+
convertPcbComponents,
|
|
3592
|
+
convertBoardNets,
|
|
3593
|
+
convertBoardTraces,
|
|
3594
|
+
convertCopperPours,
|
|
3595
|
+
convertBoardSchematic,
|
|
3596
|
+
convertStandalonePcbPrimitives,
|
|
3597
|
+
convertBoardCadModels
|
|
3598
|
+
];
|
|
3599
|
+
var convertBoardCircuitJson = ({
|
|
3600
|
+
circuitJson,
|
|
3601
|
+
componentName
|
|
3602
|
+
}) => {
|
|
3603
|
+
const pcbBoard = circuitJson.find((element) => element.type === "pcb_board");
|
|
3604
|
+
if (!pcbBoard) {
|
|
3605
|
+
throw new Error("Board conversion requires a pcb_board element");
|
|
3606
|
+
}
|
|
3607
|
+
const {
|
|
3608
|
+
pcbChipName,
|
|
3609
|
+
pcbComponentRuntimeNameByPcbComponentId,
|
|
3610
|
+
standaloneCadModelRuntimeNameByCadComponentId
|
|
3611
|
+
} = getBoardChildRuntimeNames(circuitJson);
|
|
3612
|
+
const context = {
|
|
3613
|
+
circuitJson,
|
|
3614
|
+
footprintConversionContext: createComponentPreservingBoardConversionContext(
|
|
3615
|
+
{
|
|
3616
|
+
circuitJson,
|
|
3617
|
+
pcbChipName,
|
|
3618
|
+
pcbComponentRuntimeNameByPcbComponentId
|
|
3619
|
+
}
|
|
3620
|
+
),
|
|
3621
|
+
pcbComponentRuntimeNameByPcbComponentId,
|
|
3622
|
+
standaloneCadModelRuntimeNameByCadComponentId,
|
|
3623
|
+
pcbBoard,
|
|
3624
|
+
boardProps: [],
|
|
3625
|
+
boardChildren: []
|
|
3626
|
+
};
|
|
3627
|
+
for (const convertStage of conversionStages) {
|
|
3628
|
+
convertStage(context);
|
|
3629
|
+
}
|
|
3630
|
+
const boardProps = context.boardProps.join(" ");
|
|
3631
|
+
const boardChildren = context.boardChildren.join("\n");
|
|
2722
3632
|
return `
|
|
2723
3633
|
${componentName ? `export const ${componentName} =` : "export default"} () => (
|
|
2724
|
-
<board${
|
|
2725
|
-
${
|
|
3634
|
+
<board${boardProps ? ` ${boardProps}` : ""}>
|
|
3635
|
+
${boardChildren.replace(/\n/g, "\n ")}
|
|
2726
3636
|
</board>
|
|
2727
3637
|
)
|
|
2728
3638
|
${componentName ? `export default ${componentName}` : ""}
|
|
2729
3639
|
`.replace(/\n\s*\n/g, "\n").trim();
|
|
2730
3640
|
};
|
|
2731
3641
|
|
|
3642
|
+
// lib/get-board-using-template.ts
|
|
3643
|
+
var getBoardUsingTemplate = ({
|
|
3644
|
+
circuitJson,
|
|
3645
|
+
componentName
|
|
3646
|
+
}) => convertBoardCircuitJson({ circuitJson, componentName });
|
|
3647
|
+
|
|
2732
3648
|
// lib/get-pin-attributes.ts
|
|
2733
3649
|
var attributeNames = {
|
|
2734
3650
|
is_input: "isInput",
|