circuit-json-to-tscircuit 0.0.91 → 0.0.93
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-B7377FUZ.js} +1482 -199
- package/dist/cli/main.js +5 -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 +190 -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/converter-types.ts +6 -0
- package/lib/generate-board-cad-models-tsx/execute-jscad-operation.ts +7 -0
- package/lib/generate-board-cad-models-tsx/generate-cad-model-group-model-tsx.ts +68 -0
- package/lib/generate-board-cad-models-tsx/generate-cad-model-group-tsx.ts +24 -19
- 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-prop-tsx.ts +113 -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/get-jscad-operation-fit-scale-factors.ts +66 -0
- package/lib/generate-board-cad-models-tsx/get-jscad-operation-in-base-model-frame.ts +179 -0
- package/lib/generate-board-cad-models-tsx/has-cad-model-source.ts +9 -0
- package/lib/generate-board-cad-models-tsx/is-jscad-cad-model-group-translucent.ts +15 -0
- package/lib/generate-board-cad-models-tsx/pack-jscad-operations.ts +69 -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 +4 -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-fit.test.ts +111 -0
- package/tests/board-grouped-jscad-cad-model.test.ts +125 -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 +93 -0
- package/tests/board-mixed-url-and-jscad-cad-models.test.ts +139 -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,27 +470,44 @@ function getCadModelPlacement({
|
|
|
192
470
|
};
|
|
193
471
|
}
|
|
194
472
|
|
|
195
|
-
// lib/generate-board-cad-models-tsx/get-cad-model-
|
|
196
|
-
function
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
473
|
+
// lib/generate-board-cad-models-tsx/get-cad-model-placement-attributes.ts
|
|
474
|
+
function getCadModelPlacementAttributes({
|
|
475
|
+
cadComponent,
|
|
476
|
+
parentPlacement,
|
|
477
|
+
pcbBoard
|
|
478
|
+
}) {
|
|
479
|
+
const placement = getCadModelPlacement({
|
|
480
|
+
cadComponent,
|
|
481
|
+
parentPlacement,
|
|
482
|
+
pcbBoard
|
|
483
|
+
});
|
|
484
|
+
const attributes = [
|
|
485
|
+
`positionOffset={${formatPointProp(placement.positionOffset)}}`,
|
|
486
|
+
`rotationOffset={${formatPointProp(placement.ccwRotationOffsetDegrees)}}`
|
|
487
|
+
];
|
|
488
|
+
if (cadComponent.model_unit_to_mm_scale_factor !== void 0) {
|
|
489
|
+
attributes.push(
|
|
490
|
+
`modelUnitToMmScale={${cadComponent.model_unit_to_mm_scale_factor}}`
|
|
491
|
+
);
|
|
205
492
|
}
|
|
206
|
-
if (cadComponent.
|
|
207
|
-
|
|
493
|
+
if (cadComponent.model_board_normal_direction !== void 0) {
|
|
494
|
+
attributes.push(
|
|
495
|
+
`modelBoardNormalDirection={${JSON.stringify(cadComponent.model_board_normal_direction)}}`
|
|
496
|
+
);
|
|
208
497
|
}
|
|
209
|
-
|
|
210
|
-
|
|
498
|
+
const modelOriginPosition = getCadModelOriginPosition(cadComponent);
|
|
499
|
+
if (modelOriginPosition !== void 0) {
|
|
500
|
+
attributes.push(
|
|
501
|
+
`modelOriginPosition={${formatPointProp(modelOriginPosition)}}`
|
|
502
|
+
);
|
|
211
503
|
}
|
|
212
|
-
if (cadComponent.
|
|
213
|
-
|
|
504
|
+
if (cadComponent.size !== void 0) {
|
|
505
|
+
attributes.push(`size={${formatPointProp(cadComponent.size)}}`);
|
|
214
506
|
}
|
|
215
|
-
|
|
507
|
+
attributes.push(
|
|
508
|
+
`showAsTranslucentModel={${cadComponent.show_as_translucent_model === true}}`
|
|
509
|
+
);
|
|
510
|
+
return attributes;
|
|
216
511
|
}
|
|
217
512
|
|
|
218
513
|
// lib/generate-board-cad-models-tsx/get-model-url-with-format-hint.ts
|
|
@@ -233,141 +528,571 @@ function generateCadModelTsx({
|
|
|
233
528
|
}) {
|
|
234
529
|
const modelUrl = getCadModelUrl(cadComponent);
|
|
235
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
|
+
];
|
|
539
|
+
return `<cadmodel ${attributes.join(" ")} />`;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
// lib/generate-board-cad-models-tsx/get-jscad-operation-fit-scale-factors.ts
|
|
543
|
+
import jscad2 from "@jscad/modeling";
|
|
544
|
+
|
|
545
|
+
// lib/generate-board-cad-models-tsx/execute-jscad-operation.ts
|
|
546
|
+
import jscad from "@jscad/modeling";
|
|
547
|
+
import { executeJscadOperations } from "jscad-planner";
|
|
548
|
+
function executeJscadOperation(operation) {
|
|
549
|
+
return executeJscadOperations(jscad, operation);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// lib/generate-board-cad-models-tsx/get-jscad-operation-fit-scale-factors.ts
|
|
553
|
+
var identityScaleFactors = { x: 1, y: 1, z: 1 };
|
|
554
|
+
function getSafeScaleFactor({
|
|
555
|
+
sourceLength,
|
|
556
|
+
targetLength
|
|
557
|
+
}) {
|
|
558
|
+
return sourceLength > 0 ? targetLength / sourceLength : 1;
|
|
559
|
+
}
|
|
560
|
+
function getJscadOperationFitScaleFactors({
|
|
561
|
+
cadComponent,
|
|
562
|
+
operation
|
|
563
|
+
}) {
|
|
564
|
+
if (cadComponent.size === void 0) return identityScaleFactors;
|
|
565
|
+
const geometry = executeJscadOperation(operation);
|
|
566
|
+
if (!jscad2.geometries.geom3.isA(geometry)) return identityScaleFactors;
|
|
567
|
+
const [minimumPoint, maximumPoint] = jscad2.measurements.measureBoundingBox(geometry);
|
|
568
|
+
const modelUnitToMmScaleFactor = cadComponent.model_unit_to_mm_scale_factor ?? 1;
|
|
569
|
+
const axisScaleFactors = {
|
|
570
|
+
x: getSafeScaleFactor({
|
|
571
|
+
sourceLength: maximumPoint[0] - minimumPoint[0],
|
|
572
|
+
targetLength: cadComponent.size.x * modelUnitToMmScaleFactor
|
|
573
|
+
}),
|
|
574
|
+
y: getSafeScaleFactor({
|
|
575
|
+
sourceLength: maximumPoint[1] - minimumPoint[1],
|
|
576
|
+
targetLength: cadComponent.size.y * modelUnitToMmScaleFactor
|
|
577
|
+
}),
|
|
578
|
+
z: getSafeScaleFactor({
|
|
579
|
+
sourceLength: maximumPoint[2] - minimumPoint[2],
|
|
580
|
+
targetLength: cadComponent.size.z * modelUnitToMmScaleFactor
|
|
581
|
+
})
|
|
582
|
+
};
|
|
583
|
+
if (cadComponent.model_object_fit === "fill_bounds") {
|
|
584
|
+
return axisScaleFactors;
|
|
585
|
+
}
|
|
586
|
+
const uniformScaleFactor = Math.min(
|
|
587
|
+
axisScaleFactors.x,
|
|
588
|
+
axisScaleFactors.y,
|
|
589
|
+
axisScaleFactors.z
|
|
590
|
+
);
|
|
591
|
+
return {
|
|
592
|
+
x: uniformScaleFactor,
|
|
593
|
+
y: uniformScaleFactor,
|
|
594
|
+
z: uniformScaleFactor
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
// lib/generate-board-cad-models-tsx/get-jscad-operation-in-base-model-frame.ts
|
|
599
|
+
var degreesToRadians = (angleDegrees) => angleDegrees * Math.PI / 180;
|
|
600
|
+
var getCadComponentRotation = (cadComponent) => cadComponent.rotation ?? { x: 0, y: 0, z: 0 };
|
|
601
|
+
var getModelOriginPosition = (cadComponent) => cadComponent.model_origin_position ?? { x: 0, y: 0, z: 0 };
|
|
602
|
+
var getBoardNormalRotation = (cadComponent) => {
|
|
603
|
+
switch (cadComponent.model_board_normal_direction ?? "z+") {
|
|
604
|
+
case "x+":
|
|
605
|
+
return { x: 0, y: -90, z: 0 };
|
|
606
|
+
case "x-":
|
|
607
|
+
return { x: 0, y: 90, z: 0 };
|
|
608
|
+
case "y+":
|
|
609
|
+
return { x: 90, y: 0, z: 0 };
|
|
610
|
+
case "y-":
|
|
611
|
+
return { x: -90, y: 0, z: 0 };
|
|
612
|
+
case "z-":
|
|
613
|
+
return { x: 180, y: 0, z: 0 };
|
|
614
|
+
case "z+":
|
|
615
|
+
return { x: 0, y: 0, z: 0 };
|
|
616
|
+
}
|
|
617
|
+
};
|
|
618
|
+
var rotateOperation = ({
|
|
619
|
+
operation,
|
|
620
|
+
rotationDegrees
|
|
621
|
+
}) => {
|
|
622
|
+
let rotatedOperation = operation;
|
|
623
|
+
for (const [axis, angleDegrees] of [
|
|
624
|
+
["Z", rotationDegrees.z],
|
|
625
|
+
["Y", rotationDegrees.y],
|
|
626
|
+
["X", rotationDegrees.x]
|
|
627
|
+
]) {
|
|
628
|
+
if (angleDegrees === 0) continue;
|
|
629
|
+
rotatedOperation = {
|
|
630
|
+
type: `rotate${axis}`,
|
|
631
|
+
angle: degreesToRadians(angleDegrees),
|
|
632
|
+
shape: rotatedOperation
|
|
633
|
+
};
|
|
634
|
+
}
|
|
635
|
+
return rotatedOperation;
|
|
636
|
+
};
|
|
637
|
+
var rotateOperationByInverse = ({
|
|
638
|
+
operation,
|
|
639
|
+
rotationDegrees
|
|
640
|
+
}) => {
|
|
641
|
+
let rotatedOperation = operation;
|
|
642
|
+
for (const [axis, angleDegrees] of [
|
|
643
|
+
["X", rotationDegrees.x],
|
|
644
|
+
["Y", rotationDegrees.y],
|
|
645
|
+
["Z", rotationDegrees.z]
|
|
646
|
+
]) {
|
|
647
|
+
if (angleDegrees === 0) continue;
|
|
648
|
+
rotatedOperation = {
|
|
649
|
+
type: `rotate${axis}`,
|
|
650
|
+
angle: degreesToRadians(-angleDegrees),
|
|
651
|
+
shape: rotatedOperation
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
return rotatedOperation;
|
|
655
|
+
};
|
|
656
|
+
var translateOperation = ({
|
|
657
|
+
operation,
|
|
658
|
+
translation
|
|
659
|
+
}) => {
|
|
660
|
+
if (translation.x === 0 && translation.y === 0 && translation.z === 0) {
|
|
661
|
+
return operation;
|
|
662
|
+
}
|
|
663
|
+
return {
|
|
664
|
+
type: "translate",
|
|
665
|
+
vector: [translation.x, translation.y, translation.z],
|
|
666
|
+
shape: operation
|
|
667
|
+
};
|
|
668
|
+
};
|
|
669
|
+
var scaleOperation = ({
|
|
670
|
+
operation,
|
|
671
|
+
scaleFactors
|
|
672
|
+
}) => {
|
|
673
|
+
if (scaleFactors.x === 1 && scaleFactors.y === 1 && scaleFactors.z === 1) {
|
|
674
|
+
return operation;
|
|
675
|
+
}
|
|
676
|
+
return {
|
|
677
|
+
type: "scale",
|
|
678
|
+
factors: [scaleFactors.x, scaleFactors.y, scaleFactors.z],
|
|
679
|
+
shape: operation
|
|
680
|
+
};
|
|
681
|
+
};
|
|
682
|
+
function getJscadOperationInBaseModelFrame({
|
|
683
|
+
baseCadComponent,
|
|
684
|
+
basePositionOffset,
|
|
685
|
+
cadComponent,
|
|
686
|
+
positionOffset
|
|
687
|
+
}) {
|
|
688
|
+
if (cadComponent.model_jscad === void 0) return void 0;
|
|
689
|
+
const modelOriginPosition = getModelOriginPosition(cadComponent);
|
|
690
|
+
const cadRotationDegrees = getCadComponentRotation(cadComponent);
|
|
691
|
+
const baseCadRotationDegrees = getCadComponentRotation(baseCadComponent);
|
|
692
|
+
const modelUnitToMmScaleFactor = cadComponent.model_unit_to_mm_scale_factor ?? 1;
|
|
693
|
+
let operation = cadComponent.model_jscad;
|
|
694
|
+
operation = scaleOperation({
|
|
695
|
+
operation,
|
|
696
|
+
scaleFactors: {
|
|
697
|
+
x: modelUnitToMmScaleFactor,
|
|
698
|
+
y: modelUnitToMmScaleFactor,
|
|
699
|
+
z: modelUnitToMmScaleFactor
|
|
700
|
+
}
|
|
701
|
+
});
|
|
702
|
+
operation = translateOperation({
|
|
703
|
+
operation,
|
|
704
|
+
translation: {
|
|
705
|
+
x: -modelOriginPosition.x,
|
|
706
|
+
y: -modelOriginPosition.y,
|
|
707
|
+
z: -modelOriginPosition.z
|
|
708
|
+
}
|
|
709
|
+
});
|
|
710
|
+
operation = rotateOperation({
|
|
711
|
+
operation,
|
|
712
|
+
rotationDegrees: getBoardNormalRotation(cadComponent)
|
|
713
|
+
});
|
|
714
|
+
operation = scaleOperation({
|
|
715
|
+
operation,
|
|
716
|
+
scaleFactors: getJscadOperationFitScaleFactors({
|
|
717
|
+
cadComponent,
|
|
718
|
+
operation
|
|
719
|
+
})
|
|
720
|
+
});
|
|
721
|
+
operation = rotateOperation({
|
|
722
|
+
operation,
|
|
723
|
+
rotationDegrees: cadRotationDegrees
|
|
724
|
+
});
|
|
725
|
+
operation = translateOperation({
|
|
726
|
+
operation,
|
|
727
|
+
translation: {
|
|
728
|
+
x: positionOffset.x - basePositionOffset.x,
|
|
729
|
+
y: positionOffset.y - basePositionOffset.y,
|
|
730
|
+
z: positionOffset.z - basePositionOffset.z
|
|
731
|
+
}
|
|
732
|
+
});
|
|
733
|
+
return rotateOperationByInverse({
|
|
734
|
+
operation,
|
|
735
|
+
rotationDegrees: baseCadRotationDegrees
|
|
736
|
+
});
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
// lib/generate-board-cad-models-tsx/pack-jscad-operations.ts
|
|
740
|
+
import jscad3 from "@jscad/modeling";
|
|
741
|
+
import "jscad-planner";
|
|
742
|
+
var copyPolygon = ({
|
|
743
|
+
polygon,
|
|
744
|
+
geometryColor
|
|
745
|
+
}) => ({
|
|
746
|
+
vertices: polygon.vertices.map(([x, y, z]) => [x, y, z]),
|
|
747
|
+
color: polygon.color ?? geometryColor
|
|
748
|
+
});
|
|
749
|
+
var getPackedJscadSize = (polygons) => {
|
|
750
|
+
const vertices = polygons.flatMap((polygon) => polygon.vertices);
|
|
751
|
+
if (vertices.length === 0) return void 0;
|
|
752
|
+
const [firstVertex, ...remainingVertices] = vertices;
|
|
753
|
+
let minX = firstVertex[0];
|
|
754
|
+
let minY = firstVertex[1];
|
|
755
|
+
let minZ = firstVertex[2];
|
|
756
|
+
let maxX = firstVertex[0];
|
|
757
|
+
let maxY = firstVertex[1];
|
|
758
|
+
let maxZ = firstVertex[2];
|
|
759
|
+
for (const [x, y, z] of remainingVertices) {
|
|
760
|
+
minX = Math.min(minX, x);
|
|
761
|
+
minY = Math.min(minY, y);
|
|
762
|
+
minZ = Math.min(minZ, z);
|
|
763
|
+
maxX = Math.max(maxX, x);
|
|
764
|
+
maxY = Math.max(maxY, y);
|
|
765
|
+
maxZ = Math.max(maxZ, z);
|
|
766
|
+
}
|
|
767
|
+
return { x: maxX - minX, y: maxY - minY, z: maxZ - minZ };
|
|
768
|
+
};
|
|
769
|
+
var packJscadOperations = (operations) => {
|
|
770
|
+
const polygons = [];
|
|
771
|
+
for (const operation of operations) {
|
|
772
|
+
const geometry = executeJscadOperation(operation);
|
|
773
|
+
if (!jscad3.geometries.geom3.isA(geometry)) return void 0;
|
|
774
|
+
polygons.push(
|
|
775
|
+
...jscad3.geometries.geom3.toPolygons(geometry).map(
|
|
776
|
+
(polygon) => copyPolygon({
|
|
777
|
+
polygon,
|
|
778
|
+
geometryColor: geometry.color
|
|
779
|
+
})
|
|
780
|
+
)
|
|
781
|
+
);
|
|
782
|
+
}
|
|
783
|
+
return {
|
|
784
|
+
jscad: { type: "createGeom3", polygons },
|
|
785
|
+
size: getPackedJscadSize(polygons)
|
|
786
|
+
};
|
|
787
|
+
};
|
|
788
|
+
|
|
789
|
+
// lib/generate-board-cad-models-tsx/generate-jscad-cad-model-prop-tsx.ts
|
|
790
|
+
function generateSingleJscadCadModelPropTsx({
|
|
791
|
+
cadComponent,
|
|
792
|
+
parentPlacement,
|
|
793
|
+
pcbBoard
|
|
794
|
+
}) {
|
|
236
795
|
const placement = getCadModelPlacement({
|
|
237
796
|
cadComponent,
|
|
238
797
|
parentPlacement,
|
|
239
798
|
pcbBoard
|
|
240
799
|
});
|
|
241
|
-
const
|
|
242
|
-
`
|
|
243
|
-
`positionOffset
|
|
244
|
-
`rotationOffset
|
|
800
|
+
const properties = [
|
|
801
|
+
`jscad: ${JSON.stringify(cadComponent.model_jscad)}`,
|
|
802
|
+
`positionOffset: ${formatPointProp(placement.positionOffset)}`,
|
|
803
|
+
`rotationOffset: ${formatPointProp(placement.ccwRotationOffsetDegrees)}`
|
|
245
804
|
];
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
805
|
+
const modelOriginPosition = getCadModelOriginPosition(cadComponent);
|
|
806
|
+
if (modelOriginPosition !== void 0) {
|
|
807
|
+
properties.push(
|
|
808
|
+
`modelOriginPosition: ${formatPointProp(modelOriginPosition)}`
|
|
249
809
|
);
|
|
250
810
|
}
|
|
251
|
-
if (cadComponent.
|
|
252
|
-
|
|
253
|
-
`
|
|
811
|
+
if (cadComponent.model_unit_to_mm_scale_factor !== void 0) {
|
|
812
|
+
properties.push(
|
|
813
|
+
`modelUnitToMmScale: ${cadComponent.model_unit_to_mm_scale_factor}`
|
|
254
814
|
);
|
|
255
815
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
`modelOriginPosition={${formatPointProp(modelOriginPosition)}}`
|
|
816
|
+
if (cadComponent.model_board_normal_direction !== void 0) {
|
|
817
|
+
properties.push(
|
|
818
|
+
`modelBoardNormalDirection: ${JSON.stringify(cadComponent.model_board_normal_direction)}`
|
|
260
819
|
);
|
|
261
820
|
}
|
|
262
821
|
if (cadComponent.size !== void 0) {
|
|
263
|
-
|
|
264
|
-
}
|
|
265
|
-
if (cadComponent.show_as_translucent_model === true) {
|
|
266
|
-
attributes.push("showAsTranslucentModel");
|
|
822
|
+
properties.push(`size: ${formatPointProp(cadComponent.size)}`);
|
|
267
823
|
}
|
|
268
|
-
return
|
|
824
|
+
return `{ ${properties.join(", ")} }`;
|
|
269
825
|
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
cadModelGroup,
|
|
274
|
-
groupIndex,
|
|
826
|
+
function generateJscadCadModelPropTsx({
|
|
827
|
+
cadComponents,
|
|
828
|
+
parentPlacement,
|
|
275
829
|
pcbBoard
|
|
276
830
|
}) {
|
|
277
|
-
const
|
|
278
|
-
|
|
279
|
-
|
|
831
|
+
const baseCadComponent = cadComponents[0];
|
|
832
|
+
if (!baseCadComponent || baseCadComponent.model_jscad === void 0) {
|
|
833
|
+
return void 0;
|
|
834
|
+
}
|
|
835
|
+
if (cadComponents.length === 1) {
|
|
836
|
+
return generateSingleJscadCadModelPropTsx({
|
|
837
|
+
cadComponent: baseCadComponent,
|
|
838
|
+
parentPlacement,
|
|
839
|
+
pcbBoard
|
|
840
|
+
});
|
|
841
|
+
}
|
|
842
|
+
const basePlacement = getCadModelPlacement({
|
|
843
|
+
cadComponent: baseCadComponent,
|
|
844
|
+
parentPlacement,
|
|
845
|
+
pcbBoard
|
|
846
|
+
});
|
|
847
|
+
const shapes = cadComponents.flatMap((cadComponent) => {
|
|
848
|
+
const placement = getCadModelPlacement({
|
|
280
849
|
cadComponent,
|
|
281
850
|
parentPlacement,
|
|
282
851
|
pcbBoard
|
|
283
852
|
});
|
|
284
|
-
|
|
853
|
+
const operation = getJscadOperationInBaseModelFrame({
|
|
854
|
+
baseCadComponent,
|
|
855
|
+
basePositionOffset: basePlacement.positionOffset,
|
|
856
|
+
cadComponent,
|
|
857
|
+
positionOffset: placement.positionOffset
|
|
858
|
+
});
|
|
859
|
+
return operation ? [operation] : [];
|
|
860
|
+
});
|
|
861
|
+
if (shapes.length === 0) return void 0;
|
|
862
|
+
const packedJscadOperations = packJscadOperations(shapes);
|
|
863
|
+
const jscad4 = packedJscadOperations?.jscad ?? {
|
|
864
|
+
type: "union",
|
|
865
|
+
shapes
|
|
866
|
+
};
|
|
867
|
+
const properties = [
|
|
868
|
+
`jscad: ${JSON.stringify(jscad4)}`,
|
|
869
|
+
`positionOffset: ${formatPointProp(basePlacement.positionOffset)}`,
|
|
870
|
+
`rotationOffset: ${formatPointProp(basePlacement.ccwRotationOffsetDegrees)}`,
|
|
871
|
+
`modelOriginPosition: ${formatPointProp({ x: 0, y: 0, z: 0 })}`,
|
|
872
|
+
"modelUnitToMmScale: 1",
|
|
873
|
+
'modelBoardNormalDirection: "z+"'
|
|
874
|
+
];
|
|
875
|
+
if (packedJscadOperations?.size !== void 0) {
|
|
876
|
+
properties.push(`size: ${formatPointProp(packedJscadOperations.size)}`);
|
|
877
|
+
}
|
|
878
|
+
return `{ ${properties.join(", ")} }`;
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
// lib/generate-board-cad-models-tsx/generate-cad-model-group-model-tsx.ts
|
|
882
|
+
var generateUrlCadModelElementsTsx = ({
|
|
883
|
+
cadModelGroup,
|
|
884
|
+
pcbBoard
|
|
885
|
+
}) => cadModelGroup.cadComponents.flatMap((cadComponent) => {
|
|
886
|
+
if (getCadModelUrl(cadComponent) === void 0) return [];
|
|
887
|
+
const modelElement = generateCadModelTsx({
|
|
888
|
+
cadComponent,
|
|
889
|
+
parentPlacement: cadModelGroup.parentPlacement,
|
|
890
|
+
pcbBoard
|
|
285
891
|
});
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
892
|
+
return modelElement ? [modelElement] : [];
|
|
893
|
+
});
|
|
894
|
+
var getJscadCadComponents = (cadModelGroup) => cadModelGroup.cadComponents.filter(
|
|
895
|
+
(cadComponent) => cadComponent.model_jscad !== void 0
|
|
896
|
+
);
|
|
897
|
+
function generateCadModelGroupModelTsx({
|
|
898
|
+
cadModelGroup,
|
|
899
|
+
pcbBoard
|
|
900
|
+
}) {
|
|
901
|
+
const jscadCadComponents = getJscadCadComponents(cadModelGroup);
|
|
902
|
+
if (jscadCadComponents.length > 0) {
|
|
903
|
+
return generateJscadCadModelPropTsx({
|
|
904
|
+
cadComponents: jscadCadComponents,
|
|
905
|
+
parentPlacement: cadModelGroup.parentPlacement,
|
|
906
|
+
pcbBoard
|
|
907
|
+
});
|
|
290
908
|
}
|
|
909
|
+
const urlCadModelElementsTsx = generateUrlCadModelElementsTsx({
|
|
910
|
+
cadModelGroup,
|
|
911
|
+
pcbBoard
|
|
912
|
+
});
|
|
913
|
+
if (urlCadModelElementsTsx.length === 0) return void 0;
|
|
914
|
+
if (urlCadModelElementsTsx.length === 1) return urlCadModelElementsTsx[0];
|
|
915
|
+
return `<cadassembly>${urlCadModelElementsTsx.join("\n")}</cadassembly>`;
|
|
916
|
+
}
|
|
917
|
+
function generateCadModelGroupChildrenTsx({
|
|
918
|
+
cadModelGroup,
|
|
919
|
+
pcbBoard
|
|
920
|
+
}) {
|
|
921
|
+
if (getJscadCadComponents(cadModelGroup).length === 0) return [];
|
|
922
|
+
return generateUrlCadModelElementsTsx({ cadModelGroup, pcbBoard });
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
// lib/generate-board-cad-models-tsx/is-jscad-cad-model-group-translucent.ts
|
|
926
|
+
function isJscadCadModelGroupTranslucent(cadModelGroup) {
|
|
927
|
+
const jscadCadComponents = cadModelGroup.cadComponents.filter(
|
|
928
|
+
(cadComponent) => cadComponent.model_jscad !== void 0
|
|
929
|
+
);
|
|
930
|
+
return jscadCadComponents.length > 0 && jscadCadComponents.every(
|
|
931
|
+
(cadComponent) => cadComponent.show_as_translucent_model === true
|
|
932
|
+
);
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
// lib/generate-board-cad-models-tsx/generate-cad-model-group-tsx.ts
|
|
936
|
+
function generateCadModelGroupTsx({
|
|
937
|
+
cadModelGroup,
|
|
938
|
+
pcbBoard,
|
|
939
|
+
runtimeName
|
|
940
|
+
}) {
|
|
941
|
+
const { parentPlacement } = cadModelGroup;
|
|
942
|
+
const cadModelTsx = generateCadModelGroupModelTsx({
|
|
943
|
+
cadModelGroup,
|
|
944
|
+
pcbBoard
|
|
945
|
+
});
|
|
291
946
|
if (!cadModelTsx) return void 0;
|
|
292
947
|
const attributes = [
|
|
293
|
-
`name={${JSON.stringify(
|
|
948
|
+
`name={${JSON.stringify(runtimeName)}}`,
|
|
294
949
|
`pcbX={${parentPlacement.center.x}}`,
|
|
295
950
|
`pcbY={${parentPlacement.center.y}}`,
|
|
296
951
|
`pcbRotation="${parentPlacement.ccwRotationDegrees}deg"`,
|
|
297
952
|
`layer="${parentPlacement.layer}"`,
|
|
298
953
|
"noSchematicRepresentation",
|
|
299
|
-
"obstructsWithinBounds={false}",
|
|
300
|
-
"footprint={<footprint />}",
|
|
301
|
-
`cadModel={${cadModelTsx}}`
|
|
302
|
-
];
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
// lib/generate-board-cad-models-tsx/get-cad-model-groups.ts
|
|
307
|
-
function getCadModelGroups(circuitJson) {
|
|
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);
|
|
954
|
+
"obstructsWithinBounds={false}",
|
|
955
|
+
"footprint={<footprint />}",
|
|
956
|
+
`cadModel={${cadModelTsx}}`
|
|
957
|
+
];
|
|
958
|
+
if (isJscadCadModelGroupTranslucent(cadModelGroup)) {
|
|
959
|
+
attributes.push("showAsTranslucentModel");
|
|
339
960
|
}
|
|
340
|
-
|
|
961
|
+
const childModelElementsTsx = generateCadModelGroupChildrenTsx({
|
|
962
|
+
cadModelGroup,
|
|
963
|
+
pcbBoard
|
|
964
|
+
});
|
|
965
|
+
if (childModelElementsTsx.length === 0) {
|
|
966
|
+
return `<chip ${attributes.join(" ")} />`;
|
|
967
|
+
}
|
|
968
|
+
return `<chip ${attributes.join(" ")}>${childModelElementsTsx.join("\n")}</chip>`;
|
|
341
969
|
}
|
|
342
970
|
|
|
343
|
-
// lib/
|
|
344
|
-
|
|
971
|
+
// lib/board-converter/stages/convert-board-cad-models.ts
|
|
972
|
+
var convertBoardCadModels = ({
|
|
345
973
|
circuitJson,
|
|
346
|
-
pcbBoard
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
974
|
+
pcbBoard,
|
|
975
|
+
boardChildren,
|
|
976
|
+
standaloneCadModelRuntimeNameByCadComponentId
|
|
977
|
+
}) => {
|
|
978
|
+
const standaloneCadModelGroups = getCadModelGroups(circuitJson).filter(
|
|
979
|
+
(cadModelGroup) => cadModelGroup.cadComponents.every(
|
|
980
|
+
(cadComponent) => cadComponent.pcb_component_id === void 0
|
|
981
|
+
)
|
|
982
|
+
);
|
|
983
|
+
for (const cadModelGroup of standaloneCadModelGroups) {
|
|
984
|
+
const firstCadComponent = cadModelGroup.cadComponents[0];
|
|
985
|
+
if (!firstCadComponent) continue;
|
|
986
|
+
const runtimeName = standaloneCadModelRuntimeNameByCadComponentId.get(
|
|
987
|
+
firstCadComponent.cad_component_id
|
|
988
|
+
);
|
|
989
|
+
if (!runtimeName) {
|
|
990
|
+
throw new Error(
|
|
991
|
+
`Missing runtime name for standalone CAD model ${firstCadComponent.cad_component_id}`
|
|
992
|
+
);
|
|
993
|
+
}
|
|
350
994
|
const cadModelGroupTsx = generateCadModelGroupTsx({
|
|
351
995
|
cadModelGroup,
|
|
352
|
-
|
|
353
|
-
|
|
996
|
+
pcbBoard,
|
|
997
|
+
runtimeName
|
|
354
998
|
});
|
|
355
|
-
|
|
356
|
-
}
|
|
357
|
-
}
|
|
999
|
+
if (cadModelGroupTsx) boardChildren.push(cadModelGroupTsx);
|
|
1000
|
+
}
|
|
1001
|
+
};
|
|
358
1002
|
|
|
359
1003
|
// lib/generate-board-nets-tsx.ts
|
|
360
|
-
var generateBoardNetsTsx = (context) => {
|
|
361
|
-
const runtimeNetNames =
|
|
362
|
-
return
|
|
1004
|
+
var generateBoardNetsTsx = (circuitJson, context) => {
|
|
1005
|
+
const runtimeNetNames = getRuntimeNetNamesInTraceOrder(circuitJson, context);
|
|
1006
|
+
return runtimeNetNames.map((runtimeNetName) => {
|
|
363
1007
|
const selectors = context.pcbPortSelectorsByRuntimeNetName.get(runtimeNetName) ?? [];
|
|
364
1008
|
const connectsTo = selectors.length ? ` connectsTo={${JSON.stringify(selectors)}}` : "";
|
|
365
1009
|
return `<net name={${JSON.stringify(runtimeNetName)}}${connectsTo} />`;
|
|
366
1010
|
});
|
|
367
1011
|
};
|
|
1012
|
+
var getRuntimeNetNamesInTraceOrder = (circuitJson, context) => {
|
|
1013
|
+
const orderedNames = [];
|
|
1014
|
+
const addedNames = /* @__PURE__ */ new Set();
|
|
1015
|
+
for (const element of circuitJson) {
|
|
1016
|
+
if (element.type !== "source_trace") continue;
|
|
1017
|
+
for (const sourceNetId of element.connected_source_net_ids) {
|
|
1018
|
+
const runtimeNetName = context.runtimeNetNameBySourceNetId.get(sourceNetId);
|
|
1019
|
+
if (!runtimeNetName || addedNames.has(runtimeNetName)) continue;
|
|
1020
|
+
orderedNames.push(runtimeNetName);
|
|
1021
|
+
addedNames.add(runtimeNetName);
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
for (const runtimeNetName of context.runtimeNetNameBySourceNetId.values()) {
|
|
1025
|
+
if (addedNames.has(runtimeNetName)) continue;
|
|
1026
|
+
orderedNames.push(runtimeNetName);
|
|
1027
|
+
addedNames.add(runtimeNetName);
|
|
1028
|
+
}
|
|
1029
|
+
return orderedNames;
|
|
1030
|
+
};
|
|
368
1031
|
|
|
369
|
-
// lib/
|
|
1032
|
+
// lib/board-converter/stages/convert-board-nets.ts
|
|
1033
|
+
var convertBoardNets = ({
|
|
1034
|
+
boardChildren,
|
|
1035
|
+
boardProps,
|
|
1036
|
+
circuitJson,
|
|
1037
|
+
footprintConversionContext
|
|
1038
|
+
}) => {
|
|
1039
|
+
boardChildren.push(
|
|
1040
|
+
...generateBoardNetsTsx(circuitJson, footprintConversionContext)
|
|
1041
|
+
);
|
|
1042
|
+
if (circuitJson.some((element) => element.type === "pcb_trace") && !boardProps.includes("routingDisabled")) {
|
|
1043
|
+
boardProps.push("routingDisabled");
|
|
1044
|
+
}
|
|
1045
|
+
};
|
|
1046
|
+
|
|
1047
|
+
// lib/board-converter/stages/convert-board-properties.ts
|
|
370
1048
|
import { mmStr } from "@tscircuit/mm";
|
|
1049
|
+
var convertBoardProperties = ({
|
|
1050
|
+
pcbBoard,
|
|
1051
|
+
boardProps
|
|
1052
|
+
}) => {
|
|
1053
|
+
if (pcbBoard.center.x !== 0) {
|
|
1054
|
+
boardProps.push(`pcbX={${pcbBoard.center.x}}`);
|
|
1055
|
+
}
|
|
1056
|
+
if (pcbBoard.center.y !== 0) {
|
|
1057
|
+
boardProps.push(`pcbY={${pcbBoard.center.y}}`);
|
|
1058
|
+
}
|
|
1059
|
+
if (pcbBoard.width !== void 0) {
|
|
1060
|
+
boardProps.push(`width="${mmStr(pcbBoard.width)}"`);
|
|
1061
|
+
}
|
|
1062
|
+
if (pcbBoard.height !== void 0) {
|
|
1063
|
+
boardProps.push(`height="${mmStr(pcbBoard.height)}"`);
|
|
1064
|
+
}
|
|
1065
|
+
if (pcbBoard.outline && pcbBoard.outline.length > 0) {
|
|
1066
|
+
const points = pcbBoard.outline.map((point) => `{ x: ${point.x}, y: ${point.y} }`).join(", ");
|
|
1067
|
+
boardProps.push(`outline={[${points}]}`);
|
|
1068
|
+
}
|
|
1069
|
+
if (pcbBoard.thickness !== void 0) {
|
|
1070
|
+
boardProps.push(`thickness="${mmStr(pcbBoard.thickness)}"`);
|
|
1071
|
+
}
|
|
1072
|
+
if (pcbBoard.num_layers !== void 0) {
|
|
1073
|
+
boardProps.push(`layers={${pcbBoard.num_layers}}`);
|
|
1074
|
+
}
|
|
1075
|
+
if (pcbBoard.material !== void 0) {
|
|
1076
|
+
boardProps.push(`material="${pcbBoard.material}"`);
|
|
1077
|
+
}
|
|
1078
|
+
if (pcbBoard.solder_mask_color !== void 0) {
|
|
1079
|
+
boardProps.push(`solderMaskColor="${pcbBoard.solder_mask_color}"`);
|
|
1080
|
+
}
|
|
1081
|
+
if (pcbBoard.silkscreen_color !== void 0) {
|
|
1082
|
+
boardProps.push(`silkscreenColor="${pcbBoard.silkscreen_color}"`);
|
|
1083
|
+
}
|
|
1084
|
+
if (pcbBoard.anchor_position !== void 0) {
|
|
1085
|
+
boardProps.push(
|
|
1086
|
+
`boardAnchorPosition={{ x: ${pcbBoard.anchor_position.x}, y: ${pcbBoard.anchor_position.y} }}`
|
|
1087
|
+
);
|
|
1088
|
+
}
|
|
1089
|
+
if (pcbBoard.anchor_alignment !== void 0) {
|
|
1090
|
+
boardProps.push(`boardAnchorAlignment="${pcbBoard.anchor_alignment}"`);
|
|
1091
|
+
}
|
|
1092
|
+
};
|
|
1093
|
+
|
|
1094
|
+
// lib/generate-board-schematic-sheet-tsx.ts
|
|
1095
|
+
import { mmStr as mmStr2 } from "@tscircuit/mm";
|
|
371
1096
|
var DEFAULT_SHEET_DIMENSIONS_MM = {
|
|
372
1097
|
a4: { width: 297, height: 210 },
|
|
373
1098
|
ansi_b: { width: 431.8, height: 279.4 }
|
|
@@ -391,8 +1116,8 @@ var generateBoardSchematicSheetTsx = ({
|
|
|
391
1116
|
const defaultDimensions = DEFAULT_SHEET_DIMENSIONS_MM[sheet.sheet_size ?? "a4"];
|
|
392
1117
|
const sheetWidth = sheet.sheet_width ?? defaultDimensions.width;
|
|
393
1118
|
const sheetHeight = sheet.sheet_height ?? defaultDimensions.height;
|
|
394
|
-
attrs.push(`sheetWidth="${
|
|
395
|
-
attrs.push(`sheetHeight="${
|
|
1119
|
+
attrs.push(`sheetWidth="${mmStr2(sheetWidth)}"`);
|
|
1120
|
+
attrs.push(`sheetHeight="${mmStr2(sheetHeight)}"`);
|
|
396
1121
|
return `<schematicsheet ${attrs.join(" ")}>
|
|
397
1122
|
${schematicElements.join("\n")}
|
|
398
1123
|
</schematicsheet>`;
|
|
@@ -1589,6 +2314,51 @@ var generateBoardSchematicElements = (circuitJson) => {
|
|
|
1589
2314
|
];
|
|
1590
2315
|
};
|
|
1591
2316
|
|
|
2317
|
+
// lib/board-converter/stages/convert-board-schematic.ts
|
|
2318
|
+
var convertBoardSchematic = ({
|
|
2319
|
+
boardChildren,
|
|
2320
|
+
circuitJson
|
|
2321
|
+
}) => {
|
|
2322
|
+
const schematicElements = generateBoardSchematicElements(circuitJson);
|
|
2323
|
+
boardChildren.push(
|
|
2324
|
+
generateBoardSchematicSheetTsx({
|
|
2325
|
+
circuitJson,
|
|
2326
|
+
schematicElements
|
|
2327
|
+
})
|
|
2328
|
+
);
|
|
2329
|
+
};
|
|
2330
|
+
|
|
2331
|
+
// lib/generate-board-traces-tsx.ts
|
|
2332
|
+
function generateBoardTracesTsx(circuitJson, context) {
|
|
2333
|
+
return circuitJson.flatMap((element) => {
|
|
2334
|
+
if (element.type !== "source_trace") return [];
|
|
2335
|
+
const portSelectors = element.connected_source_port_ids.flatMap(
|
|
2336
|
+
(sourcePortId) => context.pcbPortSelectorsBySourcePortId.get(sourcePortId) ?? []
|
|
2337
|
+
);
|
|
2338
|
+
const netSelectors = [
|
|
2339
|
+
...new Set(
|
|
2340
|
+
element.connected_source_net_ids.flatMap((sourceNetId) => {
|
|
2341
|
+
const runtimeNetName = context.runtimeNetNameBySourceNetId.get(sourceNetId);
|
|
2342
|
+
return runtimeNetName ? [`net.${runtimeNetName}`] : [];
|
|
2343
|
+
})
|
|
2344
|
+
)
|
|
2345
|
+
];
|
|
2346
|
+
const path = [...portSelectors, ...netSelectors];
|
|
2347
|
+
return path.length >= 2 ? [`<trace path={${JSON.stringify(path)}} />`] : [];
|
|
2348
|
+
});
|
|
2349
|
+
}
|
|
2350
|
+
|
|
2351
|
+
// lib/board-converter/stages/convert-board-traces.ts
|
|
2352
|
+
var convertBoardTraces = ({
|
|
2353
|
+
boardChildren,
|
|
2354
|
+
circuitJson,
|
|
2355
|
+
footprintConversionContext
|
|
2356
|
+
}) => {
|
|
2357
|
+
boardChildren.push(
|
|
2358
|
+
...generateBoardTracesTsx(circuitJson, footprintConversionContext)
|
|
2359
|
+
);
|
|
2360
|
+
};
|
|
2361
|
+
|
|
1592
2362
|
// lib/generate-copper-pours-tsx.ts
|
|
1593
2363
|
import { su as su6 } from "@tscircuit/soup-util";
|
|
1594
2364
|
|
|
@@ -1798,6 +2568,26 @@ var getUnassignedCopperPourNetName = ({
|
|
|
1798
2568
|
return name;
|
|
1799
2569
|
};
|
|
1800
2570
|
|
|
2571
|
+
// lib/board-converter/stages/convert-copper-pours.ts
|
|
2572
|
+
var convertCopperPours = ({
|
|
2573
|
+
boardChildren,
|
|
2574
|
+
circuitJson,
|
|
2575
|
+
footprintConversionContext
|
|
2576
|
+
}) => {
|
|
2577
|
+
boardChildren.push(
|
|
2578
|
+
...generateCopperPoursTsx(circuitJson, footprintConversionContext)
|
|
2579
|
+
);
|
|
2580
|
+
};
|
|
2581
|
+
|
|
2582
|
+
// lib/format-jsx-string-attribute.ts
|
|
2583
|
+
var formatJsxStringAttribute = (text) => {
|
|
2584
|
+
const stringText = String(text ?? "");
|
|
2585
|
+
if (!/["\\\r\n\t{}<&>]/.test(stringText)) {
|
|
2586
|
+
return `"${stringText}"`;
|
|
2587
|
+
}
|
|
2588
|
+
return `{${JSON.stringify(stringText)}}`;
|
|
2589
|
+
};
|
|
2590
|
+
|
|
1801
2591
|
// lib/generate-footprint-tsx/convert-copper-text.ts
|
|
1802
2592
|
import { su as su7 } from "@tscircuit/soup-util";
|
|
1803
2593
|
|
|
@@ -1897,8 +2687,8 @@ var convertCourtyard = (circuitJson) => {
|
|
|
1897
2687
|
import { su as su9 } from "@tscircuit/soup-util";
|
|
1898
2688
|
|
|
1899
2689
|
// lib/generate-footprint-tsx/footprint-tsx-attribute-formatters/format-mm.ts
|
|
1900
|
-
import { mmStr as
|
|
1901
|
-
var formatMm = (value) =>
|
|
2690
|
+
import { mmStr as mmStr3 } from "@tscircuit/mm";
|
|
2691
|
+
var formatMm = (value) => mmStr3(value ?? 0);
|
|
1902
2692
|
|
|
1903
2693
|
// lib/generate-footprint-tsx/convert-cutouts.ts
|
|
1904
2694
|
var convertCutouts = (circuitJson) => {
|
|
@@ -2043,26 +2833,26 @@ var convertFabrication = (circuitJson) => {
|
|
|
2043
2833
|
|
|
2044
2834
|
// lib/generate-footprint-tsx/convert-holes.ts
|
|
2045
2835
|
import { su as su11 } from "@tscircuit/soup-util";
|
|
2046
|
-
import { mmStr as
|
|
2836
|
+
import { mmStr as mmStr4 } from "@tscircuit/mm";
|
|
2047
2837
|
var convertHoles = (circuitJson) => {
|
|
2048
2838
|
const holes = su11(circuitJson).pcb_hole.list();
|
|
2049
2839
|
const elementStrings = [];
|
|
2050
2840
|
for (const hole of holes) {
|
|
2051
2841
|
if (hole.hole_shape === "circle") {
|
|
2052
2842
|
elementStrings.push(
|
|
2053
|
-
`<hole pcbX="${
|
|
2843
|
+
`<hole pcbX="${mmStr4(hole.x)}" pcbY="${mmStr4(hole.y)}" diameter="${mmStr4(hole.hole_diameter)}" />`
|
|
2054
2844
|
);
|
|
2055
2845
|
} else if (hole.hole_shape === "rect") {
|
|
2056
2846
|
elementStrings.push(
|
|
2057
|
-
`<hole pcbX="${
|
|
2847
|
+
`<hole pcbX="${mmStr4(hole.x)}" pcbY="${mmStr4(hole.y)}" width="${mmStr4(hole.hole_width)}" height="${mmStr4(hole.hole_height)}" shape="rect" />`
|
|
2058
2848
|
);
|
|
2059
2849
|
} else if (hole.hole_shape === "oval") {
|
|
2060
2850
|
elementStrings.push(
|
|
2061
|
-
`<hole pcbX="${
|
|
2851
|
+
`<hole pcbX="${mmStr4(hole.x)}" pcbY="${mmStr4(hole.y)}" width="${mmStr4(hole.hole_width)}" height="${mmStr4(hole.hole_height)}" shape="oval" />`
|
|
2062
2852
|
);
|
|
2063
2853
|
} else if (hole.hole_shape === "pill" || hole.hole_shape === "rotated_pill") {
|
|
2064
2854
|
elementStrings.push(
|
|
2065
|
-
`<hole pcbX="${
|
|
2855
|
+
`<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
2856
|
);
|
|
2067
2857
|
}
|
|
2068
2858
|
}
|
|
@@ -2276,13 +3066,13 @@ var convertPcbTraces = (circuitJson) => su14(circuitJson).pcb_trace.list().map((
|
|
|
2276
3066
|
|
|
2277
3067
|
// lib/generate-footprint-tsx/convert-plated-holes.ts
|
|
2278
3068
|
import { su as su15 } from "@tscircuit/soup-util";
|
|
2279
|
-
import { mmStr as
|
|
3069
|
+
import { mmStr as mmStr6 } from "@tscircuit/mm";
|
|
2280
3070
|
|
|
2281
3071
|
// lib/generate-footprint-tsx/footprint-tsx-attribute-formatters/format-optional-mm-attr.ts
|
|
2282
|
-
import { mmStr as
|
|
3072
|
+
import { mmStr as mmStr5 } from "@tscircuit/mm";
|
|
2283
3073
|
var formatOptionalMmAttr = (attrName, value) => {
|
|
2284
3074
|
if (value === void 0) return "";
|
|
2285
|
-
return ` ${attrName}="${
|
|
3075
|
+
return ` ${attrName}="${mmStr5(value)}"`;
|
|
2286
3076
|
};
|
|
2287
3077
|
|
|
2288
3078
|
// lib/generate-footprint-tsx/footprint-tsx-attribute-formatters/format-solder-mask-attrs.ts
|
|
@@ -2298,7 +3088,13 @@ var formatSolderMaskAttrs = (platedHole) => {
|
|
|
2298
3088
|
var getImportedPortHints = (primitive, context) => {
|
|
2299
3089
|
if (!primitive.pcb_port_id || !context) return primitive.port_hints;
|
|
2300
3090
|
const importedHint = context.portHintByPcbPortId.get(primitive.pcb_port_id);
|
|
2301
|
-
|
|
3091
|
+
if (!importedHint) return primitive.port_hints;
|
|
3092
|
+
if (!context.pcbPortIdsWithUnambiguousComponentSelectors.has(
|
|
3093
|
+
primitive.pcb_port_id
|
|
3094
|
+
)) {
|
|
3095
|
+
return [importedHint];
|
|
3096
|
+
}
|
|
3097
|
+
return [.../* @__PURE__ */ new Set([importedHint, ...primitive.port_hints ?? []])];
|
|
2302
3098
|
};
|
|
2303
3099
|
|
|
2304
3100
|
// lib/generate-footprint-tsx/convert-plated-holes.ts
|
|
@@ -2311,26 +3107,26 @@ var convertPlatedHoles = (circuitJson, context) => {
|
|
|
2311
3107
|
const tagSpacing = context ? " " : " ";
|
|
2312
3108
|
if (platedHole.shape === "oval" || platedHole.shape === "pill") {
|
|
2313
3109
|
elementStrings.push(
|
|
2314
|
-
`<platedhole${tagSpacing}${portHintsAttr} pcbX="${
|
|
3110
|
+
`<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
3111
|
);
|
|
2316
3112
|
} else if (platedHole.shape === "circle") {
|
|
2317
3113
|
elementStrings.push(
|
|
2318
|
-
`<platedhole${tagSpacing}${portHintsAttr} pcbX="${
|
|
3114
|
+
`<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
3115
|
);
|
|
2320
3116
|
} else if (platedHole.shape === "circular_hole_with_rect_pad") {
|
|
2321
3117
|
elementStrings.push(
|
|
2322
|
-
`<platedhole${tagSpacing}${portHintsAttr} pcbX="${
|
|
3118
|
+
`<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
3119
|
);
|
|
2324
3120
|
} else if (platedHole.shape === "pill_hole_with_rect_pad" || platedHole.shape === "rotated_pill_hole_with_rect_pad") {
|
|
2325
3121
|
const holeShape = platedHole.shape === "rotated_pill_hole_with_rect_pad" ? "pill" : platedHole.hole_shape;
|
|
2326
3122
|
const rotation = platedHole.shape === "rotated_pill_hole_with_rect_pad" ? platedHole.hole_ccw_rotation : void 0;
|
|
2327
3123
|
elementStrings.push(
|
|
2328
|
-
`<platedhole${tagSpacing}${portHintsAttr} pcbX="${
|
|
3124
|
+
`<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
3125
|
);
|
|
2330
3126
|
} else if (platedHole.shape === "hole_with_polygon_pad") {
|
|
2331
|
-
const holeSizeAttrs = platedHole.hole_shape === "circle" ? ` holeDiameter="${
|
|
3127
|
+
const holeSizeAttrs = platedHole.hole_shape === "circle" ? ` holeDiameter="${mmStr6(platedHole.hole_diameter ?? 0)}"` : `${formatOptionalMmAttr("holeWidth", platedHole.hole_width)}${formatOptionalMmAttr("holeHeight", platedHole.hole_height)}`;
|
|
2332
3128
|
elementStrings.push(
|
|
2333
|
-
`<platedhole${tagSpacing}${portHintsAttr} pcbX="${
|
|
3129
|
+
`<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
3130
|
);
|
|
2335
3131
|
}
|
|
2336
3132
|
}
|
|
@@ -2535,7 +3331,7 @@ var convertSilkscreenGraphics = (circuitJson) => {
|
|
|
2535
3331
|
|
|
2536
3332
|
// lib/generate-footprint-tsx/convert-silkscreen-text.ts
|
|
2537
3333
|
import { su as su18 } from "@tscircuit/soup-util";
|
|
2538
|
-
import { mmStr as
|
|
3334
|
+
import { mmStr as mmStr7 } from "@tscircuit/mm";
|
|
2539
3335
|
var convertSilkscreenText = (circuitJson) => {
|
|
2540
3336
|
const silkscreenTexts = su18(circuitJson).pcb_silkscreen_text.list();
|
|
2541
3337
|
const elementStrings = [];
|
|
@@ -2545,7 +3341,7 @@ var convertSilkscreenText = (circuitJson) => {
|
|
|
2545
3341
|
const knockoutPadding = silkscreenText.knockout_padding;
|
|
2546
3342
|
const hasUniformKnockoutPadding = knockoutPadding && knockoutPadding.left === knockoutPadding.top && knockoutPadding.top === knockoutPadding.right && knockoutPadding.right === knockoutPadding.bottom;
|
|
2547
3343
|
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="${
|
|
3344
|
+
`<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
3345
|
);
|
|
2550
3346
|
}
|
|
2551
3347
|
return elementStrings;
|
|
@@ -2553,7 +3349,7 @@ var convertSilkscreenText = (circuitJson) => {
|
|
|
2553
3349
|
|
|
2554
3350
|
// lib/generate-footprint-tsx/convert-smt-pads.ts
|
|
2555
3351
|
import { su as su19 } from "@tscircuit/soup-util";
|
|
2556
|
-
import { mmStr as
|
|
3352
|
+
import { mmStr as mmStr8 } from "@tscircuit/mm";
|
|
2557
3353
|
var convertSmtPads = (circuitJson, context) => {
|
|
2558
3354
|
const smtPads = su19(circuitJson).pcb_smtpad.list();
|
|
2559
3355
|
const elementStrings = [];
|
|
@@ -2565,29 +3361,29 @@ var convertSmtPads = (circuitJson, context) => {
|
|
|
2565
3361
|
commonAttrs.push(`portHints={${JSON.stringify(portHints)}}`);
|
|
2566
3362
|
}
|
|
2567
3363
|
if ("x" in smtPad && smtPad.x !== void 0) {
|
|
2568
|
-
commonAttrs.push(`pcbX="${
|
|
3364
|
+
commonAttrs.push(`pcbX="${mmStr8(smtPad.x)}"`);
|
|
2569
3365
|
}
|
|
2570
3366
|
if ("y" in smtPad && smtPad.y !== void 0) {
|
|
2571
|
-
commonAttrs.push(`pcbY="${
|
|
3367
|
+
commonAttrs.push(`pcbY="${mmStr8(smtPad.y)}"`);
|
|
2572
3368
|
}
|
|
2573
3369
|
if (smtPad.layer !== void 0) {
|
|
2574
3370
|
commonAttrs.push(`layer="${smtPad.layer}"`);
|
|
2575
3371
|
}
|
|
2576
3372
|
if (smtPad.shape === "circle") {
|
|
2577
3373
|
elementStrings.push(
|
|
2578
|
-
`<smtpad ${commonAttrs.join(" ")}${solderMaskAttrs} radius="${
|
|
3374
|
+
`<smtpad ${commonAttrs.join(" ")}${solderMaskAttrs} radius="${mmStr8(smtPad.radius ?? 0)}" shape="circle" />`
|
|
2579
3375
|
);
|
|
2580
3376
|
} else if (smtPad.shape === "rect") {
|
|
2581
3377
|
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="${
|
|
3378
|
+
`<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
3379
|
);
|
|
2584
3380
|
} else if (smtPad.shape === "pill") {
|
|
2585
3381
|
elementStrings.push(
|
|
2586
|
-
`<smtpad ${commonAttrs.join(" ")}${solderMaskAttrs} width="${
|
|
3382
|
+
`<smtpad ${commonAttrs.join(" ")}${solderMaskAttrs} width="${mmStr8(smtPad.width ?? 0)}" height="${mmStr8(smtPad.height ?? 0)}" radius="${mmStr8(smtPad.radius ?? 0)}" shape="pill" />`
|
|
2587
3383
|
);
|
|
2588
3384
|
} else if (smtPad.shape === "rotated_pill") {
|
|
2589
3385
|
elementStrings.push(
|
|
2590
|
-
`<smtpad ${commonAttrs.join(" ")}${solderMaskAttrs} width="${
|
|
3386
|
+
`<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
3387
|
);
|
|
2592
3388
|
} else if (smtPad.shape === "polygon") {
|
|
2593
3389
|
elementStrings.push(
|
|
@@ -2596,7 +3392,7 @@ var convertSmtPads = (circuitJson, context) => {
|
|
|
2596
3392
|
} else if (smtPad.shape === "rotated_rect") {
|
|
2597
3393
|
const cornerRadius = smtPad.corner_radius ?? smtPad.rect_border_radius ?? void 0;
|
|
2598
3394
|
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="${
|
|
3395
|
+
`<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
3396
|
);
|
|
2601
3397
|
}
|
|
2602
3398
|
}
|
|
@@ -2604,7 +3400,7 @@ var convertSmtPads = (circuitJson, context) => {
|
|
|
2604
3400
|
};
|
|
2605
3401
|
|
|
2606
3402
|
// lib/generate-footprint-tsx/convert-vias.ts
|
|
2607
|
-
import { mmStr as
|
|
3403
|
+
import { mmStr as mmStr9 } from "@tscircuit/mm";
|
|
2608
3404
|
import { su as su20 } from "@tscircuit/soup-util";
|
|
2609
3405
|
var convertVias = (circuitJson, context) => {
|
|
2610
3406
|
return su20(circuitJson).pcb_via.list().map((via) => {
|
|
@@ -2620,7 +3416,7 @@ var convertVias = (circuitJson, context) => {
|
|
|
2620
3416
|
const tentedAttr = tentedOnTop !== void 0 || tentedOnBottom !== void 0 ? ` tented="${tented}"` : "";
|
|
2621
3417
|
const runtimeNetName = via.source_net_id ? context?.runtimeNetNameBySourceNetId.get(via.source_net_id) : void 0;
|
|
2622
3418
|
const connectsToAttr = runtimeNetName ? ` connectsTo={${JSON.stringify(`net.${runtimeNetName}`)}}` : "";
|
|
2623
|
-
return `<via pcbX="${
|
|
3419
|
+
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
3420
|
});
|
|
2625
3421
|
};
|
|
2626
3422
|
|
|
@@ -2655,80 +3451,567 @@ var generateFootprintTsx = (circuitJson, context) => {
|
|
|
2655
3451
|
`.trim();
|
|
2656
3452
|
};
|
|
2657
3453
|
|
|
2658
|
-
// lib/get-
|
|
2659
|
-
|
|
3454
|
+
// lib/board-converter/get-pcb-component-render-placement.ts
|
|
3455
|
+
import { getBoundsOfPcbElements } from "@tscircuit/circuit-json-util";
|
|
3456
|
+
import { applyToPoint as applyToPoint5, inverse, translate as translate5 } from "transformation-matrix";
|
|
3457
|
+
var physicalPcbElementTypes = /* @__PURE__ */ new Set([
|
|
3458
|
+
"pcb_copper_text",
|
|
3459
|
+
"pcb_cutout",
|
|
3460
|
+
"pcb_hole",
|
|
3461
|
+
"pcb_keepout",
|
|
3462
|
+
"pcb_plated_hole",
|
|
3463
|
+
"pcb_smtpad",
|
|
3464
|
+
"pcb_trace",
|
|
3465
|
+
"pcb_via"
|
|
3466
|
+
]);
|
|
3467
|
+
var isPhysicalPcbElement = (element) => physicalPcbElementTypes.has(element.type);
|
|
3468
|
+
var getElementsAsRenderedByGeneratedTsx = (elements) => elements.map((element) => {
|
|
3469
|
+
if (element.type !== "pcb_plated_hole" || element.shape !== "rotated_pill_hole_with_rect_pad") {
|
|
3470
|
+
return element;
|
|
3471
|
+
}
|
|
3472
|
+
return {
|
|
3473
|
+
...element,
|
|
3474
|
+
rect_ccw_rotation: element.hole_ccw_rotation
|
|
3475
|
+
};
|
|
3476
|
+
});
|
|
3477
|
+
var getPcbComponentRenderPlacement = ({
|
|
2660
3478
|
circuitJson,
|
|
2661
|
-
|
|
3479
|
+
pcbBoard,
|
|
3480
|
+
pcbComponent
|
|
3481
|
+
}) => {
|
|
3482
|
+
const componentPosition = applyToPoint5(
|
|
3483
|
+
inverse(translate5(pcbBoard.center.x, pcbBoard.center.y)),
|
|
3484
|
+
pcbComponent.center
|
|
3485
|
+
);
|
|
3486
|
+
const physicalElements = circuitJson.filter(
|
|
3487
|
+
(element) => isPhysicalPcbElement(element) && "pcb_component_id" in element && element.pcb_component_id === pcbComponent.pcb_component_id
|
|
3488
|
+
);
|
|
3489
|
+
const physicalBounds = getBoundsOfPcbElements(
|
|
3490
|
+
getElementsAsRenderedByGeneratedTsx(physicalElements)
|
|
3491
|
+
);
|
|
3492
|
+
const physicalWidth = physicalBounds.maxX - physicalBounds.minX;
|
|
3493
|
+
const physicalHeight = physicalBounds.maxY - physicalBounds.minY;
|
|
3494
|
+
if (Number.isFinite(physicalWidth) && Number.isFinite(physicalHeight) && physicalWidth > 0 && physicalHeight > 0) {
|
|
3495
|
+
return {
|
|
3496
|
+
cadModelParentCenter: {
|
|
3497
|
+
x: (physicalBounds.minX + physicalBounds.maxX) / 2,
|
|
3498
|
+
y: (physicalBounds.minY + physicalBounds.maxY) / 2
|
|
3499
|
+
},
|
|
3500
|
+
componentPosition
|
|
3501
|
+
};
|
|
3502
|
+
}
|
|
3503
|
+
return {
|
|
3504
|
+
cadModelParentCenter: componentPosition,
|
|
3505
|
+
componentPosition
|
|
3506
|
+
};
|
|
3507
|
+
};
|
|
3508
|
+
|
|
3509
|
+
// lib/board-converter/get-pin-labels.ts
|
|
3510
|
+
var getCompoundPinNumber = (sourcePort) => {
|
|
3511
|
+
if (sourcePort.pin_number !== void 0) return sourcePort.pin_number;
|
|
3512
|
+
const firstPinNumber = /^\d+/u.exec(sourcePort.name)?.[0];
|
|
3513
|
+
return firstPinNumber ? Number.parseInt(firstPinNumber, 10) : void 0;
|
|
3514
|
+
};
|
|
3515
|
+
var getPinLabels = ({
|
|
3516
|
+
circuitJson,
|
|
3517
|
+
footprintConversionContext,
|
|
3518
|
+
pcbComponent,
|
|
3519
|
+
sourceComponents
|
|
2662
3520
|
}) => {
|
|
2663
|
-
|
|
2664
|
-
const
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
3521
|
+
if (sourceComponents.length === 0) return void 0;
|
|
3522
|
+
const pinLabels = {};
|
|
3523
|
+
const sourceComponentIds = new Set(
|
|
3524
|
+
sourceComponents.map((sourceComponent) => sourceComponent.source_component_id).filter(
|
|
3525
|
+
(sourceComponentId) => sourceComponentId !== void 0
|
|
3526
|
+
)
|
|
3527
|
+
);
|
|
3528
|
+
const sourcePorts = circuitJson.filter(
|
|
3529
|
+
(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)
|
|
3530
|
+
);
|
|
3531
|
+
const usedPinNumbers = new Set(
|
|
3532
|
+
sourcePorts.map(getCompoundPinNumber).filter((pinNumber) => pinNumber !== void 0)
|
|
3533
|
+
);
|
|
3534
|
+
let nextSyntheticPinNumber = Math.max(0, ...usedPinNumbers) + 1;
|
|
3535
|
+
for (const sourcePort of sourcePorts) {
|
|
3536
|
+
const importedPortHints = circuitJson.flatMap((element) => {
|
|
3537
|
+
if (sourcePort.source_component_id !== pcbComponent.source_component_id || element.type !== "pcb_port" || element.source_port_id !== sourcePort.source_port_id) {
|
|
3538
|
+
return [];
|
|
3539
|
+
}
|
|
3540
|
+
const importedPortHint = footprintConversionContext.portHintByPcbPortId.get(element.pcb_port_id);
|
|
3541
|
+
return importedPortHint ? [importedPortHint] : [];
|
|
3542
|
+
});
|
|
3543
|
+
const aliases = [
|
|
3544
|
+
sourcePort.name,
|
|
3545
|
+
...sourcePort.port_hints ?? [],
|
|
3546
|
+
...importedPortHints
|
|
3547
|
+
].filter(
|
|
3548
|
+
(alias, aliasIndex, allAliases) => alias.length > 0 && allAliases.indexOf(alias) === aliasIndex
|
|
3549
|
+
);
|
|
3550
|
+
let pinNumber = getCompoundPinNumber(sourcePort);
|
|
3551
|
+
if (pinNumber === void 0) {
|
|
3552
|
+
while (usedPinNumbers.has(nextSyntheticPinNumber)) {
|
|
3553
|
+
nextSyntheticPinNumber += 1;
|
|
3554
|
+
}
|
|
3555
|
+
pinNumber = nextSyntheticPinNumber;
|
|
3556
|
+
usedPinNumbers.add(pinNumber);
|
|
3557
|
+
nextSyntheticPinNumber += 1;
|
|
2668
3558
|
}
|
|
2669
|
-
|
|
2670
|
-
|
|
3559
|
+
const pinLabelKey = `pin${pinNumber}`;
|
|
3560
|
+
pinLabels[pinLabelKey] = [
|
|
3561
|
+
...pinLabels[pinLabelKey] ?? [],
|
|
3562
|
+
...aliases
|
|
3563
|
+
].filter(
|
|
3564
|
+
(alias, aliasIndex, allAliases) => allAliases.indexOf(alias) === aliasIndex
|
|
3565
|
+
);
|
|
3566
|
+
}
|
|
3567
|
+
return Object.keys(pinLabels).length > 0 ? pinLabels : void 0;
|
|
3568
|
+
};
|
|
3569
|
+
|
|
3570
|
+
// lib/board-converter/get-schematic-components-for-pcb-component.ts
|
|
3571
|
+
var getSchematicComponentsForPcbComponent = ({
|
|
3572
|
+
circuitJson,
|
|
3573
|
+
pcbComponent
|
|
3574
|
+
}) => {
|
|
3575
|
+
const sourceComponents = circuitJson.filter(
|
|
3576
|
+
(element) => element.type === "source_component"
|
|
3577
|
+
);
|
|
3578
|
+
const pcbSourceComponent = sourceComponents.find(
|
|
3579
|
+
(sourceComponent) => sourceComponent.source_component_id === pcbComponent.source_component_id
|
|
3580
|
+
);
|
|
3581
|
+
if (!pcbSourceComponent) return [];
|
|
3582
|
+
const matchingSourceComponentIds = new Set(
|
|
3583
|
+
sourceComponents.filter(
|
|
3584
|
+
(sourceComponent) => sourceComponent.source_component_id === pcbSourceComponent.source_component_id || pcbSourceComponent.name !== void 0 && sourceComponent.name === pcbSourceComponent.name
|
|
3585
|
+
).map((sourceComponent) => sourceComponent.source_component_id).filter(
|
|
3586
|
+
(sourceComponentId) => sourceComponentId !== void 0
|
|
3587
|
+
)
|
|
3588
|
+
);
|
|
3589
|
+
return circuitJson.filter(
|
|
3590
|
+
(element) => element.type === "schematic_component" && element.source_component_id !== void 0 && matchingSourceComponentIds.has(element.source_component_id)
|
|
3591
|
+
);
|
|
3592
|
+
};
|
|
3593
|
+
|
|
3594
|
+
// lib/board-converter/localize-pcb-component-elements.ts
|
|
3595
|
+
import { transformPCBElements } from "@tscircuit/circuit-json-util";
|
|
3596
|
+
import {
|
|
3597
|
+
applyToPoint as applyToPoint6,
|
|
3598
|
+
compose as compose4,
|
|
3599
|
+
decomposeTSR,
|
|
3600
|
+
flipY,
|
|
3601
|
+
inverse as inverse2,
|
|
3602
|
+
rotateDEG as rotateDEG3,
|
|
3603
|
+
translate as translate6
|
|
3604
|
+
} from "transformation-matrix";
|
|
3605
|
+
var FLOATING_POINT_NOISE_THRESHOLD = 1e-12;
|
|
3606
|
+
var LOCAL_COORDINATE_DECIMAL_PLACES = 12;
|
|
3607
|
+
var normalizeFloatingPointNoise = (elementPropertyValue) => {
|
|
3608
|
+
if (Array.isArray(elementPropertyValue)) {
|
|
3609
|
+
for (const item of elementPropertyValue) normalizeFloatingPointNoise(item);
|
|
3610
|
+
return;
|
|
3611
|
+
}
|
|
3612
|
+
if (typeof elementPropertyValue !== "object" || elementPropertyValue === null)
|
|
3613
|
+
return;
|
|
3614
|
+
const record = elementPropertyValue;
|
|
3615
|
+
for (const [key, property] of Object.entries(record)) {
|
|
3616
|
+
if (typeof property === "number" && Math.abs(property) < FLOATING_POINT_NOISE_THRESHOLD) {
|
|
3617
|
+
record[key] = 0;
|
|
3618
|
+
} else {
|
|
3619
|
+
normalizeFloatingPointNoise(property);
|
|
2671
3620
|
}
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
3621
|
+
}
|
|
3622
|
+
};
|
|
3623
|
+
var normalizeRoutableElementCoordinates = (localComponentElements) => {
|
|
3624
|
+
for (const element of localComponentElements) {
|
|
3625
|
+
if (element.type !== "pcb_smtpad" && element.type !== "pcb_plated_hole") {
|
|
3626
|
+
continue;
|
|
2675
3627
|
}
|
|
2676
|
-
if (
|
|
2677
|
-
|
|
3628
|
+
if (!("x" in element) || !("y" in element)) continue;
|
|
3629
|
+
element.x = Number(element.x.toFixed(LOCAL_COORDINATE_DECIMAL_PLACES));
|
|
3630
|
+
element.y = Number(element.y.toFixed(LOCAL_COORDINATE_DECIMAL_PLACES));
|
|
3631
|
+
}
|
|
3632
|
+
};
|
|
3633
|
+
var transformSilkscreenGraphic = ({
|
|
3634
|
+
absoluteToComponentLocalTransform,
|
|
3635
|
+
graphic
|
|
3636
|
+
}) => {
|
|
3637
|
+
if (graphic.shape !== "brep") return;
|
|
3638
|
+
graphic.brep_shape.outer_ring.vertices = graphic.brep_shape.outer_ring.vertices.map(
|
|
3639
|
+
(vertex) => applyToPoint6(absoluteToComponentLocalTransform, vertex)
|
|
3640
|
+
);
|
|
3641
|
+
graphic.brep_shape.inner_rings = graphic.brep_shape.inner_rings.map(
|
|
3642
|
+
(ring) => ({
|
|
3643
|
+
...ring,
|
|
3644
|
+
vertices: ring.vertices.map(
|
|
3645
|
+
(vertex) => applyToPoint6(absoluteToComponentLocalTransform, vertex)
|
|
3646
|
+
)
|
|
3647
|
+
})
|
|
3648
|
+
);
|
|
3649
|
+
};
|
|
3650
|
+
var normalizeDegrees = (degrees) => (degrees % 360 + 360) % 360;
|
|
3651
|
+
var getTransformedCcwRotationDegrees = ({
|
|
3652
|
+
absoluteCcwRotationDegrees,
|
|
3653
|
+
absoluteToComponentLocalRotationTransform
|
|
3654
|
+
}) => {
|
|
3655
|
+
const transformedRotation = decomposeTSR(
|
|
3656
|
+
compose4(
|
|
3657
|
+
absoluteToComponentLocalRotationTransform,
|
|
3658
|
+
rotateDEG3(absoluteCcwRotationDegrees)
|
|
3659
|
+
)
|
|
3660
|
+
).rotation.angle;
|
|
3661
|
+
return normalizeDegrees(transformedRotation * 180 / Math.PI);
|
|
3662
|
+
};
|
|
3663
|
+
var localizePrimitiveRotations = ({
|
|
3664
|
+
absoluteComponentElements,
|
|
3665
|
+
absoluteToComponentLocalRotationTransform,
|
|
3666
|
+
localComponentElements
|
|
3667
|
+
}) => {
|
|
3668
|
+
const rotationPropertyNames = [
|
|
3669
|
+
"ccw_rotation",
|
|
3670
|
+
"hole_ccw_rotation",
|
|
3671
|
+
"rect_ccw_rotation"
|
|
3672
|
+
];
|
|
3673
|
+
for (const [elementIndex, localElement] of localComponentElements.entries()) {
|
|
3674
|
+
if (localElement.type === "pcb_silkscreen_text" || localElement.type === "pcb_copper_text" || localElement.type === "pcb_fabrication_note_text") {
|
|
3675
|
+
continue;
|
|
2678
3676
|
}
|
|
2679
|
-
|
|
2680
|
-
|
|
3677
|
+
const absoluteElement = absoluteComponentElements[elementIndex];
|
|
3678
|
+
if (absoluteElement?.type !== localElement.type) continue;
|
|
3679
|
+
const absoluteRotations = absoluteElement;
|
|
3680
|
+
const localRotations = localElement;
|
|
3681
|
+
for (const rotationPropertyName of rotationPropertyNames) {
|
|
3682
|
+
const absoluteCcwRotationDegrees = absoluteRotations[rotationPropertyName];
|
|
3683
|
+
if (typeof absoluteCcwRotationDegrees !== "number") continue;
|
|
3684
|
+
localRotations[rotationPropertyName] = getTransformedCcwRotationDegrees({
|
|
3685
|
+
absoluteCcwRotationDegrees,
|
|
3686
|
+
absoluteToComponentLocalRotationTransform
|
|
3687
|
+
});
|
|
2681
3688
|
}
|
|
2682
|
-
|
|
2683
|
-
|
|
3689
|
+
}
|
|
3690
|
+
};
|
|
3691
|
+
var getOppositeOuterLayer = (layer) => {
|
|
3692
|
+
if (layer === "top") return "bottom";
|
|
3693
|
+
if (layer === "bottom") return "top";
|
|
3694
|
+
return layer;
|
|
3695
|
+
};
|
|
3696
|
+
var localizeBottomComponentLayers = (localComponentElements) => {
|
|
3697
|
+
for (const localElement of localComponentElements) {
|
|
3698
|
+
if ("layer" in localElement && (localElement.layer === "top" || localElement.layer === "bottom")) {
|
|
3699
|
+
localElement.layer = getOppositeOuterLayer(localElement.layer);
|
|
2684
3700
|
}
|
|
2685
|
-
if (
|
|
2686
|
-
|
|
3701
|
+
if ("layers" in localElement && Array.isArray(localElement.layers)) {
|
|
3702
|
+
localElement.layers = localElement.layers.map(
|
|
3703
|
+
(layer) => layer === "top" || layer === "bottom" ? getOppositeOuterLayer(layer) : layer
|
|
3704
|
+
);
|
|
2687
3705
|
}
|
|
2688
|
-
|
|
2689
|
-
|
|
3706
|
+
}
|
|
3707
|
+
};
|
|
3708
|
+
var localizeTextRotations = ({
|
|
3709
|
+
absoluteComponentElements,
|
|
3710
|
+
componentCcwRotationDegrees,
|
|
3711
|
+
localComponentElements
|
|
3712
|
+
}) => {
|
|
3713
|
+
for (const [elementIndex, localElement] of localComponentElements.entries()) {
|
|
3714
|
+
if (localElement.type !== "pcb_silkscreen_text" && localElement.type !== "pcb_copper_text" && localElement.type !== "pcb_fabrication_note_text") {
|
|
3715
|
+
continue;
|
|
2690
3716
|
}
|
|
2691
|
-
const
|
|
2692
|
-
if (
|
|
2693
|
-
|
|
2694
|
-
|
|
3717
|
+
const absoluteElement = absoluteComponentElements[elementIndex];
|
|
3718
|
+
if (absoluteElement?.type !== localElement.type) continue;
|
|
3719
|
+
const absoluteRotation = normalizeDegrees(absoluteElement.ccw_rotation ?? 0);
|
|
3720
|
+
if (localElement.type === "pcb_silkscreen_text") {
|
|
3721
|
+
localElement.ccw_rotation = absoluteRotation || 360;
|
|
3722
|
+
} else if (localElement.type === "pcb_copper_text") {
|
|
3723
|
+
localElement.ccw_rotation = absoluteRotation;
|
|
3724
|
+
} else {
|
|
3725
|
+
localElement.ccw_rotation = normalizeDegrees(
|
|
3726
|
+
absoluteRotation - componentCcwRotationDegrees
|
|
2695
3727
|
);
|
|
2696
3728
|
}
|
|
2697
|
-
|
|
2698
|
-
|
|
3729
|
+
}
|
|
3730
|
+
};
|
|
3731
|
+
var localizePcbComponentElements = ({
|
|
3732
|
+
circuitJson,
|
|
3733
|
+
pcbComponent
|
|
3734
|
+
}) => {
|
|
3735
|
+
const absoluteComponentElements = circuitJson.filter(
|
|
3736
|
+
(element) => "pcb_component_id" in element && element.pcb_component_id === pcbComponent.pcb_component_id
|
|
3737
|
+
);
|
|
3738
|
+
const localComponentElements = structuredClone(absoluteComponentElements);
|
|
3739
|
+
const componentLocalToAbsoluteTransform = compose4(
|
|
3740
|
+
translate6(pcbComponent.center.x, pcbComponent.center.y),
|
|
3741
|
+
rotateDEG3(pcbComponent.rotation)
|
|
3742
|
+
);
|
|
3743
|
+
let absoluteToComponentLocalTransform = inverse2(
|
|
3744
|
+
componentLocalToAbsoluteTransform
|
|
3745
|
+
);
|
|
3746
|
+
if (pcbComponent.layer === "bottom") {
|
|
3747
|
+
absoluteToComponentLocalTransform = compose4(
|
|
3748
|
+
flipY(),
|
|
3749
|
+
absoluteToComponentLocalTransform
|
|
3750
|
+
);
|
|
3751
|
+
}
|
|
3752
|
+
transformPCBElements(
|
|
3753
|
+
localComponentElements,
|
|
3754
|
+
absoluteToComponentLocalTransform
|
|
3755
|
+
);
|
|
3756
|
+
for (const localElement of localComponentElements) {
|
|
3757
|
+
if (localElement.type === "pcb_silkscreen_graphic") {
|
|
3758
|
+
transformSilkscreenGraphic({
|
|
3759
|
+
absoluteToComponentLocalTransform,
|
|
3760
|
+
graphic: localElement
|
|
3761
|
+
});
|
|
2699
3762
|
}
|
|
2700
3763
|
}
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
const boardNetsTsx = generateBoardNetsTsx(context);
|
|
2706
|
-
const boardCadModelsTsx = generateBoardCadModelsTsx({
|
|
2707
|
-
circuitJson,
|
|
2708
|
-
pcbBoard
|
|
3764
|
+
localizeTextRotations({
|
|
3765
|
+
absoluteComponentElements,
|
|
3766
|
+
componentCcwRotationDegrees: pcbComponent.rotation,
|
|
3767
|
+
localComponentElements
|
|
2709
3768
|
});
|
|
2710
|
-
|
|
2711
|
-
|
|
3769
|
+
localizePrimitiveRotations({
|
|
3770
|
+
absoluteComponentElements,
|
|
3771
|
+
absoluteToComponentLocalRotationTransform: inverse2(
|
|
3772
|
+
componentLocalToAbsoluteTransform
|
|
3773
|
+
),
|
|
3774
|
+
localComponentElements
|
|
3775
|
+
});
|
|
3776
|
+
if (pcbComponent.layer === "bottom") {
|
|
3777
|
+
localizeBottomComponentLayers(localComponentElements);
|
|
3778
|
+
}
|
|
3779
|
+
normalizeRoutableElementCoordinates(localComponentElements);
|
|
3780
|
+
normalizeFloatingPointNoise(localComponentElements);
|
|
3781
|
+
return localComponentElements;
|
|
3782
|
+
};
|
|
3783
|
+
|
|
3784
|
+
// lib/board-converter/stages/convert-pcb-components.ts
|
|
3785
|
+
var getComponentFootprintTsx = ({
|
|
3786
|
+
circuitJson,
|
|
3787
|
+
footprintConversionContext,
|
|
3788
|
+
pcbComponent
|
|
3789
|
+
}) => {
|
|
3790
|
+
const componentElements = localizePcbComponentElements({
|
|
2712
3791
|
circuitJson,
|
|
2713
|
-
|
|
3792
|
+
pcbComponent
|
|
2714
3793
|
});
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
3794
|
+
return generateFootprintTsx(componentElements, footprintConversionContext);
|
|
3795
|
+
};
|
|
3796
|
+
var convertPcbComponents = ({
|
|
3797
|
+
circuitJson,
|
|
3798
|
+
footprintConversionContext,
|
|
3799
|
+
pcbComponentRuntimeNameByPcbComponentId,
|
|
3800
|
+
pcbBoard,
|
|
3801
|
+
boardChildren
|
|
3802
|
+
}) => {
|
|
3803
|
+
const pcbComponents = circuitJson.filter(
|
|
3804
|
+
(element) => element.type === "pcb_component"
|
|
3805
|
+
);
|
|
3806
|
+
const cadModelGroupByPcbComponentId = /* @__PURE__ */ new Map();
|
|
3807
|
+
for (const cadModelGroup of getCadModelGroups(circuitJson)) {
|
|
3808
|
+
const pcbComponentId = cadModelGroup.cadComponents[0]?.pcb_component_id;
|
|
3809
|
+
if (pcbComponentId === void 0) continue;
|
|
3810
|
+
const existingCadModelGroup = cadModelGroupByPcbComponentId.get(pcbComponentId);
|
|
3811
|
+
cadModelGroupByPcbComponentId.set(
|
|
3812
|
+
pcbComponentId,
|
|
3813
|
+
existingCadModelGroup ? {
|
|
3814
|
+
...existingCadModelGroup,
|
|
3815
|
+
cadComponents: [
|
|
3816
|
+
...existingCadModelGroup.cadComponents,
|
|
3817
|
+
...cadModelGroup.cadComponents
|
|
3818
|
+
]
|
|
3819
|
+
} : cadModelGroup
|
|
3820
|
+
);
|
|
3821
|
+
}
|
|
3822
|
+
for (const pcbComponent of pcbComponents) {
|
|
3823
|
+
const sourceComponent = circuitJson.find(
|
|
3824
|
+
(element) => element.type === "source_component" && element.source_component_id === pcbComponent.source_component_id
|
|
3825
|
+
);
|
|
3826
|
+
const schematicComponents = getSchematicComponentsForPcbComponent({
|
|
3827
|
+
circuitJson,
|
|
3828
|
+
pcbComponent
|
|
3829
|
+
});
|
|
3830
|
+
const schematicSourceComponentIds = new Set(
|
|
3831
|
+
schematicComponents.map((schematicComponent) => schematicComponent.source_component_id).filter(
|
|
3832
|
+
(sourceComponentId) => sourceComponentId !== void 0
|
|
3833
|
+
)
|
|
3834
|
+
);
|
|
3835
|
+
const sourceComponents = circuitJson.filter(
|
|
3836
|
+
(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))
|
|
3837
|
+
);
|
|
3838
|
+
const { cadModelParentCenter, componentPosition } = getPcbComponentRenderPlacement({
|
|
3839
|
+
circuitJson,
|
|
3840
|
+
pcbBoard,
|
|
3841
|
+
pcbComponent
|
|
3842
|
+
});
|
|
3843
|
+
const footprintTsx = getComponentFootprintTsx({
|
|
3844
|
+
circuitJson,
|
|
3845
|
+
footprintConversionContext,
|
|
3846
|
+
pcbComponent
|
|
3847
|
+
});
|
|
3848
|
+
const pinLabels = getPinLabels({
|
|
3849
|
+
circuitJson,
|
|
3850
|
+
footprintConversionContext,
|
|
3851
|
+
pcbComponent,
|
|
3852
|
+
sourceComponents
|
|
3853
|
+
});
|
|
3854
|
+
const componentName = pcbComponentRuntimeNameByPcbComponentId.get(
|
|
3855
|
+
pcbComponent.pcb_component_id
|
|
3856
|
+
);
|
|
3857
|
+
if (!componentName) {
|
|
3858
|
+
throw new Error("Expected every PCB component to have a runtime name");
|
|
3859
|
+
}
|
|
3860
|
+
const cadModelGroup = cadModelGroupByPcbComponentId.get(
|
|
3861
|
+
pcbComponent.pcb_component_id
|
|
3862
|
+
);
|
|
3863
|
+
const localizedCadModelGroup = cadModelGroup ? {
|
|
3864
|
+
...cadModelGroup,
|
|
3865
|
+
parentPlacement: {
|
|
3866
|
+
center: cadModelParentCenter,
|
|
3867
|
+
ccwRotationDegrees: pcbComponent.rotation,
|
|
3868
|
+
layer: pcbComponent.layer === "bottom" ? "bottom" : "top"
|
|
3869
|
+
}
|
|
3870
|
+
} : void 0;
|
|
3871
|
+
const cadModelTsx = localizedCadModelGroup ? generateCadModelGroupModelTsx({
|
|
3872
|
+
cadModelGroup: localizedCadModelGroup,
|
|
3873
|
+
pcbBoard
|
|
3874
|
+
}) : void 0;
|
|
3875
|
+
const childModelElementsTsx = localizedCadModelGroup ? generateCadModelGroupChildrenTsx({
|
|
3876
|
+
cadModelGroup: localizedCadModelGroup,
|
|
3877
|
+
pcbBoard
|
|
3878
|
+
}) : [];
|
|
3879
|
+
const componentProps = [
|
|
3880
|
+
`name=${formatJsxStringAttribute(componentName)}`,
|
|
3881
|
+
`pcbX={${componentPosition.x}}`,
|
|
3882
|
+
`pcbY={${componentPosition.y}}`,
|
|
3883
|
+
`pcbRotation="${pcbComponent.rotation}deg"`,
|
|
3884
|
+
`layer="${pcbComponent.layer}"`,
|
|
3885
|
+
"noSchematicRepresentation"
|
|
3886
|
+
];
|
|
3887
|
+
if (cadModelTsx) {
|
|
3888
|
+
componentProps.push(`cadModel={${cadModelTsx}}`);
|
|
3889
|
+
}
|
|
3890
|
+
if (localizedCadModelGroup && isJscadCadModelGroupTranslucent(localizedCadModelGroup)) {
|
|
3891
|
+
componentProps.push("showAsTranslucentModel");
|
|
3892
|
+
}
|
|
3893
|
+
if (pinLabels) {
|
|
3894
|
+
componentProps.push(`pinLabels={${JSON.stringify(pinLabels)}}`);
|
|
3895
|
+
}
|
|
3896
|
+
if (sourceComponent?.manufacturer_part_number) {
|
|
3897
|
+
componentProps.push(
|
|
3898
|
+
`manufacturerPartNumber=${formatJsxStringAttribute(sourceComponent.manufacturer_part_number)}`
|
|
3899
|
+
);
|
|
3900
|
+
}
|
|
3901
|
+
if (sourceComponent?.supplier_part_numbers && Object.keys(sourceComponent.supplier_part_numbers).length > 0) {
|
|
3902
|
+
componentProps.push(
|
|
3903
|
+
`supplierPartNumbers={${JSON.stringify(sourceComponent.supplier_part_numbers)}}`
|
|
3904
|
+
);
|
|
3905
|
+
}
|
|
3906
|
+
if (pcbComponent.do_not_place === true) {
|
|
3907
|
+
componentProps.push("doNotPlace");
|
|
3908
|
+
}
|
|
3909
|
+
if (pcbComponent.obstructs_within_bounds === false) {
|
|
3910
|
+
componentProps.push("obstructsWithinBounds={false}");
|
|
3911
|
+
}
|
|
3912
|
+
const chipOpeningTsx = `<chip ${componentProps.join(" ")} footprint={${footprintTsx ?? "<footprint />"}}`;
|
|
3913
|
+
boardChildren.push(
|
|
3914
|
+
childModelElementsTsx.length === 0 ? `${chipOpeningTsx} />` : `${chipOpeningTsx}>${childModelElementsTsx.join("\n")}</chip>`
|
|
3915
|
+
);
|
|
3916
|
+
}
|
|
3917
|
+
};
|
|
3918
|
+
|
|
3919
|
+
// lib/board-converter/stages/convert-standalone-pcb-primitives.ts
|
|
3920
|
+
var convertStandalonePcbPrimitives = ({
|
|
3921
|
+
circuitJson,
|
|
3922
|
+
footprintConversionContext,
|
|
3923
|
+
pcbBoard,
|
|
3924
|
+
boardChildren
|
|
3925
|
+
}) => {
|
|
3926
|
+
const existingPcbComponentIds = new Set(
|
|
3927
|
+
circuitJson.flatMap(
|
|
3928
|
+
(element) => element.type === "pcb_component" ? [element.pcb_component_id] : []
|
|
3929
|
+
)
|
|
3930
|
+
);
|
|
3931
|
+
const standaloneElements = circuitJson.filter(
|
|
3932
|
+
(element) => !("pcb_component_id" in element) || !element.pcb_component_id || !existingPcbComponentIds.has(element.pcb_component_id)
|
|
3933
|
+
);
|
|
3934
|
+
const footprintTsx = generateFootprintTsx(
|
|
3935
|
+
standaloneElements,
|
|
3936
|
+
footprintConversionContext
|
|
3937
|
+
);
|
|
3938
|
+
if (!footprintTsx) return;
|
|
3939
|
+
const footprintContainerProps = [
|
|
3940
|
+
`name="${footprintConversionContext.pcbChipName}"`,
|
|
3941
|
+
"noSchematicRepresentation",
|
|
3942
|
+
"obstructsWithinBounds={false}"
|
|
3943
|
+
];
|
|
3944
|
+
if (pcbBoard.center.x !== 0) {
|
|
3945
|
+
footprintContainerProps.push(`pcbX={${-pcbBoard.center.x}}`);
|
|
3946
|
+
}
|
|
3947
|
+
if (pcbBoard.center.y !== 0) {
|
|
3948
|
+
footprintContainerProps.push(`pcbY={${-pcbBoard.center.y}}`);
|
|
3949
|
+
}
|
|
3950
|
+
boardChildren.push(
|
|
3951
|
+
`<chip${footprintContainerProps.length > 0 ? ` ${footprintContainerProps.join(" ")}` : ""} footprint={${footprintTsx}} />`
|
|
3952
|
+
);
|
|
3953
|
+
};
|
|
3954
|
+
|
|
3955
|
+
// lib/board-converter/convert-board-circuit-json.ts
|
|
3956
|
+
var conversionStages = [
|
|
3957
|
+
convertBoardProperties,
|
|
3958
|
+
convertPcbComponents,
|
|
3959
|
+
convertBoardNets,
|
|
3960
|
+
convertBoardTraces,
|
|
3961
|
+
convertCopperPours,
|
|
3962
|
+
convertBoardSchematic,
|
|
3963
|
+
convertStandalonePcbPrimitives,
|
|
3964
|
+
convertBoardCadModels
|
|
3965
|
+
];
|
|
3966
|
+
var convertBoardCircuitJson = ({
|
|
3967
|
+
circuitJson,
|
|
3968
|
+
componentName
|
|
3969
|
+
}) => {
|
|
3970
|
+
const pcbBoard = circuitJson.find((element) => element.type === "pcb_board");
|
|
3971
|
+
if (!pcbBoard) {
|
|
3972
|
+
throw new Error("Board conversion requires a pcb_board element");
|
|
3973
|
+
}
|
|
3974
|
+
const {
|
|
3975
|
+
pcbChipName,
|
|
3976
|
+
pcbComponentRuntimeNameByPcbComponentId,
|
|
3977
|
+
standaloneCadModelRuntimeNameByCadComponentId
|
|
3978
|
+
} = getBoardChildRuntimeNames(circuitJson);
|
|
3979
|
+
const context = {
|
|
3980
|
+
circuitJson,
|
|
3981
|
+
footprintConversionContext: createComponentPreservingBoardConversionContext(
|
|
3982
|
+
{
|
|
3983
|
+
circuitJson,
|
|
3984
|
+
pcbChipName,
|
|
3985
|
+
pcbComponentRuntimeNameByPcbComponentId
|
|
3986
|
+
}
|
|
3987
|
+
),
|
|
3988
|
+
pcbComponentRuntimeNameByPcbComponentId,
|
|
3989
|
+
standaloneCadModelRuntimeNameByCadComponentId,
|
|
3990
|
+
pcbBoard,
|
|
3991
|
+
boardProps: [],
|
|
3992
|
+
boardChildren: []
|
|
3993
|
+
};
|
|
3994
|
+
for (const convertStage of conversionStages) {
|
|
3995
|
+
convertStage(context);
|
|
3996
|
+
}
|
|
3997
|
+
const boardProps = context.boardProps.join(" ");
|
|
3998
|
+
const boardChildren = context.boardChildren.join("\n");
|
|
2722
3999
|
return `
|
|
2723
4000
|
${componentName ? `export const ${componentName} =` : "export default"} () => (
|
|
2724
|
-
<board${
|
|
2725
|
-
${
|
|
4001
|
+
<board${boardProps ? ` ${boardProps}` : ""}>
|
|
4002
|
+
${boardChildren.replace(/\n/g, "\n ")}
|
|
2726
4003
|
</board>
|
|
2727
4004
|
)
|
|
2728
4005
|
${componentName ? `export default ${componentName}` : ""}
|
|
2729
4006
|
`.replace(/\n\s*\n/g, "\n").trim();
|
|
2730
4007
|
};
|
|
2731
4008
|
|
|
4009
|
+
// lib/get-board-using-template.ts
|
|
4010
|
+
var getBoardUsingTemplate = ({
|
|
4011
|
+
circuitJson,
|
|
4012
|
+
componentName
|
|
4013
|
+
}) => convertBoardCircuitJson({ circuitJson, componentName });
|
|
4014
|
+
|
|
2732
4015
|
// lib/get-pin-attributes.ts
|
|
2733
4016
|
var attributeNames = {
|
|
2734
4017
|
is_input: "isInput",
|