circuit-to-svg 0.0.121 → 0.0.123

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.js CHANGED
@@ -18,7 +18,62 @@ function createSvgObjectsFromPcbTraceError(pcbTraceError, transform, circuitJson
18
18
  const port2 = circuitJson.find(
19
19
  (el) => el.type === "pcb_port" && el.pcb_port_id === pcb_port_ids?.[1]
20
20
  );
21
- if (!port1 || !port2) return [];
21
+ if (!port1 || !port2) {
22
+ const viaIdMatch = pcbTraceError.message?.match(
23
+ /pcb_via\[#?(pcb_via_\d+)\]/
24
+ );
25
+ const viaId = viaIdMatch?.[1];
26
+ const via = circuitJson.find(
27
+ (el) => el.type === "pcb_via" && el.pcb_via_id === viaId
28
+ );
29
+ if (via && via.type === "pcb_via") {
30
+ return createSvgObjectsForViaTraceError(pcbTraceError, via, transform);
31
+ }
32
+ if (pcbTraceError.center) {
33
+ const screenCenter = applyToPoint(transform, {
34
+ x: pcbTraceError.center.x,
35
+ y: pcbTraceError.center.y
36
+ });
37
+ return [
38
+ {
39
+ name: "rect",
40
+ type: "element",
41
+ attributes: {
42
+ x: (screenCenter.x - 5).toString(),
43
+ y: (screenCenter.y - 5).toString(),
44
+ width: "10",
45
+ height: "10",
46
+ fill: "red",
47
+ transform: `rotate(45 ${screenCenter.x} ${screenCenter.y})`
48
+ },
49
+ children: [],
50
+ value: ""
51
+ },
52
+ {
53
+ name: "text",
54
+ type: "element",
55
+ attributes: {
56
+ x: screenCenter.x.toString(),
57
+ y: (screenCenter.y - 15).toString(),
58
+ fill: "red",
59
+ "font-family": "sans-serif",
60
+ "font-size": "12",
61
+ "text-anchor": "middle"
62
+ },
63
+ children: [
64
+ {
65
+ type: "text",
66
+ value: pcbTraceError.message || "Pcb Trace Error",
67
+ name: "",
68
+ attributes: {},
69
+ children: []
70
+ }
71
+ ],
72
+ value: ""
73
+ }
74
+ ];
75
+ } else return [];
76
+ }
22
77
  const screenPort1 = applyToPoint(transform, {
23
78
  x: port1.x,
24
79
  y: port1.y
@@ -104,6 +159,86 @@ function createSvgObjectsFromPcbTraceError(pcbTraceError, transform, circuitJson
104
159
  ];
105
160
  return svgObjects;
106
161
  }
162
+ function createSvgObjectsForViaTraceError(pcbTraceError, via, transform) {
163
+ if (pcbTraceError.center && via) {
164
+ const screenCenter = applyToPoint(transform, {
165
+ x: pcbTraceError.center.x,
166
+ y: pcbTraceError.center.y
167
+ });
168
+ const screenVia = applyToPoint(transform, {
169
+ x: via.x,
170
+ y: via.y
171
+ });
172
+ const dx = screenVia.x - screenCenter.x;
173
+ const dy = screenVia.y - screenCenter.y;
174
+ const dist = Math.sqrt(dx * dx + dy * dy);
175
+ const angle = Math.atan2(dy, dx) * 180 / Math.PI;
176
+ const margin = 10;
177
+ const boxWidth = dist + margin * 2;
178
+ const boxHeight = 20;
179
+ const midX = (screenCenter.x + screenVia.x) / 2;
180
+ const midY = (screenCenter.y + screenVia.y) / 2;
181
+ return [
182
+ // Rotated bounding box
183
+ {
184
+ name: "rect",
185
+ type: "element",
186
+ attributes: {
187
+ x: (midX - boxWidth / 2).toString(),
188
+ y: (midY - boxHeight / 2).toString(),
189
+ width: boxWidth.toString(),
190
+ height: boxHeight.toString(),
191
+ fill: "none",
192
+ stroke: "red",
193
+ "stroke-width": "1",
194
+ "stroke-dasharray": "3,2",
195
+ transform: `rotate(${angle} ${midX} ${midY})`
196
+ },
197
+ children: [],
198
+ value: ""
199
+ },
200
+ // Error diamond
201
+ {
202
+ name: "rect",
203
+ type: "element",
204
+ attributes: {
205
+ x: (midX - 5).toString(),
206
+ y: (midY - 5).toString(),
207
+ width: "10",
208
+ height: "10",
209
+ fill: "red",
210
+ transform: `rotate(45 ${midX} ${midY})`
211
+ },
212
+ children: [],
213
+ value: ""
214
+ },
215
+ // Error label
216
+ {
217
+ name: "text",
218
+ type: "element",
219
+ attributes: {
220
+ x: midX.toString(),
221
+ y: (midY - boxHeight / 2 - 5).toString(),
222
+ fill: "red",
223
+ "font-family": "sans-serif",
224
+ "font-size": "12",
225
+ "text-anchor": "middle"
226
+ },
227
+ children: [
228
+ {
229
+ type: "text",
230
+ value: pcbTraceError.message || "Pcb Trace Error",
231
+ name: "",
232
+ attributes: {},
233
+ children: []
234
+ }
235
+ ],
236
+ value: ""
237
+ }
238
+ ];
239
+ }
240
+ return [];
241
+ }
107
242
 
108
243
  // lib/pcb/svg-object-fns/create-svg-objects-from-pcb-fabrication-note-path.ts
109
244
  import { applyToPoint as applyToPoint2 } from "transformation-matrix";
@@ -1351,12 +1486,35 @@ var getSchScreenFontSize = (transform, textType) => {
1351
1486
  };
1352
1487
 
1353
1488
  // lib/assembly/svg-object-fns/create-svg-objects-from-assembly-component.ts
1354
- function createSvgObjectsFromAssemblyComponent(component, transform, firstPin, name) {
1355
- const { center, width, height, rotation = 0, layer = "top" } = component;
1489
+ function createSvgObjectsFromAssemblyComponent(params, ctx) {
1490
+ const { elm, portPosition, name, arePinsInterchangeable } = params;
1491
+ const { transform } = ctx;
1492
+ const { center, width, height, rotation = 0, layer = "top" } = elm;
1493
+ if (!center || typeof width !== "number" || typeof height !== "number")
1494
+ return null;
1356
1495
  const [x, y] = applyToPoint19(transform, [center.x, center.y]);
1357
- const [pinX, pinY] = applyToPoint19(transform, [firstPin.x, firstPin.y]);
1496
+ const [pinX, pinY] = applyToPoint19(transform, [portPosition.x, portPosition.y]);
1358
1497
  const scaledWidth = width * Math.abs(transform.a);
1359
1498
  const scaledHeight = height * Math.abs(transform.d);
1499
+ const isTopLayer = layer === "top";
1500
+ const isPinTop = pinY > y;
1501
+ const isPinLeft = pinX < x;
1502
+ const children = [
1503
+ createComponentPath(scaledWidth, scaledHeight, rotation, layer),
1504
+ createComponentLabel(scaledWidth, scaledHeight, name ?? "", transform)
1505
+ ];
1506
+ if (!arePinsInterchangeable) {
1507
+ children.push(
1508
+ createPin1Indicator(
1509
+ scaledWidth,
1510
+ scaledHeight,
1511
+ rotation,
1512
+ layer,
1513
+ isPinTop,
1514
+ isPinLeft
1515
+ )
1516
+ );
1517
+ }
1360
1518
  return {
1361
1519
  name: "g",
1362
1520
  type: "element",
@@ -1364,29 +1522,14 @@ function createSvgObjectsFromAssemblyComponent(component, transform, firstPin, n
1364
1522
  attributes: {
1365
1523
  transform: `translate(${x}, ${y}) scale(1, -1)`
1366
1524
  },
1367
- children: [
1368
- createComponentPath(
1369
- scaledWidth,
1370
- scaledHeight,
1371
- x,
1372
- y,
1373
- pinX,
1374
- pinY,
1375
- rotation,
1376
- layer
1377
- ),
1378
- createComponentLabel(scaledWidth, scaledHeight, name ?? "", transform)
1379
- ]
1525
+ children
1380
1526
  };
1381
1527
  }
1382
- function createComponentPath(scaledWidth, scaledHeight, centerX, centerY, pinX, pinY, rotation, layer) {
1528
+ function createComponentPath(scaledWidth, scaledHeight, rotation, layer) {
1383
1529
  const w = scaledWidth / 2;
1384
1530
  const h = scaledHeight / 2;
1385
- const cornerSize = Math.min(w, h) * 0.3;
1386
- const isTop = pinY > centerY;
1387
- const isLeft = pinX < centerX;
1388
1531
  const strokeWidth = 0.8;
1389
- const path = getComponentPathData(w, h, cornerSize, isTop, isLeft, rotation);
1532
+ const path = getRectPathData(w, h, rotation);
1390
1533
  return {
1391
1534
  name: "path",
1392
1535
  type: "element",
@@ -1436,47 +1579,76 @@ function createComponentLabel(scaledWidth, scaledHeight, name, transform) {
1436
1579
  value: ""
1437
1580
  };
1438
1581
  }
1439
- function getComponentPathData(w, h, cornerSize, isTop, isLeft, rotation) {
1440
- const rotatePoint = (x, y, angle) => {
1441
- const rad = Math.PI / 180 * angle;
1442
- const cos = Math.cos(rad);
1443
- const sin = Math.sin(rad);
1444
- return [x * cos - y * sin, x * sin + y * cos];
1445
- };
1446
- let corners;
1447
- if (isTop && isLeft) {
1448
- corners = [
1449
- [-w, -h + cornerSize],
1450
- [-w + cornerSize, -h],
1451
- [w, -h],
1452
- [w, h],
1453
- [-w, h]
1454
- ];
1455
- } else if (isTop && !isLeft) {
1456
- corners = [
1582
+ function createPin1Indicator(scaledWidth, scaledHeight, rotation, layer, isPinTop, isPinLeft) {
1583
+ const w = scaledWidth / 2;
1584
+ const h = scaledHeight / 2;
1585
+ const indicatorSize = Math.min(w, h) * 0.5;
1586
+ let points;
1587
+ if (isPinTop && isPinLeft) {
1588
+ points = [
1457
1589
  [-w, -h],
1458
- [w - cornerSize, -h],
1459
- [w, -h + cornerSize],
1460
- [w, h],
1461
- [-w, h]
1590
+ // Corner point
1591
+ [-w + indicatorSize, -h],
1592
+ // Point along top edge
1593
+ [-w, -h + indicatorSize]
1594
+ // Point along left edge
1462
1595
  ];
1463
- } else if (!isTop && isLeft) {
1464
- corners = [
1465
- [-w, -h],
1596
+ } else if (isPinTop && !isPinLeft) {
1597
+ points = [
1466
1598
  [w, -h],
1467
- [w, h],
1468
- [-w + cornerSize, h],
1469
- [-w, h - cornerSize]
1599
+ // Corner point
1600
+ [w - indicatorSize, -h],
1601
+ // Point along top edge
1602
+ [w, -h + indicatorSize]
1603
+ // Point along right edge
1604
+ ];
1605
+ } else if (!isPinTop && isPinLeft) {
1606
+ points = [
1607
+ [-w, h],
1608
+ // Corner point
1609
+ [-w + indicatorSize, h],
1610
+ // Point along bottom edge
1611
+ [-w, h - indicatorSize]
1612
+ // Point along left edge
1470
1613
  ];
1471
1614
  } else {
1472
- corners = [
1473
- [-w, -h],
1474
- [w, -h],
1475
- [w, h - cornerSize],
1476
- [w - cornerSize, h],
1477
- [-w, h]
1615
+ points = [
1616
+ [w, h],
1617
+ // Corner point
1618
+ [w - indicatorSize, h],
1619
+ // Point along bottom edge
1620
+ [w, h - indicatorSize]
1621
+ // Point along right edge
1478
1622
  ];
1479
1623
  }
1624
+ const pointsString = points.map((p) => p.join(",")).join(" ");
1625
+ return {
1626
+ name: "polygon",
1627
+ type: "element",
1628
+ attributes: {
1629
+ class: "assembly-pin1-indicator",
1630
+ points: pointsString,
1631
+ fill: "#333",
1632
+ stroke: "none",
1633
+ transform: `rotate(${-rotation})`
1634
+ },
1635
+ value: "",
1636
+ children: []
1637
+ };
1638
+ }
1639
+ function getRectPathData(w, h, rotation) {
1640
+ const rotatePoint = (x, y, angle) => {
1641
+ const rad = Math.PI / 180 * angle;
1642
+ const cos = Math.cos(rad);
1643
+ const sin = Math.sin(rad);
1644
+ return [x * cos - y * sin, x * sin + y * cos];
1645
+ };
1646
+ const corners = [
1647
+ [-w, -h],
1648
+ [w, -h],
1649
+ [w, h],
1650
+ [-w, h]
1651
+ ];
1480
1652
  const rotatedCorners = corners.map(([x, y]) => rotatePoint(x, y, rotation));
1481
1653
  const path = rotatedCorners.map(([x, y], i) => i === 0 ? `M${x},${y}` : `L${x},${y}`).join(" ");
1482
1654
  return `${path} Z`;
@@ -1599,14 +1771,17 @@ function createSvgObjects2(elm, transform, soup) {
1599
1771
  const ports = su3(soup).pcb_port.list().filter((port) => port.pcb_component_id === elm.pcb_component_id);
1600
1772
  const firstPort = ports[0];
1601
1773
  if (sourceComponent && firstPort) {
1602
- return [
1603
- createSvgObjectsFromAssemblyComponent(
1774
+ const arePinsInterchangeable = sourceComponent.are_pins_interchangeable;
1775
+ const obj = createSvgObjectsFromAssemblyComponent(
1776
+ {
1604
1777
  elm,
1605
- transform,
1606
- { x: firstPort.x, y: firstPort.y },
1607
- sourceComponent.name
1608
- )
1609
- ].filter(Boolean);
1778
+ portPosition: { x: firstPort.x, y: firstPort.y },
1779
+ name: sourceComponent.name,
1780
+ arePinsInterchangeable
1781
+ },
1782
+ { transform }
1783
+ );
1784
+ return obj ? [obj] : [];
1610
1785
  }
1611
1786
  return [];
1612
1787
  }