circuit-to-svg 0.0.66 → 0.0.68

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
@@ -1,21 +1,119 @@
1
1
  // lib/pcb/convert-circuit-json-to-pcb-svg.ts
2
2
  import { stringify } from "svgson";
3
3
  import {
4
- applyToPoint as applyToPoint11,
4
+ applyToPoint as applyToPoint12,
5
5
  compose as compose3,
6
6
  scale,
7
7
  translate as translate3
8
8
  } from "transformation-matrix";
9
9
 
10
- // lib/pcb/svg-object-fns/create-svg-objects-from-pcb-fabrication-note-path.ts
10
+ // lib/pcb/svg-object-fns/create-svg-objects-from-pcb-trace-error.ts
11
11
  import { applyToPoint } from "transformation-matrix";
12
+ function createSvgObjectsFromPcbTraceError(pcbTraceError, transform, circuitJson, shouldDrawErrors) {
13
+ if (!shouldDrawErrors) return [];
14
+ const { pcb_port_ids } = pcbTraceError;
15
+ const port1 = circuitJson.find(
16
+ (el) => el.type === "pcb_port" && el.pcb_port_id === pcb_port_ids?.[0]
17
+ );
18
+ const port2 = circuitJson.find(
19
+ (el) => el.type === "pcb_port" && el.pcb_port_id === pcb_port_ids?.[1]
20
+ );
21
+ if (!port1 || !port2) return [];
22
+ const screenPort1 = applyToPoint(transform, {
23
+ x: port1.x,
24
+ y: port1.y
25
+ });
26
+ const screenPort2 = applyToPoint(transform, {
27
+ x: port2.x,
28
+ y: port2.y
29
+ });
30
+ const errorCenter = {
31
+ x: (screenPort1.x + screenPort2.x) / 2,
32
+ y: (screenPort1.y + screenPort2.y) / 2
33
+ };
34
+ if (isNaN(screenPort1.x) || isNaN(screenPort1.y) || isNaN(screenPort2.x) || isNaN(screenPort2.y) || isNaN(errorCenter.x) || isNaN(errorCenter.y)) {
35
+ return [];
36
+ }
37
+ const svgObjects = [
38
+ {
39
+ name: "line",
40
+ type: "element",
41
+ attributes: {
42
+ x1: screenPort1.x.toString(),
43
+ y1: screenPort1.y.toString(),
44
+ x2: errorCenter.x.toString(),
45
+ y2: errorCenter.y.toString(),
46
+ stroke: "red",
47
+ "stroke-width": "1.5",
48
+ "stroke-dasharray": "2,2"
49
+ },
50
+ children: [],
51
+ value: ""
52
+ },
53
+ {
54
+ name: "line",
55
+ type: "element",
56
+ attributes: {
57
+ x1: errorCenter.x.toString(),
58
+ y1: errorCenter.y.toString(),
59
+ x2: screenPort2.x.toString(),
60
+ y2: screenPort2.y.toString(),
61
+ stroke: "red",
62
+ "stroke-width": "1.5",
63
+ "stroke-dasharray": "2,2"
64
+ },
65
+ children: [],
66
+ value: ""
67
+ },
68
+ {
69
+ name: "rect",
70
+ type: "element",
71
+ attributes: {
72
+ x: (errorCenter.x - 5).toString(),
73
+ y: (errorCenter.y - 5).toString(),
74
+ width: "10",
75
+ height: "10",
76
+ fill: "red",
77
+ transform: `rotate(45 ${errorCenter.x} ${errorCenter.y})`
78
+ },
79
+ children: [],
80
+ value: ""
81
+ },
82
+ {
83
+ name: "text",
84
+ type: "element",
85
+ attributes: {
86
+ x: errorCenter.x.toString(),
87
+ y: (errorCenter.y - 15).toString(),
88
+ fill: "red",
89
+ "font-family": "sans-serif",
90
+ "font-size": "12",
91
+ "text-anchor": "middle"
92
+ },
93
+ children: [
94
+ {
95
+ type: "text",
96
+ value: pcbTraceError.message || "Pcb Trace Error",
97
+ name: "",
98
+ attributes: {},
99
+ children: []
100
+ }
101
+ ],
102
+ value: ""
103
+ }
104
+ ];
105
+ return svgObjects;
106
+ }
107
+
108
+ // lib/pcb/svg-object-fns/create-svg-objects-from-pcb-fabrication-note-path.ts
109
+ import { applyToPoint as applyToPoint2 } from "transformation-matrix";
12
110
  function createSvgObjectsFromPcbFabricationNotePath(fabNotePath, transform) {
13
111
  if (!fabNotePath.route || !Array.isArray(fabNotePath.route)) return [];
14
112
  const firstPoint = fabNotePath.route[0];
15
113
  const lastPoint = fabNotePath.route[fabNotePath.route.length - 1];
16
114
  const isClosed = firstPoint.x === lastPoint.x && firstPoint.y === lastPoint.y;
17
115
  const path = fabNotePath.route.slice(0, isClosed ? -1 : void 0).map((point, index) => {
18
- const [x, y] = applyToPoint(transform, [point.x, point.y]);
116
+ const [x, y] = applyToPoint2(transform, [point.x, point.y]);
19
117
  return index === 0 ? `M ${x} ${y}` : `L ${x} ${y}`;
20
118
  }).join(" ") + (isClosed ? " Z" : "");
21
119
  return [
@@ -40,7 +138,7 @@ function createSvgObjectsFromPcbFabricationNotePath(fabNotePath, transform) {
40
138
  // lib/pcb/svg-object-fns/create-svg-objects-from-pcb-fabrication-note-text.ts
41
139
  import { toString as matrixToString } from "transformation-matrix";
42
140
  import {
43
- applyToPoint as applyToPoint2,
141
+ applyToPoint as applyToPoint3,
44
142
  compose,
45
143
  rotate,
46
144
  translate
@@ -58,7 +156,7 @@ function createSvgObjectsFromPcbFabricationNoteText(pcbFabNoteText, transform) {
58
156
  console.error("Invalid anchor_position:", anchor_position);
59
157
  return [];
60
158
  }
61
- const [transformedX, transformedY] = applyToPoint2(transform, [
159
+ const [transformedX, transformedY] = applyToPoint3(transform, [
62
160
  anchor_position.x,
63
161
  anchor_position.y
64
162
  ]);
@@ -98,9 +196,9 @@ function createSvgObjectsFromPcbFabricationNoteText(pcbFabNoteText, transform) {
98
196
  }
99
197
 
100
198
  // lib/pcb/svg-object-fns/create-svg-objects-from-pcb-plated-hole.ts
101
- import { applyToPoint as applyToPoint3 } from "transformation-matrix";
199
+ import { applyToPoint as applyToPoint4 } from "transformation-matrix";
102
200
  function createSvgObjectsFromPcbPlatedHole(hole, transform) {
103
- const [x, y] = applyToPoint3(transform, [hole.x, hole.y]);
201
+ const [x, y] = applyToPoint4(transform, [hole.x, hole.y]);
104
202
  if (hole.shape === "pill") {
105
203
  const scaledOuterWidth = hole.outer_width * Math.abs(transform.a);
106
204
  const scaledOuterHeight = hole.outer_height * Math.abs(transform.a);
@@ -190,11 +288,11 @@ function createSvgObjectsFromPcbPlatedHole(hole, transform) {
190
288
  }
191
289
 
192
290
  // lib/pcb/svg-object-fns/create-svg-objects-from-pcb-silkscreen-path.ts
193
- import { applyToPoint as applyToPoint4 } from "transformation-matrix";
291
+ import { applyToPoint as applyToPoint5 } from "transformation-matrix";
194
292
  function createSvgObjectsFromPcbSilkscreenPath(silkscreenPath, transform) {
195
293
  if (!silkscreenPath.route || !Array.isArray(silkscreenPath.route)) return [];
196
294
  let path = silkscreenPath.route.map((point, index) => {
197
- const [x, y] = applyToPoint4(transform, [point.x, point.y]);
295
+ const [x, y] = applyToPoint5(transform, [point.x, point.y]);
198
296
  return index === 0 ? `M ${x} ${y}` : `L ${x} ${y}`;
199
297
  }).join(" ");
200
298
  const firstPoint = silkscreenPath.route[0];
@@ -221,7 +319,7 @@ function createSvgObjectsFromPcbSilkscreenPath(silkscreenPath, transform) {
221
319
 
222
320
  // lib/pcb/svg-object-fns/create-svg-objects-from-pcb-silkscreen-text.ts
223
321
  import {
224
- applyToPoint as applyToPoint5,
322
+ applyToPoint as applyToPoint6,
225
323
  compose as compose2,
226
324
  rotate as rotate2,
227
325
  translate as translate2,
@@ -238,7 +336,7 @@ function createSvgObjectsFromPcbSilkscreenText(pcbSilkscreenText, transform) {
238
336
  console.error("Invalid anchor_position:", anchor_position);
239
337
  return [];
240
338
  }
241
- const [transformedX, transformedY] = applyToPoint5(transform, [
339
+ const [transformedX, transformedY] = applyToPoint6(transform, [
242
340
  anchor_position.x,
243
341
  anchor_position.y
244
342
  ]);
@@ -286,7 +384,7 @@ function pairs(arr) {
286
384
  }
287
385
 
288
386
  // lib/pcb/svg-object-fns/create-svg-objects-from-pcb-trace.ts
289
- import { applyToPoint as applyToPoint6 } from "transformation-matrix";
387
+ import { applyToPoint as applyToPoint7 } from "transformation-matrix";
290
388
 
291
389
  // lib/pcb/layer-name-to-color.ts
292
390
  var LAYER_NAME_TO_COLOR = {
@@ -304,8 +402,8 @@ function createSvgObjectsFromPcbTrace(trace, transform) {
304
402
  const segments = pairs(trace.route);
305
403
  const svgObjects = [];
306
404
  for (const [start, end] of segments) {
307
- const startPoint = applyToPoint6(transform, [start.x, start.y]);
308
- const endPoint = applyToPoint6(transform, [end.x, end.y]);
405
+ const startPoint = applyToPoint7(transform, [start.x, start.y]);
406
+ const endPoint = applyToPoint7(transform, [end.x, end.y]);
309
407
  const layer = "layer" in start ? start.layer : "layer" in end ? end.layer : null;
310
408
  if (!layer) continue;
311
409
  const layerColor = LAYER_NAME_TO_COLOR[layer] ?? "white";
@@ -330,9 +428,9 @@ function createSvgObjectsFromPcbTrace(trace, transform) {
330
428
  }
331
429
 
332
430
  // lib/pcb/svg-object-fns/create-svg-objects-from-smt-pads.ts
333
- import { applyToPoint as applyToPoint7 } from "transformation-matrix";
431
+ import { applyToPoint as applyToPoint8 } from "transformation-matrix";
334
432
  function createSvgObjectsFromSmtPad(pad, transform) {
335
- const [x, y] = applyToPoint7(transform, [pad.x, pad.y]);
433
+ const [x, y] = applyToPoint8(transform, [pad.x, pad.y]);
336
434
  if (pad.shape === "rect") {
337
435
  const width = pad.width * Math.abs(transform.a);
338
436
  const height = pad.height * Math.abs(transform.d);
@@ -355,31 +453,31 @@ function createSvgObjectsFromSmtPad(pad, transform) {
355
453
  }
356
454
 
357
455
  // lib/pcb/svg-object-fns/create-svg-objects-from-pcb-board.ts
358
- import { applyToPoint as applyToPoint8 } from "transformation-matrix";
456
+ import { applyToPoint as applyToPoint9 } from "transformation-matrix";
359
457
  function createSvgObjectsFromPcbBoard(pcbBoard, transform) {
360
458
  const { width, height, center, outline } = pcbBoard;
361
459
  let path;
362
460
  if (outline && Array.isArray(outline) && outline.length >= 3) {
363
461
  path = outline.map((point, index) => {
364
- const [x, y] = applyToPoint8(transform, [point.x, point.y]);
462
+ const [x, y] = applyToPoint9(transform, [point.x, point.y]);
365
463
  return index === 0 ? `M ${x} ${y}` : `L ${x} ${y}`;
366
464
  }).join(" ");
367
465
  } else {
368
466
  const halfWidth = width / 2;
369
467
  const halfHeight = height / 2;
370
- const topLeft = applyToPoint8(transform, [
468
+ const topLeft = applyToPoint9(transform, [
371
469
  center.x - halfWidth,
372
470
  center.y - halfHeight
373
471
  ]);
374
- const topRight = applyToPoint8(transform, [
472
+ const topRight = applyToPoint9(transform, [
375
473
  center.x + halfWidth,
376
474
  center.y - halfHeight
377
475
  ]);
378
- const bottomRight = applyToPoint8(transform, [
476
+ const bottomRight = applyToPoint9(transform, [
379
477
  center.x + halfWidth,
380
478
  center.y + halfHeight
381
479
  ]);
382
- const bottomLeft = applyToPoint8(transform, [
480
+ const bottomLeft = applyToPoint9(transform, [
383
481
  center.x - halfWidth,
384
482
  center.y + halfHeight
385
483
  ]);
@@ -403,9 +501,9 @@ function createSvgObjectsFromPcbBoard(pcbBoard, transform) {
403
501
  }
404
502
 
405
503
  // lib/pcb/svg-object-fns/create-svg-objects-from-pcb-via.ts
406
- import { applyToPoint as applyToPoint9 } from "transformation-matrix";
504
+ import { applyToPoint as applyToPoint10 } from "transformation-matrix";
407
505
  function createSvgObjectsFromPcbVia(hole, transform) {
408
- const [x, y] = applyToPoint9(transform, [hole.x, hole.y]);
506
+ const [x, y] = applyToPoint10(transform, [hole.x, hole.y]);
409
507
  const scaledOuterWidth = hole.outer_diameter * Math.abs(transform.a);
410
508
  const scaledOuterHeight = hole.outer_diameter * Math.abs(transform.a);
411
509
  const scaledHoleWidth = hole.hole_diameter * Math.abs(transform.a);
@@ -441,14 +539,14 @@ function createSvgObjectsFromPcbVia(hole, transform) {
441
539
  }
442
540
 
443
541
  // lib/pcb/svg-object-fns/create-svg-objects-from-pcb-hole.ts
444
- import { applyToPoint as applyToPoint10 } from "transformation-matrix";
542
+ import { applyToPoint as applyToPoint11 } from "transformation-matrix";
445
543
 
446
544
  // lib/pcb/colors.ts
447
545
  var HOLE_COLOR = "#FF26E2";
448
546
 
449
547
  // lib/pcb/svg-object-fns/create-svg-objects-from-pcb-hole.ts
450
548
  function createSvgObjectsFromPcbHole(hole, transform) {
451
- const [x, y] = applyToPoint10(transform, [hole.x, hole.y]);
549
+ const [x, y] = applyToPoint11(transform, [hole.x, hole.y]);
452
550
  if (hole.hole_shape === "circle" || hole.hole_shape === "square") {
453
551
  const scaledDiameter = hole.hole_diameter * Math.abs(transform.a);
454
552
  const radius = scaledDiameter / 2;
@@ -513,6 +611,7 @@ function createSvgObjectsFromPcbHole(hole, transform) {
513
611
 
514
612
  // lib/pcb/convert-circuit-json-to-pcb-svg.ts
515
613
  var OBJECT_ORDER = [
614
+ "pcb_trace_error",
516
615
  "pcb_plated_hole",
517
616
  "pcb_fabrication_note_text",
518
617
  "pcb_fabrication_note_path",
@@ -567,7 +666,9 @@ function convertCircuitJsonToPcbSvg(soup, options) {
567
666
  );
568
667
  const svgObjects = soup.sort(
569
668
  (a, b) => (OBJECT_ORDER.indexOf(b.type) ?? 9999) - (OBJECT_ORDER.indexOf(a.type) ?? 9999)
570
- ).flatMap((item) => createSvgObjects(item, transform));
669
+ ).flatMap(
670
+ (item) => createSvgObjects(item, transform, soup, options?.shouldDrawErrors)
671
+ );
571
672
  let strokeWidth = String(0.05 * scaleFactor);
572
673
  for (const element of soup) {
573
674
  if ("stroke_width" in element) {
@@ -653,8 +754,15 @@ function convertCircuitJsonToPcbSvg(soup, options) {
653
754
  }
654
755
  }
655
756
  }
656
- function createSvgObjects(elm, transform) {
757
+ function createSvgObjects(elm, transform, soup, shouldDrawErrors) {
657
758
  switch (elm.type) {
759
+ case "pcb_trace_error":
760
+ return createSvgObjectsFromPcbTraceError(
761
+ elm,
762
+ transform,
763
+ soup,
764
+ shouldDrawErrors
765
+ ).filter(Boolean);
658
766
  case "pcb_component":
659
767
  return [createSvgObjectsFromPcbComponent(elm, transform)].filter(Boolean);
660
768
  case "pcb_trace":
@@ -683,7 +791,7 @@ function createSvgObjects(elm, transform) {
683
791
  }
684
792
  function createSvgObjectsFromPcbComponent(component, transform) {
685
793
  const { center, width, height, rotation = 0 } = component;
686
- const [x, y] = applyToPoint11(transform, [center.x, center.y]);
794
+ const [x, y] = applyToPoint12(transform, [center.x, center.y]);
687
795
  const scaledWidth = width * Math.abs(transform.a);
688
796
  const scaledHeight = height * Math.abs(transform.d);
689
797
  const transformStr = `translate(${x}, ${y}) rotate(${-rotation}) scale(1, -1)`;
@@ -718,8 +826,8 @@ function createSvgObjectsFromPcbComponent(component, transform) {
718
826
  };
719
827
  }
720
828
  function createSvgObjectFromPcbBoundary(transform, minX, minY, maxX, maxY) {
721
- const [x1, y1] = applyToPoint11(transform, [minX, minY]);
722
- const [x2, y2] = applyToPoint11(transform, [maxX, maxY]);
829
+ const [x1, y1] = applyToPoint12(transform, [minX, minY]);
830
+ const [x2, y2] = applyToPoint12(transform, [maxX, maxY]);
723
831
  const width = Math.abs(x2 - x1);
724
832
  const height = Math.abs(y2 - y1);
725
833
  const x = Math.min(x1, x2);
@@ -984,14 +1092,14 @@ import {
984
1092
  } from "transformation-matrix";
985
1093
 
986
1094
  // lib/sch/draw-schematic-grid.ts
987
- import { applyToPoint as applyToPoint12 } from "transformation-matrix";
1095
+ import { applyToPoint as applyToPoint13 } from "transformation-matrix";
988
1096
  function drawSchematicGrid(params) {
989
1097
  const { minX, minY, maxX, maxY } = params.bounds;
990
1098
  const cellSize = params.cellSize ?? 1;
991
1099
  const labelCells = params.labelCells ?? false;
992
1100
  const gridLines = [];
993
1101
  const transformPoint = (x, y) => {
994
- const [transformedX, transformedY] = applyToPoint12(params.transform, [x, y]);
1102
+ const [transformedX, transformedY] = applyToPoint13(params.transform, [x, y]);
995
1103
  return { x: transformedX, y: transformedY };
996
1104
  };
997
1105
  for (let x = Math.ceil(minX); x <= Math.floor(maxX); x += cellSize) {
@@ -1068,15 +1176,15 @@ function drawSchematicGrid(params) {
1068
1176
  }
1069
1177
 
1070
1178
  // lib/sch/draw-schematic-labeled-points.ts
1071
- import { applyToPoint as applyToPoint13 } from "transformation-matrix";
1179
+ import { applyToPoint as applyToPoint14 } from "transformation-matrix";
1072
1180
  function drawSchematicLabeledPoints(params) {
1073
1181
  const { points, transform } = params;
1074
1182
  const labeledPointsGroup = [];
1075
1183
  for (const point of points) {
1076
- const [x1, y1] = applyToPoint13(transform, [point.x - 0.1, point.y - 0.1]);
1077
- const [x2, y2] = applyToPoint13(transform, [point.x + 0.1, point.y + 0.1]);
1078
- const [x3, y3] = applyToPoint13(transform, [point.x - 0.1, point.y + 0.1]);
1079
- const [x4, y4] = applyToPoint13(transform, [point.x + 0.1, point.y - 0.1]);
1184
+ const [x1, y1] = applyToPoint14(transform, [point.x - 0.1, point.y - 0.1]);
1185
+ const [x2, y2] = applyToPoint14(transform, [point.x + 0.1, point.y + 0.1]);
1186
+ const [x3, y3] = applyToPoint14(transform, [point.x - 0.1, point.y + 0.1]);
1187
+ const [x4, y4] = applyToPoint14(transform, [point.x + 0.1, point.y - 0.1]);
1080
1188
  labeledPointsGroup.push({
1081
1189
  name: "path",
1082
1190
  type: "element",
@@ -1087,7 +1195,7 @@ function drawSchematicLabeledPoints(params) {
1087
1195
  "stroke-opacity": "0.7"
1088
1196
  }
1089
1197
  });
1090
- const [labelX, labelY] = applyToPoint13(transform, [
1198
+ const [labelX, labelY] = applyToPoint14(transform, [
1091
1199
  point.x + 0.15,
1092
1200
  point.y - 0.15
1093
1201
  ]);
@@ -1175,7 +1283,7 @@ import { su } from "@tscircuit/soup-util";
1175
1283
  import { symbols } from "schematic-symbols";
1176
1284
  import "svgson";
1177
1285
  import {
1178
- applyToPoint as applyToPoint15,
1286
+ applyToPoint as applyToPoint16,
1179
1287
  compose as compose5
1180
1288
  } from "transformation-matrix";
1181
1289
 
@@ -1260,8 +1368,11 @@ function pointPairsToMatrix(a1, a2, b1, b2) {
1260
1368
 
1261
1369
  // lib/utils/get-sch-font-size.ts
1262
1370
  import "transformation-matrix";
1263
- var getSchFontSize = (transform, textType) => {
1264
- return Math.abs(transform.a) * (textType === "pin_number" ? 0.15 : 0.18);
1371
+ var getSchMmFontSize = (textType) => {
1372
+ return textType === "pin_number" ? 0.15 : 0.18;
1373
+ };
1374
+ var getSchScreenFontSize = (transform, textType) => {
1375
+ return Math.abs(transform.a) * getSchMmFontSize(textType);
1265
1376
  };
1266
1377
 
1267
1378
  // lib/sch/svg-object-fns/create-svg-objects-from-sch-component-with-symbol.ts
@@ -1324,7 +1435,7 @@ var createSvgObjectsFromSchematicComponentWithSymbol = ({
1324
1435
  name: "path",
1325
1436
  attributes: {
1326
1437
  d: points.map((p, i) => {
1327
- const [x, y] = applyToPoint15(
1438
+ const [x, y] = applyToPoint16(
1328
1439
  compose5(realToScreenTransform, transformFromSymbolToReal),
1329
1440
  [p.x, p.y]
1330
1441
  );
@@ -1339,7 +1450,7 @@ var createSvgObjectsFromSchematicComponentWithSymbol = ({
1339
1450
  });
1340
1451
  }
1341
1452
  for (const text of texts) {
1342
- const screenTextPos = applyToPoint15(
1453
+ const screenTextPos = applyToPoint16(
1343
1454
  compose5(realToScreenTransform, transformFromSymbolToReal),
1344
1455
  text
1345
1456
  );
@@ -1358,7 +1469,7 @@ var createSvgObjectsFromSchematicComponentWithSymbol = ({
1358
1469
  "dominant-baseline": ninePointAnchorToDominantBaseline[text.anchor],
1359
1470
  "text-anchor": ninePointAnchorToTextAnchor[text.anchor],
1360
1471
  "font-family": "sans-serif",
1361
- "font-size": `${getSchFontSize(realToScreenTransform, "reference_designator")}px`
1472
+ "font-size": `${getSchScreenFontSize(realToScreenTransform, "reference_designator")}px`
1362
1473
  },
1363
1474
  value: "",
1364
1475
  children: [
@@ -1373,7 +1484,7 @@ var createSvgObjectsFromSchematicComponentWithSymbol = ({
1373
1484
  });
1374
1485
  }
1375
1486
  for (const box of boxes) {
1376
- const screenBoxPos = applyToPoint15(
1487
+ const screenBoxPos = applyToPoint16(
1377
1488
  compose5(realToScreenTransform, transformFromSymbolToReal),
1378
1489
  box
1379
1490
  );
@@ -1396,7 +1507,7 @@ var createSvgObjectsFromSchematicComponentWithSymbol = ({
1396
1507
  });
1397
1508
  }
1398
1509
  for (const port of symbol.ports) {
1399
- const screenPortPos = applyToPoint15(
1510
+ const screenPortPos = applyToPoint16(
1400
1511
  compose5(realToScreenTransform, transformFromSymbolToReal),
1401
1512
  port
1402
1513
  );
@@ -1421,14 +1532,14 @@ var createSvgObjectsFromSchematicComponentWithSymbol = ({
1421
1532
  import { su as su4 } from "@tscircuit/soup-util";
1422
1533
  import "schematic-symbols";
1423
1534
  import "svgson";
1424
- import { applyToPoint as applyToPoint20 } from "transformation-matrix";
1535
+ import { applyToPoint as applyToPoint21 } from "transformation-matrix";
1425
1536
 
1426
1537
  // lib/sch/svg-object-fns/create-svg-objects-from-sch-port-on-box.ts
1427
1538
  import "transformation-matrix";
1428
1539
  import "@tscircuit/soup-util";
1429
1540
 
1430
1541
  // lib/sch/svg-object-fns/create-svg-objects-for-sch-port-box-line.ts
1431
- import { applyToPoint as applyToPoint16 } from "transformation-matrix";
1542
+ import { applyToPoint as applyToPoint17 } from "transformation-matrix";
1432
1543
  import { su as su2 } from "@tscircuit/soup-util";
1433
1544
  var PIN_CIRCLE_RADIUS_MM = 0.02;
1434
1545
  var createSvgObjectsForSchPortBoxLine = ({
@@ -1458,8 +1569,8 @@ var createSvgObjectsForSchPortBoxLine = ({
1458
1569
  realEdgePos.y += realPinLineLength;
1459
1570
  break;
1460
1571
  }
1461
- const screenSchPortPos = applyToPoint16(transform, schPort.center);
1462
- const screenRealEdgePos = applyToPoint16(transform, realEdgePos);
1572
+ const screenSchPortPos = applyToPoint17(transform, schPort.center);
1573
+ const screenRealEdgePos = applyToPoint17(transform, realEdgePos);
1463
1574
  const realLineEnd = { ...schPort.center };
1464
1575
  switch (schPort.side_of_component) {
1465
1576
  case "left":
@@ -1475,7 +1586,7 @@ var createSvgObjectsForSchPortBoxLine = ({
1475
1586
  realLineEnd.y += PIN_CIRCLE_RADIUS_MM;
1476
1587
  break;
1477
1588
  }
1478
- const screenLineEnd = applyToPoint16(transform, realLineEnd);
1589
+ const screenLineEnd = applyToPoint17(transform, realLineEnd);
1479
1590
  svgObjects.push({
1480
1591
  name: "line",
1481
1592
  type: "element",
@@ -1522,7 +1633,7 @@ var getUnitVectorFromOutsideToEdge = (side) => {
1522
1633
  };
1523
1634
 
1524
1635
  // lib/sch/svg-object-fns/create-svg-objects-for-sch-port-pin-number-text.ts
1525
- import { applyToPoint as applyToPoint17 } from "transformation-matrix";
1636
+ import { applyToPoint as applyToPoint18 } from "transformation-matrix";
1526
1637
  var createSvgObjectsForSchPortPinNumberText = (params) => {
1527
1638
  const svgObjects = [];
1528
1639
  const { schPort, schComponent, transform, circuitJson } = params;
@@ -1535,7 +1646,7 @@ var createSvgObjectsForSchPortPinNumberText = (params) => {
1535
1646
  const realPinEdgeDistance = schPort.distance_from_component_edge ?? 0.4;
1536
1647
  realPinNumberPos.x += vecToEdge.x * realPinEdgeDistance / 2;
1537
1648
  realPinNumberPos.y += vecToEdge.y * realPinEdgeDistance / 2;
1538
- const screenPinNumberTextPos = applyToPoint17(transform, realPinNumberPos);
1649
+ const screenPinNumberTextPos = applyToPoint18(transform, realPinNumberPos);
1539
1650
  if (schPort.side_of_component === "top" || schPort.side_of_component === "bottom") {
1540
1651
  screenPinNumberTextPos.x -= 2;
1541
1652
  } else {
@@ -1552,7 +1663,7 @@ var createSvgObjectsForSchPortPinNumberText = (params) => {
1552
1663
  fill: colorMap.schematic.pin_number,
1553
1664
  "text-anchor": "middle",
1554
1665
  "dominant-baseline": "auto",
1555
- "font-size": `${getSchFontSize(transform, "pin_number")}px`,
1666
+ "font-size": `${getSchScreenFontSize(transform, "pin_number")}px`,
1556
1667
  transform: schPort.side_of_component === "top" || schPort.side_of_component === "bottom" ? `rotate(-90 ${screenPinNumberTextPos.x} ${screenPinNumberTextPos.y})` : ""
1557
1668
  },
1558
1669
  children: [
@@ -1570,7 +1681,7 @@ var createSvgObjectsForSchPortPinNumberText = (params) => {
1570
1681
  };
1571
1682
 
1572
1683
  // lib/sch/svg-object-fns/create-svg-objects-for-sch-port-pin-label.ts
1573
- import { applyToPoint as applyToPoint18 } from "transformation-matrix";
1684
+ import { applyToPoint as applyToPoint19 } from "transformation-matrix";
1574
1685
  var LABEL_DIST_FROM_EDGE_MM = 0.1;
1575
1686
  var createSvgObjectsForSchPortPinLabel = (params) => {
1576
1687
  const svgObjects = [];
@@ -1584,7 +1695,7 @@ var createSvgObjectsForSchPortPinLabel = (params) => {
1584
1695
  const realPinEdgeDistance = schPort.distance_from_component_edge ?? 0.4;
1585
1696
  realPinNumberPos.x += vecToEdge.x * (realPinEdgeDistance + LABEL_DIST_FROM_EDGE_MM);
1586
1697
  realPinNumberPos.y += vecToEdge.y * (realPinEdgeDistance + LABEL_DIST_FROM_EDGE_MM);
1587
- const screenPinNumberTextPos = applyToPoint18(transform, realPinNumberPos);
1698
+ const screenPinNumberTextPos = applyToPoint19(transform, realPinNumberPos);
1588
1699
  const label = schPort.display_pin_label ?? schComponent.port_labels?.[`pin${schPort.pin_number}`];
1589
1700
  if (!label) return [];
1590
1701
  svgObjects.push({
@@ -1598,7 +1709,7 @@ var createSvgObjectsForSchPortPinLabel = (params) => {
1598
1709
  fill: colorMap.schematic.pin_number,
1599
1710
  "text-anchor": schPort.side_of_component === "left" || schPort.side_of_component === "bottom" ? "start" : "end",
1600
1711
  "dominant-baseline": "middle",
1601
- "font-size": `${getSchFontSize(transform, "pin_number")}px`,
1712
+ "font-size": `${getSchScreenFontSize(transform, "pin_number")}px`,
1602
1713
  transform: schPort.side_of_component === "top" || schPort.side_of_component === "bottom" ? `rotate(-90 ${screenPinNumberTextPos.x} ${screenPinNumberTextPos.y})` : ""
1603
1714
  },
1604
1715
  children: [
@@ -1635,11 +1746,11 @@ var createSvgObjectsFromSchematicComponentWithBox = ({
1635
1746
  schComponent.source_component_id
1636
1747
  );
1637
1748
  const svgObjects = [];
1638
- const componentScreenTopLeft = applyToPoint20(transform, {
1749
+ const componentScreenTopLeft = applyToPoint21(transform, {
1639
1750
  x: schComponent.center.x - schComponent.size.width / 2,
1640
1751
  y: schComponent.center.y + schComponent.size.height / 2
1641
1752
  });
1642
- const componentScreenBottomRight = applyToPoint20(transform, {
1753
+ const componentScreenBottomRight = applyToPoint21(transform, {
1643
1754
  x: schComponent.center.x + schComponent.size.width / 2,
1644
1755
  y: schComponent.center.y - schComponent.size.height / 2
1645
1756
  });
@@ -1659,12 +1770,12 @@ var createSvgObjectsFromSchematicComponentWithBox = ({
1659
1770
  },
1660
1771
  children: []
1661
1772
  });
1662
- const screenManufacturerNumberPos = applyToPoint20(transform, {
1773
+ const screenManufacturerNumberPos = applyToPoint21(transform, {
1663
1774
  x: schComponent.center.x + schComponent.size.width / 2,
1664
1775
  y: schComponent.center.y + schComponent.size.height / 2 + 0.5
1665
1776
  // Above the component top edge
1666
1777
  });
1667
- const fontSizePx = getSchFontSize(transform, "manufacturer_number");
1778
+ const fontSizePx = getSchScreenFontSize(transform, "manufacturer_number");
1668
1779
  if (srcComponent?.manufacturer_part_number) {
1669
1780
  svgObjects.push({
1670
1781
  name: "text",
@@ -1743,14 +1854,14 @@ function createSvgObjectsFromSchematicComponent(params) {
1743
1854
  }
1744
1855
 
1745
1856
  // lib/sch/svg-object-fns/create-svg-objects-from-sch-debug-object.ts
1746
- import { applyToPoint as applyToPoint21 } from "transformation-matrix";
1857
+ import { applyToPoint as applyToPoint22 } from "transformation-matrix";
1747
1858
  function createSvgObjectsFromSchDebugObject(debugObject, transform) {
1748
1859
  if (debugObject.shape === "rect") {
1749
- let [screenLeft, screenTop] = applyToPoint21(transform, [
1860
+ let [screenLeft, screenTop] = applyToPoint22(transform, [
1750
1861
  debugObject.center.x - debugObject.size.width / 2,
1751
1862
  debugObject.center.y - debugObject.size.height / 2
1752
1863
  ]);
1753
- let [screenRight, screenBottom] = applyToPoint21(transform, [
1864
+ let [screenRight, screenBottom] = applyToPoint22(transform, [
1754
1865
  debugObject.center.x + debugObject.size.width / 2,
1755
1866
  debugObject.center.y + debugObject.size.height / 2
1756
1867
  ]);
@@ -1760,7 +1871,7 @@ function createSvgObjectsFromSchDebugObject(debugObject, transform) {
1760
1871
  ];
1761
1872
  const width = Math.abs(screenRight - screenLeft);
1762
1873
  const height = Math.abs(screenBottom - screenTop);
1763
- const [screenCenterX, screenCenterY] = applyToPoint21(transform, [
1874
+ const [screenCenterX, screenCenterY] = applyToPoint22(transform, [
1764
1875
  debugObject.center.x,
1765
1876
  debugObject.center.y
1766
1877
  ]);
@@ -1806,11 +1917,11 @@ function createSvgObjectsFromSchDebugObject(debugObject, transform) {
1806
1917
  ];
1807
1918
  }
1808
1919
  if (debugObject.shape === "line") {
1809
- const [screenStartX, screenStartY] = applyToPoint21(transform, [
1920
+ const [screenStartX, screenStartY] = applyToPoint22(transform, [
1810
1921
  debugObject.start.x,
1811
1922
  debugObject.start.y
1812
1923
  ]);
1813
- const [screenEndX, screenEndY] = applyToPoint21(transform, [
1924
+ const [screenEndX, screenEndY] = applyToPoint22(transform, [
1814
1925
  debugObject.end.x,
1815
1926
  debugObject.end.y
1816
1927
  ]);
@@ -1860,7 +1971,7 @@ function createSvgObjectsFromSchDebugObject(debugObject, transform) {
1860
1971
  }
1861
1972
 
1862
1973
  // lib/sch/svg-object-fns/create-svg-objects-from-sch-trace.ts
1863
- import { applyToPoint as applyToPoint22 } from "transformation-matrix";
1974
+ import { applyToPoint as applyToPoint23 } from "transformation-matrix";
1864
1975
  function createSchematicTrace(trace, transform) {
1865
1976
  const edges = trace.edges;
1866
1977
  if (edges.length === 0) return [];
@@ -1869,11 +1980,11 @@ function createSchematicTrace(trace, transform) {
1869
1980
  for (let edgeIndex = 0; edgeIndex < edges.length; edgeIndex++) {
1870
1981
  const edge = edges[edgeIndex];
1871
1982
  if (edge.is_crossing) continue;
1872
- const [screenFromX, screenFromY] = applyToPoint22(transform, [
1983
+ const [screenFromX, screenFromY] = applyToPoint23(transform, [
1873
1984
  edge.from.x,
1874
1985
  edge.from.y
1875
1986
  ]);
1876
- const [screenToX, screenToY] = applyToPoint22(transform, [
1987
+ const [screenToX, screenToY] = applyToPoint23(transform, [
1877
1988
  edge.to.x,
1878
1989
  edge.to.y
1879
1990
  ]);
@@ -1885,11 +1996,11 @@ function createSchematicTrace(trace, transform) {
1885
1996
  }
1886
1997
  for (const edge of edges) {
1887
1998
  if (!edge.is_crossing) continue;
1888
- const [screenFromX, screenFromY] = applyToPoint22(transform, [
1999
+ const [screenFromX, screenFromY] = applyToPoint23(transform, [
1889
2000
  edge.from.x,
1890
2001
  edge.from.y
1891
2002
  ]);
1892
- const [screenToX, screenToY] = applyToPoint22(transform, [
2003
+ const [screenToX, screenToY] = applyToPoint23(transform, [
1893
2004
  edge.to.x,
1894
2005
  edge.to.y
1895
2006
  ]);
@@ -1948,7 +2059,7 @@ function createSchematicTrace(trace, transform) {
1948
2059
  }
1949
2060
  if (trace.junctions) {
1950
2061
  for (const junction of trace.junctions) {
1951
- const [screenX, screenY] = applyToPoint22(transform, [
2062
+ const [screenX, screenY] = applyToPoint23(transform, [
1952
2063
  junction.x,
1953
2064
  junction.y
1954
2065
  ]);
@@ -1970,62 +2081,867 @@ function createSchematicTrace(trace, transform) {
1970
2081
  }
1971
2082
 
1972
2083
  // lib/sch/svg-object-fns/create-svg-objects-for-sch-net-label.ts
1973
- import { applyToPoint as applyToPoint23 } from "transformation-matrix";
1974
- var createSvgObjectsForSchNetLabel = (schNetLabel, transform) => {
1975
- const svgObjects = [];
1976
- const screenPos = applyToPoint23(transform, schNetLabel.center);
1977
- const fontSize = getSchFontSize(transform, "net_label");
1978
- const textWidth = (schNetLabel.text?.length || 0) * fontSize * 0.7;
1979
- const padding = fontSize * 0.5;
1980
- const screenLabelHeight = fontSize * 1.2;
1981
- const screenArrowPoint = fontSize * 0.3;
1982
- const screenLabelWidth = textWidth + padding * 2 + screenArrowPoint;
1983
- let rotation = 0;
1984
- let baseX = screenPos.x;
1985
- let baseY = screenPos.y;
1986
- switch (schNetLabel.anchor_side) {
1987
- case "left":
1988
- rotation = 0;
1989
- break;
1990
- case "right":
1991
- rotation = 180;
1992
- baseX -= screenLabelWidth;
1993
- break;
1994
- case "top":
1995
- rotation = -90;
1996
- baseX -= screenLabelHeight / 2;
1997
- baseY += screenLabelWidth / 2;
1998
- break;
1999
- case "bottom":
2000
- rotation = 90;
2001
- baseX -= screenLabelHeight / 2;
2002
- baseY -= screenLabelWidth / 2;
2003
- break;
2004
- default:
2005
- rotation = 0;
2084
+ import {
2085
+ applyToPoint as applyToPoint24,
2086
+ compose as compose6,
2087
+ rotate as rotate3,
2088
+ scale as scale3,
2089
+ translate as translate6
2090
+ } from "transformation-matrix";
2091
+
2092
+ // lib/sch/arial-text-metrics.ts
2093
+ var arialTextMetrics = {
2094
+ "0": {
2095
+ width: 13,
2096
+ height: 27,
2097
+ ascent: 22,
2098
+ descent: 5,
2099
+ left: -1,
2100
+ right: 12
2101
+ },
2102
+ "1": {
2103
+ width: 13,
2104
+ height: 27,
2105
+ ascent: 22,
2106
+ descent: 5,
2107
+ left: -3,
2108
+ right: 9
2109
+ },
2110
+ "2": {
2111
+ width: 13,
2112
+ height: 27,
2113
+ ascent: 22,
2114
+ descent: 5,
2115
+ left: -1,
2116
+ right: 12
2117
+ },
2118
+ "3": {
2119
+ width: 13,
2120
+ height: 27,
2121
+ ascent: 22,
2122
+ descent: 5,
2123
+ left: -1,
2124
+ right: 12
2125
+ },
2126
+ "4": {
2127
+ width: 13,
2128
+ height: 27,
2129
+ ascent: 22,
2130
+ descent: 5,
2131
+ left: 0,
2132
+ right: 12
2133
+ },
2134
+ "5": {
2135
+ width: 13,
2136
+ height: 27,
2137
+ ascent: 22,
2138
+ descent: 5,
2139
+ left: -1,
2140
+ right: 12
2141
+ },
2142
+ "6": {
2143
+ width: 13,
2144
+ height: 27,
2145
+ ascent: 22,
2146
+ descent: 5,
2147
+ left: -1,
2148
+ right: 12
2149
+ },
2150
+ "7": {
2151
+ width: 13,
2152
+ height: 27,
2153
+ ascent: 22,
2154
+ descent: 5,
2155
+ left: -1,
2156
+ right: 12
2157
+ },
2158
+ "8": {
2159
+ width: 13,
2160
+ height: 27,
2161
+ ascent: 22,
2162
+ descent: 5,
2163
+ left: -1,
2164
+ right: 12
2165
+ },
2166
+ "9": {
2167
+ width: 13,
2168
+ height: 27,
2169
+ ascent: 22,
2170
+ descent: 5,
2171
+ left: -1,
2172
+ right: 12
2173
+ },
2174
+ " ": {
2175
+ width: 7,
2176
+ height: 27,
2177
+ ascent: 22,
2178
+ descent: 5,
2179
+ left: 0,
2180
+ right: 0
2181
+ },
2182
+ "!": {
2183
+ width: 7,
2184
+ height: 27,
2185
+ ascent: 22,
2186
+ descent: 5,
2187
+ left: -2,
2188
+ right: 5
2189
+ },
2190
+ '"': {
2191
+ width: 9,
2192
+ height: 27,
2193
+ ascent: 22,
2194
+ descent: 5,
2195
+ left: -1,
2196
+ right: 7
2197
+ },
2198
+ "#": {
2199
+ width: 13,
2200
+ height: 27,
2201
+ ascent: 22,
2202
+ descent: 5,
2203
+ left: 0,
2204
+ right: 13
2205
+ },
2206
+ $: {
2207
+ width: 13,
2208
+ height: 27,
2209
+ ascent: 22,
2210
+ descent: 5,
2211
+ left: -1,
2212
+ right: 12
2213
+ },
2214
+ "%": {
2215
+ width: 21,
2216
+ height: 27,
2217
+ ascent: 22,
2218
+ descent: 5,
2219
+ left: -1,
2220
+ right: 20
2221
+ },
2222
+ "&": {
2223
+ width: 16,
2224
+ height: 27,
2225
+ ascent: 22,
2226
+ descent: 5,
2227
+ left: -1,
2228
+ right: 15
2229
+ },
2230
+ "'": {
2231
+ width: 5,
2232
+ height: 27,
2233
+ ascent: 22,
2234
+ descent: 5,
2235
+ left: -1,
2236
+ right: 3
2237
+ },
2238
+ "(": {
2239
+ width: 8,
2240
+ height: 27,
2241
+ ascent: 22,
2242
+ descent: 5,
2243
+ left: -1,
2244
+ right: 7
2245
+ },
2246
+ ")": {
2247
+ width: 8,
2248
+ height: 27,
2249
+ ascent: 22,
2250
+ descent: 5,
2251
+ left: -1,
2252
+ right: 7
2253
+ },
2254
+ "*": {
2255
+ width: 9,
2256
+ height: 27,
2257
+ ascent: 22,
2258
+ descent: 5,
2259
+ left: -1,
2260
+ right: 8
2261
+ },
2262
+ "+": {
2263
+ width: 14,
2264
+ height: 27,
2265
+ ascent: 22,
2266
+ descent: 5,
2267
+ left: -1,
2268
+ right: 13
2269
+ },
2270
+ ",": {
2271
+ width: 7,
2272
+ height: 27,
2273
+ ascent: 22,
2274
+ descent: 5,
2275
+ left: -2,
2276
+ right: 5
2277
+ },
2278
+ "-": {
2279
+ width: 8,
2280
+ height: 27,
2281
+ ascent: 22,
2282
+ descent: 5,
2283
+ left: -1,
2284
+ right: 7
2285
+ },
2286
+ ".": {
2287
+ width: 7,
2288
+ height: 27,
2289
+ ascent: 22,
2290
+ descent: 5,
2291
+ left: -2,
2292
+ right: 5
2293
+ },
2294
+ "/": {
2295
+ width: 7,
2296
+ height: 27,
2297
+ ascent: 22,
2298
+ descent: 5,
2299
+ left: 0,
2300
+ right: 7
2301
+ },
2302
+ ":": {
2303
+ width: 7,
2304
+ height: 27,
2305
+ ascent: 22,
2306
+ descent: 5,
2307
+ left: -2,
2308
+ right: 5
2309
+ },
2310
+ ";": {
2311
+ width: 7,
2312
+ height: 27,
2313
+ ascent: 22,
2314
+ descent: 5,
2315
+ left: -2,
2316
+ right: 5
2317
+ },
2318
+ "<": {
2319
+ width: 14,
2320
+ height: 27,
2321
+ ascent: 22,
2322
+ descent: 5,
2323
+ left: -1,
2324
+ right: 13
2325
+ },
2326
+ "=": {
2327
+ width: 14,
2328
+ height: 27,
2329
+ ascent: 22,
2330
+ descent: 5,
2331
+ left: -1,
2332
+ right: 13
2333
+ },
2334
+ ">": {
2335
+ width: 14,
2336
+ height: 27,
2337
+ ascent: 22,
2338
+ descent: 5,
2339
+ left: -1,
2340
+ right: 13
2341
+ },
2342
+ "?": {
2343
+ width: 13,
2344
+ height: 27,
2345
+ ascent: 22,
2346
+ descent: 5,
2347
+ left: -1,
2348
+ right: 12
2349
+ },
2350
+ "@": {
2351
+ width: 24,
2352
+ height: 27,
2353
+ ascent: 22,
2354
+ descent: 5,
2355
+ left: -1,
2356
+ right: 23
2357
+ },
2358
+ A: {
2359
+ width: 16,
2360
+ height: 27,
2361
+ ascent: 22,
2362
+ descent: 5,
2363
+ left: 0,
2364
+ right: 16
2365
+ },
2366
+ B: {
2367
+ width: 16,
2368
+ height: 27,
2369
+ ascent: 22,
2370
+ descent: 5,
2371
+ left: -2,
2372
+ right: 15
2373
+ },
2374
+ C: {
2375
+ width: 17,
2376
+ height: 27,
2377
+ ascent: 22,
2378
+ descent: 5,
2379
+ left: -1,
2380
+ right: 16
2381
+ },
2382
+ D: {
2383
+ width: 17,
2384
+ height: 27,
2385
+ ascent: 22,
2386
+ descent: 5,
2387
+ left: -2,
2388
+ right: 16
2389
+ },
2390
+ E: {
2391
+ width: 16,
2392
+ height: 27,
2393
+ ascent: 22,
2394
+ descent: 5,
2395
+ left: -2,
2396
+ right: 15
2397
+ },
2398
+ F: {
2399
+ width: 15,
2400
+ height: 27,
2401
+ ascent: 22,
2402
+ descent: 5,
2403
+ left: -2,
2404
+ right: 14
2405
+ },
2406
+ G: {
2407
+ width: 19,
2408
+ height: 27,
2409
+ ascent: 22,
2410
+ descent: 5,
2411
+ left: -1,
2412
+ right: 17
2413
+ },
2414
+ H: {
2415
+ width: 17,
2416
+ height: 27,
2417
+ ascent: 22,
2418
+ descent: 5,
2419
+ left: -2,
2420
+ right: 15
2421
+ },
2422
+ I: {
2423
+ width: 7,
2424
+ height: 27,
2425
+ ascent: 22,
2426
+ descent: 5,
2427
+ left: -2,
2428
+ right: 5
2429
+ },
2430
+ J: {
2431
+ width: 12,
2432
+ height: 27,
2433
+ ascent: 22,
2434
+ descent: 5,
2435
+ left: -1,
2436
+ right: 10
2437
+ },
2438
+ K: {
2439
+ width: 16,
2440
+ height: 27,
2441
+ ascent: 22,
2442
+ descent: 5,
2443
+ left: -2,
2444
+ right: 16
2445
+ },
2446
+ L: {
2447
+ width: 13,
2448
+ height: 27,
2449
+ ascent: 22,
2450
+ descent: 5,
2451
+ left: -2,
2452
+ right: 12
2453
+ },
2454
+ M: {
2455
+ width: 20,
2456
+ height: 27,
2457
+ ascent: 22,
2458
+ descent: 5,
2459
+ left: -2,
2460
+ right: 18
2461
+ },
2462
+ N: {
2463
+ width: 17,
2464
+ height: 27,
2465
+ ascent: 22,
2466
+ descent: 5,
2467
+ left: -2,
2468
+ right: 15
2469
+ },
2470
+ O: {
2471
+ width: 19,
2472
+ height: 27,
2473
+ ascent: 22,
2474
+ descent: 5,
2475
+ left: -1,
2476
+ right: 18
2477
+ },
2478
+ P: {
2479
+ width: 16,
2480
+ height: 27,
2481
+ ascent: 22,
2482
+ descent: 5,
2483
+ left: -2,
2484
+ right: 15
2485
+ },
2486
+ Q: {
2487
+ width: 19,
2488
+ height: 27,
2489
+ ascent: 22,
2490
+ descent: 5,
2491
+ left: -1,
2492
+ right: 18
2493
+ },
2494
+ R: {
2495
+ width: 17,
2496
+ height: 27,
2497
+ ascent: 22,
2498
+ descent: 5,
2499
+ left: -2,
2500
+ right: 17
2501
+ },
2502
+ S: {
2503
+ width: 16,
2504
+ height: 27,
2505
+ ascent: 22,
2506
+ descent: 5,
2507
+ left: -1,
2508
+ right: 15
2509
+ },
2510
+ T: {
2511
+ width: 15,
2512
+ height: 27,
2513
+ ascent: 22,
2514
+ descent: 5,
2515
+ left: -1,
2516
+ right: 14
2517
+ },
2518
+ U: {
2519
+ width: 17,
2520
+ height: 27,
2521
+ ascent: 22,
2522
+ descent: 5,
2523
+ left: -2,
2524
+ right: 15
2525
+ },
2526
+ V: {
2527
+ width: 16,
2528
+ height: 27,
2529
+ ascent: 22,
2530
+ descent: 5,
2531
+ left: 0,
2532
+ right: 16
2533
+ },
2534
+ W: {
2535
+ width: 23,
2536
+ height: 27,
2537
+ ascent: 22,
2538
+ descent: 5,
2539
+ left: 0,
2540
+ right: 22
2541
+ },
2542
+ X: {
2543
+ width: 16,
2544
+ height: 27,
2545
+ ascent: 22,
2546
+ descent: 5,
2547
+ left: 0,
2548
+ right: 16
2549
+ },
2550
+ Y: {
2551
+ width: 16,
2552
+ height: 27,
2553
+ ascent: 22,
2554
+ descent: 5,
2555
+ left: 0,
2556
+ right: 16
2557
+ },
2558
+ Z: {
2559
+ width: 15,
2560
+ height: 27,
2561
+ ascent: 22,
2562
+ descent: 5,
2563
+ left: 0,
2564
+ right: 14
2565
+ },
2566
+ "[": {
2567
+ width: 7,
2568
+ height: 27,
2569
+ ascent: 22,
2570
+ descent: 5,
2571
+ left: -2,
2572
+ right: 6
2573
+ },
2574
+ "\\": {
2575
+ width: 7,
2576
+ height: 27,
2577
+ ascent: 22,
2578
+ descent: 5,
2579
+ left: 0,
2580
+ right: 7
2581
+ },
2582
+ "]": {
2583
+ width: 7,
2584
+ height: 27,
2585
+ ascent: 22,
2586
+ descent: 5,
2587
+ left: 0,
2588
+ right: 5
2589
+ },
2590
+ "^": {
2591
+ width: 11,
2592
+ height: 27,
2593
+ ascent: 22,
2594
+ descent: 5,
2595
+ left: -1,
2596
+ right: 11
2597
+ },
2598
+ _: {
2599
+ width: 13,
2600
+ height: 27,
2601
+ ascent: 22,
2602
+ descent: 5,
2603
+ left: 0,
2604
+ right: 14
2605
+ },
2606
+ "`": {
2607
+ width: 8,
2608
+ height: 27,
2609
+ ascent: 22,
2610
+ descent: 5,
2611
+ left: -1,
2612
+ right: 5
2613
+ },
2614
+ a: {
2615
+ width: 13,
2616
+ height: 27,
2617
+ ascent: 22,
2618
+ descent: 5,
2619
+ left: -1,
2620
+ right: 12
2621
+ },
2622
+ b: {
2623
+ width: 13,
2624
+ height: 27,
2625
+ ascent: 22,
2626
+ descent: 5,
2627
+ left: -2,
2628
+ right: 12
2629
+ },
2630
+ c: {
2631
+ width: 12,
2632
+ height: 27,
2633
+ ascent: 22,
2634
+ descent: 5,
2635
+ left: -1,
2636
+ right: 12
2637
+ },
2638
+ d: {
2639
+ width: 13,
2640
+ height: 27,
2641
+ ascent: 22,
2642
+ descent: 5,
2643
+ left: -1,
2644
+ right: 12
2645
+ },
2646
+ e: {
2647
+ width: 13,
2648
+ height: 27,
2649
+ ascent: 22,
2650
+ descent: 5,
2651
+ left: -1,
2652
+ right: 12
2653
+ },
2654
+ f: {
2655
+ width: 7,
2656
+ height: 27,
2657
+ ascent: 22,
2658
+ descent: 5,
2659
+ left: 0,
2660
+ right: 8
2661
+ },
2662
+ g: {
2663
+ width: 13,
2664
+ height: 27,
2665
+ ascent: 22,
2666
+ descent: 5,
2667
+ left: -1,
2668
+ right: 12
2669
+ },
2670
+ h: {
2671
+ width: 13,
2672
+ height: 27,
2673
+ ascent: 22,
2674
+ descent: 5,
2675
+ left: -2,
2676
+ right: 12
2677
+ },
2678
+ i: {
2679
+ width: 5,
2680
+ height: 27,
2681
+ ascent: 22,
2682
+ descent: 5,
2683
+ left: -2,
2684
+ right: 4
2685
+ },
2686
+ j: {
2687
+ width: 5,
2688
+ height: 27,
2689
+ ascent: 22,
2690
+ descent: 5,
2691
+ left: 1,
2692
+ right: 4
2693
+ },
2694
+ k: {
2695
+ width: 12,
2696
+ height: 27,
2697
+ ascent: 22,
2698
+ descent: 5,
2699
+ left: -2,
2700
+ right: 12
2701
+ },
2702
+ l: {
2703
+ width: 5,
2704
+ height: 27,
2705
+ ascent: 22,
2706
+ descent: 5,
2707
+ left: -2,
2708
+ right: 4
2709
+ },
2710
+ m: {
2711
+ width: 20,
2712
+ height: 27,
2713
+ ascent: 22,
2714
+ descent: 5,
2715
+ left: -2,
2716
+ right: 18
2717
+ },
2718
+ n: {
2719
+ width: 13,
2720
+ height: 27,
2721
+ ascent: 22,
2722
+ descent: 5,
2723
+ left: -2,
2724
+ right: 12
2725
+ },
2726
+ o: {
2727
+ width: 13,
2728
+ height: 27,
2729
+ ascent: 22,
2730
+ descent: 5,
2731
+ left: -1,
2732
+ right: 12
2733
+ },
2734
+ p: {
2735
+ width: 13,
2736
+ height: 27,
2737
+ ascent: 22,
2738
+ descent: 5,
2739
+ left: -2,
2740
+ right: 12
2741
+ },
2742
+ q: {
2743
+ width: 13,
2744
+ height: 27,
2745
+ ascent: 22,
2746
+ descent: 5,
2747
+ left: -1,
2748
+ right: 12
2749
+ },
2750
+ r: {
2751
+ width: 8,
2752
+ height: 27,
2753
+ ascent: 22,
2754
+ descent: 5,
2755
+ left: -2,
2756
+ right: 8
2757
+ },
2758
+ s: {
2759
+ width: 12,
2760
+ height: 27,
2761
+ ascent: 22,
2762
+ descent: 5,
2763
+ left: -1,
2764
+ right: 11
2765
+ },
2766
+ t: {
2767
+ width: 7,
2768
+ height: 27,
2769
+ ascent: 22,
2770
+ descent: 5,
2771
+ left: 0,
2772
+ right: 6
2773
+ },
2774
+ u: {
2775
+ width: 13,
2776
+ height: 27,
2777
+ ascent: 22,
2778
+ descent: 5,
2779
+ left: -2,
2780
+ right: 12
2781
+ },
2782
+ v: {
2783
+ width: 12,
2784
+ height: 27,
2785
+ ascent: 22,
2786
+ descent: 5,
2787
+ left: 0,
2788
+ right: 12
2789
+ },
2790
+ w: {
2791
+ width: 17,
2792
+ height: 27,
2793
+ ascent: 22,
2794
+ descent: 5,
2795
+ left: 0,
2796
+ right: 17
2797
+ },
2798
+ x: {
2799
+ width: 12,
2800
+ height: 27,
2801
+ ascent: 22,
2802
+ descent: 5,
2803
+ left: 0,
2804
+ right: 12
2805
+ },
2806
+ y: {
2807
+ width: 12,
2808
+ height: 27,
2809
+ ascent: 22,
2810
+ descent: 5,
2811
+ left: 0,
2812
+ right: 12
2813
+ },
2814
+ z: {
2815
+ width: 12,
2816
+ height: 27,
2817
+ ascent: 22,
2818
+ descent: 5,
2819
+ left: 0,
2820
+ right: 11
2821
+ },
2822
+ "{": {
2823
+ width: 8,
2824
+ height: 27,
2825
+ ascent: 22,
2826
+ descent: 5,
2827
+ left: -1,
2828
+ right: 7
2829
+ },
2830
+ "|": {
2831
+ width: 6,
2832
+ height: 27,
2833
+ ascent: 22,
2834
+ descent: 5,
2835
+ left: -2,
2836
+ right: 4
2837
+ },
2838
+ "}": {
2839
+ width: 8,
2840
+ height: 27,
2841
+ ascent: 22,
2842
+ descent: 5,
2843
+ left: -1,
2844
+ right: 7
2845
+ },
2846
+ "~": {
2847
+ width: 14,
2848
+ height: 27,
2849
+ ascent: 22,
2850
+ descent: 5,
2851
+ left: -1,
2852
+ right: 13
2006
2853
  }
2007
- const transformString = `rotate(${rotation} ${screenPos.x} ${screenPos.y})`;
2008
- const points = [
2009
- { x: baseX, y: baseY },
2010
- // Left edge
2011
- { x: baseX + screenLabelWidth - screenArrowPoint, y: baseY },
2012
- // Top edge
2013
- { x: baseX + screenLabelWidth, y: baseY + screenLabelHeight / 2 },
2014
- // Arrow point
2854
+ };
2855
+
2856
+ // lib/sch/estimate-text-width.ts
2857
+ var estimateTextWidth = (text) => {
2858
+ if (!text) return 0;
2859
+ let totalWidth = 0;
2860
+ for (const char of text) {
2861
+ const metrics = arialTextMetrics[char];
2862
+ if (metrics) {
2863
+ totalWidth += metrics.width;
2864
+ } else {
2865
+ totalWidth += arialTextMetrics["?"].width;
2866
+ }
2867
+ }
2868
+ return totalWidth / 27;
2869
+ };
2870
+
2871
+ // lib/sch/svg-object-fns/create-svg-objects-for-sch-net-label.ts
2872
+ var ARROW_POINT_WIDTH_FSR = 0.3;
2873
+ var END_PADDING_FSR = 0.3;
2874
+ var END_PADDING_EXTRA_PER_CHARACTER_FSR = 0.06;
2875
+ var createSvgObjectsForSchNetLabel = (schNetLabel, realToScreenTransform) => {
2876
+ if (!schNetLabel.text) return [];
2877
+ const svgObjects = [];
2878
+ const fontSizePx = getSchScreenFontSize(realToScreenTransform, "net_label");
2879
+ const fontSizeMm = getSchMmFontSize("net_label");
2880
+ const textWidthFSR = estimateTextWidth(schNetLabel.text || "");
2881
+ const screenCenter = applyToPoint24(realToScreenTransform, schNetLabel.center);
2882
+ const realTextGrowthVec = getUnitVectorFromOutsideToEdge(
2883
+ schNetLabel.anchor_side
2884
+ );
2885
+ const screenTextGrowthVec = { ...realTextGrowthVec };
2886
+ screenTextGrowthVec.y *= -1;
2887
+ const fullWidthFsr = textWidthFSR + ARROW_POINT_WIDTH_FSR * 2 + END_PADDING_EXTRA_PER_CHARACTER_FSR * schNetLabel.text.length + END_PADDING_FSR;
2888
+ const screenAnchorPosition = schNetLabel.anchor_position ? applyToPoint24(realToScreenTransform, schNetLabel.anchor_position) : {
2889
+ x: screenCenter.x - screenTextGrowthVec.x * fullWidthFsr * fontSizePx / 2,
2890
+ y: screenCenter.y - screenTextGrowthVec.y * fullWidthFsr * fontSizePx / 2
2891
+ };
2892
+ const realAnchorPosition = schNetLabel.anchor_position ?? {
2893
+ x: schNetLabel.center.x - realTextGrowthVec.x * fullWidthFsr * fontSizeMm / 2,
2894
+ y: schNetLabel.center.y - realTextGrowthVec.y * fullWidthFsr * fontSizeMm / 2
2895
+ };
2896
+ const pathRotation = {
2897
+ left: 0,
2898
+ top: -90,
2899
+ bottom: 90,
2900
+ right: 180
2901
+ }[schNetLabel.anchor_side];
2902
+ const screenOutlinePoints = [
2903
+ // Arrow point in font-relative coordinates
2015
2904
  {
2016
- x: baseX + screenLabelWidth - screenArrowPoint,
2017
- y: baseY + screenLabelHeight
2905
+ x: 0,
2906
+ y: 0
2018
2907
  },
2019
- // Bottom after arrow
2020
- { x: baseX, y: baseY + screenLabelHeight }
2021
- // Bottom left corner
2022
- ];
2908
+ // Top left corner in font-relative coordinates
2909
+ {
2910
+ x: ARROW_POINT_WIDTH_FSR,
2911
+ y: 0.6
2912
+ },
2913
+ // Top right corner in font-relative coordinates
2914
+ {
2915
+ x: ARROW_POINT_WIDTH_FSR * 2 + END_PADDING_FSR + END_PADDING_EXTRA_PER_CHARACTER_FSR * schNetLabel.text.length + textWidthFSR,
2916
+ y: 0.6
2917
+ },
2918
+ // Bottom right corner in font-relative coordinates
2919
+ {
2920
+ x: ARROW_POINT_WIDTH_FSR * 2 + END_PADDING_FSR + END_PADDING_EXTRA_PER_CHARACTER_FSR * schNetLabel.text.length + textWidthFSR,
2921
+ y: -0.6
2922
+ },
2923
+ // Bottom left corner in font-relative coordinates
2924
+ {
2925
+ x: ARROW_POINT_WIDTH_FSR,
2926
+ y: -0.6
2927
+ }
2928
+ ].map(
2929
+ (fontRelativePoint) => applyToPoint24(
2930
+ compose6(
2931
+ realToScreenTransform,
2932
+ translate6(realAnchorPosition.x, realAnchorPosition.y),
2933
+ scale3(fontSizeMm),
2934
+ rotate3(pathRotation / 180 * Math.PI)
2935
+ ),
2936
+ fontRelativePoint
2937
+ )
2938
+ );
2023
2939
  const pathD = `
2024
- M ${points[0]?.x},${points[0]?.y}
2025
- L ${points[1]?.x},${points[1]?.y}
2026
- L ${points[2]?.x},${points[2]?.y}
2027
- L ${points[3]?.x},${points[3]?.y}
2028
- L ${points[4]?.x},${points[4]?.y}
2940
+ M ${screenOutlinePoints[0].x},${screenOutlinePoints[0].y}
2941
+ L ${screenOutlinePoints[1].x},${screenOutlinePoints[1].y}
2942
+ L ${screenOutlinePoints[2].x},${screenOutlinePoints[2].y}
2943
+ L ${screenOutlinePoints[3].x},${screenOutlinePoints[3].y}
2944
+ L ${screenOutlinePoints[4].x},${screenOutlinePoints[4].y}
2029
2945
  Z
2030
2946
  `;
2031
2947
  svgObjects.push({
@@ -2036,28 +2952,41 @@ var createSvgObjectsForSchNetLabel = (schNetLabel, transform) => {
2036
2952
  d: pathD,
2037
2953
  fill: "white",
2038
2954
  stroke: colorMap.schematic.label_global,
2039
- "stroke-width": `${getSchStrokeSize(transform)}px`,
2040
- transform: transformString
2955
+ "stroke-width": `${getSchStrokeSize(realToScreenTransform)}px`
2041
2956
  },
2042
2957
  value: "",
2043
2958
  children: []
2044
2959
  });
2045
- const screenTextX = baseX + (screenLabelWidth - screenArrowPoint) / 2;
2046
- const screenTextY = baseY + screenLabelHeight / 2 + fontSize * 0.05;
2960
+ const screenTextPos = {
2961
+ x: screenAnchorPosition.x + screenTextGrowthVec.x * fontSizePx * 0.5,
2962
+ y: screenAnchorPosition.y + screenTextGrowthVec.y * fontSizePx * 0.5
2963
+ };
2964
+ const textAnchor = {
2965
+ left: "start",
2966
+ top: "start",
2967
+ bottom: "start",
2968
+ right: "end"
2969
+ }[schNetLabel.anchor_side];
2970
+ const textTransformString = {
2971
+ left: "",
2972
+ right: "",
2973
+ top: `rotate(90 ${screenTextPos.x} ${screenTextPos.y})`,
2974
+ bottom: `rotate(-90 ${screenTextPos.x} ${screenTextPos.y})`
2975
+ }[schNetLabel.anchor_side];
2047
2976
  svgObjects.push({
2048
2977
  name: "text",
2049
2978
  type: "element",
2050
2979
  attributes: {
2051
2980
  class: "net-label-text",
2052
- x: screenTextX.toString(),
2053
- y: screenTextY.toString(),
2981
+ x: screenTextPos.x.toString(),
2982
+ y: screenTextPos.y.toString(),
2054
2983
  fill: colorMap.schematic.label_global,
2055
- "text-anchor": "middle",
2984
+ "text-anchor": textAnchor,
2056
2985
  "dominant-baseline": "central",
2057
- // Changed to central for better vertical alignment
2058
2986
  "font-family": "sans-serif",
2059
- "font-size": `${fontSize}px`,
2060
- transform: transformString
2987
+ "font-variant-numeric": "tabular-nums",
2988
+ "font-size": `${fontSizePx}px`,
2989
+ transform: textTransformString
2061
2990
  },
2062
2991
  children: [
2063
2992
  {
@@ -2128,14 +3057,6 @@ function convertCircuitJsonToSchematicSvg(circuitJson, options) {
2128
3057
  drawSchematicGrid({ bounds: realBounds, transform, ...gridConfig })
2129
3058
  );
2130
3059
  }
2131
- if (options?.labeledPoints) {
2132
- svgChildren.push(
2133
- drawSchematicLabeledPoints({
2134
- points: options.labeledPoints,
2135
- transform
2136
- })
2137
- );
2138
- }
2139
3060
  const schDebugObjectSvgs = [];
2140
3061
  const schComponentSvgs = [];
2141
3062
  const schTraceSvgs = [];
@@ -2165,6 +3086,14 @@ function convertCircuitJsonToSchematicSvg(circuitJson, options) {
2165
3086
  ...schTraceSvgs,
2166
3087
  ...schNetLabel
2167
3088
  );
3089
+ if (options?.labeledPoints) {
3090
+ svgChildren.push(
3091
+ drawSchematicLabeledPoints({
3092
+ points: options.labeledPoints,
3093
+ transform
3094
+ })
3095
+ );
3096
+ }
2168
3097
  const svgObject = {
2169
3098
  name: "svg",
2170
3099
  type: "element",