@tscircuit/circuit-json-util 0.0.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,636 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // index.ts
31
+ var soup_util_exports = {};
32
+ __export(soup_util_exports, {
33
+ applySelector: () => applySelector,
34
+ applySelectorAST: () => applySelectorAST,
35
+ directionToVec: () => directionToVec,
36
+ getBoundsOfPcbElements: () => getBoundsOfPcbElements,
37
+ getElementById: () => getElementById,
38
+ getElementId: () => getElementId,
39
+ getReadableNameForElement: () => getReadableNameForElement,
40
+ getReadableNameForPcbPort: () => getReadableNameForPcbPort,
41
+ getReadableNameForPcbSmtpad: () => getReadableNameForPcbSmtpad,
42
+ getReadableNameForPcbTrace: () => getReadableNameForPcbTrace,
43
+ oppositeDirection: () => oppositeDirection,
44
+ oppositeSide: () => oppositeSide,
45
+ rotateClockwise: () => rotateClockwise,
46
+ rotateCounterClockwise: () => rotateCounterClockwise,
47
+ rotateDirection: () => rotateDirection,
48
+ su: () => su_default,
49
+ transformPCBElement: () => transformPCBElement,
50
+ transformPCBElements: () => transformPCBElements,
51
+ transformSchematicElement: () => transformSchematicElement,
52
+ transformSchematicElements: () => transformSchematicElements,
53
+ vecToDirection: () => vecToDirection
54
+ });
55
+ module.exports = __toCommonJS(soup_util_exports);
56
+
57
+ // lib/su.ts
58
+ var Soup = __toESM(require("@tscircuit/soup"), 1);
59
+ var su = (soup, options = {}) => {
60
+ let internalStore = soup._internal_store;
61
+ if (!internalStore) {
62
+ internalStore = {
63
+ counts: {}
64
+ };
65
+ soup._internal_store = internalStore;
66
+ for (const elm of soup) {
67
+ const type = elm.type;
68
+ const idVal = elm[`${type}_id`];
69
+ if (!idVal)
70
+ continue;
71
+ const idNum = Number.parseInt(idVal.split("_").pop());
72
+ if (!Number.isNaN(idNum)) {
73
+ internalStore.counts[type] = Math.max(
74
+ internalStore.counts[type] ?? 0,
75
+ idNum
76
+ );
77
+ }
78
+ }
79
+ }
80
+ const su2 = new Proxy(
81
+ {},
82
+ {
83
+ get: (proxy_target, component_type) => {
84
+ if (component_type === "toArray") {
85
+ return () => soup;
86
+ }
87
+ return {
88
+ get: (id) => soup.find(
89
+ (e) => e.type === component_type && e[`${component_type}_id`] === id
90
+ ),
91
+ getUsing: (using) => {
92
+ const keys = Object.keys(using);
93
+ if (keys.length !== 1) {
94
+ throw new Error(
95
+ "getUsing requires exactly one key, e.g. { pcb_component_id }"
96
+ );
97
+ }
98
+ const join_key = keys[0];
99
+ const join_type = join_key.replace("_id", "");
100
+ const joiner = soup.find(
101
+ (e) => e.type === join_type && e[join_key] === using[join_key]
102
+ );
103
+ if (!joiner)
104
+ return null;
105
+ return soup.find(
106
+ (e) => e.type === component_type && e[`${component_type}_id`] === joiner[`${component_type}_id`]
107
+ );
108
+ },
109
+ getWhere: (where) => {
110
+ const keys = Object.keys(where);
111
+ return soup.find(
112
+ (e) => e.type === component_type && keys.every((key) => e[key] === where[key])
113
+ );
114
+ },
115
+ list: (where) => {
116
+ const keys = !where ? [] : Object.keys(where);
117
+ return soup.filter(
118
+ (e) => e.type === component_type && keys.every((key) => e[key] === where[key])
119
+ );
120
+ },
121
+ insert: (elm) => {
122
+ internalStore.counts[component_type] ??= -1;
123
+ internalStore.counts[component_type]++;
124
+ const index = internalStore.counts[component_type];
125
+ const newElm = {
126
+ type: component_type,
127
+ [`${component_type}_id`]: `${component_type}_${index}`,
128
+ ...elm
129
+ };
130
+ if (options.validateInserts) {
131
+ const parser = Soup[component_type] ?? Soup.any_soup_element;
132
+ parser.parse(newElm);
133
+ }
134
+ soup.push(newElm);
135
+ return newElm;
136
+ },
137
+ delete: (id) => {
138
+ const elm = soup.find(
139
+ (e) => e[`${component_type}_id`] === id
140
+ );
141
+ if (!elm)
142
+ return;
143
+ soup.splice(soup.indexOf(elm), 1);
144
+ },
145
+ update: (id, newProps) => {
146
+ const elm = soup.find(
147
+ (e) => e[`${component_type}_id`] === id
148
+ );
149
+ if (!elm)
150
+ return;
151
+ Object.assign(elm, newProps);
152
+ return elm;
153
+ },
154
+ select: (selector) => {
155
+ if (component_type === "source_component") {
156
+ return soup.find(
157
+ (e) => e.type === "source_component" && e.name === selector.replace(/\./g, "")
158
+ );
159
+ } else if (component_type === "pcb_port" || component_type === "source_port" || component_type === "schematic_port") {
160
+ const [component_name, port_selector] = selector.replace(/\./g, "").split(/[\s\>]+/);
161
+ const source_component = soup.find(
162
+ (e) => e.type === "source_component" && e.name === component_name
163
+ );
164
+ if (!source_component)
165
+ return null;
166
+ const source_port = soup.find(
167
+ (e) => e.type === "source_port" && e.source_component_id === source_component.source_component_id && (e.name === port_selector || (e.port_hints ?? []).includes(port_selector))
168
+ );
169
+ if (!source_port)
170
+ return null;
171
+ if (component_type === "source_port")
172
+ return source_port;
173
+ if (component_type === "pcb_port") {
174
+ return soup.find(
175
+ (e) => e.type === "pcb_port" && e.source_port_id === source_port.source_port_id
176
+ );
177
+ } else if (component_type === "schematic_port") {
178
+ return soup.find(
179
+ (e) => e.type === "schematic_port" && e.source_port_id === source_port.source_port_id
180
+ );
181
+ }
182
+ }
183
+ }
184
+ };
185
+ }
186
+ }
187
+ );
188
+ return su2;
189
+ };
190
+ su.unparsed = su;
191
+ var su_default = su;
192
+
193
+ // lib/transform-soup-elements.ts
194
+ var import_transformation_matrix = require("transformation-matrix");
195
+
196
+ // lib/direction-to-vec.ts
197
+ var directionToVec = (direction) => {
198
+ if (direction === "up")
199
+ return { x: 0, y: 1 };
200
+ else if (direction === "down")
201
+ return { x: 0, y: -1 };
202
+ else if (direction === "left")
203
+ return { x: -1, y: 0 };
204
+ else if (direction === "right")
205
+ return { x: 1, y: 0 };
206
+ else
207
+ throw new Error("Invalid direction");
208
+ };
209
+ var vecToDirection = ({ x, y }) => {
210
+ if (x > y)
211
+ y = 0;
212
+ if (y > x)
213
+ x = 0;
214
+ if (x > 0 && y === 0)
215
+ return "right";
216
+ else if (x < 0 && y === 0)
217
+ return "left";
218
+ else if (x === 0 && y > 0)
219
+ return "up";
220
+ else if (x === 0 && y < 0)
221
+ return "down";
222
+ else
223
+ throw new Error(`Invalid vector for direction conversion (${x}, ${y})`);
224
+ };
225
+ var rotateClockwise = (direction) => {
226
+ if (direction === "up")
227
+ return "right";
228
+ else if (direction === "right")
229
+ return "down";
230
+ else if (direction === "down")
231
+ return "left";
232
+ else if (direction === "left")
233
+ return "up";
234
+ throw new Error(`Invalid direction: ${direction}`);
235
+ };
236
+ var rotateCounterClockwise = (direction) => {
237
+ if (direction === "up")
238
+ return "left";
239
+ else if (direction === "left")
240
+ return "down";
241
+ else if (direction === "down")
242
+ return "right";
243
+ else if (direction === "right")
244
+ return "up";
245
+ throw new Error(`Invalid direction: ${direction}`);
246
+ };
247
+ var rotateDirection = (direction, num90DegreeClockwiseTurns) => {
248
+ while (num90DegreeClockwiseTurns > 0) {
249
+ direction = rotateClockwise(direction);
250
+ num90DegreeClockwiseTurns--;
251
+ }
252
+ while (num90DegreeClockwiseTurns < 0) {
253
+ direction = rotateCounterClockwise(direction);
254
+ num90DegreeClockwiseTurns++;
255
+ }
256
+ return direction;
257
+ };
258
+ var oppositeDirection = (direction) => {
259
+ if (direction === "up")
260
+ return "down";
261
+ else if (direction === "down")
262
+ return "up";
263
+ else if (direction === "left")
264
+ return "right";
265
+ else if (direction === "right")
266
+ return "left";
267
+ throw new Error(`Invalid direction: ${direction}`);
268
+ };
269
+ var oppositeSide = (sideOrDir) => {
270
+ if (sideOrDir === "top" || sideOrDir === "up")
271
+ return "bottom";
272
+ else if (sideOrDir === "bottom" || sideOrDir === "down")
273
+ return "top";
274
+ else if (sideOrDir === "left")
275
+ return "right";
276
+ else if (sideOrDir === "right")
277
+ return "left";
278
+ throw new Error(`Invalid sideOrDir: ${sideOrDir}`);
279
+ };
280
+
281
+ // lib/transform-soup-elements.ts
282
+ var transformSchematicElement = (elm, matrix) => {
283
+ if (elm.type === "schematic_component") {
284
+ elm.center = (0, import_transformation_matrix.applyToPoint)(matrix, elm.center);
285
+ } else if (elm.type === "schematic_port") {
286
+ elm.center = (0, import_transformation_matrix.applyToPoint)(matrix, elm.center);
287
+ if (elm.facing_direction) {
288
+ elm.facing_direction = rotateDirection(
289
+ elm.facing_direction,
290
+ -(Math.atan2(matrix.b, matrix.a) / Math.PI) * 2
291
+ );
292
+ }
293
+ } else if (elm.type === "schematic_text") {
294
+ elm.position = (0, import_transformation_matrix.applyToPoint)(matrix, elm.position);
295
+ } else if (elm.type === "schematic_trace") {
296
+ } else if (elm.type === "schematic_box") {
297
+ const { x, y } = (0, import_transformation_matrix.applyToPoint)(matrix, { x: elm.x, y: elm.y });
298
+ elm.x = x;
299
+ elm.y = y;
300
+ } else if (elm.type === "schematic_line") {
301
+ const { x: x1, y: y1 } = (0, import_transformation_matrix.applyToPoint)(matrix, { x: elm.x1, y: elm.y1 });
302
+ const { x: x2, y: y2 } = (0, import_transformation_matrix.applyToPoint)(matrix, { x: elm.x2, y: elm.y2 });
303
+ elm.x1 = x1;
304
+ elm.y1 = y1;
305
+ elm.x2 = x2;
306
+ elm.y2 = y2;
307
+ }
308
+ return elm;
309
+ };
310
+ var transformSchematicElements = (elms, matrix) => {
311
+ return elms.map((elm) => transformSchematicElement(elm, matrix));
312
+ };
313
+ var transformPCBElement = (elm, matrix) => {
314
+ if (elm.type === "pcb_plated_hole" || elm.type === "pcb_hole" || elm.type === "pcb_via" || elm.type === "pcb_smtpad" || elm.type === "pcb_port") {
315
+ const { x, y } = (0, import_transformation_matrix.applyToPoint)(matrix, { x: elm.x, y: elm.y });
316
+ elm.x = x;
317
+ elm.y = y;
318
+ } else if (elm.type === "pcb_keepout" || elm.type === "pcb_board") {
319
+ elm.center = (0, import_transformation_matrix.applyToPoint)(matrix, elm.center);
320
+ } else if (elm.type === "pcb_silkscreen_text" || elm.type === "pcb_fabrication_note_text") {
321
+ elm.anchor_position = (0, import_transformation_matrix.applyToPoint)(matrix, elm.anchor_position);
322
+ } else if (elm.type === "pcb_silkscreen_circle" || elm.type === "pcb_silkscreen_rect" || elm.type === "pcb_component") {
323
+ elm.center = (0, import_transformation_matrix.applyToPoint)(matrix, elm.center);
324
+ } else if (elm.type === "pcb_silkscreen_path" || elm.type === "pcb_trace" || elm.type === "pcb_fabrication_note_path") {
325
+ elm.route = elm.route.map((rp) => {
326
+ const tp = (0, import_transformation_matrix.applyToPoint)(matrix, rp);
327
+ rp.x = tp.x;
328
+ rp.y = tp.y;
329
+ return rp;
330
+ });
331
+ } else if (elm.type === "pcb_silkscreen_line") {
332
+ const p1 = { x: elm.x1, y: elm.y1 };
333
+ const p2 = { x: elm.x2, y: elm.y2 };
334
+ const p1t = (0, import_transformation_matrix.applyToPoint)(matrix, p1);
335
+ const p2t = (0, import_transformation_matrix.applyToPoint)(matrix, p2);
336
+ elm.x1 = p1t.x;
337
+ elm.y1 = p1t.y;
338
+ elm.x2 = p2t.x;
339
+ elm.y2 = p2t.y;
340
+ } else if (elm.type === "cad_component") {
341
+ const newPos = (0, import_transformation_matrix.applyToPoint)(matrix, {
342
+ x: elm.position.x,
343
+ y: elm.position.y
344
+ });
345
+ elm.position.x = newPos.x;
346
+ elm.position.y = newPos.y;
347
+ }
348
+ return elm;
349
+ };
350
+ var transformPCBElements = (elms, matrix) => {
351
+ const tsr = (0, import_transformation_matrix.decomposeTSR)(matrix);
352
+ const flipPadWidthHeight = Math.round(tsr.rotation.angle / (Math.PI / 2)) % 2 === 1;
353
+ let transformedElms = elms.map((elm) => transformPCBElement(elm, matrix));
354
+ if (flipPadWidthHeight) {
355
+ transformedElms = transformedElms.map((elm) => {
356
+ if (elm.type === "pcb_smtpad" && elm.shape === "rect") {
357
+ ;
358
+ [elm.width, elm.height] = [elm.height, elm.width];
359
+ }
360
+ return elm;
361
+ });
362
+ }
363
+ return transformedElms;
364
+ };
365
+
366
+ // lib/apply-selector.ts
367
+ var parsel = __toESM(require("parsel-js"), 1);
368
+
369
+ // lib/convert-abbreviation-to-soup-element-type.ts
370
+ var convertAbbrToType = (abbr) => {
371
+ switch (abbr) {
372
+ case "port":
373
+ return "source_port";
374
+ case "net":
375
+ return "source_net";
376
+ case "power":
377
+ return "simple_power_source";
378
+ }
379
+ return abbr;
380
+ };
381
+
382
+ // lib/apply-selector.ts
383
+ var filterByType = (elements, type) => {
384
+ type = convertAbbrToType(type);
385
+ return elements.filter(
386
+ (elm) => "ftype" in elm && elm.ftype === type || elm.type === type
387
+ );
388
+ };
389
+ var applySelector = (elements, selectorRaw) => {
390
+ const selectorAST = parsel.parse(selectorRaw);
391
+ return applySelectorAST(elements, selectorAST);
392
+ };
393
+ var doesElmMatchClassName = (elm, className) => "name" in elm && elm.name === className || "port_hints" in elm && elm.port_hints?.includes(className);
394
+ var applySelectorAST = (elements, selectorAST) => {
395
+ switch (selectorAST.type) {
396
+ case "complex": {
397
+ switch (selectorAST.combinator) {
398
+ case " ":
399
+ case ">": {
400
+ const { left, right } = selectorAST;
401
+ if (left.type === "class" || left.type === "type") {
402
+ let matchElms;
403
+ if (left.type === "class") {
404
+ matchElms = elements.filter(
405
+ (elm) => doesElmMatchClassName(elm, left.name)
406
+ );
407
+ } else if (left.type === "type") {
408
+ matchElms = filterByType(elements, left.name);
409
+ } else {
410
+ matchElms = [];
411
+ }
412
+ const childrenOfMatchingElms = matchElms.flatMap(
413
+ (matchElm) => elements.filter(
414
+ (elm) => elm[`${matchElm.type}_id`] === matchElm[`${matchElm.type}_id`] && elm !== matchElm
415
+ )
416
+ );
417
+ return applySelectorAST(childrenOfMatchingElms, right);
418
+ } else {
419
+ throw new Error(`unsupported selector type "${left.type}" `);
420
+ }
421
+ }
422
+ default: {
423
+ throw new Error(
424
+ `Couldn't apply selector AST for complex combinator "${selectorAST.combinator}"`
425
+ );
426
+ }
427
+ }
428
+ return [];
429
+ }
430
+ case "compound": {
431
+ const conditionsToMatch = selectorAST.list.map((part) => {
432
+ switch (part.type) {
433
+ case "class": {
434
+ return (elm) => doesElmMatchClassName(elm, part.name);
435
+ }
436
+ case "type": {
437
+ const name = convertAbbrToType(part.name);
438
+ return (elm) => elm.type === name;
439
+ }
440
+ }
441
+ });
442
+ return elements.filter(
443
+ (elm) => conditionsToMatch.every((condFn) => condFn?.(elm))
444
+ );
445
+ }
446
+ case "type": {
447
+ return filterByType(elements, selectorAST.name);
448
+ }
449
+ case "class": {
450
+ return elements.filter(
451
+ (elm) => doesElmMatchClassName(elm, selectorAST.name)
452
+ );
453
+ }
454
+ default: {
455
+ throw new Error(
456
+ `Couldn't apply selector AST for type: "${selectorAST.type}" ${JSON.stringify(selectorAST, null, " ")}`
457
+ );
458
+ }
459
+ }
460
+ };
461
+
462
+ // lib/get-element-id.ts
463
+ var getElementId = (elm) => {
464
+ const type = elm.type;
465
+ const id = elm[`${type}_id`];
466
+ return id;
467
+ };
468
+
469
+ // lib/get-element-by-id.ts
470
+ var getElementById = (soup, id) => {
471
+ return soup.find((elm) => getElementId(elm) === id) ?? null;
472
+ };
473
+
474
+ // lib/readable-name-functions/get-readable-name-for-pcb-trace.ts
475
+ function getReadableNameForPcbTrace(soup, pcb_trace_id) {
476
+ const pcbTrace = su(soup).pcb_trace.get(pcb_trace_id);
477
+ if (!pcbTrace) {
478
+ return `trace[${pcb_trace_id}]`;
479
+ }
480
+ const connectedPcbPortIds = pcbTrace.route.flatMap((point) => [point.start_pcb_port_id, point.end_pcb_port_id]).filter(Boolean);
481
+ if (connectedPcbPortIds.length === 0) {
482
+ return `trace[${pcb_trace_id}]`;
483
+ }
484
+ function getComponentAndPortInfo(pcb_port_id) {
485
+ const pcbPort = su(soup).pcb_port.get(pcb_port_id);
486
+ if (!pcbPort)
487
+ return null;
488
+ const pcbComponent = su(soup).pcb_component.get(pcbPort.pcb_component_id);
489
+ if (!pcbComponent)
490
+ return null;
491
+ const sourceComponent = su(soup).source_component.get(
492
+ pcbComponent.source_component_id
493
+ );
494
+ if (!sourceComponent)
495
+ return null;
496
+ const sourcePort = su(soup).source_port.get(pcbPort.source_port_id);
497
+ const portHint = sourcePort?.port_hints ? sourcePort.port_hints[1] : "";
498
+ return {
499
+ componentName: sourceComponent.name,
500
+ portHint
501
+ };
502
+ }
503
+ const selectorParts = connectedPcbPortIds.map((portId) => {
504
+ const info = getComponentAndPortInfo(portId);
505
+ if (info) {
506
+ return `.${info.componentName} > port.${info.portHint}`;
507
+ }
508
+ return `port[${portId}]`;
509
+ });
510
+ return `trace[${selectorParts.join(", ")}]`;
511
+ }
512
+
513
+ // lib/readable-name-functions/get-readable-name-for-pcb-port.ts
514
+ var getReadableNameForPcbPort = (soup, pcb_port_id) => {
515
+ const pcbPort = su(soup).pcb_port.get(pcb_port_id);
516
+ if (!pcbPort) {
517
+ return `pcb_port[#${pcb_port_id}]`;
518
+ }
519
+ const pcbComponent = su(soup).pcb_component.get(pcbPort?.pcb_component_id);
520
+ if (!pcbComponent) {
521
+ return `pcb_port[#${pcb_port_id}]`;
522
+ }
523
+ const sourceComponent = su(soup).source_component.get(
524
+ pcbComponent.source_component_id
525
+ );
526
+ if (!sourceComponent) {
527
+ return `pcb_port[#${pcb_port_id}]`;
528
+ }
529
+ const sourcePort = su(soup).source_port.get(pcbPort.source_port_id);
530
+ if (!sourcePort) {
531
+ return `pcb_port[#${pcb_port_id}]`;
532
+ }
533
+ let padIdentifier;
534
+ if (sourcePort?.port_hints && sourcePort.port_hints.length > 0) {
535
+ padIdentifier = sourcePort.port_hints[0];
536
+ } else if (sourcePort.port_hints && sourcePort.port_hints.length > 0) {
537
+ padIdentifier = sourcePort.port_hints[0];
538
+ } else {
539
+ padIdentifier = pcb_port_id;
540
+ }
541
+ return `pcb_port[.${sourceComponent.name} > .${padIdentifier}]`;
542
+ };
543
+
544
+ // lib/readable-name-functions/get-readable-name-for-pcb-smtpad.ts
545
+ function getReadableNameForPcbSmtpad(soup, pcb_smtpad_id) {
546
+ const pcbSmtpad = su(soup).pcb_smtpad.get(pcb_smtpad_id);
547
+ if (!pcbSmtpad || !pcbSmtpad.pcb_port_id) {
548
+ return `smtpad[${pcb_smtpad_id}]`;
549
+ }
550
+ return getReadableNameForPcbPort(soup, pcbSmtpad.pcb_port_id);
551
+ }
552
+
553
+ // lib/readable-name-functions/get-readable-name-for-element.ts
554
+ var getReadableNameForElement = (soup, elm) => {
555
+ if (typeof elm === "string") {
556
+ const elmObj = getElementById(soup, elm);
557
+ if (!elmObj)
558
+ `unknown (could not find element with id ${elm})`;
559
+ return getReadableNameForElement(soup, elmObj);
560
+ }
561
+ switch (elm.type) {
562
+ case "pcb_port":
563
+ return getReadableNameForPcbPort(soup, elm.pcb_port_id);
564
+ case "pcb_smtpad":
565
+ return getReadableNameForPcbSmtpad(soup, elm.pcb_smtpad_id);
566
+ case "pcb_trace":
567
+ return getReadableNameForPcbTrace(soup, elm.pcb_trace_id);
568
+ case "source_component":
569
+ return `source_component[${elm.name}]`;
570
+ default:
571
+ return `${elm.type}[#${getElementId(elm)}]`;
572
+ }
573
+ };
574
+
575
+ // lib/get-bounds-of-pcb-elements.ts
576
+ var getBoundsOfPcbElements = (elements) => {
577
+ let minX = Number.POSITIVE_INFINITY;
578
+ let minY = Number.POSITIVE_INFINITY;
579
+ let maxX = Number.NEGATIVE_INFINITY;
580
+ let maxY = Number.NEGATIVE_INFINITY;
581
+ for (const elm of elements) {
582
+ if (!elm.type.startsWith("pcb_"))
583
+ continue;
584
+ if ("x" in elm && "y" in elm) {
585
+ minX = Math.min(minX, elm.x);
586
+ minY = Math.min(minY, elm.y);
587
+ maxX = Math.max(maxX, elm.x);
588
+ maxY = Math.max(maxY, elm.y);
589
+ if ("width" in elm) {
590
+ maxX = Math.max(maxX, elm.x + elm.width);
591
+ }
592
+ if ("height" in elm) {
593
+ maxY = Math.max(maxY, elm.y + elm.height);
594
+ }
595
+ if ("radius" in elm) {
596
+ minX = Math.min(minX, elm.x - elm.radius);
597
+ minY = Math.min(minY, elm.y - elm.radius);
598
+ maxX = Math.max(maxX, elm.x + elm.radius);
599
+ maxY = Math.max(maxY, elm.y + elm.radius);
600
+ }
601
+ } else if (elm.type === "pcb_trace") {
602
+ for (const point of elm.route) {
603
+ minX = Math.min(minX, point.x);
604
+ minY = Math.min(minY, point.y);
605
+ maxX = Math.max(maxX, point.x);
606
+ maxY = Math.max(maxY, point.y);
607
+ }
608
+ }
609
+ }
610
+ return { minX, minY, maxX, maxY };
611
+ };
612
+ // Annotate the CommonJS export names for ESM import in node:
613
+ 0 && (module.exports = {
614
+ applySelector,
615
+ applySelectorAST,
616
+ directionToVec,
617
+ getBoundsOfPcbElements,
618
+ getElementById,
619
+ getElementId,
620
+ getReadableNameForElement,
621
+ getReadableNameForPcbPort,
622
+ getReadableNameForPcbSmtpad,
623
+ getReadableNameForPcbTrace,
624
+ oppositeDirection,
625
+ oppositeSide,
626
+ rotateClockwise,
627
+ rotateCounterClockwise,
628
+ rotateDirection,
629
+ su,
630
+ transformPCBElement,
631
+ transformPCBElements,
632
+ transformSchematicElement,
633
+ transformSchematicElements,
634
+ vecToDirection
635
+ });
636
+ //# sourceMappingURL=index.cjs.map